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,213 @@
1
+ # -*- coding: utf-8 -*-
2
+ ###############################################################################
3
+ #
4
+ # Stock - A writer class for Excel Stock charts.
5
+ #
6
+ # Used in conjunction with WriteExcel::Chart.
7
+ #
8
+ # See formatting note in WriteExcel::Chart.
9
+ #
10
+ # Copyright 2000-2010, John McNamara, jmcnamara@cpan.org
11
+ #
12
+ # original written in Perl by John McNamara
13
+ # converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
14
+ #
15
+
16
+ require 'writeexcel'
17
+
18
+ module Writeexcel
19
+
20
+ class Chart
21
+
22
+ # ==SYNOPSIS
23
+ #
24
+ # To create a simple Excel file with a Stock chart using WriteExcel:
25
+ #
26
+ # #!/usr/bin/ruby -w
27
+ #
28
+ # require 'writeexcel'
29
+ #
30
+ # workbook = WriteExcel.new('chart.xls')
31
+ # worksheet = workbook.add_worksheet
32
+ #
33
+ # chart = workbook.add_chart(:type => 'Chart::Stock')
34
+ #
35
+ # # Add a series for each Open-High-Low-Close.
36
+ # chart.add_series(:categories => '=Sheet1!$A$2:$A$6', :values => '=Sheet1!$B$2:$B$6')
37
+ # chart.add_series(:categories => '=Sheet1!$A$2:$A$6', :values => '=Sheet1!$C$2:$C$6')
38
+ # chart.add_series(:categories => '=Sheet1!$A$2:$A$6', :values => '=Sheet1!$D$2:$D$6')
39
+ # chart.add_series(:categories => '=Sheet1!$A$2:$A$6', :values => '=Sheet1!$E$2:$E$6')
40
+ #
41
+ # # Add the worksheet data the chart refers to.
42
+ # # ... See the full example below.
43
+ #
44
+ # workbook.close
45
+ #
46
+ # ==DESCRIPTION
47
+ #
48
+ # This module implements Stock charts for WriteExcel. The chart object
49
+ # is created via the Workbook add_chart() method:
50
+ #
51
+ # chart = workbook.add_chart(:type => 'Chart::Stock')
52
+ #
53
+ # Once the object is created it can be configured via the following methods
54
+ # that are common to all chart classes:
55
+ #
56
+ # chart.add_series
57
+ # chart.set_x_axis
58
+ # chart.set_y_axis
59
+ # chart.set_title
60
+ #
61
+ # These methods are explained in detail in Chart section of WriteExcel.
62
+ # Class specific methods or settings, if any, are explained below.
63
+ #
64
+ # ==Stock Chart Methods
65
+ #
66
+ # There aren't currently any stock chart specific methods.
67
+ # See the TODO section of Chart section in WriteExcel.
68
+ #
69
+ # The default Stock chart is an Open-High-Low-Close chart.
70
+ # A series must be added for each of these data sources.
71
+ #
72
+ # The default Stock chart is in black and white. User defined colours
73
+ # will be added at a later stage.
74
+ #
75
+ # ==EXAMPLE
76
+ #
77
+ # Here is a complete example that demonstrates most of the available features
78
+ # when creating a Stock chart.
79
+ #
80
+ # #!/usr/bin/ruby -w
81
+ #
82
+ # require 'writeexcel'
83
+ #
84
+ # workbook = WriteExcel.new('chart_stock_ex.xls')
85
+ # worksheet = workbook.add_worksheet
86
+ # bold = workbook.add_format(:bold => 1)
87
+ # date_format = workbook.add_format(:num_format => 'dd/mm/yyyy')
88
+ #
89
+ # # Add the worksheet data that the charts will refer to.
90
+ # headings = [ 'Date', 'Open', 'High', 'Low', 'Close' ]
91
+ # data = [
92
+ # [ '2009-08-23', 110.75, 113.48, 109.05, 109.40 ],
93
+ # [ '2009-08-24', 111.24, 111.60, 103.57, 104.87 ],
94
+ # [ '2009-08-25', 104.96, 108.00, 103.88, 106.00 ],
95
+ # [ '2009-08-26', 104.95, 107.95, 104.66, 107.91 ],
96
+ # [ '2009-08-27', 108.10, 108.62, 105.69, 106.15 ]
97
+ # ]
98
+ #
99
+ # worksheet.write('A1', headings, bold)
100
+ #
101
+ # row = 1
102
+ # data.each do |d|
103
+ # worksheet.write(row, 0, d[0], date_format)
104
+ # worksheet.write(row, 1, d[1])
105
+ # worksheet.write(row, 2, d[2])
106
+ # worksheet.write(row, 3, d[3])
107
+ # worksheet.write(row, 4, d[4])
108
+ # row += 1
109
+ # end
110
+ #
111
+ # # Create a new chart object. In this case an embedded chart.
112
+ # chart = workbook.add_chart(:type => 'Chart::Stock', ::embedded => 1)
113
+ #
114
+ # # Add a series for each of the Open-High-Low-Close columns.
115
+ # chart.add_series(
116
+ # :categories => '=Sheet1!$A$2:$A$6',
117
+ # :values => '=Sheet1!$B$2:$B$6',
118
+ # :name => 'Open'
119
+ # )
120
+ #
121
+ # chart.add_series(
122
+ # :categories => '=Sheet1!$A$2:$A$6',
123
+ # :values => '=Sheet1!$C$2:$C$6',
124
+ # :name => 'High'
125
+ # )
126
+ #
127
+ # chart.add_series(
128
+ # :categories => '=Sheet1!$A$2:$A$6',
129
+ # :values => '=Sheet1!$D$2:$D$6',
130
+ # :name => 'Low'
131
+ # )
132
+ #
133
+ # chart.add_series(
134
+ # :categories => '=Sheet1!$A$2:$A$6',
135
+ # :values => '=Sheet1!$E$2:$E$6',
136
+ # :name => 'Close'
137
+ # )
138
+ #
139
+ # # Add a chart title and some axis labels.
140
+ # chart.set_title(:name => 'Open-High-Low-Close')
141
+ # chart.set_x_axis(:name => 'Date')
142
+ # chart.set_y_axis(:name => 'Share price')
143
+ #
144
+ # # Insert the chart into the worksheet (with an offset).
145
+ # worksheet.insert_chart('F2', chart, 25, 10)
146
+ #
147
+ # workbook.close
148
+ #
149
+ class Stock < Chart
150
+ ###############################################################################
151
+ #
152
+ # new()
153
+ #
154
+ #
155
+ def initialize(*args) # :nodoc:
156
+ super
157
+ end
158
+
159
+ ###############################################################################
160
+ #
161
+ # _store_chart_type()
162
+ #
163
+ # Implementation of the abstract method from the specific chart class.
164
+ #
165
+ # Write the LINE chart BIFF record. A stock chart uses the same LINE record
166
+ # as a line chart but with additional DROPBAR and CHARTLINE records to define
167
+ # the stock style.
168
+ #
169
+ def store_chart_type # :nodoc:
170
+ record = 0x1018 # Record identifier.
171
+ length = 0x0002 # Number of bytes to follow.
172
+ grbit = 0x0000 # Option flags.
173
+
174
+ store_simple(record, length, grbit)
175
+ end
176
+
177
+ ###############################################################################
178
+ #
179
+ # _store_marker_dataformat_stream(). Overridden.
180
+ #
181
+ # This is an implementation of the parent abstract method to define
182
+ # properties of markers, linetypes, pie formats and other.
183
+ #
184
+ def store_marker_dataformat_stream # :nodoc:
185
+ store_dropbar
186
+ store_begin
187
+ store_lineformat(0x00000000, 0x0000, 0xFFFF, 0x0001, 0x004F)
188
+ store_areaformat(0x00FFFFFF, 0x0000, 0x01, 0x01, 0x09, 0x08)
189
+ store_end
190
+
191
+ store_dropbar
192
+ store_begin
193
+ store_lineformat(0x00000000, 0x0000, 0xFFFF, 0x0001, 0x004F)
194
+ store_areaformat(0x0000, 0x00FFFFFF, 0x01, 0x01, 0x08, 0x09)
195
+ store_end
196
+
197
+ store_chartline
198
+ store_lineformat(0x00000000, 0x0000, 0xFFFF, 0x0000, 0x004F)
199
+
200
+
201
+ store_dataformat(0x0000, 0xFFFD, 0x0000)
202
+ store_begin
203
+ store_3dbarshape
204
+ store_lineformat(0x00000000, 0x0005, 0xFFFF, 0x0000, 0x004F)
205
+ store_areaformat(0x00000000, 0x0000, 0x00, 0x01, 0x4D, 0x4D)
206
+ store_pieformat
207
+ store_markerformat(0x00, 0x00, 0x00, 0x00, 0x4D, 0x4D, 0x3C)
208
+ store_end
209
+ end
210
+ end
211
+ end # class Chart
212
+
213
+ end # module Writeexcel
@@ -0,0 +1,87 @@
1
+ module Writeexcel
2
+
3
+ class Worksheet < BIFFWriter
4
+ require 'writeexcel/helper'
5
+
6
+ class ColInfo
7
+ attr_reader :level
8
+
9
+ #
10
+ # new(firstcol, lastcol, width, [format, hidden, level, collapsed])
11
+ #
12
+ # firstcol : First formatted column
13
+ # lastcol : Last formatted column
14
+ # width : Col width in user units, 8.43 is default
15
+ # format : format object
16
+ # hidden : hidden flag
17
+ # level : outline level
18
+ # collapsed : ?
19
+ #
20
+ def initialize(*args)
21
+ @firstcol, @lastcol, @width, @format, @hidden, @level, @collapsed = args
22
+ @width ||= 8.43 # default width
23
+ @level ||= 0 # default level
24
+ end
25
+
26
+ # Write BIFF record COLINFO to define column widths
27
+ #
28
+ # Note: The SDK says the record length is 0x0B but Excel writes a 0x0C
29
+ # length record.
30
+ #
31
+ def biff_record
32
+ record = 0x007D # Record identifier
33
+ length = 0x000B # Number of bytes to follow
34
+
35
+ coldx = (pixels * 256 / 7).to_i # Col width in internal units
36
+ reserved = 0x00 # Reserved
37
+
38
+ header = [record, length].pack("vv")
39
+ data = [@firstcol, @lastcol, coldx,
40
+ ixfe, grbit, reserved].pack("vvvvvC")
41
+ [header, data]
42
+ end
43
+
44
+ # Excel rounds the column width to the nearest pixel. Therefore we first
45
+ # convert to pixels and then to the internal units. The pixel to users-units
46
+ # relationship is different for values less than 1.
47
+ #
48
+ def pixels
49
+ if @width < 1
50
+ result = @width * 12
51
+ else
52
+ result = @width * 7 + 5
53
+ end
54
+ result.to_i
55
+ end
56
+
57
+ def ixfe
58
+ if @format && @format.respond_to?(:xf_index)
59
+ ixfe = @format.xf_index
60
+ else
61
+ ixfe = 0x0F
62
+ end
63
+ end
64
+
65
+ # Set the limits for the outline levels (0 <= x <= 7).
66
+ def level
67
+ if @level < 0
68
+ 0
69
+ elsif 7 < @level
70
+ 7
71
+ else
72
+ @level
73
+ end
74
+ end
75
+
76
+ # Set the options flags. (See set_row() for more details).
77
+ def grbit
78
+ grbit = 0x0000 # Option flags
79
+ grbit |= 0x0001 if @hidden && @hidden != 0
80
+ grbit |= level << 8
81
+ grbit |= 0x1000 if @collapsed && @collapsed != 0
82
+ grbit
83
+ end
84
+ end
85
+ end
86
+
87
+ end
@@ -0,0 +1,68 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Writeexcel
4
+
5
+ class Colors
6
+ COLORS = {
7
+ :aqua => 0x0F,
8
+ :cyan => 0x0F,
9
+ :black => 0x08,
10
+ :blue => 0x0C,
11
+ :brown => 0x10,
12
+ :magenta => 0x0E,
13
+ :fuchsia => 0x0E,
14
+ :gray => 0x17,
15
+ :grey => 0x17,
16
+ :green => 0x11,
17
+ :lime => 0x0B,
18
+ :navy => 0x12,
19
+ :orange => 0x35,
20
+ :pink => 0x21,
21
+ :purple => 0x14,
22
+ :red => 0x0A,
23
+ :silver => 0x16,
24
+ :white => 0x09,
25
+ :yellow => 0x0D,
26
+ } # :nodoc:
27
+
28
+ ###############################################################################
29
+ #
30
+ # get_color(colour)
31
+ #
32
+ # Used in conjunction with the set_xxx_color methods to convert a color
33
+ # string into a number. Color range is 0..63 but we will restrict it
34
+ # to 8..63 to comply with Gnumeric. Colors 0..7 are repeated in 8..15.
35
+ #
36
+ def get_color(color = nil) # :nodoc:
37
+ if color.respond_to?(:to_int) && color.respond_to?(:+)
38
+ # the default color if arg is outside range,
39
+ if color < 0 || 63 < color
40
+ 0x7FFF
41
+ # or an index < 8 mapped into the correct range,
42
+ elsif color < 8
43
+ (color + 8).to_i
44
+ # or an integer in the valid range
45
+ else
46
+ color.to_i
47
+ end
48
+ elsif color.respond_to?(:to_sym)
49
+ color = color.downcase.to_sym if color.respond_to?(:to_str)
50
+ # or the color string converted to an integer,
51
+ if COLORS.has_key?(color)
52
+ COLORS[color]
53
+ # or the default color if string is unrecognised,
54
+ else
55
+ 0x7FFF
56
+ end
57
+ else
58
+ 0x7FFF
59
+ end
60
+ end
61
+
62
+ def inspect
63
+ to_s
64
+ end
65
+ end # class Colors
66
+
67
+ end # module Writeexcel
68
+
@@ -0,0 +1,460 @@
1
+ module Writeexcel
2
+
3
+ class Worksheet < BIFFWriter
4
+ require 'writeexcel/helper'
5
+
6
+ class Collection
7
+ def initialize
8
+ @items = {}
9
+ end
10
+
11
+ def <<(item)
12
+ if @items[item.row]
13
+ @items[item.row][item.col] = item
14
+ else
15
+ @items[item.row] = { item.col => item }
16
+ end
17
+ end
18
+
19
+ def array
20
+ return @array if @array
21
+
22
+ @array = []
23
+ @items.keys.sort.each do |row|
24
+ @items[row].keys.sort.each do |col|
25
+ @array << @items[row][col]
26
+ end
27
+ end
28
+ @array
29
+ end
30
+
31
+ end
32
+
33
+ class Comments < Collection
34
+ attr_writer :visible
35
+
36
+ def initialize
37
+ super
38
+ @visible = false
39
+ end
40
+
41
+ def visible?
42
+ @visible
43
+ end
44
+ end
45
+
46
+ class Comment
47
+ attr_reader :row, :col, :string, :encoding, :author, :author_encoding, :visible, :color, :vertices
48
+
49
+ def initialize(worksheet, row, col, string, options = {})
50
+ @worksheet = worksheet
51
+ @row, @col = row, col
52
+ @params = params_with(options)
53
+ @string, @params[:encoding] = string_and_encoding(string, @params[:encoding], 'comment')
54
+
55
+ # Limit the string to the max number of chars (not bytes).
56
+ max_len = 32767
57
+ max_len = max_len * 2 if @params[:encoding] != 0
58
+
59
+ if @string.bytesize > max_len
60
+ @string = @string[0 .. max_len]
61
+ end
62
+ @encoding = @params[:encoding]
63
+ @author = @params[:author]
64
+ @author_encoding = @params[:author_encoding]
65
+ @visible = @params[:visible]
66
+ @color = @params[:color]
67
+ @vertices = calc_vertices
68
+ end
69
+
70
+ def store_comment_record(i, num_objects, num_comments, spid)
71
+ str_len = string.bytesize
72
+ str_len = str_len / 2 if encoding != 0 # Num of chars not bytes.
73
+
74
+ spid = store_comment_mso_drawing_record(i, num_objects, num_comments, spid, visible, color, vertices)
75
+ store_obj_comment(num_objects + i + 1)
76
+ store_mso_drawing_text_box
77
+ store_txo(str_len)
78
+ store_txo_continue_1(string, encoding)
79
+ formats = [[0, 9], [str_len, 0]]
80
+ store_txo_continue_2(formats)
81
+ spid
82
+ end
83
+
84
+ #
85
+ # Write the worksheet NOTE record that is part of cell comments.
86
+ #
87
+ def store_note_record(obj_id) #:nodoc:
88
+ comment_author = author
89
+ comment_author_enc = author_encoding
90
+ ruby_19 { comment_author = [comment_author].pack('a*') if comment_author.ascii_only? }
91
+ record = 0x001C # Record identifier
92
+ length = 0x000C # Bytes to follow
93
+
94
+ comment_author = '' unless comment_author
95
+ comment_author_enc = 0 unless author_encoding
96
+
97
+ # Use the visible flag if set by the user or else use the worksheet value.
98
+ # The flag is also set in store_mso_opt_comment() but with the opposite
99
+ # value.
100
+ if visible
101
+ comment_visible = visible != 0 ? 0x0002 : 0x0000
102
+ else
103
+ comment_visible = @worksheet.comments_visible? ? 0x0002 : 0x0000
104
+ end
105
+
106
+ # Get the number of chars in the author string (not bytes).
107
+ num_chars = comment_author.bytesize
108
+ num_chars = num_chars / 2 if comment_author_enc != 0 && comment_author_enc
109
+
110
+ # Null terminate the author string.
111
+ comment_author =
112
+ ruby_18 { comment_author + "\0" } ||
113
+ ruby_19 { comment_author.force_encoding('BINARY') + "\0".force_encoding('BINARY') }
114
+
115
+ # Pack the record.
116
+ data = [@row, @col, comment_visible, obj_id, num_chars, comment_author_enc].pack("vvvvvC")
117
+
118
+ length = data.bytesize + comment_author.bytesize
119
+ header = [record, length].pack("vv")
120
+
121
+ append(header, data, comment_author)
122
+ end
123
+
124
+ #
125
+ # Write the Escher Opt record that is part of MSODRAWING.
126
+ #
127
+ def store_mso_opt_comment(spid, visible = nil, colour = 0x50) #:nodoc:
128
+ type = 0xF00B
129
+ version = 3
130
+ instance = 9
131
+ data = ''
132
+ length = 54
133
+
134
+ # Use the visible flag if set by the user or else use the worksheet value.
135
+ # Note that the value used is the opposite of Comment#note_record.
136
+ #
137
+ if visible
138
+ visible = visible != 0 ? 0x0000 : 0x0002
139
+ else
140
+ visible = @worksheet.comments_visible? ? 0x0000 : 0x0002
141
+ end
142
+
143
+ data = [spid].pack('V') +
144
+ ['0000BF00080008005801000000008101'].pack("H*") +
145
+ [colour].pack("C") +
146
+ ['000008830150000008BF011000110001'+'02000000003F0203000300BF03'].pack("H*") +
147
+ [visible].pack('v') +
148
+ ['0A00'].pack('H*')
149
+
150
+ @worksheet.add_mso_generic(type, version, instance, data, length)
151
+ end
152
+
153
+ #
154
+ # OBJ record that is part of cell comments.
155
+ # obj_id # Object ID number.
156
+ #
157
+ def obj_comment_record(obj_id) #:nodoc:
158
+ record = 0x005D # Record identifier
159
+ length = 0x0034 # Bytes to follow
160
+
161
+ obj_type = 0x0019 # Object type (comment).
162
+ data = '' # Record data.
163
+
164
+ sub_record = 0x0000 # Sub-record identifier.
165
+ sub_length = 0x0000 # Length of sub-record.
166
+ sub_data = '' # Data of sub-record.
167
+ options = 0x4011
168
+ reserved = 0x0000
169
+
170
+ # Add ftCmo (common object data) subobject
171
+ sub_record = 0x0015 # ftCmo
172
+ sub_length = 0x0012
173
+ sub_data = [obj_type, obj_id, options, reserved, reserved, reserved].pack( "vvvVVV")
174
+ data = [sub_record, sub_length].pack("vv") + sub_data
175
+
176
+ # Add ftNts (note structure) subobject
177
+ sub_record = 0x000D # ftNts
178
+ sub_length = 0x0016
179
+ sub_data = [reserved,reserved,reserved,reserved,reserved,reserved].pack( "VVVVVv")
180
+ data += [sub_record, sub_length].pack("vv") + sub_data
181
+
182
+ # Add ftEnd (end of object) subobject
183
+ sub_record = 0x0000 # ftNts
184
+ sub_length = 0x0000
185
+ data += [sub_record, sub_length].pack("vv")
186
+
187
+ # Pack the record.
188
+ header = [record, length].pack("vv")
189
+
190
+ header + data
191
+ end
192
+
193
+ private
194
+
195
+ def params_with(options)
196
+ params = default_params.update(options)
197
+
198
+ # Ensure that a width and height have been set.
199
+ params[:width] = default_width unless params[:width] && params[:width] != 0
200
+ params[:width] = params[:width] * params[:x_scale] if params[:x_scale] != 0
201
+ params[:height] = default_height unless params[:height] && params[:height] != 0
202
+ params[:height] = params[:height] * params[:y_scale] if params[:y_scale] != 0
203
+
204
+ params[:author], params[:author_encoding] =
205
+ string_and_encoding(params[:author], params[:author_encoding], 'author')
206
+
207
+ # Set the comment background colour.
208
+ params[:color] = background_color(params[:color])
209
+
210
+ # Set the default start cell and offsets for the comment. These are
211
+ # generally fixed in relation to the parent cell. However there are
212
+ # some edge cases for cells at the, er, edges.
213
+ #
214
+ params[:start_row] = default_start_row unless params[:start_row]
215
+ params[:y_offset] = default_y_offset unless params[:y_offset]
216
+ params[:start_col] = default_start_col unless params[:start_col]
217
+ params[:x_offset] = default_x_offset unless params[:x_offset]
218
+
219
+ params
220
+ end
221
+
222
+ def default_params
223
+ {
224
+ :author => '',
225
+ :author_encoding => 0,
226
+ :encoding => 0,
227
+ :color => nil,
228
+ :start_cell => nil,
229
+ :start_col => nil,
230
+ :start_row => nil,
231
+ :visible => nil,
232
+ :width => default_width,
233
+ :height => default_height,
234
+ :x_offset => nil,
235
+ :x_scale => 1,
236
+ :y_offset => nil,
237
+ :y_scale => 1
238
+ }
239
+ end
240
+
241
+ def default_width
242
+ 128
243
+ end
244
+
245
+ def default_height
246
+ 74
247
+ end
248
+
249
+ def default_start_row
250
+ case @row
251
+ when 0 then 0
252
+ when 65533 then 65529
253
+ when 65534 then 65530
254
+ when 65535 then 65531
255
+ else @row -1
256
+ end
257
+ end
258
+
259
+ def default_y_offset
260
+ case @row
261
+ when 0 then 2
262
+ when 65533 then 4
263
+ when 65534 then 4
264
+ when 65535 then 2
265
+ else 7
266
+ end
267
+ end
268
+
269
+ def default_start_col
270
+ case @col
271
+ when 253 then 250
272
+ when 254 then 251
273
+ when 255 then 252
274
+ else @col + 1
275
+ end
276
+ end
277
+
278
+ def default_x_offset
279
+ case @col
280
+ when 253 then 49
281
+ when 254 then 49
282
+ when 255 then 49
283
+ else 15
284
+ end
285
+ end
286
+
287
+ def string_and_encoding(string, encoding, type)
288
+ string = convert_to_ascii_if_ascii(string)
289
+ if encoding != 0
290
+ raise "Uneven number of bytes in #{type} string" if string.bytesize % 2 != 0
291
+ # Change from UTF-16BE to UTF-16LE
292
+ string = utf16be_to_16le(string)
293
+ # Handle utf8 strings
294
+ else
295
+ if is_utf8?(string)
296
+ string = NKF.nkf('-w16L0 -m0 -W', string)
297
+ ruby_19 { string.force_encoding('UTF-16LE') }
298
+ encoding = 1
299
+ end
300
+ end
301
+ [string, encoding]
302
+ end
303
+
304
+ def background_color(color)
305
+ color = Colors.new.get_color(color)
306
+ color = 0x50 if color == 0x7FFF # Default color.
307
+ color
308
+ end
309
+
310
+ # Calculate the positions of comment object.
311
+ def calc_vertices
312
+ @worksheet.position_object( @params[:start_col],
313
+ @params[:start_row],
314
+ @params[:x_offset],
315
+ @params[:y_offset],
316
+ @params[:width],
317
+ @params[:height]
318
+ )
319
+ end
320
+
321
+ def store_comment_mso_drawing_record(i, num_objects, num_comments, spid, visible, color, vertices)
322
+ if i == 0 && num_objects == 0
323
+ # Write the parent MSODRAWIING record.
324
+ dg_length = 200 + 128 * (num_comments - 1)
325
+ spgr_length = 176 + 128 * (num_comments - 1)
326
+
327
+ data = @worksheet.store_parent_mso_record(dg_length, spgr_length, spid)
328
+ spid += 1
329
+ else
330
+ data = ''
331
+ end
332
+ data += @worksheet.store_mso_sp_container(120) + @worksheet.store_mso_sp(202, spid, 0x0A00)
333
+ spid += 1
334
+ data +=
335
+ store_mso_opt_comment(0x80, visible, color) +
336
+ @worksheet.store_mso_client_anchor(3, *vertices) +
337
+ @worksheet.store_mso_client_data
338
+ record = 0x00EC # Record identifier
339
+ length = data.bytesize
340
+ header = [record, length].pack("vv")
341
+ append(header, data)
342
+
343
+ spid
344
+ end
345
+
346
+ def store_obj_comment(obj_id)
347
+ append(obj_comment_record(obj_id))
348
+ end
349
+
350
+ #
351
+ # Write the MSODRAWING ClientTextbox record that is part of comments.
352
+ #
353
+ def store_mso_drawing_text_box #:nodoc:
354
+ record = 0x00EC # Record identifier
355
+ length = 0x0008 # Bytes to follow
356
+
357
+ data = store_mso_client_text_box
358
+ header = [record, length].pack('vv')
359
+
360
+ append(header, data)
361
+ end
362
+
363
+ #
364
+ # Write the Escher ClientTextbox record that is part of MSODRAWING.
365
+ #
366
+ def store_mso_client_text_box #:nodoc:
367
+ type = 0xF00D
368
+ version = 0
369
+ instance = 0
370
+ data = ''
371
+ length = 0
372
+
373
+ @worksheet.add_mso_generic(type, version, instance, data, length)
374
+ end
375
+
376
+ #
377
+ # Write the worksheet TXO record that is part of cell comments.
378
+ # string_len # Length of the note text.
379
+ # format_len # Length of the format runs.
380
+ # rotation # Options
381
+ #
382
+ def store_txo(string_len, format_len = 16, rotation = 0) #:nodoc:
383
+ record = 0x01B6 # Record identifier
384
+ length = 0x0012 # Bytes to follow
385
+
386
+ grbit = 0x0212 # Options
387
+ reserved = 0x0000 # Options
388
+
389
+ # Pack the record.
390
+ header = [record, length].pack('vv')
391
+ data = [grbit, rotation, reserved, reserved, string_len, format_len, reserved].pack("vvVvvvV")
392
+ append(header, data)
393
+ end
394
+
395
+ #
396
+ # Write the first CONTINUE record to follow the TXO record. It contains the
397
+ # text data.
398
+ # string # Comment string.
399
+ # encoding # Encoding of the string.
400
+ #
401
+ def store_txo_continue_1(string, encoding = 0) #:nodoc:
402
+ # Split long comment strings into smaller continue blocks if necessary.
403
+ # We can't let BIFFwriter::_add_continue() handled this since an extra
404
+ # encoding byte has to be added similar to the SST block.
405
+ #
406
+ # We make the limit size smaller than the add_continue() size and even
407
+ # so that UTF16 chars occur in the same block.
408
+ #
409
+ limit = 8218
410
+ while string.bytesize > limit
411
+ string[0 .. limit] = ""
412
+ tmp_str = string
413
+ data = [encoding].pack("C") +
414
+ ruby_18 { tmp_str } ||
415
+ ruby_19 { tmp_str.force_encoding('ASCII-8BIT') }
416
+ length = data.bytesize
417
+ header = [record, length].pack('vv')
418
+
419
+ append(header, data)
420
+ end
421
+
422
+ # Pack the record.
423
+ data =
424
+ ruby_18 { [encoding].pack("C") + string } ||
425
+ ruby_19 { [encoding].pack("C") + string.force_encoding('ASCII-8BIT') }
426
+
427
+ record = 0x003C # Record identifier
428
+ length = data.bytesize
429
+ header = [record, length].pack('vv')
430
+
431
+ append(header, data)
432
+ end
433
+
434
+ #
435
+ # Write the second CONTINUE record to follow the TXO record. It contains the
436
+ # formatting information for the string.
437
+ # formats # Formatting information
438
+ #
439
+ def store_txo_continue_2(formats) #:nodoc:
440
+ # Pack the record.
441
+ data = ''
442
+
443
+ formats.each do |a_ref|
444
+ data += [a_ref[0], a_ref[1], 0x0].pack('vvV')
445
+ end
446
+
447
+ record = 0x003C # Record identifier
448
+ length = data.bytesize
449
+ header = [record, length].pack("vv")
450
+
451
+ append(header, data)
452
+ end
453
+
454
+ def append(*args)
455
+ @worksheet.append(*args)
456
+ end
457
+ end
458
+ end
459
+
460
+ end