write_xlsx 0.90.0 → 0.97.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/Changes +37 -0
  3. data/README.md +1 -1
  4. data/examples/a_simple.rb +1 -6
  5. data/examples/conditional_format.rb +73 -46
  6. data/examples/demo.rb +1 -7
  7. data/examples/hyperlink1.rb +4 -11
  8. data/lib/write_xlsx/chart.rb +81 -205
  9. data/lib/write_xlsx/chart/axis.rb +2 -2
  10. data/lib/write_xlsx/chart/caption.rb +3 -1
  11. data/lib/write_xlsx/chart/pie.rb +2 -0
  12. data/lib/write_xlsx/chart/series.rb +11 -7
  13. data/lib/write_xlsx/format.rb +15 -11
  14. data/lib/write_xlsx/package/conditional_format.rb +351 -38
  15. data/lib/write_xlsx/package/content_types.rb +10 -0
  16. data/lib/write_xlsx/package/custom.rb +125 -0
  17. data/lib/write_xlsx/package/packager.rb +26 -0
  18. data/lib/write_xlsx/package/styles.rb +53 -21
  19. data/lib/write_xlsx/package/table.rb +11 -4
  20. data/lib/write_xlsx/utility.rb +234 -34
  21. data/lib/write_xlsx/version.rb +1 -1
  22. data/lib/write_xlsx/workbook.rb +88 -1
  23. data/lib/write_xlsx/worksheet.rb +247 -23
  24. data/test/helper.rb +6 -1
  25. data/test/regression/_test_hyperlink31.rb +26 -0
  26. data/test/regression/images/zero_dpi.jpg +0 -0
  27. data/test/regression/test_chart_bar08.rb +3 -0
  28. data/test/regression/test_chart_bar11.rb +3 -0
  29. data/test/regression/test_chart_bar14.rb +3 -0
  30. data/test/regression/test_chart_chartarea05.rb +16 -17
  31. data/test/regression/test_chart_chartarea06.rb +49 -0
  32. data/test/regression/test_chart_data_labels25.rb +61 -0
  33. data/test/regression/test_chart_format26.rb +48 -0
  34. data/test/regression/test_chart_format27.rb +58 -0
  35. data/test/regression/test_chart_format28.rb +52 -0
  36. data/test/regression/test_chart_format29.rb +59 -0
  37. data/test/regression/test_chart_format30.rb +53 -0
  38. data/test/regression/test_chart_format31.rb +60 -0
  39. data/test/regression/test_chart_table03.rb +56 -0
  40. data/test/regression/test_cond_format14.rb +42 -0
  41. data/test/regression/test_cond_format15.rb +53 -0
  42. data/test/regression/test_cond_format16.rb +53 -0
  43. data/test/regression/test_cond_format17.rb +37 -0
  44. data/test/regression/test_cond_format18.rb +136 -0
  45. data/test/regression/test_date_1904_01.rb +1 -1
  46. data/test/regression/test_escapes04.rb +3 -0
  47. data/test/regression/test_escapes05.rb +3 -0
  48. data/test/regression/test_escapes07.rb +3 -0
  49. data/test/regression/test_escapes08.rb +3 -0
  50. data/test/regression/test_hyperlink01.rb +3 -0
  51. data/test/regression/test_hyperlink02.rb +3 -0
  52. data/test/regression/test_hyperlink03.rb +4 -0
  53. data/test/regression/test_hyperlink04.rb +3 -0
  54. data/test/regression/test_hyperlink05.rb +3 -0
  55. data/test/regression/test_hyperlink06.rb +3 -0
  56. data/test/regression/test_hyperlink07.rb +3 -0
  57. data/test/regression/test_hyperlink08.rb +3 -0
  58. data/test/regression/test_hyperlink09.rb +3 -0
  59. data/test/regression/test_hyperlink10.rb +3 -0
  60. data/test/regression/test_hyperlink11.rb +3 -0
  61. data/test/regression/test_hyperlink12.rb +3 -0
  62. data/test/regression/test_hyperlink13.rb +3 -0
  63. data/test/regression/test_hyperlink14.rb +3 -0
  64. data/test/regression/test_hyperlink15.rb +3 -0
  65. data/test/regression/test_hyperlink16.rb +3 -0
  66. data/test/regression/test_hyperlink17.rb +3 -0
  67. data/test/regression/test_hyperlink18.rb +3 -0
  68. data/test/regression/test_hyperlink20.rb +3 -0
  69. data/test/regression/test_hyperlink21.rb +3 -0
  70. data/test/regression/test_hyperlink22.rb +3 -0
  71. data/test/regression/test_hyperlink23.rb +3 -0
  72. data/test/regression/test_hyperlink24.rb +3 -0
  73. data/test/regression/test_hyperlink25.rb +3 -0
  74. data/test/regression/test_hyperlink26.rb +3 -0
  75. data/test/regression/test_hyperlink27.rb +3 -0
  76. data/test/regression/test_hyperlink28.rb +50 -0
  77. data/test/regression/test_hyperlink29.rb +27 -0
  78. data/test/regression/test_hyperlink30.rb +36 -0
  79. data/test/regression/test_image35.rb +26 -0
  80. data/test/regression/test_properties01.rb +1 -4
  81. data/test/regression/test_properties02.rb +1 -4
  82. data/test/regression/test_properties03.rb +26 -0
  83. data/test/regression/test_properties04.rb +61 -0
  84. data/test/regression/test_properties05.rb +30 -0
  85. data/test/regression/test_table03.rb +3 -0
  86. data/test/regression/test_table04.rb +3 -0
  87. data/test/regression/test_table05.rb +3 -0
  88. data/test/regression/test_table06.rb +3 -0
  89. data/test/regression/test_table20.rb +34 -0
  90. data/test/regression/test_table21.rb +36 -0
  91. data/test/regression/test_table22.rb +32 -0
  92. data/test/regression/xlsx_files/chart_chartarea05.xlsx +0 -0
  93. data/test/regression/xlsx_files/chart_chartarea06.xlsx +0 -0
  94. data/test/regression/xlsx_files/chart_data_labels25.xlsx +0 -0
  95. data/test/regression/xlsx_files/chart_format26.xlsx +0 -0
  96. data/test/regression/xlsx_files/chart_format27.xlsx +0 -0
  97. data/test/regression/xlsx_files/chart_format28.xlsx +0 -0
  98. data/test/regression/xlsx_files/chart_format29.xlsx +0 -0
  99. data/test/regression/xlsx_files/chart_format30.xlsx +0 -0
  100. data/test/regression/xlsx_files/chart_format31.xlsx +0 -0
  101. data/test/regression/xlsx_files/chart_table03.xlsx +0 -0
  102. data/test/regression/xlsx_files/cond_format14.xlsx +0 -0
  103. data/test/regression/xlsx_files/cond_format15.xlsx +0 -0
  104. data/test/regression/xlsx_files/cond_format16.xlsx +0 -0
  105. data/test/regression/xlsx_files/cond_format17.xlsx +0 -0
  106. data/test/regression/xlsx_files/cond_format18.xlsx +0 -0
  107. data/test/regression/xlsx_files/date_1904_01.xlsx +0 -0
  108. data/test/regression/xlsx_files/hyperlink28.xlsx +0 -0
  109. data/test/regression/xlsx_files/hyperlink29.xlsx +0 -0
  110. data/test/regression/xlsx_files/hyperlink30.xlsx +0 -0
  111. data/test/regression/xlsx_files/hyperlink31.xlsx +0 -0
  112. data/test/regression/xlsx_files/image35.xlsx +0 -0
  113. data/test/regression/xlsx_files/properties03.xlsx +0 -0
  114. data/test/regression/xlsx_files/properties04.xlsx +0 -0
  115. data/test/regression/xlsx_files/properties05.xlsx +0 -0
  116. data/test/regression/xlsx_files/table21.xlsx +0 -0
  117. data/test/regression/xlsx_files/table22.xlsx +0 -0
  118. data/test/workbook/test_write_workbook_view.rb +81 -0
  119. data/test/worksheet/test_cond_format_22.rb +266 -0
  120. data/test/worksheet/test_cond_format_23.rb +242 -0
  121. data/test/worksheet/test_cond_format_24.rb +303 -0
  122. data/test/worksheet/test_data_bar_01.rb +53 -0
  123. data/test/worksheet/test_data_bar_02.rb +79 -0
  124. data/test/worksheet/test_data_bar_03.rb +147 -0
  125. data/test/worksheet/test_data_bar_04.rb +145 -0
  126. data/test/worksheet/test_data_bar_05.rb +147 -0
  127. data/test/worksheet/test_data_bar_06.rb +145 -0
  128. data/test/worksheet/test_data_bar_07.rb +146 -0
  129. data/test/worksheet/test_data_bar_08.rb +54 -0
  130. data/test/worksheet/test_data_bar_09.rb +80 -0
  131. data/test/worksheet/test_data_bar_10.rb +165 -0
  132. data/test/worksheet/test_data_bar_11.rb +167 -0
  133. data/test/worksheet/test_data_bar_12.rb +104 -0
  134. data/test/worksheet/test_write_data_validation_02.rb +27 -0
  135. metadata +135 -2
