rspreadsheet 0.2.15 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -1
- data/.travis.yml +5 -4
- data/DEVEL_BLOG.md +18 -2
- data/GUIDE.md +5 -0
- data/Guardfile +3 -3
- data/README.md +9 -9
- data/lib/helpers/class_extensions.rb +101 -38
- data/lib/rspreadsheet.rb +2 -1
- data/lib/rspreadsheet/cell.rb +110 -19
- data/lib/rspreadsheet/image.rb +118 -0
- data/lib/rspreadsheet/row.rb +14 -369
- data/lib/rspreadsheet/tools.rb +20 -1
- data/lib/rspreadsheet/version.rb +1 -1
- data/lib/rspreadsheet/workbook.rb +81 -20
- data/lib/rspreadsheet/worksheet.rb +31 -10
- data/lib/rspreadsheet/xml_tied_array.rb +179 -0
- data/lib/rspreadsheet/xml_tied_item.rb +111 -0
- data/lib/rspreadsheet/xml_tied_repeatable.rb +151 -0
- data/reinstall_local_gem.sh +2 -2
- data/rspreadsheet.gemspec +15 -3
- data/spec/cell_spec.rb +82 -1
- data/spec/class_extensions_spec.rb +49 -0
- data/spec/image_spec.rb +104 -0
- data/spec/included_image_spec.rb +8 -0
- data/spec/io_spec.rb +39 -27
- data/spec/row_spec.rb +16 -1
- data/spec/rspreadsheet_spec.rb +94 -35
- data/spec/spec_helper.rb +0 -1
- data/spec/test-image-blue.png +0 -0
- data/spec/test-image.png +0 -0
- data/spec/testfile1.ods +0 -0
- data/spec/testfile2-images.ods +0 -0
- data/spec/workbook_spec.rb +27 -0
- data/spec/worksheet_spec.rb +9 -2
- metadata +20 -47
- data/investigate.rb +0 -19
- data/lib/rspreadsheet/xml_tied.rb +0 -253
@@ -0,0 +1,118 @@
|
|
1
|
+
module Rspreadsheet
|
2
|
+
|
3
|
+
# Represents images embeded in a Worksheet
|
4
|
+
class WorksheetImages
|
5
|
+
include XMLTiedArray
|
6
|
+
def initialize(parent_worksheet)
|
7
|
+
initialize_xml_tied_array
|
8
|
+
@worksheet = parent_worksheet
|
9
|
+
end
|
10
|
+
|
11
|
+
def insert_image(filename,mime='image/png')
|
12
|
+
if xmlnode.nil? #TODO: this needs to be solved more generally maybe on XMLTiedArray level
|
13
|
+
@worksheet.xmlnode
|
14
|
+
end
|
15
|
+
push_new
|
16
|
+
last.initialize_from_file(filename,mime)
|
17
|
+
end
|
18
|
+
|
19
|
+
# @!group XMLTiedArray_WithRepeatableItems related methods
|
20
|
+
def subitem_xml_options; {:xml_items_node_name => 'frame', :xml_items_node_namespace => 'draw'} end
|
21
|
+
def prepare_subitem(index); Image.new(self,index) end
|
22
|
+
def xmlnode; @worksheet.xmlnode.find('./table:shapes').first end
|
23
|
+
def prepare_empty_xmlnode
|
24
|
+
Tools.insert_as_first_node_child(
|
25
|
+
@worksheet.xmlnode,
|
26
|
+
Tools.prepare_ns_node('table', 'shapes')
|
27
|
+
)
|
28
|
+
end
|
29
|
+
def prepare_empty_subnode
|
30
|
+
main_node = super # prepares <draw:frame/> node but it is entirely empty
|
31
|
+
[
|
32
|
+
['draw', 'z-index', '1'],
|
33
|
+
['draw', 'name', 'test'],
|
34
|
+
['draw', 'style-name', 'gr1'],
|
35
|
+
['draw', 'text-style-name', 'P1'],
|
36
|
+
['svg', 'width', '11.63mm'],
|
37
|
+
['svg', 'height', '10.83mm']
|
38
|
+
].each do |line|
|
39
|
+
Tools.set_ns_attribute(main_node,line[0],line[1],line[2])
|
40
|
+
end
|
41
|
+
|
42
|
+
sub_node = Tools.prepare_ns_node('draw', 'image')
|
43
|
+
[
|
44
|
+
['xlink', 'type', 'simple'],
|
45
|
+
['xlink', 'show', 'embed'],
|
46
|
+
['xlink', 'actuate', 'onLoad']
|
47
|
+
].each do |line|
|
48
|
+
Tools.set_ns_attribute(sub_node,line[0],line[1],line[2])
|
49
|
+
end
|
50
|
+
|
51
|
+
sub_node << Tools.prepare_ns_node('text','p')
|
52
|
+
main_node << sub_node
|
53
|
+
main_node
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
# Represents an image included in the spreadsheet. The Image can NOT exist
|
59
|
+
# "detached" from an spreadsheet
|
60
|
+
class Image < XMLTiedItem
|
61
|
+
attr_reader :mime
|
62
|
+
|
63
|
+
def initialize(worksheet,index)
|
64
|
+
super(worksheet,index)
|
65
|
+
@original_filename = nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def initialize_from_file(filename,mime)
|
69
|
+
# ověřit, zda soubor na disku existuje TODO: tady by to chtělo zobecnit na IO
|
70
|
+
raise 'File does not exist or it is not accessible' unless File.exists?(filename)
|
71
|
+
@original_filename = filename
|
72
|
+
@mime = mime
|
73
|
+
self
|
74
|
+
end
|
75
|
+
def xml_image_subnode
|
76
|
+
xmlnode.find('./draw:image').first
|
77
|
+
end
|
78
|
+
|
79
|
+
def move_to(ax,ay)
|
80
|
+
self.x = ax
|
81
|
+
self.y = ay
|
82
|
+
end
|
83
|
+
|
84
|
+
def original_filename; @original_filename end
|
85
|
+
|
86
|
+
def copy_to(ax,ay,worksheet)
|
87
|
+
img = worksheet.insert_image_to(ax,ay,@original_filename)
|
88
|
+
img.height = height
|
89
|
+
img.width = width
|
90
|
+
end
|
91
|
+
|
92
|
+
# TODO: put some sanity check for values into these
|
93
|
+
def x=(value); Tools.set_ns_attribute(xmlnode,'svg','x', value) end
|
94
|
+
def y=(value); Tools.set_ns_attribute(xmlnode,'svg','y', value) end
|
95
|
+
def width=(value); Tools.set_ns_attribute(xmlnode,'svg','width', value) end
|
96
|
+
def height=(value); Tools.set_ns_attribute(xmlnode,'svg','height',value) end
|
97
|
+
def name=(value); Tools.set_ns_attribute(xmlnode,'draw','name', value) end
|
98
|
+
def x; Tools.get_ns_attribute_value(xmlnode,'svg','x') end
|
99
|
+
def y; Tools.get_ns_attribute_value(xmlnode,'svg','y') end
|
100
|
+
def width; Tools.get_ns_attribute_value(xmlnode,'svg','width') end
|
101
|
+
def height; Tools.get_ns_attribute_value(xmlnode,'svg','height') end
|
102
|
+
def name; Tools.get_ns_attribute_value(xmlnode, 'draw', 'name', nil) end
|
103
|
+
def internal_filename; Tools.get_ns_attribute_value(xml_image_subnode,'xlink','href') end
|
104
|
+
def internal_filename=(value)
|
105
|
+
Tools.set_ns_attribute(xml_image_subnode,'xlink','href', value )
|
106
|
+
end
|
107
|
+
|
108
|
+
# @!group XMLTiedItem related methods
|
109
|
+
def xml_options; {:xml_items_node_name => 'frame'} end
|
110
|
+
|
111
|
+
#
|
112
|
+
# Note: when creating new empty image we might have included xlink:type attribute but specification
|
113
|
+
# says it has default value simple [1] so we omit it. The same goes for
|
114
|
+
# [1](http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#attribute-xlink_type)
|
115
|
+
#
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
data/lib/rspreadsheet/row.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'rspreadsheet/cell'
|
2
|
-
require 'rspreadsheet/
|
3
|
-
|
2
|
+
require 'rspreadsheet/xml_tied_repeatable'
|
4
3
|
|
5
4
|
module Rspreadsheet
|
6
5
|
|
@@ -9,7 +8,7 @@ module Rspreadsheet
|
|
9
8
|
#
|
10
9
|
# @row = @worksheet.row(5)
|
11
10
|
#
|
12
|
-
# Mostly you will this object to access
|
11
|
+
# Mostly you will this object to access values of cells in the row
|
13
12
|
#
|
14
13
|
# @row[2] # identical to @worksheet[5,2] or @row.cells(2).value
|
15
14
|
#
|
@@ -25,22 +24,19 @@ module Rspreadsheet
|
|
25
24
|
# and shifts all other rows down/up appropriatelly.
|
26
25
|
|
27
26
|
class Row < XMLTiedItem
|
28
|
-
include
|
27
|
+
include XMLTiedArray_WithRepeatableItems
|
29
28
|
## @return [Worksheet] worksheet which contains the row
|
30
29
|
# @!attribute [r] worksheet
|
31
|
-
|
30
|
+
def worksheet; parent end
|
32
31
|
## @return [Integer] row index of the row
|
33
32
|
# @!attribute [r] rowi
|
34
|
-
|
35
|
-
|
33
|
+
def rowi; index end
|
34
|
+
|
36
35
|
def initialize(aworksheet,arowi)
|
37
|
-
|
38
|
-
|
39
|
-
@itemcache = Hash.new #TODO: move to module XMLTiedArray
|
36
|
+
initialize_xml_tied_array
|
37
|
+
initialize_xml_tied_item(aworksheet,arowi)
|
40
38
|
end
|
41
39
|
|
42
|
-
def xmlnode; parent.find_my_subnode_respect_repeated(index, xml_options) end
|
43
|
-
|
44
40
|
# @!group Syntactic sugar
|
45
41
|
def cells(*params); subitems(*params) end
|
46
42
|
alias :cell :cells
|
@@ -91,7 +87,7 @@ class Row < XMLTiedItem
|
|
91
87
|
if myxmlnode.nil?
|
92
88
|
[]
|
93
89
|
else
|
94
|
-
|
90
|
+
worksheet.find_nonempty_subnode_indexes(myxmlnode, subitem_xml_options)
|
95
91
|
end
|
96
92
|
end
|
97
93
|
alias :used_range :range
|
@@ -103,370 +99,19 @@ class Row < XMLTiedItem
|
|
103
99
|
# @!group Private methods, which should not be called directly
|
104
100
|
# @private
|
105
101
|
# shifts internal represetation of row by diff. This should not be called directly
|
106
|
-
# by user, it is only used by
|
102
|
+
# by user, it is only used by XMLTiedArray_WithRepeatableItems as hook when shifting around rows
|
107
103
|
def _shift_by(diff)
|
108
104
|
super
|
109
|
-
@itemcache.each_value{ |cell| cell.set_rowi(
|
105
|
+
@itemcache.each_value{ |cell| cell.set_rowi(rowi) }
|
110
106
|
end
|
111
107
|
|
112
108
|
private
|
113
|
-
# @!group
|
109
|
+
# @!group XMLTiedArray_WithRepeatableItems related methods
|
114
110
|
def subitem_xml_options; {:xml_items_node_name => 'table-cell', :xml_repeated_attribute => 'number-columns-repeated'} end
|
115
|
-
def prepare_subitem(coli); Cell.new(
|
111
|
+
def prepare_subitem(coli); Cell.new(worksheet,rowi,coli) end
|
116
112
|
# @!group XMLTiedItem related methods and extensions
|
117
113
|
def xml_options; {:xml_items_node_name => 'table-row', :xml_repeated_attribute => 'number-rows-repeated'} end
|
118
|
-
def parent; @worksheet end
|
119
|
-
def index; @rowi end
|
120
|
-
def set_index(value); @rowi=value end
|
121
|
-
end
|
122
|
-
|
123
|
-
# class Row
|
124
|
-
# def initialize
|
125
|
-
# @readonly = :unknown
|
126
|
-
# @cells = {}
|
127
|
-
# end
|
128
|
-
# def worksheet; @parent_array.worksheet end
|
129
|
-
# def parent_array; @parent_array end # for debug only
|
130
|
-
# def used_col_range; 1..first_unused_column_index-1 end
|
131
|
-
# def used_range; used_col_range end
|
132
|
-
# def first_unused_column_index; raise 'this should be redefined in subclasses' end
|
133
|
-
# end
|
134
|
-
|
135
|
-
|
136
|
-
# --------------------------
|
137
|
-
|
138
|
-
|
139
|
-
# # XmlTiedArrayItemGroup is internal representation of repeated items in XmlTiedArray.
|
140
|
-
# class XmlTiedArrayItemGroup
|
141
|
-
# # extend Forwardable
|
142
|
-
# # delegate [:normalize ] => :@row_group
|
143
|
-
#
|
144
|
-
# def normalize; @rowgroup.normalize end
|
145
|
-
|
146
|
-
# end
|
147
|
-
|
148
|
-
# array which synchronizes with xml structure and reflects. number-xxx-repeated attributes
|
149
|
-
# also caches returned objects for indexes.
|
150
|
-
# options must contain
|
151
|
-
# :xml_items, :xml_repeated_attribute, :object_type
|
152
|
-
|
153
|
-
# class XmlTiedArray < Array
|
154
|
-
# def initialize(axmlnode, options={}) # TODO get rid of XmlTiedArray
|
155
|
-
# @xmlnode = axmlnode
|
156
|
-
# @options = options
|
157
|
-
#
|
158
|
-
# missing_options = [:xml_repeated_attribute,:xml_items_node_name,:object_type]-@options.keys
|
159
|
-
# raise "Some options missing (#{missing_options.inspect})" unless missing_options.empty?
|
160
|
-
#
|
161
|
-
# unless @xmlnode.nil?
|
162
|
-
# @xmlnode.elements.select{|node| node.name == options[:xml_items_node_name]}.each do |group_source_node|
|
163
|
-
# self << parse_xml_to_group(group_source_node) # it is in @xmlnode so suffices to add object to @rowgroups
|
164
|
-
# end
|
165
|
-
# end
|
166
|
-
# @itemcache=Hash.new()
|
167
|
-
# end
|
168
|
-
# def parse_xml_to_group(size_or_xmlnode) # parses xml to new RowGroup which can be added at the end
|
169
|
-
# # reading params
|
170
|
-
# if size_or_xmlnode.kind_of? LibXML::XML::Node
|
171
|
-
# size = (size_or_xmlnode[@options[:xml_repeated_attribute]] || 1).to_i
|
172
|
-
# node = size_or_xmlnode
|
173
|
-
# elsif size_or_xmlnode.to_i>0
|
174
|
-
# size = size_or_xmlnode.to_i
|
175
|
-
# node = nil
|
176
|
-
# else
|
177
|
-
# return nil
|
178
|
-
# end
|
179
|
-
# index = first_unused_index
|
180
|
-
# # construct result
|
181
|
-
# Rspreadsheet::XmlTiedArrayItemGroup.new(self,index..index+size-1,node)
|
182
|
-
# end
|
183
|
-
# def add_item_group(size_or_xmlnode)
|
184
|
-
# result = parse_xml_to_group(size_or_xmlnode)
|
185
|
-
# self << result
|
186
|
-
# @xmlnode << result.xmlnode
|
187
|
-
# result
|
188
|
-
# end
|
189
|
-
# def first_unused_index
|
190
|
-
# empty? ? 1 : last.range.end+1
|
191
|
-
# end
|
192
|
-
# # prolonges the RowArray to cantain rowi and returns it
|
193
|
-
# def detach_of_bound_item(index)
|
194
|
-
# fill_row_group_size = index-first_unused_index
|
195
|
-
# if fill_row_group_size>0
|
196
|
-
# add_item_group(fill_row_group_size)
|
197
|
-
# end
|
198
|
-
# add_item_group(1)
|
199
|
-
# get_item(index) # aby se odpoved nacacheovala
|
200
|
-
# end
|
201
|
-
# def get_item_group(index)
|
202
|
-
# find{ |item_group| item_group.range.cover?(index) }
|
203
|
-
# end
|
204
|
-
# def detach_item(index); get_item(index) end # TODO předělat do lazy podoby, kdy tohle nebude stejny
|
205
|
-
# def get_item(index)
|
206
|
-
# if index>= first_unused_index
|
207
|
-
# nil
|
208
|
-
# else
|
209
|
-
# @itemcache[index] ||= Rspreadsheet::XmlTiedArrayItem.new(self,index)
|
210
|
-
# end
|
211
|
-
# end
|
212
|
-
# # This detaches item index from the group and perhaps splits the RowGroup
|
213
|
-
# # into two pieces. This makes the row individually editable.
|
214
|
-
# def detach(index)
|
215
|
-
# group_index = get_group_index(index)
|
216
|
-
# item_group = self[group_index]
|
217
|
-
# range = item_group.range
|
218
|
-
# return self if range==(index..index)
|
219
|
-
#
|
220
|
-
# # prepare new components
|
221
|
-
# replaceby = []
|
222
|
-
# replaceby << RowGroup.new(self,range.begin..index-1)
|
223
|
-
# replaceby << (result = SingleRow.new(self,index))
|
224
|
-
# replaceby << RowGroup.new(self,index+1..range.end)
|
225
|
-
#
|
226
|
-
# # put original range somewhere in replaceby and shorten it
|
227
|
-
#
|
228
|
-
# if index>range.begin
|
229
|
-
# replaceby[0] = item_group
|
230
|
-
# item_group.range = range.begin..index-1
|
231
|
-
# else
|
232
|
-
# replaceby[2] = item_group
|
233
|
-
# item_group.range = index+1..range.end
|
234
|
-
# end
|
235
|
-
#
|
236
|
-
# # normalize and delete empty parts
|
237
|
-
# replaceby = replaceby.map(&:normalize).compact
|
238
|
-
#
|
239
|
-
# # do the replacement in xml
|
240
|
-
# marker = LibXML::XML::Node.new('temporarymarker')
|
241
|
-
# item_group.xmlnode.next = marker
|
242
|
-
# item_group.xmlnode.remove!
|
243
|
-
# replaceby.each{ |rg|
|
244
|
-
# marker.prev = rg.xmlnode
|
245
|
-
# }
|
246
|
-
# marker.remove!
|
247
|
-
#
|
248
|
-
# # do the replacement in array
|
249
|
-
# self[group_index..group_index]=replaceby
|
250
|
-
# result
|
251
|
-
# end
|
252
|
-
# private
|
253
|
-
# def get_group_index(index)
|
254
|
-
# self.find_index{ |rowgroup| rowgroup.range.cover?(index) }
|
255
|
-
# end
|
256
|
-
# end
|
257
|
-
|
258
|
-
# class XmlTiedArrayItem
|
259
|
-
# attr_reader :index
|
260
|
-
# def initialize(aarray,aindex)
|
261
|
-
# @array = aarray
|
262
|
-
# @index = aindex
|
263
|
-
# if self.virtual?
|
264
|
-
# @object = nil
|
265
|
-
# else
|
266
|
-
# @object = @array.options[:object_type].new(group.xmlnode)
|
267
|
-
# end
|
268
|
-
# end
|
269
|
-
# def group; @array.get_item_group(index) end
|
270
|
-
# def repeated?; group.repeated? end
|
271
|
-
# def virtual?; ! self.repeated? end
|
272
|
-
# def array
|
273
|
-
# raise 'Group empty' if @group.nil?
|
274
|
-
# @array
|
275
|
-
# end
|
276
|
-
# end
|
277
|
-
|
278
|
-
# class RowArray < XmlTiedArray
|
279
|
-
# attr_reader :row_array_cache
|
280
|
-
# def initialize(aworksheet,aworksheet_node)
|
281
|
-
# @worksheet = aworksheet
|
282
|
-
# @row_array_cache = Hash.new()
|
283
|
-
# super(aworksheet_node, :xml_items_node_name => 'table-row', :xml_repeated_attribute => xml_repeated_attribute, :object_type=>Row)
|
284
|
-
# end
|
285
|
-
# def get_row(rowi)
|
286
|
-
# if @row_array_cache.has_key?(rowi)
|
287
|
-
# return @row_array_cache[rowi]
|
288
|
-
# end
|
289
|
-
# item = self.get_item(rowi)
|
290
|
-
# @row_array_cache[rowi] = if item.nil?
|
291
|
-
# if rowi>0 then Rspreadsheet::UninitializedEmptyRow.new(self,rowi) else nil end
|
292
|
-
# else
|
293
|
-
# if item.repeated?
|
294
|
-
# Rspreadsheet::MemberOfRowGroup.new(item.index, item.group.to_rowgroup)
|
295
|
-
# else
|
296
|
-
# Rspreadsheet::SingleRow.new_from_rowgroup(item.group.to_rowgroup)
|
297
|
-
# end
|
298
|
-
# end
|
299
|
-
# end
|
300
|
-
# # aliases
|
301
|
-
# def first_unused_row_index; first_unused_index end
|
302
|
-
# def worksheet; @worksheet end
|
303
|
-
# def detach_of_bound_row_group(index)
|
304
|
-
# super(index)
|
305
|
-
# return get_row(index)
|
306
|
-
# end
|
307
|
-
# end
|
308
|
-
|
309
|
-
# class Row
|
310
|
-
# def initialize
|
311
|
-
# @readonly = :unknown
|
312
|
-
# @cells = {}
|
313
|
-
# end
|
314
|
-
# def self.empty_row_node
|
315
|
-
# LibXML::XML::Node.new('table-row',nil, Tools.get_namespace('table'))
|
316
|
-
# end
|
317
|
-
# def worksheet; @parent_array.worksheet end
|
318
|
-
# def parent_array; @parent_array end # for debug only
|
319
|
-
# def used_col_range; 1..first_unused_column_index-1 end
|
320
|
-
# def used_range; used_col_range end
|
321
|
-
# def first_unused_column_index; raise 'this should be redefined in subclasses' end
|
322
|
-
# def cells(coli)
|
323
|
-
# coli = coli.to_i
|
324
|
-
# return nil if coli.to_i<=0
|
325
|
-
# @cells[coli] ||= get_cell(coli)
|
326
|
-
# end
|
327
|
-
# end
|
328
|
-
|
329
|
-
# class RowWithXMLNode < Row
|
330
|
-
# attr_accessor :xmlnode
|
331
|
-
# def style_name=(value); Tools.set_ns_attribute(@xmlnode,'table','style-name',value) end
|
332
|
-
# def get_cell(coli)
|
333
|
-
# Cell.new(self,coli,cellnodes(coli))
|
334
|
-
# end
|
335
|
-
# def nonemptycells
|
336
|
-
# nonemptycellsindexes.collect{ |index| cells(index) }
|
337
|
-
# end
|
338
|
-
# def nonemptycellsindexes
|
339
|
-
# used_col_range.to_a.select do |coli|
|
340
|
-
# cellnode = cellnodes(coli)
|
341
|
-
# !(cellnode.content.nil? or cellnode.content.empty? or cellnode.content =='') or
|
342
|
-
# !cellnode.attributes.to_a.reject{ |attr| attr.name == 'number-columns-repeated'}.empty?
|
343
|
-
# end
|
344
|
-
# end
|
345
|
-
# def cellnodes(coli)
|
346
|
-
# cellnode = nil
|
347
|
-
# while true
|
348
|
-
# curr_coli=1
|
349
|
-
# cellnode = @xmlnode.elements.select{|n| n.name=='table-cell'}.find do |el|
|
350
|
-
# curr_coli += (Tools.get_ns_attribute_value(el, 'table', 'number-columns-repeated') || 1).to_i
|
351
|
-
# curr_coli > coli
|
352
|
-
# end
|
353
|
-
# unless cellnode.nil?
|
354
|
-
# return cellnode
|
355
|
-
# else
|
356
|
-
# add_cell
|
357
|
-
# end
|
358
|
-
# end
|
359
|
-
# end
|
360
|
-
# def add_cell(repeated=1)
|
361
|
-
# cell = Cell.new(self,first_unused_column_index)
|
362
|
-
# Tools.set_ns_attribute(cell.xmlnode,'table','number-columns-repeated',repeated) if repeated>1
|
363
|
-
# @xmlnode << cell.xmlnode
|
364
|
-
# cell
|
365
|
-
# end
|
366
|
-
# def first_unused_column_index
|
367
|
-
# 1 + @xmlnode.elements.select{|n| n.name=='table-cell'}.reduce(0) do |sum, el|
|
368
|
-
# sum + (Tools.get_ns_attribute_value(el, 'table', 'number-columns-repeated') || 1).to_i
|
369
|
-
# end
|
370
|
-
# end
|
371
|
-
# end
|
372
|
-
|
373
|
-
# class RowGroup < RowWithXMLNode
|
374
|
-
# @readonly = :yes_always
|
375
|
-
# attr_reader :range
|
376
|
-
# attr_accessor :parent_array, :xmlnode
|
377
|
-
# def initialize(aparent_array,arange,axmlnode=nil)
|
378
|
-
# super()
|
379
|
-
# @parent_array = aparent_array
|
380
|
-
# @range = arange
|
381
|
-
# if axmlnode.nil?
|
382
|
-
# axmlnode = Row.empty_row_node
|
383
|
-
# Tools.set_ns_attribute(axmlnode,'table','number-rows-repeated',range.size) if range.size>1
|
384
|
-
# end
|
385
|
-
# @xmlnode = axmlnode
|
386
|
-
# end
|
387
|
-
# # returns SingleRow if size of range is 1 and nil if it is 0 or less
|
388
|
-
# def normalize
|
389
|
-
# case range.size
|
390
|
-
# when 2..Float::INFINITY then self
|
391
|
-
# when 1 then SingleRow.new_from_rowgroup(self)
|
392
|
-
# else nil
|
393
|
-
# end
|
394
|
-
# end
|
395
|
-
# def repeated; range.size end
|
396
|
-
# def repeated?; range.size>1 end
|
397
|
-
# def range=(arange)
|
398
|
-
# @range=arange
|
399
|
-
# Tools.set_ns_attribute(@xmlnode,'table','number-rows-repeated',range.size, 1)
|
400
|
-
# end
|
401
|
-
# end
|
402
|
-
|
403
|
-
# class SingleRow < RowWithXMLNode
|
404
|
-
# @readonly = :no
|
405
|
-
# attr_accessor :xmlnode
|
406
|
-
# # index Integer
|
407
|
-
# def initialize(aparent_array,aindex,axmlnode=nil)
|
408
|
-
# super()
|
409
|
-
# @parent_array = aparent_array
|
410
|
-
# @index = aindex
|
411
|
-
# if axmlnode.nil?
|
412
|
-
# axmlnode = Row.empty_row_node
|
413
|
-
# end
|
414
|
-
# @xmlnode = axmlnode
|
415
|
-
# end
|
416
|
-
# def self.new_from_rowgroup(rg)
|
417
|
-
# anode = rg.xmlnode
|
418
|
-
# Tools.remove_ns_attribute(anode,'table','number-rows-repeated')
|
419
|
-
# SingleRow.new(rg.parent_array,rg.range.begin,anode)
|
420
|
-
# end
|
421
|
-
# def normalize; self end
|
422
|
-
# def repeated?; false end
|
423
|
-
# def repeated; 1 end
|
424
|
-
# def range; (@index..@index) end
|
425
|
-
# def detach; self end
|
426
|
-
# def row; @index end
|
427
|
-
# def still_out_of_used_range?; false end
|
428
|
-
# end
|
429
|
-
|
430
|
-
# class LazyDetachableRow < Row
|
431
|
-
# @readonly = :yes_but_detachable
|
432
|
-
# def initialize(rowi)
|
433
|
-
# super()
|
434
|
-
# @index = rowi.to_i
|
435
|
-
# end
|
436
|
-
# def add_cell; detach.add_cell end
|
437
|
-
# def style_name=(value); detach.style_name=value end
|
438
|
-
# def row; @index end
|
439
|
-
# end
|
440
|
-
|
441
|
-
# ## there are not data in this object, they are taken from RowGroup, but this is only readonly
|
442
|
-
# class MemberOfRowGroup < LazyDetachableRow
|
443
|
-
# @readonly = :yes_but_detachable
|
444
|
-
# extend Forwardable
|
445
|
-
# delegate [:repeated?, :repeated, :xmlnode, :parent_array] => :@row_group
|
446
|
-
# attr_accessor :row_group # for dubugging
|
447
|
-
#
|
448
|
-
# # @index Integer
|
449
|
-
# # @row_group RepeatedRow
|
450
|
-
# def initialize(arowi,arow_group)
|
451
|
-
# super(arowi)
|
452
|
-
# @row_group = arow_group
|
453
|
-
# raise 'Wrong parameter given - class is '+@row_group.class.to_a unless @row_group.is_a? RowGroup
|
454
|
-
# end
|
455
|
-
# def detach # detaches MemberOfRowGroup from its RowGroup perhaps splitting RowGroup
|
456
|
-
# @row_group.parent_array.detach(@index)
|
457
|
-
# end
|
458
|
-
# def get_cell(coli)
|
459
|
-
# c = Cell.new(self,coli,@row_group.cellnodes(coli))
|
460
|
-
# c.mode = :repeated
|
461
|
-
# c
|
462
|
-
# end
|
463
|
-
# def first_unused_column_index
|
464
|
-
# @row_group.first_unused_column_index
|
465
|
-
# end
|
466
|
-
# def nonemptycells
|
467
|
-
# @row_group.nonemptycellsindexes.collect{ |coli| cells(coli) }
|
468
|
-
# end
|
469
|
-
# end
|
470
114
|
|
115
|
+
end
|
471
116
|
|
472
117
|
end
|