caxlsx 2.0.2 → 3.0.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 (181) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/README.md +41 -33
  4. data/Rakefile +9 -11
  5. data/examples/auto_filter.rb +10 -1
  6. data/examples/conditional_formatting/example_conditional_formatting.rb +18 -3
  7. data/examples/data_validation.rb +57 -40
  8. data/examples/example.rb +115 -7
  9. data/examples/merge_cells.rb +17 -0
  10. data/examples/no_grid_with_borders.rb +18 -0
  11. data/examples/pivot_test.rb +63 -0
  12. data/examples/split.rb +16 -0
  13. data/lib/axlsx.rb +34 -15
  14. data/lib/axlsx/content_type/abstract_content_type.rb +1 -1
  15. data/lib/axlsx/content_type/content_type.rb +1 -1
  16. data/lib/axlsx/doc_props/app.rb +1 -1
  17. data/lib/axlsx/doc_props/core.rb +5 -5
  18. data/lib/axlsx/drawing/area_chart.rb +99 -0
  19. data/lib/axlsx/drawing/area_series.rb +110 -0
  20. data/lib/axlsx/drawing/axes.rb +1 -1
  21. data/lib/axlsx/drawing/axis.rb +12 -9
  22. data/lib/axlsx/drawing/bar_3D_chart.rb +13 -13
  23. data/lib/axlsx/drawing/bar_chart.rb +143 -0
  24. data/lib/axlsx/drawing/bar_series.rb +9 -9
  25. data/lib/axlsx/drawing/bubble_chart.rb +59 -0
  26. data/lib/axlsx/drawing/bubble_series.rb +63 -0
  27. data/lib/axlsx/drawing/cat_axis.rb +5 -5
  28. data/lib/axlsx/drawing/chart.rb +52 -8
  29. data/lib/axlsx/drawing/d_lbls.rb +3 -3
  30. data/lib/axlsx/drawing/drawing.rb +6 -1
  31. data/lib/axlsx/drawing/graphic_frame.rb +3 -3
  32. data/lib/axlsx/drawing/hyperlink.rb +1 -3
  33. data/lib/axlsx/drawing/line_3D_chart.rb +2 -2
  34. data/lib/axlsx/drawing/line_chart.rb +10 -10
  35. data/lib/axlsx/drawing/line_series.rb +32 -3
  36. data/lib/axlsx/drawing/marker.rb +1 -1
  37. data/lib/axlsx/drawing/num_data.rb +4 -4
  38. data/lib/axlsx/drawing/num_data_source.rb +6 -6
  39. data/lib/axlsx/drawing/num_val.rb +3 -1
  40. data/lib/axlsx/drawing/one_cell_anchor.rb +3 -2
  41. data/lib/axlsx/drawing/pic.rb +25 -19
  42. data/lib/axlsx/drawing/picture_locking.rb +1 -3
  43. data/lib/axlsx/drawing/pie_3D_chart.rb +5 -6
  44. data/lib/axlsx/drawing/pie_series.rb +6 -6
  45. data/lib/axlsx/drawing/scaling.rb +6 -6
  46. data/lib/axlsx/drawing/scatter_chart.rb +10 -10
  47. data/lib/axlsx/drawing/scatter_series.rb +40 -7
  48. data/lib/axlsx/drawing/ser_axis.rb +2 -2
  49. data/lib/axlsx/drawing/series.rb +3 -3
  50. data/lib/axlsx/drawing/series_title.rb +2 -2
  51. data/lib/axlsx/drawing/str_data.rb +3 -3
  52. data/lib/axlsx/drawing/str_val.rb +3 -1
  53. data/lib/axlsx/drawing/title.rb +22 -4
  54. data/lib/axlsx/drawing/two_cell_anchor.rb +6 -1
  55. data/lib/axlsx/drawing/val_axis.rb +1 -1
  56. data/lib/axlsx/drawing/view_3D.rb +2 -2
  57. data/lib/axlsx/drawing/vml_drawing.rb +1 -1
  58. data/lib/axlsx/package.rb +33 -31
  59. data/lib/axlsx/rels/relationship.rb +1 -1
  60. data/lib/axlsx/rels/relationships.rb +7 -4
  61. data/lib/axlsx/stylesheet/border_pr.rb +2 -2
  62. data/lib/axlsx/stylesheet/cell_alignment.rb +1 -3
  63. data/lib/axlsx/stylesheet/cell_protection.rb +1 -3
  64. data/lib/axlsx/stylesheet/cell_style.rb +1 -3
  65. data/lib/axlsx/stylesheet/color.rb +1 -3
  66. data/lib/axlsx/stylesheet/font.rb +1 -1
  67. data/lib/axlsx/stylesheet/gradient_stop.rb +1 -1
  68. data/lib/axlsx/stylesheet/num_fmt.rb +10 -3
  69. data/lib/axlsx/stylesheet/pattern_fill.rb +1 -1
  70. data/lib/axlsx/stylesheet/styles.rb +7 -7
  71. data/lib/axlsx/stylesheet/table_style_element.rb +1 -3
  72. data/lib/axlsx/util/accessors.rb +6 -6
  73. data/lib/axlsx/util/constants.rb +107 -99
  74. data/lib/axlsx/util/mime_type_utils.rb +11 -0
  75. data/lib/axlsx/util/options_parser.rb +2 -1
  76. data/lib/axlsx/util/parser.rb +4 -4
  77. data/lib/axlsx/util/serialized_attributes.rb +16 -6
  78. data/lib/axlsx/util/simple_typed_list.rb +28 -52
  79. data/lib/axlsx/util/storage.rb +4 -4
  80. data/lib/axlsx/util/validators.rb +29 -17
  81. data/lib/axlsx/version.rb +1 -1
  82. data/lib/axlsx/workbook/defined_name.rb +11 -12
  83. data/lib/axlsx/workbook/defined_names.rb +2 -2
  84. data/lib/axlsx/workbook/shared_strings_table.rb +5 -5
  85. data/lib/axlsx/workbook/workbook.rb +36 -11
  86. data/lib/axlsx/workbook/workbook_view.rb +80 -0
  87. data/lib/axlsx/workbook/workbook_views.rb +22 -0
  88. data/lib/axlsx/workbook/worksheet/auto_filter/auto_filter.rb +2 -2
  89. data/lib/axlsx/workbook/worksheet/auto_filter/filters.rb +1 -3
  90. data/lib/axlsx/workbook/worksheet/break.rb +1 -3
  91. data/lib/axlsx/workbook/worksheet/cell.rb +136 -74
  92. data/lib/axlsx/workbook/worksheet/cell_serializer.rb +63 -43
  93. data/lib/axlsx/workbook/worksheet/cfvo.rb +1 -3
  94. data/lib/axlsx/workbook/worksheet/cfvos.rb +4 -1
  95. data/lib/axlsx/workbook/worksheet/col.rb +7 -10
  96. data/lib/axlsx/workbook/worksheet/col_breaks.rb +2 -2
  97. data/lib/axlsx/workbook/worksheet/cols.rb +5 -2
  98. data/lib/axlsx/workbook/worksheet/comment.rb +5 -6
  99. data/lib/axlsx/workbook/worksheet/comments.rb +9 -12
  100. data/lib/axlsx/workbook/worksheet/conditional_formatting.rb +1 -1
  101. data/lib/axlsx/workbook/worksheet/conditional_formatting_rule.rb +1 -1
  102. data/lib/axlsx/workbook/worksheet/data_bar.rb +4 -6
  103. data/lib/axlsx/workbook/worksheet/data_validation.rb +6 -4
  104. data/lib/axlsx/workbook/worksheet/dimension.rb +2 -2
  105. data/lib/axlsx/workbook/worksheet/header_footer.rb +6 -8
  106. data/lib/axlsx/workbook/worksheet/icon_set.rb +3 -5
  107. data/lib/axlsx/workbook/worksheet/merged_cells.rb +4 -2
  108. data/lib/axlsx/workbook/worksheet/outline_pr.rb +33 -0
  109. data/lib/axlsx/workbook/worksheet/page_margins.rb +1 -3
  110. data/lib/axlsx/workbook/worksheet/page_set_up_pr.rb +1 -1
  111. data/lib/axlsx/workbook/worksheet/page_setup.rb +21 -23
  112. data/lib/axlsx/workbook/worksheet/pane.rb +1 -3
  113. data/lib/axlsx/workbook/worksheet/pivot_table.rb +44 -28
  114. data/lib/axlsx/workbook/worksheet/pivot_table_cache_definition.rb +4 -4
  115. data/lib/axlsx/workbook/worksheet/print_options.rb +1 -3
  116. data/lib/axlsx/workbook/worksheet/protected_range.rb +1 -3
  117. data/lib/axlsx/workbook/worksheet/protected_ranges.rb +5 -2
  118. data/lib/axlsx/workbook/worksheet/rich_text.rb +55 -0
  119. data/lib/axlsx/workbook/worksheet/rich_text_run.rb +250 -0
  120. data/lib/axlsx/workbook/worksheet/row.rb +40 -51
  121. data/lib/axlsx/workbook/worksheet/row_breaks.rb +2 -2
  122. data/lib/axlsx/workbook/worksheet/selection.rb +1 -3
  123. data/lib/axlsx/workbook/worksheet/sheet_data.rb +3 -1
  124. data/lib/axlsx/workbook/worksheet/sheet_pr.rb +21 -3
  125. data/lib/axlsx/workbook/worksheet/sheet_protection.rb +1 -3
  126. data/lib/axlsx/workbook/worksheet/table.rb +6 -6
  127. data/lib/axlsx/workbook/worksheet/table_style_info.rb +1 -3
  128. data/lib/axlsx/workbook/worksheet/tables.rb +4 -1
  129. data/lib/axlsx/workbook/worksheet/worksheet.rb +64 -78
  130. data/lib/axlsx/workbook/worksheet/worksheet_drawing.rb +10 -10
  131. data/lib/axlsx/workbook/worksheet/worksheet_hyperlinks.rb +3 -3
  132. data/test/drawing/tc_area_chart.rb +39 -0
  133. data/test/drawing/tc_area_series.rb +71 -0
  134. data/test/drawing/tc_axis.rb +27 -0
  135. data/test/drawing/tc_bar_chart.rb +71 -0
  136. data/test/drawing/tc_bubble_chart.rb +44 -0
  137. data/test/drawing/tc_bubble_series.rb +21 -0
  138. data/test/drawing/tc_chart.rb +23 -10
  139. data/test/drawing/tc_data_source.rb +6 -0
  140. data/test/drawing/tc_drawing.rb +2 -2
  141. data/test/drawing/tc_line_chart.rb +5 -5
  142. data/test/drawing/tc_line_series.rb +47 -6
  143. data/test/drawing/tc_pic.rb +11 -15
  144. data/test/drawing/tc_scatter_series.rb +36 -1
  145. data/test/drawing/tc_str_val.rb +9 -0
  146. data/test/drawing/tc_title.rb +5 -0
  147. data/test/stylesheet/tc_styles.rb +2 -2
  148. data/test/tc_axlsx.rb +31 -0
  149. data/test/tc_helper.rb +2 -0
  150. data/test/tc_package.rb +19 -1
  151. data/test/util/tc_mime_type_utils.rb +13 -0
  152. data/test/util/tc_simple_typed_list.rb +2 -3
  153. data/test/util/tc_validators.rb +34 -10
  154. data/test/workbook/tc_defined_name.rb +12 -4
  155. data/test/workbook/tc_shared_strings_table.rb +16 -1
  156. data/test/workbook/tc_workbook.rb +38 -3
  157. data/test/workbook/tc_workbook_view.rb +50 -0
  158. data/test/workbook/worksheet/auto_filter/tc_filters.rb +1 -1
  159. data/test/workbook/worksheet/tc_break.rb +1 -1
  160. data/test/workbook/worksheet/tc_cell.rb +76 -8
  161. data/test/workbook/worksheet/tc_col.rb +2 -2
  162. data/test/workbook/worksheet/tc_conditional_formatting.rb +2 -2
  163. data/test/workbook/worksheet/tc_data_bar.rb +1 -1
  164. data/test/workbook/worksheet/tc_data_validation.rb +11 -11
  165. data/test/workbook/worksheet/tc_header_footer.rb +2 -2
  166. data/test/workbook/worksheet/tc_icon_set.rb +1 -1
  167. data/test/workbook/worksheet/tc_outline_pr.rb +19 -0
  168. data/test/workbook/worksheet/tc_page_setup.rb +3 -3
  169. data/test/workbook/worksheet/tc_pivot_table.rb +21 -6
  170. data/test/workbook/worksheet/tc_print_options.rb +1 -1
  171. data/test/workbook/worksheet/tc_rich_text.rb +44 -0
  172. data/test/workbook/worksheet/tc_rich_text_run.rb +172 -0
  173. data/test/workbook/worksheet/tc_row.rb +7 -2
  174. data/test/workbook/worksheet/tc_sheet_calc_pr.rb +1 -1
  175. data/test/workbook/worksheet/tc_sheet_format_pr.rb +4 -4
  176. data/test/workbook/worksheet/tc_sheet_pr.rb +26 -4
  177. data/test/workbook/worksheet/tc_sheet_protection.rb +5 -5
  178. data/test/workbook/worksheet/tc_sheet_view.rb +4 -4
  179. data/test/workbook/worksheet/tc_table.rb +2 -3
  180. data/test/workbook/worksheet/tc_worksheet.rb +99 -45
  181. metadata +89 -16
