ricardoo27-writeexcel 0.6.12.1

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 (245) hide show
  1. data/.document +5 -0
  2. data/.gitattributes +1 -0
  3. data/README.rdoc +136 -0
  4. data/Rakefile +52 -0
  5. data/VERSION +1 -0
  6. data/charts/chartex.rb +316 -0
  7. data/charts/demo1.rb +46 -0
  8. data/charts/demo101.bin +0 -0
  9. data/charts/demo2.rb +65 -0
  10. data/charts/demo201.bin +0 -0
  11. data/charts/demo3.rb +117 -0
  12. data/charts/demo301.bin +0 -0
  13. data/charts/demo4.rb +119 -0
  14. data/charts/demo401.bin +0 -0
  15. data/charts/demo5.rb +48 -0
  16. data/charts/demo501.bin +0 -0
  17. data/examples/a_simple.rb +43 -0
  18. data/examples/autofilter.rb +265 -0
  19. data/examples/bigfile.rb +30 -0
  20. data/examples/chart_area.rb +121 -0
  21. data/examples/chart_bar.rb +120 -0
  22. data/examples/chart_column.rb +120 -0
  23. data/examples/chart_line.rb +120 -0
  24. data/examples/chart_pie.rb +108 -0
  25. data/examples/chart_scatter.rb +121 -0
  26. data/examples/chart_stock.rb +148 -0
  27. data/examples/chess.rb +142 -0
  28. data/examples/colors.rb +129 -0
  29. data/examples/comments1.rb +27 -0
  30. data/examples/comments2.rb +352 -0
  31. data/examples/copyformat.rb +52 -0
  32. data/examples/data_validate.rb +279 -0
  33. data/examples/date_time.rb +87 -0
  34. data/examples/defined_name.rb +32 -0
  35. data/examples/demo.rb +124 -0
  36. data/examples/diag_border.rb +36 -0
  37. data/examples/formats.rb +490 -0
  38. data/examples/formula_result.rb +30 -0
  39. data/examples/header.rb +137 -0
  40. data/examples/hide_sheet.rb +29 -0
  41. data/examples/hyperlink.rb +43 -0
  42. data/examples/images.rb +63 -0
  43. data/examples/indent.rb +31 -0
  44. data/examples/merge1.rb +40 -0
  45. data/examples/merge2.rb +45 -0
  46. data/examples/merge3.rb +66 -0
  47. data/examples/merge4.rb +83 -0
  48. data/examples/merge5.rb +80 -0
  49. data/examples/merge6.rb +67 -0
  50. data/examples/outline.rb +255 -0
  51. data/examples/outline_collapsed.rb +209 -0
  52. data/examples/panes.rb +113 -0
  53. data/examples/password_protection.rb +33 -0
  54. data/examples/properties.rb +34 -0
  55. data/examples/properties_jp.rb +33 -0
  56. data/examples/protection.rb +47 -0
  57. data/examples/regions.rb +53 -0
  58. data/examples/repeat.rb +43 -0
  59. data/examples/republic.png +0 -0
  60. data/examples/right_to_left.rb +27 -0
  61. data/examples/row_wrap.rb +53 -0
  62. data/examples/set_first_sheet.rb +14 -0
  63. data/examples/stats.rb +74 -0
  64. data/examples/stocks.rb +81 -0
  65. data/examples/store_formula.rb +15 -0
  66. data/examples/tab_colors.rb +31 -0
  67. data/examples/utf8.rb +15 -0
  68. data/examples/write_arrays.rb +83 -0
  69. data/html/en/doc_en.html +5946 -0
  70. data/html/images/a_simple.jpg +0 -0
  71. data/html/images/area1.jpg +0 -0
  72. data/html/images/bar1.jpg +0 -0
  73. data/html/images/chart_area.xls +0 -0
  74. data/html/images/column1.jpg +0 -0
  75. data/html/images/data_validation.jpg +0 -0
  76. data/html/images/line1.jpg +0 -0
  77. data/html/images/pie1.jpg +0 -0
  78. data/html/images/regions.jpg +0 -0
  79. data/html/images/scatter1.jpg +0 -0
  80. data/html/images/stats.jpg +0 -0
  81. data/html/images/stock1.jpg +0 -0
  82. data/html/images/stocks.jpg +0 -0
  83. data/html/index.html +16 -0
  84. data/html/style.css +433 -0
  85. data/lib/writeexcel.rb +1159 -0
  86. data/lib/writeexcel/biffwriter.rb +223 -0
  87. data/lib/writeexcel/caller_info.rb +12 -0
  88. data/lib/writeexcel/cell_range.rb +332 -0
  89. data/lib/writeexcel/chart.rb +1968 -0
  90. data/lib/writeexcel/charts/area.rb +154 -0
  91. data/lib/writeexcel/charts/bar.rb +177 -0
  92. data/lib/writeexcel/charts/column.rb +156 -0
  93. data/lib/writeexcel/charts/external.rb +66 -0
  94. data/lib/writeexcel/charts/line.rb +154 -0
  95. data/lib/writeexcel/charts/pie.rb +169 -0
  96. data/lib/writeexcel/charts/scatter.rb +192 -0
  97. data/lib/writeexcel/charts/stock.rb +213 -0
  98. data/lib/writeexcel/col_info.rb +87 -0
  99. data/lib/writeexcel/colors.rb +68 -0
  100. data/lib/writeexcel/comments.rb +460 -0
  101. data/lib/writeexcel/compatibility.rb +65 -0
  102. data/lib/writeexcel/convert_date_time.rb +117 -0
  103. data/lib/writeexcel/data_validations.rb +370 -0
  104. data/lib/writeexcel/debug_info.rb +41 -0
  105. data/lib/writeexcel/embedded_chart.rb +35 -0
  106. data/lib/writeexcel/excelformula.y +139 -0
  107. data/lib/writeexcel/excelformulaparser.rb +587 -0
  108. data/lib/writeexcel/format.rb +1575 -0
  109. data/lib/writeexcel/formula.rb +987 -0
  110. data/lib/writeexcel/helper.rb +78 -0
  111. data/lib/writeexcel/image.rb +218 -0
  112. data/lib/writeexcel/olewriter.rb +305 -0
  113. data/lib/writeexcel/outline.rb +24 -0
  114. data/lib/writeexcel/properties.rb +242 -0
  115. data/lib/writeexcel/shared_string_table.rb +153 -0
  116. data/lib/writeexcel/storage_lite.rb +984 -0
  117. data/lib/writeexcel/workbook.rb +2478 -0
  118. data/lib/writeexcel/worksheet.rb +6925 -0
  119. data/lib/writeexcel/worksheets.rb +25 -0
  120. data/lib/writeexcel/write_file.rb +63 -0
  121. data/test/excelfile/Chart1.xls +0 -0
  122. data/test/excelfile/Chart2.xls +0 -0
  123. data/test/excelfile/Chart3.xls +0 -0
  124. data/test/excelfile/Chart4.xls +0 -0
  125. data/test/excelfile/Chart5.xls +0 -0
  126. data/test/helper.rb +31 -0
  127. data/test/perl_output/Chart1.xls.data +0 -0
  128. data/test/perl_output/Chart2.xls.data +0 -0
  129. data/test/perl_output/Chart3.xls.data +0 -0
  130. data/test/perl_output/Chart4.xls.data +0 -0
  131. data/test/perl_output/Chart5.xls.data +0 -0
  132. data/test/perl_output/README +31 -0
  133. data/test/perl_output/a_simple.xls +0 -0
  134. data/test/perl_output/autofilter.xls +0 -0
  135. data/test/perl_output/biff_add_continue_testdata +0 -0
  136. data/test/perl_output/chart_area.xls +0 -0
  137. data/test/perl_output/chart_bar.xls +0 -0
  138. data/test/perl_output/chart_column.xls +0 -0
  139. data/test/perl_output/chart_line.xls +0 -0
  140. data/test/perl_output/chess.xls +0 -0
  141. data/test/perl_output/colors.xls +0 -0
  142. data/test/perl_output/comments0.xls +0 -0
  143. data/test/perl_output/comments1.xls +0 -0
  144. data/test/perl_output/comments2.xls +0 -0
  145. data/test/perl_output/data_validate.xls +0 -0
  146. data/test/perl_output/date_time.xls +0 -0
  147. data/test/perl_output/defined_name.xls +0 -0
  148. data/test/perl_output/demo.xls +0 -0
  149. data/test/perl_output/demo101.bin +0 -0
  150. data/test/perl_output/demo201.bin +0 -0
  151. data/test/perl_output/demo301.bin +0 -0
  152. data/test/perl_output/demo401.bin +0 -0
  153. data/test/perl_output/demo501.bin +0 -0
  154. data/test/perl_output/diag_border.xls +0 -0
  155. data/test/perl_output/f_font_biff +0 -0
  156. data/test/perl_output/f_font_key +1 -0
  157. data/test/perl_output/f_xf_biff +0 -0
  158. data/test/perl_output/file_font_biff +0 -0
  159. data/test/perl_output/file_font_key +1 -0
  160. data/test/perl_output/file_xf_biff +0 -0
  161. data/test/perl_output/formula_result.xls +0 -0
  162. data/test/perl_output/headers.xls +0 -0
  163. data/test/perl_output/hidden.xls +0 -0
  164. data/test/perl_output/hide_zero.xls +0 -0
  165. data/test/perl_output/hyperlink.xls +0 -0
  166. data/test/perl_output/images.xls +0 -0
  167. data/test/perl_output/indent.xls +0 -0
  168. data/test/perl_output/merge1.xls +0 -0
  169. data/test/perl_output/merge2.xls +0 -0
  170. data/test/perl_output/merge3.xls +0 -0
  171. data/test/perl_output/merge4.xls +0 -0
  172. data/test/perl_output/merge5.xls +0 -0
  173. data/test/perl_output/merge6.xls +0 -0
  174. data/test/perl_output/ole_write_header +0 -0
  175. data/test/perl_output/outline.xls +0 -0
  176. data/test/perl_output/outline_collapsed.xls +0 -0
  177. data/test/perl_output/panes.xls +0 -0
  178. data/test/perl_output/password_protection.xls +0 -0
  179. data/test/perl_output/protection.xls +0 -0
  180. data/test/perl_output/regions.xls +0 -0
  181. data/test/perl_output/right_to_left.xls +0 -0
  182. data/test/perl_output/set_first_sheet.xls +0 -0
  183. data/test/perl_output/stats.xls +0 -0
  184. data/test/perl_output/stocks.xls +0 -0
  185. data/test/perl_output/store_formula.xls +0 -0
  186. data/test/perl_output/tab_colors.xls +0 -0
  187. data/test/perl_output/unicode_cyrillic.xls +0 -0
  188. data/test/perl_output/utf8.xls +0 -0
  189. data/test/perl_output/workbook1.xls +0 -0
  190. data/test/perl_output/workbook2.xls +0 -0
  191. data/test/perl_output/ws_colinfo +1 -0
  192. data/test/perl_output/ws_store_colinfo +0 -0
  193. data/test/perl_output/ws_store_dimensions +0 -0
  194. data/test/perl_output/ws_store_filtermode +0 -0
  195. data/test/perl_output/ws_store_filtermode_off +0 -0
  196. data/test/perl_output/ws_store_filtermode_on +0 -0
  197. data/test/perl_output/ws_store_selection +0 -0
  198. data/test/perl_output/ws_store_window2 +1 -0
  199. data/test/republic.png +0 -0
  200. data/test/test_00_IEEE_double.rb +13 -0
  201. data/test/test_01_add_worksheet.rb +10 -0
  202. data/test/test_02_merge_formats.rb +49 -0
  203. data/test/test_04_dimensions.rb +388 -0
  204. data/test/test_05_rows.rb +175 -0
  205. data/test/test_06_extsst.rb +74 -0
  206. data/test/test_11_date_time.rb +475 -0
  207. data/test/test_12_date_only.rb +525 -0
  208. data/test/test_13_date_seconds.rb +477 -0
  209. data/test/test_21_escher.rb +624 -0
  210. data/test/test_22_mso_drawing_group.rb +741 -0
  211. data/test/test_23_note.rb +57 -0
  212. data/test/test_24_txo.rb +74 -0
  213. data/test/test_25_position_object.rb +80 -0
  214. data/test/test_26_autofilter.rb +309 -0
  215. data/test/test_27_autofilter.rb +126 -0
  216. data/test/test_28_autofilter.rb +156 -0
  217. data/test/test_29_process_jpg.rb +670 -0
  218. data/test/test_30_validation_dval.rb +74 -0
  219. data/test/test_31_validation_dv_strings.rb +123 -0
  220. data/test/test_32_validation_dv_formula.rb +203 -0
  221. data/test/test_40_property_types.rb +188 -0
  222. data/test/test_41_properties.rb +235 -0
  223. data/test/test_42_set_properties.rb +434 -0
  224. data/test/test_50_name_stored.rb +295 -0
  225. data/test/test_51_name_print_area.rb +353 -0
  226. data/test/test_52_name_print_titles.rb +450 -0
  227. data/test/test_53_autofilter.rb +199 -0
  228. data/test/test_60_chart_generic.rb +574 -0
  229. data/test/test_61_chart_subclasses.rb +84 -0
  230. data/test/test_62_chart_formats.rb +268 -0
  231. data/test/test_63_chart_area_formats.rb +645 -0
  232. data/test/test_biff.rb +71 -0
  233. data/test/test_big_workbook.rb +17 -0
  234. data/test/test_compatibility.rb +12 -0
  235. data/test/test_example_match.rb +3246 -0
  236. data/test/test_format.rb +1189 -0
  237. data/test/test_formula.rb +61 -0
  238. data/test/test_ole.rb +102 -0
  239. data/test/test_storage_lite.rb +116 -0
  240. data/test/test_workbook.rb +146 -0
  241. data/test/test_worksheet.rb +106 -0
  242. data/utils/add_magic_comment.rb +80 -0
  243. data/writeexcel.gemspec +278 -0
  244. data/writeexcel.rdoc +1425 -0
  245. metadata +292 -0
