write_xlsx 1.12.3 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +22 -0
  3. data/Changes +23 -0
  4. data/README.md +1 -1
  5. data/lib/write_xlsx/chart/area.rb +2 -2
  6. data/lib/write_xlsx/chart/axis.rb +55 -32
  7. data/lib/write_xlsx/chart/axis_writer.rb +528 -0
  8. data/lib/write_xlsx/chart/bar.rb +2 -2
  9. data/lib/write_xlsx/chart/caption.rb +16 -9
  10. data/lib/write_xlsx/chart/chart_area.rb +121 -0
  11. data/lib/write_xlsx/chart/column.rb +2 -2
  12. data/lib/write_xlsx/chart/d_pt_point_writer.rb +14 -0
  13. data/lib/write_xlsx/chart/doughnut.rb +0 -3
  14. data/lib/write_xlsx/chart/formatting_writer.rb +652 -0
  15. data/lib/write_xlsx/chart/initialization.rb +100 -0
  16. data/lib/write_xlsx/chart/line.rb +4 -3
  17. data/lib/write_xlsx/chart/pie.rb +6 -2
  18. data/lib/write_xlsx/chart/radar.rb +2 -2
  19. data/lib/write_xlsx/chart/scatter.rb +4 -3
  20. data/lib/write_xlsx/chart/series.rb +35 -15
  21. data/lib/write_xlsx/chart/series_data.rb +132 -0
  22. data/lib/write_xlsx/chart/series_writer.rb +318 -0
  23. data/lib/write_xlsx/chart/settings.rb +226 -0
  24. data/lib/write_xlsx/chart/stock.rb +2 -2
  25. data/lib/write_xlsx/chart/table.rb +50 -0
  26. data/lib/write_xlsx/chart/xml_writer.rb +305 -0
  27. data/lib/write_xlsx/chart.rb +286 -2477
  28. data/lib/write_xlsx/chartsheet.rb +35 -83
  29. data/lib/write_xlsx/constants.rb +11 -0
  30. data/lib/write_xlsx/drawing.rb +5 -3
  31. data/lib/write_xlsx/format/alignment_state.rb +39 -0
  32. data/lib/write_xlsx/format/alignment_style.rb +92 -0
  33. data/lib/write_xlsx/format/border_state.rb +47 -0
  34. data/lib/write_xlsx/format/border_style.rb +116 -0
  35. data/lib/write_xlsx/format/fill_state.rb +26 -0
  36. data/lib/write_xlsx/format/fill_style.rb +52 -0
  37. data/lib/write_xlsx/format/font_state.rb +74 -0
  38. data/lib/write_xlsx/format/font_style.rb +172 -0
  39. data/lib/write_xlsx/format/format_state.rb +65 -0
  40. data/lib/write_xlsx/format/number_format_state.rb +20 -0
  41. data/lib/write_xlsx/format/number_format_style.rb +28 -0
  42. data/lib/write_xlsx/format/protection_state.rb +20 -0
  43. data/lib/write_xlsx/format/protection_style.rb +28 -0
  44. data/lib/write_xlsx/format.rb +1093 -426
  45. data/lib/write_xlsx/formats.rb +0 -2
  46. data/lib/write_xlsx/image_property.rb +4 -1
  47. data/lib/write_xlsx/inserted_chart.rb +1 -1
  48. data/lib/write_xlsx/object_positioning.rb +203 -0
  49. data/lib/write_xlsx/package/app.rb +3 -3
  50. data/lib/write_xlsx/package/button.rb +6 -2
  51. data/lib/write_xlsx/package/comments.rb +11 -3
  52. data/lib/write_xlsx/package/conditional_format.rb +7 -3
  53. data/lib/write_xlsx/package/content_types.rb +2 -2
  54. data/lib/write_xlsx/package/core.rb +2 -2
  55. data/lib/write_xlsx/package/custom.rb +3 -2
  56. data/lib/write_xlsx/package/metadata.rb +2 -2
  57. data/lib/write_xlsx/package/packager.rb +0 -3
  58. data/lib/write_xlsx/package/relationships.rb +2 -2
  59. data/lib/write_xlsx/package/rich_value.rb +4 -2
  60. data/lib/write_xlsx/package/rich_value_rel.rb +2 -2
  61. data/lib/write_xlsx/package/rich_value_structure.rb +2 -2
  62. data/lib/write_xlsx/package/rich_value_types.rb +3 -3
  63. data/lib/write_xlsx/package/shared_strings.rb +2 -2
  64. data/lib/write_xlsx/package/styles.rb +13 -9
  65. data/lib/write_xlsx/package/table.rb +8 -2
  66. data/lib/write_xlsx/package/theme.rb +0 -3
  67. data/lib/write_xlsx/package/vml.rb +2 -2
  68. data/lib/write_xlsx/page_setup.rb +192 -0
  69. data/lib/write_xlsx/shape.rb +97 -100
  70. data/lib/write_xlsx/sheets.rb +9 -4
  71. data/lib/write_xlsx/sparkline.rb +2 -2
  72. data/lib/write_xlsx/utility/cell_reference.rb +124 -0
  73. data/lib/write_xlsx/utility/chart_formatting.rb +262 -0
  74. data/lib/write_xlsx/utility/common.rb +44 -0
  75. data/lib/write_xlsx/utility/date_time.rb +113 -0
  76. data/lib/write_xlsx/utility/dimensions.rb +40 -0
  77. data/lib/write_xlsx/utility/drawing.rb +136 -0
  78. data/lib/write_xlsx/utility/rich_text.rb +184 -0
  79. data/lib/write_xlsx/utility/sheetname_quoting.rb +73 -0
  80. data/lib/write_xlsx/utility/string_width.rb +45 -0
  81. data/lib/write_xlsx/utility/url.rb +27 -0
  82. data/lib/write_xlsx/utility/xml_primitives.rb +32 -0
  83. data/lib/write_xlsx/version.rb +1 -1
  84. data/lib/write_xlsx/workbook/chart_data.rb +188 -0
  85. data/lib/write_xlsx/workbook/format_preparation.rb +199 -0
  86. data/lib/write_xlsx/workbook/initialization.rb +223 -0
  87. data/lib/write_xlsx/workbook/package_preparation.rb +231 -0
  88. data/lib/write_xlsx/workbook/workbook_writer.rb +164 -0
  89. data/lib/write_xlsx/workbook.rb +143 -981
  90. data/lib/write_xlsx/worksheet/asset_manager.rb +60 -0
  91. data/lib/write_xlsx/worksheet/autofilter.rb +390 -0
  92. data/lib/write_xlsx/worksheet/cell_data.rb +13 -6
  93. data/lib/write_xlsx/worksheet/cell_data_manager.rb +47 -0
  94. data/lib/write_xlsx/worksheet/cell_data_store.rb +61 -0
  95. data/lib/write_xlsx/worksheet/columns.rb +204 -0
  96. data/lib/write_xlsx/worksheet/comments_support.rb +61 -0
  97. data/lib/write_xlsx/worksheet/conditional_formats.rb +30 -0
  98. data/lib/write_xlsx/worksheet/data_validation.rb +9 -1
  99. data/lib/write_xlsx/worksheet/data_writing.rb +1017 -0
  100. data/lib/write_xlsx/worksheet/drawing_methods.rb +308 -0
  101. data/lib/write_xlsx/worksheet/drawing_preparation.rb +290 -0
  102. data/lib/write_xlsx/worksheet/drawing_relations.rb +76 -0
  103. data/lib/write_xlsx/worksheet/drawing_xml_writer.rb +50 -0
  104. data/lib/write_xlsx/worksheet/formatting.rb +418 -0
  105. data/lib/write_xlsx/worksheet/hyperlink.rb +9 -1
  106. data/lib/write_xlsx/worksheet/initialization.rb +146 -0
  107. data/lib/write_xlsx/worksheet/panes.rb +64 -0
  108. data/lib/write_xlsx/worksheet/print_options.rb +72 -0
  109. data/lib/write_xlsx/worksheet/protection.rb +65 -0
  110. data/lib/write_xlsx/worksheet/rich_text_helpers.rb +78 -0
  111. data/lib/write_xlsx/worksheet/row_col_sizing.rb +69 -0
  112. data/lib/write_xlsx/worksheet/rows.rb +84 -0
  113. data/lib/write_xlsx/worksheet/selection.rb +41 -0
  114. data/lib/write_xlsx/worksheet/xml_writer.rb +1246 -0
  115. data/lib/write_xlsx/worksheet.rb +376 -4530
  116. metadata +66 -4
  117. data/lib/write_xlsx/utility.rb +0 -986
  118. data/lib/write_xlsx/worksheet/page_setup.rb +0 -192
