diff options
| -rw-r--r-- | lib/axlsx/drawing/graphic_frame.rb | 3 | ||||
| -rw-r--r-- | lib/axlsx/drawing/vml_drawing.rb | 8 | ||||
| -rw-r--r-- | lib/axlsx/drawing/vml_shape.rb | 88 | ||||
| -rw-r--r-- | lib/axlsx/util/validators.rb | 14 | ||||
| -rw-r--r-- | lib/axlsx/workbook/workbook.rb | 1 | ||||
| -rw-r--r-- | lib/axlsx/workbook/worksheet/comment.rb | 100 | ||||
| -rw-r--r-- | lib/axlsx/workbook/worksheet/comments.rb | 92 |
7 files changed, 212 insertions, 94 deletions
diff --git a/lib/axlsx/drawing/graphic_frame.rb b/lib/axlsx/drawing/graphic_frame.rb index 6466a656..fd65aa19 100644 --- a/lib/axlsx/drawing/graphic_frame.rb +++ b/lib/axlsx/drawing/graphic_frame.rb @@ -32,7 +32,8 @@ module Axlsx # @param [String] str # @return [String] def to_xml_string(str = '') - str << '<xdr:graphicFrame>' + # macro attribute should be optional! + str << '<xdr:graphicFrame macro="">' str << '<xdr:nvGraphicFramePr>' str << '<xdr:cNvPr id="2" name="' << chart.title.text << '"/>' str << '<xdr:cNvGraphicFramePr/>' diff --git a/lib/axlsx/drawing/vml_drawing.rb b/lib/axlsx/drawing/vml_drawing.rb index 8ff6469b..2ae1dc68 100644 --- a/lib/axlsx/drawing/vml_drawing.rb +++ b/lib/axlsx/drawing/vml_drawing.rb @@ -1,16 +1,24 @@ module Axlsx + # a vml drawing used for comments in excel. class VmlDrawing + # creates a new Vml Drawing object. + # @param [Comments] the comments object this drawing is associated with def initialize(comments) raise ArgumentError, "you must provide a comments object" unless comments.is_a?(Comments) @comments = comments end + # The part name for this vml drawing + # @return [String] def pn "#{VML_DRAWING_PN}" % (@comments.worksheet.index + 1) end + # serialize the vml_drawing to xml. + # @param [String] str + # @return [String] def to_xml_string(str = '') str = <<BAD_PROGRAMMER <xml xmlns:v="urn:schemas-microsoft-com:vml" diff --git a/lib/axlsx/drawing/vml_shape.rb b/lib/axlsx/drawing/vml_shape.rb index d6de8b21..eff39ae3 100644 --- a/lib/axlsx/drawing/vml_shape.rb +++ b/lib/axlsx/drawing/vml_shape.rb @@ -1,21 +1,62 @@ module Axlsx + # A VmlShape is used to position and render a comment. class VmlShape - attr_accessor :row + # The row anchor position for this shape determined by the comment's ref value + # @return [Integer] + attr_reader :row - attr_accessor :column + # The column anchor position for this shape determined by the comment's ref value + # @return [Integer] + attr_reader :column - attr_accessor :left_column - attr_accessor :left_offset - attr_accessor :top_row - attr_accessor :top_offset - attr_accessor :right_column - attr_accessor :right_offset - attr_accessor :bottom_row - attr_accessor :bottom_offset + # The left column for this shape + # @return [Integer] + attr_reader :left_column + + # The left offset for this shape + # @return [Integer] + attr_reader :left_offset + + # The top row for this shape + # @return [Integer] + attr_reader :top_row + + # The top offset for this shape + # @return [Integer] + attr_reader :top_offset + + # The right column for this shape + # @return [Integer] + attr_reader :right_column + + # The right offset for this shape + # @return [Integer] + attr_reader :right_offset + + # The botttom row for this shape + # @return [Integer] + attr_reader :bottom_row + + # The bottom offset for this shape + # @return [Integer] + attr_reader :bottom_offset + + # The id of this shape derrived from teh comment's worksheet index and the index of this comment + # @return [String] attr_reader :id + # Creates a new VmlShape object for the comment provided. + # @param [Comment] comment + # @option options [Integer|String] left_column + # @option options [Integer|String] left_offset + # @option options [Integer|String] top_row + # @option options [Integer|String] top_offset + # @option options [Integer|String] right_column + # @option options [Integer|String] right_offset + # @option options [Integer|String] bottom_row + # @option options [Integer|String] bottom_offset def initialize(comment, options={}) @id = "_x0000_s#{comment.comments.worksheet.index+1}08#{comment.index+1}" @row = @column = @left_column = @top_row = @right_column = @bottom_row = 0 @@ -29,6 +70,33 @@ module Axlsx yield self if block_given? end + # @see left_column + def left_column=(v); Axlsx::validate_integerish(v); @left_column = v.to_i end + + # @see left_offset + def left_offset=(v); Axlsx::validate_integerish(v); @left_offset = v.to_i end + + # @see top_row + def top_row=(v); Axlsx::validate_integerish(v); @top_row = v.to_i end + + # @see top_offset + def top_offset=(v); Axlsx::validate_integerish(v); @top_offset = v.to_i end + + # @see right_column + def right_column=(v); Axlsx::validate_integerish(v); @right_column = v.to_i end + + # @see right_offset + def right_offset=(v); Axlsx::validate_integerish(v); @right_offset = v.to_i end + + # @see bottom_row + def bottom_row=(v); Axlsx::validate_integerish(v); @bottom_row = v.to_i end + + # @see_bottom_offset + def bottom_offset=(v); Axlsx::validate_integerish(v); @bottom_offset = v.to_i end + + # serialize the shape to a string + # @param [String] str + # @return [String] def to_xml_string(str ='') str << <<SHAME_ON_YOU diff --git a/lib/axlsx/util/validators.rb b/lib/axlsx/util/validators.rb index 4387aae5..e5d2c79a 100644 --- a/lib/axlsx/util/validators.rb +++ b/lib/axlsx/util/validators.rb @@ -45,8 +45,20 @@ module Axlsx true end + + # Requires that the value can be converted to an integer + # @para, [Any] v the value to validate + # @raise [ArgumentError] raised if the value cannot be converted to an integer + def self.validate_integerish(v) + raise ArugumentError, (ERR_INTEGERISH % v.inspect) unless (v.to_i.is_a?(Integer)) + end + + # Requires that the value is between -54000000 and 54000000 + # @param [Any] v The value validated + # @raise [ArgumentError] raised if the value cannot be converted to an integer between the allowed angle values for chart label rotation. + # @return [Boolean] true if the data is valid def self.validate_angle(v) - raise ArgumentError, (ERR_ANGLE % v.inspect) unless (v >= -5400000 && v <= 5400000) + raise ArgumentError, (ERR_ANGLE % v.inspect) unless (v.to_i >= -5400000 && v.to_i <= 5400000) end # Requires that the value is a Fixnum or Integer and is greater or equal to 0 # @param [Any] v The value validated diff --git a/lib/axlsx/workbook/workbook.rb b/lib/axlsx/workbook/workbook.rb index daf522ea..fc9fbc51 100644 --- a/lib/axlsx/workbook/workbook.rb +++ b/lib/axlsx/workbook/workbook.rb @@ -15,6 +15,7 @@ require 'axlsx/workbook/worksheet/conditional_formatting_rule.rb' require 'axlsx/workbook/worksheet/row.rb' require 'axlsx/workbook/worksheet/col.rb' require 'axlsx/workbook/worksheet/comments.rb' +require 'axlsx/workbook/worksheet/comment.rb' require 'axlsx/workbook/worksheet/worksheet.rb' require 'axlsx/workbook/shared_strings_table.rb' require 'axlsx/workbook/worksheet/table.rb' diff --git a/lib/axlsx/workbook/worksheet/comment.rb b/lib/axlsx/workbook/worksheet/comment.rb new file mode 100644 index 00000000..7753a71a --- /dev/null +++ b/lib/axlsx/workbook/worksheet/comment.rb @@ -0,0 +1,100 @@ +module Axlsx + + # A comment is the text data for a comment + class Comment + + # The text to render + # @return [String] + attr_reader :text + + # The index of the the author for this comment in the owning Comments object + # @see Comments + # @return [Integer] + attr_reader :author_index + + # The owning Comments object + # @return [Comments] + attr_reader :comments + + + # The string based cell position reference (e.g. 'A1') that determines the positioning of this comment + # @return [String] + attr_reader :ref + + # TODO + # r (Rich Text Run) + # rPh (Phonetic Text Run) + # phoneticPr (Phonetic Properties) + + def initialize(comments, options={}) + raise ArgumentError, "A comment needs a parent comments object" unless comments.is_a?(Comments) + @comments = comments + options.each do |o| + self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}=" + end + yield self if block_given? + end + + # The vml shape that will render this comment + # @return [VmlShape] + def vml_shape + @vml_shape ||= initialize_vml_shape + end + + # The index of this comment + # @return [Integer] + def index + @comments.comment_list.index(self) + end + + # @see ref + def ref=(v) + Axlsx::DataTypeValidator.validate "Comment.ref", [String, Cell], v + @ref = v if v.is_a?(String) + @ref = v.r if v.is_a?(Cell) + end + + # @see text + def text=(v) + Axlsx::validate_string(v) + @text = v + end + + # @see author_index + def author_index=(v) + Axlsx::validate_unsigned_int(v) + @author_index = v + end + + # serialize the object + # @param [String] str + # @return [String] + def to_xml_string(str = "") + author = @comments.authors[author_index] + str << '<comment ref="' << ref << '" authorId="' << author_index.to_s << '">' + str << '<text><r>' + str << '<rPr> <b/><color indexed="81"/></rPr>' + str << '<t>' << author.to_s << ': +</t></r>' + str << '<r>' + str << '<rPr><color indexed="81"/></rPr>' + str << '<t>' << text << '</t></r></text>' + str << '</comment>' + end + + private + + # initialize the vml shape based on this comment's ref/position in the worksheet. + # by default, all columns are 5 columns wide and 5 rows high + def initialize_vml_shape + ws = self.comments.worksheet + @vml_shape = VmlShape.new(self, :row => ws[ref].row.index, :column => ws[ref].index) do |vml| + vml.left_column = vml.row + 1 + vml.right_column = vml.column + 4 + vml.top_row = vml.row + vml.bottom_row = vml.row + 4 + end + end + + end +end diff --git a/lib/axlsx/workbook/worksheet/comments.rb b/lib/axlsx/workbook/worksheet/comments.rb index 90d3ec43..9334af7b 100644 --- a/lib/axlsx/workbook/worksheet/comments.rb +++ b/lib/axlsx/workbook/worksheet/comments.rb @@ -11,16 +11,22 @@ module Axlsx # @return [SimpleTypedList] attr_reader :comment_list + # the vml_drawing that holds the shapes for comments + # @return [VmlDrawing] attr_reader :vml_drawing # The worksheet that these comments belong to # @return [Worksheet] attr_reader :worksheet + # The index of this collection in the workbook. Effectively the index of the worksheet. + # @return [Integer] def index @worksheet.index end + # The part name for this object + # @return [String] def pn "#{COMMENT_PN % (index+1)}" end @@ -29,16 +35,12 @@ module Axlsx # @param [Worksheet] worksheet The sheet that these comments belong to. def initialize(worksheet) raise ArgumentError, "you must provide a worksheet" unless worksheet.is_a?(Worksheet) - @worksheet = worksheet @authors = SimpleTypedList.new String @comment_list = SimpleTypedList.new Comment @vml_drawing = VmlDrawing.new(self) end - # LeftColumn, LeftOffset, TopRow, TopOffset, RightColumn, RightOffset, BottomRow, BottomOffset. - - # Adds a new comment to the worksheet that owns these comments. # @note the author, text and ref options are required # @option options [String] author The name of the author for this comment @@ -50,9 +52,13 @@ module Axlsx raise ArgumentError, "Comment requires ref" unless options[:ref] options[:author_index] = @authors.index(options[:author]) || @authors << options[:author] @comment_list << Comment.new(self, options) + yield @comment_list.last if block_given? @comment_list.last end + # serialize the object + # @param [String] str + # @return [String] def to_xml_string(str="") str << '<?xml version="1.0" encoding="UTF-8"?>' str << '<comments xmlns="' << XML_NS << '">' @@ -71,82 +77,4 @@ module Axlsx end - class Comment - - attr_reader :text - - attr_reader :author_index - - attr_reader :comments - - attr_reader :ref - - # TODO - # r (Rich Text Run) - # rPh (Phonetic Text Run) - # phoneticPr (Phonetic Properties) - def initialize(comments, options={}) - raise ArgumentError, "A comment needs a parent comments object" unless comments.is_a?(Comments) - @comments = comments - options.each do |o| - self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}=" - end - yield self if block_given? - end - - def pn - "#{COMMENT_PN % (index+1)}" - end - - def vml_shape - @vml_shape ||= initialize_vml_shape - end - - def initialize_vml_shape - ws = self.comments.worksheet - @vml_shape = VmlShape.new(self, :row => ws[ref].row.index, :column => ws[ref].index) do |vml| - vml.left_column = vml.row + 1 - vml.right_column = vml.column + 4 - vml.top_row = vml.row - vml.bottom_row = vml.row + 4 - end - end - - # The index of this comment - # @return [Integer] - def index - @comments.comment_list.index(self) - end - - def ref=(v) - Axlsx::DataTypeValidator.validate "Comment.ref", [String, Cell], v - @ref = v if v.is_a?(String) - @ref = v.r if v.is_a?(Cell) - end - - def text=(v) - Axlsx::validate_string(v) - @text = v - end - - def author_index=(v) - Axlsx::validate_unsigned_int(v) - @author_index = v - end - - def to_xml_string(str = "") - author = @comments.authors[author_index] - str << '<comment ref="' << ref << '" authorId="' << author_index.to_s << '">' - str << '<text><r>' - str << '<rPr> <b/><color indexed="81"/></rPr>' - str << '<t>' << author.to_s << ': -</t></r>' - str << '<r>' - str << '<rPr><color indexed="81"/></rPr>' - str << '<t>' << text << '</t></r></text>' - str << '</comment>' - end - - end - end |