@@ -184,8 +184,8 @@ def set_position_axis
184
184
  end
185
185
 
186
186
  def set_font_properties(args)
187
- @num_font = @chart.convert_font_args(args[:num_font])
188
- @name_font = @chart.convert_font_args(args[:name_font])
187
+ @num_font = convert_font_args(args[:num_font])
188
+ @name_font = convert_font_args(args[:name_font])
189
189
  end
190
190
 
191
191
  def set_axis_name_layout(args)
@@ -3,6 +3,8 @@
3
3
  module Writexlsx
4
4
  class Chart
5
5
  class Caption
6
+ include Writexlsx::Utility
7
+
6
8
  attr_accessor :name, :formula, :data_id, :name_font
7
9
  attr_reader :layout, :overlay, :none
8
10
 
@@ -13,7 +15,7 @@ def initialize(chart)
13
15
  def merge_with_hash(params) # :nodoc:
14
16
  @name, @formula = @chart.process_names(params[:name], params[:name_formula])
15
17
  @data_id = @chart.data_id(@formula, params[:data])
16
- @name_font = @chart.convert_font_args(params[:name_font])
18
+ @name_font = convert_font_args(params[:name_font])
17
19
  @layout = @chart.layout_properties(params[:layout], 1)
18
20
 
19
21
  # Set the title overlay option.
