caxlsx 3.0.4 → 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 -334
  5. data/LICENSE +21 -21
  6. data/README.md +168 -170
  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 -151
  21. data/lib/axlsx/drawing/bar_chart.rb +138 -143
  22. data/lib/axlsx/drawing/bar_series.rb +97 -80
  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 -363
  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 -289
  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 -162
  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 -764
  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 -170
  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 -71
  186. data/test/drawing/tc_bar_chart.rb +86 -71
  187. data/test/drawing/tc_bar_series.rb +46 -37
  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 -12
  247. data/test/tc_package.rb +317 -264
  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 -135
  278. data/test/workbook/worksheet/tc_pivot_table_cache_definition.rb +62 -54
  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 -139
  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 -67
  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 +11 -11
@@ -1,764 +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
- # @see Worksheet#column_widths
397
- # @return [Row]
398
- # @option options [Array] values
399
- # @option options [Array, Symbol] types
400
- # @option options [Array, Integer] style
401
- # @option options [Array] widths each member of the widths array will affect how auto_fit behavies.
402
- # @option options [Float] height the row's height (in points)
403
- # @option options [Array, Boolean] escape_formulas - Whether to treat a value starting with an equal
404
- # sign as formula (default) or as simple string.
405
- # Allowing user generated data to be interpreted as formulas can be dangerous
406
- # (see https://www.owasp.org/index.php/CSV_Injection for details).
407
- def add_row(values=[], options={})
408
- row = Row.new(self, values, options)
409
- update_column_info row, options.delete(:widths)
410
- yield row if block_given?
411
- row
412
- end
413
-
414
- alias :<< :add_row
415
-
416
- # Add conditional formatting to this worksheet.
417
- #
418
- # @param [String] cells The range to apply the formatting to
419
- # @param [Array|Hash] rules An array of hashes (or just one) to create Conditional formatting rules from.
420
- # @example This would format column A whenever it is FALSE.
421
- # # for a longer example, see examples/example_conditional_formatting.rb (link below)
422
- # worksheet.add_conditional_formatting( "A1:A1048576", { :type => :cellIs, :operator => :equal, :formula => "FALSE", :dxfId => 1, :priority => 1 }
423
- #
424
- # @see ConditionalFormattingRule#initialize
425
- # @see file:examples/example_conditional_formatting.rb
426
- def add_conditional_formatting(cells, rules)
427
- cf = ConditionalFormatting.new( :sqref => cells )
428
- cf.add_rules rules
429
- conditional_formattings << cf
430
- conditional_formattings
431
- end
432
-
433
- # Add data validation to this worksheet.
434
- #
435
- # @param [String] cells The cells the validation will apply to.
436
- # @param [hash] data_validation options defining the validation to apply.
437
- # @see examples/data_validation.rb for an example
438
- def add_data_validation(cells, data_validation)
439
- dv = DataValidation.new(data_validation)
440
- dv.sqref = cells
441
- data_validations << dv
442
- end
443
-
444
- # Adds a new hyperlink to the worksheet
445
- # @param [Hash] options for the hyperlink
446
- # @see WorksheetHyperlink for a list of options
447
- # @return [WorksheetHyperlink]
448
- def add_hyperlink(options={})
449
- hyperlinks.add(options)
450
- end
451
-
452
- # 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.
453
- # @param [Class] chart_type
454
- # @option options [Array] start_at
455
- # @option options [Array] end_at
456
- # @option options [Cell, String] title
457
- # @option options [Boolean] show_legend
458
- # @option options [Integer] style
459
- # @note each chart type also specifies additional options
460
- # @see Chart
461
- # @see Pie3DChart
462
- # @see Bar3DChart
463
- # @see Line3DChart
464
- # @see README for examples
465
- def add_chart(chart_type, options={})
466
- chart = worksheet_drawing.add_chart(chart_type, options)
467
- yield chart if block_given?
468
- chart
469
- end
470
-
471
- # needs documentation
472
- def add_table(ref, options={})
473
- tables << Table.new(ref, self, options)
474
- yield tables.last if block_given?
475
- tables.last
476
- end
477
-
478
- def add_pivot_table(ref, range, options={})
479
- pivot_tables << PivotTable.new(ref, range, self, options)
480
- yield pivot_tables.last if block_given?
481
- pivot_tables.last
482
- end
483
-
484
- # Shortcut to worsksheet_comments#add_comment
485
- def add_comment(options={})
486
- worksheet_comments.add_comment(options)
487
- end
488
-
489
- # Adds a media item to the worksheets drawing
490
- # @option [Hash] options options passed to drawing.add_image
491
- def add_image(options={})
492
- image = worksheet_drawing.add_image(options)
493
- yield image if block_given?
494
- image
495
- end
496
-
497
- # Adds a page break (row break) to the worksheet
498
- # @param cell A Cell object or excel style string reference indicating where the break
499
- # should be added to the sheet.
500
- # @example
501
- # ws.add_page_break("A4")
502
- def add_page_break(cell)
503
- DataTypeValidator.validate :worksheet_page_break, [String, Cell], cell
504
- column_index, row_index = if cell.is_a?(String)
505
- Axlsx.name_to_indices(cell)
506
- else
507
- cell.pos
508
- end
509
- if column_index > 0
510
- col_breaks.add_break(:id => column_index)
511
- end
512
- row_breaks.add_break(:id => row_index)
513
- end
514
-
515
- # This is a helper method that Lets you specify a fixed width for multiple columns in a worksheet in one go.
516
- # Note that you must call column_widths AFTER adding data, otherwise the width will not be set successfully.
517
- # 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.
518
- # @example This would set the first and third column widhts but leave the second column in autofit state.
519
- # ws.column_widths 7.2, nil, 3
520
- # @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
521
- # @param [Integer|Float|nil] widths
522
- def column_widths(*widths)
523
- widths.each_with_index do |value, index|
524
- next if value == nil
525
- Axlsx::validate_unsigned_numeric(value) unless value == nil
526
- find_or_create_column_info(index).width = value
527
- end
528
- end
529
-
530
- # Set the style for cells in a specific column
531
- # @param [Integer] index the index of the column
532
- # @param [Integer] style the cellXfs index
533
- # @param [Hash] options
534
- # @option [Integer] :row_offset only cells after this column will be updated.
535
- # @note You can also specify the style for specific columns in the call to add_row by using an array for the :styles option
536
- # @see Worksheet#add_row
537
- # @see README.md for an example
538
- def col_style(index, style, options={})
539
- offset = options.delete(:row_offset) || 0
540
- cells = @rows[(offset..-1)].map { |row| row[index] }.flatten.compact
541
- cells.each { |cell| cell.style = style }
542
- end
543
-
544
- # Set the style for cells in a specific row
545
- # @param [Integer] index or range of indexes in the table
546
- # @param [Integer] style the cellXfs index
547
- # @param [Hash] options the options used when applying the style
548
- # @option [Integer] :col_offset only cells after this column will be updated.
549
- # @note You can also specify the style in the add_row call
550
- # @see Worksheet#add_row
551
- # @see README.md for an example
552
- def row_style(index, style, options={})
553
- offset = options.delete(:col_offset) || 0
554
- cells = cols[(offset..-1)].map { |column| column[index] }.flatten.compact
555
- cells.each { |cell| cell.style = style }
556
- end
557
-
558
- # Returns a sheet node serialization for this sheet in the workbook.
559
- def to_sheet_node_xml_string(str='')
560
- add_autofilter_defined_name_to_workbook
561
- str << '<sheet '
562
- serialized_attributes str
563
- str << ('name="' << name << '" ')
564
- str << ('r:id="' << rId << '"></sheet>')
565
- end
566
-
567
- # Serializes the worksheet object to an xml string
568
- # This intentionally does not use nokogiri for performance reasons
569
- # @return [String]
570
- def to_xml_string str=''
571
- add_autofilter_defined_name_to_workbook
572
- auto_filter.apply if auto_filter.range
573
- str << '<?xml version="1.0" encoding="UTF-8"?>'
574
- str << worksheet_node
575
- serializable_parts.each do |item|
576
- item.to_xml_string(str) if item
577
- end
578
- str << '</worksheet>'
579
- end
580
-
581
- # The worksheet relationships. This is managed automatically by the worksheet
582
- # @return [Relationships]
583
- def relationships
584
- r = Relationships.new
585
- r + [tables.relationships,
586
- worksheet_comments.relationships,
587
- hyperlinks.relationships,
588
- worksheet_drawing.relationship,
589
- pivot_tables.relationships].flatten.compact || []
590
- r
591
- end
592
-
593
- # Returns the cell or cells defined using excel style A1:B3 references.
594
- # @param [String|Integer] cell_def the string defining the cell or range of cells, or the rownumber
595
- # @return [Cell, Array]
596
- def [](cell_def)
597
- return rows[cell_def] if cell_def.is_a?(Integer)
598
- parts = cell_def.split(':').map{ |part| name_to_cell part }
599
- if parts.size == 1
600
- parts.first
601
- else
602
- range(*parts)
603
- end
604
- end
605
-
606
- # returns the column and row index for a named based cell
607
- # @param [String] name The cell or cell range to return. "A1" will return the first cell of the first row.
608
- # @return [Cell]
609
- def name_to_cell(name)
610
- col_index, row_index = *Axlsx::name_to_indices(name)
611
- r = rows[row_index]
612
- r[col_index] if r
613
- end
614
-
615
- # shortcut method to access styles direclty from the worksheet
616
- # This lets us do stuff like:
617
- # @example
618
- # p = Axlsx::Package.new
619
- # p.workbook.add_worksheet(:name => 'foo') do |sheet|
620
- # my_style = sheet.styles.add_style { :bg_color => "FF0000" }
621
- # sheet.add_row ['Oh No!'], :styles => my_style
622
- # end
623
- # p.serialize 'foo.xlsx'
624
- def styles
625
- @styles ||= self.workbook.styles
626
- end
627
-
628
- # shortcut level to specify the outline level for a series of rows
629
- # Oulining is what lets you add collapse and expand to a data set.
630
- # @param [Integer] start_index The zero based index of the first row of outlining.
631
- # @param [Integer] end_index The zero based index of the last row to be outlined
632
- # @param [integer] level The level of outline to apply
633
- # @param [Integer] collapsed The initial collapsed state of the outline group
634
- def outline_level_rows(start_index, end_index, level = 1, collapsed = true)
635
- outline rows, (start_index..end_index), level, collapsed
636
- end
637
-
638
- # shortcut level to specify the outline level for a series of columns
639
- # Oulining is what lets you add collapse and expand to a data set.
640
- # @param [Integer] start_index The zero based index of the first column of outlining.
641
- # @param [Integer] end_index The zero based index of the last column to be outlined
642
- # @param [integer] level The level of outline to apply
643
- # @param [Integer] collapsed The initial collapsed state of the outline group
644
- def outline_level_columns(start_index, end_index, level = 1, collapsed = true)
645
- outline column_info, (start_index..end_index), level, collapsed
646
- end
647
-
648
- private
649
-
650
- def xml_space
651
- workbook.xml_space
652
- end
653
-
654
- def outline(collection, range, level = 1, collapsed = true)
655
- range.each do |index|
656
- unless (item = collection[index]).nil?
657
- item.outline_level = level
658
- item.hidden = collapsed
659
- end
660
- sheet_view.show_outline_symbols = true
661
- end
662
- end
663
-
664
- def validate_sheet_name(name)
665
- DataTypeValidator.validate :worksheet_name, String, name
666
- # ignore first character (BOM) after encoding to utf16 because Excel does so, too.
667
- character_length = name.encode("utf-16")[1..-1].encode("utf-16").bytesize / 2
668
- raise ArgumentError, (ERR_SHEET_NAME_TOO_LONG % name) if character_length > 31
669
- raise ArgumentError, (ERR_SHEET_NAME_CHARACTER_FORBIDDEN % name) if '[]*/\?:'.chars.any? { |char| name.include? char }
670
- name = Axlsx::coder.encode(name)
671
- sheet_names = @workbook.worksheets.reject { |s| s == self }.map { |s| s.name }
672
- raise ArgumentError, (ERR_DUPLICATE_SHEET_NAME % name) if sheet_names.include?(name)
673
- end
674
-
675
- def serializable_parts
676
- [sheet_pr, dimension, sheet_view, sheet_format_pr, column_info,
677
- sheet_data, sheet_calc_pr, @sheet_protection, protected_ranges,
678
- auto_filter, merged_cells, conditional_formattings,
679
- data_validations, hyperlinks, print_options, page_margins,
680
- page_setup, header_footer, row_breaks, col_breaks, worksheet_drawing, worksheet_comments,
681
- tables]
682
- end
683
-
684
- def range(*cell_def)
685
- first, last = cell_def
686
- cells = []
687
- rows[(first.row.row_index..last.row.row_index)].each do |r|
688
- r[(first.index..last.index)].each do |c|
689
- cells << c
690
- end
691
- end
692
- cells
693
- end
694
-
695
- # A collection of protected ranges in the worksheet
696
- # @note The recommended way to manage protected ranges is with Worksheet#protect_range
697
- # @see Worksheet#protect_range
698
- # @return [SimpleTypedList] The protected ranges for this worksheet
699
- def protected_ranges
700
- @protected_ranges ||= ProtectedRanges.new self
701
- # SimpleTypedList.new ProtectedRange
702
- end
703
-
704
- # conditional formattings
705
- # @return [Array]
706
- def conditional_formattings
707
- @conditional_formattings ||= ConditionalFormattings.new self
708
- end
709
-
710
- # data validations array
711
- # @return [Array]
712
- def data_validations
713
- @data_validations ||= DataValidations.new self
714
- end
715
-
716
- # merged cells array
717
- # @return [Array]
718
- def merged_cells
719
- @merged_cells ||= MergedCells.new self
720
- end
721
-
722
-
723
- # Helper method for parsingout the root node for worksheet
724
- # @return [String]
725
- def worksheet_node
726
- "<worksheet xmlns=\"#{XML_NS}\" xmlns:r=\"#{XML_NS_R}\" xml:space=\"#{xml_space}\">"
727
- end
728
-
729
- def sheet_data
730
- @sheet_data ||= SheetData.new self
731
- end
732
-
733
- def worksheet_drawing
734
- @worksheet_drawing ||= WorksheetDrawing.new self
735
- end
736
-
737
- # The comments associated with this worksheet
738
- # @return [SimpleTypedList]
739
- def worksheet_comments
740
- @worksheet_comments ||= WorksheetComments.new self
741
- end
742
-
743
- def workbook=(v) DataTypeValidator.validate "Worksheet.workbook", Workbook, v; @workbook = v; end
744
-
745
- def update_column_info(cells, widths=nil)
746
- cells.each_with_index do |cell, index|
747
- width = widths ? widths[index] : nil
748
- col = find_or_create_column_info(index)
749
- next if width == :ignore
750
- col.update_width(cell, width, workbook.use_autowidth)
751
- end
752
- end
753
-
754
- def find_or_create_column_info(index)
755
- column_info[index] ||= Col.new(index + 1, index + 1)
756
- end
757
-
758
- def add_autofilter_defined_name_to_workbook
759
- return if !auto_filter.range
760
- workbook.add_defined_name auto_filter.defined_name, name: '_xlnm._FilterDatabase', local_sheet_id: index, hidden: 1
761
- end
762
-
763
- end
764
- 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