write_xlsx 0.90.0 → 0.97.0

Sign up to get free protection for your applications and to get access to all the features.
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