axlsx 1.1.4 → 1.3.1

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 (242) hide show
  1. data/.yardopts +6 -2
  2. data/CHANGELOG.md +72 -0
  3. data/README.md +114 -31
  4. data/Rakefile +11 -3
  5. data/examples/auto_filter.rb +16 -0
  6. data/examples/auto_filter.xlsx +0 -0
  7. data/examples/basic_charts.rb +58 -0
  8. data/examples/chart_colors.rb +17 -2
  9. data/examples/data_validation.rb +50 -0
  10. data/examples/example.rb +171 -60
  11. data/examples/example.xlsx +0 -0
  12. data/examples/example_streamed.xlsx +0 -0
  13. data/examples/extractive.pdf +0 -0
  14. data/examples/extractive.rb +3 -0
  15. data/examples/extractive.xlsx +0 -0
  16. data/examples/hyperlinks.rb +23 -0
  17. data/examples/hyperlinks.xlsx +0 -0
  18. data/examples/no-use_autowidth.xlsx +0 -0
  19. data/examples/page_setup.rb +11 -0
  20. data/examples/page_setup.xlsx +0 -0
  21. data/examples/scraping_html.rb +91 -0
  22. data/examples/shared_strings_example.xlsx +0 -0
  23. data/examples/sheet_protection.rb +10 -0
  24. data/examples/sheet_view.rb +34 -0
  25. data/examples/skydrive/axlsx.csv +1 -0
  26. data/examples/skydrive/axlsx.xlsx +0 -0
  27. data/examples/skydrive/real_example.rb +8 -8
  28. data/examples/sprk2012/Screen Shot 2012-09-11 at 10.42.06 PM.png +0 -0
  29. data/examples/sprk2012/Screen Shot 2012-09-11 at 11.07.48 PM.png +0 -0
  30. data/examples/sprk2012/Screen Shot 2012-09-11 at 8.31.50 PM.png +0 -0
  31. data/examples/sprk2012/Screen Shot 2012-09-11 at 9.23.27 PM.png +0 -0
  32. data/examples/sprk2012/Screen Shot 2012-09-11 at 9.32.06 PM.png +0 -0
  33. data/examples/sprk2012/Screen Shot 2012-09-11 at 9.33.35 PM.png +0 -0
  34. data/examples/sprk2012/Screen Shot 2012-09-11 at 9.46.44 PM.png +0 -0
  35. data/examples/sprk2012/Screen Shot 2012-09-12 at 5.07.23 PM.png +0 -0
  36. data/examples/sprk2012/basics.rb +11 -0
  37. data/examples/sprk2012/basics.xlsx +0 -0
  38. data/examples/sprk2012/gravatar.jpeg +0 -0
  39. data/examples/sprk2012/hair_club.jpg +0 -0
  40. data/examples/sprk2012/images.rb +9 -0
  41. data/examples/sprk2012/images.xlsx +0 -0
  42. data/examples/sprk2012/line_chart.rb +56 -0
  43. data/examples/sprk2012/line_chart.xlsx +0 -0
  44. data/examples/sprk2012/sprk2012.key +0 -0
  45. data/examples/sprk2012/styles.rb +20 -0
  46. data/examples/sprk2012/styles.xlsx +0 -0
  47. data/examples/styles.rb +62 -0
  48. data/examples/styles.xlsx +0 -0
  49. data/examples/two_cell_anchor_image.rb +11 -0
  50. data/lib/axlsx/content_type/content_type.rb +2 -0
  51. data/lib/axlsx/content_type/default.rb +30 -15
  52. data/lib/axlsx/content_type/override.rb +29 -14
  53. data/lib/axlsx/doc_props/app.rb +161 -104
  54. data/lib/axlsx/doc_props/core.rb +9 -5
  55. data/lib/axlsx/drawing/ax_data_source.rb +7 -6
  56. data/lib/axlsx/drawing/axis.rb +82 -36
  57. data/lib/axlsx/drawing/bar_3D_chart.rb +49 -45
  58. data/lib/axlsx/drawing/bar_series.rb +2 -1
  59. data/lib/axlsx/drawing/cat_axis.rb +43 -39
  60. data/lib/axlsx/drawing/chart.rb +65 -54
  61. data/lib/axlsx/drawing/d_lbls.rb +100 -0
  62. data/lib/axlsx/drawing/drawing.rb +20 -8
  63. data/lib/axlsx/drawing/graphic_frame.rb +2 -1
  64. data/lib/axlsx/drawing/line_3D_chart.rb +3 -10
  65. data/lib/axlsx/drawing/num_data.rb +2 -2
  66. data/lib/axlsx/drawing/num_data_source.rb +4 -1
  67. data/lib/axlsx/drawing/pic.rb +44 -4
  68. data/lib/axlsx/drawing/pie_3D_chart.rb +10 -7
  69. data/lib/axlsx/drawing/scatter_chart.rb +2 -8
  70. data/lib/axlsx/drawing/title.rb +21 -9
  71. data/lib/axlsx/drawing/two_cell_anchor.rb +46 -9
  72. data/lib/axlsx/drawing/view_3D.rb +42 -32
  73. data/lib/axlsx/drawing/vml_drawing.rb +42 -0
  74. data/lib/axlsx/drawing/vml_shape.rb +125 -0
  75. data/lib/axlsx/package.rb +43 -16
  76. data/lib/axlsx/rels/relationship.rb +3 -3
  77. data/lib/axlsx/rels/relationships.rb +1 -11
  78. data/lib/axlsx/stylesheet/gradient_fill.rb +1 -1
  79. data/lib/axlsx/stylesheet/styles.rb +11 -2
  80. data/lib/axlsx/stylesheet/table_style.rb +3 -3
  81. data/lib/axlsx/util/constants.rb +131 -2
  82. data/lib/axlsx/util/simple_typed_list.rb +18 -22
  83. data/lib/axlsx/util/validators.rb +100 -9
  84. data/lib/axlsx/version.rb +2 -7
  85. data/lib/axlsx/workbook/defined_name.rb +174 -0
  86. data/lib/axlsx/workbook/defined_names.rb +21 -0
  87. data/lib/axlsx/workbook/workbook.rb +70 -13
  88. data/lib/axlsx/workbook/worksheet/auto_filter/auto_filter.rb +77 -0
  89. data/lib/axlsx/workbook/worksheet/auto_filter/filter_column.rb +102 -0
  90. data/lib/axlsx/workbook/worksheet/auto_filter/filters.rb +253 -0
  91. data/lib/axlsx/workbook/worksheet/cell.rb +41 -8
  92. data/lib/axlsx/workbook/worksheet/col.rb +15 -0
  93. data/lib/axlsx/workbook/worksheet/cols.rb +20 -0
  94. data/lib/axlsx/workbook/worksheet/comment.rb +101 -0
  95. data/lib/axlsx/workbook/worksheet/comments.rb +85 -0
  96. data/lib/axlsx/workbook/worksheet/conditional_formattings.rb +25 -0
  97. data/lib/axlsx/workbook/worksheet/data_bar.rb +1 -1
  98. data/lib/axlsx/workbook/worksheet/data_validation.rb +245 -0
  99. data/lib/axlsx/workbook/worksheet/data_validations.rb +28 -0
  100. data/lib/axlsx/workbook/worksheet/date_time_converter.rb +1 -1
  101. data/lib/axlsx/workbook/worksheet/dimension.rb +65 -0
  102. data/lib/axlsx/workbook/worksheet/merged_cells.rb +35 -0
  103. data/lib/axlsx/workbook/worksheet/page_set_up_pr.rb +47 -0
  104. data/lib/axlsx/workbook/worksheet/page_setup.rb +241 -0
  105. data/lib/axlsx/workbook/worksheet/pane.rb +144 -0
  106. data/lib/axlsx/workbook/worksheet/print_options.rb +63 -0
  107. data/lib/axlsx/workbook/worksheet/protected_range.rb +46 -0
  108. data/lib/axlsx/workbook/worksheet/protected_ranges.rb +34 -0
  109. data/lib/axlsx/workbook/worksheet/row.rb +36 -20
  110. data/lib/axlsx/workbook/worksheet/selection.rb +111 -0
  111. data/lib/axlsx/workbook/worksheet/sheet_calc_pr.rb +49 -0
  112. data/lib/axlsx/workbook/worksheet/sheet_data.rb +25 -0
  113. data/lib/axlsx/workbook/worksheet/sheet_pr.rb +107 -0
  114. data/lib/axlsx/workbook/worksheet/sheet_protection.rb +224 -0
  115. data/lib/axlsx/workbook/worksheet/sheet_view.rb +379 -0
  116. data/lib/axlsx/workbook/worksheet/table.rb +10 -3
  117. data/lib/axlsx/workbook/worksheet/table_style_info.rb +68 -0
  118. data/lib/axlsx/workbook/worksheet/tables.rb +31 -0
  119. data/lib/axlsx/workbook/worksheet/worksheet.rb +414 -254
  120. data/lib/axlsx/workbook/worksheet/worksheet_comments.rb +57 -0
  121. data/lib/axlsx/workbook/worksheet/worksheet_drawing.rb +64 -0
  122. data/lib/axlsx/workbook/worksheet/worksheet_hyperlink.rb +101 -0
  123. data/lib/axlsx/workbook/worksheet/worksheet_hyperlinks.rb +38 -0
  124. data/lib/axlsx.rb +38 -16
  125. data/test/content_type/tc_content_type.rb +1 -6
  126. data/test/doc_props/tc_app.rb +31 -1
  127. data/test/doc_props/tc_core.rb +3 -1
  128. data/test/drawing/tc_axis.rb +38 -3
  129. data/test/drawing/tc_bar_3D_chart.rb +12 -12
  130. data/test/drawing/tc_bar_series.rb +1 -2
  131. data/test/drawing/tc_cat_axis.rb +3 -3
  132. data/test/drawing/tc_chart.rb +29 -9
  133. data/test/drawing/tc_d_lbls.rb +47 -0
  134. data/test/drawing/tc_drawing.rb +11 -5
  135. data/test/drawing/tc_hyperlink.rb +4 -5
  136. data/test/drawing/tc_line_series.rb +7 -3
  137. data/test/drawing/tc_num_data.rb +5 -1
  138. data/test/drawing/tc_pic.rb +22 -2
  139. data/test/drawing/tc_pie_3D_chart.rb +4 -8
  140. data/test/drawing/tc_pie_series.rb +7 -2
  141. data/test/drawing/tc_scatter_chart.rb +6 -1
  142. data/test/drawing/tc_scatter_series.rb +1 -1
  143. data/test/drawing/tc_series.rb +1 -1
  144. data/test/drawing/tc_title.rb +16 -0
  145. data/test/drawing/tc_two_cell_anchor.rb +1 -2
  146. data/test/drawing/tc_view_3D.rb +18 -18
  147. data/test/drawing/tc_vml_drawing.rb +25 -0
  148. data/test/drawing/tc_vml_shape.rb +100 -0
  149. data/test/rels/tc_relationship.rb +1 -0
  150. data/test/stylesheet/tc_gradient_fill.rb +8 -0
  151. data/test/stylesheet/tc_pattern_fill.rb +7 -1
  152. data/test/stylesheet/tc_styles.rb +16 -4
  153. data/test/stylesheet/tc_table_style.rb +8 -0
  154. data/test/stylesheet/tc_table_style_element.rb +10 -1
  155. data/test/tc_helper.rb +1 -0
  156. data/test/tc_package.rb +94 -17
  157. data/test/util/tc_simple_typed_list.rb +13 -0
  158. data/test/util/tc_validators.rb +101 -8
  159. data/test/workbook/tc_defined_name.rb +41 -0
  160. data/test/workbook/tc_workbook.rb +5 -3
  161. data/test/workbook/worksheet/auto_filter/tc_auto_filter.rb +38 -0
  162. data/test/workbook/worksheet/auto_filter/tc_filter_column.rb +76 -0
  163. data/test/workbook/worksheet/auto_filter/tc_filters.rb +50 -0
  164. data/test/workbook/worksheet/tc_cell.rb +53 -7
  165. data/test/workbook/worksheet/tc_col.rb +9 -0
  166. data/test/workbook/worksheet/tc_comment.rb +57 -0
  167. data/test/workbook/worksheet/tc_comments.rb +57 -0
  168. data/test/workbook/worksheet/tc_conditional_formatting.rb +44 -0
  169. data/test/workbook/worksheet/tc_data_bar.rb +1 -1
  170. data/test/workbook/worksheet/tc_data_validation.rb +265 -0
  171. data/test/workbook/worksheet/tc_page_set_up_pr.rb +15 -0
  172. data/test/workbook/worksheet/tc_page_setup.rb +143 -0
  173. data/test/workbook/worksheet/tc_pane.rb +94 -0
  174. data/test/workbook/worksheet/tc_print_options.rb +72 -0
  175. data/test/workbook/worksheet/tc_protected_range.rb +17 -0
  176. data/test/workbook/worksheet/tc_row.rb +32 -14
  177. data/test/workbook/worksheet/tc_selection.rb +94 -0
  178. data/test/workbook/worksheet/tc_sheet_calc_pr.rb +18 -0
  179. data/test/workbook/worksheet/tc_sheet_pr.rb +27 -0
  180. data/test/workbook/worksheet/tc_sheet_protection.rb +117 -0
  181. data/test/workbook/worksheet/tc_sheet_view.rb +214 -0
  182. data/test/workbook/worksheet/{table/tc_table.rb → tc_table.rb} +9 -12
  183. data/test/workbook/worksheet/tc_table_style_info.rb +53 -0
  184. data/test/workbook/worksheet/tc_worksheet.rb +155 -51
  185. data/test/workbook/worksheet/tc_worksheet_hyperlink.rb +64 -0
  186. metadata +194 -81
  187. data/examples/#extractive.csv# +0 -0
  188. data/examples/#extractive.rb# +0 -45
  189. data/examples/chart_colors.rb~ +0 -0
  190. data/examples/chart_colors.xlsx +0 -0
  191. data/examples/colored_series_data.xlsx +0 -0
  192. data/examples/conditional_formatting/getting_barred.xlsx +0 -0
  193. data/examples/example.csv +0 -1000
  194. data/examples/extractive.csv +0 -1
  195. data/examples/extractive.csv~ +0 -1
  196. data/examples/extractive.rb~ +0 -3
  197. data/examples/stack.rb +0 -21
  198. data/examples/stack.rb~ +0 -27
  199. data/examples/stack.xlsx +0 -0
  200. data/examples/~$chart_colors.xlsx +0 -0
  201. data/examples/~$extractive.xlsx +0 -0
  202. data/lib/axlsx/drawing/ax_data_source.rb~ +0 -55
  203. data/lib/axlsx/drawing/data_source.rb~ +0 -51
  204. data/lib/axlsx/drawing/hlink_click.rb~ +0 -0
  205. data/lib/axlsx/drawing/hyperlink.rb~ +0 -64
  206. data/lib/axlsx/drawing/num_data.rb~ +0 -51
  207. data/lib/axlsx/drawing/num_data_source.rb~ +0 -54
  208. data/lib/axlsx/drawing/num_val.rb~ +0 -40
  209. data/lib/axlsx/drawing/picture_locking.rb~ +0 -36
  210. data/lib/axlsx/drawing/ref.rb~ +0 -41
  211. data/lib/axlsx/drawing/str_data.rb~ +0 -58
  212. data/lib/axlsx/drawing/str_val.rb~ +0 -35
  213. data/lib/axlsx/util/cbf.rb +0 -333
  214. data/lib/axlsx/util/cfb.rb~ +0 -201
  215. data/lib/axlsx/util/font_tables.rb~ +0 -0
  216. data/lib/axlsx/util/ms_off_crypto.rb +0 -189
  217. data/lib/axlsx/util/ms_off_crypto.rb~ +0 -3
  218. data/lib/axlsx/util/ms_offcrypto.rb~ +0 -0
  219. data/lib/axlsx/util/parser.rb~ +0 -6
  220. data/lib/axlsx/util/storage.rb~ +0 -0
  221. data/lib/axlsx/workbook/shared_strings_table.rb~ +0 -69
  222. data/lib/axlsx/workbook/worksheet/cfvo.rb~ +0 -0
  223. data/lib/axlsx/workbook/worksheet/col.rb~ +0 -0
  224. data/lib/axlsx/workbook/worksheet/color_scale.rb~ +0 -46
  225. data/lib/axlsx/workbook/worksheet/data_bar.rb~ +0 -0
  226. data/lib/axlsx/workbook/worksheet/icon_set.rb~ +0 -95
  227. data/lib/axlsx/workbook/worksheet/shared_strings_table.rb~ +0 -0
  228. data/lib/axlsx/workbook/worksheet/table.rb~ +0 -97
  229. data/lib/schema/dc.xsd~ +0 -118
  230. data/lib/schema/dcterms.xsd~ +0 -331
  231. data/lib/schema/opc-coreProperties.xsd~ +0 -50
  232. data/test/drawing/tc_data_source.rb~ +0 -30
  233. data/test/drawing/tc_num_data.rb~ +0 -35
  234. data/test/drawing/tc_num_val.rb~ +0 -29
  235. data/test/drawing/tc_str_data.rb~ +0 -30
  236. data/test/drawing/tc_str_val.rb~ +0 -26
  237. data/test/workbook/worksheet/table/tc_table.rb~ +0 -72
  238. data/test/workbook/worksheet/tc_cfvo.rb~ +0 -20
  239. data/test/workbook/worksheet/tc_col.rb~ +0 -10
  240. data/test/workbook/worksheet/tc_color_scale.rb~ +0 -0
  241. data/test/workbook/worksheet/tc_data_bar.rb~ +0 -0
  242. data/test/workbook/worksheet/tc_icon_set.rb~ +0 -0