@@ -11,8 +11,8 @@ module Axlsx
11
11
  # @param [String] str
12
12
  # @return [String]
13
13
  def to_xml_string(str = '')
14
- return if @list.empty?
15
- str << "<definedNames>"
14
+ return if empty?
15
+ str << '<definedNames>'
16
16
  each { |defined_name| defined_name.to_xml_string(str) }
17
17
  str << '</definedNames>'
18
18
  end
@@ -38,7 +38,7 @@ module Axlsx
38
38
  @xml_space = xml_space
39
39
  @unique_cells = {}
40
40
  @shared_xml_string = ""
41
- shareable_cells = cells.flatten.select{ |cell| cell.plain_string? }
41
+ shareable_cells = cells.flatten.select{ |cell| cell.plain_string? || cell.contains_rich_text? }
42
42
  @count = shareable_cells.size
43
43
  resolve(shareable_cells)
44
44
  end
@@ -47,10 +47,10 @@ module Axlsx
47
47
  # @param [String] str
48
48
  # @return [String]
49
49
  def to_xml_string(str='')
50
- str << '<?xml version="1.0" encoding="UTF-8"?><sst xmlns="' << XML_NS << '"'
51
- str << ' count="' << @count.to_s << '" uniqueCount="' << unique_count.to_s << '"'
52
- str << ' xml:space="' << xml_space.to_s << '">' << @shared_xml_string << '</sst>'
53
- str = Axlsx::sanitize(str)
50
+ Axlsx::sanitize(@shared_xml_string)
51
+ str << ('<?xml version="1.0" encoding="UTF-8"?><sst xmlns="' << XML_NS << '"')
52
+ str << (' count="' << @count.to_s << '" uniqueCount="' << unique_count.to_s << '"')
53
+ str << (' xml:space="' << xml_space.to_s << '">' << @shared_xml_string << '</sst>')
54
54
  end
