-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcontainers.go
349 lines (310 loc) · 9.94 KB
/
containers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
package reportbro
import (
"sort"
)
type containerProvider interface {
base() *Container
prepare(ctx Context, pdfDoc *FPDFRB, onlyVerify bool)
createRenderElements(contentHeight float64, ctx Context, pdfDoc *FPDFRB) bool
isFinished() bool
renderPDF(containerOffsetX float64, containerOffsetY float64, pdfDoc *FPDFRB, cleanup bool)
cleanup()
}
type containers struct {
containers []*Container
}
func (self *containers) addContainer(container *Container) {
self.containers = append(self.containers, container)
}
func (self *containers) GetContainer(ID string) *Container {
for _, container := range self.containers {
if container.ID == ID {
return container
}
}
return nil
}
type Container struct {
ID string
Report *report
DocElements []DocElementBaseProvider
Width float64
Height float64
AllowPageBreak bool
ContainerOffsetY float64
SortedElements []DocElementBaseProvider
RenderElements []DocElementBaseProvider
RenderElementsCreated bool
ExplicitPageBreak bool
PageY float64
FirstElementOffsetY float64
UsedBandHeight float64
ManualPageBreak bool
}
func (self *Container) base() *Container {
return self
}
func (self *Container) init(containerID string, containers *containers, report *report) {
self.ID = containerID
self.Report = report
self.DocElements = make([]DocElementBaseProvider, 0) // type: List[DocElementBase]
self.Width = 0.0
self.Height = 0.0
containers.addContainer(self)
self.AllowPageBreak = true
self.ContainerOffsetY = 0.0
self.SortedElements = nil // type: List[DocElementBase]
self.RenderElements = nil // type: List[DocElementBase]
self.RenderElementsCreated = false
self.ExplicitPageBreak = true
self.PageY = 0.0
self.FirstElementOffsetY = 0.0
self.UsedBandHeight = 0.0
}
func (self *Container) add(docElement DocElementBaseProvider) {
self.DocElements = append(self.DocElements, docElement)
}
func (self *Container) isVisible() bool {
return true
}
func (self *Container) prepare(ctx Context, pdfDoc *FPDFRB, onlyVerify bool) {
self.SortedElements = make([]DocElementBaseProvider, 0)
for _, elem := range self.DocElements {
if pdfDoc != nil || elem.base().SpreadsheetHide == false || onlyVerify {
elem.prepare(ctx, pdfDoc, onlyVerify)
if self.AllowPageBreak == false {
// make sure element can be rendered multiple times (for header/footer)
elem.base().FirstRenderElement = true
elem.base().RenderingComplete = false
}
self.SortedElements = append(self.SortedElements, elem)
}
}
if pdfDoc != nil {
y := make([]float64, len(self.SortedElements))
zIndex := make([]int, len(self.SortedElements))
for key, sortedElement := range self.SortedElements {
y[key] = sortedElement.base().Y
zIndex[key] = sortedElement.base().ZIndex
}
sort.Slice(self.SortedElements, func(i, j int) bool {
return (self.SortedElements[i].base().Y < self.SortedElements[j].base().Y)
})
sort.Slice(self.SortedElements, func(i, j int) bool {
return (self.SortedElements[i].base().ZIndex < self.SortedElements[j].base().ZIndex)
})
// // predecessors are only needed for rendering pdf document
for i, elem := range self.SortedElements {
for _, j := range pyRange(i-1, -1, -1) {
elem2 := self.SortedElements[j]
if _, ok := elem2.(*PageBreakElement); ok {
// new page so all elements before are not direct predecessors
break
}
if elem.base().isPredecessor(elem2) {
elem.base().addPredecessor(elem2)
}
}
}
self.RenderElements = make([]DocElementBaseProvider, 0)
self.UsedBandHeight = 0
self.FirstElementOffsetY = 0
} else {
sort.Slice(self.SortedElements, func(i, j int) bool {
return self.SortedElements[i].base().Y < self.SortedElements[j].base().X
})
}
}
func (self *Container) ClearRenderedElements() {
self.RenderElements = make([]DocElementBaseProvider, 0)
self.UsedBandHeight = 0.0
}
func (self *Container) GetRenderElementsBottom() float64 {
bottom := 0.0
for _, renderElement := range self.RenderElements {
if renderElement.base().RenderBottom > bottom {
bottom = renderElement.base().RenderBottom
}
}
return bottom
}
func (self *Container) createRenderElements(containerHeight float64, ctx Context, pdfDoc *FPDFRB) bool {
i := 0
newPage := false
processedElements := make([]DocElementBaseProvider, 0)
completedElements := map[int]bool{}
self.RenderElementsCreated = false
self.ManualPageBreak = false
// setExplicitPageBreak := false
var NextOffsetY *float64
for newPage == false && i < len(self.SortedElements) {
elem := self.SortedElements[i]
if elem.hasUncompletedPredecessor(completedElements) {
// a predecessor is not completed yet -> start new page
newPage = true
} else {
elemDeleted := false
if _, ok := elem.(*PageBreakElement); ok {
if self.AllowPageBreak {
self.SortedElements = removeElement(self.SortedElements, i)
elemDeleted = true
newPage = true
self.ManualPageBreak = true
NextOffsetY = &elem.base().Y
} else {
self.SortedElements = make([]DocElementBaseProvider, 0)
return true
}
} else {
offsetY := 0.0
complete := false
if len(elem.base().Predecessors) > 0 {
// element is on same page as predecessor element(s) so offset is relative to predecessors
offsetY = elem.base().GetOffsetY()
} else {
if elem.base().FirstRenderElement {
offsetY = elem.base().Y - self.FirstElementOffsetY
if offsetY < 0 {
offsetY = 0
}
} else {
offsetY = 0
}
}
var renderElem DocElementBaseProvider
if elem.isPrinted(ctx) {
if offsetY >= containerHeight {
newPage = true
}
if newPage == false {
renderElem, complete = elem.getNextRenderElement(offsetY, containerHeight, ctx, pdfDoc)
if renderElem != nil {
if complete {
processedElements = append(processedElements, elem)
}
self.RenderElements = append(self.RenderElements, renderElem)
self.RenderElementsCreated = true
if renderElem.base().RenderBottom > self.UsedBandHeight {
self.UsedBandHeight = renderElem.base().RenderBottom
}
}
}
} else {
processedElements = append(processedElements, elem)
elem.finishEmptyElement(offsetY)
complete = true
}
if !complete && NextOffsetY == nil {
// in case we continue rendering on the next page the first element which is not complete
// will define the offset-y for the next page
NextOffsetY = &elem.base().Y
}
if complete {
completedElements[elem.base().ID] = true
self.SortedElements = removeElement(self.SortedElements, i)
elemDeleted = true
}
}
if elemDeleted == false {
i += 1
}
}
}
self.FirstElementOffsetY = 0
if NextOffsetY != nil {
self.FirstElementOffsetY = *NextOffsetY
}
if len(self.SortedElements) > 0 {
if self.AllowPageBreak {
self.RenderElements = append(self.RenderElements, NewPageBreakElement(self.Report, map[string]interface{}{"y": -1}))
}
for _, processedElement := range processedElements {
// remove dependency to predecessors because successor element is either already added
// to renderElements or on new page
for _, successor := range processedElement.base().Successors {
succ := successor
succ.base().clearPredecessors()
}
}
}
return (len(self.SortedElements) == 0)
}
func (self *Container) renderPDF(containerOffsetX float64, containerOffsetY float64, pdfDoc *FPDFRB, cleanup bool) {
counter := 0
for _, renderElem := range self.RenderElements {
counter += 1
if _, ok := renderElem.(*PageBreakElement); ok {
break
}
renderElem.renderPDF(containerOffsetX, containerOffsetY, pdfDoc)
if cleanup {
renderElem.cleanup()
}
}
self.RenderElements = self.RenderElements[counter:]
}
func (self *Container) RenderSpreadsheet(row int, col int, ctx Context, renderer Renderer) (int, int) {
return row, col
}
func (self *Container) isFinished() bool {
return len(self.RenderElements) == 0
}
func (self *Container) cleanup() {
for _, elem := range self.RenderElements {
elem.cleanup()
}
}
func NewContainer(containerID string, containers *containers, report *report) Container {
container := Container{}
container.init(containerID, containers, report)
return container
}
type Frame struct {
Container
X float64
Width float64
Height float64
BorderStyle BorderStyle
BackgroundColor Color
}
func (self *Frame) init(width float64, height float64, containerID string, containers *containers, report *report) {
self.Container.init(containerID, containers, report)
self.Container.Width = width
self.Container.Height = height
self.AllowPageBreak = false
}
func NewFrame(width float64, height float64, containerID string, containers *containers, report *report) *Frame {
frame := Frame{}
frame.init(width, height, containerID, containers, report)
return &frame
}
type reportBand struct {
Container
Band BandType
Report *report
}
func (self *reportBand) init(band BandType, containerID string, containers *containers, report *report) {
self.Container.init(containerID, containers, report)
self.Band = band
self.Width = report.documentProperties.pageWidth - report.documentProperties.marginLeft - report.documentProperties.marginRight
if band == BandTypeContent {
self.Height = report.documentProperties.contentHeight
} else if band == BandTypeHeader {
self.AllowPageBreak = false
self.Height = report.documentProperties.headerSize
} else if band == BandTypeFooter {
self.AllowPageBreak = false
self.Height = report.documentProperties.footerSize
}
}
func (self *reportBand) isVisible() bool {
if self.Band == BandTypeHeader {
return self.Report.documentProperties.header
}
return self.Report.documentProperties.footer
}
func newReportBand(band BandType, containerID string, containers *containers, report *report) *reportBand {
reportBand := reportBand{}
reportBand.init(band, containerID, containers, report)
return &reportBand
}