@@ -4,9 +4,68 @@ module Axlsx
4
4
  # The Worksheet class represents a worksheet in the workbook.
5
5
  class Worksheet
6
6
 
7
+ # definition of characters which are less than the maximum width of 0-9 in the default font for use in String#count.
8
+ # This is used for autowidth calculations
9
+ # @return [String]
10
+ def self.thin_chars
11
+ @thin_chars ||= "^.acefijklrstxyzFIJL()-"
12
+ end
13
+
14
+ # Creates a new worksheet.
15
+ # @note the recommended way to manage worksheets is Workbook#add_worksheet
16
+ # @see Workbook#add_worksheet
17
+ # @option options [String] name The name of this worksheet.
18
+ # @option options [Hash] page_margins A hash containing page margins for this worksheet. @see PageMargins
19
+ # @option options [Hash] print_options A hash containing print options for this worksheet. @see PrintOptions
20
+ # @option options [Boolean] show_gridlines indicates if gridlines should be shown for this sheet.
21
+ def initialize(wb, options={})
22
+ self.workbook = wb
23
+ @workbook.worksheets << self
24
+ @sheet_protection = nil
25
+
26
+ initialize_page_options(options)
27
+ options.each do |o|
28
+ self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
29
+ end
30
+ end
31
+
32
+ # Initalizes page margin, setup and print options
33
+ # @param [Hash] options Options passed in from the initializer
34
+ def initialize_page_options(options)
35
+ @page_margins = PageMargins.new options[:page_margins] if options[:page_margins]
36
+ @page_setup = PageSetup.new options[:page_setup] if options[:page_setup]
37
+ @print_options = PrintOptions.new options[:print_options] if options[:print_options]
38
+ end
39
+
7
40
  # The name of the worksheet
