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.
- data/.document +5 -0
- data/.gitattributes +1 -0
- data/README.rdoc +136 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/charts/chartex.rb +316 -0
- data/charts/demo1.rb +46 -0
- data/charts/demo101.bin +0 -0
- data/charts/demo2.rb +65 -0
- data/charts/demo201.bin +0 -0
- data/charts/demo3.rb +117 -0
- data/charts/demo301.bin +0 -0
- data/charts/demo4.rb +119 -0
- data/charts/demo401.bin +0 -0
- data/charts/demo5.rb +48 -0
- data/charts/demo501.bin +0 -0
- data/examples/a_simple.rb +43 -0
- data/examples/autofilter.rb +265 -0
- data/examples/bigfile.rb +30 -0
- data/examples/chart_area.rb +121 -0
- data/examples/chart_bar.rb +120 -0
- data/examples/chart_column.rb +120 -0
- data/examples/chart_line.rb +120 -0
- data/examples/chart_pie.rb +108 -0
- data/examples/chart_scatter.rb +121 -0
- data/examples/chart_stock.rb +148 -0
- data/examples/chess.rb +142 -0
- data/examples/colors.rb +129 -0
- data/examples/comments1.rb +27 -0
- data/examples/comments2.rb +352 -0
- data/examples/copyformat.rb +52 -0
- data/examples/data_validate.rb +279 -0
- data/examples/date_time.rb +87 -0
- data/examples/defined_name.rb +32 -0
- data/examples/demo.rb +124 -0
- data/examples/diag_border.rb +36 -0
- data/examples/formats.rb +490 -0
- data/examples/formula_result.rb +30 -0
- data/examples/header.rb +137 -0
- data/examples/hide_sheet.rb +29 -0
- data/examples/hyperlink.rb +43 -0
- data/examples/images.rb +63 -0
- data/examples/indent.rb +31 -0
- data/examples/merge1.rb +40 -0
- data/examples/merge2.rb +45 -0
- data/examples/merge3.rb +66 -0
- data/examples/merge4.rb +83 -0
- data/examples/merge5.rb +80 -0
- data/examples/merge6.rb +67 -0
- data/examples/outline.rb +255 -0
- data/examples/outline_collapsed.rb +209 -0
- data/examples/panes.rb +113 -0
- data/examples/password_protection.rb +33 -0
- data/examples/properties.rb +34 -0
- data/examples/properties_jp.rb +33 -0
- data/examples/protection.rb +47 -0
- data/examples/regions.rb +53 -0
- data/examples/repeat.rb +43 -0
- data/examples/republic.png +0 -0
- data/examples/right_to_left.rb +27 -0
- data/examples/row_wrap.rb +53 -0
- data/examples/set_first_sheet.rb +14 -0
- data/examples/stats.rb +74 -0
- data/examples/stocks.rb +81 -0
- data/examples/store_formula.rb +15 -0
- data/examples/tab_colors.rb +31 -0
- data/examples/utf8.rb +15 -0
- data/examples/write_arrays.rb +83 -0
- data/html/en/doc_en.html +5946 -0
- data/html/images/a_simple.jpg +0 -0
- data/html/images/area1.jpg +0 -0
- data/html/images/bar1.jpg +0 -0
- data/html/images/chart_area.xls +0 -0
- data/html/images/column1.jpg +0 -0
- data/html/images/data_validation.jpg +0 -0
- data/html/images/line1.jpg +0 -0
- data/html/images/pie1.jpg +0 -0
- data/html/images/regions.jpg +0 -0
- data/html/images/scatter1.jpg +0 -0
- data/html/images/stats.jpg +0 -0
- data/html/images/stock1.jpg +0 -0
- data/html/images/stocks.jpg +0 -0
- data/html/index.html +16 -0
- data/html/style.css +433 -0
- data/lib/writeexcel.rb +1159 -0
- data/lib/writeexcel/biffwriter.rb +223 -0
- data/lib/writeexcel/caller_info.rb +12 -0
- data/lib/writeexcel/cell_range.rb +332 -0
- data/lib/writeexcel/chart.rb +1968 -0
- data/lib/writeexcel/charts/area.rb +154 -0
- data/lib/writeexcel/charts/bar.rb +177 -0
- data/lib/writeexcel/charts/column.rb +156 -0
- data/lib/writeexcel/charts/external.rb +66 -0
- data/lib/writeexcel/charts/line.rb +154 -0
- data/lib/writeexcel/charts/pie.rb +169 -0
- data/lib/writeexcel/charts/scatter.rb +192 -0
- data/lib/writeexcel/charts/stock.rb +213 -0
- data/lib/writeexcel/col_info.rb +87 -0
- data/lib/writeexcel/colors.rb +68 -0
- data/lib/writeexcel/comments.rb +460 -0
- data/lib/writeexcel/compatibility.rb +65 -0
- data/lib/writeexcel/convert_date_time.rb +117 -0
- data/lib/writeexcel/data_validations.rb +370 -0
- data/lib/writeexcel/debug_info.rb +41 -0
- data/lib/writeexcel/embedded_chart.rb +35 -0
- data/lib/writeexcel/excelformula.y +139 -0
- data/lib/writeexcel/excelformulaparser.rb +587 -0
- data/lib/writeexcel/format.rb +1575 -0
- data/lib/writeexcel/formula.rb +987 -0
- data/lib/writeexcel/helper.rb +78 -0
- data/lib/writeexcel/image.rb +218 -0
- data/lib/writeexcel/olewriter.rb +305 -0
- data/lib/writeexcel/outline.rb +24 -0
- data/lib/writeexcel/properties.rb +242 -0
- data/lib/writeexcel/shared_string_table.rb +153 -0
- data/lib/writeexcel/storage_lite.rb +984 -0
- data/lib/writeexcel/workbook.rb +2478 -0
- data/lib/writeexcel/worksheet.rb +6925 -0
- data/lib/writeexcel/worksheets.rb +25 -0
- data/lib/writeexcel/write_file.rb +63 -0
- data/test/excelfile/Chart1.xls +0 -0
- data/test/excelfile/Chart2.xls +0 -0
- data/test/excelfile/Chart3.xls +0 -0
- data/test/excelfile/Chart4.xls +0 -0
- data/test/excelfile/Chart5.xls +0 -0
- data/test/helper.rb +31 -0
- data/test/perl_output/Chart1.xls.data +0 -0
- data/test/perl_output/Chart2.xls.data +0 -0
- data/test/perl_output/Chart3.xls.data +0 -0
- data/test/perl_output/Chart4.xls.data +0 -0
- data/test/perl_output/Chart5.xls.data +0 -0
- data/test/perl_output/README +31 -0
- data/test/perl_output/a_simple.xls +0 -0
- data/test/perl_output/autofilter.xls +0 -0
- data/test/perl_output/biff_add_continue_testdata +0 -0
- data/test/perl_output/chart_area.xls +0 -0
- data/test/perl_output/chart_bar.xls +0 -0
- data/test/perl_output/chart_column.xls +0 -0
- data/test/perl_output/chart_line.xls +0 -0
- data/test/perl_output/chess.xls +0 -0
- data/test/perl_output/colors.xls +0 -0
- data/test/perl_output/comments0.xls +0 -0
- data/test/perl_output/comments1.xls +0 -0
- data/test/perl_output/comments2.xls +0 -0
- data/test/perl_output/data_validate.xls +0 -0
- data/test/perl_output/date_time.xls +0 -0
- data/test/perl_output/defined_name.xls +0 -0
- data/test/perl_output/demo.xls +0 -0
- data/test/perl_output/demo101.bin +0 -0
- data/test/perl_output/demo201.bin +0 -0
- data/test/perl_output/demo301.bin +0 -0
- data/test/perl_output/demo401.bin +0 -0
- data/test/perl_output/demo501.bin +0 -0
- data/test/perl_output/diag_border.xls +0 -0
- data/test/perl_output/f_font_biff +0 -0
- data/test/perl_output/f_font_key +1 -0
- data/test/perl_output/f_xf_biff +0 -0
- data/test/perl_output/file_font_biff +0 -0
- data/test/perl_output/file_font_key +1 -0
- data/test/perl_output/file_xf_biff +0 -0
- data/test/perl_output/formula_result.xls +0 -0
- data/test/perl_output/headers.xls +0 -0
- data/test/perl_output/hidden.xls +0 -0
- data/test/perl_output/hide_zero.xls +0 -0
- data/test/perl_output/hyperlink.xls +0 -0
- data/test/perl_output/images.xls +0 -0
- data/test/perl_output/indent.xls +0 -0
- data/test/perl_output/merge1.xls +0 -0
- data/test/perl_output/merge2.xls +0 -0
- data/test/perl_output/merge3.xls +0 -0
- data/test/perl_output/merge4.xls +0 -0
- data/test/perl_output/merge5.xls +0 -0
- data/test/perl_output/merge6.xls +0 -0
- data/test/perl_output/ole_write_header +0 -0
- data/test/perl_output/outline.xls +0 -0
- data/test/perl_output/outline_collapsed.xls +0 -0
- data/test/perl_output/panes.xls +0 -0
- data/test/perl_output/password_protection.xls +0 -0
- data/test/perl_output/protection.xls +0 -0
- data/test/perl_output/regions.xls +0 -0
- data/test/perl_output/right_to_left.xls +0 -0
- data/test/perl_output/set_first_sheet.xls +0 -0
- data/test/perl_output/stats.xls +0 -0
- data/test/perl_output/stocks.xls +0 -0
- data/test/perl_output/store_formula.xls +0 -0
- data/test/perl_output/tab_colors.xls +0 -0
- data/test/perl_output/unicode_cyrillic.xls +0 -0
- data/test/perl_output/utf8.xls +0 -0
- data/test/perl_output/workbook1.xls +0 -0
- data/test/perl_output/workbook2.xls +0 -0
- data/test/perl_output/ws_colinfo +1 -0
- data/test/perl_output/ws_store_colinfo +0 -0
- data/test/perl_output/ws_store_dimensions +0 -0
- data/test/perl_output/ws_store_filtermode +0 -0
- data/test/perl_output/ws_store_filtermode_off +0 -0
- data/test/perl_output/ws_store_filtermode_on +0 -0
- data/test/perl_output/ws_store_selection +0 -0
- data/test/perl_output/ws_store_window2 +1 -0
- data/test/republic.png +0 -0
- data/test/test_00_IEEE_double.rb +13 -0
- data/test/test_01_add_worksheet.rb +10 -0
- data/test/test_02_merge_formats.rb +49 -0
- data/test/test_04_dimensions.rb +388 -0
- data/test/test_05_rows.rb +175 -0
- data/test/test_06_extsst.rb +74 -0
- data/test/test_11_date_time.rb +475 -0
- data/test/test_12_date_only.rb +525 -0
- data/test/test_13_date_seconds.rb +477 -0
- data/test/test_21_escher.rb +624 -0
- data/test/test_22_mso_drawing_group.rb +741 -0
- data/test/test_23_note.rb +57 -0
- data/test/test_24_txo.rb +74 -0
- data/test/test_25_position_object.rb +80 -0
- data/test/test_26_autofilter.rb +309 -0
- data/test/test_27_autofilter.rb +126 -0
- data/test/test_28_autofilter.rb +156 -0
- data/test/test_29_process_jpg.rb +670 -0
- data/test/test_30_validation_dval.rb +74 -0
- data/test/test_31_validation_dv_strings.rb +123 -0
- data/test/test_32_validation_dv_formula.rb +203 -0
- data/test/test_40_property_types.rb +188 -0
- data/test/test_41_properties.rb +235 -0
- data/test/test_42_set_properties.rb +434 -0
- data/test/test_50_name_stored.rb +295 -0
- data/test/test_51_name_print_area.rb +353 -0
- data/test/test_52_name_print_titles.rb +450 -0
- data/test/test_53_autofilter.rb +199 -0
- data/test/test_60_chart_generic.rb +574 -0
- data/test/test_61_chart_subclasses.rb +84 -0
- data/test/test_62_chart_formats.rb +268 -0
- data/test/test_63_chart_area_formats.rb +645 -0
- data/test/test_biff.rb +71 -0
- data/test/test_big_workbook.rb +17 -0
- data/test/test_compatibility.rb +12 -0
- data/test/test_example_match.rb +3246 -0
- data/test/test_format.rb +1189 -0
- data/test/test_formula.rb +61 -0
- data/test/test_ole.rb +102 -0
- data/test/test_storage_lite.rb +116 -0
- data/test/test_workbook.rb +146 -0
- data/test/test_worksheet.rb +106 -0
- data/utils/add_magic_comment.rb +80 -0
- data/writeexcel.gemspec +278 -0
- data/writeexcel.rdoc +1425 -0
- 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
|