axlsx 1.1.0 → 1.2.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 (214) hide show
  1. data/.yardopts +5 -2
  2. data/CHANGELOG.md +78 -0
  3. data/LICENSE +1 -1
  4. data/README.md +132 -331
  5. data/Rakefile +17 -5
  6. data/examples/basic_charts.rb +54 -0
  7. data/examples/chart_colors.rb +88 -0
  8. data/examples/conditional_formatting/example_conditional_formatting.rb +72 -0
  9. data/examples/conditional_formatting/getting_barred.rb +37 -0
  10. data/examples/conditional_formatting/hitting_the_high_notes.rb +37 -0
  11. data/examples/conditional_formatting/scaled_colors.rb +39 -0
  12. data/examples/conditional_formatting/stop_and_go.rb +37 -0
  13. data/examples/data_validation.rb +50 -0
  14. data/examples/example.rb +300 -152
  15. data/examples/example.xlsx +0 -0
  16. data/examples/example_streamed.xlsx +0 -0
  17. data/examples/extractive.pdf +0 -0
  18. data/examples/extractive.rb +45 -0
  19. data/examples/no-use_autowidth.xlsx +0 -0
  20. data/examples/sample.png +0 -0
  21. data/examples/scraping_html.rb +91 -0
  22. data/examples/shared_strings_example.xlsx +0 -0
  23. data/examples/sheet_protection.rb +10 -0
  24. data/examples/sheet_view.rb +34 -0
  25. data/examples/skydrive/real_example.rb +63 -0
  26. data/examples/two_cell_anchor_image.rb +11 -0
  27. data/lib/axlsx/content_type/content_type.rb +2 -0
  28. data/lib/axlsx/content_type/default.rb +30 -15
  29. data/lib/axlsx/content_type/override.rb +29 -14
  30. data/lib/axlsx/doc_props/app.rb +161 -104
  31. data/lib/axlsx/doc_props/core.rb +9 -5
  32. data/lib/axlsx/drawing/ax_data_source.rb +26 -0
  33. data/lib/axlsx/drawing/axis.rb +106 -35
  34. data/lib/axlsx/drawing/bar_3D_chart.rb +49 -45
  35. data/lib/axlsx/drawing/bar_series.rb +25 -7
  36. data/lib/axlsx/drawing/cat_axis.rb +50 -22
  37. data/lib/axlsx/drawing/chart.rb +69 -56
  38. data/lib/axlsx/drawing/d_lbls.rb +100 -0
  39. data/lib/axlsx/drawing/drawing.rb +28 -12
  40. data/lib/axlsx/drawing/graphic_frame.rb +2 -1
  41. data/lib/axlsx/drawing/line_3D_chart.rb +3 -10
  42. data/lib/axlsx/drawing/line_series.rb +20 -4
  43. data/lib/axlsx/drawing/num_data.rb +52 -0
  44. data/lib/axlsx/drawing/num_data_source.rb +61 -0
  45. data/lib/axlsx/drawing/num_val.rb +32 -0
  46. data/lib/axlsx/drawing/pic.rb +44 -4
  47. data/lib/axlsx/drawing/pie_3D_chart.rb +10 -7
  48. data/lib/axlsx/drawing/pie_series.rb +18 -4
  49. data/lib/axlsx/drawing/scatter_chart.rb +12 -18
  50. data/lib/axlsx/drawing/scatter_series.rb +28 -2
  51. data/lib/axlsx/drawing/ser_axis.rb +1 -1
  52. data/lib/axlsx/drawing/series.rb +1 -1
  53. data/lib/axlsx/drawing/str_data.rb +42 -0
  54. data/lib/axlsx/drawing/str_val.rb +33 -0
  55. data/lib/axlsx/drawing/title.rb +21 -9
  56. data/lib/axlsx/drawing/two_cell_anchor.rb +46 -9
  57. data/lib/axlsx/drawing/view_3D.rb +44 -31
  58. data/lib/axlsx/drawing/vml_drawing.rb +42 -0
  59. data/lib/axlsx/drawing/vml_shape.rb +125 -0
  60. data/lib/axlsx/package.rb +44 -16
  61. data/lib/axlsx/rels/relationship.rb +3 -3
  62. data/lib/axlsx/rels/relationships.rb +1 -11
  63. data/lib/axlsx/stylesheet/color.rb +0 -1
  64. data/lib/axlsx/stylesheet/dxf.rb +79 -0
  65. data/lib/axlsx/stylesheet/font.rb +2 -1
  66. data/lib/axlsx/stylesheet/gradient_fill.rb +1 -1
  67. data/lib/axlsx/stylesheet/styles.rb +143 -50
  68. data/lib/axlsx/stylesheet/table_style.rb +3 -3
  69. data/lib/axlsx/stylesheet/xf.rb +2 -0
  70. data/lib/axlsx/util/constants.rb +36 -0
  71. data/lib/axlsx/util/simple_typed_list.rb +15 -21
  72. data/lib/axlsx/util/validators.rb +122 -5
  73. data/lib/axlsx/version.rb +2 -7
  74. data/lib/axlsx/workbook/defined_name.rb +174 -0
  75. data/lib/axlsx/workbook/defined_names.rb +21 -0
  76. data/lib/axlsx/workbook/shared_strings_table.rb +12 -13
  77. data/lib/axlsx/workbook/workbook.rb +71 -13
  78. data/lib/axlsx/workbook/worksheet/auto_filter.rb +34 -0
  79. data/lib/axlsx/workbook/worksheet/cell.rb +45 -36
  80. data/lib/axlsx/workbook/worksheet/cfvo.rb +62 -0
  81. data/lib/axlsx/workbook/worksheet/col.rb +17 -1
  82. data/lib/axlsx/workbook/worksheet/color_scale.rb +76 -0
  83. data/lib/axlsx/workbook/worksheet/cols.rb +20 -0
  84. data/lib/axlsx/workbook/worksheet/comment.rb +101 -0
  85. data/lib/axlsx/workbook/worksheet/comments.rb +85 -0
  86. data/lib/axlsx/workbook/worksheet/conditional_formatting.rb +82 -0
  87. data/lib/axlsx/workbook/worksheet/conditional_formatting_rule.rb +216 -0
  88. data/lib/axlsx/workbook/worksheet/conditional_formattings.rb +25 -0
  89. data/lib/axlsx/workbook/worksheet/data_bar.rb +97 -0
  90. data/lib/axlsx/workbook/worksheet/data_validation.rb +245 -0
  91. data/lib/axlsx/workbook/worksheet/data_validations.rb +28 -0
  92. data/lib/axlsx/workbook/worksheet/dimension.rb +65 -0
  93. data/lib/axlsx/workbook/worksheet/icon_set.rb +83 -0
  94. data/lib/axlsx/workbook/worksheet/merged_cells.rb +35 -0
  95. data/lib/axlsx/workbook/worksheet/page_setup.rb +113 -0
  96. data/lib/axlsx/workbook/worksheet/pane.rb +144 -0
  97. data/lib/axlsx/workbook/worksheet/print_options.rb +63 -0
  98. data/lib/axlsx/workbook/worksheet/protected_range.rb +46 -0
  99. data/lib/axlsx/workbook/worksheet/protected_ranges.rb +34 -0
  100. data/lib/axlsx/workbook/worksheet/row.rb +69 -12
  101. data/lib/axlsx/workbook/worksheet/selection.rb +111 -0
  102. data/lib/axlsx/workbook/worksheet/sheet_data.rb +25 -0
  103. data/lib/axlsx/workbook/worksheet/sheet_pr.rb +24 -0
  104. data/lib/axlsx/workbook/worksheet/sheet_protection.rb +224 -0
  105. data/lib/axlsx/workbook/worksheet/sheet_view.rb +379 -0
  106. data/lib/axlsx/workbook/worksheet/table.rb +3 -3
  107. data/lib/axlsx/workbook/worksheet/tables.rb +31 -0
  108. data/lib/axlsx/workbook/worksheet/worksheet.rb +379 -233
  109. data/lib/axlsx/workbook/worksheet/worksheet_comments.rb +57 -0
  110. data/lib/axlsx/workbook/worksheet/worksheet_drawing.rb +64 -0
  111. data/lib/axlsx.rb +31 -16
  112. data/test/benchmark.rb +30 -38
  113. data/test/content_type/tc_content_type.rb +1 -6
  114. data/test/doc_props/tc_app.rb +31 -1
  115. data/test/doc_props/tc_core.rb +3 -1
  116. data/test/drawing/tc_axis.rb +46 -3
  117. data/test/drawing/tc_bar_3D_chart.rb +12 -12
  118. data/test/drawing/tc_bar_series.rb +17 -13
  119. data/test/drawing/tc_cat_axis.rb +3 -3
  120. data/test/drawing/tc_cat_axis_data.rb +23 -13
  121. data/test/drawing/tc_chart.rb +29 -11
  122. data/test/drawing/tc_d_lbls.rb +47 -0
  123. data/test/drawing/tc_data_source.rb +17 -0
  124. data/test/drawing/tc_drawing.rb +11 -5
  125. data/test/drawing/tc_hyperlink.rb +4 -5
  126. data/test/drawing/tc_line_series.rb +9 -11
  127. data/test/drawing/tc_named_axis_data.rb +27 -0
  128. data/test/drawing/tc_num_data.rb +31 -0
  129. data/test/drawing/tc_num_val.rb +29 -0
  130. data/test/drawing/tc_pic.rb +22 -2
  131. data/test/drawing/tc_pie_3D_chart.rb +4 -8
  132. data/test/drawing/tc_pie_series.rb +11 -13
  133. data/test/drawing/tc_scatter_chart.rb +6 -1
  134. data/test/drawing/tc_scatter_series.rb +6 -5
  135. data/test/drawing/tc_series.rb +1 -1
  136. data/test/drawing/tc_str_data.rb +18 -0
  137. data/test/drawing/tc_str_val.rb +21 -0
  138. data/test/drawing/tc_title.rb +16 -0
  139. data/test/drawing/tc_two_cell_anchor.rb +2 -3
  140. data/test/drawing/tc_view_3D.rb +18 -18
  141. data/test/drawing/tc_vml_drawing.rb +25 -0
  142. data/test/drawing/tc_vml_shape.rb +100 -0
  143. data/test/profile.rb +2 -1
  144. data/test/rels/tc_relationship.rb +1 -0
  145. data/test/stylesheet/tc_dxf.rb +81 -0
  146. data/test/stylesheet/tc_gradient_fill.rb +8 -0
  147. data/test/stylesheet/tc_pattern_fill.rb +7 -1
  148. data/test/stylesheet/tc_styles.rb +163 -3
  149. data/test/stylesheet/tc_table_style.rb +8 -0
  150. data/test/stylesheet/tc_table_style_element.rb +10 -1
  151. data/test/tc_helper.rb +1 -0
  152. data/test/tc_package.rb +93 -17
  153. data/test/util/tc_simple_typed_list.rb +13 -0
  154. data/test/util/tc_validators.rb +95 -9
  155. data/test/workbook/tc_defined_name.rb +41 -0
  156. data/test/workbook/tc_workbook.rb +5 -3
  157. data/test/workbook/worksheet/table/tc_table.rb +3 -11
  158. data/test/workbook/worksheet/tc_cell.rb +52 -18
  159. data/test/workbook/worksheet/tc_cfvo.rb +31 -0
  160. data/test/workbook/worksheet/tc_col.rb +9 -0
  161. data/test/workbook/worksheet/tc_color_scale.rb +29 -0
  162. data/test/workbook/worksheet/tc_comment.rb +57 -0
  163. data/test/workbook/worksheet/tc_comments.rb +57 -0
  164. data/test/workbook/worksheet/tc_conditional_formatting.rb +217 -0
  165. data/test/workbook/worksheet/tc_data_bar.rb +39 -0
  166. data/test/workbook/worksheet/tc_data_validation.rb +265 -0
  167. data/test/workbook/worksheet/tc_date_time_converter.rb +11 -5
  168. data/test/workbook/worksheet/tc_icon_set.rb +45 -0
  169. data/test/workbook/worksheet/tc_page_setup.rb +138 -0
  170. data/test/workbook/worksheet/tc_pane.rb +94 -0
  171. data/test/workbook/worksheet/tc_print_options.rb +72 -0
  172. data/test/workbook/worksheet/tc_protected_range.rb +17 -0
  173. data/test/workbook/worksheet/tc_row.rb +44 -13
  174. data/test/workbook/worksheet/tc_selection.rb +94 -0
  175. data/test/workbook/worksheet/tc_sheet_protection.rb +117 -0
  176. data/test/workbook/worksheet/tc_sheet_view.rb +214 -0
  177. data/test/workbook/worksheet/tc_worksheet.rb +147 -50
  178. metadata +216 -148
  179. data/examples/example.csv +0 -1000
  180. data/examples/example.rb~ +0 -112
  181. data/lib/axlsx/drawing/cat_axis_data.rb +0 -34
  182. data/lib/axlsx/drawing/hlink_click.rb~ +0 -0
  183. data/lib/axlsx/drawing/hyperlink.rb~ +0 -64
  184. data/lib/axlsx/drawing/named_axis_data.rb +0 -36
  185. data/lib/axlsx/drawing/picture_locking.rb~ +0 -36
  186. data/lib/axlsx/drawing/val_axis_data.rb +0 -27
  187. data/lib/axlsx/stylesheet/#num_fmt.rb# +0 -69
  188. data/lib/axlsx/util/cbf.rb +0 -333
  189. data/lib/axlsx/util/cfb.rb~ +0 -201
  190. data/lib/axlsx/util/ms_off_crypto.rb +0 -189
  191. data/lib/axlsx/util/ms_off_crypto.rb~ +0 -3
  192. data/lib/axlsx/util/ms_offcrypto.rb~ +0 -0
  193. data/lib/axlsx/util/parser.rb~ +0 -6
  194. data/lib/axlsx/util/storage.rb~ +0 -0
  195. data/lib/axlsx/workbook/shared_strings_table.rb~ +0 -69
  196. data/lib/axlsx/workbook/worksheet/col.rb~ +0 -0
  197. data/lib/axlsx/workbook/worksheet/shared_strings_table.rb~ +0 -0
  198. data/lib/axlsx/workbook/worksheet/table.rb~ +0 -97
  199. data/lib/schema/dc.xsd~ +0 -118
  200. data/lib/schema/dcterms.xsd~ +0 -331
  201. data/lib/schema/opc-coreProperties.xsd~ +0 -50
  202. data/test/#benchmark.txt# +0 -7
  203. data/test/#tc_helper.rb# +0 -3
  204. data/test/benchmark.rb~ +0 -0
  205. data/test/benchmark.txt +0 -6
  206. data/test/benchmark.txt~ +0 -6
  207. data/test/drawing/tc_val_axis_data.rb +0 -17
  208. data/test/example.csv +0 -1000
  209. data/test/example.xlsx +0 -0
  210. data/test/example_streamed.xlsx +0 -0
  211. data/test/tc_axlsx.rb~ +0 -0
  212. data/test/tc_helper.rb~ +0 -3
  213. data/test/workbook/worksheet/table/tc_table.rb~ +0 -72
  214. data/test/workbook/worksheet/tc_col.rb~ +0 -10