@@ -96,6 +96,8 @@ def write_plot_area
96
96
  write_layout(@plotarea.layout, 'plot')
97
97
  # Write the subclass chart type element.
98
98
  write_chart_type
99
+ # Write the c:spPr eleent for the plotarea formatting.
100
+ write_sp_pr(@plotarea)
99
101
  end
100
102
  end
101
103
 
@@ -57,16 +57,20 @@ def initialize(params)
57
57
 
58
58
  class Trendline < Chartline
59
59
  attr_reader :name, :forward, :backward, :order, :period
60
+ attr_reader :intercept, :display_equation, :display_r_squared
60
61
 
61
62
  def initialize(params)
62
63
  super(params)
63
64
 
64
- @name = params[:name]
65
- @forward = params[:forward]
66
- @backward = params[:backward]
67
- @order = params[:order]
68
- @period = params[:period]
69
- @type = value_or_raise(types, params[:type], 'trendline type')
65
+ @name = params[:name]
66
+ @forward = params[:forward]
67
+ @backward = params[:backward]
68
+ @order = params[:order]
69
+ @period = params[:period]
70
+ @intercept = params[:intercept]
71
+ @display_equation = params[:display_equation]
72
+ @display_r_squared = params[:display_r_squared]
73
+ @type = value_or_raise(types, params[:type], 'trendline type')
70
74
  end
71
75
 
72
76
  private
@@ -293,7 +297,7 @@ def labels_properties(labels) # :nodoc:
293
297
  end
294
298
 
295
299
  if labels[:font]
296
- labels[:font] = @chart.convert_font_args(labels[:font])
300
+ labels[:font] = convert_font_args(labels[:font])
297
301
  end
298
302
 
299
303
  labels
@@ -163,7 +163,7 @@ class Format
163
163
  include Writexlsx::Utility
164
164
 
165
165
  attr_reader :xf_index, :dxf_index, :num_format # :nodoc:
166
- attr_reader :underline, :font_script, :size, :theme, :font, :font_family, :hyperlink # :nodoc:
166
+ attr_reader :underline, :font_script, :size, :theme, :font, :font_family, :hyperlink, :xf_id # :nodoc:
167
167
  attr_reader :diag_type, :diag_color, :font_only, :color, :color_indexed # :nodoc:
168
168
  attr_reader :left, :left_color, :right, :right_color, :top, :top_color, :bottom, :bottom_color # :nodoc:
169
169
  attr_reader :font_scheme # :nodoc:
@@ -200,6 +200,7 @@ def initialize(formats, params = {}) # :nodoc:
200
200
  @font_extend = 0
201
201
  @theme = 0
202
202
  @hyperlink = 0