@@ -1,6 +1,28 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # frozen_string_literal: true
3
3
 
4
+ ###############################################################################
5
+ #
6
+ # Workbook
7
+ #
8
+ # The Workbook class acts as a facade coordinating workbook state,
9
+ # package preparation and XML generation.
10
+ #
11
+ # Responsibilities are delegated to specialized modules:
12
+ #
13
+ # Initialization - workbook setup and default state
14
+ # WorkbookWriter - workbook XML generation
15
+ # PackagePreparation - package assembly and workbook preparation
16
+ # FormatPreparation - format, font, border and fill preparation
17
+ # ChartData - chart cache data extraction and defined name helpers
18
+ #
19
+ ###############################################################################
20
+
21
+ require 'write_xlsx/workbook/initialization'
22
+ require 'write_xlsx/workbook/workbook_writer'
23
+ require 'write_xlsx/workbook/package_preparation'
24
+ require 'write_xlsx/workbook/format_preparation'
25
+ require 'write_xlsx/workbook/chart_data'
4
26
  require 'write_xlsx/chart'
5
27
  require 'write_xlsx/chartsheet'
6
28
  require 'write_xlsx/format'
@@ -8,7 +30,9 @@ require 'write_xlsx/formats'
8
30
  require 'write_xlsx/image_property'
9
31
  require 'write_xlsx/shape'
10
32
  require 'write_xlsx/sheets'
11
- require 'write_xlsx/utility'
33
+ require 'write_xlsx/utility/common'
34
+ require 'write_xlsx/utility/cell_reference'
35
+ require 'write_xlsx/utility/xml_primitives'
12
36
  require 'write_xlsx/worksheet'
13
37
  require 'write_xlsx/zip_file_utils'
14
38
  require 'write_xlsx/package/xml_writer_simple'
@@ -22,7 +46,13 @@ module Writexlsx
22
46
  MAX_URL_LENGTH = 2_079
23
47
 
24
48
  class Workbook
25
- include Writexlsx::Utility
49
+ include Writexlsx::Utility::Common
50
+ include Writexlsx::Utility::CellReference
51
+ include Writexlsx::Utility::XmlPrimitives
52
+ include Initialization
53
+ include PackagePreparation
54
+ include FormatPreparation
55
+ include ChartData
26
56
 
27
57
  attr_writer :firstsheet # :nodoc:
28
58
  attr_reader :palette # :nodoc:
@@ -44,92 +74,25 @@ module Writexlsx
44
74
  attr_writer :has_embedded_descriptions # :nodoc:
45
75
  attr_accessor :charts # :nodoc:
46
76
 
77
+ ###############################################################################
78
+ #
79
+ # Lifecycle
80
+ #
81
+ ###############################################################################
82
+
47
83
  def initialize(file, *option_params)
48
84
  options, default_formats = process_workbook_options(*option_params)
49
- @options = options.dup # for test
50
- @default_formats = default_formats.dup # for test
51
- @writer = Package::XMLWriterSimple.new
52
-
53
- @file = file
54
- @tempdir = options[:tempdir] ||
55
- File.join(
56
- Dir.tmpdir,
57
- Digest::MD5.hexdigest("#{Time.now.to_f}-#{Process.pid}")
58
- )
59
- @date_1904 = options[:date_1904] || false
60
- @activesheet = 0
61
- @firstsheet = 0
62
- @selected = 0
63
- @fileclosed = false
64
- @worksheets = Sheets.new
65
- @charts = []
66
- @drawings = []
67
- @formats = Formats.new
68
- @xf_formats = []
69
- @dxf_formats = []
70
- @num_formats = []
71
- @defined_names = []
72
- @named_ranges = []
73
- @custom_colors = []
74
- @doc_properties = {}
75
- @custom_properties = []
76
- @optimization = options[:optimization] || 0
77
- @x_window = 240
78
- @y_window = 15
79
- @window_width = 16_095
80
- @window_height = 9_660
81
- @tab_ratio = 600
82
- @excel2003_style = options[:excel2003_style] || false
83
- @image_types = {}
84
- @images = []
85
- @strings_to_urls = options[:strings_to_urls].nil? || options[:strings_to_urls] ? true : false
86
-
87
- @max_url_length = MAX_URL_LENGTH
88
- @has_comments = false
89
- @read_only = 0
90
- @has_metadata = false
91
- @has_embedded_images = false
92
- @has_embedded_descriptions = false
93
-
94
- if options[:max_url_length]
95
- @max_url_length = options[:max_url_length].to_i
96
-
97
- @max_url_length = MAX_URL_LENGTH if @max_url_length < 255
98
- end
99
-
100
- # Structures for the shared strings data.
101
- @shared_strings = Package::SharedStrings.new
102
-
103
- # Structures for embedded images.
104
- @embedded_image_indexes = {}
105
- @embedded_images = []
106
-
107
- # Formula calculation default settings.
108
- @calc_id = 124519
109
- @calc_mode = 'auto'
110
- @calc_on_load = true
111
-
112
- if @excel2003_style
113
- add_format(default_formats.merge(
114
- xf_index: 0,
115
- font_family: 0,
116
- font: 'Arial',
117
- size: 10,
118
- theme: -1
119
- ))
120
- else
121
- add_format(default_formats.merge(xf_index: 0))
122
- end
123
-
124
- # Add a default URL format.
125
- @default_url_format = add_format(hyperlink: 1)
126
85
 
