caxlsx 3.1.1 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (294) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +9 -9
  3. data/.yardopts_guide +18 -18
  4. data/CHANGELOG.md +354 -343
  5. data/LICENSE +21 -21
  6. data/README.md +168 -172
  7. data/Rakefile +29 -29
  8. data/examples/generate.rb +15 -15
  9. data/lib/axlsx/content_type/abstract_content_type.rb +32 -32
  10. data/lib/axlsx/content_type/content_type.rb +26 -26
  11. data/lib/axlsx/content_type/default.rb +25 -25
  12. data/lib/axlsx/content_type/override.rb +25 -25
  13. data/lib/axlsx/doc_props/app.rb +235 -235
  14. data/lib/axlsx/doc_props/core.rb +39 -39
  15. data/lib/axlsx/drawing/area_chart.rb +99 -99
  16. data/lib/axlsx/drawing/area_series.rb +110 -110
  17. data/lib/axlsx/drawing/ax_data_source.rb +26 -26
  18. data/lib/axlsx/drawing/axes.rb +61 -61
  19. data/lib/axlsx/drawing/axis.rb +190 -190
  20. data/lib/axlsx/drawing/bar_3D_chart.rb +148 -148
  21. data/lib/axlsx/drawing/bar_chart.rb +138 -138
  22. data/lib/axlsx/drawing/bar_series.rb +97 -97
  23. data/lib/axlsx/drawing/bubble_chart.rb +59 -59
  24. data/lib/axlsx/drawing/bubble_series.rb +63 -63
  25. data/lib/axlsx/drawing/cat_axis.rb +85 -85
  26. data/lib/axlsx/drawing/chart.rb +276 -276
  27. data/lib/axlsx/drawing/d_lbls.rb +90 -90
  28. data/lib/axlsx/drawing/drawing.rb +167 -167
  29. data/lib/axlsx/drawing/graphic_frame.rb +54 -54
  30. data/lib/axlsx/drawing/hyperlink.rb +100 -100
  31. data/lib/axlsx/drawing/line_3D_chart.rb +68 -68
  32. data/lib/axlsx/drawing/line_chart.rb +99 -99
  33. data/lib/axlsx/drawing/line_series.rb +110 -110
  34. data/lib/axlsx/drawing/marker.rb +84 -84
  35. data/lib/axlsx/drawing/num_data.rb +52 -52
  36. data/lib/axlsx/drawing/num_data_source.rb +62 -62
  37. data/lib/axlsx/drawing/num_val.rb +34 -34
  38. data/lib/axlsx/drawing/one_cell_anchor.rb +99 -99
  39. data/lib/axlsx/drawing/pic.rb +211 -211
  40. data/lib/axlsx/drawing/picture_locking.rb +42 -42
  41. data/lib/axlsx/drawing/pie_3D_chart.rb +47 -47
  42. data/lib/axlsx/drawing/pie_series.rb +74 -74
  43. data/lib/axlsx/drawing/scaling.rb +60 -60
  44. data/lib/axlsx/drawing/scatter_chart.rb +74 -74
  45. data/lib/axlsx/drawing/scatter_series.rb +129 -98
  46. data/lib/axlsx/drawing/ser_axis.rb +45 -45
  47. data/lib/axlsx/drawing/series.rb +69 -69
  48. data/lib/axlsx/drawing/series_title.rb +25 -25
  49. data/lib/axlsx/drawing/str_data.rb +42 -42
  50. data/lib/axlsx/drawing/str_val.rb +34 -34
  51. data/lib/axlsx/drawing/title.rb +97 -97
  52. data/lib/axlsx/drawing/two_cell_anchor.rb +97 -97
  53. data/lib/axlsx/drawing/val_axis.rb +37 -37
  54. data/lib/axlsx/drawing/view_3D.rb +115 -115
  55. data/lib/axlsx/drawing/vml_drawing.rb +42 -42
  56. data/lib/axlsx/drawing/vml_shape.rb +66 -66
  57. data/lib/axlsx/package.rb +388 -388
  58. data/lib/axlsx/rels/relationship.rb +130 -130
  59. data/lib/axlsx/rels/relationships.rb +32 -32
  60. data/lib/axlsx/stylesheet/border.rb +73 -71
  61. data/lib/axlsx/stylesheet/border_pr.rb +71 -71
  62. data/lib/axlsx/stylesheet/cell_alignment.rb +132 -132
  63. data/lib/axlsx/stylesheet/cell_protection.rb +41 -41
  64. data/lib/axlsx/stylesheet/cell_style.rb +72 -72
  65. data/lib/axlsx/stylesheet/color.rb +76 -76
  66. data/lib/axlsx/stylesheet/dxf.rb +79 -79
  67. data/lib/axlsx/stylesheet/fill.rb +35 -35
  68. data/lib/axlsx/stylesheet/font.rb +156 -156
  69. data/lib/axlsx/stylesheet/gradient_fill.rb +103 -103
  70. data/lib/axlsx/stylesheet/gradient_stop.rb +37 -37
  71. data/lib/axlsx/stylesheet/num_fmt.rb +86 -86
  72. data/lib/axlsx/stylesheet/pattern_fill.rb +73 -73
  73. data/lib/axlsx/stylesheet/styles.rb +494 -420
  74. data/lib/axlsx/stylesheet/table_style.rb +54 -54
  75. data/lib/axlsx/stylesheet/table_style_element.rb +77 -77
  76. data/lib/axlsx/stylesheet/table_styles.rb +46 -46
  77. data/lib/axlsx/stylesheet/xf.rb +147 -147
  78. data/lib/axlsx/util/accessors.rb +64 -64
  79. data/lib/axlsx/util/constants.rb +410 -401
  80. data/lib/axlsx/util/mime_type_utils.rb +11 -11
  81. data/lib/axlsx/util/options_parser.rb +16 -16
  82. data/lib/axlsx/util/serialized_attributes.rb +89 -89
  83. data/lib/axlsx/util/simple_typed_list.rb +179 -179
  84. data/lib/axlsx/util/storage.rb +146 -146
  85. data/lib/axlsx/util/validators.rb +312 -312
  86. data/lib/axlsx/util/zip_command.rb +73 -73
  87. data/lib/axlsx/version.rb +5 -5
  88. data/lib/axlsx/workbook/defined_name.rb +128 -128
  89. data/lib/axlsx/workbook/defined_names.rb +21 -21
  90. data/lib/axlsx/workbook/shared_strings_table.rb +77 -77
  91. data/lib/axlsx/workbook/workbook.rb +395 -370
  92. data/lib/axlsx/workbook/workbook_view.rb +80 -80
  93. data/lib/axlsx/workbook/workbook_views.rb +22 -22
  94. data/lib/axlsx/workbook/worksheet/auto_filter/auto_filter.rb +77 -77
  95. data/lib/axlsx/workbook/worksheet/auto_filter/filter_column.rb +94 -94
  96. data/lib/axlsx/workbook/worksheet/auto_filter/filters.rb +244 -244
  97. data/lib/axlsx/workbook/worksheet/break.rb +35 -35
  98. data/lib/axlsx/workbook/worksheet/cell.rb +506 -505
  99. data/lib/axlsx/workbook/worksheet/cell_serializer.rb +164 -164
  100. data/lib/axlsx/workbook/worksheet/cfvo.rb +60 -60
  101. data/lib/axlsx/workbook/worksheet/cfvos.rb +18 -18
  102. data/lib/axlsx/workbook/worksheet/col.rb +145 -145
  103. data/lib/axlsx/workbook/worksheet/col_breaks.rb +35 -35
  104. data/lib/axlsx/workbook/worksheet/color_scale.rb +110 -110
  105. data/lib/axlsx/workbook/worksheet/cols.rb +23 -23
  106. data/lib/axlsx/workbook/worksheet/comment.rb +91 -91
  107. data/lib/axlsx/workbook/worksheet/comments.rb +82 -82
  108. data/lib/axlsx/workbook/worksheet/conditional_formatting.rb +82 -82
  109. data/lib/axlsx/workbook/worksheet/conditional_formatting_rule.rb +220 -220
  110. data/lib/axlsx/workbook/worksheet/conditional_formattings.rb +25 -25
  111. data/lib/axlsx/workbook/worksheet/data_bar.rb +129 -129
  112. data/lib/axlsx/workbook/worksheet/data_validation.rb +246 -246
  113. data/lib/axlsx/workbook/worksheet/data_validations.rb +28 -28
  114. data/lib/axlsx/workbook/worksheet/date_time_converter.rb +30 -30
  115. data/lib/axlsx/workbook/worksheet/dimension.rb +64 -64
  116. data/lib/axlsx/workbook/worksheet/header_footer.rb +52 -52
  117. data/lib/axlsx/workbook/worksheet/icon_set.rb +81 -81
  118. data/lib/axlsx/workbook/worksheet/merged_cells.rb +37 -37
  119. data/lib/axlsx/workbook/worksheet/outline_pr.rb +33 -33
  120. data/lib/axlsx/workbook/worksheet/page_margins.rb +97 -97
  121. data/lib/axlsx/workbook/worksheet/page_set_up_pr.rb +44 -44
  122. data/lib/axlsx/workbook/worksheet/page_setup.rb +240 -240
  123. data/lib/axlsx/workbook/worksheet/pane.rb +139 -139
  124. data/lib/axlsx/workbook/worksheet/pivot_table.rb +296 -294
  125. data/lib/axlsx/workbook/worksheet/pivot_table_cache_definition.rb +66 -66
  126. data/lib/axlsx/workbook/worksheet/pivot_tables.rb +24 -24
  127. data/lib/axlsx/workbook/worksheet/print_options.rb +39 -39
  128. data/lib/axlsx/workbook/worksheet/protected_range.rb +47 -47
  129. data/lib/axlsx/workbook/worksheet/protected_ranges.rb +37 -37
  130. data/lib/axlsx/workbook/worksheet/rich_text.rb +55 -55
  131. data/lib/axlsx/workbook/worksheet/rich_text_run.rb +250 -250
  132. data/lib/axlsx/workbook/worksheet/row.rb +164 -164
  133. data/lib/axlsx/workbook/worksheet/row_breaks.rb +33 -33
  134. data/lib/axlsx/workbook/worksheet/selection.rb +101 -101
  135. data/lib/axlsx/workbook/worksheet/sheet_calc_pr.rb +29 -29
  136. data/lib/axlsx/workbook/worksheet/sheet_data.rb +27 -27
  137. data/lib/axlsx/workbook/worksheet/sheet_pr.rb +87 -87
  138. data/lib/axlsx/workbook/worksheet/sheet_protection.rb +118 -118
  139. data/lib/axlsx/workbook/worksheet/sheet_view.rb +213 -213
  140. data/lib/axlsx/workbook/worksheet/table.rb +102 -102
  141. data/lib/axlsx/workbook/worksheet/table_style_info.rb +49 -49
  142. data/lib/axlsx/workbook/worksheet/tables.rb +34 -34
  143. data/lib/axlsx/workbook/worksheet/worksheet.rb +786 -768
  144. data/lib/axlsx/workbook/worksheet/worksheet_comments.rb +58 -58
  145. data/lib/axlsx/workbook/worksheet/worksheet_drawing.rb +58 -58
  146. data/lib/axlsx/workbook/worksheet/worksheet_hyperlink.rb +74 -74
  147. data/lib/axlsx/workbook/worksheet/worksheet_hyperlinks.rb +38 -38
  148. data/lib/axlsx.rb +185 -171
  149. data/lib/caxlsx.rb +2 -2
  150. data/lib/schema/dc.xsd +118 -118
  151. data/lib/schema/dcmitype.xsd +51 -51
  152. data/lib/schema/dcterms.xsd +331 -331
  153. data/lib/schema/dml-chartDrawing.xsd +146 -146
  154. data/lib/schema/dml-compatibility.xsd +14 -14
  155. data/lib/schema/dml-lockedCanvas.xsd +11 -11
  156. data/lib/schema/dml-main.xsd +3048 -3048
  157. data/lib/schema/dml-picture.xsd +23 -23
  158. data/lib/schema/dml-spreadsheetDrawing.xsd +185 -185
  159. data/lib/schema/dml-wordprocessingDrawing.xsd +185 -185
  160. data/lib/schema/shared-additionalCharacteristics.xsd +28 -28
  161. data/lib/schema/shared-bibliography.xsd +144 -144
  162. data/lib/schema/shared-commonSimpleTypes.xsd +166 -166
  163. data/lib/schema/shared-customXmlDataProperties.xsd +25 -25
  164. data/lib/schema/shared-customXmlSchemaProperties.xsd +18 -18
  165. data/lib/schema/shared-documentPropertiesCustom.xsd +59 -59
  166. data/lib/schema/shared-documentPropertiesExtended.xsd +56 -56
  167. data/lib/schema/shared-documentPropertiesVariantTypes.xsd +195 -195
  168. data/lib/schema/shared-relationshipReference.xsd +25 -25
  169. data/lib/schema/vml-main.xsd +569 -569
  170. data/lib/schema/vml-officeDrawing.xsd +509 -509
  171. data/lib/schema/vml-presentationDrawing.xsd +12 -12
  172. data/lib/schema/vml-spreadsheetDrawing.xsd +108 -108
  173. data/lib/schema/vml-wordprocessingDrawing.xsd +96 -96
  174. data/lib/schema/xml.xsd +116 -116
  175. data/test/benchmark.rb +72 -72
  176. data/test/content_type/tc_content_type.rb +76 -76
  177. data/test/content_type/tc_default.rb +16 -16
  178. data/test/content_type/tc_override.rb +14 -14
  179. data/test/doc_props/tc_app.rb +43 -43
  180. data/test/doc_props/tc_core.rb +42 -42
  181. data/test/drawing/tc_area_chart.rb +39 -39
  182. data/test/drawing/tc_area_series.rb +71 -71
  183. data/test/drawing/tc_axes.rb +7 -7
  184. data/test/drawing/tc_axis.rb +112 -112
  185. data/test/drawing/tc_bar_3D_chart.rb +86 -86
  186. data/test/drawing/tc_bar_chart.rb +86 -86
  187. data/test/drawing/tc_bar_series.rb +46 -46
  188. data/test/drawing/tc_bubble_chart.rb +44 -44
  189. data/test/drawing/tc_bubble_series.rb +21 -21
  190. data/test/drawing/tc_cat_axis.rb +31 -31
  191. data/test/drawing/tc_cat_axis_data.rb +27 -27
  192. data/test/drawing/tc_chart.rb +123 -123
  193. data/test/drawing/tc_d_lbls.rb +57 -57
  194. data/test/drawing/tc_data_source.rb +23 -23
  195. data/test/drawing/tc_drawing.rb +80 -80
  196. data/test/drawing/tc_graphic_frame.rb +27 -27
  197. data/test/drawing/tc_hyperlink.rb +64 -64
  198. data/test/drawing/tc_line_3d_chart.rb +47 -47
  199. data/test/drawing/tc_line_chart.rb +39 -39
  200. data/test/drawing/tc_line_series.rb +71 -71
  201. data/test/drawing/tc_marker.rb +44 -44
  202. data/test/drawing/tc_named_axis_data.rb +27 -27
  203. data/test/drawing/tc_num_data.rb +31 -31
  204. data/test/drawing/tc_num_val.rb +29 -29
  205. data/test/drawing/tc_one_cell_anchor.rb +66 -66
  206. data/test/drawing/tc_pic.rb +103 -103
  207. data/test/drawing/tc_picture_locking.rb +72 -72
  208. data/test/drawing/tc_pie_3D_chart.rb +28 -28
  209. data/test/drawing/tc_pie_series.rb +33 -33
  210. data/test/drawing/tc_scaling.rb +36 -36
  211. data/test/drawing/tc_scatter_chart.rb +48 -48
  212. data/test/drawing/tc_scatter_series.rb +74 -56
  213. data/test/drawing/tc_ser_axis.rb +31 -31
  214. data/test/drawing/tc_series.rb +23 -23
  215. data/test/drawing/tc_series_title.rb +54 -54
  216. data/test/drawing/tc_str_data.rb +18 -18
  217. data/test/drawing/tc_str_val.rb +30 -30
  218. data/test/drawing/tc_title.rb +70 -70
  219. data/test/drawing/tc_two_cell_anchor.rb +36 -36
  220. data/test/drawing/tc_val_axis.rb +24 -24
  221. data/test/drawing/tc_view_3D.rb +54 -54
  222. data/test/drawing/tc_vml_drawing.rb +25 -25
  223. data/test/drawing/tc_vml_shape.rb +106 -106
  224. data/test/profile.rb +24 -24
  225. data/test/rels/tc_relationship.rb +52 -52
  226. data/test/rels/tc_relationships.rb +37 -37
  227. data/test/stylesheet/tc_border.rb +37 -37
  228. data/test/stylesheet/tc_border_pr.rb +32 -32
  229. data/test/stylesheet/tc_cell_alignment.rb +81 -81
  230. data/test/stylesheet/tc_cell_protection.rb +29 -29
  231. data/test/stylesheet/tc_cell_style.rb +57 -57
  232. data/test/stylesheet/tc_color.rb +43 -43
  233. data/test/stylesheet/tc_dxf.rb +81 -81
  234. data/test/stylesheet/tc_fill.rb +18 -18
  235. data/test/stylesheet/tc_font.rb +133 -133
  236. data/test/stylesheet/tc_gradient_fill.rb +72 -72
  237. data/test/stylesheet/tc_gradient_stop.rb +31 -31
  238. data/test/stylesheet/tc_num_fmt.rb +30 -30
  239. data/test/stylesheet/tc_pattern_fill.rb +43 -43
  240. data/test/stylesheet/tc_styles.rb +309 -261
  241. data/test/stylesheet/tc_table_style.rb +44 -44
  242. data/test/stylesheet/tc_table_style_element.rb +45 -45
  243. data/test/stylesheet/tc_table_styles.rb +29 -29
  244. data/test/stylesheet/tc_xf.rb +120 -120
  245. data/test/tc_axlsx.rb +109 -109
  246. data/test/tc_helper.rb +10 -10
  247. data/test/tc_package.rb +317 -314
  248. data/test/util/tc_mime_type_utils.rb +13 -13
  249. data/test/util/tc_serialized_attributes.rb +19 -19
  250. data/test/util/tc_simple_typed_list.rb +77 -77
  251. data/test/util/tc_validators.rb +210 -210
  252. data/test/workbook/tc_defined_name.rb +49 -49
  253. data/test/workbook/tc_shared_strings_table.rb +59 -59
  254. data/test/workbook/tc_workbook.rb +165 -160
  255. data/test/workbook/tc_workbook_view.rb +50 -50
  256. data/test/workbook/worksheet/auto_filter/tc_auto_filter.rb +38 -38
  257. data/test/workbook/worksheet/auto_filter/tc_filter_column.rb +76 -76
  258. data/test/workbook/worksheet/auto_filter/tc_filters.rb +50 -50
  259. data/test/workbook/worksheet/tc_break.rb +49 -49
  260. data/test/workbook/worksheet/tc_cell.rb +465 -453
  261. data/test/workbook/worksheet/tc_cfvo.rb +31 -31
  262. data/test/workbook/worksheet/tc_col.rb +93 -93
  263. data/test/workbook/worksheet/tc_color_scale.rb +58 -58
  264. data/test/workbook/worksheet/tc_comment.rb +72 -72
  265. data/test/workbook/worksheet/tc_comments.rb +57 -57
  266. data/test/workbook/worksheet/tc_conditional_formatting.rb +224 -224
  267. data/test/workbook/worksheet/tc_data_bar.rb +46 -46
  268. data/test/workbook/worksheet/tc_data_validation.rb +265 -265
  269. data/test/workbook/worksheet/tc_date_time_converter.rb +124 -124
  270. data/test/workbook/worksheet/tc_header_footer.rb +151 -151
  271. data/test/workbook/worksheet/tc_icon_set.rb +45 -45
  272. data/test/workbook/worksheet/tc_outline_pr.rb +19 -19
  273. data/test/workbook/worksheet/tc_page_margins.rb +97 -97
  274. data/test/workbook/worksheet/tc_page_set_up_pr.rb +15 -15
  275. data/test/workbook/worksheet/tc_page_setup.rb +143 -143
  276. data/test/workbook/worksheet/tc_pane.rb +54 -54
  277. data/test/workbook/worksheet/tc_pivot_table.rb +180 -143
  278. data/test/workbook/worksheet/tc_pivot_table_cache_definition.rb +62 -62
  279. data/test/workbook/worksheet/tc_print_options.rb +72 -72
  280. data/test/workbook/worksheet/tc_protected_range.rb +17 -17
  281. data/test/workbook/worksheet/tc_rich_text.rb +44 -44
  282. data/test/workbook/worksheet/tc_rich_text_run.rb +173 -173
  283. data/test/workbook/worksheet/tc_row.rb +160 -160
  284. data/test/workbook/worksheet/tc_selection.rb +55 -55
  285. data/test/workbook/worksheet/tc_sheet_calc_pr.rb +18 -18
  286. data/test/workbook/worksheet/tc_sheet_format_pr.rb +88 -88
  287. data/test/workbook/worksheet/tc_sheet_pr.rb +49 -49
  288. data/test/workbook/worksheet/tc_sheet_protection.rb +117 -117
  289. data/test/workbook/worksheet/tc_sheet_view.rb +214 -214
  290. data/test/workbook/worksheet/tc_table.rb +77 -77
  291. data/test/workbook/worksheet/tc_table_style_info.rb +53 -53
  292. data/test/workbook/worksheet/tc_worksheet.rb +632 -601
  293. data/test/workbook/worksheet/tc_worksheet_hyperlink.rb +55 -55
  294. metadata +101 -101
