surpass 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +0 -0
- data/README.txt +133 -0
- data/Rakefile +35 -0
- data/examples/big-16mb.rb +25 -0
- data/examples/big-random-strings.rb +28 -0
- data/examples/blanks.rb +34 -0
- data/examples/col_width.rb +16 -0
- data/examples/dates.rb +31 -0
- data/examples/format.rb +23 -0
- data/examples/hello-world.rb +9 -0
- data/examples/image.rb +10 -0
- data/examples/merged.rb +36 -0
- data/examples/merged0.rb +27 -0
- data/examples/merged1.rb +99 -0
- data/examples/num_formats.rb +55 -0
- data/examples/numbers.rb +24 -0
- data/examples/outline.rb +110 -0
- data/examples/panes.rb +48 -0
- data/examples/protection.rb +132 -0
- data/examples/python.bmp +0 -0
- data/examples/row_styles.rb +16 -0
- data/examples/row_styles_empty.rb +15 -0
- data/examples/set_cell_and_range_style.rb +12 -0
- data/examples/wrapped-text.rb +13 -0
- data/examples/write_arrays.rb +16 -0
- data/examples/ws_props.rb +80 -0
- data/lib/biff_record.rb +2168 -0
- data/lib/bitmap.rb +218 -0
- data/lib/cell.rb +214 -0
- data/lib/chart.rb +16 -0
- data/lib/column.rb +40 -0
- data/lib/document.rb +406 -0
- data/lib/excel_formula.rb +6 -0
- data/lib/excel_magic.rb +1013 -0
- data/lib/formatting.rb +554 -0
- data/lib/row.rb +137 -0
- data/lib/style.rb +179 -0
- data/lib/surpass.rb +51 -0
- data/lib/utilities.rb +86 -0
- data/lib/workbook.rb +206 -0
- data/lib/worksheet.rb +561 -0
- data/spec/biff_record_spec.rb +268 -0
- data/spec/cell_spec.rb +56 -0
- data/spec/data/random-strings.txt +10000 -0
- data/spec/document_spec.rb +168 -0
- data/spec/excel_formula_spec.rb +0 -0
- data/spec/formatting_spec.rb +53 -0
- data/spec/reference/P-0508-0000507647-3280-5298.xls +0 -0
- data/spec/reference/all-cell-styles.bin +0 -0
- data/spec/reference/all-number-formats.bin +0 -0
- data/spec/reference/all-styles.bin +0 -0
- data/spec/reference/mini.xls +0 -0
- data/spec/row_spec.rb +19 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/style_spec.rb +89 -0
- data/spec/utilities_spec.rb +57 -0
- data/spec/workbook_spec.rb +48 -0
- data/spec/worksheet_spec.rb +0 -0
- data/stats/cloc.txt +8 -0
- data/stats/rcov.txt +0 -0
- data/stats/specdoc.txt +158 -0
- data/surpass-manual-0-0-3.pdf +0 -0
- data/surpass.gemspec +34 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/excel.rake +6 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/metrics.rake +42 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- metadata +144 -0
data/lib/style.rb
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
class StyleFormat
|
2
|
+
attr_accessor :number_format_string
|
3
|
+
attr_accessor :font
|
4
|
+
attr_accessor :alignment
|
5
|
+
attr_accessor :borders
|
6
|
+
attr_accessor :pattern
|
7
|
+
attr_accessor :protection
|
8
|
+
|
9
|
+
def initialize(hash = {})
|
10
|
+
@number_format_string = hash[:number_format_string] || 'General'
|
11
|
+
|
12
|
+
@font = Font.new(hash_select(hash, /^font_/))
|
13
|
+
@alignment = Alignment.new(hash_select(hash, /^text_/))
|
14
|
+
@borders = Borders.new(hash_select(hash, /^border_/))
|
15
|
+
@pattern = Pattern.new(hash_select(hash, /^fill_/))
|
16
|
+
@protection = Protection.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def hash_select(hash, pattern)
|
20
|
+
new_hash = {}
|
21
|
+
hash.keys.each do |k|
|
22
|
+
next unless k.to_s =~ pattern
|
23
|
+
new_key = k.to_s.gsub(pattern, '').to_sym
|
24
|
+
new_hash[new_key] = hash[k]
|
25
|
+
end
|
26
|
+
new_hash
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class StyleCollection
|
31
|
+
attr_accessor :fonts
|
32
|
+
attr_accessor :number_formats
|
33
|
+
attr_accessor :styles
|
34
|
+
attr_accessor :default_style
|
35
|
+
attr_accessor :default_format
|
36
|
+
|
37
|
+
FIRST_USER_DEFINED_NUM_FORMAT_INDEX = 164
|
38
|
+
|
39
|
+
STANDARD_NUMBER_FORMATS = [
|
40
|
+
'General',
|
41
|
+
'0',
|
42
|
+
'0.00',
|
43
|
+
'#,##0',
|
44
|
+
'#,##0.00',
|
45
|
+
'"$"#,##0_);("$"#,##',
|
46
|
+
'"$"#,##0_);[Red]("$"#,##',
|
47
|
+
'"$"#,##0.00_);("$"#,##',
|
48
|
+
'"$"#,##0.00_);[Red]("$"#,##',
|
49
|
+
'0%',
|
50
|
+
'0.00%',
|
51
|
+
'0.00E+00',
|
52
|
+
'# ?/?',
|
53
|
+
'# ??/??',
|
54
|
+
'M/D/YY',
|
55
|
+
'D-MMM-YY',
|
56
|
+
'D-MMM',
|
57
|
+
'MMM-YY',
|
58
|
+
'h:mm AM/PM',
|
59
|
+
'h:mm:ss AM/PM',
|
60
|
+
'h:mm',
|
61
|
+
'h:mm:ss',
|
62
|
+
'M/D/YY h:mm',
|
63
|
+
'_(#,##0_);(#,##0)',
|
64
|
+
'_(#,##0_);[Red](#,##0)',
|
65
|
+
'_(#,##0.00_);(#,##0.00)',
|
66
|
+
'_(#,##0.00_);[Red](#,##0.00)',
|
67
|
+
'_("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)',
|
68
|
+
'_(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)',
|
69
|
+
'_("$"* #,##0.00_);_("$"* (#,##0.00);_("$"* "-"??_);_(@_)',
|
70
|
+
'_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)',
|
71
|
+
'mm:ss',
|
72
|
+
'[h]:mm:ss',
|
73
|
+
'mm:ss.0',
|
74
|
+
'##0.0E+0',
|
75
|
+
'@'
|
76
|
+
]
|
77
|
+
|
78
|
+
def initialize
|
79
|
+
# Populate default font list.
|
80
|
+
@fonts = {}
|
81
|
+
# Initialize blank fonts into slots 0,1,2,3,5 in order to skip slot 4.
|
82
|
+
[0,1,2,3,5].each do |i|
|
83
|
+
@fonts[i] = Font.new
|
84
|
+
end
|
85
|
+
|
86
|
+
# Populate default number format list.
|
87
|
+
@number_formats = {}
|
88
|
+
STANDARD_NUMBER_FORMATS.each_with_index do |s, i|
|
89
|
+
index = (i <= 23) ? i : i + 14
|
90
|
+
@number_formats[index] = s
|
91
|
+
end
|
92
|
+
|
93
|
+
@styles = {}
|
94
|
+
@default_style = StyleFormat.new
|
95
|
+
|
96
|
+
# Store the 6 parameters of the default_style
|
97
|
+
@default_format = add_style(@default_style)[0]
|
98
|
+
end
|
99
|
+
|
100
|
+
def add(style)
|
101
|
+
if style.nil?
|
102
|
+
0x10 # Return the index of the default style.
|
103
|
+
else
|
104
|
+
add_style(style)[1] # Return the index of the style just stored.
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def number_format_index(number_format_string)
|
109
|
+
index = @number_formats.index(number_format_string)
|
110
|
+
if index.nil?
|
111
|
+
# TODO implement regex to check if valid string
|
112
|
+
index = FIRST_USER_DEFINED_NUM_FORMAT_INDEX + @number_formats.length - STANDARD_NUMBER_FORMATS.length
|
113
|
+
@number_formats[index] = number_format_string
|
114
|
+
end
|
115
|
+
index
|
116
|
+
end
|
117
|
+
|
118
|
+
def font_index(font)
|
119
|
+
index = @fonts.index(font)
|
120
|
+
if index.nil?
|
121
|
+
index = @fonts.length + 1
|
122
|
+
@fonts[index] = font
|
123
|
+
end
|
124
|
+
index
|
125
|
+
end
|
126
|
+
|
127
|
+
def format_index(format)
|
128
|
+
index = @styles.index(format)
|
129
|
+
if index.nil?
|
130
|
+
index = 0x10 + @styles.length
|
131
|
+
@styles[index] = format
|
132
|
+
end
|
133
|
+
index
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
# This is private, please use add(style) instead.
|
138
|
+
def add_style(style)
|
139
|
+
number_format_index = number_format_index(style.number_format_string)
|
140
|
+
font_index = font_index(style.font)
|
141
|
+
|
142
|
+
format = [font_index, number_format_index, style.alignment, style.borders, style.pattern, style.protection]
|
143
|
+
[format, format_index(format)]
|
144
|
+
end
|
145
|
+
|
146
|
+
public
|
147
|
+
def to_biff
|
148
|
+
fonts_biff + number_formats_biff + cell_styles_biff + StyleRecord.new.to_biff
|
149
|
+
end
|
150
|
+
|
151
|
+
# TODO use inject here?
|
152
|
+
def fonts_biff
|
153
|
+
result = ''
|
154
|
+
@fonts.sort.each do |i, f|
|
155
|
+
result += f.to_biff
|
156
|
+
end
|
157
|
+
result
|
158
|
+
end
|
159
|
+
|
160
|
+
def number_formats_biff
|
161
|
+
result = ''
|
162
|
+
@number_formats.sort.each do |i, f|
|
163
|
+
next if i < FIRST_USER_DEFINED_NUM_FORMAT_INDEX
|
164
|
+
result += NumberFormatRecord.new(i, f).to_biff
|
165
|
+
end
|
166
|
+
result
|
167
|
+
end
|
168
|
+
|
169
|
+
def cell_styles_biff
|
170
|
+
result = ''
|
171
|
+
0.upto(15) do |i|
|
172
|
+
result += XFRecord.new(@default_format, 'style').to_biff
|
173
|
+
end
|
174
|
+
@styles.sort.each do |i, f|
|
175
|
+
result += XFRecord.new(f).to_biff
|
176
|
+
end
|
177
|
+
result
|
178
|
+
end
|
179
|
+
end
|
data/lib/surpass.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module Surpass
|
2
|
+
|
3
|
+
# :stopdoc:
|
4
|
+
VERSION = '0.0.3'
|
5
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
6
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
7
|
+
# :startdoc:
|
8
|
+
|
9
|
+
# Returns the version string for the library.
|
10
|
+
#
|
11
|
+
def self.version
|
12
|
+
VERSION
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the library path for the module. If any arguments are given,
|
16
|
+
# they will be joined to the end of the libray path using
|
17
|
+
# <tt>File.join</tt>.
|
18
|
+
#
|
19
|
+
def self.libpath( *args )
|
20
|
+
args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the lpath for the module. If any arguments are given,
|
24
|
+
# they will be joined to the end of the path using
|
25
|
+
# <tt>File.join</tt>.
|
26
|
+
#
|
27
|
+
def self.path( *args )
|
28
|
+
args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Utility method used to require all files ending in .rb that lie in the
|
32
|
+
# directory below this file that has the same name as the filename passed
|
33
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
34
|
+
# the _filename_ does not have to be equivalent to the directory.
|
35
|
+
#
|
36
|
+
def self.require_all_libs_relative_to( fname, dir = "." )
|
37
|
+
dir ||= ::File.basename(fname, '.*')
|
38
|
+
search_me = ::File.expand_path(
|
39
|
+
::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
40
|
+
|
41
|
+
Dir.glob(search_me).sort.each do |rb|
|
42
|
+
next if File.basename(rb) === File.basename(__FILE__) # skip surpass.rb
|
43
|
+
require rb
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end # module Surpass
|
48
|
+
|
49
|
+
Surpass.require_all_libs_relative_to(__FILE__)
|
50
|
+
|
51
|
+
require 'date'
|
data/lib/utilities.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
module Utilities
|
2
|
+
# For ease of comparing with pyExcelerator output values
|
3
|
+
# python seems to automatically decode to hex values
|
4
|
+
def hex_array_to_binary_string(array_of_hex_values)
|
5
|
+
[array_of_hex_values.collect {|h| [sprintf("%02x", h)]}.join].pack('H*')
|
6
|
+
end
|
7
|
+
|
8
|
+
def binary_string_to_hex_array(binary_string)
|
9
|
+
binary_string.unpack("H*")
|
10
|
+
end
|
11
|
+
|
12
|
+
def points_to_pixels(points)
|
13
|
+
points*(4.0/3)
|
14
|
+
end
|
15
|
+
|
16
|
+
def pixels_to_points(pixels)
|
17
|
+
pixels * (3.0 / 4)
|
18
|
+
end
|
19
|
+
|
20
|
+
def twips_to_pixels(twips)
|
21
|
+
twips / 15.0
|
22
|
+
end
|
23
|
+
|
24
|
+
def pixels_to_twips(pixels)
|
25
|
+
pixels * 15.0
|
26
|
+
end
|
27
|
+
|
28
|
+
def as_excel_date(date)
|
29
|
+
date = DateTime.parse(date.strftime("%c")) if date.is_a?(Time)
|
30
|
+
excel_date = (date - Date.civil(1899, 12, 31)).to_f
|
31
|
+
excel_date += 1 if excel_date > 59 # Add a day for Excel's missing leap day in 1900
|
32
|
+
excel_date
|
33
|
+
end
|
34
|
+
|
35
|
+
def mock_unicode_string(s)
|
36
|
+
[s.length, 0].pack('vC') + s
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def as_boolean(input)
|
41
|
+
case input
|
42
|
+
when 1, true
|
43
|
+
true
|
44
|
+
when 0, false
|
45
|
+
false
|
46
|
+
else
|
47
|
+
raise "Can't convert #{input} from excel boolean!"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def as_numeric(input)
|
52
|
+
case input
|
53
|
+
when true, 1
|
54
|
+
1
|
55
|
+
when false, 0
|
56
|
+
0
|
57
|
+
else
|
58
|
+
raise "Can't convert #{input} to excel boolean!"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Mimic python's "hex" function 0x00
|
63
|
+
def hex(value)
|
64
|
+
"0x" + value.to_s(16)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def String.random_alphanumeric(size=16)
|
69
|
+
s = ""
|
70
|
+
size.times { s << (i = Kernel.rand(62); i += ((i < 10) ? 48 : ((i < 36) ? 55 : 61 ))).chr }
|
71
|
+
s
|
72
|
+
end
|
73
|
+
|
74
|
+
class TrueClass
|
75
|
+
def to_i
|
76
|
+
1
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class FalseClass
|
81
|
+
def to_i
|
82
|
+
0
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
include Utilities
|
data/lib/workbook.rb
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
class Workbook
|
2
|
+
MACROS = {
|
3
|
+
'Consolidate_Area' => 0x00,
|
4
|
+
'Auto_Open' => 0x01,
|
5
|
+
'Auto_Close' => 0x02,
|
6
|
+
'Extract' => 0x03,
|
7
|
+
'Database' => 0x04,
|
8
|
+
'Criteria' => 0x05,
|
9
|
+
'Print_Area' => 0x06,
|
10
|
+
'Print_Titles' => 0x07, # in the docs it says Pint_Titles, I think its a mistake
|
11
|
+
'Recorder' => 0x08,
|
12
|
+
'Data_Form' => 0x09,
|
13
|
+
'Auto_Activate' => 0x0A,
|
14
|
+
'Auto_Deactivate' => 0x0B,
|
15
|
+
'Sheet_Title' => 0x0C,
|
16
|
+
'_FilterDatabase' => 0x0D
|
17
|
+
}
|
18
|
+
|
19
|
+
attr_accessor :owner
|
20
|
+
attr_accessor :country_code
|
21
|
+
attr_accessor :wnd_protect
|
22
|
+
attr_accessor :obj_protect
|
23
|
+
attr_accessor :protect
|
24
|
+
attr_accessor :backup_on_save
|
25
|
+
attr_accessor :styles
|
26
|
+
attr_accessor :sst
|
27
|
+
|
28
|
+
def hpos_twips=(value)
|
29
|
+
@hpos_twips = value & 0xFFFF
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :vpos_twips
|
33
|
+
def vpos_twips=(value)
|
34
|
+
@vpos_twips = value & 0xFFFF
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :width_twips
|
38
|
+
def width_twips=(value)
|
39
|
+
@width_twips = value & 0xFFFF
|
40
|
+
end
|
41
|
+
|
42
|
+
attr_reader :height_twips
|
43
|
+
def height_twips=(value)
|
44
|
+
@height_twips = value & 0xFFFF
|
45
|
+
end
|
46
|
+
|
47
|
+
attr_reader :active_sheet
|
48
|
+
def active_sheet=(value)
|
49
|
+
@active_sheet = value & 0xFFFF
|
50
|
+
@first_tab_index = @active_sheet
|
51
|
+
end
|
52
|
+
|
53
|
+
attr_reader :tab_width_twips
|
54
|
+
def tab_width_twips=(value)
|
55
|
+
@tab_width_twips = value & 0xFFFF
|
56
|
+
end
|
57
|
+
|
58
|
+
attr_reader :default_style
|
59
|
+
|
60
|
+
def initialize(filename = nil)
|
61
|
+
@owner = 'None'
|
62
|
+
@wnd_protect = 0
|
63
|
+
@obj_protect = 0
|
64
|
+
@protect = 0
|
65
|
+
@backup_on_save = 0
|
66
|
+
|
67
|
+
@hpos_twips = 0x01E0
|
68
|
+
@vpos_twips = 0x005A
|
69
|
+
@width_twips = 0x3FCF
|
70
|
+
@height_twips = 0x2A4E
|
71
|
+
|
72
|
+
@active_sheet = 0
|
73
|
+
@first_tab_index = 0
|
74
|
+
@selected_tabs = 0x01
|
75
|
+
@tab_width_twips = 0x0258
|
76
|
+
|
77
|
+
@wnd_hidden = false
|
78
|
+
@wnd_mini = false
|
79
|
+
@hscroll_visible = true
|
80
|
+
@vscroll_visible = true
|
81
|
+
@tabs_visible = true
|
82
|
+
|
83
|
+
@styles = ::StyleCollection.new
|
84
|
+
|
85
|
+
@dates_1904 = false
|
86
|
+
@use_cell_values = true
|
87
|
+
|
88
|
+
@sst = SharedStringTable.new
|
89
|
+
|
90
|
+
@worksheets = []
|
91
|
+
@names = []
|
92
|
+
@refs = []
|
93
|
+
|
94
|
+
@filename = filename
|
95
|
+
end
|
96
|
+
|
97
|
+
def add_sheet(name = nil)
|
98
|
+
name ||= "Sheet#{@worksheets.length + 1}"
|
99
|
+
s = Worksheet.new(name, self)
|
100
|
+
@worksheets << s
|
101
|
+
s
|
102
|
+
end
|
103
|
+
|
104
|
+
def print_area(sheetnum, rstart, rend, cstart, cend)
|
105
|
+
if !sheetnum.is_a?(Integer)
|
106
|
+
i = 0
|
107
|
+
@worksheets.each_with_index do |w, i|
|
108
|
+
sheetnum = i+1 if w.name === sheetnum
|
109
|
+
break if sheetnum.is_a?(Integer)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
options = 0x0020 # see Options Flags for Name record
|
114
|
+
|
115
|
+
# FIXME: this is just a bad hack, need to use Formula to make the rpn
|
116
|
+
#~ rpn = ExcelFormula.Formula('').rpn()[2:] # minus the size field
|
117
|
+
rpn = [0x3B, 0x0000, rstart, rend, cstart, cend].pack('Cv5')
|
118
|
+
args = [options, 0x00, MACROS['Print_Area'], sheetnum, rpn]
|
119
|
+
@names << NameRecord.new(*args).to_biff
|
120
|
+
end
|
121
|
+
|
122
|
+
def to_biff
|
123
|
+
raise "You cannot save a workbook with no worksheets" if @worksheets.empty?
|
124
|
+
|
125
|
+
section_1_array = []
|
126
|
+
section_1_array << Biff8BOFRecord.new(Biff8BOFRecord::BOOK_GLOBAL).to_biff
|
127
|
+
section_1_array << InterfaceHeaderRecord.new.to_biff
|
128
|
+
section_1_array << MMSRecord.new.to_biff
|
129
|
+
section_1_array << InterfaceEndRecord.new.to_biff
|
130
|
+
section_1_array << WriteAccessRecord.new(owner).to_biff
|
131
|
+
section_1_array << CodepageBiff8Record.new.to_biff
|
132
|
+
section_1_array << DSFRecord.new.to_biff
|
133
|
+
section_1_array << TabIDRecord.new(@worksheets.length).to_biff
|
134
|
+
section_1_array << FnGroupCountRecord.new.to_biff
|
135
|
+
section_1_array << WindowProtectRecord.new(as_numeric(@wnd_protect)).to_biff
|
136
|
+
section_1_array << ProtectRecord.new(as_numeric(@protect)).to_biff
|
137
|
+
section_1_array << ObjectProtectRecord.new(as_numeric(@obj_protect)).to_biff
|
138
|
+
section_1_array << PasswordRecord.new.to_biff
|
139
|
+
section_1_array << Prot4RevRecord.new.to_biff
|
140
|
+
section_1_array << Prot4RevPassRecord.new.to_biff
|
141
|
+
section_1_array << BackupRecord.new(@backup_on_save).to_biff
|
142
|
+
section_1_array << HideObjRecord.new.to_biff
|
143
|
+
section_1_array << window_1_record
|
144
|
+
section_1_array << DateModeRecord.new(@dates_1904).to_biff
|
145
|
+
section_1_array << PrecisionRecord.new(@use_cell_values).to_biff
|
146
|
+
section_1_array << RefreshAllRecord.new.to_biff
|
147
|
+
section_1_array << BookBoolRecord.new.to_biff
|
148
|
+
section_1_array << @styles.to_biff
|
149
|
+
section_1_array << '' # Palette
|
150
|
+
section_1_array << UseSelfsRecord.new.to_biff
|
151
|
+
section_1 = section_1_array.join
|
152
|
+
|
153
|
+
section_3_array = []
|
154
|
+
section_3_array << CountryRecord.new(@country_code, @country_code).to_biff unless @country_code.nil?
|
155
|
+
# section_3_array << InternalReferenceSupBookRecord.new(@worksheets.length).to_biff
|
156
|
+
# section_3_array << ExternSheetRecord.new(@refs).to_biff
|
157
|
+
# section_3_array << @names.collect {|n| n.to_biff}.join
|
158
|
+
section_3_array << @sst.to_biff
|
159
|
+
section_3 = section_3_array.join
|
160
|
+
|
161
|
+
section_4 = '' # ExtSSTRecord
|
162
|
+
section_5 = EOFRecord.new.to_biff
|
163
|
+
|
164
|
+
@worksheets[@active_sheet].selected = true
|
165
|
+
worksheet_biff_data = @worksheets.collect {|w| w.to_biff }
|
166
|
+
worksheet_biff_data_lengths = worksheet_biff_data.collect {|w| w.length }
|
167
|
+
section_6 = worksheet_biff_data.join
|
168
|
+
|
169
|
+
# Need to know how long the bound sheet records will be
|
170
|
+
boundsheet_data_lengths = @worksheets.collect {|w| BoundSheetRecord.new(0x00, w.visibility, w.name).to_biff.length }
|
171
|
+
total_boundsheet_data_length = boundsheet_data_lengths.inject(0) {|sum, l| sum + l}
|
172
|
+
start_position = section_1.length + total_boundsheet_data_length + section_3.length + section_4.length + section_5.length
|
173
|
+
|
174
|
+
boundsheet_records = []
|
175
|
+
@worksheets.each_with_index do |w, i|
|
176
|
+
boundsheet_records << BoundSheetRecord.new(start_position, w.visibility, w.name).to_biff
|
177
|
+
start_position += worksheet_biff_data_lengths[i]
|
178
|
+
end
|
179
|
+
|
180
|
+
section_2 = boundsheet_records.join
|
181
|
+
section_1 + section_2 + section_3 + section_4 + section_5 + section_6
|
182
|
+
end
|
183
|
+
|
184
|
+
def window_1_record
|
185
|
+
flags = 0
|
186
|
+
flags |= (as_numeric(@wnd_hidden)) << 0
|
187
|
+
flags |= (as_numeric(@wnd_mini)) << 1
|
188
|
+
flags |= (as_numeric(@hscroll_visible)) << 3
|
189
|
+
flags |= (as_numeric(@vscroll_visible)) << 4
|
190
|
+
flags |= (as_numeric(@tabs_visible)) << 5
|
191
|
+
|
192
|
+
args = [@hpos_twips, @vpos_twips, @width_twips, @height_twips, flags, @active_sheet, @first_tab_index, @selected_tabs, @tab_width_twips]
|
193
|
+
Window1Record.new(*args).to_biff
|
194
|
+
end
|
195
|
+
|
196
|
+
def data
|
197
|
+
doc = ExcelDocument.new
|
198
|
+
doc.data(to_biff)
|
199
|
+
end
|
200
|
+
|
201
|
+
def save(filename = nil)
|
202
|
+
@filename = filename unless filename.nil?
|
203
|
+
doc = ExcelDocument.new
|
204
|
+
doc.save(@filename, to_biff)
|
205
|
+
end
|
206
|
+
end
|