caxlsx 3.2.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +9 -9
  3. data/.yardopts_guide +18 -18
  4. data/CHANGELOG.md +394 -354
  5. data/LICENSE +21 -21
  6. data/README.md +184 -168
  7. data/Rakefile +28 -29
  8. data/examples/generate.rb +15 -15
  9. data/lib/axlsx/content_type/abstract_content_type.rb +29 -32
  10. data/lib/axlsx/content_type/content_type.rb +22 -26
  11. data/lib/axlsx/content_type/default.rb +21 -25
  12. data/lib/axlsx/content_type/override.rb +21 -25
  13. data/lib/axlsx/doc_props/app.rb +230 -235
  14. data/lib/axlsx/doc_props/core.rb +34 -39
  15. data/lib/axlsx/drawing/area_chart.rb +96 -99
  16. data/lib/axlsx/drawing/area_series.rb +107 -110
  17. data/lib/axlsx/drawing/ax_data_source.rb +21 -26
  18. data/lib/axlsx/drawing/axes.rb +60 -61
  19. data/lib/axlsx/drawing/axis.rb +185 -190
  20. data/lib/axlsx/drawing/bar_3D_chart.rb +145 -148
  21. data/lib/axlsx/drawing/bar_chart.rb +135 -138
  22. data/lib/axlsx/drawing/bar_series.rb +91 -97
  23. data/lib/axlsx/drawing/bubble_chart.rb +56 -59
  24. data/lib/axlsx/drawing/bubble_series.rb +60 -63
  25. data/lib/axlsx/drawing/cat_axis.rb +80 -85
  26. data/lib/axlsx/drawing/chart.rb +294 -276
  27. data/lib/axlsx/drawing/d_lbls.rb +92 -90
  28. data/lib/axlsx/drawing/drawing.rb +163 -167
  29. data/lib/axlsx/drawing/graphic_frame.rb +51 -54
  30. data/lib/axlsx/drawing/hyperlink.rb +97 -100
  31. data/lib/axlsx/drawing/line_3D_chart.rb +64 -68
  32. data/lib/axlsx/drawing/line_chart.rb +96 -99
  33. data/lib/axlsx/drawing/line_series.rb +107 -110
  34. data/lib/axlsx/drawing/marker.rb +80 -84
  35. data/lib/axlsx/drawing/num_data.rb +47 -52
  36. data/lib/axlsx/drawing/num_data_source.rb +58 -62
  37. data/lib/axlsx/drawing/num_val.rb +31 -34
  38. data/lib/axlsx/drawing/one_cell_anchor.rb +97 -99
  39. data/lib/axlsx/drawing/pic.rb +244 -211
  40. data/lib/axlsx/drawing/picture_locking.rb +39 -42
  41. data/lib/axlsx/drawing/pie_3D_chart.rb +42 -47
  42. data/lib/axlsx/drawing/pie_series.rb +69 -74
  43. data/lib/axlsx/drawing/scaling.rb +57 -60
  44. data/lib/axlsx/drawing/scatter_chart.rb +71 -74
  45. data/lib/axlsx/drawing/scatter_series.rb +126 -129
  46. data/lib/axlsx/drawing/ser_axis.rb +41 -45
  47. data/lib/axlsx/drawing/series.rb +67 -69
  48. data/lib/axlsx/drawing/series_title.rb +23 -25
  49. data/lib/axlsx/drawing/str_data.rb +37 -42
  50. data/lib/axlsx/drawing/str_val.rb +31 -34
  51. data/lib/axlsx/drawing/title.rb +104 -97
  52. data/lib/axlsx/drawing/two_cell_anchor.rb +95 -97
  53. data/lib/axlsx/drawing/val_axis.rb +34 -37
  54. data/lib/axlsx/drawing/view_3D.rb +115 -115
  55. data/lib/axlsx/drawing/vml_drawing.rb +39 -42
  56. data/lib/axlsx/drawing/vml_shape.rb +63 -66
  57. data/lib/axlsx/package.rb +397 -388
  58. data/lib/axlsx/rels/relationship.rb +127 -130
  59. data/lib/axlsx/rels/relationships.rb +29 -32
  60. data/lib/axlsx/stylesheet/border.rb +70 -73
  61. data/lib/axlsx/stylesheet/border_pr.rb +69 -71
  62. data/lib/axlsx/stylesheet/cell_alignment.rb +124 -132
  63. data/lib/axlsx/stylesheet/cell_protection.rb +38 -41
  64. data/lib/axlsx/stylesheet/cell_style.rb +68 -72
  65. data/lib/axlsx/stylesheet/color.rb +77 -76
  66. data/lib/axlsx/stylesheet/dxf.rb +75 -79
  67. data/lib/axlsx/stylesheet/fill.rb +31 -35
  68. data/lib/axlsx/stylesheet/font.rb +157 -156
  69. data/lib/axlsx/stylesheet/gradient_fill.rb +101 -103
  70. data/lib/axlsx/stylesheet/gradient_stop.rb +36 -37
  71. data/lib/axlsx/stylesheet/num_fmt.rb +83 -86
  72. data/lib/axlsx/stylesheet/pattern_fill.rb +71 -73
  73. data/lib/axlsx/stylesheet/styles.rb +543 -494
  74. data/lib/axlsx/stylesheet/table_style.rb +51 -54
  75. data/lib/axlsx/stylesheet/table_style_element.rb +74 -77
  76. data/lib/axlsx/stylesheet/table_styles.rb +42 -46
  77. data/lib/axlsx/stylesheet/xf.rb +144 -147
  78. data/lib/axlsx/util/accessors.rb +62 -64
  79. data/lib/axlsx/util/constants.rb +414 -410
  80. data/lib/axlsx/util/mime_type_utils.rb +24 -11
  81. data/lib/axlsx/util/options_parser.rb +15 -16
  82. data/lib/axlsx/util/serialized_attributes.rb +88 -89
  83. data/lib/axlsx/util/simple_typed_list.rb +180 -179
  84. data/lib/axlsx/util/storage.rb +142 -146
  85. data/lib/axlsx/util/validators.rb +315 -312
  86. data/lib/axlsx/util/zip_command.rb +71 -73
  87. data/lib/axlsx/version.rb +4 -5
  88. data/lib/axlsx/workbook/defined_name.rb +129 -128
  89. data/lib/axlsx/workbook/defined_names.rb +20 -21
  90. data/lib/axlsx/workbook/shared_strings_table.rb +74 -77
  91. data/lib/axlsx/workbook/workbook.rb +430 -395
  92. data/lib/axlsx/workbook/workbook_view.rb +75 -80
  93. data/lib/axlsx/workbook/workbook_views.rb +20 -22
  94. data/lib/axlsx/workbook/worksheet/auto_filter/auto_filter.rb +78 -77
  95. data/lib/axlsx/workbook/worksheet/auto_filter/filter_column.rb +94 -94
  96. data/lib/axlsx/workbook/worksheet/auto_filter/filters.rb +243 -244
  97. data/lib/axlsx/workbook/worksheet/border_creator.rb +79 -0
  98. data/lib/axlsx/workbook/worksheet/break.rb +32 -35
  99. data/lib/axlsx/workbook/worksheet/cell.rb +552 -506
  100. data/lib/axlsx/workbook/worksheet/cell_serializer.rb +164 -164
  101. data/lib/axlsx/workbook/worksheet/cfvo.rb +60 -60
  102. data/lib/axlsx/workbook/worksheet/cfvos.rb +16 -18
  103. data/lib/axlsx/workbook/worksheet/col.rb +142 -145
  104. data/lib/axlsx/workbook/worksheet/col_breaks.rb +34 -35
  105. data/lib/axlsx/workbook/worksheet/color_scale.rb +108 -110
  106. data/lib/axlsx/workbook/worksheet/cols.rb +23 -23
  107. data/lib/axlsx/workbook/worksheet/comment.rb +90 -91
  108. data/lib/axlsx/workbook/worksheet/comments.rb +78 -82
  109. data/lib/axlsx/workbook/worksheet/conditional_formatting.rb +81 -82
  110. data/lib/axlsx/workbook/worksheet/conditional_formatting_rule.rb +216 -220
  111. data/lib/axlsx/workbook/worksheet/conditional_formattings.rb +23 -25
  112. data/lib/axlsx/workbook/worksheet/data_bar.rb +127 -129
  113. data/lib/axlsx/workbook/worksheet/data_validation.rb +266 -246
  114. data/lib/axlsx/workbook/worksheet/data_validations.rb +25 -28
  115. data/lib/axlsx/workbook/worksheet/date_time_converter.rb +28 -30
  116. data/lib/axlsx/workbook/worksheet/dimension.rb +65 -64
  117. data/lib/axlsx/workbook/worksheet/header_footer.rb +51 -52
  118. data/lib/axlsx/workbook/worksheet/icon_set.rb +80 -81
  119. data/lib/axlsx/workbook/worksheet/merged_cells.rb +37 -37
  120. data/lib/axlsx/workbook/worksheet/outline_pr.rb +32 -33
  121. data/lib/axlsx/workbook/worksheet/page_margins.rb +97 -97
  122. data/lib/axlsx/workbook/worksheet/page_set_up_pr.rb +42 -44
  123. data/lib/axlsx/workbook/worksheet/page_setup.rb +237 -240
  124. data/lib/axlsx/workbook/worksheet/pane.rb +138 -139
  125. data/lib/axlsx/workbook/worksheet/pivot_table.rb +332 -296
  126. data/lib/axlsx/workbook/worksheet/pivot_table_cache_definition.rb +63 -66
  127. data/lib/axlsx/workbook/worksheet/pivot_tables.rb +23 -24
  128. data/lib/axlsx/workbook/worksheet/print_options.rb +38 -39
  129. data/lib/axlsx/workbook/worksheet/protected_range.rb +46 -47
  130. data/lib/axlsx/workbook/worksheet/protected_ranges.rb +37 -37
  131. data/lib/axlsx/workbook/worksheet/rich_text.rb +53 -55
  132. data/lib/axlsx/workbook/worksheet/rich_text_run.rb +266 -250
  133. data/lib/axlsx/workbook/worksheet/row.rb +173 -164
  134. data/lib/axlsx/workbook/worksheet/row_breaks.rb +32 -33
  135. data/lib/axlsx/workbook/worksheet/selection.rb +99 -101
  136. data/lib/axlsx/workbook/worksheet/sheet_calc_pr.rb +28 -29
  137. data/lib/axlsx/workbook/worksheet/sheet_data.rb +25 -27
  138. data/lib/axlsx/workbook/worksheet/sheet_format_pr.rb +18 -18
  139. data/lib/axlsx/workbook/worksheet/sheet_pr.rb +87 -87
  140. data/lib/axlsx/workbook/worksheet/sheet_protection.rb +117 -118
  141. data/lib/axlsx/workbook/worksheet/sheet_view.rb +206 -213
  142. data/lib/axlsx/workbook/worksheet/table.rb +100 -102
  143. data/lib/axlsx/workbook/worksheet/table_style_info.rb +48 -49
  144. data/lib/axlsx/workbook/worksheet/tables.rb +34 -34
  145. data/lib/axlsx/workbook/worksheet/worksheet.rb +857 -786
  146. data/lib/axlsx/workbook/worksheet/worksheet_comments.rb +58 -58
  147. data/lib/axlsx/workbook/worksheet/worksheet_drawing.rb +59 -58
  148. data/lib/axlsx/workbook/worksheet/worksheet_hyperlink.rb +73 -74
  149. data/lib/axlsx/workbook/worksheet/worksheet_hyperlinks.rb +38 -38
  150. data/lib/axlsx.rb +218 -185
  151. data/lib/caxlsx.rb +1 -2
  152. data/lib/schema/dc.xsd +118 -118
  153. data/lib/schema/dcmitype.xsd +51 -51
  154. data/lib/schema/dcterms.xsd +331 -331
  155. data/lib/schema/dml-chartDrawing.xsd +146 -146
  156. data/lib/schema/dml-compatibility.xsd +14 -14
  157. data/lib/schema/dml-lockedCanvas.xsd +11 -11
  158. data/lib/schema/dml-main.xsd +3048 -3048
  159. data/lib/schema/dml-picture.xsd +23 -23
  160. data/lib/schema/dml-spreadsheetDrawing.xsd +185 -185
  161. data/lib/schema/dml-wordprocessingDrawing.xsd +185 -185
  162. data/lib/schema/shared-additionalCharacteristics.xsd +28 -28
  163. data/lib/schema/shared-bibliography.xsd +144 -144
  164. data/lib/schema/shared-commonSimpleTypes.xsd +166 -166
  165. data/lib/schema/shared-customXmlDataProperties.xsd +25 -25
  166. data/lib/schema/shared-customXmlSchemaProperties.xsd +18 -18
  167. data/lib/schema/shared-documentPropertiesCustom.xsd +59 -59
  168. data/lib/schema/shared-documentPropertiesExtended.xsd +56 -56
  169. data/lib/schema/shared-documentPropertiesVariantTypes.xsd +195 -195
  170. data/lib/schema/shared-relationshipReference.xsd +25 -25
  171. data/lib/schema/vml-main.xsd +569 -569
  172. data/lib/schema/vml-officeDrawing.xsd +509 -509
  173. data/lib/schema/vml-presentationDrawing.xsd +12 -12
  174. data/lib/schema/vml-spreadsheetDrawing.xsd +108 -108
  175. data/lib/schema/vml-wordprocessingDrawing.xsd +96 -96
  176. data/lib/schema/xml.xsd +116 -116
  177. metadata +5 -252
  178. data/test/benchmark.rb +0 -72
  179. data/test/content_type/tc_content_type.rb +0 -76
  180. data/test/content_type/tc_default.rb +0 -16
  181. data/test/content_type/tc_override.rb +0 -14
  182. data/test/doc_props/tc_app.rb +0 -43
  183. data/test/doc_props/tc_core.rb +0 -42
  184. data/test/drawing/tc_area_chart.rb +0 -39
  185. data/test/drawing/tc_area_series.rb +0 -71
  186. data/test/drawing/tc_axes.rb +0 -8
  187. data/test/drawing/tc_axis.rb +0 -112
  188. data/test/drawing/tc_bar_3D_chart.rb +0 -86
  189. data/test/drawing/tc_bar_chart.rb +0 -86
  190. data/test/drawing/tc_bar_series.rb +0 -46
  191. data/test/drawing/tc_bubble_chart.rb +0 -44
  192. data/test/drawing/tc_bubble_series.rb +0 -21
  193. data/test/drawing/tc_cat_axis.rb +0 -31
  194. data/test/drawing/tc_cat_axis_data.rb +0 -27
  195. data/test/drawing/tc_chart.rb +0 -123
  196. data/test/drawing/tc_d_lbls.rb +0 -57
  197. data/test/drawing/tc_data_source.rb +0 -23
  198. data/test/drawing/tc_drawing.rb +0 -80
  199. data/test/drawing/tc_graphic_frame.rb +0 -27
  200. data/test/drawing/tc_hyperlink.rb +0 -64
  201. data/test/drawing/tc_line_3d_chart.rb +0 -47
  202. data/test/drawing/tc_line_chart.rb +0 -39
  203. data/test/drawing/tc_line_series.rb +0 -71
  204. data/test/drawing/tc_marker.rb +0 -44
  205. data/test/drawing/tc_named_axis_data.rb +0 -27
  206. data/test/drawing/tc_num_data.rb +0 -31
  207. data/test/drawing/tc_num_val.rb +0 -29
  208. data/test/drawing/tc_one_cell_anchor.rb +0 -66
  209. data/test/drawing/tc_pic.rb +0 -103
  210. data/test/drawing/tc_picture_locking.rb +0 -72
  211. data/test/drawing/tc_pie_3D_chart.rb +0 -28
  212. data/test/drawing/tc_pie_series.rb +0 -33
  213. data/test/drawing/tc_scaling.rb +0 -36
  214. data/test/drawing/tc_scatter_chart.rb +0 -48
  215. data/test/drawing/tc_scatter_series.rb +0 -74
  216. data/test/drawing/tc_ser_axis.rb +0 -31
  217. data/test/drawing/tc_series.rb +0 -23
  218. data/test/drawing/tc_series_title.rb +0 -54
  219. data/test/drawing/tc_str_data.rb +0 -18
  220. data/test/drawing/tc_str_val.rb +0 -30
  221. data/test/drawing/tc_title.rb +0 -70
  222. data/test/drawing/tc_two_cell_anchor.rb +0 -36
  223. data/test/drawing/tc_val_axis.rb +0 -24
  224. data/test/drawing/tc_view_3D.rb +0 -54
  225. data/test/drawing/tc_vml_drawing.rb +0 -25
  226. data/test/drawing/tc_vml_shape.rb +0 -106
  227. data/test/fixtures/image1.gif +0 -0
  228. data/test/fixtures/image1.jpeg +0 -0
  229. data/test/fixtures/image1.jpg +0 -0
  230. data/test/fixtures/image1.png +0 -0
  231. data/test/fixtures/image1_fake.jpg +0 -0
  232. data/test/profile.rb +0 -24
  233. data/test/rels/tc_relationship.rb +0 -52
  234. data/test/rels/tc_relationships.rb +0 -37
  235. data/test/stylesheet/tc_border.rb +0 -37
  236. data/test/stylesheet/tc_border_pr.rb +0 -32
  237. data/test/stylesheet/tc_cell_alignment.rb +0 -81
  238. data/test/stylesheet/tc_cell_protection.rb +0 -29
  239. data/test/stylesheet/tc_cell_style.rb +0 -57
  240. data/test/stylesheet/tc_color.rb +0 -43
  241. data/test/stylesheet/tc_dxf.rb +0 -81
  242. data/test/stylesheet/tc_fill.rb +0 -18
  243. data/test/stylesheet/tc_font.rb +0 -133
  244. data/test/stylesheet/tc_gradient_fill.rb +0 -72
  245. data/test/stylesheet/tc_gradient_stop.rb +0 -31
  246. data/test/stylesheet/tc_num_fmt.rb +0 -30
  247. data/test/stylesheet/tc_pattern_fill.rb +0 -43
  248. data/test/stylesheet/tc_styles.rb +0 -309
  249. data/test/stylesheet/tc_table_style.rb +0 -44
  250. data/test/stylesheet/tc_table_style_element.rb +0 -45
  251. data/test/stylesheet/tc_table_styles.rb +0 -29
  252. data/test/stylesheet/tc_xf.rb +0 -120
  253. data/test/tc_axlsx.rb +0 -109
  254. data/test/tc_helper.rb +0 -10
  255. data/test/tc_package.rb +0 -317
  256. data/test/util/tc_mime_type_utils.rb +0 -13
  257. data/test/util/tc_serialized_attributes.rb +0 -19
  258. data/test/util/tc_simple_typed_list.rb +0 -77
  259. data/test/util/tc_validators.rb +0 -210
  260. data/test/workbook/tc_defined_name.rb +0 -49
  261. data/test/workbook/tc_shared_strings_table.rb +0 -59
  262. data/test/workbook/tc_workbook.rb +0 -165
  263. data/test/workbook/tc_workbook_view.rb +0 -50
  264. data/test/workbook/worksheet/auto_filter/tc_auto_filter.rb +0 -38
  265. data/test/workbook/worksheet/auto_filter/tc_filter_column.rb +0 -76
  266. data/test/workbook/worksheet/auto_filter/tc_filters.rb +0 -50
  267. data/test/workbook/worksheet/tc_break.rb +0 -49
  268. data/test/workbook/worksheet/tc_cell.rb +0 -465
  269. data/test/workbook/worksheet/tc_cfvo.rb +0 -31
  270. data/test/workbook/worksheet/tc_col.rb +0 -93
  271. data/test/workbook/worksheet/tc_color_scale.rb +0 -58
  272. data/test/workbook/worksheet/tc_comment.rb +0 -72
  273. data/test/workbook/worksheet/tc_comments.rb +0 -57
  274. data/test/workbook/worksheet/tc_conditional_formatting.rb +0 -224
  275. data/test/workbook/worksheet/tc_data_bar.rb +0 -46
  276. data/test/workbook/worksheet/tc_data_validation.rb +0 -265
  277. data/test/workbook/worksheet/tc_date_time_converter.rb +0 -124
  278. data/test/workbook/worksheet/tc_header_footer.rb +0 -151
  279. data/test/workbook/worksheet/tc_icon_set.rb +0 -45
  280. data/test/workbook/worksheet/tc_outline_pr.rb +0 -19
  281. data/test/workbook/worksheet/tc_page_margins.rb +0 -97
  282. data/test/workbook/worksheet/tc_page_set_up_pr.rb +0 -15
  283. data/test/workbook/worksheet/tc_page_setup.rb +0 -143
  284. data/test/workbook/worksheet/tc_pane.rb +0 -54
  285. data/test/workbook/worksheet/tc_pivot_table.rb +0 -180
  286. data/test/workbook/worksheet/tc_pivot_table_cache_definition.rb +0 -62
  287. data/test/workbook/worksheet/tc_print_options.rb +0 -72
  288. data/test/workbook/worksheet/tc_protected_range.rb +0 -17
  289. data/test/workbook/worksheet/tc_rich_text.rb +0 -44
  290. data/test/workbook/worksheet/tc_rich_text_run.rb +0 -173
  291. data/test/workbook/worksheet/tc_row.rb +0 -160
  292. data/test/workbook/worksheet/tc_selection.rb +0 -55
  293. data/test/workbook/worksheet/tc_sheet_calc_pr.rb +0 -18
  294. data/test/workbook/worksheet/tc_sheet_format_pr.rb +0 -88
  295. data/test/workbook/worksheet/tc_sheet_pr.rb +0 -49
  296. data/test/workbook/worksheet/tc_sheet_protection.rb +0 -117
  297. data/test/workbook/worksheet/tc_sheet_view.rb +0 -214
  298. data/test/workbook/worksheet/tc_table.rb +0 -77
  299. data/test/workbook/worksheet/tc_table_style_info.rb +0 -53
  300. data/test/workbook/worksheet/tc_worksheet.rb +0 -632
  301. data/test/workbook/worksheet/tc_worksheet_hyperlink.rb +0 -55
