caxlsx 2.0.2 → 3.0.0

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