rubyXL 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/Gemfile +16 -0
  2. data/Gemfile.lock +34 -0
  3. data/LICENSE.txt +20 -0
  4. data/README +0 -0
  5. data/README.rdoc +19 -0
  6. data/Rakefile +53 -0
  7. data/VERSION +1 -0
  8. data/lib/.DS_Store +0 -0
  9. data/lib/Hash.rb +60 -0
  10. data/lib/cell.rb +360 -0
  11. data/lib/color.rb +14 -0
  12. data/lib/parser.rb +413 -0
  13. data/lib/private_class.rb +182 -0
  14. data/lib/rubyXL.rb +9 -0
  15. data/lib/test.html +1 -0
  16. data/lib/tests/test.rb +110 -0
  17. data/lib/tests/test10.rb +16 -0
  18. data/lib/tests/test2.rb +118 -0
  19. data/lib/tests/test3.rb +76 -0
  20. data/lib/tests/test4.rb +92 -0
  21. data/lib/tests/test5.rb +90 -0
  22. data/lib/tests/test6.rb +50 -0
  23. data/lib/tests/test7.rb +48 -0
  24. data/lib/tests/test8.rb +12 -0
  25. data/lib/tests/test9.rb +60 -0
  26. data/lib/workbook.rb +336 -0
  27. data/lib/worksheet.rb +1245 -0
  28. data/lib/writer/app_writer.rb +62 -0
  29. data/lib/writer/calc_chain_writer.rb +33 -0
  30. data/lib/writer/content_types_writer.rb +77 -0
  31. data/lib/writer/core_writer.rb +51 -0
  32. data/lib/writer/root_rels_writer.rb +25 -0
  33. data/lib/writer/shared_strings_writer.rb +44 -0
  34. data/lib/writer/styles_writer.rb +376 -0
  35. data/lib/writer/theme_writer.rb +346 -0
  36. data/lib/writer/workbook_rels_writer.rb +59 -0
  37. data/lib/writer/workbook_writer.rb +77 -0
  38. data/lib/writer/worksheet_writer.rb +208 -0
  39. data/lib/zip.rb +20 -0
  40. data/pkg/rubyXL-1.0.4.gem +0 -0
  41. data/rubyXL.gemspec +106 -0
  42. data/spec/lib/cell_spec.rb +359 -0
  43. data/spec/lib/color_spec.rb +14 -0
  44. data/spec/lib/hash_spec.rb +28 -0
  45. data/spec/lib/parser_spec.rb +49 -0
  46. data/spec/lib/workbook_spec.rb +51 -0
  47. data/spec/lib/worksheet_spec.rb +1650 -0
  48. metadata +222 -0
