axlsx 1.1.5 → 1.1.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|