@@ -3,22 +3,6 @@ require 'cgi'
3
3
  module Axlsx
4
4
  # A cell in a worksheet.
5
5
  # Cell stores inforamation requried to serialize a single worksheet cell to xml. You must provde the Row that the cell belongs to and the cells value. The data type will automatically be determed if you do not specify the :type option. The default style will be applied if you do not supply the :style option. Changing the cell's type will recast the value to the type specified. Altering the cell's value via the property accessor will also automatically cast the provided value to the cell's type.
6
- # @example Manually creating and manipulating Cell objects
7
- # ws = Workbook.new.add_worksheet
8
- # # This is the simple, and recommended way to create cells. Data types will automatically be determined for you.
9
- # ws.add_row :values => [1,"fish",Time.now]
10
- #
11
- # # but you can also do this
12
- # r = ws.add_row
13
- # r.add_cell 1
14
- #
15
- # # or even this
16
- # r = ws.add_row
17
- # c = Cell.new row, 1, :value=>integer
18
- #
19
- # # cells can also be accessed via Row#cells. The example here changes the cells type, which will automatically updated the value from 1 to 1.0
20
- # r.cells.last.type = :float
21
- #
22
6
  # @note The recommended way to generate cells is via Worksheet#add_row
23
7
  #
24
8
  # @see Worksheet#add_row