203
+ @xf_id = 0
203
204
 
204
205
  @hidden = 0
205
206
  @locked = 1
@@ -396,7 +397,8 @@ def get_font_key
396
397
  @font,
397
398
  @italic,
398
399
  @size,
399
- @underline
400
+ @underline,
401
+ @theme
400
402
  ].join(':')
401
403
  end
402
404
 
@@ -593,15 +595,15 @@ def set_rotation(rotation)
593
595
  end
594
596
 
595
597
  #
596
- # Set the properties for the hyperlink style. TODO. This doesn't currently
597
- # work. Fix it when styles are supported.
598
+ # Set the properties for the hyperlink style. This isn't a public method. To
599
+ # be fixed when styles are supported.
598
600
  #
599
- def set_hyperlink
600
- @hyperlink = 1
601
+ def set_hyperlink(hyperlink)
602
+ @xf_id = 1
601
603
 
602
604
  set_underline(1)
603
605
  set_theme(10)
604
- set_align('top')
606
+ @hyperlink = hyperlink
605
607
  end
606
608
 
607
609
  def set_font_info(fonts)
@@ -804,11 +806,11 @@ def xf_attributes
804
806
  ['fontId' , font_index],
805
807
  ['fillId' , fill_index],
806
808
  ['borderId', border_index],
807
- ['xfId' , 0]
809
+ ['xfId' , xf_id]
808
810
  ]
809
811
  attributes << ['applyNumberFormat', 1] if num_format_index > 0
810
812
  # Add applyFont attribute if XF format uses a font element.
811
- attributes << ['applyFont', 1] if font_index > 0
813
+ attributes << ['applyFont', 1] if font_index > 0 && !ptrue?(@hyperlink)
812
814
  # Add applyFill attribute if XF format uses a fill element.
813
815
  attributes << ['applyFill', 1] if fill_index > 0
814
816
  # Add applyBorder attribute if XF format uses a border element.
@@ -817,8 +819,10 @@ def xf_attributes
817
819
  # Check if XF format has alignment properties set.
818
820
  apply_align, align = get_align_properties
819
821
  # We can also have applyAlignment without a sub-element.
820
- attributes << ['applyAlignment', 1] if apply_align
821
- attributes << ['applyProtection', 1] if get_protection_properties
822
+ attributes << ['applyAlignment', 1] if apply_align || ptrue?(@hyperlink)
823
+ if get_protection_properties || ptrue?(hyperlink)
824
+ attributes << ['applyProtection', 1]
825
+ end
822
826
 
823
827
  attributes
824
828
  end
@@ -7,8 +7,8 @@ class ConditionalFormat
7
7
 
8
8
  def self.factory(worksheet, *args)
9
9
  range, param =
10
- Package::ConditionalFormat.new(worksheet, nil, nil).
11
- range_param_for_conditional_formatting(*args)
10
+ Package::ConditionalFormat.new(worksheet, nil, nil).
11
+ range_param_for_conditional_formatting(*args)
12
12
 
13
13
  case param[:type]
14
14
  when 'cellIs'
@@ -29,6 +29,8 @@ def self.factory(worksheet, *args)
29
29
  DataBarFormat.new(worksheet, range, param)
30
30
  when 'expression'
31
31
  ExpressionFormat.new(worksheet, range, param)
32
+ when 'iconSet'
33
+ IconSetFormat.new(worksheet, range, param)
32
34
  else # when 'duplicateValues', 'uniqueValues'
33
35
  ConditionalFormat.new(worksheet, range, param)
34
36
  end
@@ -59,11 +61,13 @@ def write_formula_tag(data) #:nodoc:
59
61
  #
60
62
  # Write the <cfvo> element.
61
63
  #
62
- def write_cfvo(type, val)
63
- @writer.empty_tag('cfvo', [
64
- ['type', type],
65
- ['val', val]
66
- ])
64
+ def write_cfvo(type, value, criteria = nil)
65
+ attributes = [ ['type', type] ]
66
+ attributes << [ 'val', value] if value
67
+
68
+ attributes << ['gte', 0] if ptrue?(criteria)
69
+
70
+ @writer.empty_tag('cfvo', attributes)
67
71
  end
68
72
 
69
73
  def attributes
@@ -154,6 +158,54 @@ def bar_color
154
158
  @param[:bar_color]
155
159
  end
156
160
 
