lib/write_xlsx/worksheet.rb in write_xlsx-0.59.0 vs lib/write_xlsx/worksheet.rb in write_xlsx-0.60.0
- old
+ new
@@ -354,10 +354,11 @@
attr_reader :autofilter_area # :nodoc:
attr_reader :writer, :set_rows, :col_formats # :nodoc:
attr_accessor :vml_shape_id, :rel_count, :hlink_refs # :nodoc:
attr_reader :comments_author # :nodoc:
attr_accessor :dxf_priority # :nodoc:
+ attr_reader :vba_codename # :nodoc:
def initialize(workbook, index, name) #:nodoc:
@writer = Package::XMLWriterSimple.new
@workbook = workbook
@@ -419,11 +420,13 @@
@outline_row_level = 0
@outline_col_level = 0
@merge = []
+ @has_vml = false
@comments = Package::Comments.new(self)
+ @buttons_array = []
@validations = []
@cond_formats = {}
@dxf_priority = 1
@@ -2100,10 +2103,12 @@
# Check that row and col are valid and store max and min values
check_dimensions(row, col)
store_row_col_max_min_values(row, col)
+ @has_vml = true
+
# Process the properties of the cell comment.
@comments.add(Package::Comment.new(@workbook, self, row, col, string, options))
end
#
@@ -2641,13 +2646,26 @@
index = shared_string_index(str[0, STR_MAX])
# External links to URLs and to other Excel workbooks have slightly
# different characteristics that we have to account for.
if link_type == 1
- # Substiture white space in url.
- url = url.sub(/[\s\x00]/, '%20')
+ # Escape URL unless it looks already escaped.
+ unless url =~ /%[0-9a-fA-F]{2}/
+ # Escape the URL escape symbol.
+ url = url.gsub(/%/, "%25")
+ # Escape whitespae in URL.
+ url = url.gsub(/[\s\x00]/, '%20')
+
+ # Escape other special characters in URL.
+ re = /(["<>\[\]`^{}])/
+ while re =~ url
+ match = $~[1]
+ url = url.sub(re, sprintf("%%%x", match.ord))
+ end
+ end
+
# Ordinary URL style external links don't have a "location" string.
str = nil
elsif link_type == 3
# External Workbook links need to be modified into the right format.
# The URL will look something like 'c:\temp\file.xlsx#Sheet!A1'.
@@ -3867,10 +3885,18 @@
@sparklines << sparkline
end
#
+ # Insert a button form object into the worksheet.
+ #
+ def insert_button(*args)
+ @buttons_array << button_params(*(row_col_notation(args)))
+ @has_vml = 1
+ end
+
+ #
# :call-seq:
# data_validation(cell_or_cell_range, options)
#
# Data validation is a feature of Excel which allows you to restrict
# the data that a users enters in a cell and to display help and
@@ -4727,10 +4753,14 @@
def comments_count # :nodoc:
@comments.size
end
+ def has_vml? # :nodoc:
+ @has_vml
+ end
+
def has_comments? # :nodoc:
!@comments.empty?
end
def is_chartsheet? # :nodoc:
@@ -4992,10 +5022,42 @@
# TODO Add the alpha part to the RGB.
sprintf("FF%02X%02X%02X", *rgb[0, 3])
end
+ def buttons_data # :nodoc:
+ @buttons_array
+ end
+
+ #
+ # Turn the HoH that stores the comments into an array for easier handling
+ # and set the external links for comments and buttons.
+ #
+ def prepare_vml_objects(vml_data_id, vml_shape_id, comment_id)
+ @external_vml_links <<
+ [ '/vmlDrawing', "../drawings/vmlDrawing#{comment_id}.vml"]
+
+ if has_comments?
+ @comments_array = @comments.sorted_comments
+ @external_comment_links <<
+ [ '/comments', "../comments#{comment_id}.xml" ]
+ end
+
+ count = @comments.size
+ start_data_id = vml_data_id
+
+ # The VML o:idmap data id contains a comma separated range when there is
+ # more than one 1024 block of comments, like this: data="1,2".
+ (1 .. (count / 1024)).each do |i|
+ vml_data_id = "#{vml_data_id},#{start_data_id + i}"
+ end
+ @vml_data_id = vml_data_id
+ @vml_shape_id = vml_shape_id
+
+ count
+ end
+
private
def check_for_valid_input_params(param)
check_parameter(param, valid_validation_parameter, 'data_validation')
@@ -5711,10 +5773,74 @@
raise "Shape #{index} (#{shape[:type]}) vertical alignment (#{shape[:valign]}) not in ['t', 'ctr', 'v']\n"
end
end
#
+ # This method handles the parameters passed to insert_button as well as
+ # calculating the comment object position and vertices.
+ #
+ def button_params(row, col, params)
+ button = { :_row => row, :_col => col }
+
+ button_number = 1 + @buttons_array.size
+
+ # Set the button caption.
+ caption = params[:caption] || "Button #{button_number}"
+
+ button[:_font] = { :_caption => caption }
+
+ # Set the macro name.
+ if params[:macro]
+ button[:_macro] = "[0]!#{params[:macro]}"
+ else
+ button[:_macro] = "[0]!Button#{button_number}_Click"
+ end
+
+ # Ensure that a width and height have been set.
+ default_width = 64
+ default_height = 20
+ params[:width] = default_width if !params[:width]
+ params[:height] = default_height if !params[:height]
+
+ # Set the x/y offsets.
+ params[:x_offset] = 0 if !params[:x_offset]
+ params[:y_offset] = 0 if !params[:y_offset]
+
+ # Scale the size of the comment box if required.
+ if params[:x_scale]
+ params[:width] = params[:width] * params[:x_scale]
+ end
+ if params[:y_scale]
+ params[:height] = params[:height] * params[:y_scale]
+ end
+
+ # Round the dimensions to the nearest pixel.
+ params[:width] = (0.5 + params[:width]).to_i
+ params[:height] = (0.5 + params[:height]).to_i
+
+ params[:start_row] = row
+ params[:start_col] = col
+
+ # Calculate the positions of comment object.
+ vertices = position_object_pixels(
+ params[:start_col],
+ params[:start_row],
+ params[:x_offset],
+ params[:y_offset],
+ params[:width],
+ params[:height]
+ )
+
+ # Add the width and height for VML.
+ vertices << [params[:width], params[:height]]
+
+ button[:_vertices] = vertices
+
+ button
+ end
+
+ #
# Based on the algorithm provided by Daniel Rentz of OpenOffice.
#
def encode_password(password) #:nodoc:
i = 0
chars = password.split(//)
@@ -5755,12 +5881,17 @@
#
# Write the <sheetPr> element for Sheet level properties.
#
def write_sheet_pr #:nodoc:
- return if !fit_page? && !filter_on? && !tab_color? && !outline_changed?
+ if !fit_page? && !filter_on? && !tab_color? &&
+ !outline_changed? && !vba_codename?
+ return
+ end
+ codename = @vba_codename
attributes = []
+ (attributes << 'codeName' << codename) if codename
(attributes << 'filterMode' << 1) if filter_on?
if fit_page? || tab_color? || outline_changed?
@writer.tag_elements('sheetPr', attributes) do
write_tab_color
@@ -6676,11 +6807,11 @@
#
# Write the <legacyDrawing> element.
#
def write_legacy_drawing #:nodoc:
- return unless has_comments?
+ return unless @has_vml
# Increment the relationship id for any drawings or comments.
@rel_count += 1
id = @rel_count
@@ -7649,9 +7780,13 @@
ptrue?(@tab_color)
end
def outline_changed?
ptrue?(@outline_changed)
+ end
+
+ def vba_codename?
+ ptrue?(@vba_codename)
end
def zoom_scale_normal? #:nodoc:
ptrue?(@zoom_scale_normal)
end