@@ -0,0 +1,1245 @@
1
+ module RubyXL
2
+ class Worksheet < PrivateClass
3
+
4
+ attr_accessor :sheet_name, :sheet_data, :cols, :merged_cells, :pane,
5
+ :validations, :sheet_view, :legacy_drawing, :extLst, :workbook, :row_styles
6
+
7
+ def initialize(workbook, sheet_name='Sheet1',sheet_data=[[nil]],cols=[], merged_cells=[])
8
+ @workbook = workbook
9
+
10
+ @sheet_name = sheet_name
11
+ @sheet_data = sheet_data
12
+ @cols = cols
13
+ @merged_cells = merged_cells
14
+ @row_styles={}
15
+ @sheet_view = {
16
+ :attributes => {
17
+ :workbookViewId => 0, :zoomScale => 100, :tabSelected => 1, :view=>'normalLayout', :zoomScaleNormal => 100
18
+ }
19
+ }
20
+ @extLst = nil
21
+ @legacy_drawing=nil
22
+ end
23
+
24
+ # allows for easier access to sheet_data
25
+ def [](row=0)
26
+ return @sheet_data[row]
27
+ end
28
+
29
+ def get_table(headers=[])
30
+ validate_workbook
31
+
32
+ if !headers.is_a?(Array)
33
+ headers = [headers]
34
+ end
35
+
36
+ row_num = find_first_row_with_content(headers)
37
+
38
+ if row_num.nil?
39
+ return nil
40
+ end
41
+
42
+ table_hash = {}
43
+ table_hash[:table] = []
44
+
45
+ headers.each do |header|
46
+ row_strings = @sheet_data[row_num].map { |cell| cell.nil? ? '' : cell.value.to_s }
47
+ header_column = row_strings.index(header)
48
+ table_hash[header.to_sym] = []
49
+
50
+ original_row = row_num + 1
51
+ current_row = original_row
52
+
53
+ cell = @sheet_data[current_row][header_column]
54
+
55
+ # makes array of hashes in table_hash[:table]
56
+ # as well as hash of arrays in table_hash[header.to_sym]
57
+ while !cell.nil? && !cell.value.nil?
58
+ table_hash[header.to_sym] << cell.value
59
+
60
+ table_index = current_row - original_row
61
+
62
+ if table_hash[:table][table_index].nil?
63
+ table_hash[:table][table_index] = {}
64
+ end
65
+
66
+ table_hash[:table][table_index][header.to_sym] = cell.value
67
+
68
+ current_row += 1
69
+ if @sheet_data[current_row].nil?
70
+ cell = nil
71
+ else
72
+ cell = @sheet_data[current_row][header_column]
73
+ end
74
+ end
75
+ end
76
+
77
+ return table_hash
78
+ end
79
+
80
+ #changes color of fill in (zer0 indexed) row
81
+ def change_row_fill(row=0,rgb='ffffff')
82
+ validate_workbook
83
+ validate_nonnegative(row)
84
+ increase_rows(row)
85
+ Color.validate_color(rgb)
86
+ if @row_styles[(Integer(row)+1).to_s].nil?
87
+ @row_styles[(Integer(row)+1).to_s] = {}
88
+ @row_styles[(Integer(row)+1).to_s][:style] = '0'
89
+ end
90
+
91
+ @row_styles[(Integer(row)+1).to_s][:style] = modify_fill(@workbook,Integer(@row_styles[(Integer(row)+1).to_s][:style]),rgb)
92
+
93
+ @sheet_data[Integer(row)].each do |c|
94
+ unless c.nil?
95
+ c.change_fill(rgb)
96
+ end
97
+ end
98
+ end
99
+
100
+ def change_row_font_name(row=0,font_name='Verdana')
101
+ change_row_font(row,Worksheet::NAME,font_name)
102
+ @workbook.fonts[font_id(@row_styles[(row+1).to_s][:style])][:font][:name][:attributes][:val] = font_name.to_s
103
+ end
104
+
105
+ def change_row_font_size(row=0,font_size=10)
106
+ change_row_font(row,Worksheet::SIZE,font_size)
107
+ @workbook.fonts[font_id(@row_styles[(row+1).to_s][:style])][:font][:sz][:attributes][:val] = font_size
108
+ end
109
+
110
+ def change_row_font_color(row=0,font_color='000000')
111
+ Color.validate_color(font_color)
112
+
113
+ change_row_font(row,Worksheet::COLOR,font_color)
114
+
115
+ font = @workbook.fonts[font_id(@row_styles[(row+1).to_s][:style])][:font]
116
+ if font[:color].nil? || font[:color][:attributes].nil?
117
+ font[:color] = { :attributes => { :rgb => nil } }
118
+ end
119
+ font[:color][:attributes][:rgb] = font_color.to_s
120
+ end
121
+
122
+ def change_row_italics(row=0,italicized=false)
123
+ change_row_font(row,Worksheet::ITALICS,italicized)
124
+ @workbook.fonts[font_id(@row_styles[(row+1).to_s][:style])][:font][:i] = italicized ? {} : nil
125
+ end
126
+
127
+ def change_row_bold(row=0,bolded=false)
128
+ change_row_font(row,Worksheet::BOLD,bolded)
129
+ @workbook.fonts[font_id(@row_styles[(row+1).to_s][:style])][:font][:b] = bolded ? {} : nil
130
+ end
131
+
132
+ def change_row_underline(row=0,underlined=false)
133
+ change_row_font(row,Worksheet::UNDERLINE,underlined)
134
+ @workbook.fonts[font_id(@row_styles[(row+1).to_s][:style])][:font][:u] = underlined ? {} : nil
135
+ end
136
+
137
+ def change_row_strikethrough(row=0,struckthrough=false)
138
+ change_row_font(row,Worksheet::STRIKETHROUGH,struckthrough)
139
+ @workbook.fonts[font_id(@row_styles[(row+1).to_s][:style])][:font][:strike] = struckthrough ? {} : nil
140
+ end
141
+
142
+ def change_row_height(row=0,height=10)
143
+ validate_workbook
144
+ validate_nonnegative(row)
145
+
146
+ increase_rows(row)
147
+
148
+ if height.to_i.to_s == height.to_s
149
+ height = Integer(height)
150
+ elsif height.to_f.to_s == height.to_s
151
+ height = Float(height)
152
+ else
153
+ raise 'You must enter a number for the height'
154
+ end
155
+
156
+ if @row_styles[(row+1).to_s].nil?
157
+ @row_styles[(row+1).to_s] = {}
158
+ @row_styles[(row+1).to_s][:style] = '0'
159
+ end
160
+ @row_styles[(row+1).to_s][:height] = height
161
+ @row_styles[(row+1).to_s][:customHeight] = '1'
162
+ end
163
+
164
+ def change_row_horizontal_alignment(row=0,alignment='center')
165
+ validate_workbook
166
+ validate_nonnegative(row)
167
+ validate_horizontal_alignment(alignment)
168
+ change_row_alignment(row,alignment,true)
169
+ end
170
+
171
+ def change_row_vertical_alignment(row=0,alignment='center')
172
+ validate_workbook
173
+ validate_nonnegative(row)
174
+ validate_vertical_alignment(alignment)
175
+ change_row_alignment(row,alignment,false)
176
+ end
177
+
178
+ def change_row_border_top(row=0,weight='thin')
179
+ change_row_border(row, :top, weight)
180
+ end
181
+
182
+ def change_row_border_left(row=0,weight='thin')
183
+ change_row_border(row, :left, weight)
184
+ end
185
+
186
+ def change_row_border_right(row=0,weight='thin')
187
+ change_row_border(row, :right, weight)
188
+ end
189
+
190
+ def change_row_border_bottom(row=0,weight='thin')
191
+ change_row_border(row, :bottom, weight)
192
+ end
193
+
194
+ def change_row_border_diagonal(row=0,weight='thin')
195
+ change_row_border(row, :diagonal, weight)
196
+ end
197
+
198
+ def change_column_font_name(col=0,font_name='Verdana')
199
+ s = change_column_font(col,Worksheet::NAME,font_name)
200
+ @workbook.fonts[font_id(s)][:font][:name][:attributes][:val] = font_name.to_s
201
+ end
202
+
203
+ def change_column_font_size(col=0,font_size=10)
204
+ s = change_column_font(col,Worksheet::SIZE,font_size)
205
+ @workbook.fonts[font_id(s)][:font][:sz][:attributes][:val] = font_size
206
+ end
207
+
208
+ def change_column_font_color(col=0,font_color='000000')
209
+ Color.validate_color(font_color)
210
+ s = change_column_font(col,Worksheet::COLOR,font_color)
211
+
212
+ font = @workbook.fonts[font_id(s)][:font]
213
+ if font[:color].nil? || font[:color][:attributes].nil?
214
+ font[:color] = { :attributes => { :rgb => nil } }
215
+ end
216
+
217
+ font[:color][:attributes][:rgb] = font_color.to_s
218
+ end
219
+
220
+ def change_column_italics(col=0,italicized=false)
221
+ s = change_column_font(col,Worksheet::ITALICS,italicized)
222
+ @workbook.fonts[font_id(s)][:font][:i] = italicized ? {} : nil
223
+ end
224
+
225
+ def change_column_bold(col=0,bolded=false)
226
+ s = change_column_font(col,Worksheet::BOLD,bolded)
227
+ @workbook.fonts[font_id(s)][:font][:b] = bolded ? {} : nil
228
+ end
229
+
230
+ def change_column_underline(col=0,underlined=false)
231
+ s = change_column_font(col,Worksheet::UNDERLINE,underlined)
232
+ @workbook.fonts[font_id(s)][:font][:u] = underlined ? {} : nil
233
+ end
234
+
235
+ def change_column_strikethrough(col=0,struckthrough=false)
236
+ s = change_column_font(col,Worksheet::STRIKETHROUGH,struckthrough)
237
+ @workbook.fonts[font_id(s)][:font][:strike] = struckthrough ? {} : nil
238
+ end
239
+
240
+ def change_column_width(col=0,width=13)
241
+ validate_workbook
242
+ validate_nonnegative(col)
243
+ increase_columns(col)
244
+
245
+ i = get_cols_index(col)
246
+
247
+ if width.to_i.to_s == width.to_s
248
+ width = Integer(width)
249
+ elsif width.to_f.to_s == width.to_s
250
+ width = Float(width)
251
+ else
252
+ raise 'You must enter a number for the width'
253
+ end
254
+
255
+ change_cols(i,col)
256
+ @cols.last[:attributes][:width] = width
257
+ @cols.last[:attributes][:customWidth] = '1'
258
+ end
259
+
260
+ def change_column_fill(col=0, color_index='ffffff')
261
+ validate_workbook
262
+ validate_nonnegative(col)
263
+ Color.validate_color(color_index)
264
+ increase_columns(col)
265
+
266
+ i = get_cols_index(col)
267
+
268
+ if cols[i].nil?
269
+ style_index = 0
270
+ else
271
+ #just copies any style if there is none which already exists for this col
272
+ #while it changes style/min/max, width *might* be preserved
273
+ style_index = Integer(@cols[i][:attributes][:style])
274
+ end
275
+
276
+ modify_fill(@workbook,style_index,color_index)
277
+
278
+ change_cols(i,col)
279
+
280
+ @sheet_data.each_with_index do |row,i|
281
+ c = row[Integer(col)]
282
+ unless c.nil?
283
+ c.change_fill(color_index)
284
+ end
285
+ end
286
+
287
+ end
288
+
289
+ def change_column_horizontal_alignment(col=0,alignment='center')
290
+ validate_workbook
291
+ validate_nonnegative(col)
292
+ validate_horizontal_alignment(alignment)
293
+ change_column_alignment(col,alignment,true)
294
+ end
295
+
296
+ def change_column_vertical_alignment(col=0,alignment='center')
297
+ validate_workbook
298
+ validate_nonnegative(col)
299
+ validate_vertical_alignment(alignment)
300
+ change_column_alignment(col,alignment,false)
301
+ end
302
+
303
+ def change_column_border_top(col=0,weight='thin')
304
+ change_column_border(col,:top,weight)
305
+ end
306
+
307
+ def change_column_border_left(col=0,weight='thin')
308
+ change_column_border(col,:left,weight)
309
+ end
310
+
311
+ def change_column_border_right(col=0,weight='thin')
312
+ change_column_border(col,:right,weight)
313
+ end
314
+
315
+ def change_column_border_bottom(col=0,weight='thin')
316
+ change_column_border(col,:bottom,weight)
317
+ end
318
+
319
+ def change_column_border_diagonal(col=0,weight='thin')
320
+ change_column_border(col,:diagonal,weight)
321
+ end
322
+
323
+ # merges cells within a rectangular range
324
+ def merge_cells(row1=0,col1=0,row2=0,col2=0)
325
+ validate_workbook
326
+ @merged_cells << {
327
+ :attributes => {
328
+ :ref => ''
329
+ }
330
+ }
331
+ cell1 = Cell.convert_to_cell(row1,col1)
332
+ cell2 = Cell.convert_to_cell(row2,col2)
333
+ @merged_cells.last[:attributes][:ref] = cell1+':'+cell2
334
+ end
335
+
336
+ def add_cell(row=0, column=0, data='', formula=nil,overwrite=true)
337
+ validate_workbook
338
+ validate_nonnegative(row)
339
+ validate_nonnegative(column)
340
+
341
+ unless @sheet_data.size > row && @sheet_data[row].size > column
342
+ increase_columns(column)
343
+ increase_rows(row)
344
+ end
345
+
346
+ datatype = 'str'
347
+ unless formula.nil?
348
+ datatype = ''
349
+ end
350
+ if overwrite || @sheet_data[row][column].nil?
351
+ @sheet_data[row][column] = Cell.new(self,row,column,data,formula,datatype)
352
+
353
+ if (data.is_a?Integer) || (data.is_a?Float)
354
+ @sheet_data[row][column].datatype = ''
355
+ end
356
+ col = @cols[get_cols_index(column)]
357
+
358
+ if @row_styles[(row+1).to_s] != nil
359
+ @sheet_data[row][column].style_index = @row_styles[(row+1).to_s][:style]
360
+ elsif col != nil
361
+ @sheet_data[row][column].style_index = col[:attributes][:style]
362
+ end
363
+ end
364
+
365
+ add_cell_style(row,column)
366
+
367
+ return @sheet_data[row][column]
368
+ end
369
+
370
+ def add_cell_obj(cell, overwrite=true)
371
+ validate_workbook
372
+
373
+ if cell.nil?
374
+ return cell
375
+ end
376
+
377
+ row = cell.row
378
+ column = cell.column
379
+
380
+ validate_nonnegative(row)
381
+ validate_nonnegative(column)
382
+
383
+ unless @sheet_data.size > row && @sheet_data[row].size > column
384
+ increase_columns(column)
385
+ increase_rows(row)
386
+ end
387
+ if overwrite || @sheet_data[row][column].nil?
388
+ @sheet_data[row][column] = cell
389
+ end
390
+
391
+ add_cell_style(row,column)
392
+
393
+ return @sheet_data[row][column]
394
+ end
395
+
396
+ #inserts row at row_index, pushes down, copies style from below (row previously at that index)
397
+ #USE OF THIS METHOD will break formulas which reference cells which are being "pushed down"
398
+ def insert_row(row_index)
399
+ validate_workbook
400
+ validate_nonnegative(row_index)
401
+
402
+ increase_rows(row_index)
403
+
404
+ @sheet_data.insert(row_index,Array.new(@sheet_data[row_index].size))
405
+
406
+ row_num = row_index+1
407
+
408
+ #copy cell styles from row above, (or below if first row)
409
+ @sheet_data[row_index].each_index do |i|
410
+ if row_index > 0
411
+ old_cell = @sheet_data[row_index-1][i]
412
+ else
413
+ old_cell = @sheet_data[row_index+1][i]
414
+ end
415
+
416
+ unless old_cell.nil?
417
+ #only add cell if style exists, not copying content
418
+
419
+ if @row_styles[(row_num+1).to_s].nil?
420
+ @row_styles[(row_num+1).to_s] = {:style=>0}
421
+ end
422
+ if old_cell.style_index != 0 && old_cell.style_index.to_s != @row_styles[(row_num+1).to_s][:style].to_s
423
+ c = Cell.new(self,row_index,i)
424
+ c.style_index = old_cell.style_index
425
+ @sheet_data[row_index][i] = c
426
+ end
427
+ end
428
+ end
429
+
430
+ #copy row styles from row above, (or below if first row)
431
+ (@row_styles.size+1).downto(row_num+1) do |i|
432
+ @row_styles[i.to_s] = @row_styles[(i-1).to_s]
433
+ end
434
+ if row_index > 0
435
+ @row_styles[row_num.to_s] = @row_styles[(row_num-1).to_s]
436
+ else
437
+ @row_styles[row_num.to_s] = nil#@row_styles[(row_num+1).to_s]
438
+ end
439
+
440
+ #update row value for all rows below
441
+ (row_index+1).upto(@sheet_data.size-1) do |i|
442
+ row = @sheet_data[i]
443
+ row.each do |c|
444
+ unless c.nil?
445
+ c.row += 1
446
+ end
447
+ end
448
+ end
449
+
450
+ return @sheet_data[row_index]
451
+ end
452
+
453
+ # inserts column at col_index, pushes everything right, takes styles from column to left
454
+ # USE OF THIS METHOD will break formulas which reference cells which are being "pushed down"
455
+ def insert_column(col_index)
456
+ validate_workbook
457
+ validate_nonnegative(col_index)
458
+ increase_columns(col_index)
459
+
460
+ old_index = col_index > 0 ? col_index-1 : col_index+1
461
+ old_col = @cols[get_cols_index(old_index)]
462
+ if old_index == 1
463
+ old_col = nil
464
+ end
465
+
466
+ #go through each cell in column
467
+ @sheet_data.each_with_index do |r,i|
468
+ #insert "column" in each row
469
+ r.insert(col_index, nil)
470
+
471
+ #copy styles over to each cell
472
+ old_cell = r[old_index]
473
+ unless old_cell.nil?
474
+ #only add cell if style exists, not copying content
475
+ if old_cell.style_index != 0
476
+ if !old_col.nil? && old_cell.style_index.to_s != old_col[:attributes][:style].to_s
477
+ c = Cell.new(self,i,col_index)
478
+ c.style_index = old_cell.style_index
479
+ @sheet_data[i][col_index] = c
480
+ end
481
+ end
482
+ end
483
+ end
484
+
485
+ #copy over column-level styles
486
+ new_col = change_cols(get_cols_index(old_index),old_index)
487
+ @cols[-1] = deep_copy(old_col)#-1 = last
488
+
489
+ new_col = @cols.last
490
+ if @cols.last.nil?
491
+ @cols.pop
492
+ end
493
+
494
+ #shift col styles 'right'
495
+ @cols.each do |col|
496
+ if Integer(col[:attributes][:min]) > col_index
497
+ col[:attributes][:min] = (1 + Integer(col[:attributes][:min])).to_s
498
+ end
499
+ if Integer(col[:attributes][:max]) > col_index
500
+ col[:attributes][:max] = (1 + Integer(col[:attributes][:max])).to_s
501
+ end
502
+ end
503
+ unless new_col.nil?
504
+ new_col[:attributes][:min] = (1 + Integer(new_col[:attributes][:min])).to_s
505
+ new_col[:attributes][:max] = (1 + Integer(new_col[:attributes][:max])).to_s
506
+ end
507
+
508
+ #update column numbers
509
+ @sheet_data.each do |row|
510
+ (col_index+1).upto(row.size) do |j|
511
+ unless row[j].nil?
512
+ row[j].column += 1
513
+ end
514
+ end
515
+ end
516
+ end
517
+
518
+ def get_row_fill(row=0)
519
+ validate_workbook
520
+ validate_nonnegative(row)
521
+
522
+ if @sheet_data.size <= row
523
+ return nil
524
+ end
525
+
526
+ if @row_styles[(row+1).to_s].nil?
527
+ return "ffffff" #default, white
528
+ end
529
+
530
+ xf = xf_attr_row(row)
531
+
532
+ return @workbook.get_fill_color(xf)
533
+ end
534
+
535
+ def get_row_font_name(row=0)
536
+ validate_workbook
537
+ validate_nonnegative(row)
538
+
539
+ if @sheet_data.size <= row
540
+ return nil
541
+ end
542
+
543
+ if @row_styles[(row+1).to_s].nil?
544
+ return 'Verdana'
545
+ end
546
+
547
+ xf = xf_attr_row(row)
548
+
549
+ return @workbook.fonts[xf[:fontId].to_s][:font][:name][:attributes][:val]
550
+ end
551
+
552
+ def get_row_font_size(row=0)
553
+ validate_workbook
554
+ validate_nonnegative(row)
555
+
556
+ if @sheet_data.size <= row
557
+ return nil
558
+ end
559
+
560
+ if @row_styles[(row+1).to_s].nil?
561
+ return '10'
562
+ end
563
+
564
+ xf = xf_attr_row(row)
565
+
566
+ return @workbook.fonts[xf[:fontId].to_s][:font][:sz][:attributes][:val]
567
+ end
568
+
569
+ def get_row_font_color(row=0)
570
+ validate_workbook
571
+ validate_nonnegative(row)
572
+
573
+ if @sheet_data.size <= row
574
+ return nil
575
+ end
576
+
577
+ if @row_styles[(row+1).to_s].nil?
578
+ return '000000'
579
+ end
580
+
581
+ xf = xf_attr_row(row)
582
+
583
+ color = @workbook.fonts[xf[:fontId].to_s][:font][:color]
584
+
585
+ if color.nil? || color[:attributes].nil? || color[:attributes][:rgb].nil?
586
+ return '000000'
587
+ end
588
+
589
+ return color[:attributes][:rgb]
590
+ end
591
+
592
+ def is_row_italicized(row=0)
593
+ return get_row_bool(row,:i)
594
+ end
595
+
596
+ def is_row_bolded(row=0)
597
+ return get_row_bool(row,:b)
598
+ end
599
+
600
+ def is_row_underlined(row=0)
601
+ return get_row_bool(row,:u)
602
+ end
603
+
604
+ def is_row_struckthrough(row=0)
605
+ return get_row_bool(row,:strike)
606
+ end
607
+
608
+
609
+ def get_row_height(row=0)
610
+ validate_workbook
611
+ validate_nonnegative(row)
612
+
613
+ if @sheet_data.size <= row
614
+ return nil
615
+ end
616
+
617
+ if @row_styles[(row+1).to_s].nil?
618
+ return 13
619
+ else
620
+ @row_styles[(row+1).to_s][:height]
621
+ end
622
+ end
623
+
624
+ def get_row_horizontal_alignment(row=0)
625
+ return get_row_alignment(row,true)
626
+ end
627
+
628
+ def get_row_vertical_alignment(row=0)
629
+ return get_row_alignment(row,false)
630
+ end
631
+
632
+ def get_row_border_top(row=0)
633
+ return get_row_border(row,:top)
634
+ end
635
+
636
+ def get_row_border_left(row=0)
637
+ return get_row_border(row,:left)
638
+ end
639
+
640
+ def get_row_border_right(row=0)
641
+ return get_row_border(row,:right)
642
+ end
643
+
644
+ def get_row_border_bottom(row=0)
645
+ return get_row_border(row,:bottom)
646
+ end
647
+
648
+ def get_row_border_diagonal(row=0)
649
+ return get_row_border(row,:diagonal)
650
+ end
651
+
652
+ def get_column_font_name(col=0)
653
+ validate_workbook
654
+ validate_nonnegative(col)
655
+
656
+ if @sheet_data[0].size <= col
657
+ return nil
658
+ end
659
+
660
+ style_index = get_cols_style_index(col)
661
+
662
+ return @workbook.fonts[font_id( style_index ).to_s][:font][:name][:attributes][:val]
663
+ end
664
+
665
+ def get_column_font_size(col=0)
666
+ validate_workbook
667
+ validate_nonnegative(col)
668
+
669
+ if @sheet_data[0].size <= col
670
+ return nil
671
+ end
672
+
673
+ style_index = get_cols_style_index(col)
674
+
675
+ return @workbook.fonts[font_id( style_index ).to_s][:font][:sz][:attributes][:val]
676
+ end
677
+
678
+ def get_column_font_color(col=0)
679
+ validate_workbook
680
+ validate_nonnegative(col)
681
+
682
+ if @sheet_data[0].size <= col
683
+ return nil
684
+ end
685
+
686
+ style_index = get_cols_style_index(col)
687
+
688
+ font = @workbook.fonts[font_id( style_index ).to_s][:font]
689
+
690
+ if font[:color].nil? || font[:color][:attributes].nil? || font[:color][:attributes][:rgb].nil?
691
+ return '000000'
692
+ end
693
+
694
+ return font[:color][:attributes][:rgb]
695
+
696
+ end
697
+
698
+ def is_column_italicized(col=0)
699
+ get_column_bool(col,:i)
700
+ end
701
+
702
+ def is_column_bolded(col=0)
703
+ get_column_bool(col,:b)
704
+ end
705
+
706
+ def is_column_underlined(col=0)
707
+ get_column_bool(col,:u)
708
+ end
709
+
710
+ def is_column_struckthrough(col=0)
711
+ get_column_bool(col,:strike)
712
+ end
713
+
714
+ def get_column_width(col=0)
715
+ validate_workbook
716
+ validate_nonnegative(col)
717
+
718
+ if @sheet_data[0].size <= col
719
+ return nil
720
+ end
721
+
722
+ cols_index = get_cols_index(col)
723
+
724
+ if @cols[cols_index].nil? || @cols[cols_index][:attributes].nil? || @cols[cols_index][:attributes][:width].to_s == ''
725
+ return 10
726
+ end
727
+
728
+ return @cols[cols_index][:attributes][:width]
729
+ end
730
+
731
+ def get_column_fill(col=0)
732
+ validate_workbook
733
+ validate_nonnegative(col)
734
+
735
+ if @sheet_data[0].size <= col
736
+ return nil
737
+ end
738
+
739
+ style_index = get_cols_style_index(col)
740
+
741
+ if style_index == 0
742
+ return "ffffff" #default, white
743
+ end
744
+
745
+ return @workbook.get_fill_color(@workbook.cell_xfs[:xf][style_index][:attributes])
746
+ end
747
+
748
+ def get_column_horizontal_alignment(col=0)
749
+ get_column_alignment(col, :horizontal)
750
+ end
751
+
752
+ def get_column_vertical_alignment(col=0)
753
+ get_column_alignment(col, :vertical)
754
+ end
755
+
756
+ def get_column_border_top(col=0)
757
+ return get_column_border(col,:top)
758
+ end
759
+
760
+ def get_column_border_left(col=0)
761
+ return get_column_border(col,:left)
762
+ end
763
+
764
+ def get_column_border_right(col=0)
765
+ return get_column_border(col,:right)
766
+ end
767
+
768
+ def get_column_border_bottom(col=0)
769
+ return get_column_border(col,:bottom)
770
+ end
771
+
772
+ def get_column_border_diagonal(col=0)
773
+ return get_column_border(col,:diagonal)
774
+ end
775
+
776
+
777
+ private
778
+
779
+ Worksheet::NAME = 0
780
+ Worksheet::SIZE = 1
781
+ Worksheet::COLOR = 2
782
+ Worksheet::ITALICS = 3
783
+ Worksheet::BOLD = 4
784
+ Worksheet::UNDERLINE = 5
785
+ Worksheet::STRIKETHROUGH = 6
786
+
787
+ #row_styles is assumed to not be nil at specified row
788
+ def xf_attr_row(row)
789
+ row_style = @row_styles[(row+1).to_s][:style]
790
+ return @workbook.get_style_attributes(@workbook.get_style(row_style))
791
+ end
792
+
793
+ def xf_attr_col(column)
794
+ col_style = @cols[get_cols_index(column)][:style]
795
+ return @workbook.get_style_attributes(@workbook.get_style(Integer(col_style)))
796
+ end
797
+
798
+ def get_row_bool(row,property)
799
+ validate_workbook
800
+ validate_nonnegative(row)
801
+
802
+ if @sheet_data.size <= row
803
+ return nil
804
+ end
805
+
806
+ if @row_styles[(row+1).to_s].nil?
807
+ return false
808
+ end
809
+
810
+ xf = xf_attr_row(row)
811
+
812
+ return !@workbook.fonts[xf[:fontId].to_s][:font][property].nil?
813
+ end
814
+
815
+ def get_row_alignment(row,is_horizontal)
816
+ validate_workbook
817
+ validate_nonnegative(row)
818
+
819
+ if @sheet_data.size <= row || @row_styles[(row+1).to_s].nil?
820
+ return nil
821
+ end
822
+
823
+ xf_obj = @workbook.get_style(@row_styles[(row+1).to_s][:style])
824
+
825
+ if xf_obj[:alignment].nil? || xf_obj[:alignment][:attributes].nil?
826
+ return nil
827
+ end
828
+
829
+ if is_horizontal
830
+ return xf_obj[:alignment][:attributes][:horizontal].to_s
831
+ else
832
+ return xf_obj[:alignment][:attributes][:vertical].to_s
833
+ end
834
+ end
835
+
836
+ def get_row_border(row,border_direction)
837
+ validate_workbook
838
+ validate_nonnegative(row)
839
+
840
+ if @sheet_data.size <= row || @row_styles[(row+1).to_s].nil?
841
+ return nil
842
+ end
843
+
844
+ if @workbook.borders[xf_attr_row(row)[:borderId]].nil? && !@workbook.borders[xf_attr_row(row)[:borderId].to_s].nil?
845
+ @workbook.borders[xf_attr_row(row)[:borderId]] = deep_copy(@workbook.borders[xf_attr_row(row)[:borderId].to_s])
846
+ @workbook.borders.delete(xf_attr_row(row)[:borderId].to_s)
847
+ end
848
+
849
+ if @workbook.borders[xf_attr_row(row)[:borderId]][:border][border_direction][:attributes].nil?
850
+ return nil
851
+ end
852
+
853
+ return @workbook.borders[xf_attr_row(row)[:borderId]][:border][border_direction][:attributes][:style]
854
+ end
855
+
856
+ def get_column_bool(col,property)
857
+ validate_workbook
858
+ validate_nonnegative(col)
859
+
860
+ if @sheet_data[0].size <= col
861
+ return nil
862
+ end
863
+
864
+ style_index = get_cols_style_index(col)
865
+
866
+ return !@workbook.fonts[font_id( style_index ).to_s][:font][property].nil?
867
+ end
868
+
869
+ def get_column_alignment(col, type)
870
+ validate_workbook
871
+ validate_nonnegative(col)
872
+
873
+ if @sheet_data[0].size <= col
874
+ return nil
875
+ end
876
+
877
+ style_index = get_cols_style_index(col)
878
+
879
+ xf_obj = @workbook.get_style(style_index)
880
+ if xf_obj[:alignment].nil?
881
+ return nil
882
+ end
883
+
884
+ return xf_obj[:alignment][:attributes][type]
885
+ end
886
+
887
+ def get_column_border(col, border_direction)
888
+ validate_workbook
889
+ validate_nonnegative(col)
890
+ style_index = get_cols_style_index(col)
891
+ xf = @workbook.get_style_attributes(@workbook.get_style(style_index))
892
+
893
+ if @sheet_data[0].size <= col
894
+ return nil
895
+ end
896
+
897
+ if @workbook.borders[xf[:borderId]].nil? && !@workbook.borders[xf[:borderId].to_s].nil?
898
+ @workbook.borders[xf[:borderId]] = deep_copy(@workbook.borders[xf[:borderId].to_s])
899
+ @workbook.borders.delete(xf[:borderId].to_s)
900
+ end
901
+
902
+ if @workbook.borders[xf[:borderId]][:border][border_direction][:attributes].nil?
903
+ return nil
904
+ end
905
+
906
+ return @workbook.borders[xf[:borderId]][:border][border_direction][:attributes][:style]
907
+ end
908
+
909
+ def deep_copy(hash)
910
+ Marshal.load(Marshal.dump(hash))
911
+ end
912
+
913
+ #validates Workbook, ensures that this worksheet is in @workbook
914
+ def validate_workbook()
915
+ unless @workbook.nil? || @workbook.worksheets.nil?
916
+ @workbook.worksheets.each do |sheet|
917
+ if sheet == self
918
+ return
919
+ end
920
+ end
921
+ end
922
+ raise "This worksheet #{self} is not in workbook #{@workbook}"
923
+ end
924
+
925
+ # because cols is not ordered by col num, this actually gets
926
+ # the index in the array based on which column is actually being asked for by the user
927
+ def get_cols_index(col)
928
+ i = @cols.size - 1
929
+
930
+ @cols.reverse_each do |column|
931
+ if col >= (Integer(column[:attributes][:min])-1)
932
+ if col <= (Integer(column[:attributes][:max])-1)
933
+ break
934
+ end
935
+ end
936
+ i -= 1
937
+ end
938
+ if i < 0
939
+ i = @cols.size #effectively nil
940
+ end
941
+ i
942
+ end
943
+
944
+ def get_cols_style_index(col)
945
+ cols_index = get_cols_index(col)
946
+ if cols_index == @cols.size
947
+ return 0
948
+ end
949
+ return Integer(@cols[cols_index][:attributes][:style])
950
+ end
951
+
952
+ #change cols array
953
+ def change_cols(i,col_index)
954
+ if @cols[i].nil?
955
+ @cols << {:attributes=>{:style=>nil,:min=>nil,:max=>nil,:width=>nil,:customWidth=>nil}}
956
+ else
957
+ @cols << deep_copy(@cols[i])
958
+ end
959
+ @cols.last[:attributes][:style] = (@workbook.cell_xfs[:xf].size-1).to_s
960
+ @cols.last[:attributes][:min] = (Integer(col_index)+1).to_s
961
+ @cols.last[:attributes][:max] = (Integer(col_index)+1).to_s
962
+ @cols.last[:attributes][:width] = '10'
963
+ @cols.last[:attributes][:customWidth] = '0'
964
+ end
965
+
966
+ # row - zer0 indexed int
967
+ # change_type - NAME or SIZE or COLOR etc
968
+ # main method to change font, called from each separate font mutator method
969
+ def change_row_font(row,change_type,arg)
970
+ validate_workbook
971
+ validate_nonnegative(row)
972
+
973
+ increase_rows(row)
974
+
975
+ if @row_styles[(row+1).to_s].nil?
976
+ @row_styles[(row+1).to_s] = {}
977
+ end
978
+
979
+ @row_styles[(row+1).to_s][:style] =
980
+ modify_font(@workbook,Integer(@row_styles[(row+1).to_s][:style]))
981
+
982
+ if @sheet_data[row].nil?
983
+ @sheet_data[row] = []
984
+ end
985
+ @sheet_data[Integer(row)].each do |c|
986
+ unless c.nil?
987
+ font_switch(c,change_type,arg)
988
+ end
989
+ end
990
+ end
991
+
992
+ #main method to change font, called from each separate font mutator method
993
+ def change_column_font(col, change_type, arg)
994
+ validate_workbook
995
+ validate_nonnegative(col)
996
+
997
+ increase_columns(col)
998
+
999
+ i = get_cols_index(col)
1000
+
1001
+ #just copies any style if there is none which already exists for this col
1002
+ #while it changes style/min/max, width *might* be preserved
1003
+ if @cols[i].nil?
1004
+ style_index = 0
1005
+ else
1006
+ style_index = Integer(@cols[i][:attributes][:style])
1007
+ end
1008
+
1009
+ style_index = modify_font(@workbook,style_index)
1010
+
1011
+ change_cols(i,col)
1012
+
1013
+ @sheet_data.each_with_index do |row,i|
1014
+ c = row[col]
1015
+ unless c.nil?
1016
+ font_switch(c,change_type,arg)
1017
+ end
1018
+ end
1019
+ style_index
1020
+ end
1021
+
1022
+ #performs correct modification based on what type of change_type is specified
1023
+ def font_switch(c,change_type,arg)
1024
+ case change_type
1025
+ when Worksheet::NAME
1026
+ unless arg.is_a?String
1027
+ raise 'Not a String'
1028
+ end
1029
+ c.change_font_name(arg)
1030
+ when Worksheet::SIZE
1031
+ unless arg.is_a?(Integer) || arg.is_a?(Float)
1032
+ raise 'Not a Number'
1033
+ end
1034
+ c.change_font_size(arg)
1035
+ when Worksheet::COLOR
1036
+ Color.validate_color(arg)
1037
+ c.change_font_color(arg)
1038
+ when Worksheet::ITALICS
1039
+ unless arg == !!arg
1040
+ raise 'Not a boolean'
1041
+ end
1042
+ c.change_font_italics(arg)
1043
+ when Worksheet::BOLD
1044
+ unless arg == !!arg
1045
+ raise 'Not a boolean'
1046
+ end
1047
+ c.change_font_bold(arg)
1048
+ when Worksheet::UNDERLINE
1049
+ unless arg == !!arg
1050
+ raise 'Not a boolean'
1051
+ end
1052
+ c.change_font_underline(arg)
1053
+ when Worksheet::STRIKETHROUGH
1054
+ unless arg == !!arg
1055
+ raise 'Not a boolean'
1056
+ end
1057
+ c.change_font_strikethrough(arg)
1058
+ else
1059
+ raise 'Invalid change_type'
1060
+ end
1061
+ end
1062
+
1063
+ #increases number of rows until the array at index row is not nil
1064
+ def increase_rows(row)
1065
+ @sheet_data.size.upto(row) do
1066
+ @sheet_data << Array.new(@sheet_data[0].size)
1067
+ end
1068
+ end
1069
+
1070
+ #increases number of columns until the array at index column is not nil
1071
+ def increase_columns(column)
1072
+ @sheet_data.each do |r|
1073
+ r.size.upto(column) do
1074
+ r << nil
1075
+ end
1076
+ end
1077
+ end
1078
+
1079
+ def font_id(style_index)
1080
+ @workbook.get_style_attributes(@workbook.get_style(style_index))[:fontId]
1081
+ end
1082
+
1083
+ def change_row_alignment(row,alignment,is_horizontal)
1084
+ validate_workbook
1085
+ validate_nonnegative(row)
1086
+
1087
+ increase_rows(row)
1088
+
1089
+ if @row_styles[(row+1).to_s].nil?
1090
+ @row_styles[(row+1).to_s] = {}
1091
+ @row_styles[(row+1).to_s][:style] = '0'
1092
+ end
1093
+
1094
+ @row_styles[(row+1).to_s][:style] =
1095
+ modify_alignment(@workbook,@row_styles[(row+1).to_s][:style],is_horizontal,alignment)
1096
+
1097
+ @sheet_data[row].each do |c|
1098
+ unless c.nil?
1099
+ if is_horizontal
1100
+ c.change_horizontal_alignment(alignment)
1101
+ else
1102
+ c.change_vertical_alignment(alignment)
1103
+ end
1104
+ end
1105
+ end
1106
+ end
1107
+
1108
+ def change_column_alignment(col,alignment,is_horizontal)
1109
+ validate_workbook
1110
+ validate_nonnegative(col)
1111
+
1112
+ increase_columns(col)
1113
+
1114
+ i = get_cols_index(col)
1115
+
1116
+ if @cols[i].nil?
1117
+ style_index = 0
1118
+ else
1119
+ style_index = Integer(@cols[i][:attributes][:style])
1120
+ end
1121
+
1122
+ style_index = modify_alignment(@workbook,style_index,is_horizontal,alignment)
1123
+
1124
+ change_cols(i,col)
1125
+
1126
+ @cols[i][:attributes][:style] = style_index
1127
+
1128
+ @sheet_data.each_with_index do |row,i|
1129
+ c = row[Integer(col)]
1130
+ unless c.nil?
1131
+ if is_horizontal
1132
+ c.change_horizontal_alignment(alignment)
1133
+ else
1134
+ c.change_vertical_alignment(alignment)
1135
+ end
1136
+ end
1137
+ end
1138
+ end
1139
+
1140
+ def change_row_border(row, direction, weight)
1141
+ validate_workbook
1142
+ validate_nonnegative(row)
1143
+ validate_border(weight)
1144
+ increase_rows(row)
1145
+
1146
+ if @row_styles[(row+1).to_s].nil?
1147
+ @row_styles[(row+1).to_s]= {}
1148
+ @row_styles[(row+1).to_s][:style] = '0'
1149
+ end
1150
+ @row_styles[(row+1).to_s][:style] = modify_border(@workbook,@row_styles[(row+1).to_s][:style])
1151
+
1152
+ if @workbook.borders[xf_attr_row(row)[:borderId]][:border][direction][:attributes].nil?
1153
+ @workbook.borders[xf_attr_row(row)[:borderId]][:border][direction][:attributes] = { :style => nil }
1154
+ end
1155
+ @workbook.borders[xf_attr_row(row)[:borderId]][:border][direction][:attributes][:style] = weight.to_s
1156
+
1157
+ @sheet_data[row].each do |c|
1158
+ unless c.nil?
1159
+ case direction
1160
+ when :top
1161
+ c.change_border_top(weight)
1162
+ when :left
1163
+ c.change_border_left(weight)
1164
+ when :right
1165
+ c.change_border_right(weight)
1166
+ when :bottom
1167
+ c.change_border_bottom(weight)
1168
+ when :diagonal
1169
+ c.change_border_diagonal(weight)
1170
+ else
1171
+ raise 'invalid direction'
1172
+ end
1173
+ end
1174
+ end
1175
+ end
1176
+
1177
+ def change_column_border(col,direction,weight)
1178
+ validate_workbook
1179
+ validate_nonnegative(col)
1180
+ validate_border(weight)
1181
+
1182
+ increase_columns(col)
1183
+
1184
+ i = get_cols_index(col)
1185
+ if @cols[i].nil?
1186
+ style_index = 0
1187
+ else
1188
+ style_index = Integer(@cols[i][:attributes][:style])
1189
+ end
1190
+
1191
+ style_index = modify_border(@workbook,style_index)
1192
+
1193
+ change_cols(i,col)
1194
+
1195
+ xf = @workbook.get_style_attributes(@workbook.get_style(style_index))
1196
+
1197
+ if @workbook.borders[xf[:borderId]][:border][direction][:attributes].nil?
1198
+ @workbook.borders[xf[:borderId]][:border][direction][:attributes] = { :style => nil }
1199
+ end
1200
+ @workbook.borders[xf[:borderId]][:border][direction][:attributes][:style] = weight.to_s
1201
+
1202
+ @sheet_data.each_with_index do |row,i|
1203
+ c = row[Integer(col)]
1204
+ unless c.nil?
1205
+ case direction
1206
+ when :top
1207
+ c.change_border_top(weight)
1208
+ when :left
1209
+ c.change_border_left(weight)
1210
+ when :right
1211
+ c.change_border_right(weight)
1212
+ when :bottom
1213
+ c.change_border_bottom(weight)
1214
+ when :diagonal
1215
+ c.change_border_diagonal(weight)
1216
+ else
1217
+ raise 'invalid direction'
1218
+ end
1219
+ end
1220
+ end
1221
+ end
1222
+
1223
+ def add_cell_style(row,column)
1224
+ xf = @workbook.get_style_attributes(@workbook.get_style(@sheet_data[row][column].style_index))
1225
+ @workbook.fonts[xf[:fontId].to_s][:count] += 1
1226
+ @workbook.fills[xf[:fillId].to_s][:count] += 1
1227
+ @workbook.borders[xf[:borderId].to_s][:count] += 1
1228
+ end
1229
+
1230
+ # finds first row which contains at least all strings in cells_content
1231
+ def find_first_row_with_content(cells_content)
1232
+ validate_workbook
1233
+ index = nil
1234
+
1235
+ @sheet_data.each_with_index do |row, index|
1236
+ original_cells_content = row.map { |cell| cell.nil? ? '' : cell.value.to_s }
1237
+ if (cells_content & original_cells_content).size == cells_content.size
1238
+ return index
1239
+ end
1240
+ end
1241
+ return nil
1242
+ end
1243
+
1244
+ end #end class
1245
+ end