55
55
 
56
56
  private
@@ -5,10 +5,13 @@ require 'axlsx/workbook/worksheet/auto_filter/auto_filter.rb'
5
5
  require 'axlsx/workbook/worksheet/date_time_converter.rb'
6
6
  require 'axlsx/workbook/worksheet/protected_range.rb'
7
7
  require 'axlsx/workbook/worksheet/protected_ranges.rb'
8
+ require 'axlsx/workbook/worksheet/rich_text_run'
9
+ require 'axlsx/workbook/worksheet/rich_text'
8
10
  require 'axlsx/workbook/worksheet/cell_serializer.rb'
9
11
  require 'axlsx/workbook/worksheet/cell.rb'
10
12
  require 'axlsx/workbook/worksheet/page_margins.rb'
11
13
  require 'axlsx/workbook/worksheet/page_set_up_pr.rb'
14
+ require 'axlsx/workbook/worksheet/outline_pr.rb'
12
15
  require 'axlsx/workbook/worksheet/page_setup.rb'
13
16
  require 'axlsx/workbook/worksheet/header_footer.rb'
14
17
  require 'axlsx/workbook/worksheet/print_options.rb'
@@ -37,7 +40,8 @@ require 'axlsx/workbook/worksheet/worksheet_hyperlinks'
37
40
  require 'axlsx/workbook/worksheet/break'