8
41
  # @return [String]
9
- attr_reader :name
42
+ def name
43
+ @name ||= "Sheet" + (index+1).to_s
44
+ end
45
+
46
+ # The sheet calculation properties
47
+ # @return [SheetCalcPr]
48
+ def sheet_calc_pr
49
+ @sheet_calc_pr ||= SheetCalcPr.new
50
+ end
51
+
52
+ # The sheet protection object for this workbook
53
+ # @return [SheetProtection]
54
+ # @see SheetProtection
55
+ def sheet_protection
56
+ @sheet_protection ||= SheetProtection.new
57
+ yield @sheet_protection if block_given?
58
+ @sheet_protection
59
+ end
60
+
61
+ # The sheet view object for this worksheet
62
+ # @return [SheetView]
63
+ # @see [SheetView]
64
+ def sheet_view
65
+ @sheet_view ||= SheetView.new
66
+ yield @sheet_view if block_given?
67
+ @sheet_view
68
+ end
10
69
 
11
70
  # The workbook that owns this worksheet
12
71
  # @return [Workbook]
@@ -14,49 +73,59 @@ module Axlsx
14
73
 
15
74
  # The tables in this worksheet
16
75
  # @return [Array] of Table
17
- attr_reader :tables
76
+ def tables
77
+ @tables ||= Tables.new self
78
+ end
79
+
80
+ # A typed collection of hyperlinks associated with this worksheet
81
+ # @return [WorksheetHyperlinks]
82
+ def hyperlinks
83
+ @hyperlinks ||= WorksheetHyperlinks.new self
84
+ end
85
+
86
+ # The a shortcut to the worksheet_comments list of comments
87
+ # @return [Array|SimpleTypedList]
88
+ def comments
89
+ worksheet_comments.comments if worksheet_comments.has_comments?
90
+ end
18
91
 
