surpass 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/History.txt +0 -0
  2. data/README.txt +133 -0
  3. data/Rakefile +35 -0
  4. data/examples/big-16mb.rb +25 -0
  5. data/examples/big-random-strings.rb +28 -0
  6. data/examples/blanks.rb +34 -0
  7. data/examples/col_width.rb +16 -0
  8. data/examples/dates.rb +31 -0
  9. data/examples/format.rb +23 -0
  10. data/examples/hello-world.rb +9 -0
  11. data/examples/image.rb +10 -0
  12. data/examples/merged.rb +36 -0
  13. data/examples/merged0.rb +27 -0
  14. data/examples/merged1.rb +99 -0
  15. data/examples/num_formats.rb +55 -0
  16. data/examples/numbers.rb +24 -0
  17. data/examples/outline.rb +110 -0
  18. data/examples/panes.rb +48 -0
  19. data/examples/protection.rb +132 -0
  20. data/examples/python.bmp +0 -0
  21. data/examples/row_styles.rb +16 -0
  22. data/examples/row_styles_empty.rb +15 -0
  23. data/examples/set_cell_and_range_style.rb +12 -0
  24. data/examples/wrapped-text.rb +13 -0
  25. data/examples/write_arrays.rb +16 -0
  26. data/examples/ws_props.rb +80 -0
  27. data/lib/biff_record.rb +2168 -0
  28. data/lib/bitmap.rb +218 -0
  29. data/lib/cell.rb +214 -0
  30. data/lib/chart.rb +16 -0
  31. data/lib/column.rb +40 -0
  32. data/lib/document.rb +406 -0
  33. data/lib/excel_formula.rb +6 -0
  34. data/lib/excel_magic.rb +1013 -0
  35. data/lib/formatting.rb +554 -0
  36. data/lib/row.rb +137 -0
  37. data/lib/style.rb +179 -0
  38. data/lib/surpass.rb +51 -0
  39. data/lib/utilities.rb +86 -0
  40. data/lib/workbook.rb +206 -0
  41. data/lib/worksheet.rb +561 -0
  42. data/spec/biff_record_spec.rb +268 -0
  43. data/spec/cell_spec.rb +56 -0
  44. data/spec/data/random-strings.txt +10000 -0
  45. data/spec/document_spec.rb +168 -0
  46. data/spec/excel_formula_spec.rb +0 -0
  47. data/spec/formatting_spec.rb +53 -0
  48. data/spec/reference/P-0508-0000507647-3280-5298.xls +0 -0
  49. data/spec/reference/all-cell-styles.bin +0 -0
  50. data/spec/reference/all-number-formats.bin +0 -0
  51. data/spec/reference/all-styles.bin +0 -0
  52. data/spec/reference/mini.xls +0 -0
  53. data/spec/row_spec.rb +19 -0
  54. data/spec/spec_helper.rb +10 -0
  55. data/spec/style_spec.rb +89 -0
  56. data/spec/utilities_spec.rb +57 -0
  57. data/spec/workbook_spec.rb +48 -0
  58. data/spec/worksheet_spec.rb +0 -0
  59. data/stats/cloc.txt +8 -0
  60. data/stats/rcov.txt +0 -0
  61. data/stats/specdoc.txt +158 -0
  62. data/surpass-manual-0-0-3.pdf +0 -0
  63. data/surpass.gemspec +34 -0
  64. data/tasks/ann.rake +80 -0
  65. data/tasks/bones.rake +20 -0
  66. data/tasks/excel.rake +6 -0
  67. data/tasks/gem.rake +201 -0
  68. data/tasks/git.rake +40 -0
  69. data/tasks/metrics.rake +42 -0
  70. data/tasks/notes.rake +27 -0
  71. data/tasks/post_load.rake +34 -0
  72. data/tasks/rdoc.rake +51 -0
  73. data/tasks/rubyforge.rake +55 -0
  74. data/tasks/setup.rb +292 -0
  75. data/tasks/spec.rake +54 -0
  76. data/tasks/svn.rake +47 -0
  77. data/tasks/test.rake +40 -0
  78. 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