86
+ setup_core_state(file, options, default_formats)
87
+ setup_workbook_state(options)
88
+ setup_format_state(default_formats)
89
+ setup_shared_strings
90
+ setup_embedded_assets
91
+ setup_calculation_state
92
+ setup_default_formats
127
93
  set_color_palette
128
94
  end
129
95
 
130
- #
131
- # The close method is used to close an Excel file.
132
- #
133
96
  def close
134
97
  # In case close() is called twice.
135
98
  return if @fileclosed
@@ -138,101 +101,11 @@ module Writexlsx
138
101
  store_workbook
139
102
  end
140
103
 
104
+ ###############################################################################
141
105
  #
142
- # get array of Worksheet objects
143
- #
144
- # :call-seq:
145
- # sheets -> array of all Wordsheet object
146
- # sheets(1, 3, 4) -> array of spcified Worksheet object.
147
- #
148
- def sheets(*args)
149
- if args.empty?
150
- @worksheets
151
- else
152
- args.collect { |i| @worksheets[i] }
153
- end
154
- end
155
-
156
- #
157
- # Return a worksheet object in the workbook using the sheetname.
106
+ # Workbook object creation API
158
107
  #
159
- def worksheet_by_name(sheetname = nil)
160
- sheets.select { |s| s.name == sheetname }.first
161
- end
162
- alias get_worksheet_by_name worksheet_by_name
163
-
164
- #
165
- # Set the date system: false = 1900 (the default), true = 1904
166
- #
167
- def set_1904(mode = true)
168
- raise "set_1904() must be called before add_worksheet()" unless sheets.empty?
169
-
170
- @date_1904 = ptrue?(mode)
171
- end
172
-
173
- #
174
- # return date system. false = 1900, true = 1904
175
- #
176
- def get_1904
177
- @date_1904
178
- end
179
-
180
- def set_tempdir(dir)
181
- @tempdir = dir.dup
182
- end
183
-
184
- #
185
- # user must not use. it is internal method.
186
- #
187
- def set_xml_writer(filename) # :nodoc:
188
- @writer.set_xml_writer(filename)
189
- end
190
-
191
- #
192
- # user must not use. it is internal method.
193
- #
194
- def xml_str # :nodoc:
195
- @writer.string
196
- end
197
-
198
- #
199
- # user must not use. it is internal method.
200
- #
201
- def assemble_xml_file # :nodoc:
202
- return unless @writer
203
-
204
- # Prepare format object for passing to Style.rb.
205
- prepare_format_properties
206
-
207
- write_xml_declaration do
208
- # Write the root workbook element.
209
- write_workbook do
210
- # Write the XLSX file version.
211
- write_file_version
212
-
213
- # Write the fileSharing element.
214
- write_file_sharing
215
-
216
- # Write the workbook properties.
217
- write_workbook_pr
218
-
219
- # Write the workbook view properties.
220
- write_book_views
221
-
222
- # Write the worksheet names and ids.
223
- @worksheets.write_sheets(@writer)
224
-
225
- # Write the workbook defined names.
226
- write_defined_names
227
-
228
- # Write the workbook calculation properties.
229
- write_calc_pr
230
-
231
- # Write the workbook extension storage.
232
- # write_ext_lst
233
- end
234
- end
235
- end
108
+ ###############################################################################
236
109
 
237
110
  #
238
111
  # At least one worksheet should be added to a new workbook. A worksheet is used to write data into cells:
@@ -312,6 +185,32 @@ module Writexlsx
312
185
  shape
313
186
  end
314
187
 
188
+ ###############################################################################
189
+ #
190
+ # Workbook configuration API
191
+ #
192
+ ###############################################################################
193
+
194
+ #
195
+ # Set the date system: false = 1900 (the default), true = 1904
196
+ #
197
+ def set_1904(mode = true)
198
+ raise "set_1904() must be called before add_worksheet()" unless sheets.empty?
199
+
200
+ @date_1904 = ptrue?(mode)
201
+ end
202
+
203
+ #
204
+ # return date system. false = 1900, true = 1904
205
+ #
206
+ def get_1904
207
+ @date_1904
208
+ end
209
+
210
+ def set_tempdir(dir)
211
+ @tempdir = dir.dup
212
+ end
213
+
315
214
  #
316
215
  # Create a defined name in Excel. We handle global/workbook level names and
317
216
  # local/worksheet names.
@@ -497,14 +396,6 @@ module Writexlsx
497
396
  @calc_id = calc_id if calc_id
498
397
  end
499
398
 
500
- #
501
- # Get the default url format used when a user defined format isn't specified
502
- # with write_url(). The format is the hyperlink style defined by Excel for the
503
- # default theme.
504
- #
505
- attr_reader :default_url_format
506
- alias get_default_url_format default_url_format
507
-
508
399
  #
509
400
  # Change the RGB components of the elements in the colour palette.
510
401
  #
@@ -537,10 +428,67 @@ module Writexlsx
537
428
  index + 8
538
429
  end
539
430
 
431
+ ###############################################################################
432
+ #
433
+ # Workbook accessors and lookup
434
+ #
435
+ ###############################################################################
436
+
437
+ #
438
+ # get array of Worksheet objects
439
+ #
440
+ # :call-seq:
441
+ # sheets -> array of all Wordsheet object
442
+ # sheets(1, 3, 4) -> array of spcified Worksheet object.
443
+ #
444
+ def sheets(*args)
445
+ if args.empty?
446
+ @worksheets
447
+ else
448
+ args.collect { |i| @worksheets[i] }
449
+ end
450
+ end
451
+
452
+ #
453
+ # Return a worksheet object in the workbook using the sheetname.
454
+ #
455
+ def worksheet_by_name(sheetname = nil)
456
+ sheets.select { |s| s.name == sheetname }.first
457
+ end
458
+ alias get_worksheet_by_name worksheet_by_name
459
+
460
+ #
461
+ # user must not use. it is internal method.
462
+ #
463
+ def set_xml_writer(filename) # :nodoc:
464
+ @writer.set_xml_writer(filename)
465
+ end
466
+
467
+ #
468
+ # user must not use. it is internal method.
469
+ #
470
+ def xml_str # :nodoc:
471
+ @writer.string
472
+ end
473
+
474
+ #
475
+ # Get the default url format used when a user defined format isn't specified
476
+ # with write_url(). The format is the hyperlink style defined by Excel for the
477
+ # default theme.
478
+ #
479
+ attr_reader :default_url_format
480
+ alias get_default_url_format default_url_format
481
+
540
482
  attr_writer :activesheet