19
92
  # The rows in this worksheet
20
93
  # @note The recommended way to manage rows is Worksheet#add_row
21
94
  # @return [SimpleTypedList]
22
95
  # @see Worksheet#add_row
23
- attr_reader :rows
24
-
25
- # An array of content based calculated column widths.
26
- # @note a single auto fit data item is a hash with :longest => [String] and :sz=> [Integer] members.
27
- # @return [Array] of Hash
28
- attr_reader :auto_fit_data
96
+ def rows
97
+ @rows ||= SimpleTypedList.new Row
98
+ end
29
99
 
30
- # An array of merged cell ranges e.d "A1:B3"
31
- # Content and formatting is read from the first cell.
32
- # @return Array
33
- attr_reader :merged_cells
100
+ # returns the sheet data as columnw
101
+ def cols
102
+ @rows.transpose
103
+ end
34
104
 
35
105
  # An range that excel will apply an autfilter to "A1:B3"
36
106
  # This will turn filtering on for the cells in the range.
37
107
  # The first row is considered the header, while subsequent rows are considerd to be data.
38
- # @return Array
39
- attr_reader :auto_filter
40
-
41
- # Indicates if the worksheet should show gridlines or not
42
- # @return Boolean
43
- attr_reader :show_gridlines
44
-
45
-
46
- # Indicates if the worksheet is selected in the workbook
47
- # It is possible to have more than one worksheet selected, however it might cause issues
48
- # in some older versions of excel when using copy and paste.
49
- # @return Boolean
50
- attr_reader :selected
108
+ # @return String
109
+ def auto_filter
110
+ @auto_filter ||= AutoFilter.new self
111
+ end
51
112
 
52
- # Indicates if the worksheet should print in a single page
113
+ # Indicates if the worksheet will be fit by witdh or height to a specific number of pages.
114
+ # To alter the width or height for page fitting, please use page_setup.fit_to_widht or page_setup.fit_to_height.
115
+ # If you want the worksheet to fit on more pages (e.g. 2x2), set {PageSetup#fit_to_width} and {PageSetup#fit_to_height} accordingly.
53
116
  # @return Boolean
54
- attr_reader :fit_to_page
117
+ # @see #page_setup
118
+ def fit_to_page?
119
+ return false unless self.instance_values.keys.include?('page_setup')
120
+ page_setup.fit_to_page?
121
+ end
55
122
 
56
123
 
57
124
  # Column info for the sheet
58
125
  # @return [SimpleTypedList]
59
- attr_reader :column_info
126
+ def column_info
127
+ @column_info ||= Cols.new self
128
+ end
60
129
 
61
130
  # Page margins for printing the worksheet.
62
131
  # @example
@@ -78,44 +147,51 @@ module Axlsx
78
147
  @page_margins ||= PageMargins.new
79
148
  yield @page_margins if block_given?
80
149
  @page_margins
81
-
82
150
  end
83
151
 
84
- # definition of characters which are less than the maximum width of 0-9 in the default font for use in String#count.
85
- # This is used for autowidth calculations
86
- # @return [String]
87
- def self.thin_chars
88
- @thin_chars ||= "^.acefijklrstxyzFIJL()-"
152
+ # Page setup settings for printing the worksheet.
153
+ # @example
154
+ # wb = Axlsx::Package.new.workbook
155
+ #
156
+ # # using options when creating the worksheet.
157
+ # ws = wb.add_worksheet :page_setup => {:fit_to_width => 2, :orientation => :landscape}
158
+ #
159
+ # # use the set method of the page_setup object
160
+ # ws.page_setup.set(:paper_width => "297mm", :paper_height => "210mm")
161
+ #
162
+ # # setup page in a block
163
+ # ws.page_setup do |page|
164
+ # page.scale = 80
165
+ # page.orientation = :portrait
166
+ # end
167
+ # @see PageSetup#initialize
168
+ # @return [PageSetup]
169
+ def page_setup
170
+ @page_setup ||= PageSetup.new
171
+ yield @page_setup if block_given?
172
+ @page_setup
89
173
  end
90
174
 
91
- # Creates a new worksheet.
92
- # @note the recommended way to manage worksheets is Workbook#add_worksheet
93
- # @see Workbook#add_worksheet
94
- # @option options [String] name The name of this worksheet.
95
- # @option options [Hash] page_margins A hash containing page margins for this worksheet. @see PageMargins
96
- # @option options [Boolean] show_gridlines indicates if gridlines should be shown for this sheet.
97
- def initialize(wb, options={})
98
- self.workbook = wb
99
- @workbook.worksheets << self
100
-
101
- @drawing = @page_margins = @auto_filter = nil
102
- @merged_cells = []
103
- @auto_fit_data = []
104
- @conditional_formattings = []
105
-
106
- @selected = false
107
- @show_gridlines = true
108
- self.name = "Sheet" + (index+1).to_s
109
- @page_margins = PageMargins.new options[:page_margins] if options[:page_margins]
110
-
111
- @rows = SimpleTypedList.new Row
112
- @column_info = SimpleTypedList.new Col
113
- # @cols = SimpleTypedList.new Cell
114
- @tables = SimpleTypedList.new Table
115
-
116
- options.each do |o|
117
- self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
118
- end
175
+ # Options for printing the worksheet.
176
+ # @example
177
+ # wb = Axlsx::Package.new.workbook
178
+ # # using options when creating the worksheet.
179
+ # ws = wb.add_worksheet :print_options => {:grid_lines => true, :horizontal_centered => true}
180
+ #
181
+ # # use the set method of the page_margins object
182
+ # ws.print_options.set(:headings => true)
183
+ #
184
+ # # set page margins in a block
185
+ # ws.print_options do |options|
186
+ # options.horizontal_centered = true
187
+ # options.vertical_centered = true
188
+ # end
189
+ # @see PrintOptions#initialize
190
+ # @return [PrintOptions]
191
+ def print_options
192
+ @print_options ||= PrintOptions.new
193
+ yield @print_options if block_given?
194
+ @print_options
119
195
  end