161
+ def bar_border_color
162
+ @param[:bar_border_color]
163
+ end
164
+
165
+ def bar_negative_color
166
+ @param[:bar_negative_color]
167
+ end
168
+
169
+ def bar_negative_color_same
170
+ @param[:bar_negative_color_same]
171
+ end
172
+
173
+ def bar_no_border
174
+ @param[:bar_no_border]
175
+ end
176
+
177
+ def bar_axis_position
178
+ @param[:bar_axis_position]
179
+ end
180
+
181
+ def bar_axis_color
182
+ @param[:bar_axis_color]
183
+ end
184
+
185
+ def icon_style
186
+ @param[:icon_style]
187
+ end
188
+
189
+ def total_icons
190
+ @param[:total_icons]
191
+ end
192
+
193
+ def icons
194
+ @param[:icons]
195
+ end
196
+
197
+ def icons_only
198
+ @param[:icons_only]
199
+ end
200
+
201
+ def reverse_icons
202
+ @param[:reverse_icons]
203
+ end
204
+
205
+ def bar_only
206
+ @param[:bar_only]
207
+ end
208
+
157
209
  def range_param_for_conditional_formatting(*args) # :nodoc:
158
210
  range_start_cell_for_conditional_formatting(*args)
159
211
  param_for_conditional_formatting(*args)
@@ -274,17 +326,68 @@ def handling_of_blanks_error_types
274
326
  @param[:mid_color] = palette_color(@param[:mid_color])
275
327
  @param[:min_color] = palette_color(@param[:min_color])
276
328
  when 'dataBar'
277
- # Color scales don't use any additional formatting.
329
+ # Excel 2007 data bars don't use any additional formatting.
278
330
  @param[:format] = nil
279
331
 
280
- @param[:min_type] ||= 'min'
281
- @param[:max_type] ||= 'max'
282
- @param[:min_value] ||= 0
283
- @param[:max_value] ||= 0
284
- @param[:bar_color] ||= '#638EC6'
332
+ if !@param[:min_type]
333
+ @param[:min_type] = 'min'
334
+ @param[:x14_min_type] = 'autoMin'
335
+ else
336
+ @param[:x14_min_type] = @param[:min_type]
337
+ end
338
+ if !@param[:max_type]
339
+ @param[:max_type] = 'max'
340
+ @param[:x14_max_type] = 'autoMax'
341
+ else
342
+ @param[:x14_max_type] = @param[:max_type]
343
+ end
344
+
345
+ @param[:min_value] ||= 0
346
+ @param[:max_value] ||= 0
347
+ @param[:bar_color] ||= '#638EC6'
348
+ @param[:bar_border_color] ||= @param[:bar_color]
349
+ @param[:bar_only] ||= 0
350
+ @param[:bar_no_border] ||= 0
351
+ @param[:bar_solid] ||= 0
352
+ @param[:bar_direction] ||= ''
353
+ @param[:bar_negative_color] ||= '#FF0000'
354
+ @param[:bar_negative_border_color] ||= '#FF0000'
355
+ @param[:bar_negative_color_same] ||= 0
356
+ @param[:bar_negative_border_color_same] ||= 0
357
+ @param[:bar_axis_position] ||= ''
358
+ @param[:bar_axis_color] ||= '#000000'
359
+
360
+ @param[:bar_color] =
361
+ palette_color(@param[:bar_color])
362
+ @param[:bar_border_color] =
363
+ palette_color(@param[:bar_border_color])
364
+ @param[:bar_negative_color] =
365
+ palette_color(@param[:bar_negative_color])
366
+ @param[:bar_negative_border_color] =
367
+ palette_color(@param[:bar_negative_border_color])
368
+ @param[:bar_axis_color] =
369
+ palette_color(@param[:bar_axis_color])
370
+ end
371
+
372
+ # Adjust for 2010 style data_bar parameters.
373
+ if ptrue?(@param[:is_data_bar_2010])
374
+ @worksheet.excel_version = 2010
285
375
 
286
- @param[:bar_color] = palette_color(@param[:bar_color])
376
+ if @param[:min_type] == 'min' && @param[:min_value] == 0
377
+ @param[:min_value] = nil
378
+ end
379
+ if @param[:max_type] == 'max' && @param[:max_value] == 0
380
+ @param[:max_value] = nil
381
+ end
382
+
383
+ # Store range for Excel 2010 data bars.
384
+ @param[:range] = range
287
385
  end