@@ -74,13 +58,20 @@ module Axlsx
74
58
  @value = cast_value(v)
75
59
  end
76
60
 
77
-
78
61
  # Indicates that the cell has one or more of the custom cell styles applied.
79
62
  # @return [Boolean]
80
63
  def is_text_run?
81
64
  @is_text_run ||= false
82
65
  end
83
66
 
67
+ # Indicates if the cell is good for shared string table
68
+ def plain_string?
69
+ @type == :string && # String typed
70
+ !is_text_run? && # No inline styles
71
+ !@value.nil? && # Not nil
72
+ !@value.empty? && # Not empty
73
+ !@value.start_with?('=') # Not a formula
74
+ end
84
75
 
85
76
  # The inline font_name property for the cell
86
77
  # @return [String]
@@ -151,10 +142,10 @@ module Axlsx
151
142
  # The inline color property for the cell
152
143
  # @return [Color]
153
144
  attr_reader :color
154
- # @param [String] The 8 character representation for an rgb color #FFFFFFFF"
145
+ # @param [String] v The 8 character representation for an rgb color #FFFFFFFF"
155
146
  def color=(v)
156
147
  @color = v.is_a?(Color) ? v : Color.new(:rgb=>v)
157
- @has_run_style = true
148
+ @is_text_run = true
158
149
  end
