axlsx 1.1.5 → 1.1.6
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.
- data/README.md +26 -7
- data/Rakefile +2 -1
- data/examples/chart_colors.xlsx +0 -0
- data/examples/data_validation.rb +50 -0
- data/examples/example.xlsx +0 -0
- data/examples/example_streamed.xlsx +0 -0
- data/examples/examples_saved.xlsx +0 -0
- data/examples/fish.xlsx +0 -0
- data/examples/no-use_autowidth.xlsx +0 -0
- data/examples/pareto.rb +28 -0
- data/examples/pareto.xlsx +0 -0
- data/examples/pie_chart.rb +16 -0
- data/examples/pie_chart.xlsx +0 -0
- data/examples/pie_chart_saved.xlsx +0 -0
- data/examples/shared_strings_example.xlsx +0 -0
- data/examples/sheet_protection.rb +10 -0
- data/examples/sheet_protection.xlsx +0 -0
- data/examples/two_cell_anchor_image.rb +11 -0
- data/examples/two_cell_anchor_image.xlsx +0 -0
- data/examples/~$pie_chart_saved.xlsx +0 -0
- data/lib/axlsx.rb +7 -0
- data/lib/axlsx/content_type/default.rb +15 -9
- data/lib/axlsx/content_type/override.rb +10 -6
- data/lib/axlsx/doc_props/app.rb +152 -99
- data/lib/axlsx/drawing/axis.rb +30 -23
- data/lib/axlsx/drawing/bar_series.rb +1 -1
- data/lib/axlsx/drawing/drawing.rb +7 -2
- data/lib/axlsx/drawing/pic.rb +44 -4
- data/lib/axlsx/drawing/two_cell_anchor.rb +6 -1
- data/lib/axlsx/drawing/vml_shape.rb +2 -5
- data/lib/axlsx/rels/relationships.rb +1 -1
- data/lib/axlsx/stylesheet/table_style.rb +3 -3
- data/lib/axlsx/util/simple_typed_list.rb +0 -13
- data/lib/axlsx/util/validators.rb +21 -0
- data/lib/axlsx/version.rb +1 -1
- data/lib/axlsx/workbook/workbook.rb +2 -0
- data/lib/axlsx/workbook/worksheet/cell.rb +3 -4
- data/lib/axlsx/workbook/worksheet/comment.rb +3 -9
- data/lib/axlsx/workbook/worksheet/data_validation.rb +245 -0
- data/lib/axlsx/workbook/worksheet/page_setup.rb +17 -3
- data/lib/axlsx/workbook/worksheet/row.rb +34 -18
- data/lib/axlsx/workbook/worksheet/sheet_protection.rb +224 -0
- data/lib/axlsx/workbook/worksheet/table.rb +2 -2
- data/lib/axlsx/workbook/worksheet/worksheet.rb +57 -22
- data/test/doc_props/tc_app.rb +31 -1
- data/test/drawing/tc_axis.rb +12 -2
- data/test/drawing/tc_chart.rb +21 -3
- data/test/drawing/tc_drawing.rb +6 -1
- data/test/drawing/tc_hyperlink.rb +0 -5
- data/test/drawing/tc_pic.rb +22 -2
- data/test/drawing/tc_scatter_chart.rb +6 -1
- data/test/drawing/tc_two_cell_anchor.rb +1 -2
- data/test/stylesheet/tc_styles.rb +3 -4
- data/test/stylesheet/tc_table_style.rb +8 -0
- data/test/stylesheet/tc_table_style_element.rb +10 -1
- data/test/tc_package.rb +43 -15
- data/test/util/tc_simple_typed_list.rb +13 -0
- data/test/util/tc_validators.rb +7 -7
- data/test/workbook/worksheet/table/tc_table.rb +3 -3
- data/test/workbook/worksheet/tc_cell.rb +15 -6
- data/test/workbook/worksheet/tc_col.rb +9 -0
- data/test/workbook/worksheet/tc_comment.rb +8 -7
- data/test/workbook/worksheet/tc_comments.rb +8 -1
- data/test/workbook/worksheet/tc_conditional_formatting.rb +44 -0
- data/test/workbook/worksheet/tc_data_bar.rb +1 -1
- data/test/workbook/worksheet/tc_data_validation.rb +265 -0
- data/test/workbook/worksheet/tc_page_setup.rb +22 -4
- data/test/workbook/worksheet/tc_row.rb +14 -2
- data/test/workbook/worksheet/tc_sheet_protection.rb +117 -0
- data/test/workbook/worksheet/tc_worksheet.rb +29 -4
- metadata +31 -10
@@ -22,10 +22,14 @@ module Axlsx
|
|
22
22
|
# * verticalDpi
|
23
23
|
|
24
24
|
# Number of vertical pages to fit on.
|
25
|
-
# @
|
25
|
+
# @note PageSetup#fit_to is the recomended way to manage page fitting as only specifying one of fit_to_width/fit_to_height will result in the counterpart
|
26
|
+
# being set to 1.
|
27
|
+
# @return [Integer]
|
26
28
|
attr_reader :fit_to_height
|
27
29
|
|
28
30
|
# Number of horizontal pages to fit on.
|
31
|
+
# @note PageSetup#fit_to is the recomended way to manage page fitting as only specifying one of width/height will result in the counterpart
|
32
|
+
# being set to 1.
|
29
33
|
# @return [Integer]
|
30
34
|
attr_reader :fit_to_width
|
31
35
|
|
@@ -45,7 +49,6 @@ module Axlsx
|
|
45
49
|
# @return [Integer]
|
46
50
|
attr_reader :scale
|
47
51
|
|
48
|
-
|
49
52
|
# Creates a new PageSetup object
|
50
53
|
# @option options [Integer] fit_to_height Number of vertical pages to fit on
|
51
54
|
# @option options [Integer] fit_to_width Number of horizontal pages to fit on
|
@@ -77,13 +80,24 @@ module Axlsx
|
|
77
80
|
def paper_width=(v); Axlsx::validate_number_with_unit(v); @paper_width = v; end
|
78
81
|
# @see scale
|
79
82
|
def scale=(v); Axlsx::validate_page_scale(v); @scale = v; end
|
83
|
+
|
84
|
+
# convenience method to achieve sanity when setting fit_to_width and fit_to_height
|
85
|
+
# as they both default to 1 if only their counterpart is specified.
|
86
|
+
# @note This method will overwrite any value you explicitly set via the fit_to_height or fit_to_width methods.
|
87
|
+
# @option options [Integer] width The number of pages to fit this worksheet on horizontally. Default 9999
|
88
|
+
# @option options [Integer] height The number of pages to fit this worksheet on vertically. Default 9999
|
89
|
+
def fit_to(options={})
|
90
|
+
self.fit_to_width = options[:width] || 9999
|
91
|
+
self.fit_to_height = options[:height] || 9999
|
92
|
+
[@fit_to_width, @fit_to_height]
|
93
|
+
end
|
80
94
|
|
81
95
|
# Serializes the page settings element.
|
82
96
|
# @param [String] str
|
83
97
|
# @return [String]
|
84
98
|
def to_xml_string(str = '')
|
85
99
|
str << '<pageSetup '
|
86
|
-
str << instance_values.map{ |k,v| k.gsub(/_(.)/){ $1.upcase } << %{="#{v}"} }.join(' ')
|
100
|
+
str << instance_values.reject{ |k, v| k == 'worksheet' }.map{ |k,v| k.gsub(/_(.)/){ $1.upcase } << %{="#{v}"} }.join(' ')
|
87
101
|
str << '/>'
|
88
102
|
end
|
89
103
|
end
|
@@ -5,9 +5,16 @@ module Axlsx
|
|
5
5
|
# @see Worksheet#add_row
|
6
6
|
class Row
|
7
7
|
|
8
|
-
#
|
9
|
-
|
8
|
+
# No support is provided for the following attributes
|
9
|
+
# spans
|
10
|
+
# thickTop
|
11
|
+
# thickBottom
|
10
12
|
|
13
|
+
|
14
|
+
# A list of serilizable attributes.
|
15
|
+
# @note height(ht) and customHeight are manages separately for now. Have a look at Row#height
|
16
|
+
SERIALIZABLE_ATTRIBUTES = [:hidden, :outlineLevel, :collapsed, :s, :customFormat, :ph]
|
17
|
+
|
11
18
|
# The worksheet this row belongs to
|
12
19
|
# @return [Worksheet]
|
13
20
|
attr_reader :worksheet
|
@@ -16,36 +23,40 @@ module Axlsx
|
|
16
23
|
# @return [SimpleTypedList]
|
17
24
|
attr_reader :cells
|
18
25
|
|
19
|
-
#
|
26
|
+
# Row height measured in point size. There is no margin padding on row height.
|
20
27
|
# @return [Float]
|
21
28
|
attr_reader :height
|
22
29
|
|
23
|
-
# Flag indicating if the outlining of
|
30
|
+
# Flag indicating if the outlining of row.
|
24
31
|
# @return [Boolean]
|
25
32
|
attr_reader :collapsed
|
26
33
|
|
27
|
-
# Flag indicating if the
|
34
|
+
# Flag indicating if the the row is hidden.
|
28
35
|
# @return [Boolean]
|
29
36
|
attr_reader :hidden
|
30
37
|
|
31
|
-
#
|
38
|
+
# Outlining level of the row, when outlining is on
|
32
39
|
# @return [Integer]
|
33
40
|
attr_reader :outlineLevel
|
34
41
|
|
35
|
-
#
|
42
|
+
# The style applied ot the row. This affects the entire row.
|
36
43
|
# @return [Integer]
|
37
|
-
attr_reader :
|
38
|
-
|
39
|
-
# TODO 18.3.1.73
|
40
|
-
# customFormat
|
41
|
-
# # hidden
|
42
|
-
# ph
|
43
|
-
# # s (style)
|
44
|
-
# spans
|
45
|
-
# thickTop
|
46
|
-
# thickBottom
|
44
|
+
attr_reader :s
|
47
45
|
|
46
|
+
# indicates that a style has been applied directly to the row via Row#s
|
47
|
+
# @return [Boolean]
|
48
|
+
attr_reader :customFormat
|
48
49
|
|
50
|
+
# indicates if the row should show phonetic
|
51
|
+
# @return [Boolean]
|
52
|
+
attr_reader :ph
|
53
|
+
|
54
|
+
# NOTE removing this from the api as it is actually incorrect.
|
55
|
+
# having a method to style a row's cells is fine, but it is not an attribute on the row.
|
56
|
+
# The proper attribute is ':s'
|
57
|
+
# attr_reader style
|
58
|
+
#
|
59
|
+
|
49
60
|
# Creates a new row. New Cell objects are created based on the values, types and style options.
|
50
61
|
# A new cell is created for each item in the values array. style and types options are applied as follows:
|
51
62
|
# If the types option is defined and is a symbol it is applied to all the cells created.
|
@@ -81,6 +92,12 @@ module Axlsx
|
|
81
92
|
Axlsx.validate_boolean(v)
|
82
93
|
@hidden = v
|
83
94
|
end
|
95
|
+
|
96
|
+
# @see Row#ph
|
97
|
+
def ph=(v) Axlsx.validate_boolean(v); @ph = v end
|
98
|
+
|
99
|
+
# @see Row#s
|
100
|
+
def s=(v) Axlsx.validate_unsigned_numeric(v); @s = v; @customFormat = true end
|
84
101
|
|
85
102
|
# @see Row#outline
|
86
103
|
def outlineLevel=(v)
|
@@ -88,7 +105,6 @@ module Axlsx
|
|
88
105
|
@outlineLevel = v
|
89
106
|
end
|
90
107
|
|
91
|
-
|
92
108
|
# The index of this row in the worksheet
|
93
109
|
# @return [Integer]
|
94
110
|
def index
|
@@ -0,0 +1,224 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module Axlsx
|
3
|
+
|
4
|
+
# The SheetProtection object manages worksheet protection options per sheet.
|
5
|
+
class SheetProtection
|
6
|
+
|
7
|
+
# If 1 or true then AutoFilters should not be allowed to operate when the sheet is protected.
|
8
|
+
# If 0 or false then AutoFilters should be allowed to operate when the sheet is protected.
|
9
|
+
# @return [Boolean]
|
10
|
+
# default true
|
11
|
+
attr_reader :auto_filter
|
12
|
+
|
13
|
+
# If 1 or true then deleting columns should not be allowed when the sheet is protected.
|
14
|
+
# If 0 or false then deleting columns should be allowed when the sheet is protected.
|
15
|
+
# @return [Boolean]
|
16
|
+
# default true
|
17
|
+
attr_reader :delete_columns
|
18
|
+
|
19
|
+
# If 1 or true then deleting rows should not be allowed when the sheet is protected.
|
20
|
+
# If 0 or false then deleting rows should be allowed when the sheet is protected.
|
21
|
+
# @return [Boolean]
|
22
|
+
# default true
|
23
|
+
attr_reader :delete_rows
|
24
|
+
|
25
|
+
# If 1 or true then formatting cells should not be allowed when the sheet is protected.
|
26
|
+
# If 0 or false then formatting cells should be allowed when the sheet is protected.
|
27
|
+
# @return [Boolean]
|
28
|
+
# default true
|
29
|
+
attr_reader :format_cells
|
30
|
+
|
31
|
+
# If 1 or true then formatting columns should not be allowed when the sheet is protected.
|
32
|
+
# If 0 or false then formatting columns should be allowed when the sheet is protected.
|
33
|
+
# @return [Boolean]
|
34
|
+
# default true
|
35
|
+
attr_reader :format_columns
|
36
|
+
|
37
|
+
# If 1 or true then formatting rows should not be allowed when the sheet is protected.
|
38
|
+
# If 0 or false then formatting rows should be allowed when the sheet is protected.
|
39
|
+
# @return [Boolean]
|
40
|
+
# default true
|
41
|
+
attr_reader :format_rows
|
42
|
+
|
43
|
+
# If 1 or true then inserting columns should not be allowed when the sheet is protected.
|
44
|
+
# If 0 or false then inserting columns should be allowed when the sheet is protected.
|
45
|
+
# @return [Boolean]
|
46
|
+
# default true
|
47
|
+
attr_reader :insert_columns
|
48
|
+
|
49
|
+
# If 1 or true then inserting hyperlinks should not be allowed when the sheet is protected.
|
50
|
+
# If 0 or false then inserting hyperlinks should be allowed when the sheet is protected.
|
51
|
+
# @return [Boolean]
|
52
|
+
# default true
|
53
|
+
attr_reader :insert_hyperlinks
|
54
|
+
|
55
|
+
# If 1 or true then inserting rows should not be allowed when the sheet is protected.
|
56
|
+
# If 0 or false then inserting rows should be allowed when the sheet is protected.
|
57
|
+
# @return [Boolean]
|
58
|
+
# default true
|
59
|
+
attr_reader :insert_rows
|
60
|
+
|
61
|
+
# If 1 or true then editing of objects should not be allowed when the sheet is protected.
|
62
|
+
# If 0 or false then objects are allowed to be edited when the sheet is protected.
|
63
|
+
# @return [Boolean]
|
64
|
+
# default false
|
65
|
+
attr_reader :objects
|
66
|
+
|
67
|
+
# If 1 or true then PivotTables should not be allowed to operate when the sheet is protected.
|
68
|
+
# If 0 or false then PivotTables should be allowed to operate when the sheet is protected.
|
69
|
+
# @return [Boolean]
|
70
|
+
# default true
|
71
|
+
attr_reader :pivot_tables
|
72
|
+
|
73
|
+
# Specifies the salt which was prepended to the user-supplied password before it was hashed using the hashing algorithm
|
74
|
+
# @return [String]
|
75
|
+
attr_reader :salt_value
|
76
|
+
|
77
|
+
# If 1 or true then Scenarios should not be edited when the sheet is protected.
|
78
|
+
# If 0 or false then Scenarios are allowed to be edited when the sheet is protected.
|
79
|
+
# @return [Boolean]
|
80
|
+
# default false
|
81
|
+
attr_reader :scenarios
|
82
|
+
|
83
|
+
# If 1 or true then selection of locked cells should not be allowed when the sheet is protected.
|
84
|
+
# If 0 or false then selection of locked cells should be allowed when the sheet is protected.
|
85
|
+
# @return [Boolean]
|
86
|
+
# default false
|
87
|
+
attr_reader :select_locked_cells
|
88
|
+
|
89
|
+
# If 1 or true then selection of unlocked cells should not be allowed when the sheet is protected.
|
90
|
+
# If 0 or false then selection of unlocked cells should be allowed when the sheet is protected.
|
91
|
+
# @return [Boolean]
|
92
|
+
# default false
|
93
|
+
attr_reader :select_unlocked_cells
|
94
|
+
|
95
|
+
# If 1 or true then the sheet is protected.
|
96
|
+
# If 0 or false then the sheet is not protected.
|
97
|
+
# @return [Boolean]
|
98
|
+
# default true
|
99
|
+
attr_reader :sheet
|
100
|
+
|
101
|
+
# If 1 or true then sorting should not be allowed when the sheet is protected.
|
102
|
+
# If 0 or false then sorting should be allowed when the sheet is protected.
|
103
|
+
# @return [Boolean]
|
104
|
+
# default true
|
105
|
+
attr_reader :sort
|
106
|
+
|
107
|
+
# Password hash
|
108
|
+
# @return [String]
|
109
|
+
# default nil
|
110
|
+
attr_reader :password
|
111
|
+
|
112
|
+
# Creates a new SheetProtection instance
|
113
|
+
# @option options [Boolean] sheet @see SheetProtection#sheet
|
114
|
+
# @option options [Boolean] objects @see SheetProtection#objects
|
115
|
+
# @option options [Boolean] scenarios @see SheetProtection#scenarios
|
116
|
+
# @option options [Boolean] format_cells @see SheetProtection#objects
|
117
|
+
# @option options [Boolean] format_columns @see SheetProtection#format_columns
|
118
|
+
# @option options [Boolean] format_rows @see SheetProtection#format_rows
|
119
|
+
# @option options [Boolean] insert_columns @see SheetProtection#insert_columns
|
120
|
+
# @option options [Boolean] insert_rows @see SheetProtection#insert_rows
|
121
|
+
# @option options [Boolean] insert_hyperlinks @see SheetProtection#insert_hyperlinks
|
122
|
+
# @option options [Boolean] delete_columns @see SheetProtection#delete_columns
|
123
|
+
# @option options [Boolean] delete_rows @see SheetProtection#delete_rows
|
124
|
+
# @option options [Boolean] select_locked_cells @see SheetProtection#select_locked_cells
|
125
|
+
# @option options [Boolean] sort @see SheetProtection#sort
|
126
|
+
# @option options [Boolean] auto_filter @see SheetProtection#auto_filter
|
127
|
+
# @option options [Boolean] pivot_tables @see SheetProtection#pivot_tables
|
128
|
+
# @option options [Boolean] select_unlocked_cells @see SheetProtection#select_unlocked_cells
|
129
|
+
# @option options [String] password. The password required for unlocking. @see SheetProtection#password=
|
130
|
+
# @option options [Boolean] objects @see SheetProtection#objects
|
131
|
+
def initialize(options={})
|
132
|
+
@objects = @scenarios = @select_locked_cells = @select_unlocked_cells = false
|
133
|
+
@sheet = @format_cells = @format_rows = @format_columns = @insert_columns = @insert_rows = @insert_hyperlinks = @delete_columns = @delete_rows = @sort = @auto_filter = @pivot_tables = true
|
134
|
+
@password = nil
|
135
|
+
|
136
|
+
options.each do |o|
|
137
|
+
self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
# create validating setters for boolean values
|
143
|
+
# @return [Boolean]
|
144
|
+
[:sheet, :objects, :scenarios, :select_locked_cells, :sort,
|
145
|
+
:select_unlocked_cells, :format_cells, :format_rows, :format_columns,
|
146
|
+
:insert_columns, :insert_rows, :insert_hyperlinks, :delete_columns,
|
147
|
+
:delete_rows, :auto_filter, :pivot_tables].each do |f_name|
|
148
|
+
define_method "#{f_name.to_s}=".to_sym do |v|
|
149
|
+
Axlsx::validate_boolean(v)
|
150
|
+
instance_variable_set "@#{f_name.to_s}".to_sym, v
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# This block is intended to implement the salt_value, hash_value and spin count as per the ECMA-376 standard.
|
155
|
+
# However, it does not seem to actually work in EXCEL - instead they are using their old retro algorithm shown below
|
156
|
+
# defined in the transitional portion of the speck. I am leaving this code in in the hope that someday Ill be able to
|
157
|
+
# figure out why it does not work, and if Excel even supports it.
|
158
|
+
# def propper_password=(v)
|
159
|
+
# @algorithm_name = v == nil ? nil : 'SHA-1'
|
160
|
+
# @salt_value = @spin_count = @hash_value = v if v == nil
|
161
|
+
# return if v == nil
|
162
|
+
# require 'digest/sha1'
|
163
|
+
# @spin_count = 10000
|
164
|
+
# @salt_value = Digest::SHA1.hexdigest(rand(36**8).to_s(36))
|
165
|
+
# @spin_count.times do |count|
|
166
|
+
# @hash_value = Digest::SHA1.hexdigest((@hash_value ||= (@salt_value + v.to_s)) + Array(count).pack('V'))
|
167
|
+
# end
|
168
|
+
# end
|
169
|
+
|
170
|
+
|
171
|
+
|
172
|
+
# encodes password for protection locking
|
173
|
+
def password=(v)
|
174
|
+
return if v == nil
|
175
|
+
@password = create_password_hash(v)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Serialize the object
|
179
|
+
# @param [String] str
|
180
|
+
# @return [String]
|
181
|
+
def to_xml_string(str = '')
|
182
|
+
str << '<sheetProtection '
|
183
|
+
str << instance_values.map{ |k,v| k.gsub(/_(.)/){ $1.upcase } << %{="#{v.to_s}"} }.join(' ')
|
184
|
+
str << '/>'
|
185
|
+
end
|
186
|
+
|
187
|
+
private
|
188
|
+
# Creates a password hash for a given password
|
189
|
+
# @return [String]
|
190
|
+
def create_password_hash(password)
|
191
|
+
encoded_password = encode_password(password)
|
192
|
+
|
193
|
+
password_as_hex = [encoded_password].pack("v")
|
194
|
+
password_as_string = password_as_hex.unpack("H*").first.upcase
|
195
|
+
|
196
|
+
password_as_string[2..3] + password_as_string[0..1]
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
# Encodes a given password
|
201
|
+
# Based on the algorithm provided by Daniel Rentz of OpenOffice.
|
202
|
+
# http://www.openoffice.org/sc/excelfileformat.pdf, Revision 1.42, page 115 (21.05.2012)
|
203
|
+
# @return [String]
|
204
|
+
def encode_password(password)
|
205
|
+
i = 0
|
206
|
+
chars = password.split(//)
|
207
|
+
count = chars.size
|
208
|
+
|
209
|
+
chars.collect! do |char|
|
210
|
+
i += 1
|
211
|
+
char = char.unpack('c')[0] << i #ord << i
|
212
|
+
low_15 = char & 0x7fff
|
213
|
+
high_15 = char & 0x7fff << 15
|
214
|
+
high_15 = high_15 >> 15
|
215
|
+
char = low_15 | high_15
|
216
|
+
end
|
217
|
+
|
218
|
+
encoded_password = 0x0000
|
219
|
+
chars.each { |c| encoded_password ^= c }
|
220
|
+
encoded_password ^= count
|
221
|
+
encoded_password ^= 0xCE4B
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
@@ -19,8 +19,8 @@ module Axlsx
|
|
19
19
|
attr_reader :style
|
20
20
|
|
21
21
|
# Creates a new Table object
|
22
|
-
# @param [String] ref The reference to the table data.
|
23
|
-
# @param [
|
22
|
+
# @param [String] ref The reference to the table data like 'A1:G24'.
|
23
|
+
# @param [Worksheet] sheet The sheet containing the table data.
|
24
24
|
# @option options [Cell, String] name
|
25
25
|
# @option options [TableStyle] style
|
26
26
|
def initialize(ref, sheet, options={})
|
@@ -8,6 +8,15 @@ module Axlsx
|
|
8
8
|
# @return [String]
|
9
9
|
attr_reader :name
|
10
10
|
|
11
|
+
# The sheet protection object for this workbook
|
12
|
+
# @return [SheetProtection]
|
13
|
+
# @see SheetProtection
|
14
|
+
def sheet_protection
|
15
|
+
@sheet_protection ||= SheetProtection.new
|
16
|
+
yield @sheet_protection if block_given?
|
17
|
+
@sheet_protection
|
18
|
+
end
|
19
|
+
|
11
20
|
# The workbook that owns this worksheet
|
12
21
|
# @return [Workbook]
|
13
22
|
attr_reader :workbook
|
@@ -51,9 +60,14 @@ module Axlsx
|
|
51
60
|
# @return Boolean
|
52
61
|
attr_reader :selected
|
53
62
|
|
54
|
-
# Indicates if the worksheet
|
63
|
+
# Indicates if the worksheet will be fit by witdh or height to a specific number of pages.
|
64
|
+
# To alter the width or height for page fitting, please use page_setup.fit_to_widht or page_setup.fit_to_height.
|
65
|
+
# If you want the worksheet to fit on more pages (e.g. 2x2), set {PageSetup#fit_to_width} and {PageSetup#fit_to_height} accordingly.
|
55
66
|
# @return Boolean
|
56
|
-
|
67
|
+
# @see #page_setup
|
68
|
+
def fit_to_page
|
69
|
+
(@page_setup != nil && (@page_setup.fit_to_width != nil || @page_setup.fit_to_height != nil))
|
70
|
+
end
|
57
71
|
|
58
72
|
|
59
73
|
# Column info for the sheet
|
@@ -88,7 +102,7 @@ module Axlsx
|
|
88
102
|
# wb = Axlsx::Package.new.workbook
|
89
103
|
#
|
90
104
|
# # using options when creating the worksheet.
|
91
|
-
# ws = wb.add_worksheet :page_setup => {:fit_to_width =>
|
105
|
+
# ws = wb.add_worksheet :page_setup => {:fit_to_width => 2, :orientation => :landscape}
|
92
106
|
#
|
93
107
|
# # use the set method of the page_setup object
|
94
108
|
# ws.page_setup.set(:paper_width => "297mm", :paper_height => "210mm")
|
@@ -110,15 +124,15 @@ module Axlsx
|
|
110
124
|
# @example
|
111
125
|
# wb = Axlsx::Package.new.workbook
|
112
126
|
# # using options when creating the worksheet.
|
113
|
-
# ws = wb.add_worksheet :print_options => {:
|
127
|
+
# ws = wb.add_worksheet :print_options => {:grid_lines => true, :horizontal_centered => true}
|
114
128
|
#
|
115
129
|
# # use the set method of the page_margins object
|
116
130
|
# ws.print_options.set(:headings => true)
|
117
131
|
#
|
118
132
|
# # set page margins in a block
|
119
133
|
# ws.print_options do |options|
|
120
|
-
# options.
|
121
|
-
# options.
|
134
|
+
# options.horizontal_centered = true
|
135
|
+
# options.vertical_centered = true
|
122
136
|
# end
|
123
137
|
# @see PrintOptions#initialize
|
124
138
|
# @return [PrintOptions]
|
@@ -146,16 +160,17 @@ module Axlsx
|
|
146
160
|
self.workbook = wb
|
147
161
|
@workbook.worksheets << self
|
148
162
|
@page_marging = @page_setup = @print_options = nil
|
149
|
-
@drawing = @page_margins = @auto_filter = nil
|
163
|
+
@drawing = @page_margins = @auto_filter = @sheet_protection = nil
|
150
164
|
@merged_cells = []
|
151
165
|
@auto_fit_data = []
|
152
166
|
@conditional_formattings = []
|
167
|
+
@data_validations = []
|
153
168
|
@comments = Comments.new(self)
|
154
169
|
@selected = false
|
155
170
|
@show_gridlines = true
|
156
171
|
self.name = "Sheet" + (index+1).to_s
|
157
172
|
@page_margins = PageMargins.new options[:page_margins] if options[:page_margins]
|
158
|
-
@page_setup = PageSetup.new options[:page_setup]
|
173
|
+
@page_setup = PageSetup.new options[:page_setup] if options[:page_setup]
|
159
174
|
@print_options = PrintOptions.new options[:print_options] if options[:print_options]
|
160
175
|
@rows = SimpleTypedList.new Row
|
161
176
|
@column_info = SimpleTypedList.new Col
|
@@ -188,6 +203,17 @@ module Axlsx
|
|
188
203
|
cf.add_rules rules
|
189
204
|
@conditional_formattings << cf
|
190
205
|
end
|
206
|
+
|
207
|
+
# Add data validation to this worksheet.
|
208
|
+
#
|
209
|
+
# @param [String] cells The cells the validation will apply to.
|
210
|
+
# @param [hash] data_validation options defining the validation to apply.
|
211
|
+
# @see examples/data_validation.rb for an example
|
212
|
+
def add_data_validation(cells, data_validation)
|
213
|
+
dv = DataValidation.new(data_validation)
|
214
|
+
dv.sqref = cells
|
215
|
+
@data_validations << dv
|
216
|
+
end
|
191
217
|
|
192
218
|
# Creates merge information for this worksheet.
|
193
219
|
# Cells can be merged by calling the merge_cells method on a worksheet.
|
@@ -202,7 +228,7 @@ module Axlsx
|
|
202
228
|
@merged_cells << if cells.is_a?(String)
|
203
229
|
cells
|
204
230
|
elsif cells.is_a?(Array)
|
205
|
-
cells = cells.sort { |x, y| x.
|
231
|
+
cells = cells.sort { |x, y| [x.index, x.row.index] <=> [y.index, y.row.index] }
|
206
232
|
"#{cells.first.r}:#{cells.last.r}"
|
207
233
|
end
|
208
234
|
end
|
@@ -233,12 +259,11 @@ module Axlsx
|
|
233
259
|
end
|
234
260
|
|
235
261
|
|
236
|
-
#
|
237
|
-
# This is true by default.
|
262
|
+
# (see #fit_to_page)
|
238
263
|
# @return [Boolean]
|
239
264
|
def fit_to_page=(v)
|
240
|
-
|
241
|
-
|
265
|
+
warn('axlsx::DEPRECIATED: Worksheet#fit_to_page has been depreciated. This value will automatically be set for you when you use PageSetup#fit_to.')
|
266
|
+
fit_to_page
|
242
267
|
end
|
243
268
|
|
244
269
|
|
@@ -462,6 +487,7 @@ module Axlsx
|
|
462
487
|
# @param [String] str
|
463
488
|
# @return [String]
|
464
489
|
def to_xml_string
|
490
|
+
rels = relationships
|
465
491
|
str = '<?xml version="1.0" encoding="UTF-8"?>'
|
466
492
|
str.concat "<worksheet xmlns=\"%s\" xmlns:r=\"%s\">" % [XML_NS, XML_NS_R]
|
467
493
|
str.concat "<sheetPr><pageSetUpPr fitToPage=\"%s\"></pageSetUpPr></sheetPr>" % fit_to_page if fit_to_page
|
@@ -477,19 +503,28 @@ module Axlsx
|
|
477
503
|
@rows.each_with_index { |row, index| row.to_xml_string(index, str) }
|
478
504
|
str.concat '</sheetData>'
|
479
505
|
str.concat "<autoFilter ref='%s'></autoFilter>" % @auto_filter if @auto_filter
|
506
|
+
@sheet_protection.to_xml_string(str) if @sheet_protection
|
480
507
|
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?
|
481
508
|
print_options.to_xml_string(str) if @print_options
|
482
509
|
page_margins.to_xml_string(str) if @page_margins
|
483
510
|
page_setup.to_xml_string(str) if @page_setup
|
484
|
-
str
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
511
|
+
str << "<drawing r:id='rId" << (rels.index{ |r| r.Type == DRAWING_R } + 1).to_s << "'/>" if @drawing
|
512
|
+
str << "<legacyDrawing r:id='rId" << (rels.index{ |r| r.Type == VML_DRAWING_R } + 1).to_s << "'/>" if @comments.size > 0
|
513
|
+
unless @tables.empty?
|
514
|
+
str.concat "<tableParts count='%s'>%s</tableParts>" % [@tables.size, @tables.reduce('') { |memo, obj| memo += "<tablePart r:id='%s'/>" % obj.rId }]
|
515
|
+
end
|
516
|
+
@conditional_formattings.each do |cf|
|
517
|
+
str.concat cf.to_xml_string
|
518
|
+
end
|
519
|
+
|
520
|
+
unless @data_validations.empty?
|
521
|
+
str.concat "<dataValidations count=\"#{@data_validations.size}\">"
|
522
|
+
@data_validations.each do |df|
|
523
|
+
str.concat df.to_xml_string
|
524
|
+
end
|
525
|
+
str.concat '</dataValidations>'
|
526
|
+
end
|
527
|
+
str + '</worksheet>'
|
493
528
|
end
|
494
529
|
|
495
530
|
# The worksheet relationships. This is managed automatically by the worksheet
|