120
196
 
121
197
  # convinience method to access all cells in this worksheet
@@ -124,22 +200,6 @@ module Axlsx
124
200
  rows.flatten
125
201
  end
126
202
 
127
- # Add conditional formatting to this worksheet.
128
- #
129
- # @param [String] cells The range to apply the formatting to
130
- # @param [Array|Hash] rules An array of hashes (or just one) to create Conditional formatting rules from.
131
- # @example This would format column A whenever it is FALSE.
132
- # # for a longer example, see examples/example_conditional_formatting.rb (link below)
133
- # worksheet.add_conditional_formatting( "A1:A1048576", { :type => :cellIs, :operator => :equal, :formula => "FALSE", :dxfId => 1, :priority => 1 }
134
- #
135
- # @see ConditionalFormattingRule#initialize
136
- # @see file:examples/example_conditional_formatting.rb
137
- def add_conditional_formatting(cells, rules)
138
- cf = ConditionalFormatting.new( :sqref => cells )
139
- cf.add_rules rules
140
- @conditional_formattings << cf
141
- end
142
-
143
203
  # Creates merge information for this worksheet.
144
204
  # Cells can be merged by calling the merge_cells method on a worksheet.
145
205
  # @example This would merge the three cells C1..E1 #
@@ -148,75 +208,83 @@ module Axlsx
148
208
  # worksheet.merge_cells worksheet.rows.first.cells[(2..4)]
149
209
  # #alternatively you can do it from a single cell
150
210
  # worksheet["C1"].merge worksheet["E1"]
151
- # @param [Array, string]
211
+ # @param [Array, string] cells
152
212
  def merge_cells(cells)
153
- @merged_cells << if cells.is_a?(String)
154
- cells
155
- elsif cells.is_a?(Array)
156
- cells = cells.sort { |x, y| x.r <=> y.r }
157
- "#{cells.first.r}:#{cells.last.r}"
158
- end
213
+ merged_cells.add cells
159
214
  end
160
215
 
216
+ # Adds a new protected cell range to the worksheet. Note that protected ranges are only in effect when sheet protection is enabled.
217
+ # @param [String|Array] cells The string reference for the cells to protect or an array of cells.
218
+ # @return [ProtectedRange]
219
+ # @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.
220
+ def protect_range(cells)
221
+ protected_ranges.add_range(cells)
222
+ end
161
223
 
162
- # The demensions of a worksheet. This is not actually a required element by the spec,
224
+ # The dimensions of a worksheet. This is not actually a required element by the spec,
163
225
  # but at least a few other document readers expect this for conversion
164
- # @return [String] the A1:B2 style reference for the first and last row column intersection in the workbook
226
+ # @return [Dimension]
165
227
  def dimension
166
- dim_start = rows.first.cells.first == nil ? 'A1' : rows.first.cells.first.r
167
- dim_end = rows.last.cells.last == nil ? 'AA:200' : rows.last.cells.last.r
168
- "#{dim_start}:#{dim_end}"
228
+ @dimension ||= Dimension.new self
229
+ end
230
+
231
+ # The sheet properties for this workbook.
232
+ # Currently only pageSetUpPr -> fitToPage is implemented
233
+ # @return [SheetPr]
234
+ def sheet_pr
235
+ @sheet_pr ||= SheetPr.new self
169
236
  end
170
237
 
171
238
  # Indicates if gridlines should be shown in the sheet.
172
239
  # This is true by default.
173
240
  # @return [Boolean]
241
+ # @deprecated Use {SheetView#show_grid_lines=} instead.
174
242
  def show_gridlines=(v)
243
+ warn('axlsx::DEPRECIATED: Worksheet#show_gridlines= has been depreciated. This value can be set over SheetView#show_grid_lines=.')
175
244
  Axlsx::validate_boolean v
176
- @show_gridlines = v
245
+ sheet_view.show_grid_lines = v
177
246
  end
178
247
 
179
248
  # @see selected
180
249
  # @return [Boolean]
250
+ # @deprecated Use {SheetView#tab_selected=} instead.
181
251
  def selected=(v)
252
+ warn('axlsx::DEPRECIATED: Worksheet#selected= has been depreciated. This value can be set over SheetView#tab_selected=.')
182
253
  Axlsx::validate_boolean v
183
- @selected = v
254
+ sheet_view.tab_selected = v
184
255
  end
185
256
 
186
-
187
- # Indicates if the worksheet should print in a single page.
188
- # This is true by default.
189
- # @return [Boolean]
190
- def fit_to_page=(v)
191
- Axlsx::validate_boolean v
192
- @fit_to_page = v
257
+ # Indicates if the worksheet should show gridlines or not
258
+ # @return Boolean
259
+ # @deprecated Use {SheetView#show_grid_lines} instead.
260
+ def show_gridlines
261
+ warn('axlsx::DEPRECIATED: Worksheet#show_gridlines has been depreciated. This value can get over SheetView#show_grid_lines.')
262
+ sheet_view.show_grid_lines
193
263
  end
194
264
 
265
+ # Indicates if the worksheet is selected in the workbook
266
+ # It is possible to have more than one worksheet selected, however it might cause issues
267
+ # in some older versions of excel when using copy and paste.
268
+ # @return Boolean
269
+ # @deprecated Use {SheetView#tab_selected} instead.
270
+ def selected
271
+ warn('axlsx::DEPRECIATED: Worksheet#selected has been depreciated. This value can get over SheetView#tab_selected.')
272
+ sheet_view.tab_selected
273
+ end
195
274
 
196
- # returns the column and row index for a named based cell
197
- # @param [String] name The cell or cell range to return. "A1" will return the first cell of the first row.
198
- # @return [Cell]
199
- def name_to_cell(name)
200
- col_index, row_index = *Axlsx::name_to_indices(name)
201
- r = rows[row_index]
202
- r.cells[col_index] if r
275
+ # (see #fit_to_page)
276
+ # @return [Boolean]
277
+ def fit_to_page=(v)
278
+ warn('axlsx::DEPRECIATED: Worksheet#fit_to_page has been depreciated. This value will automatically be set for you when you use PageSetup#fit_to.')
279
+ fit_to_page?
203
280
  end
204
281
 
205
282
  # The name of the worksheet
206
283
  # The name of a worksheet must be unique in the workbook, and must not exceed 31 characters
