ricardoo27-writeexcel 0.6.12.1

Sign up to get free protection for your applications and to get access to all the features.
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