38
41
  require 'axlsx/workbook/worksheet/row_breaks'
39
42
  require 'axlsx/workbook/worksheet/col_breaks'
40
-
43
+ require 'axlsx/workbook/workbook_view'
44
+ require 'axlsx/workbook/workbook_views'
41
45
 
42
46
 
43
47
  require 'axlsx/workbook/worksheet/worksheet.rb'
@@ -93,6 +97,15 @@ require 'axlsx/workbook/worksheet/selection.rb'
93
97
  @use_shared_strings = v
94
98
  end
95
99
 
100
+ # If true reverse the order in which the workbook is serialized
101
+ # @return [Boolean]
102
+ attr_reader :is_reversed
103
+
104
+ def is_reversed=(v)
105
+ Axlsx::validate_boolean(v)
106
+ @is_reversed = v
107
+ end
108
+
96
109
 
97
110
  # A collection of worksheets associated with this workbook.
98
111
  # @note The recommended way to manage worksheets is add_worksheet
@@ -139,6 +152,10 @@ require 'axlsx/workbook/worksheet/selection.rb'
139
152
  # @return [SimpleTypedList]
140
153
  attr_reader :pivot_tables
141
154
 
155
+ # A collection of views for this workbook
156
+ def views
157
+ @views ||= WorkbookViews.new
158
+ end
142
159
 
143
160
  # A collection of defined names for this workbook
144
161
  # @note The recommended way to manage defined names is Workbook#add_defined_name
@@ -263,6 +280,14 @@ require 'axlsx/workbook/worksheet/selection.rb'
263
280
  worksheet
264
281
  end
265
282
 
283
+ # Adds a new WorkbookView
284
+ # @return WorkbookViews
285
+ # @option options [Hash] options passed into the added WorkbookView
286
+ # @see WorkbookView#initialize
287
+ def add_view(options={})
288
+ views << WorkbookView.new(options)
289
+ end
290
+
266
291
  # Adds a defined name to this workbook
267
292
  # @return [DefinedName]
268
293
  # @param [String] formula @see DefinedName
@@ -283,7 +308,7 @@ require 'axlsx/workbook/worksheet/selection.rb'
283
308
  end
284
309
  r << Relationship.new(self, STYLES_R, STYLES_PN)
285
310
  if use_shared_strings
286
- r << Relationship.new(self, SHARED_STRINGS_R, SHARED_STRINGS_PN)
311
+ r << Relationship.new(self, SHARED_STRINGS_R, SHARED_STRINGS_PN)
287
312
  end
288
313
  r
289
314
  end
@@ -327,23 +352,23 @@ require 'axlsx/workbook/worksheet/selection.rb'
327
352
  # @param [String] str
328
353
  # @return [String]
329
354
  def to_xml_string(str='')
330
- add_worksheet unless worksheets.size > 0
355
+ add_worksheet(name: 'Sheet1') unless worksheets.size > 0
331
356
  str << '<?xml version="1.0" encoding="UTF-8"?>'
332
- str << '<workbook xmlns="' << XML_NS << '" xmlns:r="' << XML_NS_R << '">'
333
- str << '<workbookPr date1904="' << @@date1904.to_s << '"/>'
357
+ str << ('<workbook xmlns="' << XML_NS << '" xmlns:r="' << XML_NS_R << '">')
358
+ str << ('<workbookPr date1904="' << @@date1904.to_s << '"/>')
359
+ views.to_xml_string(str)
334
360
  str << '<sheets>'
335
- @worksheets.each_with_index do |sheet, index|
336
- str << '<sheet name="' << sheet.name << '" sheetId="' << (index+1).to_s << '" r:id="' << sheet.rId << '"/>'
337
- if defined_name = sheet.auto_filter.defined_name
338
- add_defined_name defined_name, :name => '_xlnm._FilterDatabase', :local_sheet_id => index, :hidden => 1
339
- end
361
+ if is_reversed
362
+ worksheets.reverse_each { |sheet| sheet.to_sheet_node_xml_string(str) }
363
+ else
364
+ worksheets.each { |sheet| sheet.to_sheet_node_xml_string(str) }
340
365
  end
341
366
  str << '</sheets>'
342
367
  defined_names.to_xml_string(str)
343
368
  unless pivot_tables.empty?
344
369
  str << '<pivotCaches>'
345
370
  pivot_tables.each do |pivot_table|
346
- str << '<pivotCache cacheId="' << pivot_table.cache_definition.cache_id.to_s << '" r:id="' << pivot_table.cache_definition.rId << '"/>'
371
+ str << ('<pivotCache cacheId="' << pivot_table.cache_definition.cache_id.to_s << '" r:id="' << pivot_table.cache_definition.rId << '"/>')
347
372
  end
348
373
  str << '</pivotCaches>'
349
374
  end
