sp-excel-loader 0.3.40

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +661 -0
  4. data/README.md +8 -0
  5. data/lib/sp-excel-loader.rb +6 -0
  6. data/lib/sp/excel/loader.rb +61 -0
  7. data/lib/sp/excel/loader/jrxml/band.rb +80 -0
  8. data/lib/sp/excel/loader/jrxml/band_container.rb +229 -0
  9. data/lib/sp/excel/loader/jrxml/box.rb +75 -0
  10. data/lib/sp/excel/loader/jrxml/casper_checkbox.rb +97 -0
  11. data/lib/sp/excel/loader/jrxml/casper_combo.rb +86 -0
  12. data/lib/sp/excel/loader/jrxml/casper_date.rb +54 -0
  13. data/lib/sp/excel/loader/jrxml/casper_radio_button.rb +48 -0
  14. data/lib/sp/excel/loader/jrxml/casper_text_field.rb +157 -0
  15. data/lib/sp/excel/loader/jrxml/client_combo_text_field.rb +72 -0
  16. data/lib/sp/excel/loader/jrxml/excel_to_jrxml.rb +1183 -0
  17. data/lib/sp/excel/loader/jrxml/extensions.rb +330 -0
  18. data/lib/sp/excel/loader/jrxml/field.rb +65 -0
  19. data/lib/sp/excel/loader/jrxml/group.rb +71 -0
  20. data/lib/sp/excel/loader/jrxml/image.rb +63 -0
  21. data/lib/sp/excel/loader/jrxml/jasper.rb +228 -0
  22. data/lib/sp/excel/loader/jrxml/parameter.rb +73 -0
  23. data/lib/sp/excel/loader/jrxml/pen.rb +97 -0
  24. data/lib/sp/excel/loader/jrxml/property.rb +52 -0
  25. data/lib/sp/excel/loader/jrxml/property_expression.rb +52 -0
  26. data/lib/sp/excel/loader/jrxml/report_element.rb +92 -0
  27. data/lib/sp/excel/loader/jrxml/static_text.rb +59 -0
  28. data/lib/sp/excel/loader/jrxml/style.rb +99 -0
  29. data/lib/sp/excel/loader/jrxml/text_field.rb +83 -0
  30. data/lib/sp/excel/loader/jrxml/variable.rb +77 -0
  31. data/lib/sp/excel/loader/json_to_xlsx.rb +159 -0
  32. data/lib/sp/excel/loader/model_exporter.rb +249 -0
  33. data/lib/sp/excel/loader/payrollexporter.rb +168 -0
  34. data/lib/sp/excel/loader/rubyxl_table_patch.rb +91 -0
  35. data/lib/sp/excel/loader/version.rb +26 -0
  36. data/lib/sp/excel/loader/workbookloader.rb +480 -0
  37. data/spec/calc_spec.rb +87 -0
  38. data/spec/model.xls +0 -0
  39. metadata +151 -0