@@ -1,494 +1,543 @@
1
- # encoding: UTF-8
2
- module Axlsx
3
- require 'axlsx/stylesheet/border.rb'
4
- require 'axlsx/stylesheet/border_pr.rb'
5
- require 'axlsx/stylesheet/cell_alignment.rb'
6
- require 'axlsx/stylesheet/cell_style.rb'
7
- require 'axlsx/stylesheet/color.rb'
8
- require 'axlsx/stylesheet/fill.rb'
9
- require 'axlsx/stylesheet/font.rb'
10
- require 'axlsx/stylesheet/gradient_fill.rb'
11
- require 'axlsx/stylesheet/gradient_stop.rb'
12
- require 'axlsx/stylesheet/num_fmt.rb'
13
- require 'axlsx/stylesheet/pattern_fill.rb'
14
- require 'axlsx/stylesheet/table_style.rb'
15
- require 'axlsx/stylesheet/table_styles.rb'
16
- require 'axlsx/stylesheet/table_style_element.rb'
17
- require 'axlsx/stylesheet/dxf.rb'
18
- require 'axlsx/stylesheet/xf.rb'
19
- require 'axlsx/stylesheet/cell_protection.rb'
20
-
21
- #The Styles class manages worksheet styles
22
- # In addition to creating the require style objects for a valid xlsx package, this class provides the key mechanism for adding styles to your workbook, and safely applying them to the cells of your worksheet.
23
- # All portions of the stylesheet are implemented here exception colors, which specify legacy and modified pallete colors, and exLst, whic is used as a future feature data storage area.
24
- # @see Office Open XML Part 1 18.8.11 for gory details on how this stuff gets put together
25
- # @see Styles#add_style
26
- # @note The recommended way to manage styles is with add_style
27
- class Styles
28
- # numFmts for your styles.
29
- # The default styles, which change based on the system local, are as follows.
30
- # id formatCode
31
- # 0 General
32
- # 1 0
33
- # 2 0.00
34
- # 3 #,##0
35
- # 4 #,##0.00
36
- # 9 0%
37
- # 10 0.00%
38
- # 11 0.00E+00
39
- # 12 # ?/?
40
- # 13 # ??/??
41
- # 14 mm-dd-yy
42
- # 15 d-mmm-yy
43
- # 16 d-mmm
44
- # 17 mmm-yy
45
- # 18 h:mm AM/PM
46
- # 19 h:mm:ss AM/PM
47
- # 20 h:mm
48
- # 21 h:mm:ss
49
- # 22 m/d/yy h:mm
50
- # 37 #,##0 ;(#,##0)
51
- # 38 #,##0 ;[Red](#,##0)
52
- # 39 #,##0.00;(#,##0.00)
53
- # 40 #,##0.00;[Red](#,##0.00)
54
- # 45 mm:ss
55
- # 46 [h]:mm:ss
56
- # 47 mmss.0
57
- # 48 ##0.0E+0
58
- # 49 @
59
- # Axlsx also defines the following constants which you can use in add_style.
60
- # NUM_FMT_PERCENT formats to "0%"
61
- # NUM_FMT_YYYYMMDD formats to "yyyy/mm/dd"
62
- # NUM_FMT_YYYYMMDDHHMMSS formats to "yyyy/mm/dd hh:mm:ss"
63
- # @see Office Open XML Part 1 - 18.8.31 for more information on creating number formats
64
- # @return [SimpleTypedList]
65
- # @note The recommended way to manage styles is with add_style
66
- # @see Styles#add_style
67
- attr_reader :numFmts
68
-
69
- # The collection of fonts used in this workbook
70
- # @return [SimpleTypedList]
71
- # @note The recommended way to manage styles is with add_style
72
- # @see Styles#add_style
73
- attr_reader :fonts
74
-
75
- # The collection of fills used in this workbook
76
- # @return [SimpleTypedList]
77
- # @note The recommended way to manage styles is with add_style
78
- # @see Styles#add_style
79
- attr_reader :fills
80
-
81
- # The collection of borders used in this workbook
82
- # Axlsx predefines THIN_BORDER which can be used to put a border around all of your cells.
83
- # @return [SimpleTypedList]
84
- # @note The recommended way to manage styles is with add_style
85
- # @see Styles#add_style
86
- attr_reader :borders
87
-
88
- # The collection of master formatting records for named cell styles, which means records defined in cellStyles, in the workbook
89
- # @return [SimpleTypedList]
90
- # @note The recommended way to manage styles is with add_style
91
- # @see Styles#add_style
92
- attr_reader :cellStyleXfs
93
-
94
- # The collection of named styles, referencing cellStyleXfs items in the workbook.
95
- # @return [SimpleTypedList]
96
- # @note The recommended way to manage styles is with add_style
97
- # @see Styles#add_style
98
- attr_reader :cellStyles
99
-
100
- # The collection of master formatting records. This is the list that you will actually use in styling a workbook.
101
- # @return [SimpleTypedList]
102
- # @note The recommended way to manage styles is with add_style
103
- # @see Styles#add_style
104
- attr_reader :cellXfs
105
-
106
- # The collection of non-cell formatting records used in the worksheet.
107
- # @return [SimpleTypedList]
108
- # @note The recommended way to manage styles is with add_style
109
- # @see Styles#add_style
110
- attr_reader :dxfs
111
-
112
- # The collection of table styles that will be available to the user in the excel UI
113
- # @return [SimpleTypedList]
114
- # @note The recommended way to manage styles is with add_style
115
- # @see Styles#add_style
116
- attr_reader :tableStyles
117
-
118
- # Creates a new Styles object and prepopulates it with the requires objects to generate a valid package style part.
119
- def initialize()
120
- load_default_styles
121
- end
122
-
123
- # Drastically simplifies style creation and management.
124
- # @return [Integer]
125
- # @option options [String] fg_color The text color
126
- # @option options [Integer] sz The text size
127
- # @option options [Boolean] b Indicates if the text should be bold
128
- # @option options [Boolean] i Indicates if the text should be italicised
129
- # @option options [Boolean] u Indicates if the text should be underlined
130
- # @option options [Boolean] strike Indicates if the text should be rendered with a strikethrough
131
- # @option options [Boolean] shadow Indicates if the text should be rendered with a shadow
132
- # @option options [Integer] charset The character set to use.
133
- # @option options [Integer] family The font family to use.
134
- # @option options [String] font_name The name of the font to use
135
- # @option options [Integer] num_fmt The number format to apply
136
- # @option options [String] format_code The formatting to apply.
137
- # @option options [Integer|Hash] border The border style to use.
138
- # borders support style, color and edges options @see parse_border_options
139
- # @option options [String] bg_color The background color to apply to the cell
140
- # @option options [Boolean] hidden Indicates if the cell should be hidden
141
- # @option options [Boolean] locked Indicates if the cell should be locked
142
- # @option options [Symbol] type What type of style is this. Options are [:dxf, :xf]. :xf is default
143
- # @option options [Hash] alignment A hash defining any of the attributes used in CellAlignment
144
- # @see CellAlignment
145
- #
146
- # @example You Got Style
147
- # require "rubygems" # if that is your preferred way to manage gems!
148
- # require "axlsx"
149
- #
150
- # p = Axlsx::Package.new
151
- # ws = p.workbook.add_worksheet
152
- #
153
- # # black text on a white background at 14pt with thin borders!
154
- # title = ws.styles.add_style(:bg_color => "FFFF0000", :fg_color=>"#FF000000", :sz=>14, :border=> {:style => :thin, :color => "FFFF0000"}
155
- #
156
- # ws.add_row ["Least Popular Pets"]
157
- # ws.add_row ["", "Dry Skinned Reptiles", "Bald Cats", "Violent Parrots"], :style=>title
158
- # ws.add_row ["Votes", 6, 4, 1], :style=>Axlsx::STYLE_THIN_BORDER
159
- # f = File.open('example_you_got_style.xlsx', 'w')
160
- # p.serialize(f)
161
- #
162
- # @example Styling specifically
163
- # # an example of applying specific styles to specific cells
164
- # require "rubygems" # if that is your preferred way to manage gems!
165
- # require "axlsx"
166
- #
167
- # p = Axlsx::Package.new
168
- # ws = p.workbook.add_worksheet
169
- #
170
- # # define your styles
171
- # title = ws.styles.add_style(:bg_color => "FFFF0000",
172
- # :fg_color=>"#FF000000",
173
- # :border=>Axlsx::STYLE_THIN_BORDER,
174
- # :alignment=>{:horizontal => :center})
175
- #
176
- # date_time = ws.styles.add_style(:num_fmt => Axlsx::NUM_FMT_YYYYMMDDHHMMSS,
177
- # :border=>Axlsx::STYLE_THIN_BORDER)
178
- #
179
- # percent = ws.styles.add_style(:num_fmt => Axlsx::NUM_FMT_PERCENT,
180
- # :border=>Axlsx::STYLE_THIN_BORDER)
181
- #
182
- # currency = ws.styles.add_style(:format_code=>"¥#,##0;[Red]¥-#,##0",
183
- # :border=>Axlsx::STYLE_THIN_BORDER)
184
- #
185
- # # build your rows
186
- # ws.add_row ["Generated At:", Time.now], :styles=>[nil, date_time]
187
- # ws.add_row ["Previous Year Quarterly Profits (JPY)"], :style=>title
188
- # ws.add_row ["Quarter", "Profit", "% of Total"], :style=>title
189
- # ws.add_row ["Q1", 4000, 40], :style=>[title, currency, percent]
190
- # ws.add_row ["Q2", 3000, 30], :style=>[title, currency, percent]
191
- # ws.add_row ["Q3", 1000, 10], :style=>[title, currency, percent]
192
- # ws.add_row ["Q4", 2000, 20], :style=>[title, currency, percent]
193
- # f = File.open('example_you_got_style.xlsx', 'w')
194
- # p.serialize(f)
195
- #
196
- # @example Differential styling
197
- # # Differential styles apply on top of cell styles. Used in Conditional Formatting. Must specify :type => :dxf, and you can't use :num_fmt.
198
- # require "rubygems" # if that is your preferred way to manage gems!
199
- # require "axlsx"
200
- #
201
- # p = Axlsx::Package.new
202
- # wb = p.workbook
203
- # ws = wb.add_worksheet
204
- #
205
- # # define your styles
206
- # profitable = wb.styles.add_style(:bg_color => "FFFF0000",
207
- # :fg_color=>"#FF000000",
208
- # :type => :dxf)
209
- #
210
- # ws.add_row ["Genreated At:", Time.now], :styles=>[nil, date_time]
211
- # ws.add_row ["Previous Year Quarterly Profits (JPY)"], :style=>title
212
- # ws.add_row ["Quarter", "Profit", "% of Total"], :style=>title
213
- # ws.add_row ["Q1", 4000, 40], :style=>[title, currency, percent]
214
- # ws.add_row ["Q2", 3000, 30], :style=>[title, currency, percent]
215
- # ws.add_row ["Q3", 1000, 10], :style=>[title, currency, percent]
216
- # ws.add_row ["Q4", 2000, 20], :style=>[title, currency, percent]
217
- #
218
- # ws.add_conditional_formatting("A1:A7", { :type => :cellIs, :operator => :greaterThan, :formula => "2000", :dxfId => profitable, :priority => 1 })
219
- # f = File.open('example_differential_styling', 'w')
220
- # p.serialize(f)
221
- #
222
- def add_style(options={})
223
- # Default to :xf
224
- options[:type] ||= :xf
225
- raise ArgumentError, "Type must be one of [:xf, :dxf]" unless [:xf, :dxf].include?(options[:type] )
226
-
227
- fill = parse_fill_options options
228
- font = parse_font_options options
229
- numFmt = parse_num_fmt_options options
230
- border = parse_border_options options
231
- alignment = parse_alignment_options options
232
- protection = parse_protection_options options
233
-
234
- case options[:type]
235
- when :dxf
236
- style = Dxf.new :fill => fill, :font => font, :numFmt => numFmt, :border => border, :alignment => alignment, :protection => protection
237
- else
238
- style = Xf.new :fillId=>fill || 0, :fontId=>font || 0, :numFmtId=>numFmt || 0, :borderId=>border || 0, :alignment => alignment, :protection => protection, :applyFill=>!fill.nil?, :applyFont=>!font.nil?, :applyNumberFormat =>!numFmt.nil?, :applyBorder=>!border.nil?, :applyAlignment => !alignment.nil?, :applyProtection => !protection.nil?
239
- end
240
-
241
- options[:type] == :xf ? cellXfs << style : dxfs << style
242
- end
243
-
244
- # parses add_style options for protection styles
245
- # noop if options hash does not include :hide or :locked key
246
-
247
- # @option options [Boolean] hide boolean value defining cell protection attribute for hiding.
248
- # @option options [Boolean] locked boolean value defining cell protection attribute for locking.
249
- # @return [CellProtection]
250
- def parse_protection_options(options={})
251
- return if (options.keys & [:hidden, :locked]).empty?
252
- CellProtection.new(options)
253
- end
254
-
255
- # parses add_style options for alignment
256
- # noop if options hash does not include :alignment key
257
- # @option options [Hash] alignment A hash of options to prive the CellAlignment intializer
258
- # @return [CellAlignment]
259
- # @see CellAlignment
260
- def parse_alignment_options(options={})
261
- return unless options[:alignment]
262
- CellAlignment.new options[:alignment]
263
- end
264
-
265
- # parses add_style options for fonts. If the options hash contains :type => :dxf we return a new Font object.
266
- # if not, we return the index of the newly created font object in the styles.fonts collection.
267
- # @note noop if none of the options described here are set on the options parameter.
268
- # @option options [Symbol] type The type of style object we are working with (dxf or xf)
269
- # @option options [String] fg_color The text color
270
- # @option options [Integer] sz The text size
271
- # @option options [Boolean] b Indicates if the text should be bold
272
- # @option options [Boolean] i Indicates if the text should be italicised
273
- # @option options [Boolean] u Indicates if the text should be underlined
274
- # @option options [Boolean] strike Indicates if the text should be rendered with a strikethrough
275
- # @option options [Boolean] outline Indicates if the text should be rendered with a shadow
276
- # @option options [Integer] charset The character set to use.
277
- # @option options [Integer] family The font family to use.
278
- # @option options [String] font_name The name of the font to use
279
- # @return [Font|Integer]
280
- def parse_font_options(options={})
281
- return if (options.keys & [:fg_color, :sz, :b, :i, :u, :strike, :outline, :shadow, :charset, :family, :font_name]).empty?
282
- fonts.first.instance_values.each do |key, value|
283
- # Thanks for that 1.8.7 - cant do a simple merge...
284
- options[key.to_sym] = value unless options.keys.include?(key.to_sym)
285
- end
286
- font = Font.new(options)
287
- font.color = Color.new(:rgb => options[:fg_color]) if options[:fg_color]
288
- font.name = options[:font_name] if options[:font_name]
289
- options[:type] == :dxf ? font : fonts << font
290
- end
291
-
292
- # parses add_style options for fills. If the options hash contains :type => :dxf we return a Fill object. If not, we return the index of the fill after being added to the fills collection.
293
- # @note noop if :bg_color is not specified in options
294
- # @option options [String] bg_color The rgb color to apply to the fill
295
- # @return [Fill|Integer]
296
- def parse_fill_options(options={})
297
- return unless options[:bg_color]
298
- color = Color.new(:rgb=>options[:bg_color])
299
- dxf = options[:type] == :dxf
300
- color_key = dxf ? :bgColor : :fgColor
301
- pattern = PatternFill.new(:patternType =>:solid, color_key=>color)
302
- fill = Fill.new(pattern)
303
- dxf ? fill : fills << fill
304
- end
305
-
306
- # parses Style#add_style options for borders.
307
- # @note noop if :border is not specified in options
308
- # @option options [Hash|Integer] A border style definition hash or the index of an existing border.
309
- # Border style definition hashes must include :style and :color key-value entries and
310
- # may include an :edges entry that references an array of symbols identifying which border edges
311
- # you wish to apply the style or any other valid Border initializer options.
312
- # If the :edges entity is not provided the style is applied to all edges of cells that reference this style.
313
- # Also available :border_top, :border_right, :border_bottom and :border_left options with :style and/or :color
314
- # key-value entries, which override :border values.
315
- # @example
316
- # #apply a thick red border to the top and bottom
317
- # { :border => { :style => :thick, :color => "FFFF0000", :edges => [:top, :bottom] }
318
- # @return [Border|Integer]
319
- def parse_border_options(options={})
320
- if options[:border].nil? && Border::EDGES.all?{|x| options["border_#{x}".to_sym].nil? }
321
- return nil
322
- end
323
-
324
- if options[:border].is_a?(Integer)
325
- if options[:border] >= borders.size
326
- raise ArgumentError, (ERR_INVALID_BORDER_ID % options[:border])
327
- end
328
-
329
- if options[:type] == :dxf
330
- return borders[options[:border]].clone
331
- else
332
- return options[:border]
333
- end
334
- end
335
-
336
- validate_border_hash = ->(val){
337
- if !(val.keys.include?(:style) && val.keys.include?(:color))
338
- raise ArgumentError, (ERR_INVALID_BORDER_OPTIONS % options[:border])
339
- end
340
- }
341
-
342
- borders_array = []
343
-
344
- if options[:border].nil?
345
- base_border_opts = {}
346
- else
347
- if options[:border].is_a?(Array)
348
- borders_array += options[:border]
349
-
350
- base_border_opts = {}
351
-
352
- options[:border].each do |b_opts|
353
- if b_opts[:edges].nil?
354
- base_border_opts = base_border_opts.merge(b_opts)
355
- end
356
- end
357
- else
358
- borders_array << options[:border]
359
-
360
- base_border_opts = options[:border]
361
-
362
- validate_border_hash.call(base_border_opts)
363
- end
364
- end
365
-
366
- Border::EDGES.each do |edge|
367
- val = options["border_#{edge}".to_sym]
368
-
369
- if val
370
- borders_array << val.merge(edges: [edge])
371
- end
372
- end
373
-
374
- border = Border.new(base_border_opts)
375
-
376
- Border::EDGES.each do |edge|
377
- edge_b_opts = base_border_opts
378
-
379
- skip_edge = true
380
-
381
- borders_array.each do |b_opts|
382
- if b_opts[:edges] && b_opts[:edges].include?(edge)
383
- edge_b_opts = edge_b_opts.merge(b_opts)
384
- skip_edge = false
385
- end
386
- end
387
-
388
- if options["border_#{edge}".to_sym]
389
- edge_b_opts = edge_b_opts.merge(options["border_#{edge}".to_sym])
390
- skip_edge = false
391
- end
392
-
393
- if skip_edge && base_border_opts[:edges]
394
- next
395
- end
396
-
397
- if !edge_b_opts.empty?
398
- if base_border_opts.empty?
399
- validate_border_hash.call(edge_b_opts)
400
- end
401
-
402
- border.prs << BorderPr.new({
403
- :name => edge,
404
- :style => edge_b_opts[:style],
405
- :color => Color.new(:rgb => edge_b_opts[:color]) },
406
- )
407
- end
408
- end
409
-
410
- if options[:type] == :dxf
411
- return border
412
- else
413
- return borders << border
414
- end
415
- end
416
-
417
- # Parses Style#add_style options for number formatting.
418
- # noop if neither :format_code or :num_format options are set.
419
- # @option options [Hash] A hash describing the :format_code and/or :num_fmt integer for the style.
420
- # @return [NumFmt|Integer]
421
- def parse_num_fmt_options(options={})
422
- return if (options.keys & [:format_code, :num_fmt]).empty?
423
-
424
- #When the user provides format_code - we always need to create a new numFmt object
425
- #When the type is :dxf we always need to create a new numFmt object
426
- if options[:format_code] || options[:type] == :dxf
427
- #If this is a standard xf we pull from numFmts the highest current and increment for num_fmt
428
- options[:num_fmt] ||= (@numFmts.map{ |num_fmt| num_fmt.numFmtId }.max + 1) if options[:type] != :dxf
429
- numFmt = NumFmt.new(:numFmtId => options[:num_fmt] || 0, :formatCode=> options[:format_code].to_s)
430
- options[:type] == :dxf ? numFmt : (numFmts << numFmt; numFmt.numFmtId)
431
- else
432
- options[:num_fmt]
433
- end
434
- end
435
-
436
- # Serializes the object
437
- # @param [String] str
438
- # @return [String]
439
- def to_xml_string(str = '')
440
- str << ('<styleSheet xmlns="' << XML_NS << '">')
441
- [:numFmts, :fonts, :fills, :borders, :cellStyleXfs, :cellXfs, :cellStyles, :dxfs, :tableStyles].each do |key|
442
- self.instance_values[key.to_s].to_xml_string(str) unless self.instance_values[key.to_s].nil?
443
- end
444
- str << '</styleSheet>'
445
- end
446
-
447
- private
448
- # Creates the default set of styles the exel requires to be valid as well as setting up the
449
- # Axlsx::STYLE_THIN_BORDER
450
- def load_default_styles
451
- @numFmts = SimpleTypedList.new NumFmt, 'numFmts'
452
- @numFmts << NumFmt.new(:numFmtId => NUM_FMT_YYYYMMDD, :formatCode=> "yyyy/mm/dd")
453
- @numFmts << NumFmt.new(:numFmtId => NUM_FMT_YYYYMMDDHHMMSS, :formatCode=> "yyyy/mm/dd hh:mm:ss")
454
-
455
- @numFmts.lock
456
-
457
- @fonts = SimpleTypedList.new Font, 'fonts'
458
- @fonts << Font.new(:name => "Arial", :sz => 11, :family=>1)
459
- @fonts.lock
460
-
461
- @fills = SimpleTypedList.new Fill, 'fills'
462
- @fills << Fill.new(Axlsx::PatternFill.new(:patternType=>:none))
463
- @fills << Fill.new(Axlsx::PatternFill.new(:patternType=>:gray125))
464
- @fills.lock
465
-
466
- @borders = SimpleTypedList.new Border, 'borders'
467
- @borders << Border.new
468
- black_border = Border.new
469
- [:left, :right, :top, :bottom].each do |item|
470
- black_border.prs << BorderPr.new(:name=>item, :style=>:thin, :color=>Color.new(:rgb=>"FF000000"))
471
- end
472
- @borders << black_border
473
- @borders.lock
474
-
475
- @cellStyleXfs = SimpleTypedList.new Xf, "cellStyleXfs"
476
- @cellStyleXfs << Xf.new(:borderId=>0, :numFmtId=>0, :fontId=>0, :fillId=>0)
477
- @cellStyleXfs.lock
478
-
479
- @cellStyles = SimpleTypedList.new CellStyle, 'cellStyles'
480
- @cellStyles << CellStyle.new(:name =>"Normal", :builtinId =>0, :xfId=>0)
481
- @cellStyles.lock
482
-
483
- @cellXfs = SimpleTypedList.new Xf, "cellXfs"
484
- @cellXfs << Xf.new(:borderId=>0, :xfId=>0, :numFmtId=>0, :fontId=>0, :fillId=>0)
485
- @cellXfs << Xf.new(:borderId=>1, :xfId=>0, :numFmtId=>0, :fontId=>0, :fillId=>0)
486
- # default date formatting
487
- @cellXfs << Xf.new(:borderId=>0, :xfId=>0, :numFmtId=>14, :fontId=>0, :fillId=>0, :applyNumberFormat=>1)
488
- @cellXfs.lock
489
-
490
- @dxfs = SimpleTypedList.new(Dxf, "dxfs"); @dxfs.lock
491
- @tableStyles = TableStyles.new(:defaultTableStyle => "TableStyleMedium9", :defaultPivotStyle => "PivotStyleLight16"); @tableStyles.lock
492
- end
493
- end
494
- end
1
+ module Axlsx
2
+ require 'axlsx/stylesheet/border.rb'
3
+ require 'axlsx/stylesheet/border_pr.rb'
4
+ require 'axlsx/stylesheet/cell_alignment.rb'
5
+ require 'axlsx/stylesheet/cell_style.rb'
6
+ require 'axlsx/stylesheet/color.rb'
7
+ require 'axlsx/stylesheet/fill.rb'
8
+ require 'axlsx/stylesheet/font.rb'
9
+ require 'axlsx/stylesheet/gradient_fill.rb'
10
+ require 'axlsx/stylesheet/gradient_stop.rb'
11
+ require 'axlsx/stylesheet/num_fmt.rb'
12
+ require 'axlsx/stylesheet/pattern_fill.rb'
13
+ require 'axlsx/stylesheet/table_style.rb'
14
+ require 'axlsx/stylesheet/table_styles.rb'
15
+ require 'axlsx/stylesheet/table_style_element.rb'
16
+ require 'axlsx/stylesheet/dxf.rb'
17
+ require 'axlsx/stylesheet/xf.rb'
18
+ require 'axlsx/stylesheet/cell_protection.rb'
19
+
20
+ # The Styles class manages worksheet styles
21
+ # In addition to creating the require style objects for a valid xlsx package, this class provides the key mechanism for adding styles to your workbook, and safely applying them to the cells of your worksheet.
22
+ # All portions of the stylesheet are implemented here exception colors, which specify legacy and modified pallete colors, and exLst, whic is used as a future feature data storage area.
23
+ # @see Office Open XML Part 1 18.8.11 for gory details on how this stuff gets put together
24
+ # @see Styles#add_style
25
+ # @note The recommended way to manage styles is with add_style
26
+ class Styles
27
+ # numFmts for your styles.
28
+ # The default styles, which change based on the system local, are as follows.
29
+ # id formatCode
30
+ # 0 General
31
+ # 1 0
32
+ # 2 0.00
33
+ # 3 #,##0
34
+ # 4 #,##0.00
35
+ # 9 0%
36
+ # 10 0.00%
37
+ # 11 0.00E+00
38
+ # 12 # ?/?
39
+ # 13 # ??/??
40
+ # 14 mm-dd-yy
41
+ # 15 d-mmm-yy
42
+ # 16 d-mmm
43
+ # 17 mmm-yy
44
+ # 18 h:mm AM/PM
45
+ # 19 h:mm:ss AM/PM
46
+ # 20 h:mm
47
+ # 21 h:mm:ss
48
+ # 22 m/d/yy h:mm
49
+ # 37 #,##0 ;(#,##0)
50
+ # 38 #,##0 ;[Red](#,##0)
51
+ # 39 #,##0.00;(#,##0.00)
52
+ # 40 #,##0.00;[Red](#,##0.00)
53
+ # 45 mm:ss
54
+ # 46 [h]:mm:ss
55
+ # 47 mmss.0
56
+ # 48 ##0.0E+0
57
+ # 49 @
58
+ # Axlsx also defines the following constants which you can use in add_style.
59
+ # NUM_FMT_PERCENT formats to "0%"
60
+ # NUM_FMT_YYYYMMDD formats to "yyyy/mm/dd"
61
+ # NUM_FMT_YYYYMMDDHHMMSS formats to "yyyy/mm/dd hh:mm:ss"
62
+ # @see Office Open XML Part 1 - 18.8.31 for more information on creating number formats
63
+ # @return [SimpleTypedList]
64
+ # @note The recommended way to manage styles is with add_style
65
+ # @see Styles#add_style
66
+ attr_reader :numFmts
67
+
68
+ # The collection of fonts used in this workbook
69
+ # @return [SimpleTypedList]
70
+ # @note The recommended way to manage styles is with add_style
71
+ # @see Styles#add_style
72
+ attr_reader :fonts
73
+
74
+ # The collection of fills used in this workbook
75
+ # @return [SimpleTypedList]
76
+ # @note The recommended way to manage styles is with add_style
77
+ # @see Styles#add_style
78
+ attr_reader :fills
79
+
80
+ # The collection of borders used in this workbook
81
+ # Axlsx predefines THIN_BORDER which can be used to put a border around all of your cells.
82
+ # @return [SimpleTypedList]
83
+ # @note The recommended way to manage styles is with add_style
84
+ # @see Styles#add_style
85
+ attr_reader :borders
86
+
87
+ # The collection of master formatting records for named cell styles, which means records defined in cellStyles, in the workbook
88
+ # @return [SimpleTypedList]
89
+ # @note The recommended way to manage styles is with add_style
90
+ # @see Styles#add_style
91
+ attr_reader :cellStyleXfs
92
+
93
+ # The collection of named styles, referencing cellStyleXfs items in the workbook.
94
+ # @return [SimpleTypedList]
95
+ # @note The recommended way to manage styles is with add_style
96
+ # @see Styles#add_style
97
+ attr_reader :cellStyles
98
+
99
+ # The collection of master formatting records. This is the list that you will actually use in styling a workbook.
100
+ # @return [SimpleTypedList]
101
+ # @note The recommended way to manage styles is with add_style
102
+ # @see Styles#add_style
103
+ attr_reader :cellXfs
104
+
105
+ # The collection of non-cell formatting records used in the worksheet.
106
+ # @return [SimpleTypedList]
107
+ # @note The recommended way to manage styles is with add_style
108
+ # @see Styles#add_style
109
+ attr_reader :dxfs
110
+
111
+ # The collection of table styles that will be available to the user in the excel UI
112
+ # @return [SimpleTypedList]
113
+ # @note The recommended way to manage styles is with add_style
114
+ # @see Styles#add_style
115
+ attr_reader :tableStyles
116
+
117
+ # Creates a new Styles object and prepopulates it with the requires objects to generate a valid package style part.
118
+ def initialize()
119
+ load_default_styles
120
+ end
121
+
122
+ def style_index
123
+ @style_index ||= {}
124
+ end
125
+
126
+ # Drastically simplifies style creation and management.
127
+ # @return [Integer]
128
+ # @option options [String] fg_color The text color
129
+ # @option options [Integer] sz The text size
130
+ # @option options [Boolean] b Indicates if the text should be bold
131
+ # @option options [Boolean] i Indicates if the text should be italicised
132
+ # @option options [Boolean] u Indicates if the text should be underlined
133
+ # @option options [Boolean] strike Indicates if the text should be rendered with a strikethrough
134
+ # @option options [Boolean] shadow Indicates if the text should be rendered with a shadow
135
+ # @option options [Integer] charset The character set to use.
136
+ # @option options [Integer] family The font family to use.
137
+ # @option options [String] font_name The name of the font to use
138
+ # @option options [Integer] num_fmt The number format to apply
139
+ # @option options [String] format_code The formatting to apply.
140
+ # @option options [Integer|Hash] border The border style to use.
141
+ # borders support style, color and edges options @see parse_border_options
142
+ # @option options [String] bg_color The background color to apply to the cell
143
+ # @option options [Boolean] hidden Indicates if the cell should be hidden
144
+ # @option options [Boolean] locked Indicates if the cell should be locked
145
+ # @option options [Symbol] type What type of style is this. Options are [:dxf, :xf]. :xf is default
146
+ # @option options [Hash] alignment A hash defining any of the attributes used in CellAlignment
147
+ # @see CellAlignment
148
+ #
149
+ # @example You Got Style
150
+ # require "rubygems" # if that is your preferred way to manage gems!
151
+ # require "axlsx"
152
+ #
153
+ # p = Axlsx::Package.new
154
+ # ws = p.workbook.add_worksheet
155
+ #
156
+ # # black text on a white background at 14pt with thin borders!
157
+ # title = ws.styles.add_style(:bg_color => "FFFF0000", :fg_color=>"#FF000000", :sz=>14, :border=> {:style => :thin, :color => "FFFF0000"}
158
+ #
159
+ # ws.add_row ["Least Popular Pets"]
160
+ # ws.add_row ["", "Dry Skinned Reptiles", "Bald Cats", "Violent Parrots"], :style=>title
161
+ # ws.add_row ["Votes", 6, 4, 1], :style=>Axlsx::STYLE_THIN_BORDER
162
+ # f = File.open('example_you_got_style.xlsx', 'wb')
163
+ # p.serialize(f)
164
+ #
165
+ # @example Styling specifically
166
+ # # an example of applying specific styles to specific cells
167
+ # require "rubygems" # if that is your preferred way to manage gems!
168
+ # require "axlsx"
169
+ #
170
+ # p = Axlsx::Package.new
171
+ # ws = p.workbook.add_worksheet
172
+ #
173
+ # # define your styles
174
+ # title = ws.styles.add_style(:bg_color => "FFFF0000",
175
+ # :fg_color=>"#FF000000",
176
+ # :border=>Axlsx::STYLE_THIN_BORDER,
177
+ # :alignment=>{:horizontal => :center})
178
+ #
179
+ # date_time = ws.styles.add_style(:num_fmt => Axlsx::NUM_FMT_YYYYMMDDHHMMSS,
180
+ # :border=>Axlsx::STYLE_THIN_BORDER)
181
+ #
182
+ # percent = ws.styles.add_style(:num_fmt => Axlsx::NUM_FMT_PERCENT,
183
+ # :border=>Axlsx::STYLE_THIN_BORDER)
184
+ #
185
+ # currency = ws.styles.add_style(:format_code=>"¥#,##0;[Red]¥-#,##0",
186
+ # :border=>Axlsx::STYLE_THIN_BORDER)
187
+ #
188
+ # # build your rows
189
+ # ws.add_row ["Generated At:", Time.now], :styles=>[nil, date_time]
190
+ # ws.add_row ["Previous Year Quarterly Profits (JPY)"], :style=>title
191
+ # ws.add_row ["Quarter", "Profit", "% of Total"], :style=>title
192
+ # ws.add_row ["Q1", 4000, 40], :style=>[title, currency, percent]
193
+ # ws.add_row ["Q2", 3000, 30], :style=>[title, currency, percent]
194
+ # ws.add_row ["Q3", 1000, 10], :style=>[title, currency, percent]
195
+ # ws.add_row ["Q4", 2000, 20], :style=>[title, currency, percent]
196
+ # f = File.open('example_you_got_style.xlsx', 'wb')
197
+ # p.serialize(f)
198
+ #
199
+ # @example Differential styling
200
+ # # Differential styles apply on top of cell styles. Used in Conditional Formatting. Must specify :type => :dxf, and you can't use :num_fmt.
201
+ # require "rubygems" # if that is your preferred way to manage gems!
202
+ # require "axlsx"
203
+ #
204
+ # p = Axlsx::Package.new
205
+ # wb = p.workbook
206
+ # ws = wb.add_worksheet
207
+ #
208
+ # # define your styles
209
+ # profitable = wb.styles.add_style(:bg_color => "FFFF0000",
210
+ # :fg_color=>"#FF000000",
211
+ # :type => :dxf)
212
+ #
213
+ # ws.add_row ["Genreated At:", Time.now], :styles=>[nil, date_time]
214
+ # ws.add_row ["Previous Year Quarterly Profits (JPY)"], :style=>title
215
+ # ws.add_row ["Quarter", "Profit", "% of Total"], :style=>title
216
+ # ws.add_row ["Q1", 4000, 40], :style=>[title, currency, percent]
217
+ # ws.add_row ["Q2", 3000, 30], :style=>[title, currency, percent]
218
+ # ws.add_row ["Q3", 1000, 10], :style=>[title, currency, percent]
219
+ # ws.add_row ["Q4", 2000, 20], :style=>[title, currency, percent]
220
+ #
221
+ # ws.add_conditional_formatting("A1:A7", { :type => :cellIs, :operator => :greaterThan, :formula => "2000", :dxfId => profitable, :priority => 1 })
222
+ # f = File.open('example_differential_styling', 'wb')
223
+ # p.serialize(f)
224
+ #
225
+ # An index for cell styles where keys are styles codes as per Axlsx::Style and values are Cell#raw_style
226
+ # The reason for the backward key/value ordering is that style lookup must be most efficient, while `add_style` can be less efficient
227
+ def add_style(options = {})
228
+ # Default to :xf
229
+ options[:type] ||= :xf
230
+
231
+ raise ArgumentError, "Type must be one of [:xf, :dxf]" unless [:xf, :dxf].include?(options[:type])
232
+
233
+ if options[:border].is_a?(Hash)
234
+ if options[:border][:edges] == :all
235
+ options[:border][:edges] = Axlsx::Border::EDGES
236
+ elsif options[:border][:edges]
237
+ options[:border][:edges] = options[:border][:edges].map(&:to_sym) ### normalize for style caching
238
+ end
239
+ end
240
+
241
+ if options[:type] == :xf
242
+ # Check to see if style in cache already
243
+
244
+ font_defaults = { name: @fonts.first.name, sz: @fonts.first.sz, family: @fonts.first.family }
245
+
246
+ raw_style = { type: :xf }.merge(font_defaults).merge(options)
247
+
248
+ if raw_style[:format_code]
249
+ raw_style.delete(:num_fmt)
250
+ end
251
+
252
+ xf_index = style_index.key(raw_style)
253
+
254
+ if xf_index
255
+ return xf_index
256
+ end
257
+ end
258
+
259
+ fill = parse_fill_options options
260
+ font = parse_font_options options
261
+ numFmt = parse_num_fmt_options options
262
+ border = parse_border_options options
263
+ alignment = parse_alignment_options options
264
+ protection = parse_protection_options options
265
+
266
+ case options[:type]
267
+ when :dxf
268
+ style = Dxf.new :fill => fill, :font => font, :numFmt => numFmt, :border => border, :alignment => alignment, :protection => protection
269
+ else
270
+ style = Xf.new :fillId => fill || 0, :fontId => font || 0, :numFmtId => numFmt || 0, :borderId => border || 0, :alignment => alignment, :protection => protection, :applyFill => !fill.nil?, :applyFont => !font.nil?, :applyNumberFormat => !numFmt.nil?, :applyBorder => !border.nil?, :applyAlignment => !alignment.nil?, :applyProtection => !protection.nil?
271
+ end
272
+
273
+ if options[:type] == :xf
274
+ xf_index = (cellXfs << style)
275
+
276
+ # Add styles to style_index cache for re-use
277
+ style_index[xf_index] = raw_style
278
+
279
+ return xf_index
280
+ else
281
+ dxf_index = (dxfs << style)
282
+
283
+ return dxf_index
284
+ end
285
+ end
286
+
287
+ # parses add_style options for protection styles
288
+ # noop if options hash does not include :hide or :locked key
289
+
290
+ # @option options [Boolean] hide boolean value defining cell protection attribute for hiding.
291
+ # @option options [Boolean] locked boolean value defining cell protection attribute for locking.
292
+ # @return [CellProtection]
293
+ def parse_protection_options(options = {})
294
+ return if (options.keys & [:hidden, :locked]).empty?
295
+
296
+ CellProtection.new(options)
297
+ end
298
+
299
+ # parses add_style options for alignment
300
+ # noop if options hash does not include :alignment key
301
+ # @option options [Hash] alignment A hash of options to prive the CellAlignment intializer
302
+ # @return [CellAlignment]
303
+ # @see CellAlignment
304
+ def parse_alignment_options(options = {})
305
+ return unless options[:alignment]
306
+
307
+ CellAlignment.new options[:alignment]
308
+ end
309
+
310
+ # parses add_style options for fonts. If the options hash contains :type => :dxf we return a new Font object.
311
+ # if not, we return the index of the newly created font object in the styles.fonts collection.
312
+ # @note noop if none of the options described here are set on the options parameter.
313
+ # @option options [Symbol] type The type of style object we are working with (dxf or xf)
314
+ # @option options [String] fg_color The text color
315
+ # @option options [Integer] sz The text size
316
+ # @option options [Boolean] b Indicates if the text should be bold
317
+ # @option options [Boolean] i Indicates if the text should be italicised
318
+ # @option options [Boolean] u Indicates if the text should be underlined
319
+ # @option options [Boolean] strike Indicates if the text should be rendered with a strikethrough
320
+ # @option options [Boolean] outline Indicates if the text should be rendered with a shadow
321
+ # @option options [Integer] charset The character set to use.
322
+ # @option options [Integer] family The font family to use.
323
+ # @option options [String] font_name The name of the font to use
324
+ # @return [Font|Integer]
325
+ def parse_font_options(options = {})
326
+ return if (options.keys & [:fg_color, :sz, :b, :i, :u, :strike, :outline, :shadow, :charset, :family, :font_name]).empty?
327
+
328
+ Axlsx.instance_values_for(fonts.first).each do |key, value|
329
+ # Thanks for that 1.8.7 - cant do a simple merge...
330
+ options[key.to_sym] = value unless options.keys.include?(key.to_sym)
331
+ end
332
+ font = Font.new(options)
333
+ font.color = Color.new(:rgb => options[:fg_color]) if options[:fg_color]
334
+ font.name = options[:font_name] if options[:font_name]
335
+ options[:type] == :dxf ? font : fonts << font
336
+ end
337
+
338
+ # parses add_style options for fills. If the options hash contains :type => :dxf we return a Fill object. If not, we return the index of the fill after being added to the fills collection.
339
+ # @note noop if :bg_color is not specified in options
340
+ # @option options [String] bg_color The rgb color to apply to the fill
341
+ # @return [Fill|Integer]
342
+ def parse_fill_options(options = {})
343
+ return unless options[:bg_color]
344
+
345
+ color = Color.new(:rgb => options[:bg_color])
346
+ dxf = options[:type] == :dxf
347
+ color_key = dxf ? :bgColor : :fgColor
348
+ pattern = PatternFill.new(:patternType => :solid, color_key => color)
349
+ fill = Fill.new(pattern)
350
+ dxf ? fill : fills << fill
351
+ end
352
+
353
+ # parses Style#add_style options for borders.
354
+ # @note noop if :border is not specified in options
355
+ # @option options [Hash|Integer] A border style definition hash or the index of an existing border.
356
+ # Border style definition hashes must include :style and :color key-value entries and
357
+ # may include an :edges entry that references an array of symbols identifying which border edges
358
+ # you wish to apply the style or any other valid Border initializer options.
359
+ # If the :edges entity is not provided the style is applied to all edges of cells that reference this style.
360
+ # Also available :border_top, :border_right, :border_bottom and :border_left options with :style and/or :color
361
+ # key-value entries, which override :border values.
362
+ # @example
363
+ # #apply a thick red border to the top and bottom
364
+ # { :border => { :style => :thick, :color => "FFFF0000", :edges => [:top, :bottom] }
365
+ # @return [Border|Integer]
366
+ def parse_border_options(options = {})
367
+ if options[:border].nil? && Border::EDGES.all? { |x| options["border_#{x}".to_sym].nil? }
368
+ return nil
369
+ end
370
+
371
+ if options[:border].is_a?(Integer)
372
+ if options[:border] >= borders.size
373
+ raise ArgumentError, (ERR_INVALID_BORDER_ID % options[:border])
374
+ end
375
+
376
+ if options[:type] == :dxf
377
+ return borders[options[:border]].clone
378
+ else
379
+ return options[:border]
380
+ end
381
+ end
382
+
383
+ validate_border_hash = ->(val) {
384
+ if !(val.keys.include?(:style) && val.keys.include?(:color))
385
+ raise ArgumentError, (ERR_INVALID_BORDER_OPTIONS % options[:border])
386
+ end
387
+ }
388
+
389
+ borders_array = []
390
+
391
+ if options[:border].nil?
392
+ base_border_opts = {}
393
+ else
394
+ if options[:border].is_a?(Array)
395
+ borders_array += options[:border]
396
+
397
+ base_border_opts = {}
398
+
399
+ options[:border].each do |b_opts|
400
+ if b_opts[:edges].nil?
401
+ base_border_opts = base_border_opts.merge(b_opts)
402
+ end
403
+ end
404
+ else
405
+ borders_array << options[:border]
406
+
407
+ base_border_opts = options[:border]
408
+
409
+ validate_border_hash.call(base_border_opts)
410
+ end
411
+ end
412
+
413
+ Border::EDGES.each do |edge|
414
+ val = options["border_#{edge}".to_sym]
415
+
416
+ if val
417
+ borders_array << val.merge(edges: [edge])
418
+ end
419
+ end
420
+
421
+ border = Border.new(base_border_opts)
422
+
423
+ Border::EDGES.each do |edge|
424
+ edge_b_opts = base_border_opts
425
+
426
+ skip_edge = true
427
+
428
+ borders_array.each do |b_opts|
429
+ if b_opts[:edges] && b_opts[:edges].include?(edge)
430
+ edge_b_opts = edge_b_opts.merge(b_opts)
431
+ skip_edge = false
432
+ end
433
+ end
434
+
435
+ if options["border_#{edge}".to_sym]
436
+ edge_b_opts = edge_b_opts.merge(options["border_#{edge}".to_sym])
437
+ skip_edge = false
438
+ end
439
+
440
+ if skip_edge && base_border_opts[:edges]
441
+ next
442
+ end
443
+
444
+ if !edge_b_opts.empty?
445
+ if base_border_opts.empty?
446
+ validate_border_hash.call(edge_b_opts)
447
+ end
448
+
449
+ border.prs << BorderPr.new({
450
+ :name => edge,
451
+ :style => edge_b_opts[:style],
452
+ :color => Color.new(:rgb => edge_b_opts[:color])
453
+ })
454
+ end
455
+ end
456
+
457
+ if options[:type] == :dxf
458
+ return border
459
+ else
460
+ return borders << border
461
+ end
462
+ end
463
+
464
+ # Parses Style#add_style options for number formatting.
465
+ # noop if neither :format_code or :num_format options are set.
466
+ # @option options [Hash] A hash describing the :format_code and/or :num_fmt integer for the style.
467
+ # @return [NumFmt|Integer]
468
+ def parse_num_fmt_options(options = {})
469
+ return if (options.keys & [:format_code, :num_fmt]).empty?
470
+
471
+ # When the user provides format_code - we always need to create a new numFmt object
472
+ # When the type is :dxf we always need to create a new numFmt object
473
+ if options[:format_code] || options[:type] == :dxf
474
+ # If this is a standard xf we pull from numFmts the highest current and increment for num_fmt
475
+ options[:num_fmt] ||= (@numFmts.map { |num_fmt| num_fmt.numFmtId }.max + 1) if options[:type] != :dxf
476
+ numFmt = NumFmt.new(:numFmtId => options[:num_fmt] || 0, :formatCode => options[:format_code].to_s)
477
+ options[:type] == :dxf ? numFmt : (numFmts << numFmt; numFmt.numFmtId)
478
+ else
479
+ options[:num_fmt]
480
+ end
481
+ end
482
+
483
+ # Serializes the object
484
+ # @param [String] str
485
+ # @return [String]
486
+ def to_xml_string(str = '')
487
+ str << ('<styleSheet xmlns="' << XML_NS << '">')
488
+ instance_vals = Axlsx.instance_values_for(self)
489
+ [:numFmts, :fonts, :fills, :borders, :cellStyleXfs, :cellXfs, :cellStyles, :dxfs, :tableStyles].each do |key|
490
+ instance_vals[key.to_s].to_xml_string(str) unless instance_vals[key.to_s].nil?
491
+ end
492
+ str << '</styleSheet>'
493
+ end
494
+
495
+ private
496
+
497
+ # Creates the default set of styles the exel requires to be valid as well as setting up the
498
+ # Axlsx::STYLE_THIN_BORDER
499
+ def load_default_styles
500
+ @numFmts = SimpleTypedList.new NumFmt, 'numFmts'
501
+ @numFmts << NumFmt.new(:numFmtId => NUM_FMT_YYYYMMDD, :formatCode => "yyyy/mm/dd")
502
+ @numFmts << NumFmt.new(:numFmtId => NUM_FMT_YYYYMMDDHHMMSS, :formatCode => "yyyy/mm/dd hh:mm:ss")
503
+
504
+ @numFmts.lock
505
+
506
+ @fonts = SimpleTypedList.new Font, 'fonts'
507
+ @fonts << Font.new(:name => "Arial", :sz => 11, :family => 1)
508
+ @fonts.lock
509
+
510
+ @fills = SimpleTypedList.new Fill, 'fills'
511
+ @fills << Fill.new(Axlsx::PatternFill.new(:patternType => :none))
512
+ @fills << Fill.new(Axlsx::PatternFill.new(:patternType => :gray125))
513
+ @fills.lock
514
+
515
+ @borders = SimpleTypedList.new Border, 'borders'
516
+ @borders << Border.new
517
+ black_border = Border.new
518
+ [:left, :right, :top, :bottom].each do |item|
519
+ black_border.prs << BorderPr.new(:name => item, :style => :thin, :color => Color.new(:rgb => "FF000000"))
520
+ end
521
+ @borders << black_border
522
+ @borders.lock
523
+
524
+ @cellStyleXfs = SimpleTypedList.new Xf, "cellStyleXfs"
525
+ @cellStyleXfs << Xf.new(:borderId => 0, :numFmtId => 0, :fontId => 0, :fillId => 0)
526
+ @cellStyleXfs.lock
527
+
528
+ @cellStyles = SimpleTypedList.new CellStyle, 'cellStyles'
529
+ @cellStyles << CellStyle.new(:name => "Normal", :builtinId => 0, :xfId => 0)
530
+ @cellStyles.lock
531
+
532
+ @cellXfs = SimpleTypedList.new Xf, "cellXfs"
533
+ @cellXfs << Xf.new(:borderId => 0, :xfId => 0, :numFmtId => 0, :fontId => 0, :fillId => 0)
534
+ @cellXfs << Xf.new(:borderId => 1, :xfId => 0, :numFmtId => 0, :fontId => 0, :fillId => 0)
535
+ # default date formatting
536
+ @cellXfs << Xf.new(:borderId => 0, :xfId => 0, :numFmtId => 14, :fontId => 0, :fillId => 0, :applyNumberFormat => 1)
537
+ @cellXfs.lock
538
+
539
+ @dxfs = SimpleTypedList.new(Dxf, "dxfs"); @dxfs.lock
540
+ @tableStyles = TableStyles.new(:defaultTableStyle => "TableStyleMedium9", :defaultPivotStyle => "PivotStyleLight16"); @tableStyles.lock
541
+ end
542
+ end
543
+ end