@@ -0,0 +1,80 @@
1
+ # <xsd:complexType name="CT_BookView">
2
+ # <xsd:sequence>
3
+ # <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
4
+ # </xsd:sequence>
5
+ # <xsd:attribute name="visibility" type="ST_Visibility" use="optional" default="visible"/>
6
+ # <xsd:attribute name="minimized" type="xsd:boolean" use="optional" default="false"/>
7
+ # <xsd:attribute name="showHorizontalScroll" type="xsd:boolean" use="optional" default="true"/>
8
+ # <xsd:attribute name="showVerticalScroll" type="xsd:boolean" use="optional" default="true"/>
9
+ # <xsd:attribute name="showSheetTabs" type="xsd:boolean" use="optional" default="true"/>
10
+ # <xsd:attribute name="xWindow" type="xsd:int" use="optional"/>
11
+ # <xsd:attribute name="yWindow" type="xsd:int" use="optional"/>
12
+ # <xsd:attribute name="windowWidth" type="xsd:unsignedInt" use="optional"/>
13
+ # <xsd:attribute name="windowHeight" type="xsd:unsignedInt" use="optional"/>
14
+ # <xsd:attribute name="tabRatio" type="xsd:unsignedInt" use="optional" default="600"/>
15
+ # <xsd:attribute name="firstSheet" type="xsd:unsignedInt" use="optional" default="0"/>
16
+ # <xsd:attribute name="activeTab" type="xsd:unsignedInt" use="optional" default="0"/>
17
+ # <xsd:attribute name="autoFilterDateGrouping" type="xsd:boolean" use="optional"
18
+ # default="true"/>
19
+ # </xsd:complexType>
20
+
21
+ module Axlsx
22
+
23
+ # A BookView defines the display properties for a workbook.
24
+ # Units for window widths and other dimensions are expressed in twips.
25
+ # Twip measurements are portable between different display resolutions.
26
+ # The formula is (screen pixels) * (20 * 72) / (logical device dpi),
27
+ # where the logical device dpi can be different for x and y coordinates.
28
+ class WorkbookView
29
+
30
+ include Axlsx::SerializedAttributes
31
+ include Axlsx::OptionsParser
32
+ include Axlsx::Accessors
33
+
34
+
35
+ # Creates a new BookView object
36
+ # @param [Hash] options A hash of key/value pairs that will be mapped to this instances attributes.
37
+ # @option [Symbol] visibility Specifies visible state of the workbook window. The default value for this attribute is :visible.
38
+ # @option [Boolean] minimized Specifies a boolean value that indicates whether the workbook window is minimized.
39
+ # @option [Boolean] show_horizontal_scroll Specifies a boolean value that indicates whether to display the horizontal scroll bar in the user interface.
40
+ # @option [Boolean] show_vertical_scroll Specifies a boolean value that indicates whether to display the vertical scroll bar.
41
+ # @option [Boolean] show_sheet_tabs Specifies a boolean value that indicates whether to display the sheet tabs in the user interface.
42
+ # @option [Integer] tab_ratio Specifies ratio between the workbook tabs bar and the horizontal scroll bar.
43
+ # @option [Integer] first_sheet Specifies the index to the first sheet in this book view.
44
+ # @option [Integer] active_tab Specifies an unsignedInt that contains the index to the active sheet in this book view.
45
+ # @option [Integer] x_window Specifies the X coordinate for the upper left corner of the workbook window. The unit of measurement for this value is twips.
46
+ # @option [Integer] y_window Specifies the Y coordinate for the upper left corner of the workbook window. The unit of measurement for this value is twips.
47
+ # @option [Integer] window_width Specifies the width of the workbook window. The unit of measurement for this value is twips.
48
+ # @option [Integer] window_height Specifies the height of the workbook window. The unit of measurement for this value is twips.
49
+ # @option [Boolean] auto_filter_date_grouping Specifies a boolean value that indicates whether to group dates when presenting the user with filtering options in the user interface.
50
+ def initialize(options={})
51
+ parse_options options
52
+ yield self if block_given?
53
+ end
54
+
55
+
56
+ unsigned_int_attr_accessor :x_window, :y_window, :window_width, :window_height,
57
+ :tab_ratio, :first_sheet, :active_tab
58
+
59
+ validated_attr_accessor [:visibility], :validate_view_visibility
60
+
61
+ serializable_attributes :visibility, :minimized,
62
+ :show_horizontal_scroll, :show_vertical_scroll,
63
+ :show_sheet_tabs, :tab_ratio, :first_sheet, :active_tab,
64
+ :x_window, :y_window, :window_width, :window_height,
65
+ :auto_filter_date_grouping
66
+
67
+ boolean_attr_accessor :minimized, :show_horizontal_scroll, :show_vertical_scroll,
68
+ :show_sheet_tabs, :auto_filter_date_grouping
69
+
70
+
71
+ # Serialize the WorkbookView
72
+ # @param [String] str
73
+ # @return [String]
74
+ def to_xml_string(str = '')
75
+ str << '<workbookView '
76
+ serialized_attributes str
77
+ str << '></workbookView>'
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,22 @@
1
+ module Axlsx
2
+ # a simple types list of BookView objects
3
+ class WorkbookViews < SimpleTypedList
4
+
5
+ # creates the book views object
6
+ def initialize
7
+ super WorkbookView
8
+ end
9
+
10
+ # Serialize to xml
11
+ # @param [String] str
12
+ # @return [String]
13
+ def to_xml_string(str = '')
14
+ return if empty?
15
+ str << "<bookViews>"
16
+ each { |view| view.to_xml_string(str) }
17
+ str << '</bookViews>'
18
+ end
19
+ end
20
+ end
21
+
22
+
@@ -47,8 +47,8 @@ module Axlsx
47
47
  columns.last
48
48
  end
49
49
 
50
- # actually performs the filtering of rows who's cells do not
51
- # match the filter.
50
+ # actually performs the filtering of rows who's cells do not
51
+ # match the filter.
52
52
  def apply
53
53
  first_cell, last_cell = range.split(':')
54
54
  start_point = Axlsx::name_to_indices(first_cell)
@@ -237,9 +237,7 @@ include Axlsx::SerializedAttributes
237
237
  # Serialize the object to xml
238
238
  # @param [String] str The string object this serialization will be concatenated to.