159
150
 
160
151
  # The inline sz property for the cell
@@ -204,7 +195,7 @@ module Axlsx
204
195
  # @option options [Symbol] scheme must be one of :none, major, :minor
205
196
  def initialize(row, value="", options={})
206
197
  self.row=row
207
- @font_name = @charset = @family = @b = @i = @strike = @outline = @shadow = nil
198
+ @value = @font_name = @charset = @family = @b = @i = @strike = @outline = @shadow = nil
208
199
  @condense = @u = @vertAlign = @sz = @color = @scheme = @extend = @ssti = nil
209
200
  @styles = row.worksheet.workbook.styles
210
201
  @row.cells << self
@@ -220,15 +211,6 @@ module Axlsx
220
211
  # @return [Integer]
221
212
  attr_reader :ssti
222
213
 
223
- # equality comparison to test value, type and inline style attributes
224
- # this is how we work out if the cell needs to be added or already exists in the shared strings table
225
- def shareable_hash
226
- self_hash = {}
227
- INLINE_STYLES.each { |style| self_hash[style] = self.instance_variable_get("@" + style) }
228
- self_hash['color'] = self_hash['color'].instance_values if self_hash['color']
229
- self_hash
230
- end
231
-
232
214
  # @return [Integer] The index of the cell in the containing row.
233
215
  def index
234
216
  @row.cells.index(self)
@@ -237,9 +219,8 @@ module Axlsx
237
219
  # @return [String] The alpha(column)numeric(row) reference for this sell.
238
220
  # @example Relative Cell Reference
239
221
  # ws.rows.first.cells.first.r #=> "A1"
240
- # @note this will be discontinued in 1.1.0 - prefer Axlsx.cell_r
241
222
  def r
242
- "#{Axlsx::col_ref(index)}#{@row.index+1}"
223
+ Axlsx::cell_r index, @row.index
243
224
  end
244
225
 
245
226
  # @return [String] The absolute alpha(column)numeric(row) reference for this sell.
@@ -280,9 +261,8 @@ module Axlsx
280
261
  # @return [String]
281
262
  def run_xml_string(str = '')
282
263
  if is_text_run?
283
- data = self.instance_values.reject{|key, value| value == nil }
264
+ data = instance_values.reject{|key, value| value == nil || key == 'value' || key == 'type' }
284
265
  keys = data.keys & INLINE_STYLES
