rspreadsheet 0.2.15 → 0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|