239
239
  def to_xml_string(str = '')
240
- str << '<dateGroupItem '
241
- serialized_attributes str
242
- str << '/>'
240
+ serialized_tag('dateGroupItem', str)
243
241
  end
244
242
  end
245
243
  end
@@ -28,9 +28,7 @@ module Axlsx
28
28
 
29
29
  # serializes the break to xml
30
30
  def to_xml_string(str='')
31
- str << '<brk '
32
- serialized_attributes str
33
- str << '></brk>'
31
+ serialized_tag('brk', str)
34
32
  end
35
33
  end
36
34
  end
@@ -30,17 +30,24 @@ module Axlsx
30
30
  # @option options [String] color an 8 letter rgb specification
31
31
  # @option options [Number] formula_value The value to cache for a formula cell.
32
32
  # @option options [Symbol] scheme must be one of :none, major, :minor
33
- def initialize(row, value="", options={})
34
- self.row=row
35
- @value = nil
36
- #@value = @font_name = @charset = @family = @b = @i = @strike = @outline = @shadow = nil
37
- #@formula_value = @condense = @u = @vertAlign = @sz = @color = @scheme = @extend = @ssti = nil
38
- @styles = row.worksheet.workbook.styles
39
- @row.cells << self
40
- parse_options options
41
- @style ||= 0
42
- @type ||= cell_type_from_value(value)
43
- @value = cast_value(value)
33
+ def initialize(row, value = nil, options = {})
34
+ @row = row
35
+ # Do not use instance vars if not needed to use less RAM
36
+ # And do not call parse_options on frequently used options
37
+ # to get less GC cycles
38
+ type = options.delete(:type) || cell_type_from_value(value)
39
+ self.type = type unless type == :string
40
+
41
+
42
+ val = options.delete(:style)
43
+ self.style = val unless val.nil? || val == 0
44
+ val = options.delete(:formula_value)
45
+ self.formula_value = val unless val.nil?
46
+
47
+ parse_options(options)
48
+
49
+ self.value = value
50
+ value.cell = self if contains_rich_text?
44
51
  end
45
52
 
46
53
  # this is the cached value for formula cells. If you want the values to render in iOS/Mac OSX preview
@@ -53,21 +60,27 @@ module Axlsx
53
60
  # needs to define bla=(v) and bla methods on the class that hook into a
54
61
  # set_attr method that kicks the suplied validator and updates the instance_variable
55
62
  # for the key
56
- INLINE_STYLES = ['value', 'type', 'font_name', 'charset',
57
- 'family', 'b', 'i', 'strike','outline',
58
- 'shadow', 'condense', 'extend', 'u',
59
- 'vertAlign', 'sz', 'color', 'scheme']
63
+ INLINE_STYLES = [:value, :type, :font_name, :charset,
64
+ :family, :b, :i, :strike, :outline,
65
+ :shadow, :condense, :extend, :u,
66
+ :vertAlign, :sz, :color, :scheme].freeze
67
+
68
+ # An array of valid cell types
69
+ CELL_TYPES = [:date, :time, :float, :integer, :richtext,
70
+ :string, :boolean, :iso_8601, :text].freeze
60
71
 
61
72
  # The index of the cellXfs item to be applied to this cell.
62
73
  # @return [Integer]
63
74
  # @see Axlsx::Styles
64
- attr_reader :style
75
+ def style
76
+ defined?(@style) ? @style : 0
77
+ end
65
78
 
66
79
  # The row this cell belongs to.
67
80
  # @return [Row]
68
81
  attr_reader :row
69
82
 
70
- # The cell's data type. Currently only six types are supported, :date, :time, :float, :integer, :string and :boolean.
83
+ # The cell's data type.
71
84
  # Changing the type for a cell will recast the value into that type. If no type option is specified in the constructor, the type is
72
85
  # automatically determed.
73
86
  # @see Cell#cell_type_from_value
@@ -78,18 +91,21 @@ module Axlsx
78
91
  # :string to :integer or :float, type conversions always return 0 or 0.0
79
92
  # :string, :integer, or :float to :time conversions always return the original value as a string and set the cells type to :string.
80
93
  # No support is currently implemented for parsing time strings.
81
- attr_reader :type
94
+ def type
95
+ defined?(@type) ? @type : :string
96
+ end
97
+
82
98
  # @see type
83
99
  def type=(v)
84
- RestrictionValidator.validate "Cell.type", [:date, :time, :float, :integer, :string, :boolean, :iso_8601], v
85
- @type=v
86
- self.value = @value unless @value.nil?
100
+ RestrictionValidator.validate :cell_type, CELL_TYPES, v
101
+ @type = v
102
+ self.value = @value unless !defined?(@value) || @value.nil?
87
103
  end
88
104
 
89
-
90
105
  # The value of this cell.
91
106
  # @return [String, Integer, Float, Time, Boolean] casted value based on cell's type attribute.
92
107
  attr_reader :value
108
+
93
109
  # @see value
94
110
  def value=(v)
95
111
  #TODO: consider doing value based type determination first?
@@ -99,16 +115,20 @@ module Axlsx
99
115
  # Indicates that the cell has one or more of the custom cell styles applied.
100
116
  # @return [Boolean]
101
117
  def is_text_run?
102
- @is_text_run ||= false
118
+ defined?(@is_text_run) && @is_text_run && !contains_rich_text?
119
+ end
120
+
121
+ def contains_rich_text?
122
+ type == :richtext
103
123
  end
104
124
 
105
125
  # Indicates if the cell is good for shared string table
106
126
  def plain_string?