207
- # @param [String] v
208
- def name=(v)
209
- DataTypeValidator.validate "Worksheet.name", String, v
210
- raise ArgumentError, (ERR_SHEET_NAME_TOO_LONG % v) if v.size > 31
211
- sheet_names = @workbook.worksheets.map { |s| s.name }
212
- raise ArgumentError, (ERR_DUPLICATE_SHEET_NAME % v) if sheet_names.include?(v)
213
- @name=v
214
- end
215
-
216
- # The absolute auto filter range
217
- # @see auto_filter
218
- def abs_auto_filter
219
- Axlsx.cell_range(@auto_filter.split(':').collect { |name| name_to_cell(name)}) if @auto_filter
284
+ # @param [String] name
285
+ def name=(name)
286
+ validate_sheet_name name
287
+ @name=Axlsx::coder.encode(name)
220
288
  end
221
289
 
222
290
  # The auto filter range for the worksheet
@@ -224,7 +292,7 @@ module Axlsx
224
292
  # @see auto_filter
225
293
  def auto_filter=(v)
226
294
  DataTypeValidator.validate "Worksheet.auto_filter", String, v
227
- @auto_filter = v
295
+ auto_filter.range = v
228
296
  end
229
297
 
230
298
  # The part name of this worksheet
@@ -256,7 +324,7 @@ module Axlsx
256
324
  # @return [Drawing]
257
325
  # @see Worksheet#add_chart
258
326
  def drawing
259
- @drawing || @drawing = Axlsx::Drawing.new(self)
327
+ worksheet_drawing.drawing
260
328
  end
261
329
 
262
330
  # Adds a row to the worksheet and updates auto fit data.
@@ -300,71 +368,47 @@ module Axlsx
300
368
  # @option options [Float] height the row's height (in points)
301
369
  def add_row(values=[], options={})
302
370
  Row.new(self, values, options)
303
- update_column_info @rows.last.cells, options.delete(:widths) ||[], options.delete(:style) || []
304
- # update_auto_fit_data @rows.last.cells, options.delete(:widths) || []
371
+ update_column_info @rows.last.cells, options.delete(:widths) || []
305
372
  yield @rows.last if block_given?
306
373
  @rows.last
307
374
  end
308
375
 
309
376
  alias :<< :add_row
310
377
 
311
- # Set the style for cells in a specific row
312
- # @param [Integer] index or range of indexes in the table
313
- # @param [Integer] the cellXfs index
314
- # @option options [Integer] col_offset only cells after this column will be updated.
315
- # @note You can also specify the style in the add_row call
316
- # @see Worksheet#add_row
317
- # @see README.md for an example
318
- def row_style(index, style, options={})
319
- offset = options.delete(:col_offset) || 0
320
- rs = @rows[index]
321
- if rs.is_a?(Array)
322
- rs.each { |r| r.cells[(offset..-1)].each { |c| c.style = style } }
323
- else
324
- rs.cells[(offset..-1)].each { |c| c.style = style }
325
- end
326
- end
327
-
328
- # returns the sheet data as columnw
329
- def cols
330
- @rows.transpose
378
+ # Add conditional formatting to this worksheet.
379
+ #
380
+ # @param [String] cells The range to apply the formatting to
381
+ # @param [Array|Hash] rules An array of hashes (or just one) to create Conditional formatting rules from.
382
+ # @example This would format column A whenever it is FALSE.
383
+ # # for a longer example, see examples/example_conditional_formatting.rb (link below)
384
+ # worksheet.add_conditional_formatting( "A1:A1048576", { :type => :cellIs, :operator => :equal, :formula => "FALSE", :dxfId => 1, :priority => 1 }
385
+ #
386
+ # @see ConditionalFormattingRule#initialize
387
+ # @see file:examples/example_conditional_formatting.rb
388
+ def add_conditional_formatting(cells, rules)
389
+ cf = ConditionalFormatting.new( :sqref => cells )
390
+ cf.add_rules rules
391
+ conditional_formattings << cf
392
+ conditional_formattings
331
393
  end
332
394
 
333
-
334
- # Set the style for cells in a specific column
335
- # @param [Integer] index the index of the column
336
- # @param [Integer] the cellXfs index
337
- # @option options [Integer] row_offset only cells after this column will be updated.
338
- # @note You can also specify the style for specific columns in the call to add_row by using an array for the :styles option
339
- # @see Worksheet#add_row
340
- # @see README.md for an example
341
- def col_style(index, style, options={})
342
- offset = options.delete(:row_offset) || 0
343
- @rows[(offset..-1)].each do |r|
344
- cells = r.cells[index]
345
- next unless cells
346
- if cells.is_a?(Array)
347
- cells.each { |c| c.style = style }
348
- else
349
- cells.style = style
350
- end
351
- end
395
+ # Add data validation to this worksheet.
396
+ #
397
+ # @param [String] cells The cells the validation will apply to.
398
+ # @param [hash] data_validation options defining the validation to apply.
399
+ # @see examples/data_validation.rb for an example
400
+ def add_data_validation(cells, data_validation)
401
+ dv = DataValidation.new(data_validation)
402
+ dv.sqref = cells
403
+ data_validations << dv
352
404
  end
353
405
 
354
- # This is a helper method that Lets you specify a fixed width for multiple columns in a worksheet in one go.
355
- # Axlsx is sparse, so if you have not set data for a column, you cannot set the width.
356
- # Setting a fixed column width to nil will revert the behaviour back to calculating the width for you.
357
- # @example This would set the first and third column widhts but leave the second column in autofit state.
358
- # ws.column_widths 7.2, nil, 3
359
- # @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
360
- # @param [Integer|Float|Fixnum|nil] values
361
- def column_widths(*args)
362
- args.each_with_index do |value, index|
363
- next if value == nil
364
- Axlsx::validate_unsigned_numeric(value) unless value == nil
365
- @column_info[index] ||= Col.new index+1, index+1
366
- @column_info[index].width = value
367
- end
406
+ # Adds a new hyperlink to the worksheet
407
+ # @param [Hash] options for the hyperlink
408
+ # @see WorksheetHyperlink for a list of options
409
+ # @return [WorksheetHyperlink]
410
+ def add_hyperlink(options={})
411
+ hyperlinks.add(options)
368
412
  end
369
413
 
370
414
  # 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.
@@ -381,68 +425,113 @@ module Axlsx
381
425
  # @see Line3DChart
382
426
  # @see README for examples
383
427
  def add_chart(chart_type, options={})
384
- chart = drawing.add_chart(chart_type, options)
428
+ chart = worksheet_drawing.add_chart(chart_type, options)
385
429
  yield chart if block_given?
386
430
  chart
387
431
  end
388
432
 
389
433
  # needs documentation
390
434
  def add_table(ref, options={})
391
- table = Table.new(ref, self, options)
392
- @tables << table
393
- yield table if block_given?
394
- table
435
+ tables << Table.new(ref, self, options)
436
+ yield tables.last if block_given?
437
+ tables.last
438
+ end
439
+
440
+ # Shortcut to worsksheet_comments#add_comment
441
+ def add_comment(options={})
442
+ worksheet_comments.add_comment(options)
395
443
  end