@@ -0,0 +1,223 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # BIFFwriter - An abstract base class for Excel workbooks and worksheets.
4
+ #
5
+ #
6
+ # Used in conjunction with WriteExcel
7
+ #
8
+ # Copyright 2000-2010, John McNamara, jmcnamara@cpan.org
9
+ #
10
+ # original written in Perl by John McNamara
11
+ # converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
12
+ #
13
+
14
+
15
+ require 'tempfile'
16
+ require 'writeexcel/write_file'
17
+
18
+ class BIFFWriter < WriteFile #:nodoc:
19
+
20
+ BIFF_Version = 0x0600
21
+ BigEndian = [1].pack("I") == [1].pack("N")
22
+
23
+ attr_reader :data, :datasize
24
+
25
+ ######################################################################
26
+ # The args here aren't used by BIFFWriter, but they are needed by its
27
+ # subclasses. I don't feel like creating multiple constructors.
28
+ ######################################################################
29
+
30
+ def initialize
31
+ super
32
+ set_byte_order
33
+ @ignore_continue = false
34
+ end
35
+
36
+ ###############################################################################
37
+ #
38
+ # _set_byte_order()
39
+ #
40
+ # Determine the byte order and store it as class data to avoid
41
+ # recalculating it for each call to new().
42
+ #
43
+ def set_byte_order
44
+ # Check if "pack" gives the required IEEE 64bit float
45
+ teststr = [1.2345].pack("d")
46
+ hexdata = [0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F]
47
+ number = hexdata.pack("C8")
48
+
49
+ if number == teststr
50
+ @byte_order = false # Little Endian
51
+ elsif number == teststr.reverse
52
+ @byte_order = true # Big Endian
53
+ else
54
+ # Give up. I'll fix this in a later version.
55
+ raise( "Required floating point format not supported " +
56
+ "on this platform. See the portability section " +
57
+ "of the documentation."
58
+ )
59
+ end
60
+ end
61
+
62
+ ###############################################################################
63
+ #
64
+ # get_data().
65
+ #
66
+ # Retrieves data from memory in one chunk, or from disk in $buffer
67
+ # sized chunks.
68
+ #
69
+ def get_data
70
+ buflen = 4096
71
+
72
+ # Return data stored in memory
73
+ unless @data.nil?
74
+ tmp = @data
75
+ @data = nil
76
+ if @using_tmpfile
77
+ @filehandle.open
78
+ @filehandle.binmode
79
+ end
80
+ return tmp
81
+ end
82
+
83
+ # Return data stored on disk
84
+ if @using_tmpfile
85
+ return @filehandle.read(buflen)
86
+ end
87
+
88
+ # No data to return
89
+ nil
90
+ end
91
+
92
+ ###############################################################################
93
+ #
94
+ # _store_bof($type)
95
+ #
96
+ # $type = 0x0005, Workbook
97
+ # $type = 0x0010, Worksheet
98
+ # $type = 0x0020, Chart
99
+ #
100
+ # Writes Excel BOF record to indicate the beginning of a stream or
101
+ # sub-stream in the BIFF file.
102
+ #
103
+ def store_bof(type = 0x0005)
104
+ record = 0x0809 # Record identifier
105
+ length = 0x0010 # Number of bytes to follow
106
+
107
+ # According to the SDK $build and $year should be set to zero.
108
+ # However, this throws a warning in Excel 5. So, use these
109
+ # magic numbers.
110
+ build = 0x0DBB
111
+ year = 0x07CC
112
+
113
+ bfh = 0x00000041
114
+ sfo = 0x00000006
115
+
116
+ header = [record,length].pack("vv")
117
+ data = [BIFF_Version,type,build,year,bfh,sfo].pack("vvvvVV")
118
+
119
+ prepend(header, data)
120
+ end
121
+
122
+ ###############################################################################
123
+ #
124
+ # _store_eof()
125
+ #
126
+ # Writes Excel EOF record to indicate the end of a BIFF stream.
127
+ #
128
+ def store_eof
129
+ record = 0x000A
130
+ length = 0x0000
131
+ header = [record,length].pack("vv")
132
+
133
+ append(header)
134
+ end
135
+
136
+ ###############################################################################
137
+ #
138
+ # _add_continue()
139
+ #
140
+ # Excel limits the size of BIFF records. In Excel 5 the limit is 2084 bytes. In
141
+ # Excel 97 the limit is 8228 bytes. Records that are longer than these limits
142
+ # must be split up into CONTINUE blocks.
143
+ #
144
+ # This function take a long BIFF record and inserts CONTINUE records as
145
+ # necessary.
146
+ #
147
+ # Some records have their own specialised Continue blocks so there is also an
148
+ # option to bypass this function.
149
+ #
150
+ def add_continue(data)
151
+ # Skip this if another method handles the continue blocks.
152
+ return data if @ignore_continue
153
+
154
+ record = 0x003C # Record identifier
155
+ header = [record, @limit].pack("vv")
156
+
157
+ # The first 2080/8224 bytes remain intact. However, we have to change
158
+ # the length field of the record.
159
+ #
160
+ data_array = split_by_length(data, @limit)
161
+ first_data = data_array.shift
162
+ last_data = data_array.pop || ''
163
+ first_data[2, 2] = [@limit-4].pack('v')
164
+ first_data <<
165
+ data_array.join(header) <<
166
+ [record, last_data.bytesize].pack('vv') <<
167
+ last_data
168
+ end
169
+
170
+ ###############################################################################
171
+ #
172
+ # _add_mso_generic()
173
+ # my $type = $_[0];
174
+ # my $version = $_[1];
175
+ # my $instance = $_[2];
176
+ # my $data = $_[3];
177
+ #
178
+ # Create a mso structure that is part of an Escher drawing object. These are
179
+ # are used for images, comments and filters. This generic method is used by
180
+ # other methods to create specific mso records.
181
+ #
182
+ # Returns the packed record.
183
+ #
184
+ def add_mso_generic(type, version, instance, data, length = nil)
185
+ length ||= data.bytesize
186
+
187
+ # The header contains version and instance info packed into 2 bytes.
188
+ header = version | (instance << 4)
189
+
190
+ record = [header, type, length].pack('vvV') + data
191
+ end
192
+
193
+ def not_using_tmpfile
194
+ @filehandle.close(true) if @filehandle
195
+ @filehandle = nil
196
+ @using_tmpfile = nil
197
+ end
198
+
199
+ def clear_data_for_test # :nodoc:
200
+ @data = ''
201
+ end
202
+
203
+ def cleanup # :nodoc:
204
+ @filehandle.close(true) if @filehandle
205
+ end
206
+
207
+ # override Object#inspect
208
+ def inspect # :nodoc:
209
+ to_s
210
+ end
211
+
212
+ private
213
+
214
+ def split_by_length(data, length)
215
+ array = []
216
+ s = 0
217
+ while s < data.length
218
+ array << data[s, length]
219
+ s += length
220
+ end
221
+ array
222
+ end
223
+ end
@@ -0,0 +1,12 @@
1
+ # -*- coding: utf-8 -*-
2
+ module CallerInfo
3
+ #
4
+ # return stack trace info if defined?($debug).
5
+ #
6
+ def caller_info
7
+ caller(3).collect { |info|
8
+ file = File.expand_path(info.sub(/:(\d+)[^\d`]*(`([^']+)')?/, ''))
9
+ { :file => file, :line => $1, :method => $3 }
10
+ }.select { |info| info[:method] } # delete if info[:method] == nil
11
+ end
12
+ end
@@ -0,0 +1,332 @@
1
+ module Writeexcel
2
+
3
+ class Worksheet < BIFFWriter
4
+ class CellRange
5
+ attr_accessor :row_min, :row_max, :col_min, :col_max
6
+
7
+ def initialize(worksheet)
8
+ @worksheet = worksheet
9
+ end
10
+
11
+ def increment_row_max
12
+ @row_max += 1 if @row_max
13
+ end
14
+
15
+ def increment_col_max
16
+ @col_max += 1 if @col_max
17
+ end
18
+
19
+ def row(val)
20
+ @row_min = val if !@row_min || (val < row_min)
21
+ @row_max = val if !@row_max || (val > row_max)
22
+ end
23
+
24
+ def col(val)
25
+ @col_min = val if !@col_min || (val < col_min)
26
+ @col_max = val if !@col_max || (val > col_max)
27
+ end
28
+
29
+ #
30
+ # assemble the NAME record in the long format that is used for storing the repeat
31
+ # rows and columns when both are specified. This share a lot of code with
32
+ # name_record_short() but we use a separate method to keep the code clean.
33
+ # Code abstraction for reuse can be carried too far, and I should know. ;-)
34
+ #
35
+ # type
36
+ # ext_ref # TODO
37
+ #
38
+ def name_record_long(type, ext_ref) #:nodoc:
39
+ record = 0x0018 # Record identifier
40
+ length = 0x002a # Number of bytes to follow
41
+
42
+ grbit = 0x0020 # Option flags
43
+ chkey = 0x00 # Keyboard shortcut
44
+ cch = 0x01 # Length of text name
45
+ cce = 0x001a # Length of text definition
46
+ unknown01 = 0x0000 #
47
+ ixals = @worksheet.index + 1 # Sheet index
48
+ unknown02 = 0x00 #
49
+ cch_cust_menu = 0x00 # Length of cust menu text
50
+ cch_description = 0x00 # Length of description text
51
+ cch_helptopic = 0x00 # Length of help topic text
52
+ cch_statustext = 0x00 # Length of status bar text
53
+ rgch = type # Built-in name type
54
+
55
+ unknown03 = 0x29
56
+ unknown04 = 0x0017
57
+ unknown05 = 0x3b
58
+
59
+ header = [record, length].pack("vv")
60
+ data = [grbit].pack("v")
61
+ data += [chkey].pack("C")
62
+ data += [cch].pack("C")
63
+ data += [cce].pack("v")
64
+ data += [unknown01].pack("v")
65
+ data += [ixals].pack("v")
66
+ data += [unknown02].pack("C")
67
+ data += [cch_cust_menu].pack("C")
68
+ data += [cch_description].pack("C")
69
+ data += [cch_helptopic].pack("C")
70
+ data += [cch_statustext].pack("C")
71
+ data += [rgch].pack("C")
72
+
73
+ # Column definition
74
+ data += [unknown03].pack("C")
75
+ data += [unknown04].pack("v")
76
+ data += [unknown05].pack("C")
77
+ data += [ext_ref].pack("v")
78
+ data += [0x0000].pack("v")
79
+ data += [0xffff].pack("v")
80
+ data += [@col_min].pack("v")
81
+ data += [@col_max].pack("v")
82
+
83
+ # Row definition
84
+ data += [unknown05].pack("C")
85
+ data += [ext_ref].pack("v")
86
+ data += [@row_min].pack("v")
87
+ data += [@row_max].pack("v")
88
+ data += [0x00].pack("v")
89
+ data += [0xff].pack("v")
90
+ # End of data
91
+ data += [0x10].pack("C")
92
+
93
+ [header, data]
94
+ end
95
+
96
+ #
97
+ # assemble the NAME record in the short format that is used for storing the print
98
+ # area, repeat rows only and repeat columns only.
99
+ #
100
+ # type
101
+ # ext_ref # TODO
102
+ # hidden # Name is hidden
103
+ #
104
+ def name_record_short(type, ext_ref, hidden = nil) #:nodoc:
105
+ record = 0x0018 # Record identifier
106
+ length = 0x001b # Number of bytes to follow
107
+
108
+ grbit = 0x0020 # Option flags
109
+ chkey = 0x00 # Keyboard shortcut
110
+ cch = 0x01 # Length of text name
111
+ cce = 0x000b # Length of text definition
112
+ unknown01 = 0x0000 #
113
+ ixals = @worksheet.index + 1 # Sheet index
114
+ unknown02 = 0x00 #
115
+ cch_cust_menu = 0x00 # Length of cust menu text
116
+ cch_description = 0x00 # Length of description text
117
+ cch_helptopic = 0x00 # Length of help topic text
118
+ cch_statustext = 0x00 # Length of status bar text
119
+ rgch = type # Built-in name type
120
+ unknown03 = 0x3b #
121
+
122
+ grbit = 0x0021 if hidden
123
+
124
+ rowmin = row_min
125
+ rowmax = row_max
126
+ rowmin, rowmax = 0x0000, 0xffff unless row_min
127
+
128
+ colmin = col_min
129
+ colmax = col_max
130
+ colmin, colmax = 0x00, 0xff unless col_min
131
+
132
+ header = [record, length].pack("vv")
133
+ data = [grbit].pack("v")
134
+ data += [chkey].pack("C")
135
+ data += [cch].pack("C")
136
+ data += [cce].pack("v")
137
+ data += [unknown01].pack("v")
138
+ data += [ixals].pack("v")
139
+ data += [unknown02].pack("C")
140
+ data += [cch_cust_menu].pack("C")
141
+ data += [cch_description].pack("C")
142
+ data += [cch_helptopic].pack("C")
143
+ data += [cch_statustext].pack("C")
144
+ data += [rgch].pack("C")
145
+ data += [unknown03].pack("C")
146
+ data += [ext_ref].pack("v")
147
+
148
+ data += [rowmin].pack("v")
149
+ data += [rowmax].pack("v")
150
+ data += [colmin].pack("v")
151
+ data += [colmax].pack("v")
152
+
153
+ [header, data]
154
+ end
155
+ end
156
+
157
+ class CellDimension < CellRange
158
+ def row_min
159
+ @row_min || 0
160
+ end
161
+
162
+ def col_min
163
+ @col_min || 0
164
+ end
165
+
166
+ def row_max
167
+ @row_max || 0
168
+ end
169
+
170
+ def col_max
171
+ @col_max || 0
172
+ end
173
+ end
174
+
175
+ class PrintRange < CellRange
176
+ def name_record_short(ext_ref, hidden)
177
+ super(0x06, ext_ref, hidden) # 0x06 NAME type = Print_Area
178
+ end
179
+ end
180
+
181
+ class TitleRange < CellRange
182
+ def name_record_long(ext_ref)
183
+ super(0x07, ext_ref) # 0x07 NAME type = Print_Titles
184
+ end
185
+
186
+ def name_record_short(ext_ref, hidden)
187
+ super(0x07, ext_ref, hidden) # 0x07 NAME type = Print_Titles
188
+ end
189
+ end
190
+
191
+ class FilterRange < CellRange
192
+ def name_record_short(ext_ref, hidden)
193
+ super(0x0D, ext_ref, hidden) # 0x0D NAME type = Filter Database
194
+ end
195
+
196
+ def count
197
+ if @col_min && @col_max
198
+ 1 + @col_max - @col_min
199
+ else
200
+ 0
201
+ end
202
+ end
203
+
204
+ def inside?(col)
205
+ @col_min <= col && col <= @col_max
206
+ end
207
+
208
+ def store
209
+ record = 0x00EC # Record identifier
210
+
211
+ spid = @worksheet.object_ids.spid
212
+
213
+ # Number of objects written so far.
214
+ num_objects = @worksheet.images_size + @worksheet.charts_size
215
+
216
+ (0 .. count-1).each do |i|
217
+ if i == 0 && num_objects
218
+ spid, data = write_parent_msodrawing_record(count, @worksheet.comments_size, spid, vertices(i))
219
+ else
220
+ spid, data = write_child_msodrawing_record(spid, vertices(i))
221
+ end
222
+ length = data.bytesize
223
+ header = [record, length].pack("vv")
224
+ append(header, data)
225
+
226
+ store_obj_filter(num_objects + i + 1, col_min + i)
227
+ end
228
+ spid
229
+ end
230
+
231
+ private
232
+
233
+ def write_parent_msodrawing_record(num_filters, num_comments, spid, vertices)
234
+ # Write the parent MSODRAWIING record.
235
+ dg_length = 168 + 96 * (num_filters - 1)
236
+ spgr_length = 144 + 96 * (num_filters - 1)
237
+
238
+ dg_length += 128 * num_comments
239
+ spgr_length += 128 * num_comments
240
+
241
+ data = store_parent_mso_record(dg_length, spgr_length, spid)
242
+ spid += 1
243
+ data += store_child_mso_record(spid, *vertices)
244
+ spid += 1
245
+ [spid, data]
246
+ end
247
+
248
+ def write_child_msodrawing_record(spid, vertices)
249
+ data = store_child_mso_record(spid, *vertices)
250
+ spid += 1
251
+ [spid, data]
252
+ end
253
+
254
+ def store_parent_mso_record(dg_length, spgr_length, spid)
255
+ @worksheet.__send__("store_parent_mso_record", dg_length, spgr_length, spid)
256
+ end
257
+
258
+ def store_child_mso_record(spid, *vertices)
259
+ @worksheet.__send__("store_child_mso_record", spid, *vertices)
260
+ end
261
+
262
+ def vertices(i)
263
+ [
264
+ col_min + i, 0,
265
+ row_min, 0,
266
+ col_min + i + 1, 0,
267
+ row_min + 1, 0
268
+ ]
269
+ end
270
+
271
+ #
272
+ # Write the OBJ record that is part of filter records.
273
+ # obj_id # Object ID number.
274
+ # col
275
+ #
276
+ def store_obj_filter(obj_id, col) #:nodoc:
277
+ record = 0x005D # Record identifier
278
+ length = 0x0046 # Bytes to follow
279
+
280
+ obj_type = 0x0014 # Object type (combo box).
281
+ data = '' # Record data.
282
+
283
+ sub_record = 0x0000 # Sub-record identifier.
284
+ sub_length = 0x0000 # Length of sub-record.
285
+ sub_data = '' # Data of sub-record.
286
+ options = 0x2101
287
+ reserved = 0x0000
288
+
289
+ # Add ftCmo (common object data) subobject
290
+ sub_record = 0x0015 # ftCmo
291
+ sub_length = 0x0012
292
+ sub_data = [obj_type, obj_id, options, reserved, reserved, reserved].pack('vvvVVV')
293
+ data = [sub_record, sub_length].pack('vv') + sub_data
294
+
295
+ # Add ftSbs Scroll bar subobject
296
+ sub_record = 0x000C # ftSbs
297
+ sub_length = 0x0014
298
+ sub_data = ['0000000000000000640001000A00000010000100'].pack('H*')
299
+ data += [sub_record, sub_length].pack('vv') + sub_data
300
+
301
+ # Add ftLbsData (List box data) subobject
302
+ sub_record = 0x0013 # ftLbsData
303
+ sub_length = 0x1FEE # Special case (undocumented).
304
+
305
+ # If the filter is active we set one of the undocumented flags.
306
+
307
+ if @worksheet.instance_variable_get(:@filter_cols)[col]
308
+ sub_data = ['000000000100010300000A0008005700'].pack('H*')
309
+ else
310
+ sub_data = ['00000000010001030000020008005700'].pack('H*')
311
+ end
312
+
313
+ data += [sub_record, sub_length].pack('vv') + sub_data
314
+
315
+ # Add ftEnd (end of object) subobject
316
+ sub_record = 0x0000 # ftNts
317
+ sub_length = 0x0000
318
+ data += [sub_record, sub_length].pack('vv')
319
+
320
+ # Pack the record.
321
+ header = [record, length].pack('vv')
322
+
323
+ append(header, data)
324
+ end
325
+
326
+ def append(*args)
327
+ @worksheet.append(*args)
328
+ end
329
+ end
330
+ end
331
+
332
+ end