@@ -1,768 +1,786 @@
1
- # encoding: UTF-8
2
- module Axlsx
3
-
4
- # The Worksheet class represents a worksheet in the workbook.
5
- class Worksheet
6
- include Axlsx::OptionsParser
7
- include Axlsx::SerializedAttributes
8
-
9
- # Creates a new worksheet.
10
- # @note the recommended way to manage worksheets is Workbook#add_worksheet
11
- # @see Workbook#add_worksheet
12
- # @option options [String] name The name of this worksheet.
13
- # @option options [Hash] page_margins A hash containing page margins for this worksheet. @see PageMargins
14
- # @option options [Hash] print_options A hash containing print options for this worksheet. @see PrintOptions
15
- # @option options [Hash] header_footer A hash containing header/footer options for this worksheet. @see HeaderFooter
16
- # @option options [Boolean] show_gridlines indicates if gridlines should be shown for this sheet.
17
- def initialize(wb, options={})
18
- self.workbook = wb
19
- @sheet_protection = nil
20
- initialize_page_options(options)
21
- parse_options options
22
- @workbook.worksheets << self
23
- @sheet_id = index + 1
24
- yield self if block_given?
25
- end
26
-
27
- serializable_attributes :sheet_id, :state
28
-
29
- # Initalizes page margin, setup and print options
30
- # @param [Hash] options Options passed in from the initializer
31
- def initialize_page_options(options)
32
- @page_margins = PageMargins.new options[:page_margins] if options[:page_margins]
33
- @page_setup = PageSetup.new options[:page_setup] if options[:page_setup]
34
- @print_options = PrintOptions.new options[:print_options] if options[:print_options]
35
- @header_footer = HeaderFooter.new options[:header_footer] if options[:header_footer]
36
- @row_breaks = RowBreaks.new
37
- @col_breaks = ColBreaks.new
38
- end
39
-
40
- # The name of the worksheet
41
- # @return [String]
42
- def name
43
- @name ||= "Sheet" + (index+1).to_s
44
- end
45
-
46
- # Specifies the visible state of this sheet. Allowed states are
47
- # :visible, :hidden or :very_hidden. The default value is :visible.
48
- #
49
- # Worksheets in the :hidden state can be shown using the sheet formatting properties in excel.
50
- # :very_hidden sheets should be inaccessible to end users.
51
- # @param [Symbol] sheet_state The visible state for this sheet.
52
- def state=(sheet_state)
53
- RestrictionValidator.validate :worksheet_state, [:visible, :hidden, :very_hidden], sheet_state
54
- @state = sheet_state
55
- end
56
-
57
- # The visibility of this sheet
58
- def state
59
- @state ||= :visible
60
- end
61
-
62
- # The sheet calculation properties
63
- # @return [SheetCalcPr]
64
- def sheet_calc_pr
65
- @sheet_calc_pr ||= SheetCalcPr.new
66
- end
67
-
68
- # The sheet protection object for this workbook
69
- # @return [SheetProtection]
70
- # @see SheetProtection
71
- def sheet_protection
72
- @sheet_protection ||= SheetProtection.new
73
- yield @sheet_protection if block_given?
74
- @sheet_protection
75
- end
76
-
77
- # The sheet view object for this worksheet
78
- # @return [SheetView]
79
- # @see [SheetView]
80
- def sheet_view
81
- @sheet_view ||= SheetView.new
82
- yield @sheet_view if block_given?
83
- @sheet_view
84
- end
85
-
86
- # The sheet format pr for this worksheet
87
- # @return [SheetFormatPr]
88
- # @see [SheetFormatPr]
89
- def sheet_format_pr
90
- @sheet_format_pr ||= SheetFormatPr.new
91
- yield @sheet_format_pr if block_given?
92
- @sheet_format_pr
93
- end
94
-
95
- # The workbook that owns this worksheet
96
- # @return [Workbook]
97
- attr_reader :workbook
98
-
99
- # The tables in this worksheet
100
- # @return [Array] of Table
101
- def tables
102
- @tables ||= Tables.new self
103
- end
104
-
105
- # The pivot tables in this worksheet
106
- # @return [Array] of Table
107
- def pivot_tables
108
- @pivot_tables ||= PivotTables.new self
109
- end
110
-
111
- # A collection of column breaks added to this worksheet
112
- # @note Please do not use this directly. Instead use
113
- # add_page_break
114
- # @see Worksheet#add_page_break
115
- def col_breaks
116
- @col_breaks ||= ColBreaks.new
117
- end
118
-
119
- # A collection of row breaks added to this worksheet
120
- # @note Please do not use this directly. Instead use
121
- # add_page_break
122
- # @see Worksheet#add_page_break
123
- def row_breaks
124
- @row_breaks ||= RowBreaks.new
125
- end
126
-
127
- # A typed collection of hyperlinks associated with this worksheet
128
- # @return [WorksheetHyperlinks]
129
- def hyperlinks
130
- @hyperlinks ||= WorksheetHyperlinks.new self
131
- end
132
-
133
- # The a shortcut to the worksheet_comments list of comments
134
- # @return [Array|SimpleTypedList]
135
- def comments
136
- worksheet_comments.comments if worksheet_comments.has_comments?
137
- end
138
-
139
- # The rows in this worksheet
140
- # @note The recommended way to manage rows is Worksheet#add_row
141
- # @return [SimpleTypedList]
142
- # @see Worksheet#add_row
143
- def rows
144
- @rows ||= SimpleTypedList.new Row
145
- end
146
-
147
- # returns the sheet data as columns
148
- # If you pass a block, it will be evaluated whenever a row does not have a
149
- # cell at a specific index. The block will be called with the row and column
150
- # index in the missing cell was found.
151
- # @example
152
- # cols { |row_index, column_index| puts "warn - row #{row_index} does not have a cell at #{column_index}" }
153
- def cols(&block)
154
- @rows.transpose(&block)
155
- end
156
-
157
- # A range that excel will apply an auto-filter to "A1:B3"
158
- # This will turn filtering on for the cells in the range.
159
- # The first row is considered the header, while subsequent rows are considered to be data.
160
- # @return String
161
- def auto_filter
162
- @auto_filter ||= AutoFilter.new self
163
- end
164
-
165
- # Indicates if the worksheet will be fit by witdh or height to a specific number of pages.
166
- # To alter the width or height for page fitting, please use page_setup.fit_to_widht or page_setup.fit_to_height.
167
- # If you want the worksheet to fit on more pages (e.g. 2x2), set {PageSetup#fit_to_width} and {PageSetup#fit_to_height} accordingly.
168
- # @return Boolean
169
- # @see #page_setup
170
- def fit_to_page?
171
- return false unless self.instance_values.keys.include?('page_setup')
172
- page_setup.fit_to_page?
173
- end
174
-
175
-
176
- # Column info for the sheet
177
- # @return [SimpleTypedList]
178
- def column_info
179
- @column_info ||= Cols.new self
180
- end
181
-
182
- # Page margins for printing the worksheet.
183
- # @example
184
- # wb = Axlsx::Package.new.workbook
185
- # # using options when creating the worksheet.
186
- # ws = wb.add_worksheet :page_margins => {:left => 1.9, :header => 0.1}
187
- #
188
- # # use the set method of the page_margins object
189
- # ws.page_margins.set(:bottom => 3, :footer => 0.7)
190
- #
191
- # # set page margins in a block
192
- # ws.page_margins do |margins|
193
- # margins.right = 6
194
- # margins.top = 0.2
195
- # end
196
- # @see PageMargins#initialize
197
- # @return [PageMargins]
198
- def page_margins
199
- @page_margins ||= PageMargins.new
200
- yield @page_margins if block_given?
201
- @page_margins
202
- end
203
-
204
- # Page setup settings for printing the worksheet.
205
- # @example
206
- # wb = Axlsx::Package.new.workbook
207
- #
208
- # # using options when creating the worksheet.
209
- # ws = wb.add_worksheet :page_setup => {:fit_to_width => 2, :orientation => :landscape}
210
- #
211
- # # use the set method of the page_setup object
212
- # ws.page_setup.set(:paper_width => "297mm", :paper_height => "210mm")
213
- #
214
- # # setup page in a block
215
- # ws.page_setup do |page|
216
- # page.scale = 80
217
- # page.orientation = :portrait
218
- # end
219
- # @see PageSetup#initialize
220
- # @return [PageSetup]
221
- def page_setup
222
- @page_setup ||= PageSetup.new
223
- yield @page_setup if block_given?
224
- @page_setup
225
- end
226
-
227
- # Options for printing the worksheet.
228
- # @example
229
- # wb = Axlsx::Package.new.workbook
230
- # # using options when creating the worksheet.
231
- # ws = wb.add_worksheet :print_options => {:grid_lines => true, :horizontal_centered => true}
232
- #
233
- # # use the set method of the page_margins object
234
- # ws.print_options.set(:headings => true)
235
- #
236
- # # set page margins in a block
237
- # ws.print_options do |options|
238
- # options.horizontal_centered = true
239
- # options.vertical_centered = true
240
- # end
241
- # @see PrintOptions#initialize
242
- # @return [PrintOptions]
243
- def print_options
244
- @print_options ||= PrintOptions.new
245
- yield @print_options if block_given?
246
- @print_options
247
- end
248
-
249
- # Options for headers and footers.
250
- # @example
251
- # wb = Axlsx::Package.new.workbook
252
- # # would generate something like: "file.xlsx : sheet_name 2 of 7 date with timestamp"
253
- # header = {:different_odd_ => false, :odd_header => "&L&F : &A&C&Pof%N%R%D %T"}
254
- # ws = wb.add_worksheet :header_footer => header
255
- #
256
- # @see HeaderFooter#initialize
257
- # @return [HeaderFooter]
258
- def header_footer
259
- @header_footer ||= HeaderFooter.new
260
- yield @header_footer if block_given?
261
- @header_footer
262
- end
263
-
264
- # convenience method to access all cells in this worksheet
265
- # @return [Array] cells
266
- def cells
267
- rows.flatten
268
- end
269
-
270
- # Creates merge information for this worksheet.
271
- # Cells can be merged by calling the merge_cells method on a worksheet.
272
- # @example This would merge the three cells C1..E1 #
273
- # worksheet.merge_cells "C1:E1"
274
- # # you can also provide an array of cells to be merged
275
- # worksheet.merge_cells worksheet.rows.first.cells[(2..4)]
276
- # #alternatively you can do it from a single cell
277
- # worksheet["C1"].merge worksheet["E1"]
278
- # @param [Array, string] cells
279
- def merge_cells(cells)
280
- merged_cells.add cells
281
- end
282
-
283
- # Adds a new protected cell range to the worksheet. Note that protected ranges are only in effect when sheet protection is enabled.
284
- # @param [String|Array] cells The string reference for the cells to protect or an array of cells.
285
- # @return [ProtectedRange]
286
- # @note When using an array of cells, a contiguous range is created from the minimum top left to the maximum top bottom of the cells provided.
287
- def protect_range(cells)
288
- protected_ranges.add_range(cells)
289
- end
290
-
291
- # The dimensions of a worksheet. This is not actually a required element by the spec,
292
- # but at least a few other document readers expect this for conversion
293
- # @return [Dimension]
294
- def dimension
295
- @dimension ||= Dimension.new self
296
- end
297
-
298
- # The sheet properties for this workbook.
299
- # Currently only pageSetUpPr -> fitToPage is implemented
300
- # @return [SheetPr]
301
- def sheet_pr
302
- @sheet_pr ||= SheetPr.new self
303
- end
304
-
305
- # The name of the worksheet
306
- # The name of a worksheet must be unique in the workbook, and must not exceed 31 characters
307
- # @param [String] name
308
- def name=(name)
309
- validate_sheet_name name
310
- @name=Axlsx::coder.encode(name)
311
- end
312
-
313
- # The auto filter range for the worksheet
314
- # @param [String] v
315
- # @see auto_filter
316
- def auto_filter=(v)
317
- DataTypeValidator.validate :worksheet_auto_filter, String, v
318
- auto_filter.range = v
319
- end
320
-
321
- # Accessor for controlling whether leading and trailing spaces in cells are
322
- # preserved or ignored. The default is to preserve spaces.
323
- attr_accessor :preserve_spaces
324
-
325
- # The part name of this worksheet
326
- # @return [String]
327
- def pn
328
- "#{WORKSHEET_PN % (index+1)}"
329
- end
330
-
331
- # The relationship part name of this worksheet
332
- # @return [String]
333
- def rels_pn
334
- "#{WORKSHEET_RELS_PN % (index+1)}"
335
- end
336
-
337
- # The relationship id of this worksheet.
338
- # @return [String]
339
- # @see Relationship#Id
340
- def rId
341
- @workbook.relationships.for(self).Id
342
- end
343
-
344
- # The index of this worksheet in the owning Workbook's worksheets list.
345
- # @return [Integer]
346
- def index
347
- @workbook.worksheets.index(self)
348
- end
349
-
350
- # The drawing associated with this worksheet.
351
- # @note the recommended way to work with drawings and charts is Worksheet#add_chart
352
- # @return [Drawing]
353
- # @see Worksheet#add_chart
354
- def drawing
355
- worksheet_drawing.drawing
356
- end
357
-
358
- # Adds a row to the worksheet and updates auto fit data.
359
- # @example - put a vanilla row in your spreadsheet
360
- # ws.add_row [1, 'fish on my pl', '8']
361
- #
362
- # @example - specify a fixed width for a column in your spreadsheet
363
- # # The first column will ignore the content of this cell when calculating column autowidth.
364
- # # The second column will include this text in calculating the columns autowidth
365
- # # The third cell will set a fixed with of 80 for the column.
366
- # # If you need to un-fix a column width, use :auto. That will recalculate the column width based on all content in the column
367
- #
368
- # ws.add_row ['I wish', 'for a fish', 'on my fish wish dish'], :widths=>[:ignore, :auto, 80]
369
- #
370
- # @example - specify a fixed height for a row
371
- # ws.add_row ['I wish', 'for a fish', 'on my fish wish dish'], :height => 40
372
- #
373
- # @example - create and use a style for all cells in the row
374
- # blue = ws.styles.add_style :color => "#00FF00"
375
- # ws.add_row [1, 2, 3], :style=>blue
376
- #
377
- # @example - only style some cells
378
- # blue = ws.styles.add_style :color => "#00FF00"
379
- # red = ws.styles.add_style :color => "#FF0000"
380
- # big = ws.styles.add_style :sz => 40
381
- # ws.add_row ["red fish", "blue fish", "one fish", "two fish"], :style=>[red, blue, nil, big] # the last nil is optional
382
- #
383
- #
384
- # @example - force the second cell to be a float value
385
- # ws.add_row [3, 4, 5], :types => [nil, :float]
386
- #
387
- # @example - use << alias
388
- # ws << [3, 4, 5], :types => [nil, :float]
389
- #
390
- # @example - specify whether a row should escape formulas or not
391
- # ws.add_row ['=IF(2+2=4,4,5)', 2, 3], :escape_formulas=>true
392
- #
393
- # @example - specify whether a certain cells in a row should escape formulas or not
394
- # ws.add_row ['=IF(2+2=4,4,5)', '=IF(13+13=4,4,5)'], :escape_formulas=>[true, false]
395
- #
396
- # @example - add a column offset when adding a row (inserts 'n' blank, unstyled columns before data)
397
- # ws.add_row ['I wish', 'for a fish', 'on my fish wish dish'], offset: 3
398
- #
399
- # @see Worksheet#column_widths
400
- # @return [Row]
401
- # @option options [Array] values
402
- # @option options [Array, Symbol] types
403
- # @option options [Array, Integer] style
404
- # @option options [Array] widths each member of the widths array will affect how auto_fit behavies.
405
- # @option options [Float] height the row's height (in points)
406
- # @option options [Integer] offset - add empty columns before values
407
- # @option options [Array, Boolean] escape_formulas - Whether to treat a value starting with an equal
408
- # sign as formula (default) or as simple string.
409
- # Allowing user generated data to be interpreted as formulas can be dangerous
410
- # (see https://www.owasp.org/index.php/CSV_Injection for details).
411
- def add_row(values=[], options={})
412
- row = Row.new(self, values, options)
413
- update_column_info row, options.delete(:widths)
414
- yield row if block_given?
415
- row
416
- end
417
-
418
- alias :<< :add_row
419
-
420
- # Add conditional formatting to this worksheet.
421
- #
422
- # @param [String] cells The range to apply the formatting to
423
- # @param [Array|Hash] rules An array of hashes (or just one) to create Conditional formatting rules from.
424
- # @example This would format column A whenever it is FALSE.
425
- # # for a longer example, see examples/example_conditional_formatting.rb (link below)
426
- # worksheet.add_conditional_formatting( "A1:A1048576", { :type => :cellIs, :operator => :equal, :formula => "FALSE", :dxfId => 1, :priority => 1 }
427
- #
428
- # @see ConditionalFormattingRule#initialize
429
- # @see file:examples/example_conditional_formatting.rb
430
- def add_conditional_formatting(cells, rules)
431
- cf = ConditionalFormatting.new( :sqref => cells )
432
- cf.add_rules rules
433
- conditional_formattings << cf
434
- conditional_formattings
435
- end
436
-
437
- # Add data validation to this worksheet.
438
- #
439
- # @param [String] cells The cells the validation will apply to.
440
- # @param [hash] data_validation options defining the validation to apply.
441
- # @see examples/data_validation.rb for an example
442
- def add_data_validation(cells, data_validation)
443
- dv = DataValidation.new(data_validation)
444
- dv.sqref = cells
445
- data_validations << dv
446
- end
447
-
448
- # Adds a new hyperlink to the worksheet
449
- # @param [Hash] options for the hyperlink
450
- # @see WorksheetHyperlink for a list of options
451
- # @return [WorksheetHyperlink]
452
- def add_hyperlink(options={})
453
- hyperlinks.add(options)
454
- end
455
-
456
- # Adds a chart to this worksheets drawing. This is the recommended way to create charts for your worksheet. This method wraps the complexity of dealing with ooxml drawing, anchors, markers graphic frames chart objects and all the other dirty details.
457
- # @param [Class] chart_type
458
- # @option options [Array] start_at
459
- # @option options [Array] end_at
460
- # @option options [Cell, String] title
461
- # @option options [Boolean] show_legend
462
- # @option options [Integer] style
463
- # @note each chart type also specifies additional options
464
- # @see Chart
465
- # @see Pie3DChart
466
- # @see Bar3DChart
467
- # @see Line3DChart
468
- # @see README for examples
469
- def add_chart(chart_type, options={})
470
- chart = worksheet_drawing.add_chart(chart_type, options)
471
- yield chart if block_given?
472
- chart
473
- end
474
-
475
- # needs documentation
476
- def add_table(ref, options={})
477
- tables << Table.new(ref, self, options)
478
- yield tables.last if block_given?
479
- tables.last
480
- end
481
-
482
- def add_pivot_table(ref, range, options={})
483
- pivot_tables << PivotTable.new(ref, range, self, options)
484
- yield pivot_tables.last if block_given?
485
- pivot_tables.last
486
- end
487
-
488
- # Shortcut to worsksheet_comments#add_comment
489
- def add_comment(options={})
490
- worksheet_comments.add_comment(options)
491
- end
492
-
493
- # Adds a media item to the worksheets drawing
494
- # @option [Hash] options options passed to drawing.add_image
495
- def add_image(options={})
496
- image = worksheet_drawing.add_image(options)
497
- yield image if block_given?
498
- image
499
- end
500
-
501
- # Adds a page break (row break) to the worksheet
502
- # @param cell A Cell object or excel style string reference indicating where the break
503
- # should be added to the sheet.
504
- # @example
505
- # ws.add_page_break("A4")
506
- def add_page_break(cell)
507
- DataTypeValidator.validate :worksheet_page_break, [String, Cell], cell
508
- column_index, row_index = if cell.is_a?(String)
509
- Axlsx.name_to_indices(cell)
510
- else
511
- cell.pos
512
- end
513
- if column_index > 0
514
- col_breaks.add_break(:id => column_index)
515
- end
516
- row_breaks.add_break(:id => row_index)
517
- end
518
-
519
- # This is a helper method that Lets you specify a fixed width for multiple columns in a worksheet in one go.
520
- # Note that you must call column_widths AFTER adding data, otherwise the width will not be set successfully.
521
- # Setting a fixed column width to nil will revert the behaviour back to calculating the width for you on the next call to add_row.
522
- # @example This would set the first and third column widhts but leave the second column in autofit state.
523
- # ws.column_widths 7.2, nil, 3
524
- # @note For updating only a single column it is probably easier to just set the width of the ws.column_info[col_index].width directly
525
- # @param [Integer|Float|nil] widths
526
- def column_widths(*widths)
527
- widths.each_with_index do |value, index|
528
- next if value == nil
529
- Axlsx::validate_unsigned_numeric(value) unless value == nil
530
- find_or_create_column_info(index).width = value
531
- end
532
- end
533
-
534
- # Set the style for cells in a specific column
535
- # @param [Integer] index the index of the column
536
- # @param [Integer] style the cellXfs index
537
- # @param [Hash] options
538
- # @option [Integer] :row_offset only cells after this column will be updated.
539
- # @note You can also specify the style for specific columns in the call to add_row by using an array for the :styles option
540
- # @see Worksheet#add_row
541
- # @see README.md for an example
542
- def col_style(index, style, options={})
543
- offset = options.delete(:row_offset) || 0
544
- cells = @rows[(offset..-1)].map { |row| row[index] }.flatten.compact
545
- cells.each { |cell| cell.style = style }
546
- end
547
-
548
- # Set the style for cells in a specific row
549
- # @param [Integer] index or range of indexes in the table
550
- # @param [Integer] style the cellXfs index
551
- # @param [Hash] options the options used when applying the style
552
- # @option [Integer] :col_offset only cells after this column will be updated.
553
- # @note You can also specify the style in the add_row call
554
- # @see Worksheet#add_row
555
- # @see README.md for an example
556
- def row_style(index, style, options={})
557
- offset = options.delete(:col_offset) || 0
558
- cells = cols[(offset..-1)].map { |column| column[index] }.flatten.compact
559
- cells.each { |cell| cell.style = style }
560
- end
561
-
562
- # Returns a sheet node serialization for this sheet in the workbook.
563
- def to_sheet_node_xml_string(str='')
564
- add_autofilter_defined_name_to_workbook
565
- str << '<sheet '
566
- serialized_attributes str
567
- str << ('name="' << name << '" ')
568
- str << ('r:id="' << rId << '"></sheet>')
569
- end
570
-
571
- # Serializes the worksheet object to an xml string
572
- # This intentionally does not use nokogiri for performance reasons
573
- # @return [String]
574
- def to_xml_string str=''
575
- add_autofilter_defined_name_to_workbook
576
- auto_filter.apply if auto_filter.range
577
- str << '<?xml version="1.0" encoding="UTF-8"?>'
578
- str << worksheet_node
579
- serializable_parts.each do |item|
580
- item.to_xml_string(str) if item
581
- end
582
- str << '</worksheet>'
583
- end
584
-
585
- # The worksheet relationships. This is managed automatically by the worksheet
586
- # @return [Relationships]
587
- def relationships
588
- r = Relationships.new
589
- r + [tables.relationships,
590
- worksheet_comments.relationships,
591
- hyperlinks.relationships,
592
- worksheet_drawing.relationship,
593
- pivot_tables.relationships].flatten.compact || []
594
- r
595
- end
596
-
597
- # Returns the cell or cells defined using excel style A1:B3 references.
598
- # @param [String|Integer] cell_def the string defining the cell or range of cells, or the rownumber
599
- # @return [Cell, Array]
600
- def [](cell_def)
601
- return rows[cell_def] if cell_def.is_a?(Integer)
602
- parts = cell_def.split(':').map{ |part| name_to_cell part }
603
- if parts.size == 1
604
- parts.first
605
- else
606
- range(*parts)
607
- end
608
- end
609
-
610
- # returns the column and row index for a named based cell
611
- # @param [String] name The cell or cell range to return. "A1" will return the first cell of the first row.
612
- # @return [Cell]
613
- def name_to_cell(name)
614
- col_index, row_index = *Axlsx::name_to_indices(name)
615
- r = rows[row_index]
616
- r[col_index] if r
617
- end
618
-
619
- # shortcut method to access styles direclty from the worksheet
620
- # This lets us do stuff like:
621
- # @example
622
- # p = Axlsx::Package.new
623
- # p.workbook.add_worksheet(:name => 'foo') do |sheet|
624
- # my_style = sheet.styles.add_style { :bg_color => "FF0000" }
625
- # sheet.add_row ['Oh No!'], :styles => my_style
626
- # end
627
- # p.serialize 'foo.xlsx'
628
- def styles
629
- @styles ||= self.workbook.styles
630
- end
631
-
632
- # shortcut level to specify the outline level for a series of rows
633
- # Oulining is what lets you add collapse and expand to a data set.
634
- # @param [Integer] start_index The zero based index of the first row of outlining.
635
- # @param [Integer] end_index The zero based index of the last row to be outlined
636
- # @param [integer] level The level of outline to apply
637
- # @param [Integer] collapsed The initial collapsed state of the outline group
638
- def outline_level_rows(start_index, end_index, level = 1, collapsed = true)
639
- outline rows, (start_index..end_index), level, collapsed
640
- end
641
-
642
- # shortcut level to specify the outline level for a series of columns
643
- # Oulining is what lets you add collapse and expand to a data set.
644
- # @param [Integer] start_index The zero based index of the first column of outlining.
645
- # @param [Integer] end_index The zero based index of the last column to be outlined
646
- # @param [integer] level The level of outline to apply
647
- # @param [Integer] collapsed The initial collapsed state of the outline group
648
- def outline_level_columns(start_index, end_index, level = 1, collapsed = true)
649
- outline column_info, (start_index..end_index), level, collapsed
650
- end
651
-
652
- private
653
-
654
- def xml_space
655
- workbook.xml_space
656
- end
657
-
658
- def outline(collection, range, level = 1, collapsed = true)
659
- range.each do |index|
660
- unless (item = collection[index]).nil?
661
- item.outline_level = level
662
- item.hidden = collapsed
663
- end
664
- sheet_view.show_outline_symbols = true
665
- end
666
- end
667
-
668
- def validate_sheet_name(name)
669
- DataTypeValidator.validate :worksheet_name, String, name
670
- # ignore first character (BOM) after encoding to utf16 because Excel does so, too.
671
- character_length = name.encode("utf-16")[1..-1].encode("utf-16").bytesize / 2
672
- raise ArgumentError, (ERR_SHEET_NAME_TOO_LONG % name) if character_length > 31
673
- raise ArgumentError, (ERR_SHEET_NAME_CHARACTER_FORBIDDEN % name) if '[]*/\?:'.chars.any? { |char| name.include? char }
674
- name = Axlsx::coder.encode(name)
675
- sheet_names = @workbook.worksheets.reject { |s| s == self }.map { |s| s.name }
676
- raise ArgumentError, (ERR_DUPLICATE_SHEET_NAME % name) if sheet_names.include?(name)
677
- end
678
-
679
- def serializable_parts
680
- [sheet_pr, dimension, sheet_view, sheet_format_pr, column_info,
681
- sheet_data, sheet_calc_pr, @sheet_protection, protected_ranges,
682
- auto_filter, merged_cells, conditional_formattings,
683
- data_validations, hyperlinks, print_options, page_margins,
684
- page_setup, header_footer, row_breaks, col_breaks, worksheet_drawing, worksheet_comments,
685
- tables]
686
- end
687
-
688
- def range(*cell_def)
689
- first, last = cell_def
690
- cells = []
691
- rows[(first.row.row_index..last.row.row_index)].each do |r|
692
- r[(first.index..last.index)].each do |c|
693
- cells << c
694
- end
695
- end
696
- cells
697
- end
698
-
699
- # A collection of protected ranges in the worksheet
700
- # @note The recommended way to manage protected ranges is with Worksheet#protect_range
701
- # @see Worksheet#protect_range
702
- # @return [SimpleTypedList] The protected ranges for this worksheet
703
- def protected_ranges
704
- @protected_ranges ||= ProtectedRanges.new self
705
- # SimpleTypedList.new ProtectedRange
706
- end
707
-
708
- # conditional formattings
709
- # @return [Array]
710
- def conditional_formattings
711
- @conditional_formattings ||= ConditionalFormattings.new self
712
- end
713
-
714
- # data validations array
715
- # @return [Array]
716
- def data_validations
717
- @data_validations ||= DataValidations.new self
718
- end
719
-
720
- # merged cells array
721
- # @return [Array]
722
- def merged_cells
723
- @merged_cells ||= MergedCells.new self
724
- end
725
-
726
-
727
- # Helper method for parsingout the root node for worksheet
728
- # @return [String]
729
- def worksheet_node
730
- "<worksheet xmlns=\"#{XML_NS}\" xmlns:r=\"#{XML_NS_R}\" xml:space=\"#{xml_space}\">"
731
- end
732
-
733
- def sheet_data
734
- @sheet_data ||= SheetData.new self
735
- end
736
-
737
- def worksheet_drawing
738
- @worksheet_drawing ||= WorksheetDrawing.new self
739
- end
740
-
741
- # The comments associated with this worksheet
742
- # @return [SimpleTypedList]
743
- def worksheet_comments
744
- @worksheet_comments ||= WorksheetComments.new self
745
- end
746
-
747
- def workbook=(v) DataTypeValidator.validate "Worksheet.workbook", Workbook, v; @workbook = v; end
748
-
749
- def update_column_info(cells, widths=nil)
750
- cells.each_with_index do |cell, index|
751
- width = widths ? widths[index] : nil
752
- col = find_or_create_column_info(index)
753
- next if width == :ignore
754
- col.update_width(cell, width, workbook.use_autowidth)
755
- end
756
- end
757
-
758
- def find_or_create_column_info(index)
759
- column_info[index] ||= Col.new(index + 1, index + 1)
760
- end
761
-
762
- def add_autofilter_defined_name_to_workbook
763
- return if !auto_filter.range
764
- workbook.add_defined_name auto_filter.defined_name, name: '_xlnm._FilterDatabase', local_sheet_id: index, hidden: 1
765
- end
766
-
767
- end
768
- end
1
+ # encoding: UTF-8
2
+ module Axlsx
3
+
4
+ # The Worksheet class represents a worksheet in the workbook.
5
+ class Worksheet
6
+ include Axlsx::OptionsParser
7
+ include Axlsx::SerializedAttributes
8
+
9
+ # Creates a new worksheet.
10
+ # @note the recommended way to manage worksheets is Workbook#add_worksheet
11
+ # @see Workbook#add_worksheet
12
+ # @option options [String] name The name of this worksheet.
13
+ # @option options [Hash] page_margins A hash containing page margins for this worksheet. @see PageMargins
14
+ # @option options [Hash] print_options A hash containing print options for this worksheet. @see PrintOptions
15
+ # @option options [Hash] header_footer A hash containing header/footer options for this worksheet. @see HeaderFooter
16
+ # @option options [Boolean] show_gridlines indicates if gridlines should be shown for this sheet.
17
+ def initialize(wb, options={})
18
+ self.workbook = wb
19
+ @sheet_protection = nil
20
+ initialize_page_options(options)
21
+ parse_options options
22
+ @workbook.worksheets << self
23
+ @sheet_id = index + 1
24
+ yield self if block_given?
25
+ end
26
+
27
+ serializable_attributes :sheet_id, :state
28
+
29
+ # Initalizes page margin, setup and print options
30
+ # @param [Hash] options Options passed in from the initializer
31
+ def initialize_page_options(options)
32
+ @page_margins = PageMargins.new options[:page_margins] if options[:page_margins]
33
+ @page_setup = PageSetup.new options[:page_setup] if options[:page_setup]
34
+ @print_options = PrintOptions.new options[:print_options] if options[:print_options]
35
+ @header_footer = HeaderFooter.new options[:header_footer] if options[:header_footer]
36
+ @row_breaks = RowBreaks.new
37
+ @col_breaks = ColBreaks.new
38
+ end
39
+
40
+ # The name of the worksheet
41
+ # @return [String]
42
+ def name
43
+ @name ||= "Sheet" + (index+1).to_s
44
+ end
45
+
46
+ # Specifies the visible state of this sheet. Allowed states are
47
+ # :visible, :hidden or :very_hidden. The default value is :visible.
48
+ #
49
+ # Worksheets in the :hidden state can be shown using the sheet formatting properties in excel.
50
+ # :very_hidden sheets should be inaccessible to end users.
51
+ # @param [Symbol] sheet_state The visible state for this sheet.
52
+ def state=(sheet_state)
53
+ RestrictionValidator.validate :worksheet_state, [:visible, :hidden, :very_hidden], sheet_state
54
+ @state = sheet_state
55
+ end
56
+
57
+ # The visibility of this sheet
58
+ def state
59
+ @state ||= :visible
60
+ end
61
+
62
+ # The sheet calculation properties
63
+ # @return [SheetCalcPr]
64
+ def sheet_calc_pr
65
+ @sheet_calc_pr ||= SheetCalcPr.new
66
+ end
67
+
68
+ # The sheet protection object for this workbook
69
+ # @return [SheetProtection]
70
+ # @see SheetProtection
71
+ def sheet_protection
72
+ @sheet_protection ||= SheetProtection.new
73
+ yield @sheet_protection if block_given?
74
+ @sheet_protection
75
+ end
76
+
77
+ # The sheet view object for this worksheet
78
+ # @return [SheetView]
79
+ # @see [SheetView]
80
+ def sheet_view
81
+ @sheet_view ||= SheetView.new
82
+ yield @sheet_view if block_given?
83
+ @sheet_view
84
+ end
85
+
86
+ # The sheet format pr for this worksheet
87
+ # @return [SheetFormatPr]
88
+ # @see [SheetFormatPr]
89
+ def sheet_format_pr
90
+ @sheet_format_pr ||= SheetFormatPr.new
91
+ yield @sheet_format_pr if block_given?
92
+ @sheet_format_pr
93
+ end
94
+
95
+ # The workbook that owns this worksheet
96
+ # @return [Workbook]
97
+ attr_reader :workbook
98
+
99
+ # The tables in this worksheet
100
+ # @return [Array] of Table
101
+ def tables
102
+ @tables ||= Tables.new self
103
+ end
104
+
105
+ # The pivot tables in this worksheet
106
+ # @return [Array] of Table
107
+ def pivot_tables
108
+ @pivot_tables ||= PivotTables.new self
109
+ end
110
+
111
+ # A collection of column breaks added to this worksheet
112
+ # @note Please do not use this directly. Instead use
113
+ # add_page_break
114
+ # @see Worksheet#add_page_break
115
+ def col_breaks
116
+ @col_breaks ||= ColBreaks.new
117
+ end
118
+
119
+ # A collection of row breaks added to this worksheet
120
+ # @note Please do not use this directly. Instead use
121
+ # add_page_break
122
+ # @see Worksheet#add_page_break
123
+ def row_breaks
124
+ @row_breaks ||= RowBreaks.new
125
+ end
126
+
127
+ # A typed collection of hyperlinks associated with this worksheet
128
+ # @return [WorksheetHyperlinks]
129
+ def hyperlinks
130
+ @hyperlinks ||= WorksheetHyperlinks.new self
131
+ end
132
+
133
+ # The a shortcut to the worksheet_comments list of comments
134
+ # @return [Array|SimpleTypedList]
135
+ def comments
136
+ worksheet_comments.comments if worksheet_comments.has_comments?
137
+ end
138
+
139
+ # The rows in this worksheet
140
+ # @note The recommended way to manage rows is Worksheet#add_row
141
+ # @return [SimpleTypedList]
142
+ # @see Worksheet#add_row
143
+ def rows
144
+ @rows ||= SimpleTypedList.new Row
145
+ end
146
+
147
+ # returns the sheet data as columns
148
+ # If you pass a block, it will be evaluated whenever a row does not have a
149
+ # cell at a specific index. The block will be called with the row and column
150
+ # index in the missing cell was found.
151
+ # @example
152
+ # cols { |row_index, column_index| puts "warn - row #{row_index} does not have a cell at #{column_index}" }
153
+ def cols(&block)
154
+ @rows.transpose(&block)
155
+ end
156
+
157
+ # A range that excel will apply an auto-filter to "A1:B3"
158
+ # This will turn filtering on for the cells in the range.
159
+ # The first row is considered the header, while subsequent rows are considered to be data.
160
+ # @return String
161
+ def auto_filter
162
+ @auto_filter ||= AutoFilter.new self
163
+ end
164
+
165
+ # Indicates if the worksheet will be fit by witdh or height to a specific number of pages.
166
+ # To alter the width or height for page fitting, please use page_setup.fit_to_widht or page_setup.fit_to_height.
167
+ # If you want the worksheet to fit on more pages (e.g. 2x2), set {PageSetup#fit_to_width} and {PageSetup#fit_to_height} accordingly.
168
+ # @return Boolean
169
+ # @see #page_setup
170
+ def fit_to_page?
171
+ return false unless self.instance_values.keys.include?('page_setup')
172
+ page_setup.fit_to_page?
173
+ end
174
+
175
+
176
+ # Column info for the sheet
177
+ # @return [SimpleTypedList]
178
+ def column_info
179
+ @column_info ||= Cols.new self
180
+ end
181
+
182
+ # Page margins for printing the worksheet.
183
+ # @example
184
+ # wb = Axlsx::Package.new.workbook
185
+ # # using options when creating the worksheet.
186
+ # ws = wb.add_worksheet :page_margins => {:left => 1.9, :header => 0.1}
187
+ #
188
+ # # use the set method of the page_margins object
189
+ # ws.page_margins.set(:bottom => 3, :footer => 0.7)
190
+ #
191
+ # # set page margins in a block
192
+ # ws.page_margins do |margins|
193
+ # margins.right = 6
194
+ # margins.top = 0.2
195
+ # end
196
+ # @see PageMargins#initialize
197
+ # @return [PageMargins]
198
+ def page_margins
199
+ @page_margins ||= PageMargins.new
200
+ yield @page_margins if block_given?
201
+ @page_margins
202
+ end
203
+
204
+ # Page setup settings for printing the worksheet.
205
+ # @example
206
+ # wb = Axlsx::Package.new.workbook
207
+ #
208
+ # # using options when creating the worksheet.
209
+ # ws = wb.add_worksheet :page_setup => {:fit_to_width => 2, :orientation => :landscape}
210
+ #
211
+ # # use the set method of the page_setup object
212
+ # ws.page_setup.set(:paper_width => "297mm", :paper_height => "210mm")
213
+ #
214
+ # # setup page in a block
215
+ # ws.page_setup do |page|
216
+ # page.scale = 80
217
+ # page.orientation = :portrait
218
+ # end
219
+ # @see PageSetup#initialize
220
+ # @return [PageSetup]
221
+ def page_setup
222
+ @page_setup ||= PageSetup.new
223
+ yield @page_setup if block_given?
224
+ @page_setup
225
+ end
226
+
227
+ # Options for printing the worksheet.
228
+ # @example
229
+ # wb = Axlsx::Package.new.workbook
230
+ # # using options when creating the worksheet.
231
+ # ws = wb.add_worksheet :print_options => {:grid_lines => true, :horizontal_centered => true}
232
+ #
233
+ # # use the set method of the page_margins object
234
+ # ws.print_options.set(:headings => true)
235
+ #
236
+ # # set page margins in a block
237
+ # ws.print_options do |options|
238
+ # options.horizontal_centered = true
239
+ # options.vertical_centered = true
240
+ # end
241
+ # @see PrintOptions#initialize
242
+ # @return [PrintOptions]
243
+ def print_options
244
+ @print_options ||= PrintOptions.new
245
+ yield @print_options if block_given?
246
+ @print_options
247
+ end
248
+
249
+ # Options for headers and footers.
250
+ # @example
251
+ # wb = Axlsx::Package.new.workbook
252
+ # # would generate something like: "file.xlsx : sheet_name 2 of 7 date with timestamp"
253
+ # header = {:different_odd_ => false, :odd_header => "&L&F : &A&C&Pof%N%R%D %T"}
254
+ # ws = wb.add_worksheet :header_footer => header
255
+ #
256
+ # @see HeaderFooter#initialize
257
+ # @return [HeaderFooter]
258
+ def header_footer
259
+ @header_footer ||= HeaderFooter.new
260
+ yield @header_footer if block_given?
261
+ @header_footer
262
+ end
263
+
264
+ # convenience method to access all cells in this worksheet
265
+ # @return [Array] cells
266
+ def cells
267
+ rows.flatten
268
+ end
269
+
270
+ # Creates merge information for this worksheet.
271
+ # Cells can be merged by calling the merge_cells method on a worksheet.
272
+ # @example This would merge the three cells C1..E1 #
273
+ # worksheet.merge_cells "C1:E1"
274
+ # # you can also provide an array of cells to be merged
275
+ # worksheet.merge_cells worksheet.rows.first.cells[(2..4)]
276
+ # #alternatively you can do it from a single cell
277
+ # worksheet["C1"].merge worksheet["E1"]
278
+ # @param [Array, string] cells
279
+ def merge_cells(cells)
280
+ merged_cells.add cells
281
+ end
282
+
283
+ # Adds a new protected cell range to the worksheet. Note that protected ranges are only in effect when sheet protection is enabled.
284
+ # @param [String|Array] cells The string reference for the cells to protect or an array of cells.
285
+ # @return [ProtectedRange]
286
+ # @note When using an array of cells, a contiguous range is created from the minimum top left to the maximum top bottom of the cells provided.
287
+ def protect_range(cells)
288
+ protected_ranges.add_range(cells)
289
+ end
290
+
291
+ # The dimensions of a worksheet. This is not actually a required element by the spec,
292
+ # but at least a few other document readers expect this for conversion
293
+ # @return [Dimension]
294
+ def dimension
295
+ @dimension ||= Dimension.new self
296
+ end
297
+
298
+ # The sheet properties for this workbook.
299
+ # Currently only pageSetUpPr -> fitToPage is implemented
300
+ # @return [SheetPr]
301
+ def sheet_pr
302
+ @sheet_pr ||= SheetPr.new self
303
+ end
304
+
305
+ # The name of the worksheet
306
+ # The name of a worksheet must be unique in the workbook, and must not exceed 31 characters
307
+ # @param [String] name
308
+ def name=(name)
309
+ validate_sheet_name name
310
+ @name=Axlsx::coder.encode(name)
311
+ end
312
+
313
+ # The auto filter range for the worksheet
314
+ # @param [String] v
315
+ # @see auto_filter
316
+ def auto_filter=(v)
317
+ DataTypeValidator.validate :worksheet_auto_filter, String, v
318
+ auto_filter.range = v
319
+ end
320
+
321
+ # Accessor for controlling whether leading and trailing spaces in cells are
322
+ # preserved or ignored. The default is to preserve spaces.
323
+ attr_accessor :preserve_spaces
324
+
325
+ # The part name of this worksheet
326
+ # @return [String]
327
+ def pn
328
+ "#{WORKSHEET_PN % (index+1)}"
329
+ end
330
+
331
+ # The relationship part name of this worksheet
332
+ # @return [String]
333
+ def rels_pn
334
+ "#{WORKSHEET_RELS_PN % (index+1)}"
335
+ end
336
+
337
+ # The relationship id of this worksheet.
338
+ # @return [String]
339
+ # @see Relationship#Id
340
+ def rId
341
+ @workbook.relationships.for(self).Id
342
+ end
343
+
344
+ # The index of this worksheet in the owning Workbook's worksheets list.
345
+ # @return [Integer]
346
+ def index
347
+ @workbook.worksheets.index(self)
348
+ end
349
+
350
+ # The drawing associated with this worksheet.
351
+ # @note the recommended way to work with drawings and charts is Worksheet#add_chart
352
+ # @return [Drawing]
353
+ # @see Worksheet#add_chart
354
+ def drawing
355
+ worksheet_drawing.drawing
356
+ end
357
+
358
+ # Adds a row to the worksheet and updates auto fit data.
359
+ # @example - put a vanilla row in your spreadsheet
360
+ # ws.add_row [1, 'fish on my pl', '8']
361
+ #
362
+ # @example - specify a fixed width for a column in your spreadsheet
363
+ # # The first column will ignore the content of this cell when calculating column autowidth.
364
+ # # The second column will include this text in calculating the columns autowidth
365
+ # # The third cell will set a fixed with of 80 for the column.
366
+ # # If you need to un-fix a column width, use :auto. That will recalculate the column width based on all content in the column
367
+ #
368
+ # ws.add_row ['I wish', 'for a fish', 'on my fish wish dish'], :widths=>[:ignore, :auto, 80]
369
+ #
370
+ # @example - specify a fixed height for a row
371
+ # ws.add_row ['I wish', 'for a fish', 'on my fish wish dish'], :height => 40
372
+ #
373
+ # @example - create and use a style for all cells in the row
374
+ # blue = ws.styles.add_style :color => "#00FF00"
375
+ # ws.add_row [1, 2, 3], :style=>blue
376
+ #
377
+ # @example - only style some cells
378
+ # blue = ws.styles.add_style :color => "#00FF00"
379
+ # red = ws.styles.add_style :color => "#FF0000"
380
+ # big = ws.styles.add_style :sz => 40
381
+ # ws.add_row ["red fish", "blue fish", "one fish", "two fish"], :style=>[red, blue, nil, big] # the last nil is optional
382
+ #
383
+ #
384
+ # @example - force the second cell to be a float value
385
+ # ws.add_row [3, 4, 5], :types => [nil, :float]
386
+ #
387
+ # @example - use << alias
388
+ # ws << [3, 4, 5], :types => [nil, :float]
389
+ #
390
+ # @example - specify whether a row should escape formulas or not
391
+ # ws.add_row ['=IF(2+2=4,4,5)', 2, 3], :escape_formulas=>true
392
+ #
393
+ # @example - specify whether a certain cells in a row should escape formulas or not
394
+ # ws.add_row ['=IF(2+2=4,4,5)', '=IF(13+13=4,4,5)'], :escape_formulas=>[true, false]
395
+ #
396
+ # @example - add a column offset when adding a row (inserts 'n' blank, unstyled columns before data)
397
+ # ws.add_row ['I wish', 'for a fish', 'on my fish wish dish'], offset: 3
398
+ #
399
+ # @see Worksheet#column_widths
400
+ # @return [Row]
401
+ # @option options [Array] values
402
+ # @option options [Array, Symbol] types
403
+ # @option options [Array, Integer] style
404
+ # @option options [Array] widths each member of the widths array will affect how auto_fit behavies.
405
+ # @option options [Float] height the row's height (in points)
406
+ # @option options [Integer] offset - add empty columns before values
407
+ # @option options [Array, Boolean] escape_formulas - Whether to treat a value starting with an equal
408
+ # sign as formula (default) or as simple string.
409
+ # Allowing user generated data to be interpreted as formulas can be dangerous
410
+ # (see https://www.owasp.org/index.php/CSV_Injection for details).
411
+ def add_row(values=[], options={})
412
+ row = Row.new(self, values, options)
413
+ update_column_info row, options.delete(:widths)
414
+ yield row if block_given?
415
+ row
416
+ end
417
+
418
+ alias :<< :add_row
419
+
420
+ # Add conditional formatting to this worksheet.
421
+ #
422
+ # @param [String] cells The range to apply the formatting to
423
+ # @param [Array|Hash] rules An array of hashes (or just one) to create Conditional formatting rules from.
424
+ # @example This would format column A whenever it is FALSE.
425
+ # # for a longer example, see examples/example_conditional_formatting.rb (link below)
426
+ # worksheet.add_conditional_formatting( "A1:A1048576", { :type => :cellIs, :operator => :equal, :formula => "FALSE", :dxfId => 1, :priority => 1 }
427
+ #
428
+ # @see ConditionalFormattingRule#initialize
429
+ # @see file:examples/example_conditional_formatting.rb
430
+ def add_conditional_formatting(cells, rules)
431
+ cf = ConditionalFormatting.new( :sqref => cells )
432
+ cf.add_rules rules
433
+ conditional_formattings << cf
434
+ conditional_formattings
435
+ end
436
+
437
+ # Add data validation to this worksheet.
438
+ #
439
+ # @param [String] cells The cells the validation will apply to.
440
+ # @param [hash] data_validation options defining the validation to apply.
441
+ # @see examples/data_validation.rb for an example
442
+ def add_data_validation(cells, data_validation)
443
+ dv = DataValidation.new(data_validation)
444
+ dv.sqref = cells
445
+ data_validations << dv
446
+ end
447
+
448
+ # Adds a new hyperlink to the worksheet
449
+ # @param [Hash] options for the hyperlink
450
+ # @see WorksheetHyperlink for a list of options
451
+ # @return [WorksheetHyperlink]
452
+ def add_hyperlink(options={})
453
+ hyperlinks.add(options)
454
+ end
455
+
456
+ # Adds a chart to this worksheets drawing. This is the recommended way to create charts for your worksheet. This method wraps the complexity of dealing with ooxml drawing, anchors, markers graphic frames chart objects and all the other dirty details.
457
+ # @param [Class] chart_type
458
+ # @option options [Array] start_at
459
+ # @option options [Array] end_at
460
+ # @option options [Cell, String] title
461
+ # @option options [Boolean] show_legend
462
+ # @option options [Integer] style
463
+ # @note each chart type also specifies additional options
464
+ # @see Chart
465
+ # @see Pie3DChart
466
+ # @see Bar3DChart
467
+ # @see Line3DChart
468
+ # @see README for examples
469
+ def add_chart(chart_type, options={})
470
+ chart = worksheet_drawing.add_chart(chart_type, options)
471
+ yield chart if block_given?
472
+ chart
473
+ end
474
+
475
+ # needs documentation
476
+ def add_table(ref, options={})
477
+ tables << Table.new(ref, self, options)
478
+ yield tables.last if block_given?
479
+ tables.last
480
+ end
481
+
482
+ def add_pivot_table(ref, range, options={})
483
+ pivot_tables << PivotTable.new(ref, range, self, options)
484
+ yield pivot_tables.last if block_given?
485
+ pivot_tables.last
486
+ end
487
+
488
+ # Shortcut to worsksheet_comments#add_comment
489
+ def add_comment(options={})
490
+ worksheet_comments.add_comment(options)
491
+ end
492
+
493
+ # Adds a media item to the worksheets drawing
494
+ # @option [Hash] options options passed to drawing.add_image
495
+ def add_image(options={})
496
+ image = worksheet_drawing.add_image(options)
497
+ yield image if block_given?
498
+ image
499
+ end
500
+
501
+ # Adds a page break (row break) to the worksheet
502
+ # @param cell A Cell object or excel style string reference indicating where the break
503
+ # should be added to the sheet.
504
+ # @example
505
+ # ws.add_page_break("A4")
506
+ def add_page_break(cell)
507
+ DataTypeValidator.validate :worksheet_page_break, [String, Cell], cell
508
+ column_index, row_index = if cell.is_a?(String)
509
+ Axlsx.name_to_indices(cell)
510
+ else
511
+ cell.pos
512
+ end
513
+ if column_index > 0
514
+ col_breaks.add_break(:id => column_index)
515
+ end
516
+ row_breaks.add_break(:id => row_index)
517
+ end
518
+
519
+ # This is a helper method that Lets you specify a fixed width for multiple columns in a worksheet in one go.
520
+ # Note that you must call column_widths AFTER adding data, otherwise the width will not be set successfully.
521
+ # Setting a fixed column width to nil will revert the behaviour back to calculating the width for you on the next call to add_row.
522
+ # @example This would set the first and third column widhts but leave the second column in autofit state.
523
+ # ws.column_widths 7.2, nil, 3
524
+ # @note For updating only a single column it is probably easier to just set the width of the ws.column_info[col_index].width directly
525
+ # @param [Integer|Float|nil] widths
526
+ def column_widths(*widths)
527
+ widths.each_with_index do |value, index|
528
+ next if value == nil
529
+ Axlsx::validate_unsigned_numeric(value) unless value == nil
530
+ find_or_create_column_info(index).width = value
531
+ end
532
+ end
533
+
534
+ # Set the style for cells in a specific column
535
+ # @param [Integer] index the index of the column
536
+ # @param [Integer] style the cellXfs index
537
+ # @param [Hash] options
538
+ # @option [Integer] :row_offset only cells after this column will be updated.
539
+ # @note You can also specify the style for specific columns in the call to add_row by using an array for the :styles option
540
+ # @see Worksheet#add_row
541
+ # @see README.md for an example
542
+ def col_style(index, style, options={})
543
+ offset = options.delete(:row_offset) || 0
544
+ cells = @rows[(offset..-1)].map { |row| row[index] }.flatten.compact
545
+ cells.each { |cell| cell.style = style }
546
+ end
547
+
548
+ # Set the style for cells in a specific row
549
+ # @param [Integer] index or range of indexes in the table
550
+ # @param [Integer] style the cellXfs index
551
+ # @param [Hash] options the options used when applying the style
552
+ # @option [Integer] :col_offset only cells after this column will be updated.
553
+ # @note You can also specify the style in the add_row call
554
+ # @see Worksheet#add_row
555
+ # @see README.md for an example
556
+ def row_style(index, style, options={})
557
+ offset = options.delete(:col_offset) || 0
558
+ cells = cols[(offset..-1)].map { |column| column[index] }.flatten.compact
559
+ cells.each { |cell| cell.style = style }
560
+ end
561
+
562
+ # Returns a sheet node serialization for this sheet in the workbook.
563
+ def to_sheet_node_xml_string(str='')
564
+ add_autofilter_defined_name_to_workbook
565
+ str << '<sheet '
566
+ serialized_attributes str
567
+ str << ('name="' << name << '" ')
568
+ str << ('r:id="' << rId << '"></sheet>')
569
+ end
570
+
571
+ # Serializes the worksheet object to an xml string
572
+ # This intentionally does not use nokogiri for performance reasons
573
+ # @return [String]
574
+ def to_xml_string str=''
575
+ add_autofilter_defined_name_to_workbook
576
+ auto_filter.apply if auto_filter.range
577
+ str << '<?xml version="1.0" encoding="UTF-8"?>'
578
+ str << worksheet_node
579
+ serializable_parts.each do |item|
580
+ item.to_xml_string(str) if item
581
+ end
582
+ str << '</worksheet>'
583
+ end
584
+
585
+ # The worksheet relationships. This is managed automatically by the worksheet
586
+ # @return [Relationships]
587
+ def relationships
588
+ r = Relationships.new
589
+ r + [tables.relationships,
590
+ worksheet_comments.relationships,
591
+ hyperlinks.relationships,
592
+ worksheet_drawing.relationship,
593
+ pivot_tables.relationships].flatten.compact || []
594
+ r
595
+ end
596
+
597
+ # Returns the cell or cells defined using excel style A1:B3 references.
598
+ # @param [String|Integer] cell_def the string defining the cell or range of cells, or the rownumber
599
+ # @return [Cell, Array]
600
+ def [](cell_def)
601
+ return rows[cell_def] if cell_def.is_a?(Integer)
602
+
603
+ parts = cell_def.split(':').map{ |part| name_to_cell part }
604
+
605
+ if parts.size == 1
606
+ parts.first
607
+ else
608
+ if parts.size > 2
609
+ raise ArgumentError, (ERR_CELL_REFERENCE_INVALID % cell_def)
610
+ elsif parts.first.nil?
611
+ raise ArgumentError, (ERR_CELL_REFERENCE_MISSING_CELL % [cell_def.split(":").first, cell_def])
612
+ elsif parts.last.nil?
613
+ raise ArgumentError, (ERR_CELL_REFERENCE_MISSING_CELL % [cell_def.split(":").last, cell_def])
614
+ end
615
+
616
+ range(*parts)
617
+ end
618
+ end
619
+
620
+ # returns the column and row index for a named based cell
621
+ # @param [String] name The cell or cell range to return. "A1" will return the first cell of the first row.
622
+ # @return [Cell]
623
+ def name_to_cell(name)
624
+ col_index, row_index = *Axlsx::name_to_indices(name)
625
+
626
+ r = rows[row_index]
627
+
628
+ if r
629
+ return r[col_index]
630
+ end
631
+ end
632
+
633
+ # shortcut method to access styles direclty from the worksheet
634
+ # This lets us do stuff like:
635
+ # @example
636
+ # p = Axlsx::Package.new
637
+ # p.workbook.add_worksheet(:name => 'foo') do |sheet|
638
+ # my_style = sheet.styles.add_style { :bg_color => "FF0000" }
639
+ # sheet.add_row ['Oh No!'], :styles => my_style
640
+ # end
641
+ # p.serialize 'foo.xlsx'
642
+ def styles
643
+ @styles ||= self.workbook.styles
644
+ end
645
+
646
+ # shortcut level to specify the outline level for a series of rows
647
+ # Oulining is what lets you add collapse and expand to a data set.
648
+ # @param [Integer] start_index The zero based index of the first row of outlining.
649
+ # @param [Integer] end_index The zero based index of the last row to be outlined
650
+ # @param [integer] level The level of outline to apply
651
+ # @param [Integer] collapsed The initial collapsed state of the outline group
652
+ def outline_level_rows(start_index, end_index, level = 1, collapsed = true)
653
+ outline rows, (start_index..end_index), level, collapsed
654
+ end
655
+
656
+ # shortcut level to specify the outline level for a series of columns
657
+ # Oulining is what lets you add collapse and expand to a data set.
658
+ # @param [Integer] start_index The zero based index of the first column of outlining.
659
+ # @param [Integer] end_index The zero based index of the last column to be outlined
660
+ # @param [integer] level The level of outline to apply
661
+ # @param [Integer] collapsed The initial collapsed state of the outline group
662
+ def outline_level_columns(start_index, end_index, level = 1, collapsed = true)
663
+ outline column_info, (start_index..end_index), level, collapsed
664
+ end
665
+
666
+ private
667
+
668
+ def xml_space
669
+ workbook.xml_space
670
+ end
671
+
672
+ def outline(collection, range, level = 1, collapsed = true)
673
+ range.each do |index|
674
+ unless (item = collection[index]).nil?
675
+ item.outline_level = level
676
+ item.hidden = collapsed
677
+ end
678
+ sheet_view.show_outline_symbols = true
679
+ end
680
+ end
681
+
682
+ def validate_sheet_name(name)
683
+ DataTypeValidator.validate :worksheet_name, String, name
684
+ # ignore first character (BOM) after encoding to utf16 because Excel does so, too.
685
+ raise ArgumentError, (ERR_SHEET_NAME_EMPTY) if name.empty?
686
+ character_length = name.encode("utf-16")[1..-1].encode("utf-16").bytesize / 2
687
+ raise ArgumentError, (ERR_SHEET_NAME_TOO_LONG % name) if character_length > 31
688
+ raise ArgumentError, (ERR_SHEET_NAME_CHARACTER_FORBIDDEN % name) if '[]*/\?:'.chars.any? { |char| name.include? char }
689
+ name = Axlsx::coder.encode(name)
690
+ sheet_names = @workbook.worksheets.reject { |s| s == self }.map { |s| s.name }
691
+ raise ArgumentError, (ERR_DUPLICATE_SHEET_NAME % name) if sheet_names.include?(name)
692
+ end
693
+
694
+ def serializable_parts
695
+ [sheet_pr, dimension, sheet_view, sheet_format_pr, column_info,
696
+ sheet_data, sheet_calc_pr, @sheet_protection, protected_ranges,
697
+ auto_filter, merged_cells, conditional_formattings,
698
+ data_validations, hyperlinks, print_options, page_margins,
699
+ page_setup, header_footer, row_breaks, col_breaks, worksheet_drawing, worksheet_comments,
700
+ tables]
701
+ end
702
+
703
+ def range(*cell_def)
704
+ first, last = cell_def
705
+ cells = []
706
+
707
+ rows[(first.row.row_index..last.row.row_index)].each do |r|
708
+ r[(first.index..last.index)].each do |c|
709
+ cells << c
710
+ end
711
+ end
712
+
713
+ cells
714
+ end
715
+
716
+ # A collection of protected ranges in the worksheet
717
+ # @note The recommended way to manage protected ranges is with Worksheet#protect_range
718
+ # @see Worksheet#protect_range
719
+ # @return [SimpleTypedList] The protected ranges for this worksheet
720
+ def protected_ranges
721
+ @protected_ranges ||= ProtectedRanges.new self
722
+ # SimpleTypedList.new ProtectedRange
723
+ end
724
+
725
+ # conditional formattings
726
+ # @return [Array]
727
+ def conditional_formattings
728
+ @conditional_formattings ||= ConditionalFormattings.new self
729
+ end
730
+
731
+ # data validations array
732
+ # @return [Array]
733
+ def data_validations
734
+ @data_validations ||= DataValidations.new self
735
+ end
736
+
737
+ # merged cells array
738
+ # @return [Array]
739
+ def merged_cells
740
+ @merged_cells ||= MergedCells.new self
741
+ end
742
+
743
+
744
+ # Helper method for parsingout the root node for worksheet
745
+ # @return [String]
746
+ def worksheet_node
747
+ "<worksheet xmlns=\"#{XML_NS}\" xmlns:r=\"#{XML_NS_R}\" xml:space=\"#{xml_space}\">"
748
+ end
749
+
750
+ def sheet_data
751
+ @sheet_data ||= SheetData.new self
752
+ end
753
+
754
+ def worksheet_drawing
755
+ @worksheet_drawing ||= WorksheetDrawing.new self
756
+ end
757
+
758
+ # The comments associated with this worksheet
759
+ # @return [SimpleTypedList]
760
+ def worksheet_comments
761
+ @worksheet_comments ||= WorksheetComments.new self
762
+ end
763
+
764
+ def workbook=(v) DataTypeValidator.validate "Worksheet.workbook", Workbook, v; @workbook = v; end
765
+
766
+ def update_column_info(cells, widths = nil)
767
+ cells.each_with_index do |cell, index|
768
+ width = widths ? widths[index] : nil
769
+ col = find_or_create_column_info(index)
770
+ next if width == :ignore
771
+
772
+ col.update_width(cell, width, workbook.use_autowidth)
773
+ end
774
+ end
775
+
776
+ def find_or_create_column_info(index)
777
+ column_info[index] ||= Col.new(index + 1, index + 1)
778
+ end
779
+
780
+ def add_autofilter_defined_name_to_workbook
781
+ return if !auto_filter.range
782
+ workbook.add_defined_name auto_filter.defined_name, name: '_xlnm._FilterDatabase', local_sheet_id: index, hidden: 1
783
+ end
784
+
785
+ end
786
+ end