107
- @type == :string && # String typed
127
+ (type == :string || type == :text) && # String typed
108
128
  !is_text_run? && # No inline styles
109
129
  !@value.nil? && # Not nil
110
130
  !@value.empty? && # Not empty
111
- !@value.start_with?('=') # Not a formula
131
+ !@value.start_with?(?=) # Not a formula
112
132
  end
113
133
 
114
134
  # The inline font_name property for the cell
@@ -231,7 +251,7 @@ module Axlsx
231
251
  attr_reader :vertAlign
232
252
  # @see vertAlign
233
253
  def vertAlign=(v)
234
- RestrictionValidator.validate "Cell.vertAlign", [:baseline, :subscript, :superscript], v
254
+ RestrictionValidator.validate :cell_vertAlign, [:baseline, :subscript, :superscript], v
235
255
  set_run_style nil, :vertAlign, v
236
256
  end
237
257
 
@@ -241,7 +261,7 @@ module Axlsx
241
261
  attr_reader :scheme
242
262
  # @see scheme
243
263
  def scheme=(v)
244
- RestrictionValidator.validate "Cell.schema", [:none, :major, :minor], v
264
+ RestrictionValidator.validate :cell_scheme, [:none, :major, :minor], v
245
265
  set_run_style nil, :scheme, v
246
266
  end
247
267
 
@@ -251,14 +271,14 @@ module Axlsx
251
271
 
252
272
  # @return [Integer] The index of the cell in the containing row.
253
273
  def index
254
- @row.cells.index(self)
274
+ @row.index(self)
255
275
  end
256
276
 
257
277
  # @return [String] The alpha(column)numeric(row) reference for this sell.
258
278
  # @example Relative Cell Reference
259
279
  # ws.rows.first.cells.first.r #=> "A1"
260
280
  def r
261
- Axlsx::cell_r index, @row.index
281
+ Axlsx::cell_r index, @row.row_index
262
282
  end
263
283
 
264
284
  # @return [String] The absolute alpha(column)numeric(row) reference for this sell.
@@ -272,26 +292,26 @@ module Axlsx
272
292
  # @raise [ArgumentError] Invalid cellXfs id if the value provided is not within cellXfs items range.
273
293
  def style=(v)
274
294
  Axlsx::validate_unsigned_int(v)
275
- count = @styles.cellXfs.size
295
+ count = styles.cellXfs.size
276
296
  raise ArgumentError, "Invalid cellXfs id" unless v < count
277
297
  @style = v
278
298
  end
279
299
 
280
- # @return [Array] of x/y coordinates in the cheet for this cell.
300
+ # @return [Array] of x/y coordinates in the sheet for this cell.
281
301
  def pos
282
- [index, row.index]
302
+ [index, row.row_index]
283
303
  end
284
304
 
285
305
  # Merges all the cells in a range created between this cell and the cell or string name for a cell provided
286
306
  # @see worksheet.merge_cells
287
307
  # @param [Cell, String] target The last cell, or str ref for the cell in the merge range
288
308
  def merge(target)
289
- range_end = if target.is_a?(String)
290
- target
291
- elsif(target.is_a?(Cell))
292
- target.r
293
- end
294
- self.row.worksheet.merge_cells "#{self.r}:#{range_end}" unless range_end.nil?
309
+ start, stop = if target.is_a?(String)
310
+ [self.r, target]
311
+ elsif(target.is_a?(Cell))
312
+ Axlsx.sort_cells([self, target]).map { |c| c.r }
313
+ end
314
+ self.row.worksheet.merge_cells "#{start}:#{stop}" unless stop.nil?
295
315
  end
296
316
 
297
317
  # Serializes the cell
@@ -304,17 +324,11 @@ module Axlsx
304
324
  end
305
325
 
306
326
  def is_formula?
307
- @type == :string && @value.to_s.start_with?('=')
327
+ type == :string && @value.to_s.start_with?(?=)
308
328
  end
309
329
 
310
- # This is still not perfect...
311
- # - scaling is not linear as font sizes increst
312
- # - different fonts have different mdw and char widths
313
- def autowidth
314
- return if is_formula? || value == nil
315
- mdw = 1.78 #This is the widest width of 0..9 in arial@10px)
316
- font_scale = (font_size/10.0).to_f
317
- ((value.to_s.count(Worksheet.thin_chars) * mdw + 5) / mdw * 256) / 256.0 * font_scale
330
+ def is_array_formula?
331
+ type == :string && @value.to_s.start_with?('{=') && @value.to_s.end_with?('}')
318
332
  end
319
333
 
320
334
  # returns the absolute or relative string style reference for
@@ -326,21 +340,71 @@ module Axlsx
326
340
  absolute ? r_abs : r
327
341
  end
328
342
 
343
+ # Creates a defined name in the workbook for this cell.
344
+ def name=(label)
345
+ row.worksheet.workbook.add_defined_name "#{row.worksheet.name}!#{r_abs}", name: label
346
+ @name = label
347
+ end
348
+
349
+ # returns the name of the cell
350
+ attr_reader :name
351
+
352
+ # Attempts to determine the correct width for this cell's content
353
+ # @return [Float]
354
+ def autowidth
355
+ return if is_formula? || value.nil?
356
+ if contains_rich_text?
357
+ string_width('', font_size) + value.autowidth
358
+ elsif styles.cellXfs[style].alignment && styles.cellXfs[style].alignment.wrap_text
359
+ max_width = 0
360
+ value.to_s.split(/\r?\n/).each do |line|
361
+ width = string_width(line, font_size)
362
+ max_width = width if width > max_width
363
+ end
364
+ max_width
365
+ else
366
+ string_width(value, font_size)
367
+ end
368
+ end
369
+
370
+ # Returns the sanatized value
371
+ # TODO find a better way to do this as it accounts for 30% of
372
+ # processing time in benchmarking...
373
+ def clean_value
374
+ if (type == :string || type == :text) && !Axlsx::trust_input
375
+ Axlsx::sanitize(::CGI.escapeHTML(@value.to_s))
376
+ else
377
+ @value.to_s
378
+ end
379
+ end
380
+
329
381
  private
