lib/write_xlsx/workbook.rb in write_xlsx-0.64.1 vs lib/write_xlsx/workbook.rb in write_xlsx-0.65.0

- old
+ new

@@ -1,10 +1,12 @@ # -*- coding: utf-8 -*- require 'write_xlsx/package/xml_writer_simple' require 'write_xlsx/package/packager' +require 'write_xlsx/sheets' require 'write_xlsx/worksheet' require 'write_xlsx/chartsheet' +require 'write_xlsx/formats' require 'write_xlsx/format' require 'write_xlsx/shape' require 'write_xlsx/utility' require 'write_xlsx/chart' require 'write_xlsx/zip_file_utils' @@ -12,10 +14,12 @@ require 'tempfile' require 'digest/md5' module Writexlsx + OFFICE_URL = 'http://schemas.microsoft.com/office/' # :nodoc: + # The WriteXLSX provides an object oriented interface to a new Excel workbook. # The following methods are available through a new workbook. # # * new[#method-c-new] # * add_worksheet[#method-i-add_worksheet] @@ -32,16 +36,13 @@ # class Workbook include Writexlsx::Utility - BASE_NAME = { :sheet => 'Sheet', :chart => 'Chart'} # :nodoc: - attr_writer :firstsheet # :nodoc: attr_reader :palette # :nodoc: - attr_reader :font_count, :num_format_count, :border_count, :fill_count, :custom_colors # :nodoc: - attr_reader :worksheets, :sheetnames, :charts, :drawings # :nodoc: + attr_reader :worksheets, :charts, :drawings # :nodoc: attr_reader :num_comment_files, :num_vml_files, :named_ranges # :nodoc: attr_reader :doc_properties # :nodoc: attr_reader :image_types, :images # :nodoc: attr_reader :shared_strings # :nodoc: attr_accessor :table_count # :nodoc: @@ -95,23 +96,16 @@ @date_1904 = false @activesheet = 0 @firstsheet = 0 @selected = 0 @fileclosed = false - @sheet_name = 'Sheet' - @chart_name = 'Chart' - @sheetname_count = 0 - @chartname_count = 0 - @worksheets = [] + @worksheets = Sheets.new @charts = [] @drawings = [] - @sheetnames = [] - @formats = [] + @formats = Formats.new @xf_formats = [] - @xf_format_indices = {} @dxf_formats = [] - @dxf_format_indices = {} @font_count = 0 @num_format_count = 0 @defined_names = [] @named_ranges = [] @custom_colors = [] @@ -263,11 +257,11 @@ # Write the workbook view properties. write_book_views # Write the worksheet names and ids. - write_sheets + @worksheets.write_sheets(@writer) # Write the workbook defined names. write_defined_names # Write the workbook calculation properties. @@ -303,11 +297,10 @@ # def add_worksheet(name = '') name = check_sheetname(name) worksheet = Worksheet.new(self, @worksheets.size, name) @worksheets << worksheet - @sheetnames << name worksheet end # # This method is use to create a new chart either as a standalone worksheet @@ -401,11 +394,10 @@ # Check the worksheet name for non-embedded charts. sheetname = check_chart_sheetname(name) chartsheet = Chartsheet.new(self, @worksheets.size, sheetname) chartsheet.chart = chart @worksheets << chartsheet - @sheetnames << sheetname end @charts << chart ptrue?(embedded) ? chart : chartsheet end @@ -420,20 +412,14 @@ # # See the {Format Class's rdoc}[Format.html] for more details about # Format properties and how to set them. # def add_format(properties = {}) - init_data = [ - @xf_format_indices, - @dxf_format_indices, - properties - ] + format = Format.new(@formats, properties) - format = Format.new(*init_data) + @formats.formats.push(format) # Store format reference - @formats.push(format) # Store format reference - format end # # The +add_shape+ method can be used to create new shapes that may be @@ -714,11 +700,11 @@ # Local defined names are formatted like "Sheet1!name". if name =~ /^(.*)!(.*)$/ sheetname = $1 name = $2 - sheet_index = get_sheet_index(sheetname) + sheet_index = @worksheets.index_by_name(sheetname) else sheet_index = -1 # Use -1 to indicate global names. end # Warn if the sheet index wasn't found. @@ -944,16 +930,25 @@ def shared_strings_empty? # :nodoc: @shared_strings.empty? end - def xf_formats # :nodoc: - @xf_formats.dup + def chartsheet_count + @worksheets.chartsheet_count end - def dxf_formats # :nodoc: - @dxf_formats.dup + def style_properties + [ + @xf_formats, + @palette, + @font_count, + @num_format_count, + @border_count, + @fill_count, + @custom_colors, + @dxf_formats + ] end private def setup_filename(file) #:nodoc: @@ -1035,58 +1030,17 @@ # # Check for valid worksheet names. We check the length, if it contains any # invalid characters and if the name is unique in the workbook. # def check_sheetname(name) #:nodoc: - make_and_check_sheet_chart_name(:sheet, name) + @worksheets.make_and_check_sheet_chart_name(:sheet, name) end def check_chart_sheetname(name) - make_and_check_sheet_chart_name(:chart, name) + @worksheets.make_and_check_sheet_chart_name(:chart, name) end - def make_and_check_sheet_chart_name(type, name) - count = sheet_chart_count_increment(type) - name = "#{BASE_NAME[type]}#{count}" unless ptrue?(name) - - check_valid_sheetname(name) - name - end - - def sheet_chart_count_increment(type) - case type - when :sheet - @sheetname_count += 1 - when :chart - @chartname_count += 1 - end - end - - def check_valid_sheetname(name) - # Check that sheet name is <= 31. Excel limit. - raise "Sheetname #{name} must be <= #{SHEETNAME_MAX} chars" if name.length > SHEETNAME_MAX - - # Check that sheetname doesn't contain any invalid characters - invalid_char = /[\[\]:*?\/\\]/ - if name =~ invalid_char - raise 'Invalid character []:*?/\\ in worksheet name: ' + name - end - - # Check that the worksheet name doesn't already exist since this is a fatal - # error in Excel 97. The check must also exclude case insensitive matches. - unless is_sheetname_uniq?(name) - raise "Worksheet name '#{name}', with case ignored, is already used." - end - end - - def is_sheetname_uniq?(name) - @worksheets.each do |worksheet| - return false if name.downcase == worksheet.name.downcase - end - true - end - # # Convert a range formula such as Sheet1!$B$1:$B$5 into a sheet name and cell # range such as ( 'Sheet1', 0, 1, 4, 1 ). # def get_chart_range(range) #:nodoc: @@ -1182,33 +1136,10 @@ attributes << 'activeTab' << @activesheet end @writer.empty_tag('workbookView', attributes) end - def write_sheets #:nodoc: - @writer.tag_elements('sheets') do - id_num = 1 - @worksheets.each do |sheet| - write_sheet(sheet.name, id_num, sheet.hidden?) - id_num += 1 - end - end - end - - def write_sheet(name, sheet_id, hidden = false) #:nodoc: - attributes = [ - 'name', name, - 'sheetId', sheet_id - ] - - if hidden - attributes << 'state' << 'hidden' - end - attributes << 'r:id' << "rId#{sheet_id}" - @writer.empty_tag_encoded('sheet', attributes) - end - def write_calc_pr #:nodoc: attributes = ['calcId', 124519] @writer.empty_tag('calcPr', attributes) end @@ -1217,13 +1148,14 @@ @writer.tag_elements(tag) { write_ext } end def write_ext #:nodoc: tag = 'ext' + uri = "#{OFFICE_URL}mac/excel/2008/main" attributes = [ - 'xmlns:mx', 'http://schemas.microsoft.com/office/mac/excel/2008/main', - 'uri', 'http://schemas.microsoft.com/office/mac/excel/2008/main' + 'xmlns:mx', uri, + 'uri', uri ] @writer.tag_elements(tag, attributes) { write_mx_arch_id } end def write_mx_arch_id #:nodoc: @@ -1287,12 +1219,11 @@ prepare_drawings # Add cached data to charts. add_chart_data # Package the workbook. - packager = Package::Packager.new - packager.add_workbook(self) + packager = Package::Packager.new(self) packager.set_package_dir(@tempdir) packager.create_package # Free up the Packager object. packager = nil @@ -1326,11 +1257,11 @@ # # Iterate through the XF Format objects and separate them into XF and DXF # formats. # def prepare_formats #:nodoc: - @formats.each do |format| + @formats.formats.each do |format| xf_index = format.xf_index dxf_index = format.dxf_index @xf_formats[xf_index] = format if xf_index @dxf_formats[dxf_index] = format if dxf_index @@ -1560,21 +1491,20 @@ @num_comment_files = comment_files # Add a font format for cell comments. if comment_files > 0 format = Format.new( - @xf_format_indices, - @dxf_format_indices, + @formats, :font => 'Tahoma', :size => 8, :color_indexed => 81, :font_only => 1 ) format.get_xf_index - @formats << format + @formats.formats << format end end # # Add "cached" data to charts to provide the numCache and strCache data for @@ -1726,11 +1656,11 @@ shape_count = sheet.shapes.size next if chart_count + image_count + shape_count == 0 drawing_id += 1 - (0 .. chart_count - 1).each do |index| + sheet.charts.each_with_index do |chart, index| chart_ref_id += 1 sheet.prepare_chart(index, chart_ref_id, drawing_id) end (0 .. image_count - 1).each do |index| @@ -1754,26 +1684,9 @@ # Sort the workbook charts references into the order that the were # written from the worksheets above. @charts = @charts.sort_by { |chart| chart.id } @drawing_count = drawing_id - end - - # - # Convert a sheet name to its index. Return undef otherwise. - # - def get_sheet_index(sheetname) #:nodoc: - sheet_count = @sheetnames.size - sheet_index = nil - - sheetname.sub!(/^'/, '') - sheetname.sub!(/'$/, '') - - ( 0 .. sheet_count - 1 ).each do |i| - sheet_index = i if sheetname == @sheetnames[i] - end - - sheet_index end # # Extract information from the image file such as dimension, type, filename, # and extension. Also keep track of previously seen images to optimise out