lib/rspreadsheet/row.rb in rspreadsheet-0.2.15 vs lib/rspreadsheet/row.rb in rspreadsheet-0.3

- old
+ new

@@ -1,17 +1,16 @@ require 'rspreadsheet/cell' -require 'rspreadsheet/xml_tied' +require 'rspreadsheet/xml_tied_repeatable' - module Rspreadsheet # Represents a row in a spreadsheet which has coordinates, contains value, formula and can be formated. # You can get this object like this (suppose that @worksheet contains {Rspreadsheet::Worksheet} object) # # @row = @worksheet.row(5) # -# Mostly you will this object to access row cells values +# Mostly you will this object to access values of cells in the row # # @row[2] # identical to @worksheet[5,2] or @row.cells(2).value # # or directly row `Cell` objects # @@ -23,26 +22,23 @@ # @row.delete # deletes row # # and shifts all other rows down/up appropriatelly. class Row < XMLTiedItem - include XMLTiedArray + include XMLTiedArray_WithRepeatableItems ## @return [Worksheet] worksheet which contains the row # @!attribute [r] worksheet - attr_reader :worksheet + def worksheet; parent end ## @return [Integer] row index of the row # @!attribute [r] rowi - attr_reader :rowi - + def rowi; index end + def initialize(aworksheet,arowi) - @worksheet = aworksheet - @rowi = arowi - @itemcache = Hash.new #TODO: move to module XMLTiedArray + initialize_xml_tied_array + initialize_xml_tied_item(aworksheet,arowi) end - def xmlnode; parent.find_my_subnode_respect_repeated(index, xml_options) end - # @!group Syntactic sugar def cells(*params); subitems(*params) end alias :cell :cells ## @return [String or Float or Date] value of the cell @@ -89,11 +85,11 @@ def nonemptycellsindexes myxmlnode = xmlnode if myxmlnode.nil? [] else - @worksheet.find_nonempty_subnode_indexes(myxmlnode, {:xml_items_node_name => 'table-cell', :xml_repeated_attribute => 'number-columns-repeated'}) + worksheet.find_nonempty_subnode_indexes(myxmlnode, subitem_xml_options) end end alias :used_range :range # Inserts row above itself (and shifts itself and all following rows down) def add_row_above @@ -101,372 +97,21 @@ end # @!group Private methods, which should not be called directly # @private # shifts internal represetation of row by diff. This should not be called directly - # by user, it is only used by XMLTiedArray as hook when shifting around rows + # by user, it is only used by XMLTiedArray_WithRepeatableItems as hook when shifting around rows def _shift_by(diff) super - @itemcache.each_value{ |cell| cell.set_rowi(@rowi) } + @itemcache.each_value{ |cell| cell.set_rowi(rowi) } end private - # @!group XMLTiedArray related methods + # @!group XMLTiedArray_WithRepeatableItems related methods def subitem_xml_options; {:xml_items_node_name => 'table-cell', :xml_repeated_attribute => 'number-columns-repeated'} end - def prepare_subitem(coli); Cell.new(@worksheet,@rowi,coli) end + def prepare_subitem(coli); Cell.new(worksheet,rowi,coli) end # @!group XMLTiedItem related methods and extensions def xml_options; {:xml_items_node_name => 'table-row', :xml_repeated_attribute => 'number-rows-repeated'} end - def parent; @worksheet end - def index; @rowi end - def set_index(value); @rowi=value end -end -# class Row -# def initialize -# @readonly = :unknown -# @cells = {} -# end -# def worksheet; @parent_array.worksheet end -# def parent_array; @parent_array end # for debug only -# def used_col_range; 1..first_unused_column_index-1 end -# def used_range; used_col_range end -# def first_unused_column_index; raise 'this should be redefined in subclasses' end -# end - - -# -------------------------- - - -# # XmlTiedArrayItemGroup is internal representation of repeated items in XmlTiedArray. -# class XmlTiedArrayItemGroup -# # extend Forwardable -# # delegate [:normalize ] => :@row_group -# -# def normalize; @rowgroup.normalize end - -# end - -# array which synchronizes with xml structure and reflects. number-xxx-repeated attributes -# also caches returned objects for indexes. -# options must contain -# :xml_items, :xml_repeated_attribute, :object_type - -# class XmlTiedArray < Array -# def initialize(axmlnode, options={}) # TODO get rid of XmlTiedArray -# @xmlnode = axmlnode -# @options = options -# -# missing_options = [:xml_repeated_attribute,:xml_items_node_name,:object_type]-@options.keys -# raise "Some options missing (#{missing_options.inspect})" unless missing_options.empty? -# -# unless @xmlnode.nil? -# @xmlnode.elements.select{|node| node.name == options[:xml_items_node_name]}.each do |group_source_node| -# self << parse_xml_to_group(group_source_node) # it is in @xmlnode so suffices to add object to @rowgroups -# end -# end -# @itemcache=Hash.new() -# end -# def parse_xml_to_group(size_or_xmlnode) # parses xml to new RowGroup which can be added at the end -# # reading params -# if size_or_xmlnode.kind_of? LibXML::XML::Node -# size = (size_or_xmlnode[@options[:xml_repeated_attribute]] || 1).to_i -# node = size_or_xmlnode -# elsif size_or_xmlnode.to_i>0 -# size = size_or_xmlnode.to_i -# node = nil -# else -# return nil -# end -# index = first_unused_index -# # construct result -# Rspreadsheet::XmlTiedArrayItemGroup.new(self,index..index+size-1,node) -# end -# def add_item_group(size_or_xmlnode) -# result = parse_xml_to_group(size_or_xmlnode) -# self << result -# @xmlnode << result.xmlnode -# result -# end -# def first_unused_index -# empty? ? 1 : last.range.end+1 -# end -# # prolonges the RowArray to cantain rowi and returns it -# def detach_of_bound_item(index) -# fill_row_group_size = index-first_unused_index -# if fill_row_group_size>0 -# add_item_group(fill_row_group_size) -# end -# add_item_group(1) -# get_item(index) # aby se odpoved nacacheovala -# end -# def get_item_group(index) -# find{ |item_group| item_group.range.cover?(index) } -# end -# def detach_item(index); get_item(index) end # TODO předělat do lazy podoby, kdy tohle nebude stejny -# def get_item(index) -# if index>= first_unused_index -# nil -# else -# @itemcache[index] ||= Rspreadsheet::XmlTiedArrayItem.new(self,index) -# end -# end -# # This detaches item index from the group and perhaps splits the RowGroup -# # into two pieces. This makes the row individually editable. -# def detach(index) -# group_index = get_group_index(index) -# item_group = self[group_index] -# range = item_group.range -# return self if range==(index..index) -# -# # prepare new components -# replaceby = [] -# replaceby << RowGroup.new(self,range.begin..index-1) -# replaceby << (result = SingleRow.new(self,index)) -# replaceby << RowGroup.new(self,index+1..range.end) -# -# # put original range somewhere in replaceby and shorten it -# -# if index>range.begin -# replaceby[0] = item_group -# item_group.range = range.begin..index-1 -# else -# replaceby[2] = item_group -# item_group.range = index+1..range.end -# end -# -# # normalize and delete empty parts -# replaceby = replaceby.map(&:normalize).compact -# -# # do the replacement in xml -# marker = LibXML::XML::Node.new('temporarymarker') -# item_group.xmlnode.next = marker -# item_group.xmlnode.remove! -# replaceby.each{ |rg| -# marker.prev = rg.xmlnode -# } -# marker.remove! -# -# # do the replacement in array -# self[group_index..group_index]=replaceby -# result -# end -# private -# def get_group_index(index) -# self.find_index{ |rowgroup| rowgroup.range.cover?(index) } -# end -# end - -# class XmlTiedArrayItem -# attr_reader :index -# def initialize(aarray,aindex) -# @array = aarray -# @index = aindex -# if self.virtual? -# @object = nil -# else -# @object = @array.options[:object_type].new(group.xmlnode) -# end -# end -# def group; @array.get_item_group(index) end -# def repeated?; group.repeated? end -# def virtual?; ! self.repeated? end -# def array -# raise 'Group empty' if @group.nil? -# @array -# end -# end - -# class RowArray < XmlTiedArray -# attr_reader :row_array_cache -# def initialize(aworksheet,aworksheet_node) -# @worksheet = aworksheet -# @row_array_cache = Hash.new() -# super(aworksheet_node, :xml_items_node_name => 'table-row', :xml_repeated_attribute => xml_repeated_attribute, :object_type=>Row) -# end -# def get_row(rowi) -# if @row_array_cache.has_key?(rowi) -# return @row_array_cache[rowi] -# end -# item = self.get_item(rowi) -# @row_array_cache[rowi] = if item.nil? -# if rowi>0 then Rspreadsheet::UninitializedEmptyRow.new(self,rowi) else nil end -# else -# if item.repeated? -# Rspreadsheet::MemberOfRowGroup.new(item.index, item.group.to_rowgroup) -# else -# Rspreadsheet::SingleRow.new_from_rowgroup(item.group.to_rowgroup) -# end -# end -# end -# # aliases -# def first_unused_row_index; first_unused_index end -# def worksheet; @worksheet end -# def detach_of_bound_row_group(index) -# super(index) -# return get_row(index) -# end -# end - -# class Row -# def initialize -# @readonly = :unknown -# @cells = {} -# end -# def self.empty_row_node -# LibXML::XML::Node.new('table-row',nil, Tools.get_namespace('table')) -# end -# def worksheet; @parent_array.worksheet end -# def parent_array; @parent_array end # for debug only -# def used_col_range; 1..first_unused_column_index-1 end -# def used_range; used_col_range end -# def first_unused_column_index; raise 'this should be redefined in subclasses' end -# def cells(coli) -# coli = coli.to_i -# return nil if coli.to_i<=0 -# @cells[coli] ||= get_cell(coli) -# end -# end - -# class RowWithXMLNode < Row -# attr_accessor :xmlnode -# def style_name=(value); Tools.set_ns_attribute(@xmlnode,'table','style-name',value) end -# def get_cell(coli) -# Cell.new(self,coli,cellnodes(coli)) -# end -# def nonemptycells -# nonemptycellsindexes.collect{ |index| cells(index) } -# end -# def nonemptycellsindexes -# used_col_range.to_a.select do |coli| -# cellnode = cellnodes(coli) -# !(cellnode.content.nil? or cellnode.content.empty? or cellnode.content =='') or -# !cellnode.attributes.to_a.reject{ |attr| attr.name == 'number-columns-repeated'}.empty? -# end -# end -# def cellnodes(coli) -# cellnode = nil -# while true -# curr_coli=1 -# cellnode = @xmlnode.elements.select{|n| n.name=='table-cell'}.find do |el| -# curr_coli += (Tools.get_ns_attribute_value(el, 'table', 'number-columns-repeated') || 1).to_i -# curr_coli > coli -# end -# unless cellnode.nil? -# return cellnode -# else -# add_cell -# end -# end -# end -# def add_cell(repeated=1) -# cell = Cell.new(self,first_unused_column_index) -# Tools.set_ns_attribute(cell.xmlnode,'table','number-columns-repeated',repeated) if repeated>1 -# @xmlnode << cell.xmlnode -# cell -# end -# def first_unused_column_index -# 1 + @xmlnode.elements.select{|n| n.name=='table-cell'}.reduce(0) do |sum, el| -# sum + (Tools.get_ns_attribute_value(el, 'table', 'number-columns-repeated') || 1).to_i -# end -# end -# end - -# class RowGroup < RowWithXMLNode -# @readonly = :yes_always -# attr_reader :range -# attr_accessor :parent_array, :xmlnode -# def initialize(aparent_array,arange,axmlnode=nil) -# super() -# @parent_array = aparent_array -# @range = arange -# if axmlnode.nil? -# axmlnode = Row.empty_row_node -# Tools.set_ns_attribute(axmlnode,'table','number-rows-repeated',range.size) if range.size>1 -# end -# @xmlnode = axmlnode -# end -# # returns SingleRow if size of range is 1 and nil if it is 0 or less -# def normalize -# case range.size -# when 2..Float::INFINITY then self -# when 1 then SingleRow.new_from_rowgroup(self) -# else nil -# end -# end -# def repeated; range.size end -# def repeated?; range.size>1 end -# def range=(arange) -# @range=arange -# Tools.set_ns_attribute(@xmlnode,'table','number-rows-repeated',range.size, 1) -# end -# end - -# class SingleRow < RowWithXMLNode -# @readonly = :no -# attr_accessor :xmlnode -# # index Integer -# def initialize(aparent_array,aindex,axmlnode=nil) -# super() -# @parent_array = aparent_array -# @index = aindex -# if axmlnode.nil? -# axmlnode = Row.empty_row_node -# end -# @xmlnode = axmlnode -# end -# def self.new_from_rowgroup(rg) -# anode = rg.xmlnode -# Tools.remove_ns_attribute(anode,'table','number-rows-repeated') -# SingleRow.new(rg.parent_array,rg.range.begin,anode) -# end -# def normalize; self end -# def repeated?; false end -# def repeated; 1 end -# def range; (@index..@index) end -# def detach; self end -# def row; @index end -# def still_out_of_used_range?; false end -# end - -# class LazyDetachableRow < Row -# @readonly = :yes_but_detachable -# def initialize(rowi) -# super() -# @index = rowi.to_i -# end -# def add_cell; detach.add_cell end -# def style_name=(value); detach.style_name=value end -# def row; @index end -# end - -# ## there are not data in this object, they are taken from RowGroup, but this is only readonly -# class MemberOfRowGroup < LazyDetachableRow -# @readonly = :yes_but_detachable -# extend Forwardable -# delegate [:repeated?, :repeated, :xmlnode, :parent_array] => :@row_group -# attr_accessor :row_group # for dubugging -# -# # @index Integer -# # @row_group RepeatedRow -# def initialize(arowi,arow_group) -# super(arowi) -# @row_group = arow_group -# raise 'Wrong parameter given - class is '+@row_group.class.to_a unless @row_group.is_a? RowGroup -# end -# def detach # detaches MemberOfRowGroup from its RowGroup perhaps splitting RowGroup -# @row_group.parent_array.detach(@index) -# end -# def get_cell(coli) -# c = Cell.new(self,coli,@row_group.cellnodes(coli)) -# c.mode = :repeated -# c -# end -# def first_unused_column_index -# @row_group.first_unused_column_index -# end -# def nonemptycells -# @row_group.nonemptycellsindexes.collect{ |coli| cells(coli) } -# end -# end - +end end \ No newline at end of file