330
382
 
383
+ def styles
384
+ row.worksheet.styles
385
+ end
386
+
387
+ # Returns the width of a string according to the current style
388
+ # This is still not perfect...
389
+ # - scaling is not linear as font sizes increase
390
+ def string_width(string, font_size)
391
+ font_scale = font_size / 10.0
392
+ (string.to_s.count(Worksheet::THIN_CHARS) + 3.0) * font_scale
393
+ end
394
+
331
395
  # we scale the font size if bold style is applied to either the style font or
332
396
  # the cell itself. Yes, it is a bit of a hack, but it is much better than using
333
397
  # imagemagick and loading metrics for every character.
334
398
  def font_size
335
- font = @styles.fonts[@styles.cellXfs[style].fontId] || @styles.fonts[0]
336
- size_from_styles = (font.b || b) ? font.sz * 1.5 : font.sz
337
- sz || size_from_styles
399
+ return sz if sz
400
+ font = styles.fonts[styles.cellXfs[style].fontId] || styles.fonts[0]
401
+ (font.b || (defined?(@b) && @b)) ? (font.sz * 1.5) : font.sz
338
402
  end
339
403
 
340
404
  # Utility method for setting inline style attributes
341
- def set_run_style( validator, attr, value)
342
- return unless INLINE_STYLES.include?(attr.to_s)
343
- Axlsx.send(validator, value) unless validator == nil
405
+ def set_run_style(validator, attr, value)
406
+ return unless INLINE_STYLES.include?(attr.to_sym)
407
+ Axlsx.send(validator, value) unless validator.nil?
344
408
  self.instance_variable_set :"@#{attr.to_s}", value
345
409
  @is_text_run = true
346
410
  end
@@ -351,9 +415,6 @@ module Axlsx
351
415
  @ssti = v
352
416
  end
353
417
 
354
- # assigns the owning row for this cell.
355
- def row=(v) @row=v end
356
-
357
418
  # Determines the cell type based on the cell value.
358
419
  # @note This is only used when a cell is created but no :type option is specified, the following rules apply:
359
420
  # 1. If the value is an instance of Date, the type is set to :date
@@ -369,15 +430,14 @@ module Axlsx
369
430
  :time
370
431
  elsif v.is_a?(TrueClass) || v.is_a?(FalseClass)
371
432
  :boolean
372
- elsif v.to_s =~ /\A[+-]?\d+?\Z/ #numeric
433
+ elsif v.to_s =~ Axlsx::NUMERIC_REGEX
373
434
  :integer
374
- elsif v.to_s =~ /\A[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\Z/ #float
435
+ elsif v.to_s =~ Axlsx::FLOAT_REGEX
375
436
  :float
376
- # \A(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[0-1]|0[1-9]|[1-2][0-9])
377
- # T(2[0-3]|[0-1][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?
378
- # (Z|[+-](?:2[0-3]|[0-1][0-9]):[0-5][0-9])?\Z
379
- elsif v.to_s =~/\A(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[0-1]|0[1-9]|[1-2][0-9])T(2[0-3]|[0-1][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?(Z|[+-](?:2[0-3]|[0-1][0-9]):[0-5][0-9])?\Z/
437
+ elsif v.to_s =~ Axlsx::ISO_8601_REGEX
380
438
  :iso_8601
439
+ elsif v.is_a? RichText
440
+ :richtext
381
441
  else
382
442
  :string
383
443
  end
@@ -388,27 +448,29 @@ module Axlsx
388
448
  # About Time - Time in OOXML is *different* from what you might expect. The history as to why is interesting, but you can safely assume that if you are generating docs on a mac, you will want to specify Workbook.1904 as true when using time typed values.
389
449
  # @see Axlsx#date1904
390
450
  def cast_value(v)
391
- return nil if v.nil?
392
- if @type == :date
451
+ return v if v.is_a?(RichText) || v.nil?
452
+ case type
453
+ when :date
393
454
  self.style = STYLE_DATE if self.style == 0
394
455
  v
395
- elsif (@type == :time && v.is_a?(Time)) || (@type == :time && v.respond_to?(:to_time))
456
+ when :time
396
457
  self.style = STYLE_DATE if self.style == 0
397
- v.respond_to?(:to_time) ? v.to_time : v
398
- elsif @type == :float
458
+ if !v.is_a?(Time) && v.respond_to?(:to_time)
459
+ v.to_time
460
+ else
461
+ v
462
+ end
463
+ when :float
399
464
  v.to_f
400
- elsif @type == :integer
465
+ when :integer
401
466
  v.to_i
402
- elsif @type == :boolean
467
+ when :boolean
403
468
  v ? 1 : 0
404
- elsif @type == :iso_8601
469
+ when :iso_8601
405
470
  #consumer is responsible for ensuring the iso_8601 format when specifying this type
406
471
  v
407
472
  else
408
- @type = :string
409
- # TODO find a better way to do this as it accounts for 30% of
410
- # processing time in benchmarking...
411
- Axlsx::trust_input ? v.to_s : ::CGI.escapeHTML(v.to_s)
473
+ v.to_s
412
474
  end
413
475
  end
414
476