396
444
 
397
445
  # Adds a media item to the worksheets drawing
398
- # @param [Class] media_type
399
- # @option options [] unknown
446
+ # @option [Hash] options options passed to drawing.add_image
400
447
  def add_image(options={})
401
- image = drawing.add_image(options)
448
+ image = worksheet_drawing.add_image(options)
402
449
  yield image if block_given?
403
450
  image
404
451
  end
405
452
 
406
- # Serializes the object
407
- # @param [String] str
453
+ # This is a helper method that Lets you specify a fixed width for multiple columns in a worksheet in one go.
454
+ # Axlsx is sparse, so if you have not set data for a column, you cannot set the width.
455
+ # 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.
456
+ # @example This would set the first and third column widhts but leave the second column in autofit state.
457
+ # ws.column_widths 7.2, nil, 3
458
+ # @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
459
+ # @param [Integer|Float|Fixnum|nil] widths
460
+ def column_widths(*widths)
461
+ widths.each_with_index do |value, index|
462
+ next if value == nil
463
+ Axlsx::validate_unsigned_numeric(value) unless value == nil
464
+ find_or_create_column_info(index).width = value
465
+ end
466
+ end
467
+
468
+ # Set the style for cells in a specific column
469
+ # @param [Integer] index the index of the column
470
+ # @param [Integer] style the cellXfs index
471
+ # @param [Hash] options
472
+ # @option [Integer] :row_offset only cells after this column will be updated.
473
+ # @note You can also specify the style for specific columns in the call to add_row by using an array for the :styles option
474
+ # @see Worksheet#add_row
475
+ # @see README.md for an example
476
+ def col_style(index, style, options={})
477
+ offset = options.delete(:row_offset) || 0
478
+ cells = @rows[(offset..-1)].map { |row| row.cells[index] }.flatten.compact
479
+ cells.each { |cell| cell.style = style }
480
+ end
481
+
482
+ # Set the style for cells in a specific row
483
+ # @param [Integer] index or range of indexes in the table
484
+ # @param [Integer] style the cellXfs index
485
+ # @param [Hash] options the options used when applying the style
486
+ # @option [Integer] :col_offset only cells after this column will be updated.
487
+ # @note You can also specify the style in the add_row call
488
+ # @see Worksheet#add_row
489
+ # @see README.md for an example
490
+ def row_style(index, style, options={})
491
+ offset = options.delete(:col_offset) || 0
492
+ cells = cols[(offset..-1)].map { |column| column[index] }.flatten.compact
493
+ cells.each { |cell| cell.style = style }
494
+ end
495
+
496
+ # Serializes the worksheet object to an xml string
497
+ # This intentionally does not use nokogiri for performance reasons
408
498
  # @return [String]
409
499
  def to_xml_string
500
+ auto_filter.apply if auto_filter.range
410
501
  str = '<?xml version="1.0" encoding="UTF-8"?>'
411
- str.concat "<worksheet xmlns=\"%s\" xmlns:r=\"%s\">" % [XML_NS, XML_NS_R]
412
- str.concat "<sheetPr><pageSetUpPr fitToPage=\"%s\"></pageSetUpPr></sheetPr>" % fit_to_page if fit_to_page
413
- str.concat "<dimension ref=\"%s\"></dimension>" % dimension unless rows.size == 0
414
- str.concat "<sheetViews><sheetView tabSelected='%s' workbookViewId='0' showGridLines='%s'><selection activeCell=\"A1\" sqref=\"A1\"/></sheetView></sheetViews>" % [@selected, show_gridlines]
415
-
416
- if @column_info.size > 0
417
- str << "<cols>"
418
- @column_info.each { |col| col.to_xml_string(str) }
419
- str.concat '</cols>'
502
+ str << worksheet_node
503
+ serializable_parts.each do |item|
504
+ item.to_xml_string(str) if item
420
505
  end
421
- str.concat '<sheetData>'
422
- @rows.each_with_index { |row, index| row.to_xml_string(index, str) }
423
- str.concat '</sheetData>'
424
- str.concat "<autoFilter ref='%s'></autoFilter>" % @auto_filter if @auto_filter
425
- str.concat "<mergeCells count='%s'>%s</mergeCells>" % [@merged_cells.size, @merged_cells.reduce('') { |memo, obj| memo += "<mergeCell ref='%s'></mergeCell>" % obj } ] unless @merged_cells.empty?
426
- page_margins.to_xml_string(str) if @page_margins
427
- str.concat "<drawing r:id='rId1'></drawing>" if @drawing
428
- unless @tables.empty?
429
- str.concat "<tableParts count='%s'>%s</tableParts>" % [@tables.size, @tables.reduce('') { |memo, obj| memo += "<tablePart r:id='%s'/>" % obj.rId }]
430
- end
431
- @conditional_formattings.each do |cf|
432
- str.concat cf.to_xml_string
433
- end
434
- str + '</worksheet>'
506
+ str << '</worksheet>'
507
+ sanitize(str)
435
508
  end
436
509
 
510
+ # returns the provided string with all invalid control charaters
511
+ # removed.
512
+ # @param [String] str The sting to process
513
+ # @return [String]
514
+ def sanitize(str)
515
+ str.gsub(CONTROL_CHAR_REGEX, '')
516
+ end
517
+
437
518
  # The worksheet relationships. This is managed automatically by the worksheet
438
519
  # @return [Relationships]
439
520
  def relationships
440
- r = Relationships.new
441
- @tables.each do |table|
442
- r << Relationship.new(TABLE_R, "../#{table.pn}")
443
- end
444
- r << Relationship.new(DRAWING_R, "../#{@drawing.pn}") if @drawing
445
- r
521
+ r = Relationships.new
522
+ r + [tables.relationships,
523
+ worksheet_comments.relationships,
524
+ hyperlinks.relationships,
525
+ worksheet_drawing.relationship].flatten.compact || []
526
+ r
527
+ end
528
+
529
+ # identifies the index of an object withing the collections used in generating relationships for the worksheet
530
+ # @param [Any] object the object to search for
531
+ # @return [Integer] The index of the object
532
+ def relationships_index_of(object)
533
+ objects = [tables.to_a, worksheet_comments.comments.to_a, hyperlinks.to_a, worksheet_drawing.drawing].flatten.compact || []
534
+ objects.index(object)
446
535
  end
447
536
 
448
537
  # Returns the cell or cells defined using excel style A1:B3 references.
@@ -450,59 +539,130 @@ module Axlsx
450
539
  # @return [Cell, Array]
451
540
  def [] (cell_def)
452
541
  return rows[cell_def] if cell_def.is_a?(Integer)