285
- keys.delete ['value', 'type']
286
266
  str << "<r><rPr>"
287
267
  keys.each do |key|
288
268
  case key
@@ -291,7 +271,7 @@ module Axlsx
291
271
  when 'color'
292
272
  str << data[key].to_xml_string
293
273
  else
294
- "<" << key.to_s << " val='" << data[key].to_s << "'/>"
274
+ str << "<" << key.to_s << " val='" << data[key].to_s << "'/>"
295
275
  end
296
276
  end
297
277
  str << "</rPr>" << "<t>" << value.to_s << "</t></r>"
@@ -307,13 +287,15 @@ module Axlsx
307
287
  # @param [String] str The string index the cell content will be appended to. Defaults to empty string.
308
288
  # @return [String] xml text for the cell
309
289
  def to_xml_string(r_index, c_index, str = '')
310
- return str if @value.nil?
311
290
  str << '<c r="' << Axlsx::cell_r(c_index, r_index) << '" s="' << @style.to_s << '" '
291
+ return str << '/>' if @value.nil?
292
+
312
293
  case @type
294
+
313
295
  when :string
314
296
  #parse formula
315
297
  if @value.start_with?('=')
316
- str << 't="str"><f>' << @value.to_s.gsub('=', '') << '</f>'
298
+ str << 't="str"><f>' << @value.to_s.sub('=', '') << '</f>'
317
299
  else
318
300
  #parse shared
319
301
  if @ssti
@@ -335,8 +317,35 @@ module Axlsx
335
317
  str << '</c>'
336
318
  end
337
319
 
320
+ def is_formula?
321
+ @type == :string && @value.to_s.start_with?('=')
322
+ end
323
+
324
+ # This is still not perfect...
325
+ # - scaling is not linear as font sizes increst
326
+ # - different fonts have different mdw and char widths
327
+ def autowidth
328
+ return if is_formula? || value == nil
329
+ mdw = 1.78 #This is the widest width of 0..9 in arial@10px)
330
+ font_scale = (font_size/10.0).to_f
331
+ ((value.to_s.count(Worksheet.thin_chars) * mdw + 5) / mdw * 256) / 256.0 * font_scale
332
+ end
333
+
334
+ # returns the absolute or relative string style reference for
335
+ # this cell.
336
+ # @param [Boolean] absolute -when false a relative reference will be
337
+ # returned.
338
+ # @return [String]
339
+ def reference(absolute=true)
340
+ absolute ? r_abs : r
341
+ end
342
+
338
343
  private
339
344
 
345
+ def font_size
346
+ sz || @styles.fonts[@styles.cellXfs[style].fontId].sz
347
+ end
348
+
340
349
  # Utility method for setting inline style attributes
341
350
  def set_run_style( validator, attr, value)
342
351
  return unless INLINE_STYLES.include?(attr.to_s)
@@ -0,0 +1,62 @@
1
+ module Axlsx
2
+ # Conditional Format Value Object
3
+ # Describes the values of the interpolation points in a gradient scale. This object is used by ColorScale, DataBar and IconSet classes
4
+ #
5
+ # @note The recommended way to manage these rules is via Worksheet#add_conditional_formatting
6
+ # @see Worksheet#add_conditional_formatting
7
+ # @see ConditionalFormattingRule#initialize
8
+ #
9
+ class Cfvo
10
+
11
+ # Type (ST_CfvoType)
12
+ # The type of this conditional formatting value object. options are num, percent, max, min, formula and percentile
13
+ # @return [Symbol]
14
+ attr_reader :type
15
+
16
+
17
+ # Type (xsd:boolean)
18
+ # For icon sets, determines whether this threshold value uses the greater than or equal to operator. 0 indicates 'greater than' is used instead of 'greater than or equal to'.
19
+ # The default value is true
20
+ # @return [Boolean]
21
+ attr_reader :gte
22
+
23
+
24
+ # Type (ST_Xstring)
25
+ # The value of the conditional formatting object
26
+ # This library will accept any value so long as it supports to_s
27
+ attr_reader :val
28
+
29
+ # Creates a new Cfvo object
30
+ # @option options [Symbol] type The type of conditional formatting value object
31
+ # @option options [Boolean] gte threshold value usage indicator
32
+ # @option options [String] val The value of the conditional formatting object
33
+ def initialize(options={})
34
+ @gte = true
35
+ options.each do |o|
36
+ self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
37
+ end
38
+ end
39
+
40
+ # @see type
41
+ def type=(v); Axlsx::validate_conditional_formatting_value_object_type(v); @type = v end
42
+
43
+ # @see gte
44
+ def gte=(v); Axlsx::validate_boolean(v); @gte = v end
45
+
46
+ # @see val
47
+ def val=(v)
48
+ raise ArgumentError, "#{v.inspect} must respond to to_s" unless v.respond_to?(:to_s)
49
+ @val = v.to_s
50
+ end
51
+
52
+ # serialize the Csvo object
53
+ # @param [String] str
54
+ # @return [String]
55
+ def to_xml_string(str = '')
56
+ str << '<cfvo '
57
+ str << instance_values.map { |key, value| '' << key << '="' << value.to_s << '"' }.join(' ')
58
+ str << ' />'
59
+ end
60
+
61
+ end
62
+ end
@@ -60,7 +60,8 @@ module Axlsx
60
60
 
