lib/rspreadsheet/cell.rb in rspreadsheet-0.2.0 vs lib/rspreadsheet/cell.rb in rspreadsheet-0.2.3

- old
+ new

@@ -1,47 +1,109 @@ require 'andand' +require 'rspreadsheet/xml_tied' module Rspreadsheet - -class RowOrNode - def mode - case - when xmlnode.nil? then :outbound - when repeated>1 then :repeated - else :regular - end - end -end - -class Cell < RowOrNode - attr_accessor :worksheet, :rowi, :coli + +class Cell < XMLTiedItem + attr_accessor :worksheet, :coli, :rowi + def xml_repeated_attribute; 'number-columns-repeated' end + def xml_items_node_name; 'table-cell' end + def xml_options; {:xml_items_node_name => xml_items_node_name, :xml_repeated_attribute => xml_repeated_attribute} end + def parent; row end + def index; @coli end + def set_index(value); @coli=value end + def set_rowi(arowi); @rowi = arowi end # this should ONLY be used by parent row def initialize(aworksheet,arowi,acoli) + raise "First parameter should be Worksheet object not #{aworksheet.class}" unless aworksheet.kind_of?(Rspreadsheet::Worksheet) @worksheet = aworksheet @rowi = arowi @coli = acoli end def row; @worksheet.rows(rowi) end def coordinates; [rowi,coli] end - - def xmlnode; @worksheet.cellxmlnode(@rowi,@coli) end + def to_s; value.to_s end + def valuexml; self.valuexmlnode.andand.inner_xml end + def valuexmlnode; self.xmlnode.children.first end + # use this to find node in cell xml. ex. xmlfind('.//text:a') finds all link nodes + def valuexmlfindall(path) + valuexmlnode.nil? ? [] : valuexmlnode.find(path) + end + def valuexmlfindfirst(path) + valuexmlfindall(path).first + end + def inspect + "#<Rspreadsheet::Cell:Cell\n row:#{rowi}, col:#{coli} address:#{address}\n type: #{guess_cell_type.to_s}, value:#{value}\n mode: #{mode}\n>" + end def value gt = guess_cell_type if (self.mode == :regular) or (self.mode == :repeated) case when gt == nil then nil when gt == Float then xmlnode.attributes['value'].to_f when gt == String then xmlnode.elements.first.andand.content.to_s when gt == Date then Date.strptime(xmlnode.attributes['date-value'].to_s, '%Y-%m-%d') - when gt == 'percentage' then xmlnode.attributes['value'].to_f + when gt == :percentage then xmlnode.attributes['value'].to_f end elsif self.mode == :outbound nil else raise "Unknown cell mode #{self.mode}" end end - def repeated; (Tools.get_ns_attribute_value(xmlnode, 'table', 'number-columns-repeated') || 1 ).to_i end + def value=(avalue) + detach_if_needed + if self.mode == :regular + gt = guess_cell_type(avalue) + case + when gt == nil then raise 'This value type is not storable to cell' + when gt == Float + set_type_attribute('float') + remove_all_value_attributes_and_content(xmlnode) + Tools.set_ns_attribute(xmlnode,'office','value', avalue.to_s) + xmlnode << Tools.create_ns_node('text','p', avalue.to_f.to_s) + when gt == String then + set_type_attribute('string') + remove_all_value_attributes_and_content(xmlnode) + xmlnode << Tools.create_ns_node('text','p', avalue.to_s) + when gt == Date then + set_type_attribute('date') + remove_all_value_attributes_and_content(xmlnode) + Tools.set_ns_attribute(xmlnode,'office','date-value', avalue.strftime('%Y-%m-%d')) + xmlnode << Tools.create_ns_node('text','p', avalue.strftime('%Y-%m-%d')) + when gt == :percentage + set_type_attribute('percentage') + remove_all_value_attributes_and_content(xmlnode) + Tools.set_ns_attribute(xmlnode,'office','value', '%0.2d%' % avalue.to_f) + xmlnode << Tools.create_ns_node('text','p', (avalue.to_f*100).round.to_s+'%') + end + else + raise "Unknown cell mode #{self.mode}" + end + end + def set_type_attribute(typestring) + Tools.set_ns_attribute(xmlnode,'office','value-type',typestring) + end + def remove_all_value_attributes_and_content(node) + if att = Tools.get_ns_attribute(node, 'office','value') then att.remove! end + if att = Tools.get_ns_attribute(node, 'office','date-value') then att.remove! end + node.content='' + end + def relative(rowdiff,coldiff) + @worksheet.cells(self.rowi+rowdiff, self.coli+coldiff) + end + def type + gct = guess_cell_type + case + when gct == Float then :float + when gct == String then :string + when gct == Date then :date + when gct == :percentage then :percentage + when gct == :unassigned then :unassigned + when gct == nil then :unknown + else :unknown + end + end def guess_cell_type(avalue=nil) # try guessing by value valueguess = case avalue when Numeric then Float when Date then Date @@ -86,119 +148,59 @@ String else nil end end + elsif valueguess == Float and xmlnode.andand.attributes['value-type'] == 'percentage' + result = :percentage end result end - def detach_if_needed - if (self.mode == :repeated) or (self.mode == :outbound ) # Cell did not exist individually yet, detach row and create editable cell - @worksheet.detach_cell_in_xml(rowi,coli) - end - end - def value=(avalue) - detach_if_needed - if self.mode == :regular - gt = guess_cell_type(avalue) - case - when gt == nil then raise 'This value type is not storable to cell' - when gt == Float - set_type_attribute('float') - remove_all_value_attributes_and_content(xmlnode) - Tools.set_ns_attribute(xmlnode,'office','value', avalue.to_s) - xmlnode << LibXML::XML::Node.new('p', avalue.to_f.to_s, ns_text) - when gt == String then - set_type_attribute('string') - remove_all_value_attributes_and_content(xmlnode) - xmlnode << LibXML::XML::Node.new('p', avalue.to_s, ns_text) - when gt == Date then - set_type_attribute('date') - remove_all_value_attributes_and_content(xmlnode) - Tools.set_ns_attribute(xmlnode,'office','date-value', avalue.strftime('%Y-%m-%d')) - xmlnode << LibXML::XML::Node.new('p', avalue.strftime('%Y-%m-%d'), ns_text) - when gt == 'percentage' - set_type_attribute('float') - remove_all_value_attributes_and_content(xmlnode) - Tools.set_ns_attribute(xmlnode,'office','value', avalue.to_f.to_s) - xmlnode << LibXML::XML::Node.new('p', (avalue.to_f*100).round.to_s+'%', ns_text) - end - else - raise "Unknown cell mode #{self.mode}" - end + def format + @format ||= CellFormat.new(self) end - def set_type_attribute(typestring) - Tools.set_ns_attribute(xmlnode,'office','value-type',typestring) + def address + Tools.convert_cell_coordinates_to_address(coordinates) end - def remove_all_value_attributes_and_content(node) - if att = Tools.get_ns_attribute(node, 'office','value') then att.remove! end - if att = Tools.get_ns_attribute(node, 'office','date-value') then att.remove! end - node.content='' + +end + +# proxy object to allow cell.format syntax. Also handles all logic for formats. +class CellFormat + attr_reader :bold + def initialize(cell) + @bold = false + @cell = cell end - def ns_table; xmlnode.doc.root.namespaces.find_by_prefix('table') end - def ns_office; xmlnode.doc.root.namespaces.find_by_prefix('office') end - def ns_text; xmlnode.doc.root.namespaces.find_by_prefix('text') end - def relative(rowdiff,coldiff) - @worksheet.cells(self.rowi+rowdiff, self.coli+coldiff) + def cellnode; @cell.xmlnode end + def bold=(value) + Rspreadsheet::Tools.set_ns_attribute(cellnode,'table','style-name','ce99') end - def is_repeated?; mode == :repeated end - def type - gct = guess_cell_type - case - when gct == Float then :float - when gct == String then :string - when gct == Date then :date - when gct == :percentage then :percentage - when gct == :unassigned then :unassigned - when gct == nil then :unknown - else :unknown - end + def bold; Tools.get_ns_attribute_value(text_style_node,'fo','font-weight') == 'bold' end + def italic; Tools.get_ns_attribute_value(text_style_node,'fo','font-style') == 'italic' end + def color; Tools.get_ns_attribute_value(text_style_node,'fo','color') end + def font_size; Tools.get_ns_attribute_value(text_style_node,'fo','font-size') end + def background_color; Tools.get_ns_attribute_value(cell_style_node,'fo','background-color') end + + def unused_cell_style_name + last = cellnode.doc.root.find('./office:automatic-styles/style:style'). + collect {|node| node['name']}. + collect{ |name| /^ce(\d*)$/.match(name); $1.andand.to_i}. + compact.max + "ce#{last+1}" end + def style_name; Tools.get_ns_attribute_value(cellnode,'table','style-name') end + def style_node; cellnode.doc.root.find("./office:automatic-styles/style:style[@style:name=\"#{style_name}\"]").first end + def text_style_node; cellnode.doc.root.find("./office:automatic-styles/style:style[@style:name=\"#{style_name}\"]/style:text-properties").first end + def cell_style_node; cellnode.doc.root.find("./office:automatic-styles/style:style[@style:name=\"#{style_name}\"]/style:table-cell-properties").first end end - - -# class Cell -# attr_reader :col, :xmlnode -# attr_reader :parent_row # for debug only -# attr_accessor :mode -# def self.empty_cell_node -# LibXML::XML::Node.new('table-cell',nil, Tools.get_namespace('table')) -# end -# def initialize(aparent_row,coli,axmlnode=nil) -# raise "First parameter should be Row object not #{aparent_row.class}" unless aparent_row.kind_of?(Rspreadsheet::Row) -# @parent_row = aparent_row -# if axmlnode.nil? -# axmlnode = Cell.empty_cell_node -# end -# @xmlnode = axmlnode -# @col = coli -# # set @mode -# @mode = case -# when !@parent_row.used_col_range.include?(coli) then :outbound -# when Tools.get_ns_attribute_value(@xmlnode, 'table', 'number-columns-repeated').to_i>1 then :repeated -# else:regular -# end -# end -# def to_s; value end -# def cell_xml; self.xmlnode.to_s end -# def xml; self.xmlnode.children.first.andand.inner_xml end -# def address; Rspreadsheet::Tools.c2a(row,col) end -# def row; @parent_row.row end -# def worksheet; @parent_row.worksheet end -# # use this to find node in cell xml. ex. xmlfind('.//text:a') finds all link nodes -# def xmlfindall(path) -# xmlnode.find(path) -# end -# def xmlfindfirst(path) -# xmlfindall(path).first -# end -# # based on @xmlnode and optionally value which is about to be assigned, guesses which type the result should be -# def inspect -# "#<Rspreadsheet::Cell:Cell\n row:#{row}, col:#{col} address:#{address}\n type: #{guess_cell_type.to_s}, value:#{value}\n mode: #{mode}\n>" -# end -# end end + + + + +