541
483
 
542
484
  attr_reader :writer
543
485
 
486
+ ###############################################################################
487
+ #
488
+ # Workbook state queries
489
+ #
490
+ ###############################################################################
491
+
544
492
  def date_1904? # :nodoc:
545
493
  @date_1904 ||= false
546
494
  !!@date_1904
@@ -555,6 +503,7 @@ module Writexlsx
555
503
  # return the string index.
556
504
  #
557
505
  EMPTY_HASH = {}.freeze
506
+
558
507
  def shared_string_index(str) # :nodoc:
559
508
  @shared_strings.index(str, EMPTY_HASH)
560
509
  end
@@ -642,121 +591,18 @@ module Writexlsx
642
591
  end
643
592
  end
644
593
 
594
+ ###############################################################################
595
+ #
596
+ # private helpers
597
+ #
598
+ ###############################################################################
645
599
  private
646
600
 
601
+ ###############################################################################
647
602
  #
648
- # Workbook の生成時のオプションハッシュを解析する
603
+ # Worksheet and chart naming helpers
649
604
  #
650
- def process_workbook_options(*params)
651
- case params.size
652
- when 0
653
- [{}, {}]
654
- when 1 # one hash
655
- options_keys = %i[tempdir date_1904 optimization excel2003_style strings_to_urls max_url_length]
656
-
657
- hash = params.first
658
- options = hash.reject { |k, _v| !options_keys.include?(k) }
659
-
660
- default_format_properties =
661
- hash[:default_format_properties] ||
662
- hash.reject { |k, _v| options_keys.include?(k) }
663
-
664
- [options, default_format_properties.dup]
665
- when 2 # array which includes options and default_format_properties
666
- options, default_format_properties = params
667
- default_format_properties ||= {}
668
-
669
- [options.dup, default_format_properties.dup]
670
- end
671
- end
672
-
673
- def filename
674
- setup_filename unless @filename
675
- @filename
676
- end
677
-
678
- def fileobj
679
- setup_filename unless @fileobj
680
- @fileobj
681
- end
682
-
683
- def setup_filename # :nodoc:
684
- if @file.respond_to?(:to_str) && @file != ''
685
- @filename = @file
686
- @fileobj = nil
687
- elsif @file.respond_to?(:write)
688
- @filename = File.join(tempdir, Digest::MD5.hexdigest(Time.now.to_s) + '.xlsx.tmp')
689
- @fileobj = @file
690
- else
691
- raise "'#{@file}' must be valid filename String of IO object."
692
- end
693
- end
694
-
695
- attr_reader :tempdir
696
-
697
- #
698
- # Sets the colour palette to the Excel defaults.
699
- #
700
- def set_color_palette # :nodoc:
701
- @palette = [
702
- [0x00, 0x00, 0x00, 0x00], # 8
703
- [0xff, 0xff, 0xff, 0x00], # 9
704
- [0xff, 0x00, 0x00, 0x00], # 10
705
- [0x00, 0xff, 0x00, 0x00], # 11
706
- [0x00, 0x00, 0xff, 0x00], # 12
707
- [0xff, 0xff, 0x00, 0x00], # 13
708
- [0xff, 0x00, 0xff, 0x00], # 14
709
- [0x00, 0xff, 0xff, 0x00], # 15
710
- [0x80, 0x00, 0x00, 0x00], # 16
711
- [0x00, 0x80, 0x00, 0x00], # 17
712
- [0x00, 0x00, 0x80, 0x00], # 18
713
- [0x80, 0x80, 0x00, 0x00], # 19
714
- [0x80, 0x00, 0x80, 0x00], # 20
715
- [0x00, 0x80, 0x80, 0x00], # 21
716
- [0xc0, 0xc0, 0xc0, 0x00], # 22
717
- [0x80, 0x80, 0x80, 0x00], # 23
718
- [0x99, 0x99, 0xff, 0x00], # 24
719
- [0x99, 0x33, 0x66, 0x00], # 25
720
- [0xff, 0xff, 0xcc, 0x00], # 26
721
- [0xcc, 0xff, 0xff, 0x00], # 27
722
- [0x66, 0x00, 0x66, 0x00], # 28
723
- [0xff, 0x80, 0x80, 0x00], # 29
724
- [0x00, 0x66, 0xcc, 0x00], # 30
725
- [0xcc, 0xcc, 0xff, 0x00], # 31
726
- [0x00, 0x00, 0x80, 0x00], # 32
727
- [0xff, 0x00, 0xff, 0x00], # 33
728
- [0xff, 0xff, 0x00, 0x00], # 34
729
- [0x00, 0xff, 0xff, 0x00], # 35
730
- [0x80, 0x00, 0x80, 0x00], # 36
731
- [0x80, 0x00, 0x00, 0x00], # 37
732
- [0x00, 0x80, 0x80, 0x00], # 38
733
- [0x00, 0x00, 0xff, 0x00], # 39
734
- [0x00, 0xcc, 0xff, 0x00], # 40
735
- [0xcc, 0xff, 0xff, 0x00], # 41
736
- [0xcc, 0xff, 0xcc, 0x00], # 42
737
- [0xff, 0xff, 0x99, 0x00], # 43
738
- [0x99, 0xcc, 0xff, 0x00], # 44
739
- [0xff, 0x99, 0xcc, 0x00], # 45
740
- [0xcc, 0x99, 0xff, 0x00], # 46
741
- [0xff, 0xcc, 0x99, 0x00], # 47
742
- [0x33, 0x66, 0xff, 0x00], # 48
743
- [0x33, 0xcc, 0xcc, 0x00], # 49
744
- [0x99, 0xcc, 0x00, 0x00], # 50
745
- [0xff, 0xcc, 0x00, 0x00], # 51
746
- [0xff, 0x99, 0x00, 0x00], # 52
747
- [0xff, 0x66, 0x00, 0x00], # 53
748
- [0x66, 0x66, 0x99, 0x00], # 54
749
- [0x96, 0x96, 0x96, 0x00], # 55
750
- [0x00, 0x33, 0x66, 0x00], # 56
751
- [0x33, 0x99, 0x66, 0x00], # 57
752
- [0x00, 0x33, 0x00, 0x00], # 58
753
- [0x33, 0x33, 0x00, 0x00], # 59
754
- [0x99, 0x33, 0x00, 0x00], # 60
755
- [0x99, 0x33, 0x66, 0x00], # 61
756
- [0x33, 0x33, 0x99, 0x00], # 62
757
- [0x33, 0x33, 0x33, 0x00] # 63
758
- ]
759
- end
605
+ ###############################################################################
760
606
 