61
61
  # @see Col#outline
62
62
  def outlineLevel=(v)
63
- Axlsx.validate_boolean(v)
63
+ Axlsx.validate_unsigned_numeric(v)
64
+ raise ArgumentError, 'outlineLevel must be between 0 and 7' unless 0 <= v && v <= 7
64
65
  @outlineLevel = v
65
66
  end
66
67
 
@@ -101,6 +102,21 @@ module Axlsx
101
102
  self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
102
103
  end
103
104
  end
105
+
106
+ # updates the width for this col based on the cells autowidth and
107
+ # an optionally specified fixed width
108
+ # @param [Cell] cell The cell to use in updating this col's width
109
+ # @param [Integer] fixed_width If this is specified the width is set
110
+ # to this value and the cell's attributes are ignored.
111
+ # @param [Boolean] use_autowidth If this is false, the cell's
112
+ # autowidth value will be ignored.
113
+ def update_width(cell, fixed_width=nil, use_autowidth=true)
114
+ if fixed_width.is_a? Numeric
115
+ self.width = fixed_width
116
+ elsif use_autowidth
117
+ self.width = [width || 0, cell.autowidth || 0].max
118
+ end
119
+ end
104
120
 
105
121
  # Serialize this columns data to an xml string
106
122
  # @param [String] str
