axlsx 1.0.13 → 1.0.14
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +161 -134
- data/examples/example.rb +133 -153
- data/lib/axlsx.rb +3 -1
- data/lib/axlsx/#cfb.xlsx# +0 -0
- data/lib/axlsx/drawing/axis.rb +13 -10
- data/lib/axlsx/drawing/bar_3D_chart.rb +19 -11
- data/lib/axlsx/drawing/bar_series.rb +1 -1
- data/lib/axlsx/drawing/cat_axis.rb +5 -5
- data/lib/axlsx/drawing/cat_axis_data.rb +7 -7
- data/lib/axlsx/drawing/chart.rb +29 -15
- data/lib/axlsx/drawing/drawing.rb +1 -1
- data/lib/axlsx/drawing/graphic_frame.rb +10 -10
- data/lib/axlsx/drawing/line_3D_chart.rb +15 -7
- data/lib/axlsx/drawing/marker.rb +1 -1
- data/lib/axlsx/drawing/one_cell_anchor.rb +4 -4
- data/lib/axlsx/drawing/pic.rb +14 -14
- data/lib/axlsx/drawing/pie_3D_chart.rb +2 -2
- data/lib/axlsx/drawing/pie_series.rb +1 -1
- data/lib/axlsx/drawing/scaling.rb +5 -5
- data/lib/axlsx/drawing/ser_axis.rb +3 -3
- data/lib/axlsx/drawing/series.rb +3 -3
- data/lib/axlsx/drawing/series_title.rb +7 -7
- data/lib/axlsx/drawing/title.rb +13 -9
- data/lib/axlsx/drawing/two_cell_anchor.rb +4 -4
- data/lib/axlsx/drawing/val_axis.rb +2 -2
- data/lib/axlsx/drawing/val_axis_data.rb +7 -9
- data/lib/axlsx/drawing/view_3D.rb +7 -7
- data/lib/axlsx/package.rb +8 -0
- data/lib/axlsx/util/constants.rb +0 -4
- data/lib/axlsx/util/ms_off_crypto.rb +88 -0
- data/lib/axlsx/util/ms_off_crypto.rb~ +3 -0
- data/lib/axlsx/util/ms_offcrypto.rb~ +0 -0
- data/lib/axlsx/version.rb +1 -1
- data/lib/axlsx/workbook/workbook.rb +1 -0
- data/lib/axlsx/workbook/worksheet/cell.rb +21 -8
- data/lib/axlsx/workbook/worksheet/worksheet.rb +74 -18
- data/test/content_type/tc_content_type.rb +81 -0
- data/test/content_type/tc_default.rb +40 -0
- data/test/content_type/tc_override.rb +40 -0
- data/test/doc_props/tc_app.rb +19 -0
- data/test/doc_props/tc_core.rb +34 -0
- data/test/drawing/tc_axis.rb +40 -0
- data/test/drawing/tc_bar_3D_chart.rb +66 -0
- data/test/drawing/tc_bar_series.rb +34 -0
- data/test/drawing/tc_cat_axis.rb +32 -0
- data/test/drawing/tc_cat_axis_data.rb +18 -0
- data/test/drawing/tc_chart.rb +73 -0
- data/test/drawing/tc_drawing.rb +80 -0
- data/test/drawing/tc_graphic_frame.rb +26 -0
- data/test/drawing/tc_line_3d_chart.rb +48 -0
- data/test/drawing/tc_line_series.rb +27 -0
- data/test/drawing/tc_line_series.tc~ +34 -0
- data/test/drawing/tc_marker.rb +45 -0
- data/test/drawing/tc_one_cell_anchor.rb +67 -0
- data/test/drawing/tc_pic.rb +71 -0
- data/test/drawing/tc_picture_locking.rb +73 -0
- data/test/drawing/tc_picture_locking.rb~ +77 -0
- data/test/drawing/tc_pie_3D_chart.rb +33 -0
- data/test/drawing/tc_pie_series.rb +35 -0
- data/test/drawing/tc_scaling.rb +37 -0
- data/test/drawing/tc_ser_axis.rb +31 -0
- data/test/drawing/tc_series.rb +24 -0
- data/test/drawing/tc_series_title.rb +34 -0
- data/test/drawing/tc_title.rb +34 -0
- data/test/drawing/tc_two_cell_anchor.rb +38 -0
- data/test/drawing/tc_val_axis.rb +25 -0
- data/test/drawing/tc_val_axis_data.rb +18 -0
- data/test/drawing/tc_view_3D.rb +55 -0
- data/test/rels/tc_relationship.rb +16 -0
- data/test/rels/tc_relationships.rb +27 -0
- data/test/stylesheet/tc_border.rb +38 -0
- data/test/stylesheet/tc_border_pr.rb +33 -0
- data/test/stylesheet/tc_cell_alignment.rb +77 -0
- data/test/stylesheet/tc_cell_protection.rb +30 -0
- data/test/stylesheet/tc_cell_style.rb +58 -0
- data/test/stylesheet/tc_color.rb +38 -0
- data/test/stylesheet/tc_fill.rb +19 -0
- data/test/stylesheet/tc_font.rb +114 -0
- data/test/stylesheet/tc_gradient_fill.rb +65 -0
- data/test/stylesheet/tc_gradient_stop.rb +32 -0
- data/test/stylesheet/tc_num_fmt.rb +31 -0
- data/test/stylesheet/tc_pattern_fill.rb +38 -0
- data/test/stylesheet/tc_styles.rb +52 -0
- data/test/stylesheet/tc_table_style.rb +37 -0
- data/test/stylesheet/tc_table_style_element.rb +37 -0
- data/test/stylesheet/tc_table_styles.rb +30 -0
- data/test/stylesheet/tc_xf.rb +121 -0
- data/test/tc_package.rb +78 -0
- data/test/util/tc_simple_typed_list.rb +66 -0
- data/test/util/tc_validators.rb +76 -0
- data/test/workbook/tc_workbook.rb +60 -0
- data/test/workbook/worksheet/tc_cell.rb +194 -0
- data/test/workbook/worksheet/tc_row.rb +36 -0
- data/test/workbook/worksheet/tc_worksheet.rb +159 -0
- metadata +191 -31
- data/lib/axlsx/workbook/#workbook.rb# +0 -165
@@ -6,13 +6,13 @@ module Axlsx
|
|
6
6
|
# @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
|
7
7
|
# @return [String]
|
8
8
|
def to_xml(xml)
|
9
|
-
xml.
|
10
|
-
xml.
|
11
|
-
xml.
|
12
|
-
xml.
|
13
|
-
xml.
|
14
|
-
xml.
|
15
|
-
xml.
|
9
|
+
xml[:c].tx {
|
10
|
+
xml[:c].strRef {
|
11
|
+
xml[:c].f Axlsx::cell_range([@cell])
|
12
|
+
xml[:c].strCache {
|
13
|
+
xml[:c].ptCount :val=>1
|
14
|
+
xml[:c].pt(:idx=>0) {
|
15
|
+
xml[:c].v @text
|
16
16
|
}
|
17
17
|
}
|
18
18
|
}
|
data/lib/axlsx/drawing/title.rb
CHANGED
@@ -42,18 +42,22 @@ module Axlsx
|
|
42
42
|
# @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
|
43
43
|
# @return [String]
|
44
44
|
def to_xml(xml)
|
45
|
-
xml.
|
46
|
-
|
47
|
-
xml.
|
48
|
-
xml.
|
49
|
-
|
50
|
-
xml.
|
51
|
-
|
52
|
-
xml.
|
45
|
+
xml[:c].title {
|
46
|
+
unless @text.empty?
|
47
|
+
xml[:c].tx {
|
48
|
+
xml[:c].strRef {
|
49
|
+
xml[:c].f Axlsx::cell_range([@cell])
|
50
|
+
xml[:c].strCache {
|
51
|
+
xml[:c].ptCount :val=>1
|
52
|
+
xml[:c].pt(:idx=>0) {
|
53
|
+
xml[:c].v @text
|
54
|
+
}
|
53
55
|
}
|
54
56
|
}
|
55
57
|
}
|
56
|
-
|
58
|
+
end
|
59
|
+
xml[:c].layout
|
60
|
+
xml[:c].overlay :val=>0
|
57
61
|
}
|
58
62
|
end
|
59
63
|
|
@@ -58,15 +58,15 @@ module Axlsx
|
|
58
58
|
# @return [String]
|
59
59
|
def to_xml(xml)
|
60
60
|
#build it for now, break it down later!
|
61
|
-
xml.
|
62
|
-
xml.
|
61
|
+
xml[:xdr].twoCellAnchor {
|
62
|
+
xml.from {
|
63
63
|
from.to_xml(xml)
|
64
64
|
}
|
65
|
-
xml.
|
65
|
+
xml.to {
|
66
66
|
to.to_xml(xml)
|
67
67
|
}
|
68
68
|
@object.to_xml(xml)
|
69
|
-
xml.
|
69
|
+
xml.clientData
|
70
70
|
}
|
71
71
|
end
|
72
72
|
|
@@ -25,9 +25,9 @@ module Axlsx
|
|
25
25
|
# @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
|
26
26
|
# @return [String]
|
27
27
|
def to_xml(xml)
|
28
|
-
xml.
|
28
|
+
xml.valAx {
|
29
29
|
super(xml)
|
30
|
-
xml.
|
30
|
+
xml.crossBetween :val=>@crossBetween
|
31
31
|
}
|
32
32
|
end
|
33
33
|
end
|
@@ -6,17 +6,15 @@ module Axlsx
|
|
6
6
|
# @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
|
7
7
|
# @return [String]
|
8
8
|
def to_xml(xml)
|
9
|
-
xml.
|
10
|
-
xml.
|
11
|
-
xml.
|
12
|
-
xml.
|
13
|
-
xml.
|
14
|
-
xml.
|
9
|
+
xml.val {
|
10
|
+
xml.numRef {
|
11
|
+
xml.f Axlsx::cell_range(@list)
|
12
|
+
xml.numCache {
|
13
|
+
xml.formatCode 'General'
|
14
|
+
xml.ptCount :val=>size
|
15
15
|
each_with_index do |item, index|
|
16
16
|
v = item.is_a?(Cell) ? item.value : item
|
17
|
-
xml.
|
18
|
-
xml.send('c:v', v)
|
19
|
-
}
|
17
|
+
xml.pt(:idx=>index) { xml.v v }
|
20
18
|
end
|
21
19
|
}
|
22
20
|
}
|
@@ -72,13 +72,13 @@ module Axlsx
|
|
72
72
|
# @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
|
73
73
|
# @return [String]
|
74
74
|
def to_xml(xml)
|
75
|
-
xml.
|
76
|
-
xml.
|
77
|
-
xml.
|
78
|
-
xml.
|
79
|
-
xml.
|
80
|
-
xml.
|
81
|
-
xml.
|
75
|
+
xml[:c].view3D {
|
76
|
+
xml[:c].rotX :val=>@rotX unless @rotX.nil?
|
77
|
+
xml[:c].hPercent :val=>@hPercent unless @hPercent.nil?
|
78
|
+
xml[:c].rotY :val=>@rotY unless @rotY.nil?
|
79
|
+
xml[:c].depthPercent :val=>@depthPercent unless @depthPercent.nil?
|
80
|
+
xml[:c].rAngAx :val=>@rAngAx unless @rAngAx.nil?
|
81
|
+
xml[:c].perspective :val=>@perspective unless @perspective.nil?
|
82
82
|
}
|
83
83
|
end
|
84
84
|
end
|
data/lib/axlsx/package.rb
CHANGED
@@ -4,6 +4,14 @@ module Axlsx
|
|
4
4
|
# xlsx document including valdation and serialization.
|
5
5
|
class Package
|
6
6
|
|
7
|
+
# provides access to the app doc properties for this package
|
8
|
+
# see App
|
9
|
+
attr_reader :app
|
10
|
+
|
11
|
+
# provides access to the core doc properties for the package
|
12
|
+
# see Core
|
13
|
+
attr_reader :core
|
14
|
+
|
7
15
|
# Initializes your package
|
8
16
|
#
|
9
17
|
# @param [Hash] options A hash that you can use to specify the author and workbook for this package.
|
data/lib/axlsx/util/constants.rb
CHANGED
@@ -12,10 +12,6 @@ module Axlsx
|
|
12
12
|
# extended-properties namespace
|
13
13
|
APP_NS = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"
|
14
14
|
|
15
|
-
XML_NS_MC="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
16
|
-
|
17
|
-
XML_NS_X14AC = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"
|
18
|
-
|
19
15
|
# doc props namespace
|
20
16
|
APP_NS_VT = "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
|
21
17
|
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'digest'
|
2
|
+
require 'base64'
|
3
|
+
require 'openssl'
|
4
|
+
module Axlsx
|
5
|
+
class MsOffCrypto
|
6
|
+
|
7
|
+
attr_reader :verifier
|
8
|
+
attr_reader :key
|
9
|
+
|
10
|
+
def initialize(password = "passowrd")
|
11
|
+
@password = password
|
12
|
+
@salt_size = 0x10
|
13
|
+
@key_size = 0x100
|
14
|
+
@verifier = rand(16**16).to_s
|
15
|
+
|
16
|
+
#fixed salt for testing
|
17
|
+
@salt = [0x90,0xAC,0x68,0x0E,0x76,0xF9,0x43,0x2B,0x8D,0x13,0xB7,0x1D,0xB7,0xC0,0xFC,0x0D].join
|
18
|
+
# @salt =Digest::SHA1.digest(rand(16**16).to_s)
|
19
|
+
end
|
20
|
+
|
21
|
+
def encryption_info
|
22
|
+
# v.major v.minor flags header length flags size # AES 128 bit
|
23
|
+
header = [3, 0, 2, 0, 0x24, 0, 0, 0, 0xA4, 0, 0, 0, 0x24, 0, 0, 0, 0, 0, 0, 0, 0x0E, 0x66, 0, 0]
|
24
|
+
header.concat [0x04, 0x80, 0, 0, 0x80, 0, 0, 0, 0x18, 0, 0, 0, 0xA0, 0xC7, 0xDC, 0x2, 0, 0, 0, 0]
|
25
|
+
header.concat "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)".bytes.to_a.pack('s*').bytes.to_a
|
26
|
+
header.concat [0, 0]
|
27
|
+
header.concat [0x10, 0, 0, 0]
|
28
|
+
header.concat [0x90,0xAC,0x68,0x0E,0x76,0xF9,0x43,0x2B,0x8D,0x13,0xB7,0x1D,0xB7,0xC0,0xFC,0x0D]
|
29
|
+
header.concat encrypted_verifier.bytes.to_a.pack('c*').bytes.to_a
|
30
|
+
header.concat [20, 0,0,0]
|
31
|
+
header.concat encrypted_verifier_hash.bytes.to_a.pack('c*').bytes.to_a
|
32
|
+
header.flatten!
|
33
|
+
header.pack('c*')
|
34
|
+
end
|
35
|
+
|
36
|
+
def encryption_verifier
|
37
|
+
{:salt_size => @salt_size,
|
38
|
+
:salt => @salt,
|
39
|
+
:encrypted_verifier => encrypted_verifier,
|
40
|
+
:varifier_hash_size => 0x14,
|
41
|
+
:encrypted_verifier_hash => encrypted_verifier_hash}
|
42
|
+
end
|
43
|
+
|
44
|
+
# 2.3.3
|
45
|
+
def encrypted_verifier
|
46
|
+
@encrypted_verifier ||= encrypt(@verifier)
|
47
|
+
end
|
48
|
+
|
49
|
+
# 2.3.3
|
50
|
+
def encrypted_verifier_hash
|
51
|
+
verifier_hash = Digest::SHA1.digest(@verifier)
|
52
|
+
verifier_hash << Array.new(32 - verifier_hash.size, 0).join('')
|
53
|
+
@encrypted_verifier_hash ||= encrypt(verifier_hash)
|
54
|
+
end
|
55
|
+
|
56
|
+
# 2.3.4.7 ECMA-376 Document Encryption Key Generation (Standard Encryption)
|
57
|
+
def key
|
58
|
+
sha = Digest::SHA1.new() << (@salt + @password)
|
59
|
+
(0..49999).each { |i| sha.update(i.to_s+sha.to_s) }
|
60
|
+
key = sha.update(sha.to_s+'0').digest
|
61
|
+
a = key.bytes.each_with_index.map { |item, i| 0x36 ^ item }
|
62
|
+
x1 = Digest::SHA1.digest((a.concat Array.new(64 - key.size, 0x36)).to_s)
|
63
|
+
a = key.bytes.each_with_index.map { |item, i| 0x5C ^ item }
|
64
|
+
x2 = Digest::SHA1.digest( (a.concat Array.new(64 - key.size, 0x5C) ).to_s)
|
65
|
+
x3 = x1 + x2
|
66
|
+
@key ||= x3.bytes.to_a[(0..31)].pack('c*')
|
67
|
+
end
|
68
|
+
|
69
|
+
def verify_password
|
70
|
+
puts decrypt(@encrypted_verifier)
|
71
|
+
end
|
72
|
+
|
73
|
+
def encrypt(data)
|
74
|
+
aes = OpenSSL::Cipher.new("AES-128-ECB")
|
75
|
+
aes.encrypt
|
76
|
+
aes.key = key
|
77
|
+
aes.update(data)
|
78
|
+
end
|
79
|
+
|
80
|
+
def decrypt(data)
|
81
|
+
aes = OpenSSL::Cipher.new("AES-128-ECB")
|
82
|
+
aes.decrypt
|
83
|
+
aes.key = key
|
84
|
+
aes.update(data)
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
File without changes
|
data/lib/axlsx/version.rb
CHANGED
@@ -147,6 +147,7 @@ require 'axlsx/workbook/worksheet/worksheet.rb'
|
|
147
147
|
builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml|
|
148
148
|
xml.workbook(:xmlns => XML_NS, :'xmlns:r' => XML_NS_R) {
|
149
149
|
xml.workbookPr(:date1904=>@@date1904)
|
150
|
+
#<x:workbookProtection workbookPassword="xsd:hexBinary data" lockStructure="1" lockWindows="1" />
|
150
151
|
xml.sheets {
|
151
152
|
@worksheets.each_with_index do |sheet, index|
|
152
153
|
xml.sheet(:name=>sheet.name, :sheetId=>index+1, :"r:id"=>sheet.rId)
|
@@ -219,6 +219,18 @@ module Axlsx
|
|
219
219
|
[index, row.index]
|
220
220
|
end
|
221
221
|
|
222
|
+
# Merges all the cells in a range created between this cell and the cell or string name for a cell provided
|
223
|
+
# @see worksheet.merge_cells
|
224
|
+
# @param [Cell, String] target The last cell, or str ref for the cell in the merge range
|
225
|
+
def merge(target)
|
226
|
+
range_end = if target.is_a?(String)
|
227
|
+
target
|
228
|
+
elsif(target.is_a?(Cell))
|
229
|
+
target.r
|
230
|
+
end
|
231
|
+
self.row.worksheet.merge_cells "#{self.r}:#{range_end}" unless range_end.nil?
|
232
|
+
end
|
233
|
+
|
222
234
|
# Serializes the cell
|
223
235
|
# @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
|
224
236
|
# @return [String] xml text for the cell
|
@@ -266,6 +278,14 @@ module Axlsx
|
|
266
278
|
}
|
267
279
|
}
|
268
280
|
end
|
281
|
+
elsif @type == :time
|
282
|
+
# Using hardcoded offsets here as some operating systems will not except a 'negative' offset from the ruby epoc.
|
283
|
+
# (1970)
|
284
|
+
epoc1900 = -2209021200 #Time.local(1900, 1, 1)
|
285
|
+
epoc1904 = -2082877200 #Time.local(1904, 1, 1)
|
286
|
+
epoc = Workbook.date1904 ? epoc1904 : epoc1900
|
287
|
+
v = ((@value.localtime.to_f - epoc) /60.0/60.0/24.0).to_f
|
288
|
+
xml.c(:r => r, :s => style) { xml.v v }
|
269
289
|
else
|
270
290
|
xml.c(:r => r, :s => style) { xml.v value }
|
271
291
|
end
|
@@ -315,15 +335,8 @@ module Axlsx
|
|
315
335
|
# @see Axlsx#date1904
|
316
336
|
def cast_value(v)
|
317
337
|
if (@type == :time && v.is_a?(Time)) || (@type == :time && v.respond_to?(:to_time))
|
318
|
-
v = v.respond_to?(:to_time) ? v.to_time : v
|
319
338
|
self.style = STYLE_DATE if self.style == 0
|
320
|
-
|
321
|
-
# (1970)
|
322
|
-
epoc1900 = -2209021200 #Time.local(1900, 1, 1)
|
323
|
-
epoc1904 = -2082877200 #Time.local(1904, 1, 1)
|
324
|
-
epoc = Workbook.date1904 ? epoc1904 : epoc1900
|
325
|
-
v = ((v.localtime.to_f - epoc) /60.0/60.0/24.0).to_f
|
326
|
-
((v * 10**11).round.to_f / 10**11)
|
339
|
+
v.respond_to?(:to_time) ? v.to_time : v
|
327
340
|
elsif @type == :float
|
328
341
|
v.to_f
|
329
342
|
elsif @type == :integer
|
@@ -24,8 +24,16 @@ module Axlsx
|
|
24
24
|
# @return [Array] of Hash
|
25
25
|
attr_reader :auto_fit_data
|
26
26
|
|
27
|
-
#
|
28
|
-
#
|
27
|
+
# An array of merged cell ranges e.d "A1:B3"
|
28
|
+
# Content and formatting is read from the first cell.
|
29
|
+
# @return Array
|
30
|
+
attr_reader :merged_cells
|
31
|
+
|
32
|
+
# An range that excel will apply an autfilter to "A1:B3"
|
33
|
+
# This will turn filtering on for the cells in the range.
|
34
|
+
# The first row is considered the header, while subsequent rows are considerd to be data.
|
35
|
+
# @return Array
|
36
|
+
attr_reader :auto_filter
|
29
37
|
|
30
38
|
# Creates a new worksheet.
|
31
39
|
# @note the recommended way to manage worksheets is Workbook#add_worksheet
|
@@ -40,8 +48,28 @@ module Axlsx
|
|
40
48
|
self.name = options[:name] || "Sheet" + (index+1).to_s
|
41
49
|
@magick_draw = Magick::Draw.new
|
42
50
|
@cols = SimpleTypedList.new Cell
|
51
|
+
@merged_cells = []
|
52
|
+
end
|
53
|
+
|
54
|
+
# Creates merge information for this worksheet.
|
55
|
+
# Cells can be merged by calling the merge_cells method on a worksheet.
|
56
|
+
# @example This would merge the three cells C1..E1 #
|
57
|
+
# worksheet.merge_cells "C1:E1"
|
58
|
+
# # you can also provide an array of cells to be merged
|
59
|
+
# worksheet.merge_cells worksheet.rows.first.cells[(2..4)]
|
60
|
+
# #alternatively you can do it from a single cell
|
61
|
+
# worksheet["C1"].merge worksheet["E1"]
|
62
|
+
# @param [Array, string]
|
63
|
+
def merge_cells(cells)
|
64
|
+
@merged_cells << if cells.is_a?(String)
|
65
|
+
cells
|
66
|
+
elsif cells.is_a?(Array)
|
67
|
+
cells = cells.sort { |x, y| x.r <=> y.r }
|
68
|
+
"#{cells.first.r}:#{cells.last.r}"
|
69
|
+
end
|
43
70
|
end
|
44
71
|
|
72
|
+
|
45
73
|
# Returns the cell or cells defined using excel style A1:B3 references.
|
46
74
|
# @param [String] cell_def the string defining the cell or range of cells
|
47
75
|
# @return [Cell, Array]
|
@@ -81,6 +109,14 @@ module Axlsx
|
|
81
109
|
@name=v
|
82
110
|
end
|
83
111
|
|
112
|
+
# The auto filter range for the worksheet
|
113
|
+
# @param [String] v
|
114
|
+
# @see auto_filter
|
115
|
+
def auto_filter=(v)
|
116
|
+
DataTypeValidator.validate "Worksheet.auto_filter", String, v
|
117
|
+
@auto_filter = v
|
118
|
+
end
|
119
|
+
|
84
120
|
# The part name of this worksheet
|
85
121
|
# @return [String]
|
86
122
|
def pn
|
@@ -214,6 +250,8 @@ module Axlsx
|
|
214
250
|
row.to_xml(xml)
|
215
251
|
end
|
216
252
|
}
|
253
|
+
xml.autoFilter :ref=>@auto_filter if @auto_filter
|
254
|
+
xml.mergeCells(:count=>@merged_cells.size) { @merged_cells.each { | mc | xml.mergeCell(:ref=>mc) } } unless @merged_cells.empty?
|
217
255
|
xml.drawing :"r:id"=>"rId1" if @drawing
|
218
256
|
}
|
219
257
|
end
|
@@ -234,15 +272,21 @@ module Axlsx
|
|
234
272
|
def workbook=(v) DataTypeValidator.validate "Worksheet.workbook", Workbook, v; @workbook = v; end
|
235
273
|
|
236
274
|
# Updates auto fit data.
|
237
|
-
#
|
275
|
+
# We store an auto_fit_data item for each column. when a row is added we multiple the font size by the length of the text to
|
276
|
+
# attempt to identify the longest cell in the column. This is not 100% accurate as it needs to take into account
|
277
|
+
# any formatting that will be applied to the data, as well as the actual rendering size when the length and size is equal
|
278
|
+
# for two cells.
|
238
279
|
# @return [Array] of Cell objects
|
239
280
|
# @param [Array] cells an array of cells
|
240
281
|
def update_auto_fit_data(cells)
|
282
|
+
# TODO delay this until rendering. too much work when we dont know what they are going to do to the sheet.
|
241
283
|
styles = self.workbook.styles
|
242
284
|
cellXfs, fonts = styles.cellXfs, styles.fonts
|
243
|
-
sz =
|
285
|
+
sz = 11
|
244
286
|
cells.each_with_index do |item, index|
|
287
|
+
# ignore formula - there is no way for us to know the result
|
245
288
|
next if item.value.is_a?(String) && item.value.start_with?('=')
|
289
|
+
|
246
290
|
col = @auto_fit_data[index] || {:longest=>"", :sz=>sz}
|
247
291
|
cell_xf = cellXfs[item.style]
|
248
292
|
font = fonts[cell_xf.fontId || 0]
|
@@ -255,25 +299,37 @@ module Axlsx
|
|
255
299
|
end
|
256
300
|
cells
|
257
301
|
end
|
258
|
-
|
302
|
+
|
259
303
|
# Determines the proper width for a column based on content.
|
260
304
|
# @note
|
261
|
-
#
|
262
|
-
# Column width measured as the number of characters of the maximum digit width of the numbers 0 .. 9 as
|
263
|
-
# rendered in the normal style's font. There are 4 pixels of margin padding (two on each side), plus 1 pixel padding for the gridlines.
|
264
|
-
# width = Truncate([!{Number of Characters} * !{Maximum Digit Width} + !{5 pixel padding}]/{Maximum Digit Width}*256)/256
|
305
|
+
# width = Truncate([!{Number of Characters} * !{Maximum Digit Width} + !{5 pixel padding}]/!{Maximum Digit Width}*256)/256
|
265
306
|
# @return [Float]
|
266
307
|
# @param [Hash] A hash of auto_fit_data
|
267
308
|
def auto_width(col)
|
268
|
-
mdw =
|
269
|
-
mdw_count = 0
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
col[:longest].scan(/./mu).each do |i|
|
274
|
-
mdw_count +=1 if @magick_draw.get_type_metrics(i).width >= mdw
|
309
|
+
mdw_count, font_scale, mdw = 0, col[:sz]/11.0, 6.0
|
310
|
+
mdw_count = col[:longest].scan(/./mu).reduce(0) do | count, char |
|
311
|
+
count +=1 if @magick_draw.get_type_metrics(char).max_advance >= mdw
|
312
|
+
count
|
275
313
|
end
|
276
|
-
((mdw_count * mdw + 5) / mdw * 256) / 256.0 *
|
277
|
-
end
|
314
|
+
((mdw_count * mdw + 5) / mdw * 256) / 256.0 * font_scale
|
315
|
+
end
|
316
|
+
|
317
|
+
# Something to look into:
|
318
|
+
# width calculation actually needs to be done agains the formatted value for items that apply a
|
319
|
+
# format
|
320
|
+
# def excel_format(cell)
|
321
|
+
# # The most common case.
|
322
|
+
# return time.value.to_s if cell.style == 0
|
323
|
+
#
|
324
|
+
# # The second most common case
|
325
|
+
# num_fmt = workbook.styles.cellXfs[items.style].numFmtId
|
326
|
+
# return value.to_s if num_fmt == 0
|
327
|
+
#
|
328
|
+
# format_code = workbook.styles.numFmts[num_fmt]
|
329
|
+
# # need to find some exceptionally fast way of parsing value according to
|
330
|
+
# # an excel format_code
|
331
|
+
# item.value.to_s
|
332
|
+
# end
|
333
|
+
|
278
334
|
end
|
279
335
|
end
|