453
-
454
- parts = cell_def.split(':')
455
- first = name_to_cell parts[0]
542
+ parts = cell_def.split(':').map{ |part| name_to_cell part }
456
543
  if parts.size == 1
457
- first
544
+ parts.first
458
545
  else
459
- cells = []
460
- last = name_to_cell(parts[1])
461
- rows[(first.row.index..last.row.index)].each do |r|
462
- r.cells[(first.index..last.index)].each do |c|
463
- cells << c
464
- end
465
- end
466
- cells
546
+ range(*parts)
467
547
  end
468
548
  end
469
549
 
470
- private
550
+ # returns the column and row index for a named based cell
551
+ # @param [String] name The cell or cell range to return. "A1" will return the first cell of the first row.
552
+ # @return [Cell]
553
+ def name_to_cell(name)
554
+ col_index, row_index = *Axlsx::name_to_indices(name)
555
+ r = rows[row_index]
556
+ r.cells[col_index] if r
557
+ end
471
558
 
472
- # assigns the owner workbook for this worksheet
473
- def workbook=(v) DataTypeValidator.validate "Worksheet.workbook", Workbook, v; @workbook = v; end
559
+ # shortcut method to access styles direclty from the worksheet
560
+ # This lets us do stuff like:
561
+ # @example
562
+ # p = Axlsx::Package.new
563
+ # p.workbook.add_worksheet(:name => 'foo') do |sheet|
564
+ # my_style = sheet.styles.add_style { :bg_color => "FF0000" }
565
+ # sheet.add_row ['Oh No!'], :styles => my_style
566
+ # end
567
+ # p.serialize 'foo.xlsx'
568
+ def styles
569
+ @styles ||= self.workbook.styles
570
+ end
474
571
 
475
572
 
476
- # TODO this needs cleanup!
477
- def update_column_info(cells, widths=[], style=[])
478
- styles = self.workbook.styles
479
- cellXfs, fonts = styles.cellXfs, styles.fonts
480
- sz = 11
573
+ private
574
+
575
+ def validate_sheet_name(name)
576
+ DataTypeValidator.validate "Worksheet.name", String, name
577
+ raise ArgumentError, (ERR_SHEET_NAME_TOO_LONG % name) if name.size > 31
578
+ raise ArgumentError, (ERR_SHEET_NAME_COLON_FORBIDDEN % name) if name.include? ':'
579
+ name = Axlsx::coder.encode(name)
580
+ sheet_names = @workbook.worksheets.map { |s| s.name }
581
+ raise ArgumentError, (ERR_DUPLICATE_SHEET_NAME % name) if sheet_names.include?(name)
582
+ end
481
583
 
482
- cells.each_with_index do |cell, index|
483
- @column_info[index] ||= Col.new index+1, index+1
484
- col = @column_info[index]
485
- width = widths[index]
486
- col.width = width if [Integer, Float, Fixnum].include?(width.class)
487
- c_style = style[index] if [Integer, Fixnum].include?(style[index].class)
488
- next if width == :ignore || (cell.value.is_a?(String) && cell.value.start_with?('=') || cell.value == nil)
489
- if self.workbook.use_autowidth
490
- cell_xf = cellXfs[(c_style || 0)]
491
- font = fonts[(cell_xf.fontId || 0)]
492
- sz = cell.sz || font.sz || sz
493
- col.width = [(col.width || 0), calculate_width(cell.value.to_s, sz)].max
584
+
585
+ def serializable_parts
586
+ [sheet_pr, dimension, sheet_view, column_info,
587
+ sheet_data, sheet_calc_pr, @sheet_protection, protected_ranges,
588
+ auto_filter, merged_cells, conditional_formattings,
589
+ data_validations, hyperlinks, print_options, page_margins,
590
+ page_setup, worksheet_drawing, worksheet_comments,
591
+ tables]
592
+ end
593
+
594
+ def range(*cell_def)
595
+ first, last = cell_def
596
+ cells = []
597
+ rows[(first.row.index..last.row.index)].each do |r|
598
+ r.cells[(first.index..last.index)].each do |c|
599
+ cells << c
494
600
  end
495
601
  end
602
+ cells
496
603
  end
497
604
 
605
+ # A collection of protected ranges in the worksheet
606
+ # @note The recommended way to manage protected ranges is with Worksheet#protect_range
607
+ # @see Worksheet#protect_range
608
+ # @return [SimpleTypedList] The protected ranges for this worksheet
609
+ def protected_ranges
610
+ @protected_ranges ||= ProtectedRanges.new self
611
+ # SimpleTypedList.new ProtectedRange
612
+ end
498
613
 
499
- # This is still not perfect...
500
- # - scaling is not linear as font sizes increst
501
- # - different fonts have different mdw and char widths
502
- def calculate_width(text, sz)
503
- mdw = 1.78 #This is the widest width of 0..9 in arial@10px)
504
- font_scale = (sz/10.0).to_f
505
- ((text.count(Worksheet.thin_chars) * mdw + 5) / mdw * 256) / 256.0 * font_scale
614
+ # conditional formattings
615
+ # @return [Array]
616
+ def conditional_formattings
617
+ @conditional_formattings ||= ConditionalFormattings.new self
618
+ end
619
+
620
+ # data validations array
621
+ # @return [Array]
622
+ def data_validations
623
+ @data_validations ||= DataValidations.new self
624
+ end
625
+
626
+ # merged cells array
627
+ # @return [Array]
628
+ def merged_cells
629
+ @merged_cells ||= MergedCells.new self
630
+ end
631
+
632
+
633
+ # Helper method for parsingout the root node for worksheet
634
+ # @return [String]
635
+ def worksheet_node
636
+ "<worksheet xmlns=\"%s\" xmlns:r=\"%s\">" % [XML_NS, XML_NS_R]
506
637
  end
638
+
639
+ def sheet_data
640
+ @sheet_data ||= SheetData.new self
641
+ end
642
+
643
+ def worksheet_drawing
644
+ @worksheet_drawing ||= WorksheetDrawing.new self
645
+ end
646
+
647
+ # The comments associated with this worksheet
648
+ # @return [SimpleTypedList]
649
+ def worksheet_comments
650
+ @worksheet_comments ||= WorksheetComments.new self
651
+ end
652
+
653
+ def workbook=(v) DataTypeValidator.validate "Worksheet.workbook", Workbook, v; @workbook = v; end
654
+
655
+ def update_column_info(cells, widths=[])
656
+ cells.each_with_index do |cell, index|
657
+ col = find_or_create_column_info(index)
658
+ next if widths[index] == :ignore
659
+ col.update_width(cell, widths[index], workbook.use_autowidth)
660
+ end
661
+ end
662
+
663
+ def find_or_create_column_info(index)
664
+ column_info[index] ||= Col.new(index + 1, index + 1)
665
+ end
666
+
507
667
  end
508
668
  end