surpass 0.0.3
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/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/formatting.rb
ADDED
@@ -0,0 +1,554 @@
|
|
1
|
+
module Formatting
|
2
|
+
COLOURS = {
|
3
|
+
'aqua' => 0x31,
|
4
|
+
'black' => 0x08,
|
5
|
+
'blue' => 0x0C,
|
6
|
+
'blue-grey' => 0x36,
|
7
|
+
'bright-green' => 0xb,
|
8
|
+
'brown' => 0x3c,
|
9
|
+
'coral' => 0x1d,
|
10
|
+
'cornflower-blue' => 0x18,
|
11
|
+
'cyan' => 0x0F,
|
12
|
+
'dark-blue' => 0x12,
|
13
|
+
'dark-green' => 0x3a,
|
14
|
+
'dark-red' => 0x10,
|
15
|
+
'dark-teal' => 0x38,
|
16
|
+
'dark-yellow' => 0x13,
|
17
|
+
'fuchsia' => 0x0E,
|
18
|
+
'gold' => 0x33,
|
19
|
+
'gray' => 0x17,
|
20
|
+
'grey' => 0x17,
|
21
|
+
'green' => 0x11,
|
22
|
+
'grey-25-percent' => 0x16,
|
23
|
+
'grey-40-percent' => 0x37,
|
24
|
+
'grey-50-percent' => 0x17,
|
25
|
+
'grey-80-percent' => 0x3f,
|
26
|
+
'indigo' => 0x3e,
|
27
|
+
'lavender' => 0x2e,
|
28
|
+
'lemon-chiffon' => 0x1a,
|
29
|
+
'light-blue' => 0x30,
|
30
|
+
'light-cornflower-blue' => 0x1f,
|
31
|
+
'light-green' => 0x2a,
|
32
|
+
'light-orange' => 0x34,
|
33
|
+
'light-turquoise' => 0x29,
|
34
|
+
'light-yellow' => 0x2b,
|
35
|
+
'lime' => 0x0B,
|
36
|
+
'lime' => 0x32,
|
37
|
+
'magenta' => 0x0E,
|
38
|
+
'maroon' => 0x19,
|
39
|
+
'navy' => 0x12,
|
40
|
+
'olive-green' => 0x3b,
|
41
|
+
'orange' => 0x35,
|
42
|
+
'orchid' => 0x1c,
|
43
|
+
'pale-blue' => 0x2c,
|
44
|
+
'pink' => 0x21,
|
45
|
+
'pink' => 0xe,
|
46
|
+
'plum' => 0x3d,
|
47
|
+
'purple' => 0x14,
|
48
|
+
'red' => 0x0A,
|
49
|
+
'rose' => 0x2d,
|
50
|
+
'royal-blue' => 0x1e,
|
51
|
+
'sea-green' => 0x39,
|
52
|
+
'silver' => 0x16,
|
53
|
+
'sky-blue' => 0x28,
|
54
|
+
'tan' => 0x2f,
|
55
|
+
'teal' => 0x15,
|
56
|
+
'turquoise' => 0xf,
|
57
|
+
'violet' => 0x14,
|
58
|
+
'white' => 0x09,
|
59
|
+
'yellow' => 0x0D
|
60
|
+
}
|
61
|
+
|
62
|
+
COLORS = COLOURS
|
63
|
+
end
|
64
|
+
|
65
|
+
class Font
|
66
|
+
ESCAPEMENT_NONE = 0x00
|
67
|
+
ESCAPEMENT_SUPERSCRIPT = 0x01
|
68
|
+
ESCAPEMENT_SUBSCRIPT = 0x02
|
69
|
+
|
70
|
+
UNDERLINE_NONE = 0x00
|
71
|
+
UNDERLINE_SINGLE = 0x01
|
72
|
+
UNDERLINE_SINGLE_ACC = 0x21
|
73
|
+
UNDERLINE_DOUBLE = 0x02
|
74
|
+
UNDERLINE_DOUBLE_ACC = 0x22
|
75
|
+
|
76
|
+
FAMILY_NONE = 0x00
|
77
|
+
FAMILY_ROMAN = 0x01
|
78
|
+
FAMILY_SWISS = 0x02
|
79
|
+
FAMILY_MODERN = 0x03
|
80
|
+
FAMILY_SCRIPT = 0x04
|
81
|
+
FAMILY_DECORATIVE = 0x05
|
82
|
+
|
83
|
+
CHARSET_ANSI_LATIN = 0x00
|
84
|
+
CHARSET_SYS_DEFAULT = 0x01
|
85
|
+
CHARSET_SYMBOL = 0x02
|
86
|
+
CHARSET_APPLE_ROMAN = 0x4D
|
87
|
+
CHARSET_ANSI_JAP_SHIFT_JIS = 0x80
|
88
|
+
CHARSET_ANSI_KOR_HANGUL = 0x81
|
89
|
+
CHARSET_ANSI_KOR_JOHAB = 0x82
|
90
|
+
CHARSET_ANSI_CHINESE_GBK = 0x86
|
91
|
+
CHARSET_ANSI_CHINESE_BIG5 = 0x88
|
92
|
+
CHARSET_ANSI_GREEK = 0xA1
|
93
|
+
CHARSET_ANSI_TURKISH = 0xA2
|
94
|
+
CHARSET_ANSI_VIETNAMESE = 0xA3
|
95
|
+
CHARSET_ANSI_HEBREW = 0xB1
|
96
|
+
CHARSET_ANSI_ARABIC = 0xB2
|
97
|
+
CHARSET_ANSI_BALTIC = 0xBA
|
98
|
+
CHARSET_ANSI_CYRILLIC = 0xCC
|
99
|
+
CHARSET_ANSI_THAI = 0xDE
|
100
|
+
CHARSET_ANSI_LATIN_II = 0xEE
|
101
|
+
CHARSET_OEM_LATIN_I = 0xFF
|
102
|
+
|
103
|
+
PLAIN = 0x00
|
104
|
+
BOLD = 0x01
|
105
|
+
ITALIC = 0x02
|
106
|
+
UNDERLINE = 0x04
|
107
|
+
STRUCK_OUT = 0x08
|
108
|
+
OUTLINE = 0x010
|
109
|
+
SHADOW = 0x020
|
110
|
+
|
111
|
+
attr_accessor :height
|
112
|
+
attr_accessor :italic
|
113
|
+
attr_accessor :struck_out
|
114
|
+
attr_accessor :outline
|
115
|
+
attr_accessor :shadow
|
116
|
+
attr_accessor :colour_index
|
117
|
+
attr_accessor :bold
|
118
|
+
attr_accessor :weight # In practice, seems to be only 400 = normal, 700 = bold so just use bold = true.
|
119
|
+
attr_accessor :escapement
|
120
|
+
attr_accessor :charset
|
121
|
+
attr_accessor :name
|
122
|
+
|
123
|
+
attr_reader :family
|
124
|
+
attr_reader :underline
|
125
|
+
|
126
|
+
def initialize(hash = {})
|
127
|
+
@height = 200 # font size 10
|
128
|
+
@italic = false
|
129
|
+
@struck_out = false
|
130
|
+
@outline = false
|
131
|
+
@shadow = false
|
132
|
+
@colour_index = 0x7FFF
|
133
|
+
@bold = false
|
134
|
+
@weight = 400 # regular
|
135
|
+
@escapement = ESCAPEMENT_NONE
|
136
|
+
@charset = CHARSET_SYS_DEFAULT
|
137
|
+
@name = 'Arial'
|
138
|
+
@family = FAMILY_NONE
|
139
|
+
@underline = UNDERLINE_NONE
|
140
|
+
|
141
|
+
hash.each do |k, v|
|
142
|
+
self.send((k.to_s + '=').to_sym, v)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def family=(arg)
|
147
|
+
raise "Oops, font_family doesn't take a string. Do you want font_name instead?" if arg.is_a?(String)
|
148
|
+
@family = arg
|
149
|
+
end
|
150
|
+
|
151
|
+
# Convert font size in points to native twips
|
152
|
+
def size=(points)
|
153
|
+
@height = points * 20
|
154
|
+
end
|
155
|
+
|
156
|
+
def strikethrough=(arg)
|
157
|
+
@struck_out = arg
|
158
|
+
end
|
159
|
+
|
160
|
+
def subscript=(arg)
|
161
|
+
case arg
|
162
|
+
when TrueClass
|
163
|
+
@escapement = ESCAPEMENT_SUBSCRIPT
|
164
|
+
when FalseClass
|
165
|
+
@escapement = ESCAPEMENT_NONE
|
166
|
+
else
|
167
|
+
raise "I don't know how to set subscript to #{arg.inspect}."
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def superscript=(arg)
|
172
|
+
case arg
|
173
|
+
when TrueClass
|
174
|
+
@escapement = ESCAPEMENT_SUPERSCRIPT
|
175
|
+
when FalseClass
|
176
|
+
@escapement = ESCAPEMENT_NONE
|
177
|
+
else
|
178
|
+
raise "I don't know how to set superscript to #{arg.inspect}."
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# User-friendly underlining directives.
|
183
|
+
def underline=(arg)
|
184
|
+
case arg
|
185
|
+
when UNDERLINE_NONE, UNDERLINE_SINGLE, UNDERLINE_SINGLE_ACC, UNDERLINE_DOUBLE, UNDERLINE_DOUBLE_ACC
|
186
|
+
@underline = arg
|
187
|
+
when nil
|
188
|
+
@underline ||= UNDERLINE_NONE
|
189
|
+
when TrueClass
|
190
|
+
@underline = UNDERLINE_SINGLE
|
191
|
+
when FalseClass
|
192
|
+
@underline = UNDERLINE_NONE
|
193
|
+
when :none
|
194
|
+
@underline = UNDERLINE_NONE
|
195
|
+
when :single
|
196
|
+
@underline = UNDERLINE_SINGLE
|
197
|
+
when :single_acc, :single_accounting
|
198
|
+
@underline = UNDERLINE_SINGLE_ACC
|
199
|
+
when :double
|
200
|
+
@underline = UNDERLINE_DOUBLE
|
201
|
+
when :double_acc, :double_accounting
|
202
|
+
@underline = UNDERLINE_DOUBLE_ACC
|
203
|
+
else
|
204
|
+
raise "I don't know how to set underline to #{arg.inspect}."
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def colour_index_from_name(colour_name)
|
209
|
+
Formatting::COLOURS[colour_name.to_s]
|
210
|
+
end
|
211
|
+
|
212
|
+
def colour=(colour_name)
|
213
|
+
new_colour = colour_index_from_name(colour_name)
|
214
|
+
if new_colour.nil?
|
215
|
+
raise "Invalid Colour #{colour_name}"
|
216
|
+
else
|
217
|
+
@colour_index = new_colour
|
218
|
+
end
|
219
|
+
end
|
220
|
+
alias :color= :colour=
|
221
|
+
|
222
|
+
def to_biff
|
223
|
+
options = PLAIN
|
224
|
+
options |= BOLD if @bold
|
225
|
+
options |= ITALIC if @italic
|
226
|
+
options |= UNDERLINE if (@underline != UNDERLINE_NONE)
|
227
|
+
options |= STRUCK_OUT if @struck_out
|
228
|
+
options |= OUTLINE if @outline
|
229
|
+
options |= SHADOW if @shadow
|
230
|
+
|
231
|
+
@weight = 700 if @bold
|
232
|
+
args = [@height, options, @colour_index, @weight, @escapement, @underline, @family, @charset, @name]
|
233
|
+
FontRecord.new(*args).to_biff
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
class Alignment
|
238
|
+
HORZ_GENERAL = 0x00
|
239
|
+
HORZ_LEFT = 0x01
|
240
|
+
HORZ_CENTER = 0x02
|
241
|
+
HORZ_RIGHT = 0x03
|
242
|
+
HORZ_FILLED = 0x04
|
243
|
+
HORZ_JUSTIFIED = 0x05 # BIFF4-BIFF8X
|
244
|
+
HORZ_CENTER_ACROSS_SEL = 0x06 # Centred across selection (BIFF4-BIFF8X)
|
245
|
+
HORZ_DISTRIBUTED = 0x07 # Distributed (BIFF8X)
|
246
|
+
|
247
|
+
VERT_TOP = 0x00
|
248
|
+
VERT_CENTER = 0x01
|
249
|
+
VERT_BOTTOM = 0x02
|
250
|
+
VERT_JUSTIFIED = 0x03 # Justified (BIFF5-BIFF8X)
|
251
|
+
VERT_DISTRIBUTED = 0x04 # Distributed (BIFF8X)
|
252
|
+
|
253
|
+
DIRECTION_GENERAL = 0x00 # BIFF8X
|
254
|
+
DIRECTION_LR = 0x01
|
255
|
+
DIRECTION_RL = 0x02
|
256
|
+
|
257
|
+
ORIENTATION_NOT_ROTATED = 0x00
|
258
|
+
ORIENTATION_STACKED = 0x01
|
259
|
+
ORIENTATION_90_CC = 0x02
|
260
|
+
ORIENTATION_90_CW = 0x03
|
261
|
+
|
262
|
+
ROTATION_0_ANGLE = 0x00
|
263
|
+
ROTATION_STACKED = 0xFF
|
264
|
+
|
265
|
+
WRAP_AT_RIGHT = 0x01
|
266
|
+
NOT_WRAP_AT_RIGHT = 0x00
|
267
|
+
|
268
|
+
SHRINK_TO_FIT = 0x01
|
269
|
+
NOT_SHRINK_TO_FIT = 0x00
|
270
|
+
|
271
|
+
attr_accessor :horz
|
272
|
+
attr_accessor :vert
|
273
|
+
attr_accessor :dire
|
274
|
+
attr_accessor :orie
|
275
|
+
attr_accessor :rota
|
276
|
+
attr_accessor :shri
|
277
|
+
attr_accessor :inde
|
278
|
+
attr_accessor :merg
|
279
|
+
|
280
|
+
attr_reader :wrap
|
281
|
+
|
282
|
+
def initialize(hash = {})
|
283
|
+
# Initialize to defaults.
|
284
|
+
@horz = HORZ_GENERAL
|
285
|
+
@vert = VERT_BOTTOM
|
286
|
+
@wrap = NOT_WRAP_AT_RIGHT
|
287
|
+
@dire = DIRECTION_GENERAL
|
288
|
+
@orie = ORIENTATION_NOT_ROTATED
|
289
|
+
@rota = ROTATION_0_ANGLE
|
290
|
+
@shri = NOT_SHRINK_TO_FIT
|
291
|
+
@inde = 0
|
292
|
+
@merg = 0
|
293
|
+
|
294
|
+
# Allow defaults to be overridden in hash. Where there is no :align key in hash,
|
295
|
+
# this just leaves the default value in place.
|
296
|
+
self.align = hash[:align]
|
297
|
+
self.wrap = hash[:wrap]
|
298
|
+
end
|
299
|
+
|
300
|
+
# Don't support passing constants here because :horz and :vert are exposed
|
301
|
+
# so if someone wants to use nasty HORZ_RIGHT they can do align.vert = HORZ_RIGHT
|
302
|
+
def align=(alignment_directives)
|
303
|
+
if alignment_directives =~ /\s/
|
304
|
+
args = alignment_directives.split
|
305
|
+
else
|
306
|
+
args = [alignment_directives] # there's just 1 here
|
307
|
+
end
|
308
|
+
|
309
|
+
args.each do |a|
|
310
|
+
case a
|
311
|
+
when 'right'
|
312
|
+
@horz = HORZ_RIGHT
|
313
|
+
when 'left'
|
314
|
+
@horz = HORZ_LEFT
|
315
|
+
when 'center', 'centre'
|
316
|
+
@horz = HORZ_CENTER
|
317
|
+
when 'general'
|
318
|
+
@horz = HORZ_GENERAL
|
319
|
+
when 'filled'
|
320
|
+
@horz = HORZ_FILLED
|
321
|
+
when 'justify'
|
322
|
+
@horz = HORZ_JUSTIFIED
|
323
|
+
when 'top'
|
324
|
+
@vert = VERT_TOP
|
325
|
+
when 'bottom'
|
326
|
+
@vert = VERT_BOTTOM
|
327
|
+
when nil
|
328
|
+
# Do nothing.
|
329
|
+
else
|
330
|
+
raise "I don't know how to set align to #{a.inspect}."
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def wrap=(arg)
|
336
|
+
case arg
|
337
|
+
when TrueClass, WRAP_AT_RIGHT
|
338
|
+
@wrap = WRAP_AT_RIGHT
|
339
|
+
when FalseClass, NOT_WRAP_AT_RIGHT
|
340
|
+
@wrap = NOT_WRAP_AT_RIGHT
|
341
|
+
when nil
|
342
|
+
# Do nothing.
|
343
|
+
else
|
344
|
+
raise "I don't know how to set wrap to #{arg.inspect}."
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
class Borders
|
350
|
+
attr_reader :left
|
351
|
+
attr_reader :right
|
352
|
+
attr_reader :top
|
353
|
+
attr_reader :bottom
|
354
|
+
attr_reader :diag
|
355
|
+
|
356
|
+
attr_accessor :left_colour
|
357
|
+
attr_accessor :right_colour
|
358
|
+
attr_accessor :top_colour
|
359
|
+
attr_accessor :bottom_colour
|
360
|
+
attr_accessor :diag_colour
|
361
|
+
|
362
|
+
attr_accessor :need_diag1
|
363
|
+
attr_accessor :need_diag2
|
364
|
+
|
365
|
+
NO_LINE = 0x00
|
366
|
+
THIN = 0x01
|
367
|
+
MEDIUM = 0x02
|
368
|
+
DASHED = 0x03
|
369
|
+
DOTTED = 0x04
|
370
|
+
THICK = 0x05
|
371
|
+
DOUBLE = 0x06
|
372
|
+
HAIR = 0x07
|
373
|
+
#The following for BIFF8
|
374
|
+
MEDIUM_DASHED = 0x08
|
375
|
+
THIN_DASH_DOTTED = 0x09
|
376
|
+
MEDIUM_DASH_DOTTED = 0x0A
|
377
|
+
THIN_DASH_DOT_DOTTED = 0x0B
|
378
|
+
MEDIUM_DASH_DOT_DOTTED = 0x0C
|
379
|
+
SLANTED_MEDIUM_DASH_DOTTED = 0x0D
|
380
|
+
|
381
|
+
NEED_DIAG1 = 0x01
|
382
|
+
NEED_DIAG2 = 0x01
|
383
|
+
NO_NEED_DIAG1 = 0x00
|
384
|
+
NO_NEED_DIAG2 = 0x00
|
385
|
+
|
386
|
+
# Want to keep these sorted in this order, so need nested array instead of hash.
|
387
|
+
LINE_TYPE_DIRECTIVES = [
|
388
|
+
['none', NO_LINE],
|
389
|
+
['thin', THIN],
|
390
|
+
['medium', MEDIUM],
|
391
|
+
['dashed', DASHED],
|
392
|
+
['dotted', DOTTED],
|
393
|
+
['thick', THICK],
|
394
|
+
['double', DOUBLE],
|
395
|
+
['hair', HAIR],
|
396
|
+
['medium-dashed', MEDIUM_DASHED],
|
397
|
+
['thin-dash-dotted', THIN_DASH_DOTTED],
|
398
|
+
['medium-dash-dotted', MEDIUM_DASH_DOTTED],
|
399
|
+
['thin-dash-dot-dotted', THIN_DASH_DOT_DOTTED],
|
400
|
+
['medium-dash-dot-dotted', MEDIUM_DASH_DOT_DOTTED],
|
401
|
+
['slanted-medium-dash-dotted', SLANTED_MEDIUM_DASH_DOTTED]
|
402
|
+
]
|
403
|
+
|
404
|
+
def self.line_type_directives
|
405
|
+
LINE_TYPE_DIRECTIVES.collect {|k, v| k}
|
406
|
+
end
|
407
|
+
|
408
|
+
def initialize(hash = {})
|
409
|
+
@left = NO_LINE
|
410
|
+
@right = NO_LINE
|
411
|
+
@top = NO_LINE
|
412
|
+
@bottom = NO_LINE
|
413
|
+
@diag = NO_LINE
|
414
|
+
|
415
|
+
@left_colour = 0x40
|
416
|
+
@right_colour = 0x40
|
417
|
+
@top_colour = 0x40
|
418
|
+
@bottom_colour = 0x40
|
419
|
+
@diag_colour = 0x40
|
420
|
+
|
421
|
+
@need_diag1 = NO_NEED_DIAG1
|
422
|
+
@need_diag2 = NO_NEED_DIAG2
|
423
|
+
|
424
|
+
hash.each do |k, v|
|
425
|
+
self.send((k.to_s + '=').to_sym, v)
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
def all=(directives)
|
430
|
+
self.left = directives
|
431
|
+
self.right = directives
|
432
|
+
self.top = directives
|
433
|
+
self.bottom = directives
|
434
|
+
end
|
435
|
+
|
436
|
+
def process_directives(directives)
|
437
|
+
if directives =~ /\s/
|
438
|
+
args = directives.split
|
439
|
+
else
|
440
|
+
args = [directives] # there's just 1 here, stick it in an array
|
441
|
+
end
|
442
|
+
|
443
|
+
raise "no directives given to process_directives" if args.empty? # maybe don't need this, just get thin black border? but for development I want to know if this happens.
|
444
|
+
|
445
|
+
instructions = [THIN, Formatting::COLOURS['black']]
|
446
|
+
args.each do |a|
|
447
|
+
if Formatting::COLOURS.include?(a)
|
448
|
+
instructions[1] = Formatting::COLOURS[a]
|
449
|
+
next
|
450
|
+
end
|
451
|
+
|
452
|
+
if Borders.line_type_directives.include?(a)
|
453
|
+
line_type_directives_hash = Hash[*LINE_TYPE_DIRECTIVES.flatten]
|
454
|
+
instructions[0] = line_type_directives_hash[a]
|
455
|
+
next
|
456
|
+
end
|
457
|
+
|
458
|
+
raise "I don't know how to format a border with #{a.inspect}."
|
459
|
+
end
|
460
|
+
|
461
|
+
instructions
|
462
|
+
end
|
463
|
+
|
464
|
+
def right=(directives)
|
465
|
+
@right, @right_colour = process_directives(directives)
|
466
|
+
end
|
467
|
+
|
468
|
+
def left=(directives)
|
469
|
+
@left, @left_colour = process_directives(directives)
|
470
|
+
end
|
471
|
+
|
472
|
+
def top=(directives)
|
473
|
+
@top, @top_colour = process_directives(directives)
|
474
|
+
end
|
475
|
+
|
476
|
+
def bottom=(directives)
|
477
|
+
@bottom, @bottom_colour = process_directives(directives)
|
478
|
+
end
|
479
|
+
end
|
480
|
+
# public final static short NO_FILL = 0 ;
|
481
|
+
# /** Solidly filled */
|
482
|
+
# public final static short SOLID_FOREGROUND = 1 ;
|
483
|
+
# /** Small fine dots */
|
484
|
+
# public final static short FINE_DOTS = 2 ;
|
485
|
+
# /** Wide dots */
|
486
|
+
# public final static short ALT_BARS = 3 ;
|
487
|
+
# /** Sparse dots */
|
488
|
+
# public final static short SPARSE_DOTS = 4 ;
|
489
|
+
# /** Thick horizontal bands */
|
490
|
+
# public final static short THICK_HORZ_BANDS = 5 ;
|
491
|
+
# /** Thick vertical bands */
|
492
|
+
# public final static short THICK_VERT_BANDS = 6 ;
|
493
|
+
# /** Thick backward facing diagonals */
|
494
|
+
# public final static short THICK_BACKWARD_DIAG = 7 ;
|
495
|
+
# /** Thick forward facing diagonals */
|
496
|
+
# public final static short THICK_FORWARD_DIAG = 8 ;
|
497
|
+
# /** Large spots */
|
498
|
+
# public final static short BIG_SPOTS = 9 ;
|
499
|
+
# /** Brick-like layout */
|
500
|
+
# public final static short BRICKS = 10 ;
|
501
|
+
# /** Thin horizontal bands */
|
502
|
+
# public final static short THIN_HORZ_BANDS = 11 ;
|
503
|
+
# /** Thin vertical bands */
|
504
|
+
# public final static short THIN_VERT_BANDS = 12 ;
|
505
|
+
# /** Thin backward diagonal */
|
506
|
+
# public final static short THIN_BACKWARD_DIAG = 13 ;
|
507
|
+
# /** Thin forward diagonal */
|
508
|
+
# public final static short THIN_FORWARD_DIAG = 14 ;
|
509
|
+
# /** Squares */
|
510
|
+
# public final static short SQUARES = 15 ;
|
511
|
+
# /** Diamonds */
|
512
|
+
# public final static short DIAMONDS = 16 ;
|
513
|
+
# /** Less Dots */
|
514
|
+
# public final static short LESS_DOTS = 17 ;
|
515
|
+
# /** Least Dots */
|
516
|
+
# public final static short LEAST_DOTS = 18 ;
|
517
|
+
class Pattern
|
518
|
+
NO_PATTERN = 0x00
|
519
|
+
SOLID_PATTERN = 0x01
|
520
|
+
|
521
|
+
attr_accessor :pattern
|
522
|
+
attr_accessor :pattern_fore_colour
|
523
|
+
attr_accessor :pattern_back_colour
|
524
|
+
|
525
|
+
def initialize(hash = {})
|
526
|
+
@pattern = NO_PATTERN
|
527
|
+
@pattern_fore_colour = 0x40
|
528
|
+
@pattern_back_colour = 0x41
|
529
|
+
|
530
|
+
hash.each do |k, v|
|
531
|
+
self.send((k.to_s + '=').to_sym, v)
|
532
|
+
end
|
533
|
+
end
|
534
|
+
|
535
|
+
# Convenience method to set fill colour
|
536
|
+
def colour=(arg)
|
537
|
+
colour_index = Formatting::COLOURS[arg]
|
538
|
+
raise "Invalid colour #{arg}" if colour_index.nil?
|
539
|
+
@pattern = SOLID_PATTERN
|
540
|
+
@pattern_fore_colour = colour_index
|
541
|
+
end
|
542
|
+
alias :color= :colour=
|
543
|
+
alias :fill= :colour=
|
544
|
+
end
|
545
|
+
|
546
|
+
class Protection
|
547
|
+
attr_accessor :cell_locked
|
548
|
+
attr_accessor :formula_hidden
|
549
|
+
|
550
|
+
def initialize
|
551
|
+
@cell_locked = 1
|
552
|
+
@formula_hidden = 0
|
553
|
+
end
|
554
|
+
end
|
data/lib/row.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
class Row
|
2
|
+
attr_accessor :index
|
3
|
+
attr_accessor :parent
|
4
|
+
attr_accessor :parent_wb
|
5
|
+
attr_accessor :cells
|
6
|
+
attr_accessor :min_col_index
|
7
|
+
attr_accessor :max_col_index
|
8
|
+
attr_accessor :total_str
|
9
|
+
attr_accessor :xf_index
|
10
|
+
attr_accessor :has_default_format
|
11
|
+
attr_accessor :height_in_pixels
|
12
|
+
|
13
|
+
attr_accessor :height
|
14
|
+
attr_accessor :has_default_height
|
15
|
+
attr_accessor :height_mismatch
|
16
|
+
attr_accessor :level
|
17
|
+
attr_accessor :collapse
|
18
|
+
attr_accessor :hidden
|
19
|
+
attr_accessor :space_above
|
20
|
+
attr_accessor :space_below
|
21
|
+
|
22
|
+
def initialize(index, parent_sheet)
|
23
|
+
is_int = index.is_a?(Integer)
|
24
|
+
in_range = (index >= 0) && (index <= 65535)
|
25
|
+
raise "row index #{index} is not valid" unless is_int && in_range
|
26
|
+
|
27
|
+
@index = index
|
28
|
+
@parent = parent_sheet
|
29
|
+
@parent_wb = parent_sheet.parent()
|
30
|
+
@cells = []
|
31
|
+
@min_col_index = 0
|
32
|
+
@max_col_index = 0
|
33
|
+
@total_str = 0
|
34
|
+
@xf_index = 0x0F
|
35
|
+
@has_default_format = 0
|
36
|
+
@height_in_pixels = 0x11
|
37
|
+
|
38
|
+
@height = 0x00FF
|
39
|
+
@has_default_height = 0x00
|
40
|
+
@height_mismatch = 0
|
41
|
+
@level = 0
|
42
|
+
@collapse = 0
|
43
|
+
@hidden = 0
|
44
|
+
@space_above = 0
|
45
|
+
@space_below = 0
|
46
|
+
end
|
47
|
+
|
48
|
+
def adjust_height(style)
|
49
|
+
twips = style.font.height
|
50
|
+
points = twips/20.0
|
51
|
+
# Cell height in pixels can be calcuted by following approx. formula:
|
52
|
+
# cell height in pixels = font height in points * 83/50 + 2/5
|
53
|
+
# It works when screen resolution is 96 dpi
|
54
|
+
pix = (points*83.0/50.0 + 2.0/5.0).round
|
55
|
+
@height_in_pixels = pix if (pix > @height_in_pixels)
|
56
|
+
end
|
57
|
+
|
58
|
+
def adjust_boundary_column_indexes(*args)
|
59
|
+
args.each do |a|
|
60
|
+
is_int = (a.to_i == a)
|
61
|
+
in_range = (0 <= a) && (a <= 255)
|
62
|
+
raise "invalid boundary index #{a}" unless is_int && in_range
|
63
|
+
@min_col_index = a if a < @min_col_index
|
64
|
+
@max_col_index = a if a > @max_col_index
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def style=(style)
|
69
|
+
adjust_height(style)
|
70
|
+
@xf_index = @parent_wb.styles.add(style)
|
71
|
+
@has_default_format = 1
|
72
|
+
end
|
73
|
+
|
74
|
+
def cells_count
|
75
|
+
@cells.length
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_biff
|
79
|
+
height_options = (@height & 0x07FFF)
|
80
|
+
height_options |= (@has_default_height & 0x01) << 15
|
81
|
+
|
82
|
+
options = (@level & 0x07) << 0
|
83
|
+
options |= (@collapse & 0x01) << 4
|
84
|
+
options |= (@hidden & 0x01) << 5
|
85
|
+
options |= (@height_mismatch & 0x01) << 6
|
86
|
+
options |= (@has_default_format & 0x01) << 7
|
87
|
+
options |= (0x01 & 0x01) << 8
|
88
|
+
options |= (@xf_index & 0x0FFF) << 16
|
89
|
+
options |= (@space_above & 0x01) << 28
|
90
|
+
options |= (@space_below & 0x01) << 29
|
91
|
+
|
92
|
+
args = [@index, @min_col_index, @max_col_index, height_options, options]
|
93
|
+
RowRecord.new(*args).to_biff
|
94
|
+
end
|
95
|
+
|
96
|
+
def cells_biff
|
97
|
+
cells.collect {|c| c.to_biff }.join
|
98
|
+
end
|
99
|
+
|
100
|
+
def cell(col_index)
|
101
|
+
cells.select {|c| c.index == col_index}.first
|
102
|
+
end
|
103
|
+
|
104
|
+
def write(col, label, style)
|
105
|
+
style = StyleFormat.new(style) if style.is_a?(Hash)
|
106
|
+
style_index = @parent_wb.styles.add(style)
|
107
|
+
|
108
|
+
adjust_height(style)
|
109
|
+
adjust_boundary_column_indexes(col)
|
110
|
+
case label
|
111
|
+
when TrueClass, FalseClass
|
112
|
+
@cells << BooleanCell.new(self, col, style_index, label)
|
113
|
+
when String, NilClass
|
114
|
+
if label.to_s.length == 0
|
115
|
+
@cells << BlankCell.new(self, col, style_index)
|
116
|
+
else
|
117
|
+
@cells << StringCell.new(self, col, style_index, @parent_wb.sst.add_str(label))
|
118
|
+
@total_str += 1
|
119
|
+
end
|
120
|
+
when Numeric
|
121
|
+
@cells << NumberCell.new(self, col, style_index, label)
|
122
|
+
when Date, DateTime, Time
|
123
|
+
@cells << NumberCell.new(self, col, style_index, as_excel_date(label))
|
124
|
+
when ExcelFormula
|
125
|
+
@cells << FormulaCell.new(self, col, style_index, label)
|
126
|
+
else
|
127
|
+
raise label.class.name
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def write_blanks(c1, c2, style)
|
132
|
+
raise unless c1 <= c2
|
133
|
+
adjust_height(style)
|
134
|
+
adjust_boundary_column_indexes(c1, c2)
|
135
|
+
@cells << MulBlankCell.new(self, c1, c2, @parent_wb.styles.add(style))
|
136
|
+
end
|
137
|
+
end
|