thunderboltlabs-rubyXL 1.2.10.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,461 @@
1
+ module RubyXL
2
+ class Cell < PrivateClass
3
+
4
+ attr_accessor :row, :column, :datatype, :style_index, :formula, :worksheet
5
+ attr_reader :workbook,:formula_attributes
6
+
7
+ def initialize(worksheet,row,column,value=nil,formula=nil,datatype='s',style_index=0, fmla_attr={})
8
+ @worksheet = worksheet
9
+
10
+ @workbook = worksheet.workbook
11
+ @row = row
12
+ @column = column
13
+ @datatype = datatype
14
+ @value = value
15
+ @formula=formula
16
+ @style_index = style_index
17
+ @formula_attributes = fmla_attr
18
+ end
19
+
20
+ def value(args = {})
21
+ raw_values = args.delete(:raw) || false
22
+ return @value if raw_values
23
+
24
+ if is_date?
25
+ return @workbook.num_to_date(@value)
26
+ else
27
+ return @value
28
+ end
29
+ end
30
+
31
+ def is_date?
32
+ if !@value.is_a?(String)
33
+ if @workbook.num_fmts_by_id
34
+ num_fmt_id = xf_id()[:numFmtId]
35
+ tmp_num_fmt = @workbook.num_fmts_by_id[num_fmt_id]
36
+ num_fmt = (tmp_num_fmt &&tmp_num_fmt[:attributes] && tmp_num_fmt[:attributes][:formatCode]) ? tmp_num_fmt[:attributes][:formatCode] : nil
37
+ if num_fmt && workbook.date_num_fmt?(num_fmt)
38
+ return true
39
+ end
40
+ end
41
+ end
42
+ return false
43
+ end
44
+
45
+ def is_date_format?(num_fmt)
46
+ skip_chars = ['$', '-', '+', '/', '(', ')', ':', ' ']
47
+ num_chars = ['0', '#', '?']
48
+ non_date_formats = ['0.00E+00', '##0.0E+0', 'General', 'GENERAL', 'general', '@']
49
+ date_chars = ['y','m','d','h','s']
50
+
51
+ state = 0
52
+ s = ''
53
+ num_fmt.split(//).each do |c|
54
+ if state == 0
55
+ if c == '"'
56
+ state = 1
57
+ elsif ['\\', '_', '*'].include?(c)
58
+ state = 2
59
+ elsif skip_chars.include?(c)
60
+ next
61
+ else
62
+ s << c
63
+ end
64
+ elsif state == 1
65
+ if c == '"'
66
+ state = 0
67
+ end
68
+ elsif state == 2
69
+ state = 0
70
+ end
71
+ end
72
+ s.gsub!(/\[[^\]]*\]/, '')
73
+ if non_date_formats.include?(s)
74
+ return false
75
+ end
76
+ separator = ';'
77
+ got_sep = 0
78
+ date_count = 0
79
+ num_count = 0
80
+ s.split(//).each do |c|
81
+ if date_chars.include?(c)
82
+ date_count += 1
83
+ elsif num_chars.include?(c)
84
+ num_count += 1
85
+ elsif c == separator
86
+ got_sep = 1
87
+ end
88
+ end
89
+ if date_count > 0 && num_count == 0
90
+ return true
91
+ elsif num_count > 0 && date_count == 0
92
+ return false
93
+ elsif date_count
94
+ # ambiguous result
95
+ elsif got_sep == 0
96
+ # constant result
97
+ end
98
+ return date_count > num_count
99
+ end
100
+
101
+ # changes fill color of cell
102
+ def change_fill(rgb='ffffff')
103
+ validate_worksheet
104
+ Color.validate_color(rgb)
105
+ @style_index = modify_fill(@workbook, @style_index,rgb)
106
+ end
107
+
108
+ # Changes font name of cell
109
+ def change_font_name(font_name='Verdana')
110
+ validate_worksheet
111
+ # Get copy of font object with modified name
112
+ font = deep_copy(workbook.fonts[font_id().to_s][:font])
113
+ font[:name][:attributes][:val] = font_name.to_s
114
+ # Update font and xf array
115
+ change_font(font)
116
+ end
117
+
118
+ # Changes font size of cell
119
+ def change_font_size(font_size=10)
120
+ validate_worksheet
121
+ if font_size.is_a?(Integer) || font_size.is_a?(Float)
122
+ # Get copy of font object with modified size
123
+ font = deep_copy(workbook.fonts[font_id().to_s][:font])
124
+ font[:sz][:attributes][:val] = font_size
125
+ # Update font and xf array
126
+ change_font(font)
127
+ else
128
+ raise 'Argument must be a number'
129
+ end
130
+ end
131
+
132
+ # Changes font color of cell
133
+ def change_font_color(font_color='000000')
134
+ validate_worksheet
135
+ #if arg is a color name, convert to integer
136
+ Color.validate_color(font_color)
137
+ # Get copy of font object with modified color
138
+ font = deep_copy(workbook.fonts[font_id().to_s][:font])
139
+ font = modify_font_color(font, font_color.to_s)
140
+ # Update font and xf array
141
+ change_font(font)
142
+ end
143
+
144
+ # Changes font italics settings of cell
145
+ def change_font_italics(italicized=false)
146
+ validate_worksheet
147
+ # Get copy of font object with modified italics settings
148
+ font = deep_copy(workbook.fonts[font_id().to_s][:font])
149
+ font = modify_font_italics(font, italicized)
150
+ # Update font and xf array
151
+ change_font(font)
152
+ end
153
+
154
+ # Changes font bold settings of cell
155
+ def change_font_bold(bolded=false)
156
+ validate_worksheet
157
+ # Get copy of font object with modified bold settings
158
+ font = deep_copy(workbook.fonts[font_id().to_s][:font])
159
+ font = modify_font_bold(font, bolded)
160
+ # Update font and xf array
161
+ change_font(font)
162
+ end
163
+
164
+ # Changes font underline settings of cell
165
+ def change_font_underline(underlined=false)
166
+ validate_worksheet
167
+ # Get copy of font object with modified underline settings
168
+ font = deep_copy(workbook.fonts[font_id().to_s][:font])
169
+ font = modify_font_underline(font, underlined)
170
+ # Update font and xf array
171
+ change_font(font)
172
+ end
173
+
174
+ # Changes font strikethrough settings of cell
175
+ def change_font_strikethrough(struckthrough=false)
176
+ validate_worksheet
177
+ # Get copy of font object with modified strikethrough settings
178
+ font = deep_copy(workbook.fonts[font_id().to_s][:font])
179
+ font = modify_font_strikethrough(font, struckthrough)
180
+ # Update font and xf array
181
+ change_font(font)
182
+ end
183
+
184
+ # Helper method to update the font array and xf array
185
+ def change_font(font)
186
+ # Modify font array and retrieve new font id
187
+ font_id = modify_font(@workbook, font, font_id())
188
+ # Get copy of xf object with modified font id
189
+ xf = deep_copy(xf_id())
190
+ xf[:fontId] = Integer(font_id.to_i)
191
+ # Modify xf array and retrieve new xf id
192
+ @style_index = modify_xf(@workbook, xf)
193
+ end
194
+
195
+ # changes horizontal alignment of cell
196
+ def change_horizontal_alignment(alignment='center')
197
+ validate_worksheet
198
+ validate_horizontal_alignment(alignment)
199
+ @style_index = modify_alignment(@workbook,@style_index,true,alignment)
200
+ end
201
+
202
+ # changes vertical alignment of cell
203
+ def change_vertical_alignment(alignment='center')
204
+ validate_worksheet
205
+ validate_vertical_alignment(alignment)
206
+ @style_index = modify_alignment(@workbook,@style_index,false,alignment)
207
+ end
208
+
209
+ # changes top border of cell
210
+ def change_border_top(weight='thin')
211
+ change_border(:top, weight)
212
+ end
213
+
214
+ # changes left border of cell
215
+ def change_border_left(weight='thin')
216
+ change_border(:left, weight)
217
+ end
218
+
219
+ # changes right border of cell
220
+ def change_border_right(weight='thin')
221
+ change_border(:right, weight)
222
+ end
223
+
224
+ # changes bottom border of cell
225
+ def change_border_bottom(weight='thin')
226
+ change_border(:bottom, weight)
227
+ end
228
+
229
+ # changes diagonal border of cell
230
+ def change_border_diagonal(weight='thin')
231
+ change_border(:diagonal, weight)
232
+ end
233
+
234
+ # changes contents of cell, with formula option
235
+ def change_contents(data, formula=nil)
236
+ validate_worksheet
237
+ @datatype='str'
238
+ if data.is_a?(Date) || data.is_a?(DateTime)
239
+ data = @workbook.date_to_num(data)
240
+ end
241
+ if (data.is_a?Integer) || (data.is_a?Float)
242
+ @datatype = ''
243
+ end
244
+ @value=data
245
+ @formula=formula
246
+ end
247
+
248
+ # returns if font is italicized
249
+ def is_italicized()
250
+ validate_worksheet
251
+ if @workbook.fonts[font_id()][:font][:i].nil?
252
+ false
253
+ else
254
+ true
255
+ end
256
+ end
257
+
258
+ # returns if font is bolded
259
+ def is_bolded()
260
+ validate_worksheet
261
+ if @workbook.fonts[font_id()][:font][:b].nil?
262
+ false
263
+ else
264
+ true
265
+ end
266
+ end
267
+
268
+ # returns if font is underlined
269
+ def is_underlined()
270
+ validate_worksheet
271
+ xf = @workbook.get_style_attributes(@workbook.get_style(@style_index))
272
+ if @workbook.fonts[font_id()][:font][:u].nil?
273
+ false
274
+ else
275
+ true
276
+ end
277
+ end
278
+
279
+ # returns if font has a strike through it
280
+ def is_struckthrough()
281
+ validate_worksheet
282
+ xf = @workbook.get_style_attributes(@workbook.get_style(@style_index))
283
+ if @workbook.fonts[font_id()][:font][:strike].nil?
284
+ false
285
+ else
286
+ true
287
+ end
288
+ end
289
+
290
+ # returns cell's font name
291
+ def font_name()
292
+ validate_worksheet
293
+ @workbook.fonts[font_id()][:font][:name][:attributes][:val]
294
+ end
295
+
296
+ # returns cell's font size
297
+ def font_size()
298
+ validate_worksheet
299
+ return @workbook.fonts[font_id()][:font][:sz][:attributes][:val]
300
+ end
301
+
302
+ # returns cell's font color
303
+ def font_color()
304
+ validate_worksheet
305
+ if @workbook.fonts[font_id()][:font][:color].nil?
306
+ '000000' #black
307
+ else
308
+ @workbook.fonts[font_id()][:font][:color][:attributes][:rgb]
309
+ end
310
+ end
311
+
312
+ # returns cell's fill color
313
+ def fill_color()
314
+ validate_worksheet
315
+ xf = @workbook.get_style_attributes(@workbook.get_style(@style_index))
316
+ return @workbook.get_fill_color(xf)
317
+ end
318
+
319
+ # returns cell's horizontal alignment
320
+ def horizontal_alignment()
321
+ validate_worksheet
322
+ xf_obj = @workbook.get_style(@style_index)
323
+ if xf_obj[:alignment].nil? || xf_obj[:alignment][:attributes].nil?
324
+ return nil
325
+ end
326
+ xf_obj[:alignment][:attributes][:horizontal].to_s
327
+ end
328
+
329
+ # returns cell's vertical alignment
330
+ def vertical_alignment()
331
+ validate_worksheet
332
+ xf_obj = @workbook.get_style(@style_index)
333
+ if xf_obj[:alignment].nil? || xf_obj[:alignment][:attributes].nil?
334
+ return nil
335
+ end
336
+ xf_obj[:alignment][:attributes][:vertical].to_s
337
+ end
338
+
339
+ # returns cell's top border
340
+ def border_top()
341
+ return get_border(:top)
342
+ end
343
+
344
+ # returns cell's left border
345
+ def border_left()
346
+ return get_border(:left)
347
+ end
348
+
349
+ # returns cell's right border
350
+ def border_right()
351
+ return get_border(:right)
352
+ end
353
+
354
+ # returns cell's bottom border
355
+ def border_bottom()
356
+ return get_border(:bottom)
357
+ end
358
+
359
+ # returns cell's diagonal border
360
+ def border_diagonal()
361
+ return get_border(:diagonal)
362
+ end
363
+
364
+ # returns Excel-style cell string from matrix indices
365
+ def Cell.convert_to_cell(row=0,col=0)
366
+ row_string = (row + 1).to_s #+1 for 0 indexing
367
+ col_string = ''
368
+
369
+ if row < 0 || col < 0
370
+ raise 'Invalid input: cannot convert negative numbers'
371
+ end
372
+
373
+ unless col == 0
374
+ col_length = 1+Integer(Math.log(col) / Math.log(26)) #opposite of 26**
375
+ else
376
+ col_length = 1
377
+ end
378
+
379
+ 1.upto(col_length) do |i|
380
+
381
+ #for the last digit, 0 should mean A. easy way to do this.
382
+ if i == col_length
383
+ col+=1
384
+ end
385
+
386
+ if col >= 26**(col_length-i)
387
+ int_val = col / 26**(col_length-i) #+1 for 0 indexing
388
+ int_val += 64 #converts 1 to A, etc.
389
+
390
+ col_string += int_val.chr
391
+
392
+ #intval multiplier decrements by placeholder, essentially
393
+ #a B subtracts more than an A this way.
394
+ col -= (int_val-64)*26**(col_length-i)
395
+ end
396
+ end
397
+ col_string+row_string
398
+ end
399
+
400
+ def inspect
401
+ str = "(#{@row},#{@column}): #{@value}"
402
+ str += " =#{@formula}" if @formula
403
+ str += ", datatype = #{@datatype}, style_index = #{@style_index}"
404
+ return str
405
+ end
406
+
407
+ private
408
+
409
+ def change_border(direction, weight)
410
+ validate_worksheet
411
+ validate_border(weight)
412
+ @style_index = modify_border(@workbook,@style_index)
413
+ if @workbook.borders[border_id()][:border][direction][:attributes].nil?
414
+ @workbook.borders[border_id()][:border][direction][:attributes] = { :style => nil }
415
+ end
416
+ @workbook.borders[border_id()][:border][direction][:attributes][:style] = weight.to_s
417
+ end
418
+
419
+ def get_border(direction)
420
+ validate_worksheet
421
+
422
+ if @workbook.borders[border_id()][:border][direction][:attributes].nil?
423
+ return nil
424
+ end
425
+ return @workbook.borders[border_id()][:border][direction][:attributes][:style]
426
+ end
427
+
428
+ def validate_workbook()
429
+ unless @workbook.nil? || @workbook.worksheets.nil?
430
+ @workbook.worksheets.each do |sheet|
431
+ unless sheet.nil? || sheet.sheet_data.nil? || sheet.sheet_data[@row].nil?
432
+ if sheet.sheet_data[@row][@column] == self
433
+ return
434
+ end
435
+ end
436
+ end
437
+ end
438
+ raise "This cell #{self} is not in workbook #{@workbook}"
439
+ end
440
+
441
+ def validate_worksheet()
442
+ if !@worksheet.nil? && @worksheet[@row][@column] == self
443
+ return
444
+ else
445
+ raise "This cell #{self} is not in worksheet #{worksheet}"
446
+ end
447
+ end
448
+
449
+ def xf_id()
450
+ @workbook.get_style_attributes(@workbook.get_style(@style_index.to_s))
451
+ end
452
+
453
+ def border_id()
454
+ xf_id()[:borderId].to_s
455
+ end
456
+
457
+ def font_id()
458
+ xf_id()[:fontId].to_s
459
+ end
460
+ end
461
+ end
@@ -0,0 +1,14 @@
1
+ module RubyXL
2
+ class Color
3
+
4
+ #validates hex color code, no '#' allowed
5
+ def Color.validate_color(color)
6
+ if color =~ /^([a-f]|[A-F]|[0-9]){6}$/
7
+ return true
8
+ else
9
+ raise 'invalid color'
10
+ end
11
+ end
12
+
13
+ end
14
+ end