@@ -0,0 +1,1183 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Copyright (c) 2011-2016 Cloudware S.A. All rights reserved.
4
+ #
5
+ # This file is part of sp-excel-loader.
6
+ #
7
+ # sp-excel-loader is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Affero General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # sp-excel-loader is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Affero General Public License
18
+ # along with sp-excel-loader. If not, see <http://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ require 'set'
22
+
23
+
24
+ module Sp
25
+ module Excel
26
+ module Loader
27
+ module Jrxml
28
+
29
+ class ExcelToJrxml < WorkbookLoader
30
+
31
+ @@CT_IndexedColors = [
32
+ '000000', # 0
33
+ 'FFFFFF', # 1
34
+ 'FF0000', # 2
35
+ '00FF00', # 3
36
+ '0000FF', # 4
37
+ 'FFFF00', # 5
38
+ 'FF00FF', # 6
39
+ '00FFFF', # 7
40
+ '000000', # 8
41
+ 'FFFFFF', # 9
42
+ 'FF0000', # 10
43
+ '00FF00', # 11
44
+ '0000FF', # 12
45
+ 'FFFF00', # 13
46
+ 'FF00FF', # 14
47
+ '00FFFF', # 15
48
+ '800000', # 16
49
+ '008000', # 17
50
+ '000080', # 18
51
+ '808000', # 19
52
+ '800080', # 20
53
+ '008080', # 21
54
+ 'C0C0C0', # 22
55
+ '808080', # 23
56
+ '9999FF', # 24
57
+ '993366', # 25
58
+ 'FFFFCC', # 26
59
+ 'CCFFFF', # 27
60
+ '660066', # 28
61
+ 'FF8080', # 29
62
+ '0066CC', # 30
63
+ 'CCCCFF', # 31
64
+ '000080', # 32
65
+ 'FF00FF', # 33
66
+ 'FFFF00', # 34
67
+ '00FFFF', # 35
68
+ '800080', # 36
69
+ '800000', # 37
70
+ '008080', # 38
71
+ '0000FF', # 39
72
+ '00CCFF', # 40
73
+ 'CCFFFF', # 41
74
+ 'CCFFCC', # 42
75
+ 'FFFF99', # 43
76
+ '99CCFF', # 44
77
+ 'FF99CC', # 45
78
+ 'CC99FF', # 46
79
+ 'FFCC99', # 47
80
+ '3366FF', # 48
81
+ '33CCCC', # 49
82
+ '99CC00', # 50
83
+ 'FFCC00', # 51
84
+ 'FF9900', # 52
85
+ 'FF6600', # 53
86
+ '666699', # 54
87
+ '969696', # 55
88
+ '003366', # 56
89
+ '339966', # 57
90
+ '003300', # 58
91
+ '333300', # 59
92
+ '993300', # 60
93
+ '993366', # 61
94
+ '333399', # 62
95
+ '333333' # 63
96
+ ]
97
+
98
+ attr_reader :report
99
+ attr_reader :bindings
100
+
101
+ def initialize (a_excel_filename, a_fields_map = nil, a_enable_cb_or_rb_edition=false, write_jrxml = true, a_allow_sub_bands = true)
102
+ super(a_excel_filename)
103
+ read_all_tables()
104
+ report_name = File.basename(a_excel_filename, '.xlsx')
105
+ @report = JasperReport.new(report_name)
106
+ @current_band = nil
107
+ @first_row_in_band = 0
108
+ @band_type = nil
109
+ @v_scale = 1
110
+ @detail_cols_auto_height = false
111
+ @auto_float = false
112
+ @auto_stretch = false
113
+ @band_split_type = nil
114
+ @basic_expressions = false
115
+ @allow_sub_bands = a_allow_sub_bands
116
+ @bindings = a_fields_map
117
+ @use_casper_bindings = false
118
+
119
+ # If the field map is not supplied load aux tables from the same excel
120
+ if @bindings.nil?
121
+ @bindings = Hash.new
122
+
123
+ # Load parameters config table if it exists
124
+ if respond_to?('params_def') and not params_def.nil?
125
+ params_def.each do |param|
126
+ param.presentation = Presentation.new(param.presentation)
127
+ @bindings[param.id] = param
128
+ end
129
+ end
130
+
131
+ # Load fields config table if it exists
132
+ if respond_to?('fields_def') and not fields_def.nil?
133
+ fields_def.each do |field|
134
+ field.presentation = Presentation.new(field.presentation)
135
+ @bindings[field.id] = field
136
+ end
137
+ end
138
+
139
+ # Load variable definition table if it exists
140
+ if respond_to? ('variables_def') and not variables_def.nil?
141
+ variables_def.each do |vdef|
142
+ next if vdef.name.nil? or vdef.name.empty?
143
+ variable = Variable.new(vdef.name)
144
+ variable.java_class = vdef.java_class unless vdef.java_class.nil? or vdef.java_class.empty?
145
+ variable.calculation = vdef.calculation unless vdef.calculation.nil? or vdef.calculation.empty?
146
+ variable.reset_type = vdef.reset unless vdef.reset.nil? or vdef.reset.empty?
147
+ variable.variable_expression = vdef.expression unless vdef.expression.nil? or vdef.expression.empty?
148
+ variable.initial_value_expression = vdef.initial_expression unless vdef.initial_expression.nil? or vdef.initial_expression.empty?
149
+ @report.variables[vdef.name] = variable
150
+ end
151
+ end
152
+
153
+ end
154
+
155
+ @widget_factory = WidgetFactory.new(@bindings)
156
+ @widget_factory.cb_editable = a_enable_cb_or_rb_edition
157
+ @widget_factory.rb_editable = a_enable_cb_or_rb_edition
158
+
159
+ generate_styles()
160
+
161
+ @px_width = @report.page_width - @report.left_margin - @report.right_margin
162
+
163
+ parse_sheets()
164
+ if write_jrxml
165
+ File.write(report_name + '.jrxml', @report.to_xml)
166
+ end
167
+ end
168
+
169
+ def generate_styles
170
+
171
+ (0 .. @workbook.cell_xfs.size - 1).each do |style_index|
172
+ style = xf_to_style(style_index)
173
+ @report.styles[style.name] = style
174
+ end
175
+
176
+ end
177
+
178
+ def xf_to_style (a_style_index)
179
+
180
+ # create a style
181
+ style = Style.new('style_' + (a_style_index + 1).to_s)
182
+
183
+ # grab cell format
184
+ xf = @workbook.cell_xfs[a_style_index]
185
+
186
+ # Format font
187
+ if xf.apply_font == true
188
+ xls_font = @workbook.fonts[xf.font_id]
189
+
190
+ # on PDF we only have one font
191
+ style.font_name = 'DejaVu Sans Condensed'
192
+ # if xls_font.name.val == 'Arial'
193
+ # style.font_name = 'DejaVu Sans Condensed'
194
+ # else
195
+ # style.font_name = xls_font.name.val
196
+ # end
197
+
198
+ unless xls_font.color.nil?
199
+ style.forecolor = convert_color(xls_font.color)
200
+ end
201
+
202
+ style.font_size = xls_font.sz.val unless xls_font.sz.nil?
203
+ style.is_bold = true unless xls_font.b.nil?
204
+ style.is_italic = true unless xls_font.i.nil?
205
+ end
206
+
207
+ # background
208
+ if xf.apply_fill == true
209
+ xls_fill = @workbook.fills[xf.fill_id]
210
+ if xls_fill.pattern_fill.pattern_type == 'solid'
211
+ style.backcolor = convert_color(xls_fill.pattern_fill.fg_color)
212
+ end
213
+ end
214
+
215
+ # borders
216
+ if xf.apply_border == true
217
+ xls_border = @workbook.borders[xf.border_id]
218
+
219
+ if xls_border.outline != nil
220
+
221
+ if xls_border.outline.style != nil
222
+ style.box ||= Box.new
223
+ style.box.left_pen = LeftPen.new
224
+ style.box.top_pen = TopPen.new
225
+ style.box.right_pen = RightPen.new
226
+ style.box.bottom = BottomPen.new
227
+ apply_border_style(style.box.left_pen , xls_border.outline)
228
+ apply_border_style(style.box.top_pen , xls_border.outline)
229
+ apply_border_style(style.box.right_pen , xls_border.outline)
230
+ apply_border_style(style.box.bottom_pen, xls_border.outline)
231
+ end
232
+
233
+ else
234
+
235
+ if xls_border.left != nil && xls_border.left.style != nil
236
+ style.box ||= Box.new
237
+ style.box.left_pen = LeftPen.new
238
+ apply_border_style(style.box.left_pen, xls_border.left)
239
+ end
240
+
241
+ if xls_border.top != nil && xls_border.top.style != nil
242
+ style.box ||= Box.new
243
+ style.box.top_pen = TopPen.new
244
+ apply_border_style(style.box.top_pen, xls_border.top)
245
+ end
246
+
247
+ if xls_border.right != nil && xls_border.right.style != nil
248
+ style.box ||= Box.new
249
+ style.box.right_pen = RightPen.new
250
+ apply_border_style(style.box.right_pen, xls_border.right)
251
+ end
252
+
253
+ if xls_border.bottom != nil && xls_border.bottom.style != nil
254
+ style.box ||= Box.new
255
+ style.box.bottom_pen = BottomPen.new
256
+ apply_border_style(style.box.bottom_pen, xls_border.bottom)
257
+ end
258
+
259
+ end
260
+ end
261
+
262
+ # Alignment
263
+ if xf.apply_alignment
264
+
265
+ #byebug if a_style_index == 111
266
+ unless xf.alignment.nil?
267
+ case xf.alignment.horizontal
268
+ when 'left', nil
269
+ style.h_text_align ='Left'
270
+ when 'center'
271
+ style.h_text_align ='Center'
272
+ when 'right'
273
+ style.h_text_align ='Right'
274
+ end
275
+
276
+ case xf.alignment.vertical
277
+ when 'top'
278
+ style.v_text_align ='Top'
279
+ when 'center'
280
+ style.v_text_align ='Middle'
281
+ when 'bottom', nil
282
+ style.v_text_align ='Bottom'
283
+ end
284
+
285
+ # rotation
286
+ case xf.alignment.text_rotation
287
+ when nil
288
+ style.rotation = nil
289
+ when 0
290
+ style.rotation = 'None'
291
+ when 90
292
+ style.rotation = 'Left'
293
+ when 180
294
+ style.rotation = 'UpsideDown'
295
+ when 270
296
+ style.rotation = 'Right'
297
+ end
298
+ end
299
+ end
300
+
301
+ return style
302
+
303
+ end
304
+
305
+ def apply_border_style (a_pen, a_xls_border_style)
306
+ case a_xls_border_style.style
307
+ when 'thin'
308
+ a_pen.line_width = 0.5
309
+ a_pen.line_style = 'Solid'
310
+ when 'medium'
311
+ a_pen.line_width = 1.0
312
+ a_pen.line_style = 'Solid'
313
+ when 'dashed'
314
+ a_pen.line_width = 1.0
315
+ a_pen.line_style = 'Dotted'
316
+ when 'dotted'
317
+ a_pen.line_width = 0.5
318
+ a_pen.line_style = 'Dotted'
319
+ when 'thick'
320
+ a_pen.line_width = 2.0
321
+ a_pen.line_style = 'Solid'
322
+ when 'double'
323
+ a_pen.line_width = 0.5
324
+ a_pen.line_style = 'Double'
325
+ when 'hair'
326
+ a_pen.line_width = 0.25
327
+ a_pen.line_style = 'Solid'
328
+ when 'mediumDashed'
329
+ a_pen.line_width = 1.0
330
+ a_pen.line_style = 'Dashed'
331
+ when 'dashDot'
332
+ a_pen.line_width = 0.5
333
+ a_pen.line_style = 'Dashed'
334
+ when 'mediumDashDot'
335
+ a_pen.line_width = 1.0
336
+ a_pen.line_style = 'Dashed'
337
+ when 'dashDotDot'
338
+ a_pen.line_width = 0.5
339
+ a_pen.line_style = 'Dotted'
340
+ when 'slantDashDot'
341
+ a_pen.line_width = 0.5
342
+ a_pen.line_style = 'Dotted'
343
+ else
344
+ a_pen.line_width = 1.0
345
+ a_pen.line_style = 'Solid'
346
+ end
347
+ a_pen.line_color = convert_color(a_xls_border_style.color)
348
+ end
349
+
350
+ def convert_color (a_xls_color)
351
+ if a_xls_color.indexed.nil?
352
+ if a_xls_color.theme != nil
353
+ cs = @workbook.theme.a_theme_elements.a_clr_scheme
354
+ case a_xls_color.theme
355
+ when 0
356
+ return tint_theme_color(cs.a_lt1, a_xls_color.tint)
357
+ when 1
358
+ return tint_theme_color(cs.a_dk1, a_xls_color.tint)
359
+ when 2
360
+ return tint_theme_color(cs.a_lt2, a_xls_color.tint)
361
+ when 3
362
+ return tint_theme_color(cs.a_dk2, a_xls_color.tint)
363
+ when 4
364
+ return tint_theme_color(cs.a_accent1, a_xls_color.tint)
365
+ when 5
366
+ return tint_theme_color(cs.a_accent2, a_xls_color.tint)
367
+ when 6
368
+ return tint_theme_color(cs.a_accent3, a_xls_color.tint)
369
+ when 7
370
+ return tint_theme_color(cs.a_accent4, a_xls_color.tint)
371
+ when 8
372
+ return tint_theme_color(cs.a_accent5, a_xls_color.tint)
373
+ when 9
374
+ return tint_theme_color(cs.a_accent6, a_xls_color.tint)
375
+ else
376
+ return '#c0c0c0'
377
+ end
378
+
379
+ elsif a_xls_color.auto or a_xls_color.rgb.nil?
380
+ return '#000000'
381
+ else
382
+ return '#' + a_xls_color.rgb[2..-1]
383
+ end
384
+ else
385
+ return '#' + @@CT_IndexedColors[a_xls_color.indexed]
386
+ end
387
+ end
388
+
389
+ def tint_theme_color (a_color, a_tint)
390
+ color = a_color.a_sys_clr.last_clr unless a_color.a_sys_clr.nil?
391
+ color ||= a_color.a_srgb_clr.val
392
+ r = color[0..1].to_i(16)
393
+ g = color[2..3].to_i(16)
394
+ b = color[4..5].to_i(16)
395
+ unless a_tint.nil?
396
+ if ( a_tint < 0 )
397
+ a_tint = 1 + a_tint;
398
+ r = r * a_tint
399
+ g = g * a_tint
400
+ b = b * a_tint
401
+ else
402
+ r = r + (a_tint * (255 - r))
403
+ g = g + (a_tint * (255 - g))
404
+ b = b + (a_tint * (255 - b))
405
+ end
406
+ end
407
+ r = 255 if r > 255
408
+ g = 255 if g > 255
409
+ b = 255 if b > 255
410
+ color = "#%02X%02X%02X" % [r, g, b]
411
+ color
412
+ end
413
+
414
+ def parse_sheets
415
+ @workbook.worksheets.each do |ws|
416
+ @worksheet = ws
417
+ @raw_width = 0
418
+ @current_band = nil
419
+ @band_type = nil
420
+ for col in (1 .. @worksheet.dimension.ref.col_range.end)
421
+ @raw_width += get_column_width(@worksheet, col)
422
+ end
423
+ generate_bands()
424
+ end
425
+ end
426
+
427
+ def generate_bands ()
428
+
429
+ for row in @worksheet.dimension.ref.row_range
430
+ next if @worksheet[row].nil?
431
+ next if @worksheet[row][0].nil?
432
+ row_tag = map_row_tag(@worksheet[row][0].value.to_s)
433
+ next if row_tag.nil?
434
+
435
+ if @band_type != row_tag
436
+ adjust_band_height()
437
+ process_row_mtag(row, row_tag)
438
+ @first_row_in_band = row
439
+ end
440
+ unless @current_band.nil?
441
+ generate_band_content(row)
442
+ end
443
+ end
444
+
445
+ adjust_band_height()
446
+ end
447
+
448
+ def process_row_mtag (a_row, a_row_tag)
449
+ if a_row_tag.nil? or a_row_tag.lines.size == 0
450
+ process_row_tag(a_row, a_row_tag)
451
+ else
452
+ a_row_tag.lines.each do |tag|
453
+ process_row_tag(a_row, tag)
454
+ end
455
+ end
456
+ end
457
+
458
+ def process_row_tag (a_row, a_row_tag)
459
+
460
+ case a_row_tag
461
+ when /CasperBinding:*/
462
+ @use_casper_bindings = a_row_tag.split(':')[1].strip == 'true'
463
+ when /BG\d*:/
464
+ @report.background ||= Background.new
465
+ @current_band = Band.new
466
+ @report.background.bands << @current_band
467
+ @band_type = a_row_tag
468
+ when /TL\d*:/
469
+ @report.title ||= Title.new
470
+ @current_band = Band.new
471
+ @report.title.bands << @current_band
472
+ @band_type = a_row_tag
473
+ when /PH\d*:/
474
+ @report.page_header ||= PageHeader.new
475
+ @current_band = Band.new
476
+ @report.page_header.bands << @current_band
477
+ @band_type = a_row_tag
478
+ when /CH\d*:/
479
+ @report.column_header ||= ColumnHeader.new
480
+ @current_band = Band.new
481
+ @report.column_header.bands << @current_band
482
+ @band_type = a_row_tag
483
+ when /DT\d*/
484
+ @report.detail ||= Detail.new
485
+ @current_band = Band.new
486
+ @report.detail.bands << @current_band
487
+ @band_type = a_row_tag
488
+ when /CF\d*:/
489
+ @report.column_footer ||= ColumnFooter.new
490
+ @current_band = Band.new
491
+ @report.column_footer.bands << @current_band
492
+ @band_type = a_row_tag
493
+ when /PF\d*:/
494
+ @report.page_footer ||= PageFooter.new
495
+ @current_band = Band.new
496
+ @report.page_footer.bands << @current_band
497
+ @band_type = a_row_tag
498
+ when /LPF\d*:/
499
+ @report.last_page_footer ||= LastPageFooter.new
500
+ @current_band = Band.new
501
+ @report.last_page_footer.bands << @current_band
502
+ @band_type = a_row_tag
503
+ when /SU\d*:/
504
+ @report.summary ||= Summary.new
505
+ @current_band = Band.new
506
+ @report.summary.bands << @current_band
507
+ @band_type = a_row_tag
508
+ when /ND\d*:/
509
+ @report.no_data ||= NoData.new
510
+ @current_band = Band.new
511
+ @report.no_data.bands << @current_band
512
+ @band_type = a_row_tag
513
+ when /GH\d*:/
514
+ @report.group ||= Group.new
515
+ @current_band = Band.new
516
+ @report.group.group_header.bands << @current_band
517
+ @band_type = a_row_tag
518
+ when /GF\d*:/
519
+ @report.group ||= Group.new
520
+ @current_band = Band.new
521
+ @report.group.group_footer.bands << @current_band
522
+ @band_type = a_row_tag
523
+ when /Orientation:.+/i
524
+ @report.orientation = a_row_tag.split(':')[1].strip
525
+ @report.update_page_size()
526
+ @px_width = @report.page_width - @report.left_margin - @report.right_margin
527
+ when /Size:.+/i
528
+ @report.paper_size = a_row_tag.split(':')[1].strip
529
+ @report.update_page_size()
530
+ @px_width = @report.page_width - @report.left_margin - @report.right_margin
531
+ when /Report.isTitleStartNewPage:.+/i
532
+ @report.is_title_new_page = a_row_tag.split(':')[1].strip == 'true'
533
+ when /Report.leftMargin:.+/i
534
+ @report.left_margin = a_row_tag.split(':')[1].strip.to_i
535
+ @px_width = @report.page_width - @report.left_margin - @report.right_margin
536
+ when /Report.rightMargin:.+/i
537
+ @report.right_margin = a_row_tag.split(':')[1].strip.to_i
538
+ @px_width = @report.page_width - @report.left_margin - @report.right_margin
539
+ when /Report.topMargin:.+/i
540
+ @report.top_margin = a_row_tag.split(':')[1].strip.to_i
541
+ when /Report.bottomMargin:.+/i
542
+ @report.bottom_margin = a_row_tag.split(':')[1].strip.to_i
543
+ when /VScale:.+/i
544
+ @v_scale = a_row_tag.split(':')[1].strip.to_f
545
+ when /Query:.+/i
546
+ @report.query_string = a_row_tag.split(':')[1].strip
547
+ when /Id:.+/i
548
+ @report.id = a_row_tag.split(':')[1].strip
549
+ when /Group.expression:.+/i
550
+ @report.group ||= Group.new
551
+ @report.group.group_expression = a_row_tag.split(':')[1].strip
552
+ declare_expression_entities(@report.group.group_expression)
553
+ when /Group.isStartNewPage:.+/i
554
+ @report.group ||= Group.new
555
+ @report.group.is_start_new_page = a_row_tag.split(':')[1].strip == 'true'
556
+ when /Group.isReprintHeaderOnEachPage:.+/i
557
+ @report.group ||= Group.new
558
+ @report.group.is_reprint_header_on_each_page = a_row_tag.split(':')[1].strip == 'true'
559
+ when /BasicExpressions:.+/i
560
+ @widget_factory.basic_expressions = a_row_tag.split(':')[1].strip == 'true'
561
+ when /Style:.+/i
562
+ @report.update_extension_style(a_row_tag.split(':')[1].strip, @worksheet[a_row][2])
563
+ @current_band = nil
564
+ @band_type = nil
565
+ else
566
+ @current_band = nil
567
+ @band_type = nil
568
+ end
569
+
570
+ if @current_band != nil && @worksheet.comments != nil && @worksheet.comments.size > 0 && @worksheet.comments[0].comment_list != nil
571
+
572
+ @worksheet.comments[0].comment_list.each do |comment|
573
+ if comment.ref.col_range.begin == 0 && comment.ref.row_range.begin == a_row
574
+ comment.text.to_s.lines.each do |text|
575
+ text.strip!
576
+ next if text == ''
577
+ tag, value = text.split(':')
578
+ next if value.nil? || tag.nil?
579
+ tag.strip!
580
+ value.strip!
581
+ if tag == 'PE' or tag == 'printWhenExpression'
582
+ if @current_band.print_when_expression.nil?
583
+ @current_band.print_when_expression = value
584
+ transform_expression(value) # to force declaration of paramters/fields/variables
585
+ end
586
+ elsif tag == 'lineParentIdField'
587
+ @current_band.properties ||= Array.new
588
+ @current_band.properties << Property.new("epaper.casper.band.patch.op.add.attribute.name", value)
589
+ elsif tag == 'AF' or tag == 'autoFloat'
590
+ @current_band.auto_float = to_b(value)
591
+ elsif tag == 'AS' or tag == 'autoStretch'
592
+ @current_band.auto_stretch = to_b(value)
593
+ elsif tag == 'splitType'
594
+ @current_band.split_type = value
595
+ elsif tag == 'stretchType'
596
+ @current_band.stretch_type = value
597
+ elsif tag == 'dataRowTypeAttrName'
598
+ @current_band.properties ||= Array.new
599
+ @current_band.properties << Property.new("epaper.casper.band.patch.op.add.attribute.data_row_type.name", value)
600
+ end
601
+ end
602
+ end
603
+ end
604
+ end
605
+
606
+ end
607
+
608
+ def map_row_tag (a_row_tag)
609
+ unless @allow_sub_bands
610
+ match = a_row_tag.match(/\A(TL|SU|BG|PH|CH|DT|CF|PF|LPF|ND)\d*:\z/)
611
+ if match != nil and match.size == 2
612
+ return match[1] + ':'
613
+ end
614
+ end
615
+ a_row_tag
616
+ end
617
+
618
+ def to_b (a_value)
619
+ a_value.match(/(true|t|yes|y|1)$/i) != nil
620
+ end
621
+
622
+ def generate_band_content (a_row_idx)
623
+
624
+ row = @worksheet[a_row_idx]
625
+
626
+ max_cell_height = 0
627
+ col_idx = 1
628
+
629
+ while col_idx < row.size do
630
+
631
+ col_span, row_span, cell_width, cell_height = measure_cell(a_row_idx, col_idx)
632
+
633
+ if cell_width != nil
634
+
635
+ if row[col_idx].nil? || row[col_idx].style_index.nil?
636
+ col_idx += col_span
637
+ next
638
+ end
639
+
640
+ if @use_casper_bindings
641
+ field = create_field_with_casper_binding(row[col_idx])
642
+ else
643
+ field = create_field_legacy_mode(row[col_idx])
644
+ end
645
+ field.report_element.x = x_for_column(col_idx)
646
+ field.report_element.y = y_for_row(a_row_idx)
647
+ field.report_element.width = cell_width
648
+ field.report_element.height = cell_height
649
+ field.report_element.style = 'style_' + (row[col_idx].style_index + 1).to_s
650
+
651
+
652
+ if @current_band.stretch_type
653
+ field.report_element.stretch_type = @current_band.stretch_type
654
+ end
655
+
656
+ if @current_band.auto_float and field.report_element.y != 0
657
+ field.report_element.position_type = 'Float'
658
+ end
659
+
660
+ if @current_band.auto_stretch and field.respond_to?('is_stretch_with_overflow')
661
+ field.is_stretch_with_overflow = true
662
+ end
663
+
664
+ # overide here with field by field directives
665
+ process_field_comments(a_row_idx, col_idx, field)
666
+
667
+
668
+ # If the field is from a horizontally merged cell we need to check the right side border
669
+ if col_span > 1
670
+ field.box ||= Box.new
671
+ xf = @workbook.cell_xfs[row[col_idx + col_span - 1].style_index]
672
+ if xf.apply_border
673
+ xls_border = @workbook.borders[xf.border_id]
674
+
675
+ if xls_border.right != nil && xls_border.right.style != nil
676
+ field.box ||= Box.new
677
+ field.box.right_pen = RightPen.new
678
+ apply_border_style(field.box.right_pen, xls_border.right)
679
+ end
680
+ end
681
+ end
682
+
683
+ # If the field is from a vertically merged cell we need to check the bottom side border
684
+ if row_span > 1
685
+ field.box ||= Box.new
686
+ xf = @workbook.cell_xfs[@worksheet[a_row_idx + row_span - 1][col_idx].style_index]
687
+ if xf.apply_border
688
+ xls_border = @workbook.borders[xf.border_id]
689
+
690
+ if xls_border.bottom != nil && xls_border.bottom.style != nil
691
+ field.box ||= Box.new
692
+ field.box.bottom_pen = BottomPen.new
693
+ apply_border_style(field.box.bottom_pen, xls_border.bottom)
694
+ end
695
+ end
696
+ end
697
+ if field_has_graphics(field)
698
+ @current_band.children << field
699
+ @report.style_set.add(field.report_element.style)
700
+ end
701
+ end
702
+ col_idx += col_span
703
+ end
704
+
705
+ end
706
+
707
+ def field_has_graphics (a_field)
708
+ text_empty = false
709
+ has_border = false
710
+ opaque = false
711
+
712
+ if a_field.instance_of?(StaticText)
713
+ if a_field.text.nil? || a_field.text.length == 0
714
+ text_empty = true
715
+ end
716
+ end
717
+
718
+ if a_field.instance_of?(TextField)
719
+ if a_field.text_field_expression.nil? || a_field.text_field_expression.length == 0
720
+ text_empty = true
721
+ end
722
+ end
723
+
724
+ if a_field.box != nil
725
+ if a_field.box.right_pen != nil ||
726
+ a_field.box.left_pen != nil ||
727
+ a_field.box.top_pen != nil ||
728
+ a_field.box.bottom_pen != nil
729
+ has_border = true
730
+ end
731
+ end
732
+
733
+ style = @report.styles[a_field.report_element.style]
734
+ if style != nil
735
+ if style.box != nil
736
+ if style.box.right_pen != nil ||
737
+ style.box.left_pen != nil ||
738
+ style.box.top_pen != nil ||
739
+ style.box.bottom_pen != nil
740
+ has_border = true
741
+ end
742
+ end
743
+ if (style.mode != nil && style.mode == 'Opaque') || style.backcolor
744
+ opaque = true
745
+ end
746
+ end
747
+
748
+ return true if opaque
749
+
750
+ return true if has_border
751
+
752
+ return true unless text_empty
753
+
754
+ return false
755
+ end
756
+
757
+ def create_field_with_casper_binding (a_cell)
758
+
759
+ fid = nil
760
+ expression = a_cell.value.to_s.strip
761
+ binding = @bindings[expression]
762
+
763
+ unless binding.nil?
764
+ case binding.widget
765
+ when 'Combo'
766
+ rv = CasperCombo.new(self, expression)
767
+ when 'Date'
768
+ rv = CasperDate.new(self, expression)
769
+ parameter = Parameter.new('i18n_date_format', 'java.lang.String')
770
+ parameter.default_value_expression = '"dd/MM/yyyy"'
771
+ @report.parameters['i18n_date_format'] = parameter
772
+ when '',nil
773
+ # No widget fall trought
774
+ else
775
+ raise "Unknown widget type: '#{binding.widget}' on binding '#{binding.id}'"
776
+ end
777
+ end
778
+
779
+ unless rv
780
+ case expression
781
+ when /\A\$CB{.+}\z/
782
+ rv = CasperCheckbox.new(self, expression)
783
+
784
+ when /\A\$RB{.+}\z/
785
+ rv = CasperRadioButton.new(self, expression)
786
+
787
+ when /\A\$SE{.+}\z/
788
+ rv = CasperTextField.new(self, expression[4..-2])
789
+
790
+ when /\A\$P{([a-zA-Z0-9_\-#]+)}\z/,
791
+ /\A\$F{([a-zA-Z0-9_\-#]+)}\z/,
792
+ /\A\$V{([a-zA-Z0-9_\-#]+)}\z/
793
+ rv = CasperTextField.new(self, expression)
794
+
795
+ when /.*\$[PFV]{.+}.*/
796
+ rv = CasperTextField.new(self, transform_expression(expression))
797
+
798
+ when /\A\$I{.+}\z/
799
+ rv = Image.new()
800
+
801
+ # copy cell alignment to image
802
+ style = @report.styles['style_' + (a_cell.style_index + 1).to_s]
803
+ rv.v_align = style.v_text_align
804
+ rv.h_align = style.h_text_align
805
+
806
+ unless expression.nil?
807
+ rv.image_expression = transform_expression(expression[3..expression.length-2])
808
+ end
809
+
810
+ end
811
+
812
+ end
813
+
814
+ byebug if not rv.nil? and rv.text_field_expression.nil?
815
+
816
+ unless rv
817
+ rv = StaticText.new
818
+ rv.text = expression
819
+ end
820
+
821
+ return rv
822
+
823
+ end
824
+
825
+ def create_field_legacy_mode (a_cell)
826
+
827
+ fid = nil
828
+ expression = a_cell.value.to_s
829
+ if ! (m = /\A\$P{([a-zA-Z0-9_\-#]+)}\z/.match expression.strip).nil?
830
+
831
+ # parameter
832
+ f_id = expression.strip
833
+ rv = @widget_factory.new_for_field(f_id, self)
834
+ rv.text_field_expression = expression
835
+
836
+ add_parameter(f_id, m[1])
837
+
838
+ elsif ! (m = /\A\$F{([a-zA-Z0-9_\-#]+)}\z/.match expression.strip).nil?
839
+
840
+ # field
841
+ f_id = expression.strip
842
+ rv = @widget_factory.new_for_field(f_id, self)
843
+ rv.text_field_expression = expression
844
+
845
+ add_field(f_id.strip, m[1])
846
+
847
+ elsif ! (m = /\A\$V{([a-zA-Z0-9_\-#]+)}\z/.match expression.strip).nil?
848
+
849
+ # variable
850
+ f_id = expression.strip
851
+ rv = @widget_factory.new_for_field(f_id, self)
852
+ rv.text_field_expression = expression
853
+
854
+ add_variable(f_id, m[1])
855
+
856
+ elsif ! (m = /\A\$C{(.+)}\z/.match expression.strip).nil?
857
+
858
+ # combo
859
+ combo = @widget_factory.new_combo(expression.strip)
860
+ rv = combo[:widget]
861
+ f_id = combo[:field]
862
+ f_nm = f_id[3..f_id.length-2]
863
+ d_fld = nil != combo[:display_field] ? combo[:display_field] : "name"
864
+
865
+ if f_id.match(/^\$P{/)
866
+ add_parameter(f_id, f_nm)
867
+ elsif combo[:field].match(/^\$F{/)
868
+ add_field(f_id, f_nm)
869
+ elsif combo[:field].match(/^\$V{/)
870
+ add_variable(f_id, f_nm)
871
+ else
872
+ raise ArgumentError, "Don't know how to add '#{f_id}'!"
873
+ end
874
+
875
+ rv.text_field_expression = "TABLE_ITEM(\"#{combo[:id]}\";\"id\";#{f_id};\"#{d_fld}\")"
876
+
877
+ elsif expression.match(/^\$CB{/)
878
+
879
+ # checkbox
880
+ checkbox = @widget_factory.new_checkbox(expression.strip)
881
+ declare_expression_entities(expression.strip)
882
+ rv = checkbox[:widget]
883
+
884
+ elsif expression.match(/^\$RB{/)
885
+
886
+ # radio button
887
+ declare_expression_entities(expression.strip)
888
+ radio_button = @widget_factory.new_radio_button(expression.strip)
889
+ rv = radio_button[:widget]
890
+
891
+ elsif expression.match(/^\$DE{/)
892
+
893
+ declare_expression_entities(expression.strip)
894
+ de = expression.strip.split(',')
895
+ de[0] = de[0][4..de[0].length-1]
896
+ de[1] = de[1][0..de[1].length-2]
897
+
898
+ properties = [
899
+ Property.new("epaper.casper.text.field.editable", "false"),
900
+ Property.new("epaper.casper.text.field.editable.field_name", de[0][3..de[0].length-2])
901
+ ]
902
+
903
+ rv = TextField.new(a_properties = properties, a_pattern = nil, a_pattern_expression = nil)
904
+ rv.text_field_expression = de[1]
905
+
906
+ elsif expression.match(/^\$SE{/)
907
+
908
+ declare_expression_entities(expression.strip)
909
+ expression = expression.strip
910
+ rv = TextField.new(a_properties = nil, a_pattern = nil, a_pattern_expression = nil)
911
+ rv.text_field_expression = expression[4..expression.length-2]
912
+
913
+ elsif expression.match(/^\$I{/)
914
+
915
+ rv = Image.new()
916
+
917
+ # copy cell alignment to image
918
+ style = @report.styles['style_' + (a_cell.style_index + 1).to_s]
919
+ rv.v_align = style.v_text_align
920
+ rv.h_align = style.h_text_align
921
+
922
+ unless expression.nil?
923
+ expression = expression.strip
924
+ rv.image_expression = transform_expression(expression[3..expression.length-2])
925
+ end
926
+
927
+ elsif expression.include? '$P{' or expression.include? '$F{' or expression.include? '$V{'
928
+
929
+ expression = transform_expression(expression)
930
+ rv = TextField.new(a_properties = nil, a_pattern = nil, a_pattern_expression = nil)
931
+ rv.text_field_expression = expression.strip
932
+
933
+ else
934
+
935
+ rv = StaticText.new
936
+ rv.text = expression
937
+
938
+ end
939
+
940
+ if !f_id.nil? && rv.is_a?(TextField)
941
+ if @widget_factory.java_class(f_id) == 'java.util.Date'
942
+ rv.text_field_expression = "DateFormat.parse(#{rv.text_field_expression},\"yyyy-MM-dd\")"
943
+ rv.pattern_expression = "$P{i18n_date_format}"
944
+ rv.report_element.properties << Property.new('epaper.casper.text.field.patch.pattern', 'yyyy-MM-dd') unless rv.report_element.properties.nil?
945
+ parameter = Parameter.new('i18n_date_format', 'java.lang.String')
946
+ parameter.default_value_expression = '"dd/MM/yyyy"'
947
+ @report.parameters['i18n_date_format'] = parameter
948
+ end
949
+ end
950
+ return rv
951
+ end
952
+
953
+ def declare_expression_entities (a_expression)
954
+
955
+ a_expression.scan(/\$[A-Z]{[a-z_0-9\.\-#]+}/) { |v|
956
+ f_id = (/\A\$[PFV]{(.+)}\z/.match v).to_s
957
+ if false == f_id.nil?
958
+ f_nm = f_id[3..-2]
959
+ if f_id.match(/^\$P{/)
960
+ add_parameter(f_id, f_nm)
961
+ elsif f_id.match(/^\$F{/)
962
+ add_field(f_id, f_nm)
963
+ elsif f_id.match(/^\$V{/)
964
+ add_variable(f_id, f_nm)
965
+ else
966
+ raise ArgumentError, "Don't know how to add '#{f_id}'!"
967
+ end
968
+ end
969
+ }
970
+ nil
971
+ end
972
+
973
+ def process_field_comments (a_row, a_col, a_field)
974
+
975
+ if @worksheet.comments != nil && @worksheet.comments.size > 0 && @worksheet.comments[0].comment_list != nil
976
+
977
+ @worksheet.comments[0].comment_list.each do |comment|
978
+ if comment.ref.col_range.begin == a_col && comment.ref.row_range.begin == a_row
979
+ comment.text.to_s.lines.each do |text|
980
+ text.strip!
981
+ next if text == '' or text.nil?
982
+ idx = text.index(':')
983
+ next if idx.nil?
984
+ tag = text[0..(idx-1)]
985
+ value = text[(idx+1)..-1]
986
+ next if tag.nil? or value.nil?
987
+ tag.strip!
988
+ value.strip!
989
+
990
+ if tag == 'PE' or tag == 'printWhenExpression'
991
+ a_field.report_element.print_when_expression = value
992
+ transform_expression(value) # to force declaration of paramters/fields/variables
993
+ elsif tag == 'AF' or tag == 'autoFloat'
994
+ a_field.report_element.position_type = to_b(value) ? 'Float' : 'FixRelativeToTop'
995
+ elsif tag == 'AS' or tag == 'autoStretch' and a_field.respond_to?(:is_stretch_with_overflow)
996
+ a_field.is_stretch_with_overflow = to_b(value)
997
+ elsif tag == 'ST' or tag == 'stretchType'
998
+ a_field.report_element.stretch_type = value
999
+ elsif tag == 'BN' or tag == 'blankIfNull' and a_field.respond_to?(:is_blank_when_null)
1000
+ a_field.is_blank_when_null = to_b(value)
1001
+ elsif tag == 'PT' or tag == 'pattern' and a_field.respond_to?(:pattern)
1002
+ a_field.pattern = value
1003
+ elsif tag == 'ET' or tag == 'evaluationTime' and a_field.respond_to?(:evaluation_time)
1004
+ a_field.evaluation_time = value
1005
+ elsif tag == 'DE' or tag == 'disabledExpression'
1006
+ if a_field.respond_to? :disabled_conditional
1007
+ a_field.disabled_conditional(value)
1008
+ else
1009
+ a_field.report_element.properties ||= Array.new
1010
+ a_field.report_element.properties << PropertyExpression.new('epaper.casper.text.field.disabled.if', value)
1011
+ end
1012
+ transform_expression(value) # to force declaration of parameters/fields/variables
1013
+ elsif tag == 'SE' or tag == 'styleExpression'
1014
+ if a_field.respond_to? :style_expression
1015
+ a_field.style_expression(value)
1016
+ else
1017
+ a_field.report_element.properties ||= Array.new
1018
+ a_field.report_element.properties << PropertyExpression.new('epaper.casper.style.condition', value)
1019
+ end
1020
+ transform_expression(value) # to force declaration of parameters/fields/variables
1021
+ elsif tag == 'RIC' or tag == 'reloadIfChanged'
1022
+ if a_field.respond_to? :reload_if_changed
1023
+ a_field.reload_if_changed(value)
1024
+ else
1025
+ a_field.report_element.properties ||= Array.new
1026
+ a_field.report_element.properties << Property.new('epaper.casper.text.field.reload.if_changed', value)
1027
+ end
1028
+ elsif tag == 'EE' or tag == 'editableExpression'
1029
+ if a_field.respond_to? :enabled_conditional
1030
+ a_field.enabled_conditional(value)
1031
+ else
1032
+ a_field.report_element.properties ||= Array.new
1033
+ a_field.report_element.properties << PropertyExpression.new('epaper.casper.text.field.editable.if', value)
1034
+ end
1035
+ transform_expression(value) # to force declaration of paramters/fields/variables
1036
+ end
1037
+ end
1038
+
1039
+ end
1040
+ end
1041
+ end
1042
+ end
1043
+
1044
+ def transform_expression (a_expression)
1045
+ matches = a_expression.split(/(\$[PVF]{[a-zA-Z0-9\._]+})/)
1046
+ if matches.nil?
1047
+ return a_expression
1048
+ end
1049
+ terms = Array.new
1050
+ matches.each do |match|
1051
+ if match.length == 0
1052
+ next
1053
+ elsif match.start_with?('$P{')
1054
+ terms << match
1055
+ add_parameter(match, match[3..-2])
1056
+ elsif match.start_with?('$F{')
1057
+ terms << match
1058
+ add_field(match, match[3..-2])
1059
+ elsif match.start_with?('$V{')
1060
+ terms << match
1061
+ add_variable(match, match[3..-2])
1062
+ else
1063
+ terms << '"' + match + '"'
1064
+ end
1065
+ end
1066
+ terms.join(' + ')
1067
+ end
1068
+
1069
+ def add_parameter (a_id, a_name)
1070
+ unless @report.parameters.has_key? a_name
1071
+ parameter = Parameter.new(a_name, @widget_factory.java_class(a_id))
1072
+ if @bindings.has_key? a_id
1073
+ binding = @bindings[a_id]
1074
+ if binding.respond_to? 'default' and binding.default != nil and binding.default.strip != ''
1075
+ if binding.java_class == 'java.lang.String'
1076
+ parameter.default_value_expression = "\"#{binding.default.strip}\""
1077
+ else
1078
+ parameter.default_value_expression = binding.default.strip
1079
+ end
1080
+ end
1081
+ end
1082
+ @report.parameters[a_name] = parameter
1083
+ end
1084
+ end
1085
+
1086
+ def add_field (a_id, a_name)
1087
+ unless @report.fields.has_key? a_name
1088
+ field = Field.new(a_name, @widget_factory.java_class(a_id))
1089
+ @report.fields[a_name] = field
1090
+ end
1091
+ end
1092
+
1093
+ def add_variable (a_id, a_name)
1094
+ if "PAGE_NUMBER" != a_name
1095
+ unless @report.variables.has_key? a_name
1096
+ variable = Variable.new(a_name, @widget_factory.java_class(a_id))
1097
+ @report.variables[a_name] = variable
1098
+ end
1099
+ end
1100
+ end
1101
+
1102
+ def get_column_width (a_worksheet, a_index)
1103
+ width = a_worksheet.get_column_width_raw(a_index)
1104
+ width ||= RubyXL::ColumnRange::DEFAULT_WIDTH
1105
+ return width
1106
+ end
1107
+
1108
+
1109
+ def x_for_column (a_col_idx)
1110
+
1111
+ width = 0
1112
+ for idx in (1 .. a_col_idx - 1) do
1113
+ width += get_column_width(@worksheet, idx)
1114
+ end
1115
+ return scale_x(width).round
1116
+
1117
+ end
1118
+
1119
+ def y_for_row (a_row_idx)
1120
+ height = 0
1121
+ for idx in (@first_row_in_band .. a_row_idx - 1) do
1122
+ height += @worksheet.get_row_height(idx)
1123
+ end
1124
+ return scale_y(height).round
1125
+ end
1126
+
1127
+ def adjust_band_height ()
1128
+
1129
+ return if @current_band.nil?
1130
+
1131
+ height = 0
1132
+ for row in @worksheet.dimension.ref.row_range
1133
+ unless @worksheet[row].nil? or @worksheet[row][0].nil? or @worksheet[row][0].value.nil? or map_row_tag(@worksheet[row][0].value) != @band_type
1134
+ height += y_for_row(row + 1) - y_for_row(row)
1135
+ end
1136
+ end
1137
+
1138
+ @current_band.height = height
1139
+ end
1140
+
1141
+ def measure_cell (a_row_idx, a_col_idx)
1142
+
1143
+ @worksheet.merged_cells.each do |merged_cell|
1144
+
1145
+ col_span = merged_cell.ref.col_range.size
1146
+ row_span = merged_cell.ref.row_range.size
1147
+
1148
+ if a_row_idx == merged_cell.ref.row_range.begin && a_col_idx == merged_cell.ref.col_range.begin
1149
+
1150
+ cell_height = y_for_row(merged_cell.ref.row_range.end + 1) - y_for_row(merged_cell.ref.row_range.begin)
1151
+ cell_width = x_for_column(merged_cell.ref.col_range.end + 1) - x_for_column(merged_cell.ref.col_range.begin)
1152
+
1153
+ return col_span, row_span, cell_width, cell_height
1154
+
1155
+ elsif merged_cell.ref.row_range.include?(a_row_idx) and merged_cell.ref.col_range.include?(a_col_idx)
1156
+
1157
+ # The cell is overlaped by a merged cell
1158
+ return col_span, row_span, nil, nil
1159
+
1160
+ end
1161
+ end
1162
+
1163
+ cell_height = y_for_row(a_row_idx + 1) - y_for_row(a_row_idx)
1164
+ cell_width = x_for_column(a_col_idx + 1) - x_for_column(a_col_idx)
1165
+ return 1, 1, cell_width, cell_height
1166
+
1167
+ end
1168
+
1169
+ def scale_x (a_width)
1170
+ return (a_width * @px_width / @raw_width)
1171
+ end
1172
+
1173
+ def scale_y (a_height)
1174
+ return (a_height * @v_scale)
1175
+ end
1176
+
1177
+
1178
+ end # class ExcelToJrxml
1179
+
1180
+ end
1181
+ end
1182
+ end
1183
+ end