@@ -0,0 +1,76 @@
1
+ module Axlsx
2
+ # Conditional Format Rule color scale object
3
+ # Describes a gradated color scale in this conditional formatting rule.
4
+
5
+ # @note The recommended way to manage these rules is via Worksheet#add_conditional_formatting
6
+ # @see Worksheet#add_conditional_formatting
7
+ # @see ConditionalFormattingRule#initialize
8
+ class ColorScale
9
+
10
+ # A simple typed list of cfvos
11
+ # @return [SimpleTypedList]
12
+ # @see Cfvo
13
+ attr_reader :value_objects
14
+
15
+ # A simple types list of colors
16
+ # @return [SimpleTypedList]
17
+ # @see Color
18
+ attr_reader :colors
19
+
20
+ # creates a new ColorScale object.
21
+ # This method will yield it self so you can alter the properites of the defauls conditional formating value object (cfvo and colors
22
+ # Two value objects and two colors are created on initialization and cannot be deleted.
23
+ # @see Cfvo
24
+ # @see Color
25
+ def initialize
26
+ initialize_value_objects
27
+ initialize_colors
28
+ yield self if block_given?
29
+ end
30
+
31
+ # adds a new cfvo / color pair to the color scale and returns a hash containing
32
+ # a reference to the newly created cfvo and color objects so you can alter the default properties.
33
+ # @return [Hash] a hash with :cfvo and :color keys referencing the newly added objects.
34
+ def add(options={})
35
+ @value_objects << Cfvo.new(:type => options[:type] || :min, :val => options[:val] || 0)
36
+ @colors << Color.new(:rgb => options[:color] || "FF000000")
37
+ {:cfvo => @value_objects.last, :color => @colors.last}
38
+ end
39
+
40
+
41
+ # removes the cfvo and color pair at the index specified.
42
+ # @param [Integer] index The index of the cfvo and color object to delete
43
+ # @note you cannot remove the first two cfvo and color pairs
44
+ def delete_at(index=2)
45
+ @value_objects.delete_at index
46
+ @colors.delete_at index
47
+ end
48
+
49
+ # Serialize this color_scale object data to an xml string
50
+ # @param [String] str
51
+ # @return [String]
52
+ def to_xml_string(str = '')
53
+ str << '<colorScale>'
54
+ @value_objects.each { |cfvo| cfvo.to_xml_string(str) }
55
+ @colors.each { |color| color.to_xml_string(str) }
56
+ str << '</colorScale>'
57
+ end
58
+
59
+ private
60
+
61
+ # creates the initial cfvo objects
62
+ def initialize_value_objects
63
+ @value_objects = SimpleTypedList.new Cfvo
64
+ @value_objects.concat [Cfvo.new(:type => :min, :val => 0), Cfvo.new(:type => :max, :val => 0)]
65
+ @value_objects.lock
66
+ end
67
+
68
+ # creates the initial color objects
69
+ def initialize_colors
70
+ @colors = SimpleTypedList.new Color
71
+ @colors.concat [Color.new(:rgb => "FFFF0000"), Color.new(:rgb => "FF0000FF")]
72
+ @colors.lock
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,20 @@
1
+ module Axlsx
2
+
3
+ # The cols class manages the col object used to manage column widths.
4
+ # This is where the magic happens with autowidth
5
+ class Cols < SimpleTypedList
6
+
7
+ def initialize(worksheet)
8
+ raise ArgumentError, "you must provide a worksheet" unless worksheet.is_a?(Worksheet)
9
+ super Col
10
+ @worksheet = worksheet
11
+ end
12
+
13
+ def to_xml_string(str = '')
14
+ return if empty?
15
+ str << '<cols>'
16
+ each { |item| item.to_xml_string(str) }
17
+ str << '</cols>'
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,101 @@
1
+ module Axlsx
2
+
3
+ # A comment is the text data for a comment
4
+ class Comment
5
+
6
+ # The text to render
7
+ # @return [String]
8
+ attr_reader :text
9
+
10
+ # The author of this comment
11
+ # @see Comments
12
+ # @return [String]
13
+ attr_reader :author
14
+
15
+ # The owning Comments object
16
+ # @return [Comments]
17
+ attr_reader :comments
18
+
19
+
20
+ # The string based cell position reference (e.g. 'A1') that determines the positioning of this comment
21
+ # @return [String]
22
+ attr_reader :ref
23
+
24
+ # TODO
25
+ # r (Rich Text Run)
26
+ # rPh (Phonetic Text Run)
27
+ # phoneticPr (Phonetic Properties)
28
+
29
+ def initialize(comments, options={})
30
+ raise ArgumentError, "A comment needs a parent comments object" unless comments.is_a?(Comments)
31
+ @comments = comments
32
+ options.each do |o|
33
+ self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
34
+ end
35
+ yield self if block_given?
36
+ end
37
+
38
+ # The vml shape that will render this comment
39
+ # @return [VmlShape]
40
+ def vml_shape
41
+ @vml_shape ||= initialize_vml_shape
42
+ end
43
+
44
+ #
45
+ # The index of this author in a unique sorted list of all authors in
46
+ # the comment.
47
+ # @return [Integer]
48
+ def author_index
49
+ @comments.authors.index(author)
50
+ end
51
+
52
+ # @see ref
53
+ def ref=(v)
54
+ Axlsx::DataTypeValidator.validate "Comment.ref", [String, Cell], v
55
+ @ref = v if v.is_a?(String)
56
+ @ref = v.r if v.is_a?(Cell)
57
+ end
58
+
59
+ # @see text
60
+ def text=(v)
61
+ Axlsx::validate_string(v)
62
+ @text = v
63
+ end
64
+
65
+ # @see author
66
+ def author=(v)
67
+ @author = v
68
+ end
69
+
70
+ # serialize the object
71
+ # @param [String] str
72
+ # @return [String]
73
+ def to_xml_string(str = "")
74
+ author = @comments.authors[author_index]
75
+ str << '<comment ref="' << ref << '" authorId="' << author_index.to_s << '">'
76
+ str << '<text><r>'
77
+ str << '<rPr> <b/><color indexed="81"/></rPr>'
78
+ str << '<t>' << author.to_s << ':
79
+ </t></r>'
80
+ str << '<r>'
81
+ str << '<rPr><color indexed="81"/></rPr>'
82
+ str << '<t>' << text << '</t></r></text>'
83
+ str << '</comment>'
84
+ end
85
+
86
+ private
87
+
88
+ # initialize the vml shape based on this comment's ref/position in the worksheet.
89
+ # by default, all columns are 5 columns wide and 5 rows high
90
+ def initialize_vml_shape
91
+ pos = Axlsx::name_to_indices(ref)
92
+ @vml_shape = VmlShape.new(:row => pos[1], :column => pos[0]) do |vml|
93
+ vml.left_column = vml.column
94
+ vml.right_column = vml.column + 2
95
+ vml.top_row = vml.row
96
+ vml.bottom_row = vml.row + 4
97
+ end
98
+ end
99
+
100
+ end
101
+ end
@@ -0,0 +1,85 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Axlsx
3
+
4
+ # Comments is a collection of Comment objects for a worksheet
5
+ class Comments < SimpleTypedList
6
+
7
+ # the vml_drawing that holds the shapes for comments
8
+ # @return [VmlDrawing]
9
+ attr_reader :vml_drawing
10
+
11
+ # The worksheet that these comments belong to
12
+ # @return [Worksheet]
13
+ attr_reader :worksheet
14
+
15
+ # The index of this collection in the workbook. Effectively the index of the worksheet.
16
+ # @return [Integer]
17
+ def index
18
+ @worksheet.index
19
+ end
20
+
21
+ # The part name for this object
22
+ # @return [String]
23
+ def pn
24
+ "#{COMMENT_PN % (index+1)}"
25
+ end
26
+
27
+ # Creates a new Comments object
28
+ # @param [Worksheet] worksheet The sheet that these comments belong to.
29
+ def initialize(worksheet)
30
+ raise ArgumentError, "you must provide a worksheet" unless worksheet.is_a?(Worksheet)
31
+ super(Comment)
32
+ @worksheet = worksheet
33
+ @vml_drawing = VmlDrawing.new(self)
34
+ end
35
+
36
+ # Adds a new comment to the worksheet that owns these comments.
37
+ # @note the author, text and ref options are required
38
+ # @option options [String] author The name of the author for this comment
39
+ # @option options [String] text The text for this comment
40
+ # @option options [Stirng|Cell] ref The cell that this comment is attached to.
41
+ def add_comment(options={})
42
+ raise ArgumentError, "Comment require an author" unless options[:author]
43
+ raise ArgumentError, "Comment requires text" unless options[:text]
44
+ raise ArgumentError, "Comment requires ref" unless options[:ref]
45
+ @list << Comment.new(self, options)
46
+ yield @list.last if block_given?
47
+ @list.last
48
+ end
49
+
50
+ # A sorted list of the unique authors in the contained comments
51
+ # @return [Array]
52
+ def authors
53
+ @list.map { |comment| comment.author.to_s }.uniq.sort
54
+ end
55
+
56
+ # The relationships required by this object
57
+ # @return [Array]
58
+ def relationships
59
+ [Relationship.new(VML_DRAWING_R, "../#{vml_drawing.pn}"),
60
+ Relationship.new(COMMENT_R, "../#{pn}"),
61
+ Relationship.new(COMMENT_R_NULL, "NULL")]
62
+ end
63
+
64
+ # serialize the object
65
+ # @param [String] str
66
+ # @return [String]
67
+ def to_xml_string(str="")
68
+ str << '<?xml version="1.0" encoding="UTF-8"?>'
69
+ str << '<comments xmlns="' << XML_NS << '">'
70
+ str << '<authors>'
71
+ authors.each do |author|
72
+ str << '<author>' << author.to_s << '</author>'
73
+ end
74
+ str << '</authors>'
75
+ str << '<commentList>'
76
+ @list.each do |comment|
77
+ comment.to_xml_string str
78
+ end
79
+ str << '</commentList></comments>'
80
+
81
+ end
82
+
83
+ end
84
+
85
+ end
@@ -0,0 +1,82 @@
1
+ module Axlsx
2
+ # Conditional formatting allows styling of ranges based on functions
3
+ #
4
+ # @note The recommended way to manage conditional formatting is via Worksheet#add_conditional_formatting
5
+ # @see Worksheet#add_conditional_formatting
6
+ # @see ConditionalFormattingRule
7
+ class ConditionalFormatting
8
+
9
+ # Range over which the formatting is applied, in "A1:B2" format
10
+ # @return [String]
11
+ attr_reader :sqref
12
+
13
+ # Rules to apply the formatting to. Can be either a hash of
14
+ # options to create a {ConditionalFormattingRule}, an array of hashes
15
+ # for multiple ConditionalFormattingRules, or an array of already
16
+ # created ConditionalFormattingRules.
17
+ # @see ConditionalFormattingRule#initialize
18
+ # @return [Array]
19
+ attr_reader :rules
20
+
21
+ # Creates a new {ConditionalFormatting} object
22
+ # @option options [Array] rules The rules to apply
23
+ # @option options [String] sqref The range to apply the rules to
24
+ def initialize(options={})
25
+ @rules = []
26
+ options.each do |o|
27
+ self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
28
+ end
29
+ end
30
+
31
+ # Add Conditional Formatting Rules to this object. Rules can either
32
+ # be already created {ConditionalFormattingRule} elements or
33
+ # hashes of options for automatic creation. If rules is a hash
34
+ # instead of an array, assume only one rule being added.
35
+ #
36
+ # @example This would apply formatting "1" to cells > 20, and formatting "2" to cells < 1
37
+ # conditional_formatting.add_rules [
38
+ # { :type => :cellIs, :operator => :greaterThan, :formula => "20", :dxfId => 1, :priority=> 1 },
39
+ # { :type => :cellIs, :operator => :lessThan, :formula => "10", :dxfId => 2, :priority=> 2 } ]
40
+ #
41
+ # @param [Array|Hash] rules the rules to apply, can be just one in hash form
42
+ # @see ConditionalFormattingRule#initialize
43
+ def add_rules(rules)
44
+ rules = [rules] if rules.is_a? Hash
45
+ rules.each do |rule|
46
+ add_rule rule
47
+ end
48
+ end
49
+
50
+ # Add a ConditionalFormattingRule. If a hash of options is passed
51
+ # in create a rule on the fly.
52
+ # @param [ConditionalFormattingRule|Hash] rule A rule to use, or the options necessary to create one.
53
+ # @see ConditionalFormattingRule#initialize
54
+ def add_rule(rule)
55
+ if rule.is_a? Axlsx::ConditionalFormattingRule
56
+ @rules << rule
57
+ elsif rule.is_a? Hash
58
+ @rules << ConditionalFormattingRule.new(rule)
59
+ end
60
+ end
61
+
62
+ # @see rules
63
+ def rules=(v); @rules = v end
64
+ # @see sqref
65
+ def sqref=(v); Axlsx::validate_string(v); @sqref = v end
66
+
67
+ # Serializes the conditional formatting element
68
+ # @example Conditional Formatting XML looks like:
69
+ # <conditionalFormatting sqref="E3:E9">
70
+ # <cfRule type="cellIs" dxfId="0" priority="1" operator="greaterThan">
71
+ # <formula>0.5</formula>
72
+ # </cfRule>
73
+ # </conditionalFormatting>
74
+ # @param [String] str
75
+ # @return [String]
76
+ def to_xml_string(str = '')
77
+ str << '<conditionalFormatting sqref="' << sqref << '">'
78
+ str << rules.collect{ |rule| rule.to_xml_string }.join(' ')
79
+ str << '</conditionalFormatting>'
80
+ end
81
+ end
82
+ end