761
607
  #
762
608
  # Check for valid worksheet names. We check the length, if it contains any
@@ -770,703 +616,19 @@ module Writexlsx
770
616
  @worksheets.make_and_check_sheet_chart_name(:chart, name)
771
617
  end
772
618
 
619
+ ###############################################################################
773
620
  #
774
- # Convert a range formula such as Sheet1!$B$1:$B$5 into a sheet name and cell
775
- # range such as ( 'Sheet1', 0, 1, 4, 1 ).
621
+ # Internal utility helpers
776
622
  #
777
- def get_chart_range(range) # :nodoc:
778
- # Split the range formula into sheetname and cells at the last '!'.
779
- pos = range.rindex('!')
780
- return nil unless pos
781
-
782
- if pos > 0
783
- sheetname = range[0, pos]
784
- cells = range[(pos + 1)..-1]
785
- end
786
-
787
- # Split the cell range into 2 cells or else use single cell for both.
788
- if cells =~ /:/
789
- cell_1, cell_2 = cells.split(":")
790
- else
791
- cell_1 = cells
792
- cell_2 = cells
793
- end
794
-
795
- # Remove leading/trailing apostrophes and convert escaped quotes to single.
796
- sheetname.sub!(/^'/, '')
797
- sheetname.sub!(/'$/, '')
798
- sheetname.gsub!("''", "'")
799
-
800
- row_start, col_start = xl_cell_to_rowcol(cell_1)
801
- row_end, col_end = xl_cell_to_rowcol(cell_2)
802
-
803
- # Check that we have a 1D range only.
804
- return nil if row_start != row_end && col_start != col_end
805
-
806
- [sheetname, row_start, col_start, row_end, col_end]
807
- end
808
-
809
- def write_workbook(&block) # :nodoc:
810
- schema = 'http://schemas.openxmlformats.org'
811
- attributes = [
812
- ['xmlns',
813
- schema + '/spreadsheetml/2006/main'],
814
- ['xmlns:r',
815
- schema + '/officeDocument/2006/relationships']
816
- ]
817
- @writer.tag_elements('workbook', attributes, &block)
818
- end
819
-
820
- def write_file_version # :nodoc:
821
- attributes = [
822
- %w[appName xl],
823
- ['lastEdited', 4],
824
- ['lowestEdited', 4],
825
- ['rupBuild', 4505]
826
- ]
827
-
828
- attributes << [:codeName, '{37E998C4-C9E5-D4B9-71C8-EB1FF731991C}'] if @vba_project
829
-
830
- @writer.empty_tag('fileVersion', attributes)
831
- end
832
-
833
- #
834
- # Write the <fileSharing> element.
835
- #
836
- def write_file_sharing
837
- return unless ptrue?(@read_only)
838
-
839
- attributes = []
840
- attributes << ['readOnlyRecommended', 1]
841
- @writer.empty_tag('fileSharing', attributes)
842
- end
843
-
844
- def write_workbook_pr # :nodoc:
845
- attributes = []
846
- attributes << ['codeName', @vba_codename] if ptrue?(@vba_codename)
847
- attributes << ['date1904', 1] if date_1904?
848
- attributes << ['defaultThemeVersion', 124226]
849
- @writer.empty_tag('workbookPr', attributes)
850
- end
851
-
852
- def write_book_views # :nodoc:
853
- @writer.tag_elements('bookViews') { write_workbook_view }
854
- end
855
-
856
- def write_workbook_view # :nodoc:
857
- attributes = [
858
- ['xWindow', @x_window],
859
- ['yWindow', @y_window],
860
- ['windowWidth', @window_width],
861
- ['windowHeight', @window_height]
862
- ]
863
- attributes << ['tabRatio', @tab_ratio] if @tab_ratio != 600
864
- attributes << ['firstSheet', @firstsheet + 1] if @firstsheet > 0
865
- attributes << ['activeTab', @activesheet] if @activesheet > 0
866
- @writer.empty_tag('workbookView', attributes)
867
- end
868
-
869
- def write_calc_pr # :nodoc:
870
- attributes = [['calcId', @calc_id]]
871
-
872
- case @calc_mode
873
- when 'manual'
874
- attributes << %w[calcMode manual]
875
- attributes << ['calcOnSave', 0]
876
- when 'autoNoTable'
877
- attributes << %w[calcMode autoNoTable]
878
- end
879
-
880
- attributes << ['fullCalcOnLoad', 1] if @calc_on_load
881
-
882
- @writer.empty_tag('calcPr', attributes)
883
- end
884
-
885
- def write_ext_lst # :nodoc:
886
- @writer.tag_elements('extLst') { write_ext }
887
- end
888
-
889
- def write_ext # :nodoc:
890
- attributes = [
891
- ['xmlns:mx', "#{OFFICE_URL}mac/excel/2008/main"],
892
- ['uri', uri]
893
- ]
894
- @writer.tag_elements('ext', attributes) { write_mx_arch_id }
895
- end
896
-
897
- def write_mx_arch_id # :nodoc:
898
- @writer.empty_tag('mx:ArchID', ['Flags', 2])
899
- end
900
-
901
- def write_defined_names # :nodoc:
902
- return unless ptrue?(@defined_names)
903
-
904
- @writer.tag_elements('definedNames') do
905
- @defined_names.each { |defined_name| write_defined_name(defined_name) }
906
- end
907
- end
908
-
909
- def write_defined_name(defined_name) # :nodoc:
910
- name, id, range, hidden = defined_name
911
-
912
- attributes = [['name', name]]
913
- attributes << ['localSheetId', "#{id}"] unless id == -1
914
- attributes << %w[hidden 1] if hidden
915
-
916
- @writer.data_element('definedName', range, attributes)
917
- end
918
-
919
- def write_io(str) # :nodoc:
920
- @writer << str
921
- str
922
- end
623
+ ###############################################################################
923
624
 
924
625
  # for test
925
626
  def defined_names # :nodoc:
926
627
  @defined_names ||= []
927
628
  end
928
629
 
929
- #
930
- # Assemble worksheets into a workbook.
931
- #
932
- def store_workbook # :nodoc:
933
- # Add a default worksheet if non have been added.
934
- add_worksheet if @worksheets.empty?
935
-
936
- # Ensure that at least one worksheet has been selected.
937
- @worksheets.visible_first.select if @activesheet == 0
938
-
939
- # Set the active sheet.
940
- @activesheet = @worksheets.visible_first.index if @activesheet == 0
941
- @worksheets[@activesheet].activate
942
-
943
- # Convert the SST strings data structure.
944
- prepare_sst_string_data
945
-
946
- # Prepare the worksheet VML elements such as comments and buttons.
947
- prepare_vml_objects
948
- # Set the defined names for the worksheets such as Print Titles.
949
- prepare_defined_names
950
- # Prepare the drawings, charts and images.
951
- prepare_drawings
952
- # Add cached data to charts.
953
- add_chart_data
954
-
955
- # Prepare the worksheet tables.
956
- prepare_tables
957
-
958
- # Prepare the metadata file links.
959
- prepare_metadata
960
-
961
- # Package the workbook.
962
- packager = Package::Packager.new(self)
963
- packager.set_package_dir(tempdir)
964
- packager.create_package
965
-
966
- # Free up the Packager object.
967
- packager = nil
968
-
969
- # Store the xlsx component files with the temp dir name removed.
970
- ZipFileUtils.zip("#{tempdir}", filename)
971
-
972
- IO.copy_stream(filename, fileobj) if fileobj
973
- Writexlsx::Utility.delete_files(tempdir)
974
- end
975
-
976
630
  def zip_entry_for_part(part)
977
631
  Zip::Entry.new("", part)
978
632
  end
979
-
980
- #
981
- # prepare_sst_string_data
982
- #
983
- def prepare_sst_string_data; end
984
-
985
- #
986
- # Prepare all of the format properties prior to passing them to Styles.rb.
987
- #
988
- def prepare_format_properties # :nodoc:
989
- # Separate format objects into XF and DXF formats.
990
- prepare_formats
991
-
992
- # Set the font index for the format objects.
993
- prepare_fonts
994
-
995
- # Set the number format index for the format objects.
996
- prepare_num_formats
997
-
998
- # Set the border index for the format objects.
999
- prepare_borders
1000
-
1001
- # Set the fill index for the format objects.
1002
- prepare_fills
1003
- end
1004
-
1005
- #
1006
- # Iterate through the XF Format objects and separate them into XF and DXF
1007
- # formats.
1008
- #
1009
- def prepare_formats # :nodoc:
1010
- @formats.formats.each do |format|
1011
- xf_index = format.xf_index
1012
- dxf_index = format.dxf_index
1013
-
1014
- @xf_formats[xf_index] = format if xf_index
1015
- @dxf_formats[dxf_index] = format if dxf_index
1016
- end
1017
- end
1018
-
1019
- #
1020
- # Iterate through the XF Format objects and give them an index to non-default
1021
- # font elements.
1022
- #
1023
- def prepare_fonts # :nodoc:
1024
- fonts = {}
1025
-
1026
- @xf_formats.each { |format| format.set_font_info(fonts) }
1027
-
1028
- @font_count = fonts.size
1029
-
1030
- # For the DXF formats we only need to check if the properties have changed.
1031
- @dxf_formats.each do |format|
1032
- # The only font properties that can change for a DXF format are: color,
1033
- # bold, italic, underline and strikethrough.
1034
- format.has_dxf_font(true) if format.color? || format.bold? || format.italic? || format.underline? || format.strikeout?
1035
- end
1036
- end
1037
-
1038
- #
1039
- # Iterate through the XF Format objects and give them an index to non-default
1040
- # number format elements.
1041
- #
1042
- # User defined records start from index 0xA4.
1043
- #
1044
- def prepare_num_formats # :nodoc:
1045
- num_formats = []
1046
- unique_num_formats = {}
1047
- index = 164
1048
-
1049
- (@xf_formats + @dxf_formats).each do |format|
1050
- num_format = format.num_format
1051
-
1052
- # Check if num_format is an index to a built-in number format.
1053
- # Also check for a string of zeros, which is a valid number format
1054
- # string but would evaluate to zero.
1055
- #
1056
- if num_format.to_s =~ /^\d+$/ && num_format.to_s !~ /^0+\d/
1057
- # Number format '0' is indexed as 1 in Excel.
1058
- num_format = 1 if num_format == 0
1059
- # Index to a built-in number format.
1060
- format.num_format_index = num_format
1061
- next
1062
- elsif num_format.to_s == 'General'
1063
- # The 'General' format has an number format index of 0.
1064
- format.num_format_index = 0
1065
- next
1066
- end
1067
-
1068
- if unique_num_formats[num_format]
1069
- # Number format has already been used.
1070
- format.num_format_index = unique_num_formats[num_format]
1071
- else
1072
- # Add a new number format.
1073
- unique_num_formats[num_format] = index
1074
- format.num_format_index = index
1075
- index += 1
1076
-
1077
- # Only store/increase number format count for XF formats
1078
- # (not for DXF formats).
1079
- num_formats << num_format if ptrue?(format.xf_index)
1080
- end
1081
- end
1082
-
1083
- @num_formats = num_formats
1084
- end
1085
-
1086
- #
1087
- # Iterate through the XF Format objects and give them an index to non-default
1088
- # border elements.
1089
- #
1090
- def prepare_borders # :nodoc:
1091
- borders = {}
1092
-
1093
- @xf_formats.each { |format| format.set_border_info(borders) }
1094
-
1095
- @border_count = borders.size
1096
-
1097
- # For the DXF formats we only need to check if the properties have changed.
1098
- @dxf_formats.each do |format|
1099
- key = format.get_border_key
1100
- format.has_dxf_border(true) if key =~ /[^0:]/
1101
- end
1102
- end
1103
-
1104
- #
1105
- # Iterate through the XF Format objects and give them an index to non-default
1106
- # fill elements.
1107
- #
1108
- # The user defined fill properties start from 2 since there are 2 default
1109
- # fills: patternType="none" and patternType="gray125".
1110
- #
1111
- def prepare_fills # :nodoc:
1112
- fills = {}
1113
- index = 2 # Start from 2. See above.
1114
-
1115
- # Add the default fills.
1116
- fills['0:0:0'] = 0
1117
- fills['17:0:0'] = 1
1118
-
1119
- # Store the DXF colors separately since them may be reversed below.
1120
- @dxf_formats.each do |format|
1121
- next unless format.pattern != 0 || format.bg_color != 0 || format.fg_color != 0
1122
-
1123
- format.has_dxf_fill(true)
1124
- format.dxf_bg_color = format.bg_color
1125
- format.dxf_fg_color = format.fg_color
1126
- end
1127
-
1128
- @xf_formats.each do |format|
1129
- # The following logical statements jointly take care of special cases
1130
- # in relation to cell colours and patterns:
1131
- # 1. For a solid fill (_pattern == 1) Excel reverses the role of
1132
- # foreground and background colours, and
1133
- # 2. If the user specifies a foreground or background colour without
1134
- # a pattern they probably wanted a solid fill, so we fill in the
1135
- # defaults.
1136
- #
1137
- if format.pattern == 1 && ne_0?(format.bg_color) && ne_0?(format.fg_color)
1138
- format.fg_color, format.bg_color = format.bg_color, format.fg_color
1139
- elsif format.pattern <= 1 && ne_0?(format.bg_color) && eq_0?(format.fg_color)
1140
- format.fg_color = format.bg_color
1141
- format.bg_color = 0
1142
- format.pattern = 1
1143
- elsif format.pattern <= 1 && eq_0?(format.bg_color) && ne_0?(format.fg_color)
1144
- format.bg_color = 0
1145
- format.pattern = 1
1146
- end
1147
-
1148
- key = format.get_fill_key
1149
-
1150
- if fills[key]
1151
- # Fill has already been used.
1152
- format.fill_index = fills[key]
1153
- format.has_fill(false)
1154
- else
1155
- # This is a new fill.
1156
- fills[key] = index
1157
- format.fill_index = index
1158
- format.has_fill(true)
1159
- index += 1
1160
- end
1161
- end
1162
-
1163
- @fill_count = index
1164
- end
1165
-
1166
- def eq_0?(val)
1167
- ptrue?(val) ? false : true
1168
- end
1169
-
1170
- def ne_0?(val)
1171
- !eq_0?(val)
1172
- end
1173
-
1174
- #
1175
- # Iterate through the worksheets and store any defined names in addition to
1176
- # any user defined names. Stores the defined names for the Workbook.xml and
1177
- # the named ranges for App.xml.
1178
- #
1179
- def prepare_defined_names # :nodoc:
1180
- @worksheets.each do |sheet|
1181
- # Check for Print Area settings.
1182
- if sheet.autofilter_area
1183
- @defined_names << [
1184
- '_xlnm._FilterDatabase',
1185
- sheet.index,
1186
- sheet.autofilter_area,
1187
- 1
1188
- ]
1189
- end
1190
-
1191
- # Check for Print Area settings.
1192
- unless sheet.print_area.empty?
1193
- @defined_names << [
1194
- '_xlnm.Print_Area',
1195
- sheet.index,
1196
- sheet.print_area
1197
- ]
1198
- end
1199
-
1200
- # Check for repeat rows/cols. aka, Print Titles.
1201
- next unless !sheet.print_repeat_cols.empty? || !sheet.print_repeat_rows.empty?
1202
-
1203
- range = if !sheet.print_repeat_cols.empty? && !sheet.print_repeat_rows.empty?
1204
- sheet.print_repeat_cols + ',' + sheet.print_repeat_rows
1205
- else
1206
- sheet.print_repeat_cols + sheet.print_repeat_rows
1207
- end
1208
-
1209
- # Store the defined names.
1210
- @defined_names << ['_xlnm.Print_Titles', sheet.index, range]
1211
- end
1212
-
1213
- @defined_names = sort_defined_names(@defined_names)
1214
- @named_ranges = extract_named_ranges(@defined_names)
1215
- end
1216
-
1217
- #
1218
- # Iterate through the worksheets and set up the VML objects.
1219
- #
1220
- def prepare_vml_objects # :nodoc:
1221
- comment_id = 0
1222
- vml_drawing_id = 0
1223
- vml_data_id = 1
1224
- vml_header_id = 0
1225
- vml_shape_id = 1024
1226
- has_button = false
1227
-
1228
- @worksheets.each do |sheet|
1229
- next if !sheet.has_vml? && !sheet.has_header_vml?
1230
-
1231
- if sheet.has_vml?
1232
- if sheet.has_comments?
1233
- comment_id += 1
1234
- @has_comments = true
1235
- end
1236
- vml_drawing_id += 1
1237
-
1238
- sheet.prepare_vml_objects(
1239
- vml_data_id, vml_shape_id,
1240
- vml_drawing_id, comment_id
1241
- )
1242
-
1243
- # Each VML file should start with a shape id incremented by 1024.
1244
- vml_data_id += 1 * (1 + sheet.num_comments_block)
1245
- vml_shape_id += 1024 * (1 + sheet.num_comments_block)
1246
- end
1247
-
1248
- if sheet.has_header_vml?
1249
- vml_header_id += 1
1250
- vml_drawing_id += 1
1251
- sheet.prepare_header_vml_objects(vml_header_id, vml_drawing_id)
1252
- end
1253
-
1254
- # Set the sheet vba_codename if it has a button and the workbook
1255
- # has a vbaProject binary.
1256
- unless sheet.buttons_data.empty?
1257
- has_button = true
1258
- sheet.set_vba_name if @vba_project && !sheet.vba_codename
1259
- end
1260
- end
1261
-
1262
- # Set the workbook vba_codename if one of the sheets has a button and
1263
- # the workbook has a vbaProject binary.
1264
- set_vba_name if has_button && @vba_project && !@vba_codename
1265
- end
1266
-
1267
- #
1268
- # Set the table ids for the worksheet tables.
1269
- #
1270
- def prepare_tables
1271
- table_id = 0
1272
- seen = {}
1273
-
1274
- sheets.each do |sheet|
1275
- table_id += sheet.prepare_tables(table_id + 1, seen)
1276
- end
1277
- end
1278
-
1279
- #
1280
- # Set the metadata rel link.
1281
- #
1282
- def prepare_metadata
1283
- @worksheets.each do |sheet|
1284
- next unless sheet.has_dynamic_functions? || sheet.has_embedded_images?
1285
-
1286
- @has_metadata = true
1287
- @has_dynamic_functions ||= sheet.has_dynamic_functions?
1288
- @has_embedded_images ||= sheet.has_embedded_images?
1289
- end
1290
- end
1291
-
1292
- #
1293
- # Add "cached" data to charts to provide the numCache and strCache data for
1294
- # series and title/axis ranges.
1295
- #
1296
- def add_chart_data # :nodoc:
1297
- worksheets = {}
1298
- seen_ranges = {}
1299
-
1300
- # Map worksheet names to worksheet objects.
1301
- @worksheets.each { |worksheet| worksheets[worksheet.name] = worksheet }
1302
-
1303
- # Build an array of the worksheet charts including any combined charts.
1304
- @charts.collect { |chart| [chart, chart.combined] }.flatten.compact
1305
- .each do |chart|
1306
- chart.formula_ids.each do |range, id|
1307
- # Skip if the series has user defined data.
1308
- if chart.formula_data[id]
1309
- seen_ranges[range] = chart.formula_data[id] unless seen_ranges[range]
1310
- next
1311
- # Check to see if the data is already cached locally.
1312
- elsif seen_ranges[range]
1313
- chart.formula_data[id] = seen_ranges[range]
1314
- next
1315
- end
1316
-
1317
- # Convert the range formula to a sheet name and cell range.
1318
- sheetname, *cells = get_chart_range(range)
1319
-
1320
- # Skip if we couldn't parse the formula.
1321
- next unless sheetname
1322
-
1323
- # Handle non-contiguous ranges: (Sheet1!$A$1:$A$2,Sheet1!$A$4:$A$5).
1324
- # We don't try to parse the ranges. We just return an empty list.
1325
- if sheetname =~ /^\([^,]+,/
1326
- chart.formula_data[id] = []
1327
- seen_ranges[range] = []
1328
- next
1329
- end
1330
-
1331
- # Raise if the name is unknown since it indicates a user error in
1332
- # a chart series formula.
1333
- raise "Unknown worksheet reference '#{sheetname} in range '#{range}' passed to add_series()\n" unless worksheets[sheetname]
1334
-
1335
- # Add the data to the chart.
1336
- # And store range data locally to avoid lookup if seen agein.
1337
- chart.formula_data[id] =
1338
- seen_ranges[range] = chart_data(worksheets[sheetname], cells)
1339
- end
1340
- end
1341
- end
1342
-
1343
- def chart_data(worksheet, cells)
1344
- # Get the data from the worksheet table.
1345
- data = worksheet.get_range_data(*cells)
1346
-
1347
- # Convert shared string indexes to strings.
1348
- data.collect do |token|
1349
- if token.is_a?(Hash)
1350
- string = @shared_strings.string(token[:sst_id])
1351
-
1352
- # Ignore rich strings for now. Deparse later if necessary.
1353
- if string =~ /^<r>/ && string =~ %r{</r>$}
1354
- ''
1355
- else
1356
- string
1357
- end
1358
- else
1359
- token
1360
- end
1361
- end
1362
- end
1363
-
1364
- #
1365
- # Sort internal and user defined names in the same order as used by Excel.
1366
- # This may not be strictly necessary but unsorted elements caused a lot of
1367
- # issues in the the Spreadsheet::WriteExcel binary version. Also makes
1368
- # comparison testing easier.
1369
- #
1370
- def sort_defined_names(names) # :nodoc:
1371
- names.sort do |a, b|
1372
- name_a = normalise_defined_name(a[0])
1373
- name_b = normalise_defined_name(b[0])
1374
- sheet_a = normalise_sheet_name(a[2])
1375
- sheet_b = normalise_sheet_name(b[2])
1376
- # Primary sort based on the defined name.
1377
- if name_a > name_b
1378
- 1
1379
- elsif name_a < name_b
1380
- -1
1381
- elsif sheet_a >= sheet_b # name_a == name_b
1382
- # Secondary sort based on the sheet name.
1383
- 1
1384
- else
1385
- -1
1386
- end
1387
- end
1388
- end
1389
-
1390
- # Used in the above sort routine to normalise the defined names. Removes any
1391
- # leading '_xmln.' from internal names and lowercases the strings.
1392
- def normalise_defined_name(name) # :nodoc:
1393
- name.sub(/^_xlnm./, '').downcase
1394
- end
1395
-
1396
- # Used in the above sort routine to normalise the worksheet names for the
1397
- # secondary sort. Removes leading quote and lowercases the strings.
1398
- def normalise_sheet_name(name) # :nodoc:
1399
- name.sub(/^'/, '').downcase
1400
- end
1401
-
1402
- #
1403
- # Extract the named ranges from the sorted list of defined names. These are
1404
- # used in the App.xml file.
1405
- #
1406
- def extract_named_ranges(defined_names) # :nodoc:
1407
- named_ranges = []
1408
-
1409
- defined_names.each do |defined_name|
1410
- name, index, range = defined_name
1411
-
1412
- # Skip autoFilter ranges.
1413
- next if name == '_xlnm._FilterDatabase'
1414
-
1415
- # We are only interested in defined names with ranges.
1416
- next unless range =~ /^([^!]+)!/
1417
-
1418
- sheet_name = ::Regexp.last_match(1)
1419
-
1420
- # Match Print_Area and Print_Titles xlnm types.
1421
- if name =~ /^_xlnm\.(.*)$/
1422
- xlnm_type = ::Regexp.last_match(1)
1423
- name = "#{sheet_name}!#{xlnm_type}"
1424
- elsif index != -1
1425
- name = "#{sheet_name}!#{name}"
1426
- end
1427
-
1428
- named_ranges << name
1429
- end
1430
-
1431
- named_ranges
1432
- end
1433
-
1434
- #
1435
- # Iterate through the worksheets and set up any chart or image drawings.
1436
- #
1437
- def prepare_drawings # :nodoc:
1438
- # Store the image types for any embedded images.
1439
- @embedded_images.each do |image|
1440
- store_image_types(image.type)
1441
-
1442
- @has_embedded_descriptions = true if ptrue?(image.description)
1443
- end
1444
-
1445
- prepare_drawings_of_all_sheets
1446
-
1447
- # Sort the workbook charts references into the order that the were
1448
- # written from the worksheets above.
1449
- @charts = @charts.select { |chart| chart.id != -1 }
1450
- .sort_by { |chart| chart.id }
1451
- end
1452
-
1453
- def prepare_drawings_of_all_sheets
1454
- drawing_id = 0
1455
- chart_ref_id = 0
1456
- image_ids = {}
1457
- header_image_ids = {}
1458
- background_ids = {}
1459
-
1460
- # The image IDs start from after the embedded images.
1461
- image_ref_id = @embedded_images.size
1462
-
1463
- @worksheets.each do |sheet|
1464
- drawing_id, chart_ref_id, image_ref_id =
1465
- sheet.prepare_drawings(
1466
- drawing_id, chart_ref_id, image_ref_id, image_ids,
1467
- header_image_ids, background_ids
1468
- )
1469
- end
1470
- end
1471
633
  end
1472
634
  end