386
+
387
+ # Strip the leading = from formulas.
388
+ @param[:min_value] = @param[:min_value].to_s.sub(/^=/, '') if @param[:min_value]
389
+ @param[:mid_value] = @param[:mid_value].to_s.sub(/^=/, '') if @param[:mid_value]
390
+ @param[:max_value] = @param[:max_value].to_s.sub(/^=/, '') if @param[:max_value]
288
391
  end
289
392
 
290
393
  def palette_color(index)
@@ -293,7 +396,7 @@ def palette_color(index)
293
396
 
294
397
  def range_start_cell_for_conditional_formatting(*args) # :nodoc:
295
398
  row1, row2, col1, col2, user_range, param =
296
- row_col_param_for_conditional_formatting(*args)
399
+ row_col_param_for_conditional_formatting(*args)
297
400
  # If the first and last cell are the same write a single cell.
298
401
  if row1 == row2 && col1 == col2
299
402
  range = xl_rowcol_to_cell(row1, col1)
@@ -336,19 +439,32 @@ def row_col_param_for_conditional_formatting(*args)
336
439
 
337
440
  def param_for_conditional_formatting(*args) # :nodoc:
338
441
  dummy, dummy, dummy, dummy, dummy, @param =
339
- row_col_param_for_conditional_formatting(*args)
442
+ row_col_param_for_conditional_formatting(*args)
340
443
  check_conditional_formatting_parameters(@param)
341
444
 
342
445
  @param[:format] = @param[:format].get_dxf_index if @param[:format]
343
446
  @param[:priority] = @worksheet.dxf_priority
447
+
448
+ # Check for 2010 style data_bar parameters.
449
+ %i(data_bar_2010 bar_solid bar_border_color bar_negative_color
450
+ bar_negative_color_same bar_negative_border_color
451
+ bar_negative_border_color_same bar_no_border
452
+ bar_axis_position bar_axis_color bar_direction
453
+ ).each do |key|
454
+ if @param[key]
455
+ @param[:is_data_bar_2010] = 1
456
+ break
457
+ end
458
+ end
459
+
344
460
  @worksheet.dxf_priority += 1
345
461
  end
346
462
 
347
463
  def check_conditional_formatting_parameters(param) # :nodoc:
348
464
  # Check for valid input parameters.
349
- unless (param.keys.uniq - valid_parameter_for_conditional_formatting).empty? &&
350
- param.has_key?(:type) &&
351
- valid_type_for_conditional_formatting.has_key?(param[:type].downcase)
465
+ if !(param.keys.uniq - valid_parameter_for_conditional_formatting).empty? ||
466
+ !param.has_key?(:type) ||
467
+ !valid_type_for_conditional_formatting.has_key?(param[:type].downcase)
352
468
  raise WriteXLSXOptionParameterError, "Invalid type : #{param[:type]}"
353
469
  end
354
470
 
@@ -369,6 +485,32 @@ def check_conditional_formatting_parameters(param) # :nodoc:
369
485
  param[:maximum] = convert_date_time_if_required(param[:maximum])
370
486
  end
371
487
 
488
+ # Set properties for icon sets.
489
+ if param[:type] == 'iconSet'
490
+ if !param[:icon_style]
491
+ raise "The 'icon_style' parameter must be specified when " +
492
+ "'type' == 'icon_set' in conditional_formatting()"
493
+ end
494
+
495
+ # Check for valid icon styles.
496
+ if !icon_set_styles[param[:icon_style]]
497
+ raise "Unknown icon style '$param->{icon_style}' for parameter " +
498
+ "'icon_style' in conditional_formatting()"
499
+ else
500
+ param[:icon_style] = icon_set_styles[param[:icon_style]]
501
+ end
502
+
503
+ # Set the number of icons for the icon style.
504
+ param[:total_icons] = 3
505
+ if param[:icon_style] =~ /^4/
506
+ param[:total_icons] = 4
507
+ elsif param[:icon_style] =~ /^5/
508
+ param[:total_icons] = 5
509
+ end
510
+
511
+ param[:icons] = set_icon_properties(param[:total_icons], param[:icons])
512
+ end
513
+
372
514
  # 'Between' and 'Not between' criteria require 2 values.
373
515
  if param[:criteria] == 'between' || param[:criteria] == 'notBetween'
374
516
  unless param.has_key?(:minimum) || param.has_key?(:maximum)
@@ -400,23 +542,39 @@ def convert_date_time_if_required(val)
400
542
  # List of valid input parameters for conditional_formatting.
401
543
  def valid_parameter_for_conditional_formatting
402
544
  [
403
- :type,
404
- :format,
405
- :criteria,
406
- :value,
407
- :minimum,
408
- :maximum,
409
- :stop_if_true,
410
- :min_type,
411
- :mid_type,
412
- :max_type,
413
- :min_value,
414
- :mid_value,
415
- :max_value,
416
- :min_color,
417
- :mid_color,
418
- :max_color,
419
- :bar_color
545
+ :type,
546
+ :format,
547
+ :criteria,
548
+ :value,
549
+ :minimum,
550
+ :maximum,
551
+ :stop_if_true,
552
+ :min_type,
553
+ :mid_type,
554
+ :max_type,
555
+ :min_value,
556
+ :mid_value,
557
+ :max_value,
558
+ :min_color,
559
+ :mid_color,
560
+ :max_color,
561
+ :bar_color,
562
+ :bar_negative_color,
563
+ :bar_negative_color_same,
564
+ :bar_solid,
565
+ :bar_border_color,
566
+ :bar_negative_border_color,
567
+ :bar_negative_border_color_same,
568
+ :bar_no_border,
569
+ :bar_direction,
570
+ :bar_axis_position,
571
+ :bar_axis_color,
572
+ :bar_only,
573
+ :icon_style,
574
+ :reverse_icons,
575
+ :icons_only,
576
+ :icons,
577
+ :data_bar_2010
420
578
  ]
421
579
  end
422
580
 
@@ -440,7 +598,8 @@ def valid_type_for_conditional_formatting
440
598
  '2_color_scale' => '2_color_scale',
441
599
  '3_color_scale' => '3_color_scale',
442
600
  'data_bar' => 'dataBar',
443
- 'formula' => 'expression'
601
+ 'formula' => 'expression',
602
+ 'icon_set' => 'iconSet'
444
603
  }
445
604
  end
446
605
 
@@ -479,6 +638,100 @@ def valid_criteria_type_for_conditional_formatting
479
638
  }
480
639
  end
481
640
 
641
+ # List of valid icon styles.
642
+ def icon_set_styles
643
+ {
644
+ "3_arrows" => "3Arrows", # 1
645
+ "3_flags" => "3Flags", # 2
646
+ "3_traffic_lights_rimmed" => "3TrafficLights2", # 3
647
+ "3_symbols_circled" => "3Symbols", # 4
648
+ "4_arrows" => "4Arrows", # 5
649
+ "4_red_to_black" => "4RedToBlack", # 6
650
+ "4_traffic_lights" => "4TrafficLights", # 7
651
+ "5_arrows_gray" => "5ArrowsGray", # 8
652
+ "5_quarters" => "5Quarters", # 9
653
+ "3_arrows_gray" => "3ArrowsGray", # 10
654
+ "3_traffic_lights" => "3TrafficLights", # 11
655
+ "3_signs" => "3Signs", # 12
656
+ "3_symbols" => "3Symbols2", # 13
657
+ "4_arrows_gray" => "4ArrowsGray", # 14
658
+ "4_ratings" => "4Rating", # 15
659
+ "5_arrows" => "5Arrows", # 16
660
+ "5_ratings" => "5Rating", # 17
661
+ }
662
+ end
663
+
664
+ #
665
+ # Set the sub-properites for icons.
666
+ #
667
+ def set_icon_properties(total_icons, user_props)
668
+ props = []
669
+
670
+ # Set the default icon properties.
671
+ total_icons.times do
672
+ props << {
673
+ :criteria => 0,
674
+ :value => 0,
675
+ :type => 'percent'
676
+ }
677
+ end
678
+
679
+ # Set the default icon values based on the number of icons.
680
+ if total_icons == 3
681
+ props[0][:value] = 67
682
+ props[1][:value] = 33
683
+ elsif total_icons == 4
684
+ props[0][:value] = 75
685
+ props[1][:value] = 50
686
+ props[2][:value] = 25
687
+ elsif total_icons == 5
688
+ props[0][:value] = 80
689
+ props[1][:value] = 60
690
+ props[2][:value] = 40
691
+ props[3][:value] = 20
692
+ end
693
+
694
+ # Overwrite default properties with user defined properties.
695
+ if user_props
696
+
697
+ # Ensure we don't set user properties for lowest icon.
698
+ max_data = user_props.size
699
+ max_data = total_icons -1 if max_data >= total_icons
700
+
701
+ (0..max_data - 1).each do |i|
702
+ # Set the user defined 'value' property.
703
+ if user_props[i][:value]
704
+ props[i][:value] = user_props[i][:value].to_s.sub(/^=/, '')
705
+ end
706
+
707
+ # Set the user defined 'type' property.
708
+ if user_props[i][:type]
709
+
710
+ type = user_props[i][:type]
711
+
712
+ if type != 'percent' && type != 'percentile' &&
713
+ type != 'number' && type != 'formula'
714
+ raise "Unknown icon property type '$props->{type}' for sub-" +
715
+ "property 'type' in conditional_formatting()"
716
+ else
717
+ props[i][:type] = type
718
+
719
+ if props[i][:type] == 'number'
720
+ props[i][:type] = 'num'
721
+ end
722
+ end
723
+ end
724
+
725
+ # Set the user defined 'criteria' property.
726
+ if user_props[i][:criteria] && user_props[i][:criteria] == '>'
727
+ props[i][:criteria] = 1
728
+ end
729
+
730
+ end
731
+ end
732
+ props
733
+ end
734
+
482
735
  def date_1904?
483
736
  @worksheet.date_1904?
484
737
  end
@@ -578,6 +831,9 @@ class DataBarFormat < ConditionalFormat
578
831
  def write_cf_rule
579
832
  @writer.tag_elements('cfRule', attributes) do
580
833
  write_data_bar
834
+ if ptrue?(@param[:is_data_bar_2010])
835
+ write_data_bar_ext(@param)
836
+ end
581
837
  end
582
838
  end
583
839
 
@@ -585,13 +841,42 @@ def write_cf_rule
585
841
  # Write the <dataBar> element.
586
842
  #
587
843
  def write_data_bar
588
- @writer.tag_elements('dataBar') do
844
+ attributes = []
845
+
846
+ if ptrue?(bar_only)
847
+ attributes << ['showValue', 0]
848
+ end
849
+ @writer.tag_elements('dataBar',attributes) do
589
850
  write_cfvo(min_type, min_value)
590
851
  write_cfvo(max_type, max_value)
591
852
 
592
853
  write_color(@writer, 'rgb', bar_color)
593
854
  end
594
855
  end
856
+
857
+ #
858
+ # Write the <extLst> dataBar extension element.
859
+ #
860
+ def write_data_bar_ext(param)
861
+ # Create a pseudo GUID for each unique Excel 2010 data bar.
862
+ worksheet_count = @worksheet.index + 1
863
+ data_bar_count = @worksheet.data_bars_2010.size + 1
864
+
865
+ guid = sprintf(
866
+ "{DA7ABA51-AAAA-BBBB-%04X-%012X}",
867
+ worksheet_count, data_bar_count
868
+ )
869
+
870
+ # Store the 2010 data bar parameters to write the extLst elements.
871
+ param[:guid] = guid
872
+ @worksheet.data_bars_2010 << param
873
+
874
+ @writer.tag_elements('extLst') do
875
+ @worksheet.write_ext('{B025F937-C7B1-47D3-B67F-A62EFF666E3E}') do
876
+ @writer.data_element('x14:id', guid)
877
+ end
878
+ end
879
+ end
595
880
  end
596
881
 
597
882
  class ExpressionFormat < ConditionalFormat
@@ -599,5 +884,33 @@ def write_cf_rule
599
884
  write_cf_rule_formula_tag(criteria)
600
885
  end
601
886
  end
887
+
888
+ class IconSetFormat < ConditionalFormat
889
+ def write_cf_rule
890
+ @writer.tag_elements('cfRule', attributes) do
891
+ write_icon_set
892
+ end
893
+ end
894
+
895
+ #
896
+ # Write the <iconSet> element.
897
+ #
898
+ def write_icon_set
899
+ attributes = []
900
+ # Don't set attribute for default style.
901
+ attributes = [ ['iconSet', icon_style] ] if icon_style != '3TrafficLights'
902
+ attributes << ['showValue', 0] if icons_only
903
+ attributes << ['reverse', 1] if reverse_icons
904
+
905
+ @writer.tag_elements('iconSet', attributes) do
906
+ # Write the properties for different icon styles.
907
+ if icons
908
+ icons.reverse.each do |icon|
909
+ write_cfvo(icon[:type], icon[:value], icon[:criteria])
910
+ end
911
+ end
912
+ end
913
+ end
914
+ end
602
915
  end
603
916
  end