| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Excel::Writer::XLSX::Worksheet; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
############################################################################### |
|
4
|
|
|
|
|
|
|
# |
|
5
|
|
|
|
|
|
|
# Worksheet - A class for writing Excel Worksheets. |
|
6
|
|
|
|
|
|
|
# |
|
7
|
|
|
|
|
|
|
# |
|
8
|
|
|
|
|
|
|
# Used in conjunction with Excel::Writer::XLSX |
|
9
|
|
|
|
|
|
|
# |
|
10
|
|
|
|
|
|
|
# Copyright 2000-2019, John McNamara, jmcnamara@cpan.org |
|
11
|
|
|
|
|
|
|
# |
|
12
|
|
|
|
|
|
|
# Documentation after __END__ |
|
13
|
|
|
|
|
|
|
# |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
# perltidy with the following options: -mbl=2 -pt=0 -nola |
|
16
|
|
|
|
|
|
|
|
|
17
|
1041
|
|
|
1041
|
|
28424
|
use 5.008002; |
|
|
1041
|
|
|
|
|
4232
|
|
|
18
|
1041
|
|
|
1041
|
|
6044
|
use strict; |
|
|
1041
|
|
|
|
|
2434
|
|
|
|
1041
|
|
|
|
|
21036
|
|
|
19
|
1041
|
|
|
1041
|
|
5135
|
use warnings; |
|
|
1041
|
|
|
|
|
2305
|
|
|
|
1041
|
|
|
|
|
29704
|
|
|
20
|
1041
|
|
|
1041
|
|
5552
|
use Carp; |
|
|
1041
|
|
|
|
|
2359
|
|
|
|
1041
|
|
|
|
|
75534
|
|
|
21
|
1041
|
|
|
1041
|
|
8538
|
use File::Temp 'tempfile'; |
|
|
1041
|
|
|
|
|
23463
|
|
|
|
1041
|
|
|
|
|
56562
|
|
|
22
|
1041
|
|
|
1041
|
|
6871
|
use List::Util qw(max min); |
|
|
1041
|
|
|
|
|
2595
|
|
|
|
1041
|
|
|
|
|
114440
|
|
|
23
|
1041
|
|
|
1041
|
|
525706
|
use Excel::Writer::XLSX::Format; |
|
|
1041
|
|
|
|
|
2819
|
|
|
|
1041
|
|
|
|
|
52191
|
|
|
24
|
1041
|
|
|
1041
|
|
551843
|
use Excel::Writer::XLSX::Drawing; |
|
|
1041
|
|
|
|
|
3241
|
|
|
|
1041
|
|
|
|
|
52980
|
|
|
25
|
1041
|
|
|
1041
|
|
8015
|
use Excel::Writer::XLSX::Package::XMLwriter; |
|
|
1041
|
|
|
|
|
2330
|
|
|
|
1041
|
|
|
|
|
42544
|
|
|
26
|
1041
|
|
|
|
|
1719779
|
use Excel::Writer::XLSX::Utility qw(xl_cell_to_rowcol |
|
27
|
|
|
|
|
|
|
xl_rowcol_to_cell |
|
28
|
|
|
|
|
|
|
xl_col_to_name |
|
29
|
|
|
|
|
|
|
xl_range |
|
30
|
1041
|
|
|
1041
|
|
559112
|
quote_sheetname); |
|
|
1041
|
|
|
|
|
3092
|
|
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
our @ISA = qw(Excel::Writer::XLSX::Package::XMLwriter); |
|
33
|
|
|
|
|
|
|
our $VERSION = '1.03'; |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
############################################################################### |
|
37
|
|
|
|
|
|
|
# |
|
38
|
|
|
|
|
|
|
# Public and private API methods. |
|
39
|
|
|
|
|
|
|
# |
|
40
|
|
|
|
|
|
|
############################################################################### |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
############################################################################### |
|
44
|
|
|
|
|
|
|
# |
|
45
|
|
|
|
|
|
|
# new() |
|
46
|
|
|
|
|
|
|
# |
|
47
|
|
|
|
|
|
|
# Constructor. |
|
48
|
|
|
|
|
|
|
# |
|
49
|
|
|
|
|
|
|
sub new { |
|
50
|
|
|
|
|
|
|
|
|
51
|
1332
|
|
|
1332
|
0
|
258235
|
my $class = shift; |
|
52
|
1332
|
|
|
|
|
3164
|
my $fh = shift; |
|
53
|
1332
|
|
|
|
|
6941
|
my $self = Excel::Writer::XLSX::Package::XMLwriter->new( $fh ); |
|
54
|
1332
|
|
|
|
|
3366
|
my $rowmax = 1_048_576; |
|
55
|
1332
|
|
|
|
|
3051
|
my $colmax = 16_384; |
|
56
|
1332
|
|
|
|
|
2800
|
my $strmax = 32767; |
|
57
|
|
|
|
|
|
|
|
|
58
|
1332
|
|
|
|
|
4566
|
$self->{_name} = $_[0]; |
|
59
|
1332
|
|
|
|
|
3347
|
$self->{_index} = $_[1]; |
|
60
|
1332
|
|
|
|
|
3268
|
$self->{_activesheet} = $_[2]; |
|
61
|
1332
|
|
|
|
|
2976
|
$self->{_firstsheet} = $_[3]; |
|
62
|
1332
|
|
|
|
|
3020
|
$self->{_str_total} = $_[4]; |
|
63
|
1332
|
|
|
|
|
2915
|
$self->{_str_unique} = $_[5]; |
|
64
|
1332
|
|
|
|
|
4160
|
$self->{_str_table} = $_[6]; |
|
65
|
1332
|
|
|
|
|
3402
|
$self->{_date_1904} = $_[7]; |
|
66
|
1332
|
|
|
|
|
3113
|
$self->{_palette} = $_[8]; |
|
67
|
1332
|
|
100
|
|
|
7334
|
$self->{_optimization} = $_[9] || 0; |
|
68
|
1332
|
|
|
|
|
3344
|
$self->{_tempdir} = $_[10]; |
|
69
|
1332
|
|
|
|
|
3088
|
$self->{_excel2003_style} = $_[11]; |
|
70
|
1332
|
|
|
|
|
2996
|
$self->{_default_url_format} = $_[12]; |
|
71
|
1332
|
|
100
|
|
|
4891
|
$self->{_max_url_length} = $_[13] || 2079; |
|
72
|
|
|
|
|
|
|
|
|
73
|
1332
|
|
|
|
|
5123
|
$self->{_ext_sheets} = []; |
|
74
|
1332
|
|
|
|
|
3310
|
$self->{_fileclosed} = 0; |
|
75
|
1332
|
|
|
|
|
3341
|
$self->{_excel_version} = 2007; |
|
76
|
|
|
|
|
|
|
|
|
77
|
1332
|
|
|
|
|
3127
|
$self->{_xls_rowmax} = $rowmax; |
|
78
|
1332
|
|
|
|
|
3098
|
$self->{_xls_colmax} = $colmax; |
|
79
|
1332
|
|
|
|
|
3121
|
$self->{_xls_strmax} = $strmax; |
|
80
|
1332
|
|
|
|
|
3195
|
$self->{_dim_rowmin} = undef; |
|
81
|
1332
|
|
|
|
|
3058
|
$self->{_dim_rowmax} = undef; |
|
82
|
1332
|
|
|
|
|
3228
|
$self->{_dim_colmin} = undef; |
|
83
|
1332
|
|
|
|
|
3193
|
$self->{_dim_colmax} = undef; |
|
84
|
|
|
|
|
|
|
|
|
85
|
1332
|
|
|
|
|
3467
|
$self->{_colinfo} = {}; |
|
86
|
1332
|
|
|
|
|
3521
|
$self->{_selections} = []; |
|
87
|
1332
|
|
|
|
|
3291
|
$self->{_hidden} = 0; |
|
88
|
1332
|
|
|
|
|
3169
|
$self->{_active} = 0; |
|
89
|
1332
|
|
|
|
|
3032
|
$self->{_tab_color} = 0; |
|
90
|
|
|
|
|
|
|
|
|
91
|
1332
|
|
|
|
|
3156
|
$self->{_panes} = []; |
|
92
|
1332
|
|
|
|
|
5251
|
$self->{_active_pane} = 3; |
|
93
|
1332
|
|
|
|
|
3032
|
$self->{_selected} = 0; |
|
94
|
1332
|
|
|
|
|
2807
|
$self->{_hide_row_col_headers} = 0; |
|
95
|
|
|
|
|
|
|
|
|
96
|
1332
|
|
|
|
|
2986
|
$self->{_page_setup_changed} = 0; |
|
97
|
1332
|
|
|
|
|
2934
|
$self->{_paper_size} = 0; |
|
98
|
1332
|
|
|
|
|
3394
|
$self->{_orientation} = 1; |
|
99
|
|
|
|
|
|
|
|
|
100
|
1332
|
|
|
|
|
3049
|
$self->{_print_options_changed} = 0; |
|
101
|
1332
|
|
|
|
|
2994
|
$self->{_hcenter} = 0; |
|
102
|
1332
|
|
|
|
|
2933
|
$self->{_vcenter} = 0; |
|
103
|
1332
|
|
|
|
|
2888
|
$self->{_print_gridlines} = 0; |
|
104
|
1332
|
|
|
|
|
2956
|
$self->{_screen_gridlines} = 1; |
|
105
|
1332
|
|
|
|
|
2901
|
$self->{_print_headers} = 0; |
|
106
|
|
|
|
|
|
|
|
|
107
|
1332
|
|
|
|
|
2987
|
$self->{_header_footer_changed} = 0; |
|
108
|
1332
|
|
|
|
|
3245
|
$self->{_header} = ''; |
|
109
|
1332
|
|
|
|
|
3136
|
$self->{_footer} = ''; |
|
110
|
1332
|
|
|
|
|
2941
|
$self->{_header_footer_aligns} = 1; |
|
111
|
1332
|
|
|
|
|
3062
|
$self->{_header_footer_scales} = 1; |
|
112
|
1332
|
|
|
|
|
3176
|
$self->{_header_images} = []; |
|
113
|
1332
|
|
|
|
|
3187
|
$self->{_footer_images} = []; |
|
114
|
|
|
|
|
|
|
|
|
115
|
1332
|
|
|
|
|
3308
|
$self->{_margin_left} = 0.7; |
|
116
|
1332
|
|
|
|
|
3078
|
$self->{_margin_right} = 0.7; |
|
117
|
1332
|
|
|
|
|
3230
|
$self->{_margin_top} = 0.75; |
|
118
|
1332
|
|
|
|
|
3163
|
$self->{_margin_bottom} = 0.75; |
|
119
|
1332
|
|
|
|
|
3429
|
$self->{_margin_header} = 0.3; |
|
120
|
1332
|
|
|
|
|
2974
|
$self->{_margin_footer} = 0.3; |
|
121
|
|
|
|
|
|
|
|
|
122
|
1332
|
|
|
|
|
3099
|
$self->{_repeat_rows} = ''; |
|
123
|
1332
|
|
|
|
|
3107
|
$self->{_repeat_cols} = ''; |
|
124
|
1332
|
|
|
|
|
3232
|
$self->{_print_area} = ''; |
|
125
|
|
|
|
|
|
|
|
|
126
|
1332
|
|
|
|
|
3030
|
$self->{_page_order} = 0; |
|
127
|
1332
|
|
|
|
|
3090
|
$self->{_black_white} = 0; |
|
128
|
1332
|
|
|
|
|
2976
|
$self->{_draft_quality} = 0; |
|
129
|
1332
|
|
|
|
|
3094
|
$self->{_print_comments} = 0; |
|
130
|
1332
|
|
|
|
|
8134
|
$self->{_page_start} = 0; |
|
131
|
|
|
|
|
|
|
|
|
132
|
1332
|
|
|
|
|
3270
|
$self->{_fit_page} = 0; |
|
133
|
1332
|
|
|
|
|
2906
|
$self->{_fit_width} = 0; |
|
134
|
1332
|
|
|
|
|
2964
|
$self->{_fit_height} = 0; |
|
135
|
|
|
|
|
|
|
|
|
136
|
1332
|
|
|
|
|
3018
|
$self->{_hbreaks} = []; |
|
137
|
1332
|
|
|
|
|
3277
|
$self->{_vbreaks} = []; |
|
138
|
|
|
|
|
|
|
|
|
139
|
1332
|
|
|
|
|
3076
|
$self->{_protect} = 0; |
|
140
|
1332
|
|
|
|
|
3113
|
$self->{_password} = undef; |
|
141
|
|
|
|
|
|
|
|
|
142
|
1332
|
|
|
|
|
3052
|
$self->{_set_cols} = {}; |
|
143
|
1332
|
|
|
|
|
3293
|
$self->{_set_rows} = {}; |
|
144
|
|
|
|
|
|
|
|
|
145
|
1332
|
|
|
|
|
3046
|
$self->{_zoom} = 100; |
|
146
|
1332
|
|
|
|
|
2999
|
$self->{_zoom_scale_normal} = 1; |
|
147
|
1332
|
|
|
|
|
2986
|
$self->{_print_scale} = 100; |
|
148
|
1332
|
|
|
|
|
2881
|
$self->{_right_to_left} = 0; |
|
149
|
1332
|
|
|
|
|
2868
|
$self->{_show_zeros} = 1; |
|
150
|
1332
|
|
|
|
|
2808
|
$self->{_leading_zeros} = 0; |
|
151
|
|
|
|
|
|
|
|
|
152
|
1332
|
|
|
|
|
2798
|
$self->{_outline_row_level} = 0; |
|
153
|
1332
|
|
|
|
|
2891
|
$self->{_outline_col_level} = 0; |
|
154
|
1332
|
|
|
|
|
2936
|
$self->{_outline_style} = 0; |
|
155
|
1332
|
|
|
|
|
2870
|
$self->{_outline_below} = 1; |
|
156
|
1332
|
|
|
|
|
2926
|
$self->{_outline_right} = 1; |
|
157
|
1332
|
|
|
|
|
2961
|
$self->{_outline_on} = 1; |
|
158
|
1332
|
|
|
|
|
2972
|
$self->{_outline_changed} = 0; |
|
159
|
|
|
|
|
|
|
|
|
160
|
1332
|
|
|
|
|
2945
|
$self->{_original_row_height} = 15; |
|
161
|
1332
|
|
|
|
|
2868
|
$self->{_default_row_height} = 15; |
|
162
|
1332
|
|
|
|
|
2862
|
$self->{_default_row_pixels} = 20; |
|
163
|
1332
|
|
|
|
|
3007
|
$self->{_default_col_width} = 8.43; |
|
164
|
1332
|
|
|
|
|
2843
|
$self->{_default_col_pixels} = 64; |
|
165
|
1332
|
|
|
|
|
2939
|
$self->{_default_row_zeroed} = 0; |
|
166
|
|
|
|
|
|
|
|
|
167
|
1332
|
|
|
|
|
3177
|
$self->{_names} = {}; |
|
168
|
|
|
|
|
|
|
|
|
169
|
1332
|
|
|
|
|
3581
|
$self->{_write_match} = []; |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
|
|
172
|
1332
|
|
|
|
|
3276
|
$self->{_table} = {}; |
|
173
|
1332
|
|
|
|
|
3286
|
$self->{_merge} = []; |
|
174
|
|
|
|
|
|
|
|
|
175
|
1332
|
|
|
|
|
3123
|
$self->{_has_vml} = 0; |
|
176
|
1332
|
|
|
|
|
2930
|
$self->{_has_header_vml} = 0; |
|
177
|
1332
|
|
|
|
|
2829
|
$self->{_has_comments} = 0; |
|
178
|
1332
|
|
|
|
|
3071
|
$self->{_comments} = {}; |
|
179
|
1332
|
|
|
|
|
3060
|
$self->{_comments_array} = []; |
|
180
|
1332
|
|
|
|
|
3461
|
$self->{_comments_author} = ''; |
|
181
|
1332
|
|
|
|
|
2925
|
$self->{_comments_visible} = 0; |
|
182
|
1332
|
|
|
|
|
2911
|
$self->{_vml_shape_id} = 1024; |
|
183
|
1332
|
|
|
|
|
3030
|
$self->{_buttons_array} = []; |
|
184
|
1332
|
|
|
|
|
3217
|
$self->{_header_images_array} = []; |
|
185
|
|
|
|
|
|
|
|
|
186
|
1332
|
|
|
|
|
3177
|
$self->{_autofilter} = ''; |
|
187
|
1332
|
|
|
|
|
2909
|
$self->{_filter_on} = 0; |
|
188
|
1332
|
|
|
|
|
2974
|
$self->{_filter_range} = []; |
|
189
|
1332
|
|
|
|
|
3246
|
$self->{_filter_cols} = {}; |
|
190
|
|
|
|
|
|
|
|
|
191
|
1332
|
|
|
|
|
3152
|
$self->{_col_sizes} = {}; |
|
192
|
1332
|
|
|
|
|
3165
|
$self->{_row_sizes} = {}; |
|
193
|
1332
|
|
|
|
|
3077
|
$self->{_col_formats} = {}; |
|
194
|
1332
|
|
|
|
|
3005
|
$self->{_col_size_changed} = 0; |
|
195
|
1332
|
|
|
|
|
2951
|
$self->{_row_size_changed} = 0; |
|
196
|
|
|
|
|
|
|
|
|
197
|
1332
|
|
|
|
|
2907
|
$self->{_last_shape_id} = 1; |
|
198
|
1332
|
|
|
|
|
2937
|
$self->{_rel_count} = 0; |
|
199
|
1332
|
|
|
|
|
2909
|
$self->{_hlink_count} = 0; |
|
200
|
1332
|
|
|
|
|
3261
|
$self->{_hlink_refs} = []; |
|
201
|
1332
|
|
|
|
|
3259
|
$self->{_external_hyper_links} = []; |
|
202
|
1332
|
|
|
|
|
3219
|
$self->{_external_drawing_links} = []; |
|
203
|
1332
|
|
|
|
|
3235
|
$self->{_external_comment_links} = []; |
|
204
|
1332
|
|
|
|
|
3067
|
$self->{_external_vml_links} = []; |
|
205
|
1332
|
|
|
|
|
3230
|
$self->{_external_table_links} = []; |
|
206
|
1332
|
|
|
|
|
3131
|
$self->{_drawing_links} = []; |
|
207
|
1332
|
|
|
|
|
3260
|
$self->{_vml_drawing_links} = []; |
|
208
|
1332
|
|
|
|
|
3091
|
$self->{_charts} = []; |
|
209
|
1332
|
|
|
|
|
11997
|
$self->{_images} = []; |
|
210
|
1332
|
|
|
|
|
4165
|
$self->{_tables} = []; |
|
211
|
1332
|
|
|
|
|
3164
|
$self->{_sparklines} = []; |
|
212
|
1332
|
|
|
|
|
3203
|
$self->{_shapes} = []; |
|
213
|
1332
|
|
|
|
|
3026
|
$self->{_shape_hash} = {}; |
|
214
|
1332
|
|
|
|
|
2830
|
$self->{_has_shapes} = 0; |
|
215
|
1332
|
|
|
|
|
2797
|
$self->{_drawing} = 0; |
|
216
|
1332
|
|
|
|
|
2896
|
$self->{_drawing_rels} = {}; |
|
217
|
1332
|
|
|
|
|
2842
|
$self->{_drawing_rels_id} = 0; |
|
218
|
1332
|
|
|
|
|
3004
|
$self->{_vml_drawing_rels} = {}; |
|
219
|
1332
|
|
|
|
|
3094
|
$self->{_vml_drawing_rels_id} = 0; |
|
220
|
|
|
|
|
|
|
|
|
221
|
1332
|
|
|
|
|
2979
|
$self->{_horizontal_dpi} = 0; |
|
222
|
1332
|
|
|
|
|
2988
|
$self->{_vertical_dpi} = 0; |
|
223
|
|
|
|
|
|
|
|
|
224
|
1332
|
|
|
|
|
3219
|
$self->{_rstring} = ''; |
|
225
|
1332
|
|
|
|
|
2994
|
$self->{_previous_row} = 0; |
|
226
|
|
|
|
|
|
|
|
|
227
|
1332
|
100
|
|
|
|
5357
|
if ( $self->{_optimization} == 1 ) { |
|
228
|
8
|
|
|
|
|
53
|
my $fh = tempfile( DIR => $self->{_tempdir} ); |
|
229
|
8
|
|
|
|
|
5996
|
binmode $fh, ':utf8'; |
|
230
|
|
|
|
|
|
|
|
|
231
|
8
|
|
|
|
|
26
|
$self->{_cell_data_fh} = $fh; |
|
232
|
8
|
|
|
|
|
30
|
$self->{_fh} = $fh; |
|
233
|
|
|
|
|
|
|
} |
|
234
|
|
|
|
|
|
|
|
|
235
|
1332
|
|
|
|
|
3501
|
$self->{_validations} = []; |
|
236
|
1332
|
|
|
|
|
3489
|
$self->{_cond_formats} = {}; |
|
237
|
1332
|
|
|
|
|
3426
|
$self->{_data_bars_2010} = []; |
|
238
|
1332
|
|
|
|
|
3084
|
$self->{_use_data_bars_2010} = 0; |
|
239
|
1332
|
|
|
|
|
3112
|
$self->{_dxf_priority} = 1; |
|
240
|
|
|
|
|
|
|
|
|
241
|
1332
|
100
|
|
|
|
4379
|
if ( $self->{_excel2003_style} ) { |
|
242
|
8
|
|
|
|
|
21
|
$self->{_original_row_height} = 12.75; |
|
243
|
8
|
|
|
|
|
21
|
$self->{_default_row_height} = 12.75; |
|
244
|
8
|
|
|
|
|
17
|
$self->{_default_row_pixels} = 17; |
|
245
|
8
|
|
|
|
|
15
|
$self->{_margin_left} = 0.75; |
|
246
|
8
|
|
|
|
|
23
|
$self->{_margin_right} = 0.75; |
|
247
|
8
|
|
|
|
|
21
|
$self->{_margin_top} = 1; |
|
248
|
8
|
|
|
|
|
18
|
$self->{_margin_bottom} = 1; |
|
249
|
8
|
|
|
|
|
19
|
$self->{_margin_header} = 0.5; |
|
250
|
8
|
|
|
|
|
18
|
$self->{_margin_footer} = 0.5; |
|
251
|
8
|
|
|
|
|
17
|
$self->{_header_footer_aligns} = 0; |
|
252
|
|
|
|
|
|
|
} |
|
253
|
|
|
|
|
|
|
|
|
254
|
1332
|
|
|
|
|
3648
|
bless $self, $class; |
|
255
|
1332
|
|
|
|
|
5928
|
return $self; |
|
256
|
|
|
|
|
|
|
} |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
############################################################################### |
|
259
|
|
|
|
|
|
|
# |
|
260
|
|
|
|
|
|
|
# _set_xml_writer() |
|
261
|
|
|
|
|
|
|
# |
|
262
|
|
|
|
|
|
|
# Over-ridden to ensure that write_single_row() is called for the final row |
|
263
|
|
|
|
|
|
|
# when optimisation mode is on. |
|
264
|
|
|
|
|
|
|
# |
|
265
|
|
|
|
|
|
|
sub _set_xml_writer { |
|
266
|
|
|
|
|
|
|
|
|
267
|
956
|
|
|
956
|
|
13881
|
my $self = shift; |
|
268
|
956
|
|
|
|
|
2593
|
my $filename = shift; |
|
269
|
|
|
|
|
|
|
|
|
270
|
956
|
100
|
|
|
|
4404
|
if ( $self->{_optimization} == 1 ) { |
|
271
|
8
|
|
|
|
|
26
|
$self->_write_single_row(); |
|
272
|
|
|
|
|
|
|
} |
|
273
|
|
|
|
|
|
|
|
|
274
|
956
|
|
|
|
|
8553
|
$self->SUPER::_set_xml_writer( $filename ); |
|
275
|
|
|
|
|
|
|
} |
|
276
|
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
############################################################################### |
|
279
|
|
|
|
|
|
|
# |
|
280
|
|
|
|
|
|
|
# _assemble_xml_file() |
|
281
|
|
|
|
|
|
|
# |
|
282
|
|
|
|
|
|
|
# Assemble and write the XML file. |
|
283
|
|
|
|
|
|
|
# |
|
284
|
|
|
|
|
|
|
sub _assemble_xml_file { |
|
285
|
|
|
|
|
|
|
|
|
286
|
993
|
|
|
993
|
|
2970
|
my $self = shift; |
|
287
|
|
|
|
|
|
|
|
|
288
|
993
|
|
|
|
|
10059
|
$self->xml_declaration(); |
|
289
|
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
# Write the root worksheet element. |
|
291
|
993
|
|
|
|
|
6323
|
$self->_write_worksheet(); |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
# Write the worksheet properties. |
|
294
|
993
|
|
|
|
|
4834
|
$self->_write_sheet_pr(); |
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
# Write the worksheet dimensions. |
|
297
|
993
|
|
|
|
|
4670
|
$self->_write_dimension(); |
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
# Write the sheet view properties. |
|
300
|
993
|
|
|
|
|
4733
|
$self->_write_sheet_views(); |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# Write the sheet format properties. |
|
303
|
993
|
|
|
|
|
5129
|
$self->_write_sheet_format_pr(); |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
# Write the sheet column info. |
|
306
|
993
|
|
|
|
|
4996
|
$self->_write_cols(); |
|
307
|
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
# Write the worksheet data such as rows columns and cells. |
|
309
|
993
|
100
|
|
|
|
4601
|
if ( $self->{_optimization} == 0 ) { |
|
310
|
985
|
|
|
|
|
4545
|
$self->_write_sheet_data(); |
|
311
|
|
|
|
|
|
|
} |
|
312
|
|
|
|
|
|
|
else { |
|
313
|
8
|
|
|
|
|
33
|
$self->_write_optimized_sheet_data(); |
|
314
|
|
|
|
|
|
|
} |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
# Write the sheetProtection element. |
|
317
|
993
|
|
|
|
|
6137
|
$self->_write_sheet_protection(); |
|
318
|
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
# Write the worksheet calculation properties. |
|
320
|
|
|
|
|
|
|
#$self->_write_sheet_calc_pr(); |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
# Write the worksheet phonetic properties. |
|
323
|
993
|
100
|
|
|
|
5937
|
if ($self->{_excel2003_style}) { |
|
324
|
8
|
|
|
|
|
32
|
$self->_write_phonetic_pr(); |
|
325
|
|
|
|
|
|
|
} |
|
326
|
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
# Write the autoFilter element. |
|
328
|
993
|
|
|
|
|
5472
|
$self->_write_auto_filter(); |
|
329
|
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
# Write the mergeCells element. |
|
331
|
993
|
|
|
|
|
4929
|
$self->_write_merge_cells(); |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
# Write the conditional formats. |
|
334
|
993
|
|
|
|
|
4807
|
$self->_write_conditional_formats(); |
|
335
|
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
# Write the dataValidations element. |
|
337
|
993
|
|
|
|
|
5009
|
$self->_write_data_validations(); |
|
338
|
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
# Write the hyperlink element. |
|
340
|
993
|
|
|
|
|
5015
|
$self->_write_hyperlinks(); |
|
341
|
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
# Write the printOptions element. |
|
343
|
993
|
|
|
|
|
5099
|
$self->_write_print_options(); |
|
344
|
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
# Write the worksheet page_margins. |
|
346
|
993
|
|
|
|
|
4704
|
$self->_write_page_margins(); |
|
347
|
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
# Write the worksheet page setup. |
|
349
|
993
|
|
|
|
|
4899
|
$self->_write_page_setup(); |
|
350
|
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
# Write the headerFooter element. |
|
352
|
993
|
|
|
|
|
4632
|
$self->_write_header_footer(); |
|
353
|
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
# Write the rowBreaks element. |
|
355
|
993
|
|
|
|
|
4667
|
$self->_write_row_breaks(); |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
# Write the colBreaks element. |
|
358
|
993
|
|
|
|
|
5006
|
$self->_write_col_breaks(); |
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
# Write the drawing element. |
|
361
|
993
|
|
|
|
|
4722
|
$self->_write_drawings(); |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
# Write the legacyDrawing element. |
|
364
|
993
|
|
|
|
|
5094
|
$self->_write_legacy_drawing(); |
|
365
|
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
# Write the legacyDrawingHF element. |
|
367
|
993
|
|
|
|
|
4739
|
$self->_write_legacy_drawing_hf(); |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
# Write the tableParts element. |
|
370
|
993
|
|
|
|
|
5020
|
$self->_write_table_parts(); |
|
371
|
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
# Write the extLst elements. |
|
373
|
993
|
|
|
|
|
4745
|
$self->_write_ext_list(); |
|
374
|
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
# Close the worksheet tag. |
|
376
|
993
|
|
|
|
|
5059
|
$self->xml_end_tag( 'worksheet' ); |
|
377
|
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
# Close the XML writer filehandle. |
|
379
|
993
|
|
|
|
|
8440
|
$self->xml_get_fh()->close(); |
|
380
|
|
|
|
|
|
|
} |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
############################################################################### |
|
384
|
|
|
|
|
|
|
# |
|
385
|
|
|
|
|
|
|
# _close() |
|
386
|
|
|
|
|
|
|
# |
|
387
|
|
|
|
|
|
|
# Write the worksheet elements. |
|
388
|
|
|
|
|
|
|
# |
|
389
|
|
|
|
|
|
|
sub _close { |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
# TODO. Unused. Remove after refactoring. |
|
392
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
|
393
|
0
|
|
|
|
|
0
|
my $sheetnames = shift; |
|
394
|
0
|
|
|
|
|
0
|
my $num_sheets = scalar @$sheetnames; |
|
395
|
|
|
|
|
|
|
} |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
############################################################################### |
|
399
|
|
|
|
|
|
|
# |
|
400
|
|
|
|
|
|
|
# get_name(). |
|
401
|
|
|
|
|
|
|
# |
|
402
|
|
|
|
|
|
|
# Retrieve the worksheet name. |
|
403
|
|
|
|
|
|
|
# |
|
404
|
|
|
|
|
|
|
sub get_name { |
|
405
|
|
|
|
|
|
|
|
|
406
|
956
|
|
|
956
|
0
|
2673
|
my $self = shift; |
|
407
|
|
|
|
|
|
|
|
|
408
|
956
|
|
|
|
|
4722
|
return $self->{_name}; |
|
409
|
|
|
|
|
|
|
} |
|
410
|
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
############################################################################### |
|
413
|
|
|
|
|
|
|
# |
|
414
|
|
|
|
|
|
|
# select() |
|
415
|
|
|
|
|
|
|
# |
|
416
|
|
|
|
|
|
|
# Set this worksheet as a selected worksheet, i.e. the worksheet has its tab |
|
417
|
|
|
|
|
|
|
# highlighted. |
|
418
|
|
|
|
|
|
|
# |
|
419
|
|
|
|
|
|
|
sub select { |
|
420
|
|
|
|
|
|
|
|
|
421
|
118
|
|
|
118
|
0
|
1944
|
my $self = shift; |
|
422
|
|
|
|
|
|
|
|
|
423
|
118
|
|
|
|
|
483
|
$self->{_hidden} = 0; # Selected worksheet can't be hidden. |
|
424
|
118
|
|
|
|
|
330
|
$self->{_selected} = 1; |
|
425
|
|
|
|
|
|
|
} |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
############################################################################### |
|
429
|
|
|
|
|
|
|
# |
|
430
|
|
|
|
|
|
|
# activate() |
|
431
|
|
|
|
|
|
|
# |
|
432
|
|
|
|
|
|
|
# Set this worksheet as the active worksheet, i.e. the worksheet that is |
|
433
|
|
|
|
|
|
|
# displayed when the workbook is opened. Also set it as selected. |
|
434
|
|
|
|
|
|
|
# |
|
435
|
|
|
|
|
|
|
sub activate { |
|
436
|
|
|
|
|
|
|
|
|
437
|
8
|
|
|
8
|
0
|
62
|
my $self = shift; |
|
438
|
|
|
|
|
|
|
|
|
439
|
8
|
|
|
|
|
21
|
$self->{_hidden} = 0; # Active worksheet can't be hidden. |
|
440
|
8
|
|
|
|
|
25
|
$self->{_selected} = 1; |
|
441
|
8
|
|
|
|
|
16
|
${ $self->{_activesheet} } = $self->{_index}; |
|
|
8
|
|
|
|
|
23
|
|
|
442
|
|
|
|
|
|
|
} |
|
443
|
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
############################################################################### |
|
446
|
|
|
|
|
|
|
# |
|
447
|
|
|
|
|
|
|
# hide() |
|
448
|
|
|
|
|
|
|
# |
|
449
|
|
|
|
|
|
|
# Hide this worksheet. |
|
450
|
|
|
|
|
|
|
# |
|
451
|
|
|
|
|
|
|
sub hide { |
|
452
|
|
|
|
|
|
|
|
|
453
|
2
|
|
|
2
|
0
|
19
|
my $self = shift; |
|
454
|
|
|
|
|
|
|
|
|
455
|
2
|
|
|
|
|
5
|
$self->{_hidden} = 1; |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
# A hidden worksheet shouldn't be active or selected. |
|
458
|
2
|
|
|
|
|
5
|
$self->{_selected} = 0; |
|
459
|
2
|
|
|
|
|
12
|
${ $self->{_activesheet} } = 0; |
|
|
2
|
|
|
|
|
8
|
|
|
460
|
2
|
|
|
|
|
5
|
${ $self->{_firstsheet} } = 0; |
|
|
2
|
|
|
|
|
5
|
|
|
461
|
|
|
|
|
|
|
} |
|
462
|
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
############################################################################### |
|
465
|
|
|
|
|
|
|
# |
|
466
|
|
|
|
|
|
|
# set_first_sheet() |
|
467
|
|
|
|
|
|
|
# |
|
468
|
|
|
|
|
|
|
# Set this worksheet as the first visible sheet. This is necessary |
|
469
|
|
|
|
|
|
|
# when there are a large number of worksheets and the activated |
|
470
|
|
|
|
|
|
|
# worksheet is not visible on the screen. |
|
471
|
|
|
|
|
|
|
# |
|
472
|
|
|
|
|
|
|
sub set_first_sheet { |
|
473
|
|
|
|
|
|
|
|
|
474
|
1
|
|
|
1
|
0
|
7
|
my $self = shift; |
|
475
|
|
|
|
|
|
|
|
|
476
|
1
|
|
|
|
|
3
|
$self->{_hidden} = 0; # Active worksheet can't be hidden. |
|
477
|
1
|
|
|
|
|
2
|
${ $self->{_firstsheet} } = $self->{_index}; |
|
|
1
|
|
|
|
|
3
|
|
|
478
|
|
|
|
|
|
|
} |
|
479
|
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
############################################################################### |
|
482
|
|
|
|
|
|
|
# |
|
483
|
|
|
|
|
|
|
# protect( $password ) |
|
484
|
|
|
|
|
|
|
# |
|
485
|
|
|
|
|
|
|
# Set the worksheet protection flags to prevent modification of worksheet |
|
486
|
|
|
|
|
|
|
# objects. |
|
487
|
|
|
|
|
|
|
# |
|
488
|
|
|
|
|
|
|
sub protect { |
|
489
|
|
|
|
|
|
|
|
|
490
|
27
|
|
|
27
|
0
|
485
|
my $self = shift; |
|
491
|
27
|
|
100
|
|
|
93
|
my $password = shift || ''; |
|
492
|
27
|
|
100
|
|
|
68
|
my $options = shift || {}; |
|
493
|
|
|
|
|
|
|
|
|
494
|
27
|
100
|
|
|
|
70
|
if ( $password ne '' ) { |
|
495
|
6
|
|
|
|
|
20
|
$password = $self->_encode_password( $password ); |
|
496
|
|
|
|
|
|
|
} |
|
497
|
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
# Default values for objects that can be protected. |
|
499
|
27
|
|
|
|
|
239
|
my %defaults = ( |
|
500
|
|
|
|
|
|
|
sheet => 1, |
|
501
|
|
|
|
|
|
|
content => 0, |
|
502
|
|
|
|
|
|
|
objects => 0, |
|
503
|
|
|
|
|
|
|
scenarios => 0, |
|
504
|
|
|
|
|
|
|
format_cells => 0, |
|
505
|
|
|
|
|
|
|
format_columns => 0, |
|
506
|
|
|
|
|
|
|
format_rows => 0, |
|
507
|
|
|
|
|
|
|
insert_columns => 0, |
|
508
|
|
|
|
|
|
|
insert_rows => 0, |
|
509
|
|
|
|
|
|
|
insert_hyperlinks => 0, |
|
510
|
|
|
|
|
|
|
delete_columns => 0, |
|
511
|
|
|
|
|
|
|
delete_rows => 0, |
|
512
|
|
|
|
|
|
|
select_locked_cells => 1, |
|
513
|
|
|
|
|
|
|
sort => 0, |
|
514
|
|
|
|
|
|
|
autofilter => 0, |
|
515
|
|
|
|
|
|
|
pivot_tables => 0, |
|
516
|
|
|
|
|
|
|
select_unlocked_cells => 1, |
|
517
|
|
|
|
|
|
|
); |
|
518
|
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
# Overwrite the defaults with user specified values. |
|
521
|
27
|
|
|
|
|
43
|
for my $key ( keys %{$options} ) { |
|
|
27
|
|
|
|
|
92
|
|
|
522
|
|
|
|
|
|
|
|
|
523
|
60
|
50
|
|
|
|
117
|
if ( exists $defaults{$key} ) { |
|
524
|
60
|
|
|
|
|
161
|
$defaults{$key} = $options->{$key}; |
|
525
|
|
|
|
|
|
|
} |
|
526
|
|
|
|
|
|
|
else { |
|
527
|
0
|
|
|
|
|
0
|
carp "Unknown protection object: $key\n"; |
|
528
|
|
|
|
|
|
|
} |
|
529
|
|
|
|
|
|
|
} |
|
530
|
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
# Set the password after the user defined values. |
|
532
|
27
|
|
|
|
|
65
|
$defaults{password} = $password; |
|
533
|
|
|
|
|
|
|
|
|
534
|
27
|
|
|
|
|
122
|
$self->{_protect} = \%defaults; |
|
535
|
|
|
|
|
|
|
} |
|
536
|
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
############################################################################### |
|
539
|
|
|
|
|
|
|
# |
|
540
|
|
|
|
|
|
|
# _encode_password($password) |
|
541
|
|
|
|
|
|
|
# |
|
542
|
|
|
|
|
|
|
# Based on the algorithm provided by Daniel Rentz of OpenOffice. |
|
543
|
|
|
|
|
|
|
# |
|
544
|
|
|
|
|
|
|
sub _encode_password { |
|
545
|
|
|
|
|
|
|
|
|
546
|
1041
|
|
|
1041
|
|
10347
|
use integer; |
|
|
1041
|
|
|
|
|
2840
|
|
|
|
1041
|
|
|
|
|
8486
|
|
|
547
|
|
|
|
|
|
|
|
|
548
|
6
|
|
|
6
|
|
20
|
my $self = shift; |
|
549
|
6
|
|
|
|
|
14
|
my $plaintext = $_[0]; |
|
550
|
6
|
|
|
|
|
15
|
my $password; |
|
551
|
|
|
|
|
|
|
my $count; |
|
552
|
6
|
|
|
|
|
0
|
my @chars; |
|
553
|
6
|
|
|
|
|
10
|
my $i = 0; |
|
554
|
|
|
|
|
|
|
|
|
555
|
6
|
|
|
|
|
31
|
$count = @chars = split //, $plaintext; |
|
556
|
|
|
|
|
|
|
|
|
557
|
6
|
|
|
|
|
16
|
foreach my $char ( @chars ) { |
|
558
|
48
|
|
|
|
|
72
|
my $low_15; |
|
559
|
|
|
|
|
|
|
my $high_15; |
|
560
|
48
|
|
|
|
|
74
|
$char = ord( $char ) << ++$i; |
|
561
|
48
|
|
|
|
|
67
|
$low_15 = $char & 0x7fff; |
|
562
|
48
|
|
|
|
|
61
|
$high_15 = $char & 0x7fff << 15; |
|
563
|
48
|
|
|
|
|
63
|
$high_15 = $high_15 >> 15; |
|
564
|
48
|
|
|
|
|
75
|
$char = $low_15 | $high_15; |
|
565
|
|
|
|
|
|
|
} |
|
566
|
|
|
|
|
|
|
|
|
567
|
6
|
|
|
|
|
15
|
$password = 0x0000; |
|
568
|
6
|
|
|
|
|
21
|
$password ^= $_ for @chars; |
|
569
|
6
|
|
|
|
|
11
|
$password ^= $count; |
|
570
|
6
|
|
|
|
|
11
|
$password ^= 0xCE4B; |
|
571
|
|
|
|
|
|
|
|
|
572
|
6
|
|
|
|
|
36
|
return sprintf "%X", $password; |
|
573
|
|
|
|
|
|
|
} |
|
574
|
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
############################################################################### |
|
577
|
|
|
|
|
|
|
# |
|
578
|
|
|
|
|
|
|
# set_column($firstcol, $lastcol, $width, $format, $hidden, $level) |
|
579
|
|
|
|
|
|
|
# |
|
580
|
|
|
|
|
|
|
# Set the width of a single column or a range of columns. |
|
581
|
|
|
|
|
|
|
# See also: _write_col_info |
|
582
|
|
|
|
|
|
|
# |
|
583
|
|
|
|
|
|
|
sub set_column { |
|
584
|
|
|
|
|
|
|
|
|
585
|
189
|
|
|
189
|
0
|
1319
|
my $self = shift; |
|
586
|
189
|
|
|
|
|
572
|
my @data = @_; |
|
587
|
189
|
|
|
|
|
408
|
my $cell = $data[0]; |
|
588
|
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
590
|
189
|
100
|
|
|
|
972
|
if ( $cell =~ /^\D/ ) { |
|
591
|
188
|
|
|
|
|
842
|
@data = $self->_substitute_cellref( @_ ); |
|
592
|
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
# Returned values $row1 and $row2 aren't required here. Remove them. |
|
594
|
188
|
|
|
|
|
426
|
shift @data; # $row1 |
|
595
|
188
|
|
|
|
|
446
|
splice @data, 1, 1; # $row2 |
|
596
|
|
|
|
|
|
|
} |
|
597
|
|
|
|
|
|
|
|
|
598
|
189
|
50
|
|
|
|
667
|
return if @data < 3; # Ensure at least $firstcol, $lastcol and $width |
|
599
|
189
|
50
|
|
|
|
555
|
return if not defined $data[0]; # Columns must be defined. |
|
600
|
189
|
50
|
|
|
|
505
|
return if not defined $data[1]; |
|
601
|
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
# Assume second column is the same as first if 0. Avoids KB918419 bug. |
|
603
|
189
|
100
|
|
|
|
604
|
$data[1] = $data[0] if $data[1] == 0; |
|
604
|
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
# Ensure 2nd col is larger than first. Also for KB918419 bug. |
|
606
|
189
|
50
|
|
|
|
584
|
( $data[0], $data[1] ) = ( $data[1], $data[0] ) if $data[0] > $data[1]; |
|
607
|
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
# Check that cols are valid and store max and min values with default row. |
|
610
|
|
|
|
|
|
|
# NOTE: The check shouldn't modify the row dimensions and should only modify |
|
611
|
|
|
|
|
|
|
# the column dimensions in certain cases. |
|
612
|
189
|
|
|
|
|
390
|
my $ignore_row = 1; |
|
613
|
189
|
|
|
|
|
345
|
my $ignore_col = 1; |
|
614
|
189
|
100
|
|
|
|
646
|
$ignore_col = 0 if ref $data[3]; # Column has a format. |
|
615
|
189
|
100
|
100
|
|
|
1014
|
$ignore_col = 0 if $data[2] && $data[4]; # Column has a width but is hidden |
|
616
|
|
|
|
|
|
|
|
|
617
|
189
|
50
|
|
|
|
790
|
return -2 |
|
618
|
|
|
|
|
|
|
if $self->_check_dimensions( 0, $data[0], $ignore_row, $ignore_col ); |
|
619
|
189
|
50
|
|
|
|
668
|
return -2 |
|
620
|
|
|
|
|
|
|
if $self->_check_dimensions( 0, $data[1], $ignore_row, $ignore_col ); |
|
621
|
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
# Set the limits for the outline levels (0 <= x <= 7). |
|
623
|
189
|
100
|
|
|
|
729
|
$data[5] = 0 unless defined $data[5]; |
|
624
|
189
|
50
|
|
|
|
762
|
$data[5] = 0 if $data[5] < 0; |
|
625
|
189
|
50
|
|
|
|
830
|
$data[5] = 7 if $data[5] > 7; |
|
626
|
|
|
|
|
|
|
|
|
627
|
189
|
100
|
|
|
|
919
|
if ( $data[5] > $self->{_outline_col_level} ) { |
|
628
|
1
|
|
|
|
|
3
|
$self->{_outline_col_level} = $data[5]; |
|
629
|
|
|
|
|
|
|
} |
|
630
|
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
# Store the column data based on the first column. Padded for sorting. |
|
632
|
189
|
|
|
|
|
1458
|
$self->{_colinfo}->{ sprintf "%05d", $data[0] } = [@data]; |
|
633
|
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
# Store the column change to allow optimisations. |
|
635
|
189
|
|
|
|
|
1072
|
$self->{_col_size_changed} = 1; |
|
636
|
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
# Store the col sizes for use when calculating image vertices taking |
|
638
|
|
|
|
|
|
|
# hidden columns into account. Also store the column formats. |
|
639
|
189
|
|
|
|
|
681
|
my $width = $data[2]; |
|
640
|
189
|
|
|
|
|
421
|
my $format = $data[3]; |
|
641
|
189
|
|
100
|
|
|
762
|
my $hidden = $data[4] || 0; |
|
642
|
|
|
|
|
|
|
|
|
643
|
189
|
100
|
|
|
|
511
|
$width = $self->{_default_col_width} if !defined $width; |
|
644
|
|
|
|
|
|
|
|
|
645
|
189
|
|
|
|
|
523
|
my ( $firstcol, $lastcol ) = @data; |
|
646
|
|
|
|
|
|
|
|
|
647
|
189
|
|
|
|
|
643
|
foreach my $col ( $firstcol .. $lastcol ) { |
|
648
|
370
|
|
|
|
|
1047
|
$self->{_col_sizes}->{$col} = [$width, $hidden]; |
|
649
|
370
|
100
|
|
|
|
1468
|
$self->{_col_formats}->{$col} = $format if $format; |
|
650
|
|
|
|
|
|
|
} |
|
651
|
|
|
|
|
|
|
} |
|
652
|
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
############################################################################### |
|
655
|
|
|
|
|
|
|
# |
|
656
|
|
|
|
|
|
|
# set_selection() |
|
657
|
|
|
|
|
|
|
# |
|
658
|
|
|
|
|
|
|
# Set which cell or cells are selected in a worksheet. |
|
659
|
|
|
|
|
|
|
# |
|
660
|
|
|
|
|
|
|
sub set_selection { |
|
661
|
|
|
|
|
|
|
|
|
662
|
36
|
|
|
36
|
0
|
162
|
my $self = shift; |
|
663
|
36
|
|
|
|
|
103
|
my $pane; |
|
664
|
|
|
|
|
|
|
my $active_cell; |
|
665
|
36
|
|
|
|
|
0
|
my $sqref; |
|
666
|
|
|
|
|
|
|
|
|
667
|
36
|
50
|
|
|
|
98
|
return unless @_; |
|
668
|
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column. |
|
670
|
36
|
100
|
|
|
|
174
|
if ( $_[0] =~ /^\D/ ) { |
|
671
|
33
|
|
|
|
|
112
|
@_ = $self->_substitute_cellref( @_ ); |
|
672
|
|
|
|
|
|
|
} |
|
673
|
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
# There should be either 2 or 4 arguments. |
|
676
|
36
|
100
|
|
|
|
116
|
if ( @_ == 2 ) { |
|
|
|
50
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
# Single cell selection. |
|
679
|
28
|
|
|
|
|
114
|
$active_cell = xl_rowcol_to_cell( $_[0], $_[1] ); |
|
680
|
28
|
|
|
|
|
72
|
$sqref = $active_cell; |
|
681
|
|
|
|
|
|
|
} |
|
682
|
|
|
|
|
|
|
elsif ( @_ == 4 ) { |
|
683
|
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
# Range selection. |
|
685
|
8
|
|
|
|
|
25
|
$active_cell = xl_rowcol_to_cell( $_[0], $_[1] ); |
|
686
|
|
|
|
|
|
|
|
|
687
|
8
|
|
|
|
|
56
|
my ( $row_first, $col_first, $row_last, $col_last ) = @_; |
|
688
|
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
# Swap last row/col for first row/col as necessary |
|
690
|
8
|
100
|
|
|
|
21
|
if ( $row_first > $row_last ) { |
|
691
|
3
|
|
|
|
|
10
|
( $row_first, $row_last ) = ( $row_last, $row_first ); |
|
692
|
|
|
|
|
|
|
} |
|
693
|
|
|
|
|
|
|
|
|
694
|
8
|
100
|
|
|
|
26
|
if ( $col_first > $col_last ) { |
|
695
|
3
|
|
|
|
|
7
|
( $col_first, $col_last ) = ( $col_last, $col_first ); |
|
696
|
|
|
|
|
|
|
} |
|
697
|
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
# If the first and last cell are the same write a single cell. |
|
699
|
8
|
100
|
66
|
|
|
28
|
if ( ( $row_first == $row_last ) && ( $col_first == $col_last ) ) { |
|
700
|
1
|
|
|
|
|
2
|
$sqref = $active_cell; |
|
701
|
|
|
|
|
|
|
} |
|
702
|
|
|
|
|
|
|
else { |
|
703
|
7
|
|
|
|
|
21
|
$sqref = xl_range( $row_first, $row_last, $col_first, $col_last ); |
|
704
|
|
|
|
|
|
|
} |
|
705
|
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
} |
|
707
|
|
|
|
|
|
|
else { |
|
708
|
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
# User supplied wrong number or arguments. |
|
710
|
0
|
|
|
|
|
0
|
return; |
|
711
|
|
|
|
|
|
|
} |
|
712
|
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
# Selection isn't set for cell A1. |
|
714
|
36
|
100
|
|
|
|
105
|
return if $sqref eq 'A1'; |
|
715
|
|
|
|
|
|
|
|
|
716
|
32
|
|
|
|
|
149
|
$self->{_selections} = [ [ $pane, $active_cell, $sqref ] ]; |
|
717
|
|
|
|
|
|
|
} |
|
718
|
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
############################################################################### |
|
721
|
|
|
|
|
|
|
# |
|
722
|
|
|
|
|
|
|
# freeze_panes( $row, $col, $top_row, $left_col ) |
|
723
|
|
|
|
|
|
|
# |
|
724
|
|
|
|
|
|
|
# Set panes and mark them as frozen. |
|
725
|
|
|
|
|
|
|
# |
|
726
|
|
|
|
|
|
|
sub freeze_panes { |
|
727
|
|
|
|
|
|
|
|
|
728
|
66
|
|
|
66
|
0
|
370
|
my $self = shift; |
|
729
|
|
|
|
|
|
|
|
|
730
|
66
|
50
|
|
|
|
215
|
return unless @_; |
|
731
|
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column. |
|
733
|
66
|
100
|
|
|
|
260
|
if ( $_[0] =~ /^\D/ ) { |
|
734
|
10
|
|
|
|
|
33
|
@_ = $self->_substitute_cellref( @_ ); |
|
735
|
|
|
|
|
|
|
} |
|
736
|
|
|
|
|
|
|
|
|
737
|
66
|
|
|
|
|
140
|
my $row = shift; |
|
738
|
66
|
|
100
|
|
|
179
|
my $col = shift || 0; |
|
739
|
66
|
|
100
|
|
|
197
|
my $top_row = shift || $row; |
|
740
|
66
|
|
100
|
|
|
166
|
my $left_col = shift || $col; |
|
741
|
66
|
|
100
|
|
|
163
|
my $type = shift || 0; |
|
742
|
|
|
|
|
|
|
|
|
743
|
66
|
|
|
|
|
258
|
$self->{_panes} = [ $row, $col, $top_row, $left_col, $type ]; |
|
744
|
|
|
|
|
|
|
} |
|
745
|
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
############################################################################### |
|
748
|
|
|
|
|
|
|
# |
|
749
|
|
|
|
|
|
|
# split_panes( $y, $x, $top_row, $left_col ) |
|
750
|
|
|
|
|
|
|
# |
|
751
|
|
|
|
|
|
|
# Set panes and mark them as split. |
|
752
|
|
|
|
|
|
|
# |
|
753
|
|
|
|
|
|
|
# Implementers note. The API for this method doesn't map well from the XLS |
|
754
|
|
|
|
|
|
|
# file format and isn't sufficient to describe all cases of split panes. |
|
755
|
|
|
|
|
|
|
# It should probably be something like: |
|
756
|
|
|
|
|
|
|
# |
|
757
|
|
|
|
|
|
|
# split_panes( $y, $x, $top_row, $left_col, $offset_row, $offset_col ) |
|
758
|
|
|
|
|
|
|
# |
|
759
|
|
|
|
|
|
|
# I'll look at changing this if it becomes an issue. |
|
760
|
|
|
|
|
|
|
# |
|
761
|
|
|
|
|
|
|
sub split_panes { |
|
762
|
|
|
|
|
|
|
|
|
763
|
38
|
|
|
38
|
0
|
262
|
my $self = shift; |
|
764
|
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
# Call freeze panes but add the type flag for split panes. |
|
766
|
38
|
|
|
|
|
125
|
$self->freeze_panes( @_[ 0 .. 3 ], 2 ); |
|
767
|
|
|
|
|
|
|
} |
|
768
|
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
# Older method name for backwards compatibility. |
|
770
|
|
|
|
|
|
|
*thaw_panes = *split_panes; |
|
771
|
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
############################################################################### |
|
774
|
|
|
|
|
|
|
# |
|
775
|
|
|
|
|
|
|
# set_portrait() |
|
776
|
|
|
|
|
|
|
# |
|
777
|
|
|
|
|
|
|
# Set the page orientation as portrait. |
|
778
|
|
|
|
|
|
|
# |
|
779
|
|
|
|
|
|
|
sub set_portrait { |
|
780
|
|
|
|
|
|
|
|
|
781
|
2
|
|
|
2
|
0
|
26
|
my $self = shift; |
|
782
|
|
|
|
|
|
|
|
|
783
|
2
|
|
|
|
|
5
|
$self->{_orientation} = 1; |
|
784
|
2
|
|
|
|
|
14
|
$self->{_page_setup_changed} = 1; |
|
785
|
|
|
|
|
|
|
} |
|
786
|
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
############################################################################### |
|
789
|
|
|
|
|
|
|
# |
|
790
|
|
|
|
|
|
|
# set_landscape() |
|
791
|
|
|
|
|
|
|
# |
|
792
|
|
|
|
|
|
|
# Set the page orientation as landscape. |
|
793
|
|
|
|
|
|
|
# |
|
794
|
|
|
|
|
|
|
sub set_landscape { |
|
795
|
|
|
|
|
|
|
|
|
796
|
2
|
|
|
2
|
0
|
33
|
my $self = shift; |
|
797
|
|
|
|
|
|
|
|
|
798
|
2
|
|
|
|
|
5
|
$self->{_orientation} = 0; |
|
799
|
2
|
|
|
|
|
5
|
$self->{_page_setup_changed} = 1; |
|
800
|
|
|
|
|
|
|
} |
|
801
|
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
############################################################################### |
|
804
|
|
|
|
|
|
|
# |
|
805
|
|
|
|
|
|
|
# set_page_view() |
|
806
|
|
|
|
|
|
|
# |
|
807
|
|
|
|
|
|
|
# Set the page view mode for Mac Excel. |
|
808
|
|
|
|
|
|
|
# |
|
809
|
|
|
|
|
|
|
sub set_page_view { |
|
810
|
|
|
|
|
|
|
|
|
811
|
2
|
|
|
2
|
0
|
12
|
my $self = shift; |
|
812
|
|
|
|
|
|
|
|
|
813
|
2
|
50
|
|
|
|
14
|
$self->{_page_view} = defined $_[0] ? $_[0] : 1; |
|
814
|
|
|
|
|
|
|
} |
|
815
|
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
############################################################################### |
|
818
|
|
|
|
|
|
|
# |
|
819
|
|
|
|
|
|
|
# set_tab_color() |
|
820
|
|
|
|
|
|
|
# |
|
821
|
|
|
|
|
|
|
# Set the colour of the worksheet tab. |
|
822
|
|
|
|
|
|
|
# |
|
823
|
|
|
|
|
|
|
sub set_tab_color { |
|
824
|
|
|
|
|
|
|
|
|
825
|
4
|
|
|
4
|
0
|
96
|
my $self = shift; |
|
826
|
4
|
|
|
|
|
18
|
my $color = &Excel::Writer::XLSX::Format::_get_color( $_[0] ); |
|
827
|
|
|
|
|
|
|
|
|
828
|
4
|
|
|
|
|
14
|
$self->{_tab_color} = $color; |
|
829
|
|
|
|
|
|
|
} |
|
830
|
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
############################################################################### |
|
833
|
|
|
|
|
|
|
# |
|
834
|
|
|
|
|
|
|
# set_paper() |
|
835
|
|
|
|
|
|
|
# |
|
836
|
|
|
|
|
|
|
# Set the paper type. Ex. 1 = US Letter, 9 = A4 |
|
837
|
|
|
|
|
|
|
# |
|
838
|
|
|
|
|
|
|
sub set_paper { |
|
839
|
|
|
|
|
|
|
|
|
840
|
19
|
|
|
19
|
0
|
146
|
my $self = shift; |
|
841
|
19
|
|
|
|
|
41
|
my $paper_size = shift; |
|
842
|
|
|
|
|
|
|
|
|
843
|
19
|
50
|
|
|
|
70
|
if ( $paper_size ) { |
|
844
|
19
|
|
|
|
|
72
|
$self->{_paper_size} = $paper_size; |
|
845
|
19
|
|
|
|
|
55
|
$self->{_page_setup_changed} = 1; |
|
846
|
|
|
|
|
|
|
} |
|
847
|
|
|
|
|
|
|
} |
|
848
|
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
|
|
850
|
|
|
|
|
|
|
############################################################################### |
|
851
|
|
|
|
|
|
|
# |
|
852
|
|
|
|
|
|
|
# set_header() |
|
853
|
|
|
|
|
|
|
# |
|
854
|
|
|
|
|
|
|
# Set the page header caption and optional margin. |
|
855
|
|
|
|
|
|
|
# |
|
856
|
|
|
|
|
|
|
sub set_header { |
|
857
|
|
|
|
|
|
|
|
|
858
|
31
|
|
|
31
|
0
|
383
|
my $self = shift; |
|
859
|
31
|
|
100
|
|
|
131
|
my $string = $_[0] || ''; |
|
860
|
31
|
|
100
|
|
|
171
|
my $margin = $_[1] || 0.3; |
|
861
|
31
|
|
100
|
|
|
230
|
my $options = $_[2] || {}; |
|
862
|
|
|
|
|
|
|
|
|
863
|
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
# Replace the Excel placeholder &[Picture] with the internal &G. |
|
865
|
31
|
|
|
|
|
197
|
$string =~ s/&\[Picture\]/&G/g; |
|
866
|
|
|
|
|
|
|
|
|
867
|
31
|
50
|
|
|
|
119
|
if ( length $string >= 255 ) { |
|
868
|
0
|
|
|
|
|
0
|
carp 'Header string must be less than 255 characters'; |
|
869
|
0
|
|
|
|
|
0
|
return; |
|
870
|
|
|
|
|
|
|
} |
|
871
|
|
|
|
|
|
|
|
|
872
|
31
|
100
|
|
|
|
127
|
if ( defined $options->{align_with_margins} ) { |
|
873
|
1
|
|
|
|
|
9
|
$self->{_header_footer_aligns} = $options->{align_with_margins}; |
|
874
|
|
|
|
|
|
|
} |
|
875
|
|
|
|
|
|
|
|
|
876
|
31
|
100
|
|
|
|
102
|
if ( defined $options->{scale_with_doc} ) { |
|
877
|
1
|
|
|
|
|
7
|
$self->{_header_footer_scales} = $options->{scale_with_doc}; |
|
878
|
|
|
|
|
|
|
} |
|
879
|
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
# Reset the array in case the function is called more than once. |
|
881
|
31
|
|
|
|
|
157
|
$self->{_header_images} = []; |
|
882
|
|
|
|
|
|
|
|
|
883
|
31
|
100
|
|
|
|
111
|
if ( $options->{image_left} ) { |
|
884
|
21
|
|
|
|
|
62
|
push @{ $self->{_header_images} }, [ $options->{image_left}, 'LH' ]; |
|
|
21
|
|
|
|
|
106
|
|
|
885
|
|
|
|
|
|
|
} |
|
886
|
|
|
|
|
|
|
|
|
887
|
31
|
100
|
|
|
|
123
|
if ( $options->{image_center} ) { |
|
888
|
6
|
|
|
|
|
20
|
push @{ $self->{_header_images} }, [ $options->{image_center}, 'CH' ]; |
|
|
6
|
|
|
|
|
24
|
|
|
889
|
|
|
|
|
|
|
} |
|
890
|
|
|
|
|
|
|
|
|
891
|
31
|
100
|
|
|
|
133
|
if ( $options->{image_right} ) { |
|
892
|
5
|
|
|
|
|
9
|
push @{ $self->{_header_images} }, [ $options->{image_right}, 'RH' ]; |
|
|
5
|
|
|
|
|
16
|
|
|
893
|
|
|
|
|
|
|
} |
|
894
|
|
|
|
|
|
|
|
|
895
|
31
|
|
|
|
|
187
|
my $placeholder_count = () = $string =~ /&G/g; |
|
896
|
31
|
|
|
|
|
68
|
my $image_count = @{ $self->{_header_images} }; |
|
|
31
|
|
|
|
|
102
|
|
|
897
|
|
|
|
|
|
|
|
|
898
|
31
|
50
|
|
|
|
126
|
if ( $image_count != $placeholder_count ) { |
|
899
|
0
|
|
|
|
|
0
|
warn "Number of header images ($image_count) doesn't match placeholder " |
|
900
|
|
|
|
|
|
|
. "count ($placeholder_count) in string: $string\n"; |
|
901
|
0
|
|
|
|
|
0
|
$self->{_header_images} = []; |
|
902
|
0
|
|
|
|
|
0
|
return; |
|
903
|
|
|
|
|
|
|
} |
|
904
|
|
|
|
|
|
|
|
|
905
|
31
|
100
|
|
|
|
105
|
if ( $image_count ) { |
|
906
|
21
|
|
|
|
|
95
|
$self->{_has_header_vml} = 1; |
|
907
|
|
|
|
|
|
|
} |
|
908
|
|
|
|
|
|
|
|
|
909
|
31
|
|
|
|
|
98
|
$self->{_header} = $string; |
|
910
|
31
|
|
|
|
|
70
|
$self->{_margin_header} = $margin; |
|
911
|
31
|
|
|
|
|
110
|
$self->{_header_footer_changed} = 1; |
|
912
|
|
|
|
|
|
|
} |
|
913
|
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
############################################################################### |
|
916
|
|
|
|
|
|
|
# |
|
917
|
|
|
|
|
|
|
# set_footer() |
|
918
|
|
|
|
|
|
|
# |
|
919
|
|
|
|
|
|
|
# Set the page footer caption and optional margin. |
|
920
|
|
|
|
|
|
|
# |
|
921
|
|
|
|
|
|
|
sub set_footer { |
|
922
|
|
|
|
|
|
|
|
|
923
|
15
|
|
|
15
|
0
|
192
|
my $self = shift; |
|
924
|
15
|
|
100
|
|
|
56
|
my $string = $_[0] || ''; |
|
925
|
15
|
|
100
|
|
|
82
|
my $margin = $_[1] || 0.3; |
|
926
|
15
|
|
100
|
|
|
73
|
my $options = $_[2] || {}; |
|
927
|
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
# Replace the Excel placeholder &[Picture] with the internal &G. |
|
930
|
15
|
|
|
|
|
43
|
$string =~ s/&\[Picture\]/&G/g; |
|
931
|
|
|
|
|
|
|
|
|
932
|
15
|
50
|
|
|
|
52
|
if ( length $string >= 255 ) { |
|
933
|
0
|
|
|
|
|
0
|
carp 'Footer string must be less than 255 characters'; |
|
934
|
0
|
|
|
|
|
0
|
return; |
|
935
|
|
|
|
|
|
|
} |
|
936
|
|
|
|
|
|
|
|
|
937
|
15
|
100
|
|
|
|
68
|
if ( defined $options->{align_with_margins} ) { |
|
938
|
1
|
|
|
|
|
6
|
$self->{_header_footer_aligns} = $options->{align_with_margins}; |
|
939
|
|
|
|
|
|
|
} |
|
940
|
|
|
|
|
|
|
|
|
941
|
15
|
100
|
|
|
|
60
|
if ( defined $options->{scale_with_doc} ) { |
|
942
|
1
|
|
|
|
|
4
|
$self->{_header_footer_scales} = $options->{scale_with_doc}; |
|
943
|
|
|
|
|
|
|
} |
|
944
|
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
# Reset the array in case the function is called more than once. |
|
946
|
15
|
|
|
|
|
45
|
$self->{_footer_images} = []; |
|
947
|
|
|
|
|
|
|
|
|
948
|
15
|
100
|
|
|
|
49
|
if ( $options->{image_left} ) { |
|
949
|
4
|
|
|
|
|
9
|
push @{ $self->{_footer_images} }, [ $options->{image_left}, 'LF' ]; |
|
|
4
|
|
|
|
|
18
|
|
|
950
|
|
|
|
|
|
|
} |
|
951
|
|
|
|
|
|
|
|
|
952
|
15
|
100
|
|
|
|
58
|
if ( $options->{image_center} ) { |
|
953
|
3
|
|
|
|
|
7
|
push @{ $self->{_footer_images} }, [ $options->{image_center}, 'CF' ]; |
|
|
3
|
|
|
|
|
101
|
|
|
954
|
|
|
|
|
|
|
} |
|
955
|
|
|
|
|
|
|
|
|
956
|
15
|
100
|
|
|
|
59
|
if ( $options->{image_right} ) { |
|
957
|
5
|
|
|
|
|
9
|
push @{ $self->{_footer_images} }, [ $options->{image_right}, 'RF' ]; |
|
|
5
|
|
|
|
|
19
|
|
|
958
|
|
|
|
|
|
|
} |
|
959
|
|
|
|
|
|
|
|
|
960
|
15
|
|
|
|
|
64
|
my $placeholder_count = () = $string =~ /&G/g; |
|
961
|
15
|
|
|
|
|
39
|
my $image_count = @{ $self->{_footer_images} }; |
|
|
15
|
|
|
|
|
120
|
|
|
962
|
|
|
|
|
|
|
|
|
963
|
15
|
50
|
|
|
|
59
|
if ( $image_count != $placeholder_count ) { |
|
964
|
0
|
|
|
|
|
0
|
warn "Number of footer images ($image_count) doesn't match placeholder " |
|
965
|
|
|
|
|
|
|
. "count ($placeholder_count) in string: $string\n"; |
|
966
|
0
|
|
|
|
|
0
|
$self->{_footer_images} = []; |
|
967
|
0
|
|
|
|
|
0
|
return; |
|
968
|
|
|
|
|
|
|
} |
|
969
|
|
|
|
|
|
|
|
|
970
|
15
|
100
|
|
|
|
47
|
if ( $image_count ) { |
|
971
|
6
|
|
|
|
|
14
|
$self->{_has_header_vml} = 1; |
|
972
|
|
|
|
|
|
|
} |
|
973
|
|
|
|
|
|
|
|
|
974
|
15
|
|
|
|
|
36
|
$self->{_footer} = $string; |
|
975
|
15
|
|
|
|
|
30
|
$self->{_margin_footer} = $margin; |
|
976
|
15
|
|
|
|
|
71
|
$self->{_header_footer_changed} = 1; |
|
977
|
|
|
|
|
|
|
} |
|
978
|
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
############################################################################### |
|
981
|
|
|
|
|
|
|
# |
|
982
|
|
|
|
|
|
|
# center_horizontally() |
|
983
|
|
|
|
|
|
|
# |
|
984
|
|
|
|
|
|
|
# Center the page horizontally. |
|
985
|
|
|
|
|
|
|
# |
|
986
|
|
|
|
|
|
|
sub center_horizontally { |
|
987
|
|
|
|
|
|
|
|
|
988
|
4
|
|
|
4
|
0
|
53
|
my $self = shift; |
|
989
|
|
|
|
|
|
|
|
|
990
|
4
|
|
|
|
|
12
|
$self->{_print_options_changed} = 1; |
|
991
|
4
|
|
|
|
|
9
|
$self->{_hcenter} = 1; |
|
992
|
|
|
|
|
|
|
} |
|
993
|
|
|
|
|
|
|
|
|
994
|
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
############################################################################### |
|
996
|
|
|
|
|
|
|
# |
|
997
|
|
|
|
|
|
|
# center_vertically() |
|
998
|
|
|
|
|
|
|
# |
|
999
|
|
|
|
|
|
|
# Center the page horizontally. |
|
1000
|
|
|
|
|
|
|
# |
|
1001
|
|
|
|
|
|
|
sub center_vertically { |
|
1002
|
|
|
|
|
|
|
|
|
1003
|
4
|
|
|
4
|
0
|
34
|
my $self = shift; |
|
1004
|
|
|
|
|
|
|
|
|
1005
|
4
|
|
|
|
|
19
|
$self->{_print_options_changed} = 1; |
|
1006
|
4
|
|
|
|
|
11
|
$self->{_vcenter} = 1; |
|
1007
|
|
|
|
|
|
|
} |
|
1008
|
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
|
|
1010
|
|
|
|
|
|
|
############################################################################### |
|
1011
|
|
|
|
|
|
|
# |
|
1012
|
|
|
|
|
|
|
# set_margins() |
|
1013
|
|
|
|
|
|
|
# |
|
1014
|
|
|
|
|
|
|
# Set all the page margins to the same value in inches. |
|
1015
|
|
|
|
|
|
|
# |
|
1016
|
|
|
|
|
|
|
sub set_margins { |
|
1017
|
|
|
|
|
|
|
|
|
1018
|
2
|
|
|
2
|
0
|
50
|
my $self = shift; |
|
1019
|
|
|
|
|
|
|
|
|
1020
|
2
|
|
|
|
|
8
|
$self->set_margin_left( $_[0] ); |
|
1021
|
2
|
|
|
|
|
8
|
$self->set_margin_right( $_[0] ); |
|
1022
|
2
|
|
|
|
|
5
|
$self->set_margin_top( $_[0] ); |
|
1023
|
2
|
|
|
|
|
6
|
$self->set_margin_bottom( $_[0] ); |
|
1024
|
|
|
|
|
|
|
} |
|
1025
|
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
############################################################################### |
|
1028
|
|
|
|
|
|
|
# |
|
1029
|
|
|
|
|
|
|
# set_margins_LR() |
|
1030
|
|
|
|
|
|
|
# |
|
1031
|
|
|
|
|
|
|
# Set the left and right margins to the same value in inches. |
|
1032
|
|
|
|
|
|
|
# |
|
1033
|
|
|
|
|
|
|
sub set_margins_LR { |
|
1034
|
|
|
|
|
|
|
|
|
1035
|
1
|
|
|
1
|
0
|
24
|
my $self = shift; |
|
1036
|
|
|
|
|
|
|
|
|
1037
|
1
|
|
|
|
|
5
|
$self->set_margin_left( $_[0] ); |
|
1038
|
1
|
|
|
|
|
3
|
$self->set_margin_right( $_[0] ); |
|
1039
|
|
|
|
|
|
|
} |
|
1040
|
|
|
|
|
|
|
|
|
1041
|
|
|
|
|
|
|
|
|
1042
|
|
|
|
|
|
|
############################################################################### |
|
1043
|
|
|
|
|
|
|
# |
|
1044
|
|
|
|
|
|
|
# set_margins_TB() |
|
1045
|
|
|
|
|
|
|
# |
|
1046
|
|
|
|
|
|
|
# Set the top and bottom margins to the same value in inches. |
|
1047
|
|
|
|
|
|
|
# |
|
1048
|
|
|
|
|
|
|
sub set_margins_TB { |
|
1049
|
|
|
|
|
|
|
|
|
1050
|
1
|
|
|
1
|
0
|
28
|
my $self = shift; |
|
1051
|
|
|
|
|
|
|
|
|
1052
|
1
|
|
|
|
|
5
|
$self->set_margin_top( $_[0] ); |
|
1053
|
1
|
|
|
|
|
4
|
$self->set_margin_bottom( $_[0] ); |
|
1054
|
|
|
|
|
|
|
} |
|
1055
|
|
|
|
|
|
|
|
|
1056
|
|
|
|
|
|
|
|
|
1057
|
|
|
|
|
|
|
############################################################################### |
|
1058
|
|
|
|
|
|
|
# |
|
1059
|
|
|
|
|
|
|
# set_margin_left() |
|
1060
|
|
|
|
|
|
|
# |
|
1061
|
|
|
|
|
|
|
# Set the left margin in inches. |
|
1062
|
|
|
|
|
|
|
# |
|
1063
|
|
|
|
|
|
|
sub set_margin_left { |
|
1064
|
|
|
|
|
|
|
|
|
1065
|
5
|
|
|
5
|
0
|
87
|
my $self = shift; |
|
1066
|
5
|
|
|
|
|
11
|
my $margin = shift; |
|
1067
|
5
|
|
|
|
|
17
|
my $default = 0.7; |
|
1068
|
|
|
|
|
|
|
|
|
1069
|
|
|
|
|
|
|
# Add 0 to ensure the argument is numeric. |
|
1070
|
5
|
50
|
|
|
|
18
|
if ( defined $margin ) { $margin = 0 + $margin } |
|
|
5
|
|
|
|
|
16
|
|
|
1071
|
0
|
|
|
|
|
0
|
else { $margin = $default } |
|
1072
|
|
|
|
|
|
|
|
|
1073
|
5
|
|
|
|
|
14
|
$self->{_margin_left} = $margin; |
|
1074
|
|
|
|
|
|
|
} |
|
1075
|
|
|
|
|
|
|
|
|
1076
|
|
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
############################################################################### |
|
1078
|
|
|
|
|
|
|
# |
|
1079
|
|
|
|
|
|
|
# set_margin_right() |
|
1080
|
|
|
|
|
|
|
# |
|
1081
|
|
|
|
|
|
|
# Set the right margin in inches. |
|
1082
|
|
|
|
|
|
|
# |
|
1083
|
|
|
|
|
|
|
sub set_margin_right { |
|
1084
|
|
|
|
|
|
|
|
|
1085
|
5
|
|
|
5
|
0
|
33
|
my $self = shift; |
|
1086
|
5
|
|
|
|
|
8
|
my $margin = shift; |
|
1087
|
5
|
|
|
|
|
8
|
my $default = 0.7; |
|
1088
|
|
|
|
|
|
|
|
|
1089
|
|
|
|
|
|
|
# Add 0 to ensure the argument is numeric. |
|
1090
|
5
|
50
|
|
|
|
12
|
if ( defined $margin ) { $margin = 0 + $margin } |
|
|
5
|
|
|
|
|
10
|
|
|
1091
|
0
|
|
|
|
|
0
|
else { $margin = $default } |
|
1092
|
|
|
|
|
|
|
|
|
1093
|
5
|
|
|
|
|
13
|
$self->{_margin_right} = $margin; |
|
1094
|
|
|
|
|
|
|
} |
|
1095
|
|
|
|
|
|
|
|
|
1096
|
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
############################################################################### |
|
1098
|
|
|
|
|
|
|
# |
|
1099
|
|
|
|
|
|
|
# set_margin_top() |
|
1100
|
|
|
|
|
|
|
# |
|
1101
|
|
|
|
|
|
|
# Set the top margin in inches. |
|
1102
|
|
|
|
|
|
|
# |
|
1103
|
|
|
|
|
|
|
sub set_margin_top { |
|
1104
|
|
|
|
|
|
|
|
|
1105
|
5
|
|
|
5
|
0
|
35
|
my $self = shift; |
|
1106
|
5
|
|
|
|
|
8
|
my $margin = shift; |
|
1107
|
5
|
|
|
|
|
10
|
my $default = 0.75; |
|
1108
|
|
|
|
|
|
|
|
|
1109
|
|
|
|
|
|
|
# Add 0 to ensure the argument is numeric. |
|
1110
|
5
|
50
|
|
|
|
13
|
if ( defined $margin ) { $margin = 0 + $margin } |
|
|
5
|
|
|
|
|
12
|
|
|
1111
|
0
|
|
|
|
|
0
|
else { $margin = $default } |
|
1112
|
|
|
|
|
|
|
|
|
1113
|
5
|
|
|
|
|
12
|
$self->{_margin_top} = $margin; |
|
1114
|
|
|
|
|
|
|
} |
|
1115
|
|
|
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
|
|
1117
|
|
|
|
|
|
|
############################################################################### |
|
1118
|
|
|
|
|
|
|
# |
|
1119
|
|
|
|
|
|
|
# set_margin_bottom() |
|
1120
|
|
|
|
|
|
|
# |
|
1121
|
|
|
|
|
|
|
# Set the bottom margin in inches. |
|
1122
|
|
|
|
|
|
|
# |
|
1123
|
|
|
|
|
|
|
sub set_margin_bottom { |
|
1124
|
|
|
|
|
|
|
|
|
1125
|
|
|
|
|
|
|
|
|
1126
|
5
|
|
|
5
|
0
|
32
|
my $self = shift; |
|
1127
|
5
|
|
|
|
|
12
|
my $margin = shift; |
|
1128
|
5
|
|
|
|
|
7
|
my $default = 0.75; |
|
1129
|
|
|
|
|
|
|
|
|
1130
|
|
|
|
|
|
|
# Add 0 to ensure the argument is numeric. |
|
1131
|
5
|
50
|
|
|
|
13
|
if ( defined $margin ) { $margin = 0 + $margin } |
|
|
5
|
|
|
|
|
9
|
|
|
1132
|
0
|
|
|
|
|
0
|
else { $margin = $default } |
|
1133
|
|
|
|
|
|
|
|
|
1134
|
5
|
|
|
|
|
14
|
$self->{_margin_bottom} = $margin; |
|
1135
|
|
|
|
|
|
|
} |
|
1136
|
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
############################################################################### |
|
1139
|
|
|
|
|
|
|
# |
|
1140
|
|
|
|
|
|
|
# repeat_rows($first_row, $last_row) |
|
1141
|
|
|
|
|
|
|
# |
|
1142
|
|
|
|
|
|
|
# Set the rows to repeat at the top of each printed page. |
|
1143
|
|
|
|
|
|
|
# |
|
1144
|
|
|
|
|
|
|
sub repeat_rows { |
|
1145
|
|
|
|
|
|
|
|
|
1146
|
6
|
|
|
6
|
0
|
37
|
my $self = shift; |
|
1147
|
|
|
|
|
|
|
|
|
1148
|
6
|
|
|
|
|
12
|
my $row_min = $_[0]; |
|
1149
|
6
|
|
66
|
|
|
33
|
my $row_max = $_[1] || $_[0]; # Second row is optional |
|
1150
|
|
|
|
|
|
|
|
|
1151
|
|
|
|
|
|
|
|
|
1152
|
|
|
|
|
|
|
# Convert to 1 based. |
|
1153
|
6
|
|
|
|
|
12
|
$row_min++; |
|
1154
|
6
|
|
|
|
|
20
|
$row_max++; |
|
1155
|
|
|
|
|
|
|
|
|
1156
|
6
|
|
|
|
|
34
|
my $area = '$' . $row_min . ':' . '$' . $row_max; |
|
1157
|
|
|
|
|
|
|
|
|
1158
|
|
|
|
|
|
|
# Build up the print titles "Sheet1!$1:$2" |
|
1159
|
6
|
|
|
|
|
38
|
my $sheetname = quote_sheetname( $self->{_name} ); |
|
1160
|
6
|
|
|
|
|
20
|
$area = $sheetname . "!" . $area; |
|
1161
|
|
|
|
|
|
|
|
|
1162
|
6
|
|
|
|
|
20
|
$self->{_repeat_rows} = $area; |
|
1163
|
|
|
|
|
|
|
} |
|
1164
|
|
|
|
|
|
|
|
|
1165
|
|
|
|
|
|
|
|
|
1166
|
|
|
|
|
|
|
############################################################################### |
|
1167
|
|
|
|
|
|
|
# |
|
1168
|
|
|
|
|
|
|
# repeat_columns($first_col, $last_col) |
|
1169
|
|
|
|
|
|
|
# |
|
1170
|
|
|
|
|
|
|
# Set the columns to repeat at the left hand side of each printed page. This is |
|
1171
|
|
|
|
|
|
|
# stored as a element. |
|
1172
|
|
|
|
|
|
|
# |
|
1173
|
|
|
|
|
|
|
sub repeat_columns { |
|
1174
|
|
|
|
|
|
|
|
|
1175
|
3
|
|
|
3
|
0
|
16
|
my $self = shift; |
|
1176
|
|
|
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
1178
|
3
|
50
|
|
|
|
36
|
if ( $_[0] =~ /^\D/ ) { |
|
1179
|
3
|
|
|
|
|
23
|
@_ = $self->_substitute_cellref( @_ ); |
|
1180
|
|
|
|
|
|
|
|
|
1181
|
|
|
|
|
|
|
# Returned values $row1 and $row2 aren't required here. Remove them. |
|
1182
|
3
|
|
|
|
|
6
|
shift @_; # $row1 |
|
1183
|
3
|
|
|
|
|
6
|
splice @_, 1, 1; # $row2 |
|
1184
|
|
|
|
|
|
|
} |
|
1185
|
|
|
|
|
|
|
|
|
1186
|
3
|
|
|
|
|
7
|
my $col_min = $_[0]; |
|
1187
|
3
|
|
66
|
|
|
31
|
my $col_max = $_[1] || $_[0]; # Second col is optional |
|
1188
|
|
|
|
|
|
|
|
|
1189
|
|
|
|
|
|
|
# Convert to A notation. |
|
1190
|
3
|
|
|
|
|
16
|
$col_min = xl_col_to_name( $_[0], 1 ); |
|
1191
|
3
|
|
|
|
|
9
|
$col_max = xl_col_to_name( $_[1], 1 ); |
|
1192
|
|
|
|
|
|
|
|
|
1193
|
3
|
|
|
|
|
9
|
my $area = $col_min . ':' . $col_max; |
|
1194
|
|
|
|
|
|
|
|
|
1195
|
|
|
|
|
|
|
# Build up the print area range "=Sheet2!C1:C2" |
|
1196
|
3
|
|
|
|
|
11
|
my $sheetname = quote_sheetname( $self->{_name} ); |
|
1197
|
3
|
|
|
|
|
9
|
$area = $sheetname . "!" . $area; |
|
1198
|
|
|
|
|
|
|
|
|
1199
|
3
|
|
|
|
|
12
|
$self->{_repeat_cols} = $area; |
|
1200
|
|
|
|
|
|
|
} |
|
1201
|
|
|
|
|
|
|
|
|
1202
|
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
############################################################################### |
|
1204
|
|
|
|
|
|
|
# |
|
1205
|
|
|
|
|
|
|
# print_area($first_row, $first_col, $last_row, $last_col) |
|
1206
|
|
|
|
|
|
|
# |
|
1207
|
|
|
|
|
|
|
# Set the print area in the current worksheet. This is stored as a |
|
1208
|
|
|
|
|
|
|
# element. |
|
1209
|
|
|
|
|
|
|
# |
|
1210
|
|
|
|
|
|
|
sub print_area { |
|
1211
|
|
|
|
|
|
|
|
|
1212
|
9
|
|
|
9
|
0
|
59
|
my $self = shift; |
|
1213
|
|
|
|
|
|
|
|
|
1214
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
1215
|
9
|
50
|
|
|
|
55
|
if ( $_[0] =~ /^\D/ ) { |
|
1216
|
9
|
|
|
|
|
50
|
@_ = $self->_substitute_cellref( @_ ); |
|
1217
|
|
|
|
|
|
|
} |
|
1218
|
|
|
|
|
|
|
|
|
1219
|
9
|
50
|
|
|
|
38
|
return if @_ != 4; # Require 4 parameters |
|
1220
|
|
|
|
|
|
|
|
|
1221
|
9
|
|
|
|
|
40
|
my ( $row1, $col1, $row2, $col2 ) = @_; |
|
1222
|
|
|
|
|
|
|
|
|
1223
|
|
|
|
|
|
|
# Ignore max print area since this is the same as no print area for Excel. |
|
1224
|
9
|
100
|
33
|
|
|
145
|
if ( $row1 == 0 |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1225
|
|
|
|
|
|
|
and $col1 == 0 |
|
1226
|
|
|
|
|
|
|
and $row2 == $self->{_xls_rowmax} - 1 |
|
1227
|
|
|
|
|
|
|
and $col2 == $self->{_xls_colmax} - 1 ) |
|
1228
|
|
|
|
|
|
|
{ |
|
1229
|
1
|
|
|
|
|
4
|
return; |
|
1230
|
|
|
|
|
|
|
} |
|
1231
|
|
|
|
|
|
|
|
|
1232
|
|
|
|
|
|
|
# Build up the print area range "=Sheet2!R1C1:R2C1" |
|
1233
|
8
|
|
|
|
|
38
|
my $area = $self->_convert_name_area( $row1, $col1, $row2, $col2 ); |
|
1234
|
|
|
|
|
|
|
|
|
1235
|
8
|
|
|
|
|
39
|
$self->{_print_area} = $area; |
|
1236
|
|
|
|
|
|
|
} |
|
1237
|
|
|
|
|
|
|
|
|
1238
|
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
############################################################################### |
|
1240
|
|
|
|
|
|
|
# |
|
1241
|
|
|
|
|
|
|
# autofilter($first_row, $first_col, $last_row, $last_col) |
|
1242
|
|
|
|
|
|
|
# |
|
1243
|
|
|
|
|
|
|
# Set the autofilter area in the worksheet. |
|
1244
|
|
|
|
|
|
|
# |
|
1245
|
|
|
|
|
|
|
sub autofilter { |
|
1246
|
|
|
|
|
|
|
|
|
1247
|
32
|
|
|
32
|
0
|
696
|
my $self = shift; |
|
1248
|
|
|
|
|
|
|
|
|
1249
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
1250
|
32
|
100
|
|
|
|
172
|
if ( $_[0] =~ /^\D/ ) { |
|
1251
|
30
|
|
|
|
|
105
|
@_ = $self->_substitute_cellref( @_ ); |
|
1252
|
|
|
|
|
|
|
} |
|
1253
|
|
|
|
|
|
|
|
|
1254
|
32
|
50
|
|
|
|
105
|
return if @_ != 4; # Require 4 parameters |
|
1255
|
|
|
|
|
|
|
|
|
1256
|
32
|
|
|
|
|
89
|
my ( $row1, $col1, $row2, $col2 ) = @_; |
|
1257
|
|
|
|
|
|
|
|
|
1258
|
|
|
|
|
|
|
# Reverse max and min values if necessary. |
|
1259
|
32
|
50
|
|
|
|
86
|
( $row1, $row2 ) = ( $row2, $row1 ) if $row2 < $row1; |
|
1260
|
32
|
50
|
|
|
|
77
|
( $col1, $col2 ) = ( $col2, $col1 ) if $col2 < $col1; |
|
1261
|
|
|
|
|
|
|
|
|
1262
|
|
|
|
|
|
|
# Build up the print area range "Sheet1!$A$1:$C$13". |
|
1263
|
32
|
|
|
|
|
106
|
my $area = $self->_convert_name_area( $row1, $col1, $row2, $col2 ); |
|
1264
|
32
|
|
|
|
|
101
|
my $ref = xl_range( $row1, $row2, $col1, $col2 ); |
|
1265
|
|
|
|
|
|
|
|
|
1266
|
32
|
|
|
|
|
78
|
$self->{_autofilter} = $area; |
|
1267
|
32
|
|
|
|
|
67
|
$self->{_autofilter_ref} = $ref; |
|
1268
|
32
|
|
|
|
|
124
|
$self->{_filter_range} = [ $col1, $col2 ]; |
|
1269
|
|
|
|
|
|
|
} |
|
1270
|
|
|
|
|
|
|
|
|
1271
|
|
|
|
|
|
|
|
|
1272
|
|
|
|
|
|
|
############################################################################### |
|
1273
|
|
|
|
|
|
|
# |
|
1274
|
|
|
|
|
|
|
# filter_column($column, $criteria, ...) |
|
1275
|
|
|
|
|
|
|
# |
|
1276
|
|
|
|
|
|
|
# Set the column filter criteria. |
|
1277
|
|
|
|
|
|
|
# |
|
1278
|
|
|
|
|
|
|
sub filter_column { |
|
1279
|
|
|
|
|
|
|
|
|
1280
|
25
|
|
|
25
|
0
|
129
|
my $self = shift; |
|
1281
|
25
|
|
|
|
|
47
|
my $col = $_[0]; |
|
1282
|
25
|
|
|
|
|
41
|
my $expression = $_[1]; |
|
1283
|
|
|
|
|
|
|
|
|
1284
|
|
|
|
|
|
|
croak "Must call autofilter() before filter_column()" |
|
1285
|
25
|
50
|
|
|
|
65
|
unless $self->{_autofilter}; |
|
1286
|
25
|
50
|
|
|
|
72
|
croak "Incorrect number of arguments to filter_column()" |
|
1287
|
|
|
|
|
|
|
unless @_ == 2; |
|
1288
|
|
|
|
|
|
|
|
|
1289
|
|
|
|
|
|
|
|
|
1290
|
|
|
|
|
|
|
# Check for a column reference in A1 notation and substitute. |
|
1291
|
25
|
100
|
|
|
|
106
|
if ( $col =~ /^\D/ ) { |
|
1292
|
24
|
|
|
|
|
64
|
my $col_letter = $col; |
|
1293
|
|
|
|
|
|
|
|
|
1294
|
|
|
|
|
|
|
# Convert col ref to a cell ref and then to a col number. |
|
1295
|
24
|
|
|
|
|
139
|
( undef, $col ) = $self->_substitute_cellref( $col . '1' ); |
|
1296
|
|
|
|
|
|
|
|
|
1297
|
24
|
50
|
|
|
|
91
|
croak "Invalid column '$col_letter'" if $col >= $self->{_xls_colmax}; |
|
1298
|
|
|
|
|
|
|
} |
|
1299
|
|
|
|
|
|
|
|
|
1300
|
25
|
|
|
|
|
39
|
my ( $col_first, $col_last ) = @{ $self->{_filter_range} }; |
|
|
25
|
|
|
|
|
73
|
|
|
1301
|
|
|
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
# Reject column if it is outside filter range. |
|
1303
|
25
|
50
|
33
|
|
|
138
|
if ( $col < $col_first or $col > $col_last ) { |
|
1304
|
0
|
|
|
|
|
0
|
croak "Column '$col' outside autofilter() column range " |
|
1305
|
|
|
|
|
|
|
. "($col_first .. $col_last)"; |
|
1306
|
|
|
|
|
|
|
} |
|
1307
|
|
|
|
|
|
|
|
|
1308
|
|
|
|
|
|
|
|
|
1309
|
25
|
|
|
|
|
83
|
my @tokens = $self->_extract_filter_tokens( $expression ); |
|
1310
|
|
|
|
|
|
|
|
|
1311
|
25
|
50
|
66
|
|
|
99
|
croak "Incorrect number of tokens in expression '$expression'" |
|
1312
|
|
|
|
|
|
|
unless ( @tokens == 3 or @tokens == 7 ); |
|
1313
|
|
|
|
|
|
|
|
|
1314
|
|
|
|
|
|
|
|
|
1315
|
25
|
|
|
|
|
83
|
@tokens = $self->_parse_filter_expression( $expression, @tokens ); |
|
1316
|
|
|
|
|
|
|
|
|
1317
|
|
|
|
|
|
|
# Excel handles single or double custom filters as default filters. We need |
|
1318
|
|
|
|
|
|
|
# to check for them and handle them accordingly. |
|
1319
|
25
|
100
|
100
|
|
|
210
|
if ( @tokens == 2 && $tokens[0] == 2 ) { |
|
|
|
100
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
1320
|
|
|
|
|
|
|
|
|
1321
|
|
|
|
|
|
|
# Single equality. |
|
1322
|
6
|
|
|
|
|
34
|
$self->filter_column_list( $col, $tokens[1] ); |
|
1323
|
|
|
|
|
|
|
} |
|
1324
|
|
|
|
|
|
|
elsif (@tokens == 5 |
|
1325
|
|
|
|
|
|
|
&& $tokens[0] == 2 |
|
1326
|
|
|
|
|
|
|
&& $tokens[2] == 1 |
|
1327
|
|
|
|
|
|
|
&& $tokens[3] == 2 ) |
|
1328
|
|
|
|
|
|
|
{ |
|
1329
|
|
|
|
|
|
|
|
|
1330
|
|
|
|
|
|
|
# Double equality with "or" operator. |
|
1331
|
3
|
|
|
|
|
15
|
$self->filter_column_list( $col, $tokens[1], $tokens[4] ); |
|
1332
|
|
|
|
|
|
|
} |
|
1333
|
|
|
|
|
|
|
else { |
|
1334
|
|
|
|
|
|
|
|
|
1335
|
|
|
|
|
|
|
# Non default custom filter. |
|
1336
|
16
|
|
|
|
|
54
|
$self->{_filter_cols}->{$col} = [@tokens]; |
|
1337
|
16
|
|
|
|
|
43
|
$self->{_filter_type}->{$col} = 0; |
|
1338
|
|
|
|
|
|
|
|
|
1339
|
|
|
|
|
|
|
} |
|
1340
|
|
|
|
|
|
|
|
|
1341
|
25
|
|
|
|
|
87
|
$self->{_filter_on} = 1; |
|
1342
|
|
|
|
|
|
|
} |
|
1343
|
|
|
|
|
|
|
|
|
1344
|
|
|
|
|
|
|
|
|
1345
|
|
|
|
|
|
|
############################################################################### |
|
1346
|
|
|
|
|
|
|
# |
|
1347
|
|
|
|
|
|
|
# filter_column_list($column, @matches ) |
|
1348
|
|
|
|
|
|
|
# |
|
1349
|
|
|
|
|
|
|
# Set the column filter criteria in Excel 2007 list style. |
|
1350
|
|
|
|
|
|
|
# |
|
1351
|
|
|
|
|
|
|
sub filter_column_list { |
|
1352
|
|
|
|
|
|
|
|
|
1353
|
14
|
|
|
14
|
0
|
51
|
my $self = shift; |
|
1354
|
14
|
|
|
|
|
27
|
my $col = shift; |
|
1355
|
14
|
|
|
|
|
42
|
my @tokens = @_; |
|
1356
|
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
croak "Must call autofilter() before filter_column_list()" |
|
1358
|
14
|
50
|
|
|
|
44
|
unless $self->{_autofilter}; |
|
1359
|
14
|
50
|
|
|
|
43
|
croak "Incorrect number of arguments to filter_column_list()" |
|
1360
|
|
|
|
|
|
|
unless @tokens; |
|
1361
|
|
|
|
|
|
|
|
|
1362
|
|
|
|
|
|
|
# Check for a column reference in A1 notation and substitute. |
|
1363
|
14
|
100
|
|
|
|
69
|
if ( $col =~ /^\D/ ) { |
|
1364
|
5
|
|
|
|
|
12
|
my $col_letter = $col; |
|
1365
|
|
|
|
|
|
|
|
|
1366
|
|
|
|
|
|
|
# Convert col ref to a cell ref and then to a col number. |
|
1367
|
5
|
|
|
|
|
28
|
( undef, $col ) = $self->_substitute_cellref( $col . '1' ); |
|
1368
|
|
|
|
|
|
|
|
|
1369
|
5
|
50
|
|
|
|
26
|
croak "Invalid column '$col_letter'" if $col >= $self->{_xls_colmax}; |
|
1370
|
|
|
|
|
|
|
} |
|
1371
|
|
|
|
|
|
|
|
|
1372
|
14
|
|
|
|
|
30
|
my ( $col_first, $col_last ) = @{ $self->{_filter_range} }; |
|
|
14
|
|
|
|
|
47
|
|
|
1373
|
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
# Reject column if it is outside filter range. |
|
1375
|
14
|
50
|
33
|
|
|
92
|
if ( $col < $col_first or $col > $col_last ) { |
|
1376
|
0
|
|
|
|
|
0
|
croak "Column '$col' outside autofilter() column range " |
|
1377
|
|
|
|
|
|
|
. "($col_first .. $col_last)"; |
|
1378
|
|
|
|
|
|
|
} |
|
1379
|
|
|
|
|
|
|
|
|
1380
|
14
|
|
|
|
|
55
|
$self->{_filter_cols}->{$col} = [@tokens]; |
|
1381
|
14
|
|
|
|
|
45
|
$self->{_filter_type}->{$col} = 1; # Default style. |
|
1382
|
14
|
|
|
|
|
41
|
$self->{_filter_on} = 1; |
|
1383
|
|
|
|
|
|
|
} |
|
1384
|
|
|
|
|
|
|
|
|
1385
|
|
|
|
|
|
|
|
|
1386
|
|
|
|
|
|
|
############################################################################### |
|
1387
|
|
|
|
|
|
|
# |
|
1388
|
|
|
|
|
|
|
# _extract_filter_tokens($expression) |
|
1389
|
|
|
|
|
|
|
# |
|
1390
|
|
|
|
|
|
|
# Extract the tokens from the filter expression. The tokens are mainly non- |
|
1391
|
|
|
|
|
|
|
# whitespace groups. The only tricky part is to extract string tokens that |
|
1392
|
|
|
|
|
|
|
# contain whitespace and/or quoted double quotes (Excel's escaped quotes). |
|
1393
|
|
|
|
|
|
|
# |
|
1394
|
|
|
|
|
|
|
# Examples: 'x < 2000' |
|
1395
|
|
|
|
|
|
|
# 'x > 2000 and x < 5000' |
|
1396
|
|
|
|
|
|
|
# 'x = "foo"' |
|
1397
|
|
|
|
|
|
|
# 'x = "foo bar"' |
|
1398
|
|
|
|
|
|
|
# 'x = "foo "" bar"' |
|
1399
|
|
|
|
|
|
|
# |
|
1400
|
|
|
|
|
|
|
sub _extract_filter_tokens { |
|
1401
|
|
|
|
|
|
|
|
|
1402
|
67
|
|
|
67
|
|
25174
|
my $self = shift; |
|
1403
|
67
|
|
|
|
|
122
|
my $expression = $_[0]; |
|
1404
|
|
|
|
|
|
|
|
|
1405
|
67
|
100
|
|
|
|
178
|
return unless $expression; |
|
1406
|
|
|
|
|
|
|
|
|
1407
|
65
|
|
|
|
|
584
|
my @tokens = ( $expression =~ /"(?:[^"]|"")*"|\S+/g ); #" |
|
1408
|
|
|
|
|
|
|
|
|
1409
|
|
|
|
|
|
|
# Remove leading and trailing quotes and unescape other quotes |
|
1410
|
65
|
|
|
|
|
168
|
for ( @tokens ) { |
|
1411
|
247
|
|
|
|
|
436
|
s/^"//; #" |
|
1412
|
247
|
|
|
|
|
377
|
s/"$//; #" |
|
1413
|
247
|
|
|
|
|
414
|
s/""/"/g; #" |
|
1414
|
|
|
|
|
|
|
} |
|
1415
|
|
|
|
|
|
|
|
|
1416
|
65
|
|
|
|
|
242
|
return @tokens; |
|
1417
|
|
|
|
|
|
|
} |
|
1418
|
|
|
|
|
|
|
|
|
1419
|
|
|
|
|
|
|
|
|
1420
|
|
|
|
|
|
|
############################################################################### |
|
1421
|
|
|
|
|
|
|
# |
|
1422
|
|
|
|
|
|
|
# _parse_filter_expression(@token) |
|
1423
|
|
|
|
|
|
|
# |
|
1424
|
|
|
|
|
|
|
# Converts the tokens of a possibly conditional expression into 1 or 2 |
|
1425
|
|
|
|
|
|
|
# sub expressions for further parsing. |
|
1426
|
|
|
|
|
|
|
# |
|
1427
|
|
|
|
|
|
|
# Examples: |
|
1428
|
|
|
|
|
|
|
# ('x', '==', 2000) -> exp1 |
|
1429
|
|
|
|
|
|
|
# ('x', '>', 2000, 'and', 'x', '<', 5000) -> exp1 and exp2 |
|
1430
|
|
|
|
|
|
|
# |
|
1431
|
|
|
|
|
|
|
sub _parse_filter_expression { |
|
1432
|
|
|
|
|
|
|
|
|
1433
|
49
|
|
|
49
|
|
147
|
my $self = shift; |
|
1434
|
49
|
|
|
|
|
71
|
my $expression = shift; |
|
1435
|
49
|
|
|
|
|
131
|
my @tokens = @_; |
|
1436
|
|
|
|
|
|
|
|
|
1437
|
|
|
|
|
|
|
# The number of tokens will be either 3 (for 1 expression) |
|
1438
|
|
|
|
|
|
|
# or 7 (for 2 expressions). |
|
1439
|
|
|
|
|
|
|
# |
|
1440
|
49
|
100
|
|
|
|
129
|
if ( @tokens == 7 ) { |
|
1441
|
|
|
|
|
|
|
|
|
1442
|
10
|
|
|
|
|
64
|
my $conditional = $tokens[3]; |
|
1443
|
|
|
|
|
|
|
|
|
1444
|
10
|
100
|
|
|
|
84
|
if ( $conditional =~ /^(and|&&)$/ ) { |
|
|
|
50
|
|
|
|
|
|
|
1445
|
5
|
|
|
|
|
15
|
$conditional = 0; |
|
1446
|
|
|
|
|
|
|
} |
|
1447
|
|
|
|
|
|
|
elsif ( $conditional =~ /^(or|\|\|)$/ ) { |
|
1448
|
5
|
|
|
|
|
23
|
$conditional = 1; |
|
1449
|
|
|
|
|
|
|
} |
|
1450
|
|
|
|
|
|
|
else { |
|
1451
|
0
|
|
|
|
|
0
|
croak "Token '$conditional' is not a valid conditional " |
|
1452
|
|
|
|
|
|
|
. "in filter expression '$expression'"; |
|
1453
|
|
|
|
|
|
|
} |
|
1454
|
|
|
|
|
|
|
|
|
1455
|
10
|
|
|
|
|
44
|
my @expression_1 = |
|
1456
|
|
|
|
|
|
|
$self->_parse_filter_tokens( $expression, @tokens[ 0, 1, 2 ] ); |
|
1457
|
10
|
|
|
|
|
45
|
my @expression_2 = |
|
1458
|
|
|
|
|
|
|
$self->_parse_filter_tokens( $expression, @tokens[ 4, 5, 6 ] ); |
|
1459
|
|
|
|
|
|
|
|
|
1460
|
10
|
|
|
|
|
50
|
return ( @expression_1, $conditional, @expression_2 ); |
|
1461
|
|
|
|
|
|
|
} |
|
1462
|
|
|
|
|
|
|
else { |
|
1463
|
39
|
|
|
|
|
106
|
return $self->_parse_filter_tokens( $expression, @tokens ); |
|
1464
|
|
|
|
|
|
|
} |
|
1465
|
|
|
|
|
|
|
} |
|
1466
|
|
|
|
|
|
|
|
|
1467
|
|
|
|
|
|
|
|
|
1468
|
|
|
|
|
|
|
############################################################################### |
|
1469
|
|
|
|
|
|
|
# |
|
1470
|
|
|
|
|
|
|
# _parse_filter_tokens(@token) |
|
1471
|
|
|
|
|
|
|
# |
|
1472
|
|
|
|
|
|
|
# Parse the 3 tokens of a filter expression and return the operator and token. |
|
1473
|
|
|
|
|
|
|
# |
|
1474
|
|
|
|
|
|
|
sub _parse_filter_tokens { |
|
1475
|
|
|
|
|
|
|
|
|
1476
|
59
|
|
|
59
|
|
99
|
my $self = shift; |
|
1477
|
59
|
|
|
|
|
90
|
my $expression = shift; |
|
1478
|
59
|
|
|
|
|
135
|
my @tokens = @_; |
|
1479
|
|
|
|
|
|
|
|
|
1480
|
59
|
|
|
|
|
355
|
my %operators = ( |
|
1481
|
|
|
|
|
|
|
'==' => 2, |
|
1482
|
|
|
|
|
|
|
'=' => 2, |
|
1483
|
|
|
|
|
|
|
'=~' => 2, |
|
1484
|
|
|
|
|
|
|
'eq' => 2, |
|
1485
|
|
|
|
|
|
|
|
|
1486
|
|
|
|
|
|
|
'!=' => 5, |
|
1487
|
|
|
|
|
|
|
'!~' => 5, |
|
1488
|
|
|
|
|
|
|
'ne' => 5, |
|
1489
|
|
|
|
|
|
|
'<>' => 5, |
|
1490
|
|
|
|
|
|
|
|
|
1491
|
|
|
|
|
|
|
'<' => 1, |
|
1492
|
|
|
|
|
|
|
'<=' => 3, |
|
1493
|
|
|
|
|
|
|
'>' => 4, |
|
1494
|
|
|
|
|
|
|
'>=' => 6, |
|
1495
|
|
|
|
|
|
|
); |
|
1496
|
|
|
|
|
|
|
|
|
1497
|
59
|
|
|
|
|
119
|
my $operator = $operators{ $tokens[1] }; |
|
1498
|
59
|
|
|
|
|
110
|
my $token = $tokens[2]; |
|
1499
|
|
|
|
|
|
|
|
|
1500
|
|
|
|
|
|
|
|
|
1501
|
|
|
|
|
|
|
# Special handling of "Top" filter expressions. |
|
1502
|
59
|
100
|
|
|
|
161
|
if ( $tokens[0] =~ /^top|bottom$/i ) { |
|
1503
|
|
|
|
|
|
|
|
|
1504
|
4
|
|
|
|
|
8
|
my $value = $tokens[1]; |
|
1505
|
|
|
|
|
|
|
|
|
1506
|
4
|
50
|
33
|
|
|
33
|
if ( $value =~ /\D/ |
|
|
|
|
33
|
|
|
|
|
|
1507
|
|
|
|
|
|
|
or $value < 1 |
|
1508
|
|
|
|
|
|
|
or $value > 500 ) |
|
1509
|
|
|
|
|
|
|
{ |
|
1510
|
0
|
|
|
|
|
0
|
croak "The value '$value' in expression '$expression' " |
|
1511
|
|
|
|
|
|
|
. "must be in the range 1 to 500"; |
|
1512
|
|
|
|
|
|
|
} |
|
1513
|
|
|
|
|
|
|
|
|
1514
|
4
|
|
|
|
|
10
|
$token = lc $token; |
|
1515
|
|
|
|
|
|
|
|
|
1516
|
4
|
50
|
66
|
|
|
22
|
if ( $token ne 'items' and $token ne '%' ) { |
|
1517
|
0
|
|
|
|
|
0
|
croak "The type '$token' in expression '$expression' " |
|
1518
|
|
|
|
|
|
|
. "must be either 'items' or '%'"; |
|
1519
|
|
|
|
|
|
|
} |
|
1520
|
|
|
|
|
|
|
|
|
1521
|
4
|
100
|
|
|
|
16
|
if ( $tokens[0] =~ /^top$/i ) { |
|
1522
|
2
|
|
|
|
|
5
|
$operator = 30; |
|
1523
|
|
|
|
|
|
|
} |
|
1524
|
|
|
|
|
|
|
else { |
|
1525
|
2
|
|
|
|
|
3
|
$operator = 32; |
|
1526
|
|
|
|
|
|
|
} |
|
1527
|
|
|
|
|
|
|
|
|
1528
|
4
|
100
|
|
|
|
10
|
if ( $tokens[2] eq '%' ) { |
|
1529
|
2
|
|
|
|
|
4
|
$operator++; |
|
1530
|
|
|
|
|
|
|
} |
|
1531
|
|
|
|
|
|
|
|
|
1532
|
4
|
|
|
|
|
9
|
$token = $value; |
|
1533
|
|
|
|
|
|
|
} |
|
1534
|
|
|
|
|
|
|
|
|
1535
|
|
|
|
|
|
|
|
|
1536
|
59
|
0
|
33
|
|
|
146
|
if ( not $operator and $tokens[0] ) { |
|
1537
|
0
|
|
|
|
|
0
|
croak "Token '$tokens[1]' is not a valid operator " |
|
1538
|
|
|
|
|
|
|
. "in filter expression '$expression'"; |
|
1539
|
|
|
|
|
|
|
} |
|
1540
|
|
|
|
|
|
|
|
|
1541
|
|
|
|
|
|
|
|
|
1542
|
|
|
|
|
|
|
# Special handling for Blanks/NonBlanks. |
|
1543
|
59
|
100
|
|
|
|
153
|
if ( $token =~ /^blanks|nonblanks$/i ) { |
|
1544
|
|
|
|
|
|
|
|
|
1545
|
|
|
|
|
|
|
# Only allow Equals or NotEqual in this context. |
|
1546
|
7
|
50
|
66
|
|
|
35
|
if ( $operator != 2 and $operator != 5 ) { |
|
1547
|
0
|
|
|
|
|
0
|
croak "The operator '$tokens[1]' in expression '$expression' " |
|
1548
|
|
|
|
|
|
|
. "is not valid in relation to Blanks/NonBlanks'"; |
|
1549
|
|
|
|
|
|
|
} |
|
1550
|
|
|
|
|
|
|
|
|
1551
|
7
|
|
|
|
|
20
|
$token = lc $token; |
|
1552
|
|
|
|
|
|
|
|
|
1553
|
|
|
|
|
|
|
# The operator should always be 2 (=) to flag a "simple" equality in |
|
1554
|
|
|
|
|
|
|
# the binary record. Therefore we convert <> to =. |
|
1555
|
7
|
100
|
|
|
|
21
|
if ( $token eq 'blanks' ) { |
|
1556
|
4
|
100
|
|
|
|
14
|
if ( $operator == 5 ) { |
|
1557
|
1
|
|
|
|
|
3
|
$token = ' '; |
|
1558
|
|
|
|
|
|
|
} |
|
1559
|
|
|
|
|
|
|
} |
|
1560
|
|
|
|
|
|
|
else { |
|
1561
|
3
|
100
|
|
|
|
11
|
if ( $operator == 5 ) { |
|
1562
|
1
|
|
|
|
|
2
|
$operator = 2; |
|
1563
|
1
|
|
|
|
|
6
|
$token = 'blanks'; |
|
1564
|
|
|
|
|
|
|
} |
|
1565
|
|
|
|
|
|
|
else { |
|
1566
|
2
|
|
|
|
|
4
|
$operator = 5; |
|
1567
|
2
|
|
|
|
|
5
|
$token = ' '; |
|
1568
|
|
|
|
|
|
|
} |
|
1569
|
|
|
|
|
|
|
} |
|
1570
|
|
|
|
|
|
|
} |
|
1571
|
|
|
|
|
|
|
|
|
1572
|
|
|
|
|
|
|
|
|
1573
|
|
|
|
|
|
|
# if the string token contains an Excel match character then change the |
|
1574
|
|
|
|
|
|
|
# operator type to indicate a non "simple" equality. |
|
1575
|
59
|
100
|
100
|
|
|
202
|
if ( $operator == 2 and $token =~ /[*?]/ ) { |
|
1576
|
3
|
|
|
|
|
6
|
$operator = 22; |
|
1577
|
|
|
|
|
|
|
} |
|
1578
|
|
|
|
|
|
|
|
|
1579
|
|
|
|
|
|
|
|
|
1580
|
59
|
|
|
|
|
344
|
return ( $operator, $token ); |
|
1581
|
|
|
|
|
|
|
} |
|
1582
|
|
|
|
|
|
|
|
|
1583
|
|
|
|
|
|
|
|
|
1584
|
|
|
|
|
|
|
############################################################################### |
|
1585
|
|
|
|
|
|
|
# |
|
1586
|
|
|
|
|
|
|
# _convert_name_area($first_row, $first_col, $last_row, $last_col) |
|
1587
|
|
|
|
|
|
|
# |
|
1588
|
|
|
|
|
|
|
# Convert zero indexed rows and columns to the format required by worksheet |
|
1589
|
|
|
|
|
|
|
# named ranges, eg, "Sheet1!$A$1:$C$13". |
|
1590
|
|
|
|
|
|
|
# |
|
1591
|
|
|
|
|
|
|
sub _convert_name_area { |
|
1592
|
|
|
|
|
|
|
|
|
1593
|
40
|
|
|
40
|
|
75
|
my $self = shift; |
|
1594
|
|
|
|
|
|
|
|
|
1595
|
40
|
|
|
|
|
79
|
my $row_num_1 = $_[0]; |
|
1596
|
40
|
|
|
|
|
82
|
my $col_num_1 = $_[1]; |
|
1597
|
40
|
|
|
|
|
72
|
my $row_num_2 = $_[2]; |
|
1598
|
40
|
|
|
|
|
89
|
my $col_num_2 = $_[3]; |
|
1599
|
|
|
|
|
|
|
|
|
1600
|
40
|
|
|
|
|
88
|
my $range1 = ''; |
|
1601
|
40
|
|
|
|
|
67
|
my $range2 = ''; |
|
1602
|
40
|
|
|
|
|
65
|
my $row_col_only = 0; |
|
1603
|
40
|
|
|
|
|
74
|
my $area; |
|
1604
|
|
|
|
|
|
|
|
|
1605
|
|
|
|
|
|
|
# Convert to A1 notation. |
|
1606
|
40
|
|
|
|
|
183
|
my $col_char_1 = xl_col_to_name( $col_num_1, 1 ); |
|
1607
|
40
|
|
|
|
|
121
|
my $col_char_2 = xl_col_to_name( $col_num_2, 1 ); |
|
1608
|
40
|
|
|
|
|
136
|
my $row_char_1 = '$' . ( $row_num_1 + 1 ); |
|
1609
|
40
|
|
|
|
|
100
|
my $row_char_2 = '$' . ( $row_num_2 + 1 ); |
|
1610
|
|
|
|
|
|
|
|
|
1611
|
|
|
|
|
|
|
# We need to handle some special cases that refer to rows or columns only. |
|
1612
|
40
|
100
|
100
|
|
|
396
|
if ( $row_num_1 == 0 and $row_num_2 == $self->{_xls_rowmax} - 1 ) { |
|
|
|
100
|
100
|
|
|
|
|
|
1613
|
1
|
|
|
|
|
2
|
$range1 = $col_char_1; |
|
1614
|
1
|
|
|
|
|
4
|
$range2 = $col_char_2; |
|
1615
|
1
|
|
|
|
|
2
|
$row_col_only = 1; |
|
1616
|
|
|
|
|
|
|
} |
|
1617
|
|
|
|
|
|
|
elsif ( $col_num_1 == 0 and $col_num_2 == $self->{_xls_colmax} - 1 ) { |
|
1618
|
1
|
|
|
|
|
2
|
$range1 = $row_char_1; |
|
1619
|
1
|
|
|
|
|
2
|
$range2 = $row_char_2; |
|
1620
|
1
|
|
|
|
|
2
|
$row_col_only = 1; |
|
1621
|
|
|
|
|
|
|
} |
|
1622
|
|
|
|
|
|
|
else { |
|
1623
|
38
|
|
|
|
|
86
|
$range1 = $col_char_1 . $row_char_1; |
|
1624
|
38
|
|
|
|
|
75
|
$range2 = $col_char_2 . $row_char_2; |
|
1625
|
|
|
|
|
|
|
} |
|
1626
|
|
|
|
|
|
|
|
|
1627
|
|
|
|
|
|
|
# A repeated range is only written once (if it isn't a special case). |
|
1628
|
40
|
100
|
100
|
|
|
143
|
if ( $range1 eq $range2 && !$row_col_only ) { |
|
1629
|
1
|
|
|
|
|
2
|
$area = $range1; |
|
1630
|
|
|
|
|
|
|
} |
|
1631
|
|
|
|
|
|
|
else { |
|
1632
|
39
|
|
|
|
|
95
|
$area = $range1 . ':' . $range2; |
|
1633
|
|
|
|
|
|
|
} |
|
1634
|
|
|
|
|
|
|
|
|
1635
|
|
|
|
|
|
|
# Build up the print area range "Sheet1!$A$1:$C$13". |
|
1636
|
40
|
|
|
|
|
157
|
my $sheetname = quote_sheetname( $self->{_name} ); |
|
1637
|
40
|
|
|
|
|
131
|
$area = $sheetname . "!" . $area; |
|
1638
|
|
|
|
|
|
|
|
|
1639
|
40
|
|
|
|
|
97
|
return $area; |
|
1640
|
|
|
|
|
|
|
} |
|
1641
|
|
|
|
|
|
|
|
|
1642
|
|
|
|
|
|
|
|
|
1643
|
|
|
|
|
|
|
############################################################################### |
|
1644
|
|
|
|
|
|
|
# |
|
1645
|
|
|
|
|
|
|
# hide_gridlines() |
|
1646
|
|
|
|
|
|
|
# |
|
1647
|
|
|
|
|
|
|
# Set the option to hide gridlines on the screen and the printed page. |
|
1648
|
|
|
|
|
|
|
# |
|
1649
|
|
|
|
|
|
|
# This was mainly useful for Excel 5 where printed gridlines were on by |
|
1650
|
|
|
|
|
|
|
# default. |
|
1651
|
|
|
|
|
|
|
# |
|
1652
|
|
|
|
|
|
|
sub hide_gridlines { |
|
1653
|
|
|
|
|
|
|
|
|
1654
|
12
|
|
|
12
|
0
|
116
|
my $self = shift; |
|
1655
|
12
|
100
|
|
|
|
43
|
my $option = |
|
1656
|
|
|
|
|
|
|
defined $_[0] ? $_[0] : 1; # Default to hiding printed gridlines |
|
1657
|
|
|
|
|
|
|
|
|
1658
|
12
|
100
|
|
|
|
52
|
if ( $option == 0 ) { |
|
|
|
100
|
|
|
|
|
|
|
1659
|
5
|
|
|
|
|
22
|
$self->{_print_gridlines} = 1; # 1 = display, 0 = hide |
|
1660
|
5
|
|
|
|
|
9
|
$self->{_screen_gridlines} = 1; |
|
1661
|
5
|
|
|
|
|
14
|
$self->{_print_options_changed} = 1; |
|
1662
|
|
|
|
|
|
|
} |
|
1663
|
|
|
|
|
|
|
elsif ( $option == 1 ) { |
|
1664
|
4
|
|
|
|
|
7
|
$self->{_print_gridlines} = 0; |
|
1665
|
4
|
|
|
|
|
9
|
$self->{_screen_gridlines} = 1; |
|
1666
|
|
|
|
|
|
|
} |
|
1667
|
|
|
|
|
|
|
else { |
|
1668
|
3
|
|
|
|
|
19
|
$self->{_print_gridlines} = 0; |
|
1669
|
3
|
|
|
|
|
9
|
$self->{_screen_gridlines} = 0; |
|
1670
|
|
|
|
|
|
|
} |
|
1671
|
|
|
|
|
|
|
} |
|
1672
|
|
|
|
|
|
|
|
|
1673
|
|
|
|
|
|
|
|
|
1674
|
|
|
|
|
|
|
############################################################################### |
|
1675
|
|
|
|
|
|
|
# |
|
1676
|
|
|
|
|
|
|
# print_row_col_headers() |
|
1677
|
|
|
|
|
|
|
# |
|
1678
|
|
|
|
|
|
|
# Set the option to print the row and column headers on the printed page. |
|
1679
|
|
|
|
|
|
|
# See also the _store_print_headers() method below. |
|
1680
|
|
|
|
|
|
|
# |
|
1681
|
|
|
|
|
|
|
sub print_row_col_headers { |
|
1682
|
|
|
|
|
|
|
|
|
1683
|
2
|
|
|
2
|
0
|
13
|
my $self = shift; |
|
1684
|
2
|
50
|
|
|
|
8
|
my $headers = defined $_[0] ? $_[0] : 1; |
|
1685
|
|
|
|
|
|
|
|
|
1686
|
2
|
50
|
|
|
|
7
|
if ( $headers ) { |
|
1687
|
2
|
|
|
|
|
10
|
$self->{_print_headers} = 1; |
|
1688
|
2
|
|
|
|
|
6
|
$self->{_print_options_changed} = 1; |
|
1689
|
|
|
|
|
|
|
} |
|
1690
|
|
|
|
|
|
|
else { |
|
1691
|
0
|
|
|
|
|
0
|
$self->{_print_headers} = 0; |
|
1692
|
|
|
|
|
|
|
} |
|
1693
|
|
|
|
|
|
|
} |
|
1694
|
|
|
|
|
|
|
|
|
1695
|
|
|
|
|
|
|
|
|
1696
|
|
|
|
|
|
|
############################################################################### |
|
1697
|
|
|
|
|
|
|
# |
|
1698
|
|
|
|
|
|
|
# hide_row_col_headers() |
|
1699
|
|
|
|
|
|
|
# |
|
1700
|
|
|
|
|
|
|
# Set the option to hide the row and column headers in Excel. |
|
1701
|
|
|
|
|
|
|
# |
|
1702
|
|
|
|
|
|
|
sub hide_row_col_headers { |
|
1703
|
|
|
|
|
|
|
|
|
1704
|
1
|
|
|
1
|
0
|
8
|
my $self = shift; |
|
1705
|
1
|
|
|
|
|
5
|
$self->{_hide_row_col_headers} = 1; |
|
1706
|
|
|
|
|
|
|
} |
|
1707
|
|
|
|
|
|
|
|
|
1708
|
|
|
|
|
|
|
|
|
1709
|
|
|
|
|
|
|
############################################################################### |
|
1710
|
|
|
|
|
|
|
# |
|
1711
|
|
|
|
|
|
|
# fit_to_pages($width, $height) |
|
1712
|
|
|
|
|
|
|
# |
|
1713
|
|
|
|
|
|
|
# Store the vertical and horizontal number of pages that will define the |
|
1714
|
|
|
|
|
|
|
# maximum area printed. |
|
1715
|
|
|
|
|
|
|
# |
|
1716
|
|
|
|
|
|
|
sub fit_to_pages { |
|
1717
|
|
|
|
|
|
|
|
|
1718
|
6
|
|
|
6
|
0
|
59
|
my $self = shift; |
|
1719
|
|
|
|
|
|
|
|
|
1720
|
6
|
|
|
|
|
48
|
$self->{_fit_page} = 1; |
|
1721
|
6
|
100
|
|
|
|
25
|
$self->{_fit_width} = defined $_[0] ? $_[0] : 1; |
|
1722
|
6
|
100
|
|
|
|
26
|
$self->{_fit_height} = defined $_[1] ? $_[1] : 1; |
|
1723
|
6
|
|
|
|
|
18
|
$self->{_page_setup_changed} = 1; |
|
1724
|
|
|
|
|
|
|
} |
|
1725
|
|
|
|
|
|
|
|
|
1726
|
|
|
|
|
|
|
|
|
1727
|
|
|
|
|
|
|
############################################################################### |
|
1728
|
|
|
|
|
|
|
# |
|
1729
|
|
|
|
|
|
|
# set_h_pagebreaks(@breaks) |
|
1730
|
|
|
|
|
|
|
# |
|
1731
|
|
|
|
|
|
|
# Store the horizontal page breaks on a worksheet. |
|
1732
|
|
|
|
|
|
|
# |
|
1733
|
|
|
|
|
|
|
sub set_h_pagebreaks { |
|
1734
|
|
|
|
|
|
|
|
|
1735
|
4
|
|
|
4
|
0
|
73
|
my $self = shift; |
|
1736
|
|
|
|
|
|
|
|
|
1737
|
4
|
|
|
|
|
9
|
push @{ $self->{_hbreaks} }, @_; |
|
|
4
|
|
|
|
|
81
|
|
|
1738
|
|
|
|
|
|
|
} |
|
1739
|
|
|
|
|
|
|
|
|
1740
|
|
|
|
|
|
|
|
|
1741
|
|
|
|
|
|
|
############################################################################### |
|
1742
|
|
|
|
|
|
|
# |
|
1743
|
|
|
|
|
|
|
# set_v_pagebreaks(@breaks) |
|
1744
|
|
|
|
|
|
|
# |
|
1745
|
|
|
|
|
|
|
# Store the vertical page breaks on a worksheet. |
|
1746
|
|
|
|
|
|
|
# |
|
1747
|
|
|
|
|
|
|
sub set_v_pagebreaks { |
|
1748
|
|
|
|
|
|
|
|
|
1749
|
3
|
|
|
3
|
0
|
36
|
my $self = shift; |
|
1750
|
|
|
|
|
|
|
|
|
1751
|
3
|
|
|
|
|
13
|
push @{ $self->{_vbreaks} }, @_; |
|
|
3
|
|
|
|
|
24
|
|
|
1752
|
|
|
|
|
|
|
} |
|
1753
|
|
|
|
|
|
|
|
|
1754
|
|
|
|
|
|
|
|
|
1755
|
|
|
|
|
|
|
############################################################################### |
|
1756
|
|
|
|
|
|
|
# |
|
1757
|
|
|
|
|
|
|
# set_zoom( $scale ) |
|
1758
|
|
|
|
|
|
|
# |
|
1759
|
|
|
|
|
|
|
# Set the worksheet zoom factor. |
|
1760
|
|
|
|
|
|
|
# |
|
1761
|
|
|
|
|
|
|
sub set_zoom { |
|
1762
|
|
|
|
|
|
|
|
|
1763
|
3
|
|
|
3
|
0
|
19
|
my $self = shift; |
|
1764
|
3
|
|
50
|
|
|
12
|
my $scale = $_[0] || 100; |
|
1765
|
|
|
|
|
|
|
|
|
1766
|
|
|
|
|
|
|
# Confine the scale to Excel's range |
|
1767
|
3
|
50
|
33
|
|
|
22
|
if ( $scale < 10 or $scale > 400 ) { |
|
1768
|
0
|
|
|
|
|
0
|
carp "Zoom factor $scale outside range: 10 <= zoom <= 400"; |
|
1769
|
0
|
|
|
|
|
0
|
$scale = 100; |
|
1770
|
|
|
|
|
|
|
} |
|
1771
|
|
|
|
|
|
|
|
|
1772
|
3
|
|
|
|
|
12
|
$self->{_zoom} = int $scale; |
|
1773
|
|
|
|
|
|
|
} |
|
1774
|
|
|
|
|
|
|
|
|
1775
|
|
|
|
|
|
|
|
|
1776
|
|
|
|
|
|
|
############################################################################### |
|
1777
|
|
|
|
|
|
|
# |
|
1778
|
|
|
|
|
|
|
# set_print_scale($scale) |
|
1779
|
|
|
|
|
|
|
# |
|
1780
|
|
|
|
|
|
|
# Set the scale factor for the printed page. |
|
1781
|
|
|
|
|
|
|
# |
|
1782
|
|
|
|
|
|
|
sub set_print_scale { |
|
1783
|
|
|
|
|
|
|
|
|
1784
|
3
|
|
|
3
|
0
|
20
|
my $self = shift; |
|
1785
|
3
|
|
50
|
|
|
12
|
my $scale = $_[0] || 100; |
|
1786
|
|
|
|
|
|
|
|
|
1787
|
|
|
|
|
|
|
# Confine the scale to Excel's range |
|
1788
|
3
|
50
|
33
|
|
|
33
|
if ( $scale < 10 or $scale > 400 ) { |
|
1789
|
0
|
|
|
|
|
0
|
carp "Print scale $scale outside range: 10 <= zoom <= 400"; |
|
1790
|
0
|
|
|
|
|
0
|
$scale = 100; |
|
1791
|
|
|
|
|
|
|
} |
|
1792
|
|
|
|
|
|
|
|
|
1793
|
|
|
|
|
|
|
# Turn off "fit to page" option. |
|
1794
|
3
|
|
|
|
|
24
|
$self->{_fit_page} = 0; |
|
1795
|
|
|
|
|
|
|
|
|
1796
|
3
|
|
|
|
|
9
|
$self->{_print_scale} = int $scale; |
|
1797
|
3
|
|
|
|
|
9
|
$self->{_page_setup_changed} = 1; |
|
1798
|
|
|
|
|
|
|
} |
|
1799
|
|
|
|
|
|
|
|
|
1800
|
|
|
|
|
|
|
|
|
1801
|
|
|
|
|
|
|
############################################################################### |
|
1802
|
|
|
|
|
|
|
# |
|
1803
|
|
|
|
|
|
|
# print_black_and_white() |
|
1804
|
|
|
|
|
|
|
# |
|
1805
|
|
|
|
|
|
|
# Set the option to print the worksheet in black and white. |
|
1806
|
|
|
|
|
|
|
# |
|
1807
|
|
|
|
|
|
|
sub print_black_and_white { |
|
1808
|
|
|
|
|
|
|
|
|
1809
|
1
|
|
|
1
|
0
|
6
|
my $self = shift; |
|
1810
|
|
|
|
|
|
|
|
|
1811
|
1
|
|
|
|
|
4
|
$self->{_black_white} = 1; |
|
1812
|
|
|
|
|
|
|
} |
|
1813
|
|
|
|
|
|
|
|
|
1814
|
|
|
|
|
|
|
|
|
1815
|
|
|
|
|
|
|
############################################################################### |
|
1816
|
|
|
|
|
|
|
# |
|
1817
|
|
|
|
|
|
|
# keep_leading_zeros() |
|
1818
|
|
|
|
|
|
|
# |
|
1819
|
|
|
|
|
|
|
# Causes the write() method to treat integers with a leading zero as a string. |
|
1820
|
|
|
|
|
|
|
# This ensures that any leading zeros such, as in zip codes, are maintained. |
|
1821
|
|
|
|
|
|
|
# |
|
1822
|
|
|
|
|
|
|
sub keep_leading_zeros { |
|
1823
|
|
|
|
|
|
|
|
|
1824
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
1825
|
|
|
|
|
|
|
|
|
1826
|
0
|
0
|
|
|
|
0
|
if ( defined $_[0] ) { |
|
1827
|
0
|
|
|
|
|
0
|
$self->{_leading_zeros} = $_[0]; |
|
1828
|
|
|
|
|
|
|
} |
|
1829
|
|
|
|
|
|
|
else { |
|
1830
|
0
|
|
|
|
|
0
|
$self->{_leading_zeros} = 1; |
|
1831
|
|
|
|
|
|
|
} |
|
1832
|
|
|
|
|
|
|
} |
|
1833
|
|
|
|
|
|
|
|
|
1834
|
|
|
|
|
|
|
|
|
1835
|
|
|
|
|
|
|
############################################################################### |
|
1836
|
|
|
|
|
|
|
# |
|
1837
|
|
|
|
|
|
|
# show_comments() |
|
1838
|
|
|
|
|
|
|
# |
|
1839
|
|
|
|
|
|
|
# Make any comments in the worksheet visible. |
|
1840
|
|
|
|
|
|
|
# |
|
1841
|
|
|
|
|
|
|
sub show_comments { |
|
1842
|
|
|
|
|
|
|
|
|
1843
|
2
|
|
|
2
|
0
|
9
|
my $self = shift; |
|
1844
|
|
|
|
|
|
|
|
|
1845
|
2
|
50
|
|
|
|
10
|
$self->{_comments_visible} = defined $_[0] ? $_[0] : 1; |
|
1846
|
|
|
|
|
|
|
} |
|
1847
|
|
|
|
|
|
|
|
|
1848
|
|
|
|
|
|
|
|
|
1849
|
|
|
|
|
|
|
############################################################################### |
|
1850
|
|
|
|
|
|
|
# |
|
1851
|
|
|
|
|
|
|
# set_comments_author() |
|
1852
|
|
|
|
|
|
|
# |
|
1853
|
|
|
|
|
|
|
# Set the default author of the cell comments. |
|
1854
|
|
|
|
|
|
|
# |
|
1855
|
|
|
|
|
|
|
sub set_comments_author { |
|
1856
|
|
|
|
|
|
|
|
|
1857
|
39
|
|
|
39
|
0
|
227
|
my $self = shift; |
|
1858
|
|
|
|
|
|
|
|
|
1859
|
39
|
50
|
|
|
|
204
|
$self->{_comments_author} = $_[0] if defined $_[0]; |
|
1860
|
|
|
|
|
|
|
} |
|
1861
|
|
|
|
|
|
|
|
|
1862
|
|
|
|
|
|
|
|
|
1863
|
|
|
|
|
|
|
############################################################################### |
|
1864
|
|
|
|
|
|
|
# |
|
1865
|
|
|
|
|
|
|
# right_to_left() |
|
1866
|
|
|
|
|
|
|
# |
|
1867
|
|
|
|
|
|
|
# Display the worksheet right to left for some eastern versions of Excel. |
|
1868
|
|
|
|
|
|
|
# |
|
1869
|
|
|
|
|
|
|
sub right_to_left { |
|
1870
|
|
|
|
|
|
|
|
|
1871
|
1
|
|
|
1
|
0
|
6
|
my $self = shift; |
|
1872
|
|
|
|
|
|
|
|
|
1873
|
1
|
50
|
|
|
|
5
|
$self->{_right_to_left} = defined $_[0] ? $_[0] : 1; |
|
1874
|
|
|
|
|
|
|
} |
|
1875
|
|
|
|
|
|
|
|
|
1876
|
|
|
|
|
|
|
|
|
1877
|
|
|
|
|
|
|
############################################################################### |
|
1878
|
|
|
|
|
|
|
# |
|
1879
|
|
|
|
|
|
|
# hide_zero() |
|
1880
|
|
|
|
|
|
|
# |
|
1881
|
|
|
|
|
|
|
# Hide cell zero values. |
|
1882
|
|
|
|
|
|
|
# |
|
1883
|
|
|
|
|
|
|
sub hide_zero { |
|
1884
|
|
|
|
|
|
|
|
|
1885
|
1
|
|
|
1
|
0
|
6
|
my $self = shift; |
|
1886
|
|
|
|
|
|
|
|
|
1887
|
1
|
50
|
|
|
|
5
|
$self->{_show_zeros} = defined $_[0] ? not $_[0] : 0; |
|
1888
|
|
|
|
|
|
|
} |
|
1889
|
|
|
|
|
|
|
|
|
1890
|
|
|
|
|
|
|
|
|
1891
|
|
|
|
|
|
|
############################################################################### |
|
1892
|
|
|
|
|
|
|
# |
|
1893
|
|
|
|
|
|
|
# print_across() |
|
1894
|
|
|
|
|
|
|
# |
|
1895
|
|
|
|
|
|
|
# Set the order in which pages are printed. |
|
1896
|
|
|
|
|
|
|
# |
|
1897
|
|
|
|
|
|
|
sub print_across { |
|
1898
|
|
|
|
|
|
|
|
|
1899
|
2
|
|
|
2
|
0
|
24
|
my $self = shift; |
|
1900
|
2
|
50
|
|
|
|
9
|
my $page_order = defined $_[0] ? $_[0] : 1; |
|
1901
|
|
|
|
|
|
|
|
|
1902
|
2
|
50
|
|
|
|
6
|
if ( $page_order ) { |
|
1903
|
2
|
|
|
|
|
10
|
$self->{_page_order} = 1; |
|
1904
|
2
|
|
|
|
|
5
|
$self->{_page_setup_changed} = 1; |
|
1905
|
|
|
|
|
|
|
} |
|
1906
|
|
|
|
|
|
|
else { |
|
1907
|
0
|
|
|
|
|
0
|
$self->{_page_order} = 0; |
|
1908
|
|
|
|
|
|
|
} |
|
1909
|
|
|
|
|
|
|
} |
|
1910
|
|
|
|
|
|
|
|
|
1911
|
|
|
|
|
|
|
|
|
1912
|
|
|
|
|
|
|
############################################################################### |
|
1913
|
|
|
|
|
|
|
# |
|
1914
|
|
|
|
|
|
|
# set_start_page() |
|
1915
|
|
|
|
|
|
|
# |
|
1916
|
|
|
|
|
|
|
# Set the start page number. |
|
1917
|
|
|
|
|
|
|
# |
|
1918
|
|
|
|
|
|
|
sub set_start_page { |
|
1919
|
|
|
|
|
|
|
|
|
1920
|
3
|
|
|
3
|
0
|
26
|
my $self = shift; |
|
1921
|
3
|
50
|
|
|
|
19
|
return unless defined $_[0]; |
|
1922
|
|
|
|
|
|
|
|
|
1923
|
3
|
|
|
|
|
25
|
$self->{_page_start} = $_[0]; |
|
1924
|
|
|
|
|
|
|
} |
|
1925
|
|
|
|
|
|
|
|
|
1926
|
|
|
|
|
|
|
|
|
1927
|
|
|
|
|
|
|
############################################################################### |
|
1928
|
|
|
|
|
|
|
# |
|
1929
|
|
|
|
|
|
|
# set_first_row_column() |
|
1930
|
|
|
|
|
|
|
# |
|
1931
|
|
|
|
|
|
|
# Set the topmost and leftmost visible row and column. |
|
1932
|
|
|
|
|
|
|
# TODO: Document this when tested fully for interaction with panes. |
|
1933
|
|
|
|
|
|
|
# |
|
1934
|
|
|
|
|
|
|
sub set_first_row_column { |
|
1935
|
|
|
|
|
|
|
|
|
1936
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
1937
|
|
|
|
|
|
|
|
|
1938
|
0
|
|
0
|
|
|
0
|
my $row = $_[0] || 0; |
|
1939
|
0
|
|
0
|
|
|
0
|
my $col = $_[1] || 0; |
|
1940
|
|
|
|
|
|
|
|
|
1941
|
0
|
0
|
|
|
|
0
|
$row = $self->{_xls_rowmax} if $row > $self->{_xls_rowmax}; |
|
1942
|
0
|
0
|
|
|
|
0
|
$col = $self->{_xls_colmax} if $col > $self->{_xls_colmax}; |
|
1943
|
|
|
|
|
|
|
|
|
1944
|
0
|
|
|
|
|
0
|
$self->{_first_row} = $row; |
|
1945
|
0
|
|
|
|
|
0
|
$self->{_first_col} = $col; |
|
1946
|
|
|
|
|
|
|
} |
|
1947
|
|
|
|
|
|
|
|
|
1948
|
|
|
|
|
|
|
|
|
1949
|
|
|
|
|
|
|
############################################################################### |
|
1950
|
|
|
|
|
|
|
# |
|
1951
|
|
|
|
|
|
|
# add_write_handler($re, $code_ref) |
|
1952
|
|
|
|
|
|
|
# |
|
1953
|
|
|
|
|
|
|
# Allow the user to add their own matches and handlers to the write() method. |
|
1954
|
|
|
|
|
|
|
# |
|
1955
|
|
|
|
|
|
|
sub add_write_handler { |
|
1956
|
|
|
|
|
|
|
|
|
1957
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
1958
|
|
|
|
|
|
|
|
|
1959
|
0
|
0
|
|
|
|
0
|
return unless @_ == 2; |
|
1960
|
0
|
0
|
|
|
|
0
|
return unless ref $_[1] eq 'CODE'; |
|
1961
|
|
|
|
|
|
|
|
|
1962
|
0
|
|
|
|
|
0
|
push @{ $self->{_write_match} }, [@_]; |
|
|
0
|
|
|
|
|
0
|
|
|
1963
|
|
|
|
|
|
|
} |
|
1964
|
|
|
|
|
|
|
|
|
1965
|
|
|
|
|
|
|
|
|
1966
|
|
|
|
|
|
|
############################################################################### |
|
1967
|
|
|
|
|
|
|
# |
|
1968
|
|
|
|
|
|
|
# write($row, $col, $token, $format) |
|
1969
|
|
|
|
|
|
|
# |
|
1970
|
|
|
|
|
|
|
# Parse $token and call appropriate write method. $row and $column are zero |
|
1971
|
|
|
|
|
|
|
# indexed. $format is optional. |
|
1972
|
|
|
|
|
|
|
# |
|
1973
|
|
|
|
|
|
|
# Returns: return value of called subroutine |
|
1974
|
|
|
|
|
|
|
# |
|
1975
|
|
|
|
|
|
|
sub write { |
|
1976
|
|
|
|
|
|
|
|
|
1977
|
10398
|
|
|
10398
|
0
|
26204
|
my $self = shift; |
|
1978
|
|
|
|
|
|
|
|
|
1979
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
1980
|
10398
|
100
|
|
|
|
30482
|
if ( $_[0] =~ /^\D/ ) { |
|
1981
|
1054
|
|
|
|
|
4661
|
@_ = $self->_substitute_cellref( @_ ); |
|
1982
|
|
|
|
|
|
|
} |
|
1983
|
|
|
|
|
|
|
|
|
1984
|
10398
|
|
|
|
|
16286
|
my $token = $_[2]; |
|
1985
|
|
|
|
|
|
|
|
|
1986
|
|
|
|
|
|
|
# Handle undefs as blanks |
|
1987
|
10398
|
100
|
|
|
|
19379
|
$token = '' unless defined $token; |
|
1988
|
|
|
|
|
|
|
|
|
1989
|
|
|
|
|
|
|
|
|
1990
|
|
|
|
|
|
|
# First try user defined matches. |
|
1991
|
10398
|
|
|
|
|
14534
|
for my $aref ( @{ $self->{_write_match} } ) { |
|
|
10398
|
|
|
|
|
23242
|
|
|
1992
|
0
|
|
|
|
|
0
|
my $re = $aref->[0]; |
|
1993
|
0
|
|
|
|
|
0
|
my $sub = $aref->[1]; |
|
1994
|
|
|
|
|
|
|
|
|
1995
|
0
|
0
|
|
|
|
0
|
if ( $token =~ /$re/ ) { |
|
1996
|
0
|
|
|
|
|
0
|
my $match = &$sub( $self, @_ ); |
|
1997
|
0
|
0
|
|
|
|
0
|
return $match if defined $match; |
|
1998
|
|
|
|
|
|
|
} |
|
1999
|
|
|
|
|
|
|
} |
|
2000
|
|
|
|
|
|
|
|
|
2001
|
|
|
|
|
|
|
|
|
2002
|
|
|
|
|
|
|
# Match an array ref. |
|
2003
|
10398
|
100
|
33
|
|
|
65041
|
if ( ref $token eq "ARRAY" ) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
2004
|
1012
|
|
|
|
|
3432
|
return $self->write_row( @_ ); |
|
2005
|
|
|
|
|
|
|
} |
|
2006
|
|
|
|
|
|
|
|
|
2007
|
|
|
|
|
|
|
# Match integer with leading zero(s) |
|
2008
|
|
|
|
|
|
|
elsif ( $self->{_leading_zeros} and $token =~ /^0\d+$/ ) { |
|
2009
|
0
|
|
|
|
|
0
|
return $self->write_string( @_ ); |
|
2010
|
|
|
|
|
|
|
} |
|
2011
|
|
|
|
|
|
|
|
|
2012
|
|
|
|
|
|
|
# Match number |
|
2013
|
|
|
|
|
|
|
elsif ( $token =~ /^([+-]?)(?=[0-9]|\.[0-9])[0-9]*(\.[0-9]*)?([Ee]([+-]?[0-9]+))?$/ ) { |
|
2014
|
7196
|
|
|
|
|
17133
|
return $self->write_number( @_ ); |
|
2015
|
|
|
|
|
|
|
} |
|
2016
|
|
|
|
|
|
|
|
|
2017
|
|
|
|
|
|
|
# Match http, https or ftp URL |
|
2018
|
|
|
|
|
|
|
elsif ( $token =~ m|^[fh]tt?ps?://| ) { |
|
2019
|
14
|
|
|
|
|
179
|
return $self->write_url( @_ ); |
|
2020
|
|
|
|
|
|
|
} |
|
2021
|
|
|
|
|
|
|
|
|
2022
|
|
|
|
|
|
|
# Match mailto: |
|
2023
|
|
|
|
|
|
|
elsif ( $token =~ m/^mailto:/ ) { |
|
2024
|
0
|
|
|
|
|
0
|
return $self->write_url( @_ ); |
|
2025
|
|
|
|
|
|
|
} |
|
2026
|
|
|
|
|
|
|
|
|
2027
|
|
|
|
|
|
|
# Match internal or external sheet link |
|
2028
|
|
|
|
|
|
|
elsif ( $token =~ m[^(?:in|ex)ternal:] ) { |
|
2029
|
0
|
|
|
|
|
0
|
return $self->write_url( @_ ); |
|
2030
|
|
|
|
|
|
|
} |
|
2031
|
|
|
|
|
|
|
|
|
2032
|
|
|
|
|
|
|
# Match formula |
|
2033
|
|
|
|
|
|
|
elsif ( $token =~ /^=/ ) { |
|
2034
|
21
|
|
|
|
|
77
|
return $self->write_formula( @_ ); |
|
2035
|
|
|
|
|
|
|
} |
|
2036
|
|
|
|
|
|
|
|
|
2037
|
|
|
|
|
|
|
# Match array formula |
|
2038
|
|
|
|
|
|
|
elsif ( $token =~ /^{=.*}$/ ) { |
|
2039
|
2
|
|
|
|
|
15
|
return $self->write_formula( @_ ); |
|
2040
|
|
|
|
|
|
|
} |
|
2041
|
|
|
|
|
|
|
|
|
2042
|
|
|
|
|
|
|
# Match blank |
|
2043
|
|
|
|
|
|
|
elsif ( $token eq '' ) { |
|
2044
|
29
|
|
|
|
|
95
|
splice @_, 2, 1; # remove the empty string from the parameter list |
|
2045
|
29
|
|
|
|
|
95
|
return $self->write_blank( @_ ); |
|
2046
|
|
|
|
|
|
|
} |
|
2047
|
|
|
|
|
|
|
|
|
2048
|
|
|
|
|
|
|
# Default: match string |
|
2049
|
|
|
|
|
|
|
else { |
|
2050
|
2124
|
|
|
|
|
5406
|
return $self->write_string( @_ ); |
|
2051
|
|
|
|
|
|
|
} |
|
2052
|
|
|
|
|
|
|
} |
|
2053
|
|
|
|
|
|
|
|
|
2054
|
|
|
|
|
|
|
|
|
2055
|
|
|
|
|
|
|
############################################################################### |
|
2056
|
|
|
|
|
|
|
# |
|
2057
|
|
|
|
|
|
|
# write_row($row, $col, $array_ref, $format) |
|
2058
|
|
|
|
|
|
|
# |
|
2059
|
|
|
|
|
|
|
# Write a row of data starting from ($row, $col). Call write_col() if any of |
|
2060
|
|
|
|
|
|
|
# the elements of the array ref are in turn array refs. This allows the writing |
|
2061
|
|
|
|
|
|
|
# of 1D or 2D arrays of data in one go. |
|
2062
|
|
|
|
|
|
|
# |
|
2063
|
|
|
|
|
|
|
# Returns: the first encountered error value or zero for no errors |
|
2064
|
|
|
|
|
|
|
# |
|
2065
|
|
|
|
|
|
|
sub write_row { |
|
2066
|
|
|
|
|
|
|
|
|
2067
|
1019
|
|
|
1019
|
0
|
2036
|
my $self = shift; |
|
2068
|
|
|
|
|
|
|
|
|
2069
|
|
|
|
|
|
|
|
|
2070
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
2071
|
1019
|
100
|
|
|
|
3906
|
if ( $_[0] =~ /^\D/ ) { |
|
2072
|
7
|
|
|
|
|
26
|
@_ = $self->_substitute_cellref( @_ ); |
|
2073
|
|
|
|
|
|
|
} |
|
2074
|
|
|
|
|
|
|
|
|
2075
|
|
|
|
|
|
|
# Catch non array refs passed by user. |
|
2076
|
1019
|
50
|
|
|
|
3022
|
if ( ref $_[2] ne 'ARRAY' ) { |
|
2077
|
0
|
|
|
|
|
0
|
croak "Not an array ref in call to write_row()$!"; |
|
2078
|
|
|
|
|
|
|
} |
|
2079
|
|
|
|
|
|
|
|
|
2080
|
1019
|
|
|
|
|
2031
|
my $row = shift; |
|
2081
|
1019
|
|
|
|
|
1723
|
my $col = shift; |
|
2082
|
1019
|
|
|
|
|
1615
|
my $tokens = shift; |
|
2083
|
1019
|
|
|
|
|
2128
|
my @options = @_; |
|
2084
|
1019
|
|
|
|
|
1673
|
my $error = 0; |
|
2085
|
1019
|
|
|
|
|
1645
|
my $ret; |
|
2086
|
|
|
|
|
|
|
|
|
2087
|
1019
|
|
|
|
|
2212
|
for my $token ( @$tokens ) { |
|
2088
|
|
|
|
|
|
|
|
|
2089
|
|
|
|
|
|
|
# Check for nested arrays |
|
2090
|
3869
|
100
|
|
|
|
8208
|
if ( ref $token eq "ARRAY" ) { |
|
2091
|
1091
|
|
|
|
|
3347
|
$ret = $self->write_col( $row, $col, $token, @options ); |
|
2092
|
|
|
|
|
|
|
} |
|
2093
|
|
|
|
|
|
|
else { |
|
2094
|
2778
|
|
|
|
|
5353
|
$ret = $self->write( $row, $col, $token, @options ); |
|
2095
|
|
|
|
|
|
|
} |
|
2096
|
|
|
|
|
|
|
|
|
2097
|
|
|
|
|
|
|
# Return only the first error encountered, if any. |
|
2098
|
3869
|
|
33
|
|
|
14067
|
$error ||= $ret; |
|
2099
|
3869
|
|
|
|
|
6401
|
$col++; |
|
2100
|
|
|
|
|
|
|
} |
|
2101
|
|
|
|
|
|
|
|
|
2102
|
1019
|
|
|
|
|
3434
|
return $error; |
|
2103
|
|
|
|
|
|
|
} |
|
2104
|
|
|
|
|
|
|
|
|
2105
|
|
|
|
|
|
|
|
|
2106
|
|
|
|
|
|
|
############################################################################### |
|
2107
|
|
|
|
|
|
|
# |
|
2108
|
|
|
|
|
|
|
# write_col($row, $col, $array_ref, $format) |
|
2109
|
|
|
|
|
|
|
# |
|
2110
|
|
|
|
|
|
|
# Write a column of data starting from ($row, $col). Call write_row() if any of |
|
2111
|
|
|
|
|
|
|
# the elements of the array ref are in turn array refs. This allows the writing |
|
2112
|
|
|
|
|
|
|
# of 1D or 2D arrays of data in one go. |
|
2113
|
|
|
|
|
|
|
# |
|
2114
|
|
|
|
|
|
|
# Returns: the first encountered error value or zero for no errors |
|
2115
|
|
|
|
|
|
|
# |
|
2116
|
|
|
|
|
|
|
sub write_col { |
|
2117
|
|
|
|
|
|
|
|
|
2118
|
1112
|
|
|
1112
|
0
|
2110
|
my $self = shift; |
|
2119
|
|
|
|
|
|
|
|
|
2120
|
|
|
|
|
|
|
|
|
2121
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
2122
|
1112
|
100
|
|
|
|
3757
|
if ( $_[0] =~ /^\D/ ) { |
|
2123
|
19
|
|
|
|
|
83
|
@_ = $self->_substitute_cellref( @_ ); |
|
2124
|
|
|
|
|
|
|
} |
|
2125
|
|
|
|
|
|
|
|
|
2126
|
|
|
|
|
|
|
# Catch non array refs passed by user. |
|
2127
|
1112
|
50
|
|
|
|
3222
|
if ( ref $_[2] ne 'ARRAY' ) { |
|
2128
|
0
|
|
|
|
|
0
|
croak "Not an array ref in call to write_col()$!"; |
|
2129
|
|
|
|
|
|
|
} |
|
2130
|
|
|
|
|
|
|
|
|
2131
|
1112
|
|
|
|
|
2110
|
my $row = shift; |
|
2132
|
1112
|
|
|
|
|
1844
|
my $col = shift; |
|
2133
|
1112
|
|
|
|
|
1759
|
my $tokens = shift; |
|
2134
|
1112
|
|
|
|
|
2267
|
my @options = @_; |
|
2135
|
1112
|
|
|
|
|
1820
|
my $error = 0; |
|
2136
|
1112
|
|
|
|
|
1765
|
my $ret; |
|
2137
|
|
|
|
|
|
|
|
|
2138
|
1112
|
|
|
|
|
2357
|
for my $token ( @$tokens ) { |
|
2139
|
|
|
|
|
|
|
|
|
2140
|
|
|
|
|
|
|
# write() will deal with any nested arrays |
|
2141
|
5423
|
|
|
|
|
12442
|
$ret = $self->write( $row, $col, $token, @options ); |
|
2142
|
|
|
|
|
|
|
|
|
2143
|
|
|
|
|
|
|
# Return only the first error encountered, if any. |
|
2144
|
5423
|
|
33
|
|
|
18791
|
$error ||= $ret; |
|
2145
|
5423
|
|
|
|
|
9184
|
$row++; |
|
2146
|
|
|
|
|
|
|
} |
|
2147
|
|
|
|
|
|
|
|
|
2148
|
1112
|
|
|
|
|
2556
|
return $error; |
|
2149
|
|
|
|
|
|
|
} |
|
2150
|
|
|
|
|
|
|
|
|
2151
|
|
|
|
|
|
|
|
|
2152
|
|
|
|
|
|
|
############################################################################### |
|
2153
|
|
|
|
|
|
|
# |
|
2154
|
|
|
|
|
|
|
# write_comment($row, $col, $comment) |
|
2155
|
|
|
|
|
|
|
# |
|
2156
|
|
|
|
|
|
|
# Write a comment to the specified row and column (zero indexed). |
|
2157
|
|
|
|
|
|
|
# |
|
2158
|
|
|
|
|
|
|
# Returns 0 : normal termination |
|
2159
|
|
|
|
|
|
|
# -1 : insufficient number of arguments |
|
2160
|
|
|
|
|
|
|
# -2 : row or column out of range |
|
2161
|
|
|
|
|
|
|
# |
|
2162
|
|
|
|
|
|
|
sub write_comment { |
|
2163
|
|
|
|
|
|
|
|
|
2164
|
4153
|
|
|
4153
|
0
|
14244
|
my $self = shift; |
|
2165
|
|
|
|
|
|
|
|
|
2166
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
2167
|
4153
|
100
|
|
|
|
10114
|
if ( $_[0] =~ /^\D/ ) { |
|
2168
|
57
|
|
|
|
|
230
|
@_ = $self->_substitute_cellref( @_ ); |
|
2169
|
|
|
|
|
|
|
} |
|
2170
|
|
|
|
|
|
|
|
|
2171
|
4153
|
50
|
|
|
|
8578
|
if ( @_ < 3 ) { return -1 } # Check the number of args |
|
|
0
|
|
|
|
|
0
|
|
|
2172
|
|
|
|
|
|
|
|
|
2173
|
4153
|
|
|
|
|
6803
|
my $row = $_[0]; |
|
2174
|
4153
|
|
|
|
|
5450
|
my $col = $_[1]; |
|
2175
|
|
|
|
|
|
|
|
|
2176
|
|
|
|
|
|
|
# Check for pairs of optional arguments, i.e. an odd number of args. |
|
2177
|
4153
|
50
|
|
|
|
7719
|
croak "Uneven number of additional arguments" unless @_ % 2; |
|
2178
|
|
|
|
|
|
|
|
|
2179
|
|
|
|
|
|
|
# Check that row and col are valid and store max and min values |
|
2180
|
4153
|
50
|
|
|
|
7451
|
return -2 if $self->_check_dimensions( $row, $col ); |
|
2181
|
|
|
|
|
|
|
|
|
2182
|
4153
|
|
|
|
|
6742
|
$self->{_has_vml} = 1; |
|
2183
|
4153
|
|
|
|
|
5815
|
$self->{_has_comments} = 1; |
|
2184
|
|
|
|
|
|
|
|
|
2185
|
|
|
|
|
|
|
# Process the properties of the cell comment. |
|
2186
|
4153
|
|
|
|
|
16226
|
$self->{_comments}->{$row}->{$col} = [ @_ ]; |
|
2187
|
|
|
|
|
|
|
} |
|
2188
|
|
|
|
|
|
|
|
|
2189
|
|
|
|
|
|
|
|
|
2190
|
|
|
|
|
|
|
############################################################################### |
|
2191
|
|
|
|
|
|
|
# |
|
2192
|
|
|
|
|
|
|
# write_number($row, $col, $num, $format) |
|
2193
|
|
|
|
|
|
|
# |
|
2194
|
|
|
|
|
|
|
# Write a double to the specified row and column (zero indexed). |
|
2195
|
|
|
|
|
|
|
# An integer can be written as a double. Excel will display an |
|
2196
|
|
|
|
|
|
|
# integer. $format is optional. |
|
2197
|
|
|
|
|
|
|
# |
|
2198
|
|
|
|
|
|
|
# Returns 0 : normal termination |
|
2199
|
|
|
|
|
|
|
# -1 : insufficient number of arguments |
|
2200
|
|
|
|
|
|
|
# -2 : row or column out of range |
|
2201
|
|
|
|
|
|
|
# |
|
2202
|
|
|
|
|
|
|
sub write_number { |
|
2203
|
|
|
|
|
|
|
|
|
2204
|
7207
|
|
|
7207
|
0
|
10869
|
my $self = shift; |
|
2205
|
|
|
|
|
|
|
|
|
2206
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
2207
|
7207
|
50
|
|
|
|
16806
|
if ( $_[0] =~ /^\D/ ) { |
|
2208
|
0
|
|
|
|
|
0
|
@_ = $self->_substitute_cellref( @_ ); |
|
2209
|
|
|
|
|
|
|
} |
|
2210
|
|
|
|
|
|
|
|
|
2211
|
7207
|
50
|
|
|
|
14368
|
if ( @_ < 3 ) { return -1 } # Check the number of args |
|
|
0
|
|
|
|
|
0
|
|
|
2212
|
|
|
|
|
|
|
|
|
2213
|
|
|
|
|
|
|
|
|
2214
|
7207
|
|
|
|
|
11440
|
my $row = $_[0]; # Zero indexed row |
|
2215
|
7207
|
|
|
|
|
10074
|
my $col = $_[1]; # Zero indexed column |
|
2216
|
7207
|
|
|
|
|
11200
|
my $num = $_[2] + 0; |
|
2217
|
7207
|
|
|
|
|
10165
|
my $xf = $_[3]; # The cell format |
|
2218
|
7207
|
|
|
|
|
10363
|
my $type = 'n'; # The data type |
|
2219
|
|
|
|
|
|
|
|
|
2220
|
|
|
|
|
|
|
# Check that row and col are valid and store max and min values |
|
2221
|
7207
|
50
|
|
|
|
13732
|
return -2 if $self->_check_dimensions( $row, $col ); |
|
2222
|
|
|
|
|
|
|
|
|
2223
|
|
|
|
|
|
|
# Write previous row if in in-line string optimization mode. |
|
2224
|
7207
|
100
|
100
|
|
|
16554
|
if ( $self->{_optimization} == 1 && $row > $self->{_previous_row} ) { |
|
2225
|
2
|
|
|
|
|
9
|
$self->_write_single_row( $row ); |
|
2226
|
|
|
|
|
|
|
} |
|
2227
|
|
|
|
|
|
|
|
|
2228
|
7207
|
|
|
|
|
21650
|
$self->{_table}->{$row}->{$col} = [ $type, $num, $xf ]; |
|
2229
|
|
|
|
|
|
|
|
|
2230
|
7207
|
|
|
|
|
16075
|
return 0; |
|
2231
|
|
|
|
|
|
|
} |
|
2232
|
|
|
|
|
|
|
|
|
2233
|
|
|
|
|
|
|
|
|
2234
|
|
|
|
|
|
|
############################################################################### |
|
2235
|
|
|
|
|
|
|
# |
|
2236
|
|
|
|
|
|
|
# write_string ($row, $col, $string, $format) |
|
2237
|
|
|
|
|
|
|
# |
|
2238
|
|
|
|
|
|
|
# Write a string to the specified row and column (zero indexed). |
|
2239
|
|
|
|
|
|
|
# $format is optional. |
|
2240
|
|
|
|
|
|
|
# Returns 0 : normal termination |
|
2241
|
|
|
|
|
|
|
# -1 : insufficient number of arguments |
|
2242
|
|
|
|
|
|
|
# -2 : row or column out of range |
|
2243
|
|
|
|
|
|
|
# -3 : long string truncated to 32767 chars |
|
2244
|
|
|
|
|
|
|
# -4 : Ignore undef strings |
|
2245
|
|
|
|
|
|
|
# |
|
2246
|
|
|
|
|
|
|
sub write_string { |
|
2247
|
|
|
|
|
|
|
|
|
2248
|
2985
|
|
|
2985
|
0
|
6522
|
my $self = shift; |
|
2249
|
|
|
|
|
|
|
|
|
2250
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
2251
|
2985
|
100
|
|
|
|
8068
|
if ( $_[0] =~ /^\D/ ) { |
|
2252
|
45
|
|
|
|
|
101
|
@_ = $self->_substitute_cellref( @_ ); |
|
2253
|
|
|
|
|
|
|
} |
|
2254
|
|
|
|
|
|
|
|
|
2255
|
2985
|
50
|
|
|
|
6445
|
if ( @_ < 3 ) { return -1 } # Check the number of args |
|
|
0
|
|
|
|
|
0
|
|
|
2256
|
|
|
|
|
|
|
|
|
2257
|
2985
|
|
|
|
|
4923
|
my $row = $_[0]; # Zero indexed row |
|
2258
|
2985
|
|
|
|
|
4527
|
my $col = $_[1]; # Zero indexed column |
|
2259
|
2985
|
|
|
|
|
4469
|
my $str = $_[2]; |
|
2260
|
2985
|
|
|
|
|
4319
|
my $xf = $_[3]; # The cell format |
|
2261
|
2985
|
|
|
|
|
4369
|
my $type = 's'; # The data type |
|
2262
|
2985
|
|
|
|
|
4503
|
my $index; |
|
2263
|
2985
|
|
|
|
|
4651
|
my $str_error = 0; |
|
2264
|
|
|
|
|
|
|
|
|
2265
|
|
|
|
|
|
|
# Ignore undef strings. |
|
2266
|
2985
|
50
|
|
|
|
6165
|
return -4 if !defined $str; |
|
2267
|
|
|
|
|
|
|
|
|
2268
|
|
|
|
|
|
|
# Check that row and col are valid and store max and min values |
|
2269
|
2985
|
100
|
|
|
|
6251
|
return -2 if $self->_check_dimensions( $row, $col ); |
|
2270
|
|
|
|
|
|
|
|
|
2271
|
|
|
|
|
|
|
# Check that the string is < 32767 chars |
|
2272
|
2984
|
50
|
|
|
|
7093
|
if ( length $str > $self->{_xls_strmax} ) { |
|
2273
|
0
|
|
|
|
|
0
|
$str = substr( $str, 0, $self->{_xls_strmax} ); |
|
2274
|
0
|
|
|
|
|
0
|
$str_error = -3; |
|
2275
|
|
|
|
|
|
|
} |
|
2276
|
|
|
|
|
|
|
|
|
2277
|
|
|
|
|
|
|
# Write a shared string or an in-line string based on optimisation level. |
|
2278
|
2984
|
100
|
|
|
|
6202
|
if ( $self->{_optimization} == 0 ) { |
|
2279
|
2694
|
|
|
|
|
5789
|
$index = $self->_get_shared_string_index( $str ); |
|
2280
|
|
|
|
|
|
|
} |
|
2281
|
|
|
|
|
|
|
else { |
|
2282
|
290
|
|
|
|
|
459
|
$index = $str; |
|
2283
|
|
|
|
|
|
|
} |
|
2284
|
|
|
|
|
|
|
|
|
2285
|
|
|
|
|
|
|
# Write previous row if in in-line string optimization mode. |
|
2286
|
2984
|
100
|
100
|
|
|
8460
|
if ( $self->{_optimization} == 1 && $row > $self->{_previous_row} ) { |
|
2287
|
278
|
|
|
|
|
773
|
$self->_write_single_row( $row ); |
|
2288
|
|
|
|
|
|
|
} |
|
2289
|
|
|
|
|
|
|
|
|
2290
|
2984
|
|
|
|
|
11196
|
$self->{_table}->{$row}->{$col} = [ $type, $index, $xf ]; |
|
2291
|
|
|
|
|
|
|
|
|
2292
|
2984
|
|
|
|
|
7539
|
return $str_error; |
|
2293
|
|
|
|
|
|
|
} |
|
2294
|
|
|
|
|
|
|
|
|
2295
|
|
|
|
|
|
|
|
|
2296
|
|
|
|
|
|
|
############################################################################### |
|
2297
|
|
|
|
|
|
|
# |
|
2298
|
|
|
|
|
|
|
# write_rich_string( $row, $column, $format, $string, ..., $cell_format ) |
|
2299
|
|
|
|
|
|
|
# |
|
2300
|
|
|
|
|
|
|
# The write_rich_string() method is used to write strings with multiple formats. |
|
2301
|
|
|
|
|
|
|
# The method receives string fragments prefixed by format objects. The final |
|
2302
|
|
|
|
|
|
|
# format object is used as the cell format. |
|
2303
|
|
|
|
|
|
|
# |
|
2304
|
|
|
|
|
|
|
# Returns 0 : normal termination. |
|
2305
|
|
|
|
|
|
|
# -1 : insufficient number of arguments. |
|
2306
|
|
|
|
|
|
|
# -2 : row or column out of range. |
|
2307
|
|
|
|
|
|
|
# -3 : long string truncated to 32767 chars. |
|
2308
|
|
|
|
|
|
|
# -4 : 2 consecutive formats used. |
|
2309
|
|
|
|
|
|
|
# |
|
2310
|
|
|
|
|
|
|
sub write_rich_string { |
|
2311
|
|
|
|
|
|
|
|
|
2312
|
29
|
|
|
29
|
0
|
1112
|
my $self = shift; |
|
2313
|
|
|
|
|
|
|
|
|
2314
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
2315
|
29
|
100
|
|
|
|
823
|
if ( $_[0] =~ /^\D/ ) { |
|
2316
|
28
|
|
|
|
|
144
|
@_ = $self->_substitute_cellref( @_ ); |
|
2317
|
|
|
|
|
|
|
} |
|
2318
|
|
|
|
|
|
|
|
|
2319
|
29
|
50
|
|
|
|
110
|
if ( @_ < 3 ) { return -1 } # Check the number of args |
|
|
0
|
|
|
|
|
0
|
|
|
2320
|
|
|
|
|
|
|
|
|
2321
|
29
|
|
|
|
|
76
|
my $row = shift; # Zero indexed row. |
|
2322
|
29
|
|
|
|
|
61
|
my $col = shift; # Zero indexed column. |
|
2323
|
29
|
|
|
|
|
81
|
my $str = ''; |
|
2324
|
29
|
|
|
|
|
59
|
my $xf = undef; |
|
2325
|
29
|
|
|
|
|
54
|
my $type = 's'; # The data type. |
|
2326
|
29
|
|
|
|
|
54
|
my $length = 0; # String length. |
|
2327
|
29
|
|
|
|
|
49
|
my $index; |
|
2328
|
29
|
|
|
|
|
52
|
my $str_error = 0; |
|
2329
|
|
|
|
|
|
|
|
|
2330
|
|
|
|
|
|
|
# Check that row and col are valid and store max and min values |
|
2331
|
29
|
50
|
|
|
|
100
|
return -2 if $self->_check_dimensions( $row, $col ); |
|
2332
|
|
|
|
|
|
|
|
|
2333
|
|
|
|
|
|
|
|
|
2334
|
|
|
|
|
|
|
# If the last arg is a format we use it as the cell format. |
|
2335
|
29
|
100
|
|
|
|
108
|
if ( ref $_[-1] ) { |
|
2336
|
3
|
|
|
|
|
8
|
$xf = pop @_; |
|
2337
|
|
|
|
|
|
|
} |
|
2338
|
|
|
|
|
|
|
|
|
2339
|
|
|
|
|
|
|
|
|
2340
|
|
|
|
|
|
|
# Create a temp XML::Writer object and use it to write the rich string |
|
2341
|
|
|
|
|
|
|
# XML to a string. |
|
2342
|
29
|
50
|
|
17
|
|
864
|
open my $str_fh, '>', \$str or die "Failed to open filehandle: $!"; |
|
|
17
|
|
|
|
|
125
|
|
|
|
17
|
|
|
|
|
33
|
|
|
|
17
|
|
|
|
|
122
|
|
|
2343
|
29
|
|
|
|
|
12711
|
binmode $str_fh, ':utf8'; |
|
2344
|
|
|
|
|
|
|
|
|
2345
|
29
|
|
|
|
|
226
|
my $writer = Excel::Writer::XLSX::Package::XMLwriter->new( $str_fh ); |
|
2346
|
|
|
|
|
|
|
|
|
2347
|
29
|
|
|
|
|
169
|
$self->{_rstring} = $writer; |
|
2348
|
|
|
|
|
|
|
|
|
2349
|
|
|
|
|
|
|
# Create a temp format with the default font for unformatted fragments. |
|
2350
|
29
|
|
|
|
|
217
|
my $default = Excel::Writer::XLSX::Format->new(); |
|
2351
|
|
|
|
|
|
|
|
|
2352
|
|
|
|
|
|
|
# Convert the list of $format, $string tokens to pairs of ($format, $string) |
|
2353
|
|
|
|
|
|
|
# except for the first $string fragment which doesn't require a default |
|
2354
|
|
|
|
|
|
|
# formatting run. Use the default for strings without a leading format. |
|
2355
|
29
|
|
|
|
|
169
|
my @fragments; |
|
2356
|
29
|
|
|
|
|
63
|
my $last = 'format'; |
|
2357
|
29
|
|
|
|
|
53
|
my $pos = 0; |
|
2358
|
|
|
|
|
|
|
|
|
2359
|
29
|
|
|
|
|
144
|
for my $token ( @_ ) { |
|
2360
|
114
|
100
|
|
|
|
258
|
if ( !ref $token ) { |
|
2361
|
|
|
|
|
|
|
|
|
2362
|
|
|
|
|
|
|
# Token is a string. |
|
2363
|
81
|
100
|
|
|
|
183
|
if ( $last ne 'format' ) { |
|
2364
|
|
|
|
|
|
|
|
|
2365
|
|
|
|
|
|
|
# If previous token wasn't a format add one before the string. |
|
2366
|
25
|
|
|
|
|
66
|
push @fragments, ( $default, $token ); |
|
2367
|
|
|
|
|
|
|
} |
|
2368
|
|
|
|
|
|
|
else { |
|
2369
|
|
|
|
|
|
|
|
|
2370
|
|
|
|
|
|
|
# If previous token was a format just add the string. |
|
2371
|
56
|
|
|
|
|
114
|
push @fragments, $token; |
|
2372
|
|
|
|
|
|
|
} |
|
2373
|
|
|
|
|
|
|
|
|
2374
|
81
|
|
|
|
|
129
|
$length += length $token; # Keep track of actual string length. |
|
2375
|
81
|
|
|
|
|
127
|
$last = 'string'; |
|
2376
|
|
|
|
|
|
|
} |
|
2377
|
|
|
|
|
|
|
else { |
|
2378
|
|
|
|
|
|
|
|
|
2379
|
|
|
|
|
|
|
# Can't allow 2 formats in a row. |
|
2380
|
33
|
100
|
100
|
|
|
142
|
if ( $last eq 'format' && $pos > 0 ) { |
|
2381
|
1
|
|
|
|
|
8
|
return -4; |
|
2382
|
|
|
|
|
|
|
} |
|
2383
|
|
|
|
|
|
|
|
|
2384
|
|
|
|
|
|
|
# Token is a format object. Add it to the fragment list. |
|
2385
|
32
|
|
|
|
|
62
|
push @fragments, $token; |
|
2386
|
32
|
|
|
|
|
65
|
$last = 'format'; |
|
2387
|
|
|
|
|
|
|
} |
|
2388
|
|
|
|
|
|
|
|
|
2389
|
113
|
|
|
|
|
194
|
$pos++; |
|
2390
|
|
|
|
|
|
|
} |
|
2391
|
|
|
|
|
|
|
|
|
2392
|
|
|
|
|
|
|
|
|
2393
|
|
|
|
|
|
|
# If the first token is a string start the element. |
|
2394
|
28
|
100
|
|
|
|
91
|
if ( !ref $fragments[0] ) { |
|
2395
|
24
|
|
|
|
|
120
|
$self->{_rstring}->xml_start_tag( 'r' ); |
|
2396
|
|
|
|
|
|
|
} |
|
2397
|
|
|
|
|
|
|
|
|
2398
|
|
|
|
|
|
|
# Write the XML elements for the $format $string fragments. |
|
2399
|
28
|
|
|
|
|
84
|
for my $token ( @fragments ) { |
|
2400
|
136
|
100
|
|
|
|
329
|
if ( ref $token ) { |
|
2401
|
|
|
|
|
|
|
|
|
2402
|
|
|
|
|
|
|
# Write the font run. |
|
2403
|
56
|
|
|
|
|
188
|
$self->{_rstring}->xml_start_tag( 'r' ); |
|
2404
|
56
|
|
|
|
|
177
|
$self->_write_font( $token ); |
|
2405
|
|
|
|
|
|
|
} |
|
2406
|
|
|
|
|
|
|
else { |
|
2407
|
|
|
|
|
|
|
|
|
2408
|
|
|
|
|
|
|
# Write the string fragment part, with whitespace handling. |
|
2409
|
80
|
|
|
|
|
142
|
my @attributes = (); |
|
2410
|
|
|
|
|
|
|
|
|
2411
|
80
|
100
|
100
|
|
|
480
|
if ( $token =~ /^\s/ || $token =~ /\s$/ ) { |
|
2412
|
10
|
|
|
|
|
26
|
push @attributes, ( 'xml:space' => 'preserve' ); |
|
2413
|
|
|
|
|
|
|
} |
|
2414
|
|
|
|
|
|
|
|
|
2415
|
80
|
|
|
|
|
308
|
$self->{_rstring}->xml_data_element( 't', $token, @attributes ); |
|
2416
|
80
|
|
|
|
|
251
|
$self->{_rstring}->xml_end_tag( 'r' ); |
|
2417
|
|
|
|
|
|
|
} |
|
2418
|
|
|
|
|
|
|
} |
|
2419
|
|
|
|
|
|
|
|
|
2420
|
|
|
|
|
|
|
# Check that the string is < 32767 chars. |
|
2421
|
28
|
50
|
|
|
|
120
|
if ( $length > $self->{_xls_strmax} ) { |
|
2422
|
0
|
|
|
|
|
0
|
return -3; |
|
2423
|
|
|
|
|
|
|
} |
|
2424
|
|
|
|
|
|
|
|
|
2425
|
|
|
|
|
|
|
|
|
2426
|
|
|
|
|
|
|
# Write a shared string or an in-line string based on optimisation level. |
|
2427
|
28
|
100
|
|
|
|
118
|
if ( $self->{_optimization} == 0 ) { |
|
2428
|
20
|
|
|
|
|
80
|
$index = $self->_get_shared_string_index( $str ); |
|
2429
|
|
|
|
|
|
|
} |
|
2430
|
|
|
|
|
|
|
else { |
|
2431
|
8
|
|
|
|
|
16
|
$index = $str; |
|
2432
|
|
|
|
|
|
|
} |
|
2433
|
|
|
|
|
|
|
|
|
2434
|
|
|
|
|
|
|
# Write previous row if in in-line string optimization mode. |
|
2435
|
28
|
100
|
66
|
|
|
141
|
if ( $self->{_optimization} == 1 && $row > $self->{_previous_row} ) { |
|
2436
|
8
|
|
|
|
|
24
|
$self->_write_single_row( $row ); |
|
2437
|
|
|
|
|
|
|
} |
|
2438
|
|
|
|
|
|
|
|
|
2439
|
28
|
|
|
|
|
171
|
$self->{_table}->{$row}->{$col} = [ $type, $index, $xf ]; |
|
2440
|
|
|
|
|
|
|
|
|
2441
|
28
|
|
|
|
|
254
|
return 0; |
|
2442
|
|
|
|
|
|
|
} |
|
2443
|
|
|
|
|
|
|
|
|
2444
|
|
|
|
|
|
|
|
|
2445
|
|
|
|
|
|
|
############################################################################### |
|
2446
|
|
|
|
|
|
|
# |
|
2447
|
|
|
|
|
|
|
# write_blank($row, $col, $format) |
|
2448
|
|
|
|
|
|
|
# |
|
2449
|
|
|
|
|
|
|
# Write a blank cell to the specified row and column (zero indexed). |
|
2450
|
|
|
|
|
|
|
# A blank cell is used to specify formatting without adding a string |
|
2451
|
|
|
|
|
|
|
# or a number. |
|
2452
|
|
|
|
|
|
|
# |
|
2453
|
|
|
|
|
|
|
# A blank cell without a format serves no purpose. Therefore, we don't write |
|
2454
|
|
|
|
|
|
|
# a BLANK record unless a format is specified. This is mainly an optimisation |
|
2455
|
|
|
|
|
|
|
# for the write_row() and write_col() methods. |
|
2456
|
|
|
|
|
|
|
# |
|
2457
|
|
|
|
|
|
|
# Returns 0 : normal termination (including no format) |
|
2458
|
|
|
|
|
|
|
# -1 : insufficient number of arguments |
|
2459
|
|
|
|
|
|
|
# -2 : row or column out of range |
|
2460
|
|
|
|
|
|
|
# |
|
2461
|
|
|
|
|
|
|
sub write_blank { |
|
2462
|
|
|
|
|
|
|
|
|
2463
|
85
|
|
|
85
|
0
|
212
|
my $self = shift; |
|
2464
|
|
|
|
|
|
|
|
|
2465
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
2466
|
85
|
50
|
|
|
|
290
|
if ( $_[0] =~ /^\D/ ) { |
|
2467
|
0
|
|
|
|
|
0
|
@_ = $self->_substitute_cellref( @_ ); |
|
2468
|
|
|
|
|
|
|
} |
|
2469
|
|
|
|
|
|
|
|
|
2470
|
|
|
|
|
|
|
# Check the number of args |
|
2471
|
85
|
50
|
|
|
|
216
|
return -1 if @_ < 2; |
|
2472
|
|
|
|
|
|
|
|
|
2473
|
|
|
|
|
|
|
# Don't write a blank cell unless it has a format |
|
2474
|
85
|
100
|
|
|
|
291
|
return 0 if not defined $_[2]; |
|
2475
|
|
|
|
|
|
|
|
|
2476
|
61
|
|
|
|
|
107
|
my $row = $_[0]; # Zero indexed row |
|
2477
|
61
|
|
|
|
|
97
|
my $col = $_[1]; # Zero indexed column |
|
2478
|
61
|
|
|
|
|
90
|
my $xf = $_[2]; # The cell format |
|
2479
|
61
|
|
|
|
|
98
|
my $type = 'b'; # The data type |
|
2480
|
|
|
|
|
|
|
|
|
2481
|
|
|
|
|
|
|
# Check that row and col are valid and store max and min values |
|
2482
|
61
|
50
|
|
|
|
134
|
return -2 if $self->_check_dimensions( $row, $col ); |
|
2483
|
|
|
|
|
|
|
|
|
2484
|
|
|
|
|
|
|
# Write previous row if in in-line string optimization mode. |
|
2485
|
61
|
50
|
66
|
|
|
188
|
if ( $self->{_optimization} == 1 && $row > $self->{_previous_row} ) { |
|
2486
|
0
|
|
|
|
|
0
|
$self->_write_single_row( $row ); |
|
2487
|
|
|
|
|
|
|
} |
|
2488
|
|
|
|
|
|
|
|
|
2489
|
61
|
|
|
|
|
189
|
$self->{_table}->{$row}->{$col} = [ $type, undef, $xf ]; |
|
2490
|
|
|
|
|
|
|
|
|
2491
|
61
|
|
|
|
|
192
|
return 0; |
|
2492
|
|
|
|
|
|
|
} |
|
2493
|
|
|
|
|
|
|
|
|
2494
|
|
|
|
|
|
|
|
|
2495
|
|
|
|
|
|
|
############################################################################### |
|
2496
|
|
|
|
|
|
|
# |
|
2497
|
|
|
|
|
|
|
# write_formula($row, $col, $formula, $format) |
|
2498
|
|
|
|
|
|
|
# |
|
2499
|
|
|
|
|
|
|
# Write a formula to the specified row and column (zero indexed). |
|
2500
|
|
|
|
|
|
|
# |
|
2501
|
|
|
|
|
|
|
# $format is optional. |
|
2502
|
|
|
|
|
|
|
# |
|
2503
|
|
|
|
|
|
|
# Returns 0 : normal termination |
|
2504
|
|
|
|
|
|
|
# -1 : insufficient number of arguments |
|
2505
|
|
|
|
|
|
|
# -2 : row or column out of range |
|
2506
|
|
|
|
|
|
|
# |
|
2507
|
|
|
|
|
|
|
sub write_formula { |
|
2508
|
|
|
|
|
|
|
|
|
2509
|
114
|
|
|
114
|
0
|
346
|
my $self = shift; |
|
2510
|
|
|
|
|
|
|
|
|
2511
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
2512
|
114
|
100
|
|
|
|
391
|
if ( $_[0] =~ /^\D/ ) { |
|
2513
|
21
|
|
|
|
|
60
|
@_ = $self->_substitute_cellref( @_ ); |
|
2514
|
|
|
|
|
|
|
} |
|
2515
|
|
|
|
|
|
|
|
|
2516
|
114
|
50
|
|
|
|
305
|
if ( @_ < 3 ) { return -1 } # Check the number of args |
|
|
0
|
|
|
|
|
0
|
|
|
2517
|
|
|
|
|
|
|
|
|
2518
|
114
|
|
|
|
|
214
|
my $row = $_[0]; # Zero indexed row |
|
2519
|
114
|
|
|
|
|
196
|
my $col = $_[1]; # Zero indexed column |
|
2520
|
114
|
|
|
|
|
177
|
my $formula = $_[2]; # The formula text string |
|
2521
|
114
|
|
|
|
|
293
|
my $xf = $_[3]; # The format object. |
|
2522
|
114
|
|
|
|
|
292
|
my $value = $_[4]; # Optional formula value. |
|
2523
|
114
|
|
|
|
|
189
|
my $type = 'f'; # The data type |
|
2524
|
|
|
|
|
|
|
|
|
2525
|
|
|
|
|
|
|
# Hand off array formulas. |
|
2526
|
114
|
100
|
|
|
|
327
|
if ( $formula =~ /^{=.*}$/ ) { |
|
2527
|
3
|
|
|
|
|
26
|
return $self->write_array_formula( $row, $col, $row, $col, $formula, |
|
2528
|
|
|
|
|
|
|
$xf, $value ); |
|
2529
|
|
|
|
|
|
|
} |
|
2530
|
|
|
|
|
|
|
|
|
2531
|
|
|
|
|
|
|
# Check that row and col are valid and store max and min values |
|
2532
|
111
|
50
|
|
|
|
262
|
return -2 if $self->_check_dimensions( $row, $col ); |
|
2533
|
|
|
|
|
|
|
|
|
2534
|
|
|
|
|
|
|
# Remove the = sign if it exists. |
|
2535
|
111
|
|
|
|
|
310
|
$formula =~ s/^=//; |
|
2536
|
|
|
|
|
|
|
|
|
2537
|
|
|
|
|
|
|
# Write previous row if in in-line string optimization mode. |
|
2538
|
111
|
50
|
66
|
|
|
328
|
if ( $self->{_optimization} == 1 && $row > $self->{_previous_row} ) { |
|
2539
|
0
|
|
|
|
|
0
|
$self->_write_single_row( $row ); |
|
2540
|
|
|
|
|
|
|
} |
|
2541
|
|
|
|
|
|
|
|
|
2542
|
111
|
|
|
|
|
416
|
$self->{_table}->{$row}->{$col} = [ $type, $formula, $xf, $value ]; |
|
2543
|
|
|
|
|
|
|
|
|
2544
|
111
|
|
|
|
|
393
|
return 0; |
|
2545
|
|
|
|
|
|
|
} |
|
2546
|
|
|
|
|
|
|
|
|
2547
|
|
|
|
|
|
|
|
|
2548
|
|
|
|
|
|
|
############################################################################### |
|
2549
|
|
|
|
|
|
|
# |
|
2550
|
|
|
|
|
|
|
# write_array_formula($row1, $col1, $row2, $col2, $formula, $format) |
|
2551
|
|
|
|
|
|
|
# |
|
2552
|
|
|
|
|
|
|
# Write an array formula to the specified row and column (zero indexed). |
|
2553
|
|
|
|
|
|
|
# |
|
2554
|
|
|
|
|
|
|
# $format is optional. |
|
2555
|
|
|
|
|
|
|
# |
|
2556
|
|
|
|
|
|
|
# Returns 0 : normal termination |
|
2557
|
|
|
|
|
|
|
# -1 : insufficient number of arguments |
|
2558
|
|
|
|
|
|
|
# -2 : row or column out of range |
|
2559
|
|
|
|
|
|
|
# |
|
2560
|
|
|
|
|
|
|
sub write_array_formula { |
|
2561
|
|
|
|
|
|
|
|
|
2562
|
7
|
|
|
7
|
0
|
31
|
my $self = shift; |
|
2563
|
|
|
|
|
|
|
|
|
2564
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
2565
|
7
|
100
|
|
|
|
41
|
if ( $_[0] =~ /^\D/ ) { |
|
2566
|
4
|
|
|
|
|
18
|
@_ = $self->_substitute_cellref( @_ ); |
|
2567
|
|
|
|
|
|
|
} |
|
2568
|
|
|
|
|
|
|
|
|
2569
|
7
|
50
|
|
|
|
40
|
if ( @_ < 5 ) { return -1 } # Check the number of args |
|
|
0
|
|
|
|
|
0
|
|
|
2570
|
|
|
|
|
|
|
|
|
2571
|
7
|
|
|
|
|
100
|
my $row1 = $_[0]; # First row |
|
2572
|
7
|
|
|
|
|
80
|
my $col1 = $_[1]; # First column |
|
2573
|
7
|
|
|
|
|
20
|
my $row2 = $_[2]; # Last row |
|
2574
|
7
|
|
|
|
|
21
|
my $col2 = $_[3]; # Last column |
|
2575
|
7
|
|
|
|
|
16
|
my $formula = $_[4]; # The formula text string |
|
2576
|
7
|
|
|
|
|
13
|
my $xf = $_[5]; # The format object. |
|
2577
|
7
|
|
|
|
|
9
|
my $value = $_[6]; # Optional formula value. |
|
2578
|
7
|
|
|
|
|
15
|
my $type = 'a'; # The data type |
|
2579
|
|
|
|
|
|
|
|
|
2580
|
|
|
|
|
|
|
# Swap last row/col with first row/col as necessary |
|
2581
|
7
|
50
|
|
|
|
31
|
( $row1, $row2 ) = ( $row2, $row1 ) if $row1 > $row2; |
|
2582
|
7
|
50
|
|
|
|
24
|
( $col1, $col2 ) = ( $col1, $col2 ) if $col1 > $col2; |
|
2583
|
|
|
|
|
|
|
|
|
2584
|
|
|
|
|
|
|
|
|
2585
|
|
|
|
|
|
|
# Check that row and col are valid and store max and min values |
|
2586
|
7
|
50
|
|
|
|
22
|
return -2 if $self->_check_dimensions( $row2, $col2 ); |
|
2587
|
|
|
|
|
|
|
|
|
2588
|
|
|
|
|
|
|
|
|
2589
|
|
|
|
|
|
|
# Define array range |
|
2590
|
7
|
|
|
|
|
14
|
my $range; |
|
2591
|
|
|
|
|
|
|
|
|
2592
|
7
|
100
|
66
|
|
|
33
|
if ( $row1 == $row2 and $col1 == $col2 ) { |
|
2593
|
4
|
|
|
|
|
26
|
$range = xl_rowcol_to_cell( $row1, $col1 ); |
|
2594
|
|
|
|
|
|
|
|
|
2595
|
|
|
|
|
|
|
} |
|
2596
|
|
|
|
|
|
|
else { |
|
2597
|
3
|
|
|
|
|
20
|
$range = |
|
2598
|
|
|
|
|
|
|
xl_rowcol_to_cell( $row1, $col1 ) . ':' |
|
2599
|
|
|
|
|
|
|
. xl_rowcol_to_cell( $row2, $col2 ); |
|
2600
|
|
|
|
|
|
|
} |
|
2601
|
|
|
|
|
|
|
|
|
2602
|
|
|
|
|
|
|
# Remove array formula braces and the leading =. |
|
2603
|
7
|
|
|
|
|
65
|
$formula =~ s/^{(.*)}$/$1/; |
|
2604
|
7
|
|
|
|
|
29
|
$formula =~ s/^=//; |
|
2605
|
|
|
|
|
|
|
|
|
2606
|
|
|
|
|
|
|
# Write previous row if in in-line string optimization mode. |
|
2607
|
7
|
|
|
|
|
24
|
my $row = $row1; |
|
2608
|
7
|
50
|
33
|
|
|
32
|
if ( $self->{_optimization} == 1 && $row > $self->{_previous_row} ) { |
|
2609
|
0
|
|
|
|
|
0
|
$self->_write_single_row( $row ); |
|
2610
|
|
|
|
|
|
|
} |
|
2611
|
|
|
|
|
|
|
|
|
2612
|
7
|
|
|
|
|
30
|
$self->{_table}->{$row1}->{$col1} = |
|
2613
|
|
|
|
|
|
|
[ $type, $formula, $xf, $range, $value ]; |
|
2614
|
|
|
|
|
|
|
|
|
2615
|
|
|
|
|
|
|
|
|
2616
|
|
|
|
|
|
|
# Pad out the rest of the area with formatted zeroes. |
|
2617
|
7
|
50
|
|
|
|
25
|
if ( !$self->{_optimization} ) { |
|
2618
|
7
|
|
|
|
|
22
|
for my $row ( $row1 .. $row2 ) { |
|
2619
|
13
|
|
|
|
|
37
|
for my $col ( $col1 .. $col2 ) { |
|
2620
|
13
|
100
|
66
|
|
|
61
|
next if $row == $row1 and $col == $col1; |
|
2621
|
6
|
|
|
|
|
19
|
$self->write_number( $row, $col, 0, $xf ); |
|
2622
|
|
|
|
|
|
|
} |
|
2623
|
|
|
|
|
|
|
} |
|
2624
|
|
|
|
|
|
|
} |
|
2625
|
|
|
|
|
|
|
|
|
2626
|
7
|
|
|
|
|
26
|
return 0; |
|
2627
|
|
|
|
|
|
|
} |
|
2628
|
|
|
|
|
|
|
|
|
2629
|
|
|
|
|
|
|
|
|
2630
|
|
|
|
|
|
|
############################################################################### |
|
2631
|
|
|
|
|
|
|
# |
|
2632
|
|
|
|
|
|
|
# write_blank($row, $col, $format) |
|
2633
|
|
|
|
|
|
|
# |
|
2634
|
|
|
|
|
|
|
# Write a boolean value to the specified row and column (zero indexed). |
|
2635
|
|
|
|
|
|
|
# |
|
2636
|
|
|
|
|
|
|
# Returns 0 : normal termination (including no format) |
|
2637
|
|
|
|
|
|
|
# -2 : row or column out of range |
|
2638
|
|
|
|
|
|
|
# |
|
2639
|
|
|
|
|
|
|
sub write_boolean { |
|
2640
|
|
|
|
|
|
|
|
|
2641
|
4
|
|
|
4
|
0
|
24
|
my $self = shift; |
|
2642
|
|
|
|
|
|
|
|
|
2643
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
2644
|
4
|
50
|
|
|
|
19
|
if ( $_[0] =~ /^\D/ ) { |
|
2645
|
4
|
|
|
|
|
16
|
@_ = $self->_substitute_cellref( @_ ); |
|
2646
|
|
|
|
|
|
|
} |
|
2647
|
|
|
|
|
|
|
|
|
2648
|
4
|
|
|
|
|
8
|
my $row = $_[0]; # Zero indexed row |
|
2649
|
4
|
|
|
|
|
7
|
my $col = $_[1]; # Zero indexed column |
|
2650
|
4
|
100
|
|
|
|
11
|
my $val = $_[2] ? 1 : 0; # Boolean value. |
|
2651
|
4
|
|
|
|
|
7
|
my $xf = $_[3]; # The cell format |
|
2652
|
4
|
|
|
|
|
8
|
my $type = 'l'; # The data type |
|
2653
|
|
|
|
|
|
|
|
|
2654
|
|
|
|
|
|
|
# Check that row and col are valid and store max and min values |
|
2655
|
4
|
50
|
|
|
|
13
|
return -2 if $self->_check_dimensions( $row, $col ); |
|
2656
|
|
|
|
|
|
|
|
|
2657
|
|
|
|
|
|
|
# Write previous row if in in-line string optimization mode. |
|
2658
|
4
|
50
|
33
|
|
|
29
|
if ( $self->{_optimization} == 1 && $row > $self->{_previous_row} ) { |
|
2659
|
0
|
|
|
|
|
0
|
$self->_write_single_row( $row ); |
|
2660
|
|
|
|
|
|
|
} |
|
2661
|
|
|
|
|
|
|
|
|
2662
|
4
|
|
|
|
|
17
|
$self->{_table}->{$row}->{$col} = [ $type, $val, $xf ]; |
|
2663
|
|
|
|
|
|
|
|
|
2664
|
4
|
|
|
|
|
13
|
return 0; |
|
2665
|
|
|
|
|
|
|
} |
|
2666
|
|
|
|
|
|
|
|
|
2667
|
|
|
|
|
|
|
|
|
2668
|
|
|
|
|
|
|
############################################################################### |
|
2669
|
|
|
|
|
|
|
# |
|
2670
|
|
|
|
|
|
|
# outline_settings($visible, $symbols_below, $symbols_right, $auto_style) |
|
2671
|
|
|
|
|
|
|
# |
|
2672
|
|
|
|
|
|
|
# This method sets the properties for outlining and grouping. The defaults |
|
2673
|
|
|
|
|
|
|
# correspond to Excel's defaults. |
|
2674
|
|
|
|
|
|
|
# |
|
2675
|
|
|
|
|
|
|
sub outline_settings { |
|
2676
|
|
|
|
|
|
|
|
|
2677
|
1
|
|
|
1
|
0
|
7
|
my $self = shift; |
|
2678
|
|
|
|
|
|
|
|
|
2679
|
1
|
50
|
|
|
|
8
|
$self->{_outline_on} = defined $_[0] ? $_[0] : 1; |
|
2680
|
1
|
50
|
|
|
|
4
|
$self->{_outline_below} = defined $_[1] ? $_[1] : 1; |
|
2681
|
1
|
50
|
|
|
|
18
|
$self->{_outline_right} = defined $_[2] ? $_[2] : 1; |
|
2682
|
1
|
|
50
|
|
|
4
|
$self->{_outline_style} = $_[3] || 0; |
|
2683
|
|
|
|
|
|
|
|
|
2684
|
1
|
|
|
|
|
3
|
$self->{_outline_changed} = 1; |
|
2685
|
|
|
|
|
|
|
} |
|
2686
|
|
|
|
|
|
|
|
|
2687
|
|
|
|
|
|
|
|
|
2688
|
|
|
|
|
|
|
############################################################################### |
|
2689
|
|
|
|
|
|
|
# |
|
2690
|
|
|
|
|
|
|
# Escape urls like Excel. |
|
2691
|
|
|
|
|
|
|
# |
|
2692
|
|
|
|
|
|
|
sub _escape_url { |
|
2693
|
|
|
|
|
|
|
|
|
2694
|
98
|
|
|
98
|
|
235
|
my $url = shift; |
|
2695
|
|
|
|
|
|
|
|
|
2696
|
|
|
|
|
|
|
# Don't escape URL if it looks already escaped. |
|
2697
|
98
|
100
|
|
|
|
363
|
return $url if $url =~ /%[0-9a-fA-F]{2}/; |
|
2698
|
|
|
|
|
|
|
|
|
2699
|
|
|
|
|
|
|
# Escape the URL escape symbol. |
|
2700
|
97
|
|
|
|
|
253
|
$url =~ s/%/%25/g; |
|
2701
|
|
|
|
|
|
|
|
|
2702
|
|
|
|
|
|
|
# Escape whitespace in URL. |
|
2703
|
97
|
|
|
|
|
492
|
$url =~ s/[\s\x00]/%20/g; |
|
2704
|
|
|
|
|
|
|
|
|
2705
|
|
|
|
|
|
|
# Escape other special characters in URL. |
|
2706
|
97
|
|
|
|
|
363
|
$url =~ s/(["<>[\]`^{}])/sprintf '%%%x', ord $1/eg; |
|
|
11
|
|
|
|
|
46
|
|
|
2707
|
|
|
|
|
|
|
|
|
2708
|
97
|
|
|
|
|
596
|
return $url; |
|
2709
|
|
|
|
|
|
|
} |
|
2710
|
|
|
|
|
|
|
|
|
2711
|
|
|
|
|
|
|
|
|
2712
|
|
|
|
|
|
|
############################################################################### |
|
2713
|
|
|
|
|
|
|
# |
|
2714
|
|
|
|
|
|
|
# write_url($row, $col, $url, format, $string) |
|
2715
|
|
|
|
|
|
|
# |
|
2716
|
|
|
|
|
|
|
# Write a hyperlink. This is comprised of two elements: the visible label and |
|
2717
|
|
|
|
|
|
|
# the invisible link. The visible label is the same as the link unless an |
|
2718
|
|
|
|
|
|
|
# alternative string is specified. The label is written using the |
|
2719
|
|
|
|
|
|
|
# write_string() method. Therefore the max characters string limit applies. |
|
2720
|
|
|
|
|
|
|
# $string and $format are optional and their order is interchangeable. |
|
2721
|
|
|
|
|
|
|
# |
|
2722
|
|
|
|
|
|
|
# The hyperlink can be to a http, ftp, mail, internal sheet, or external |
|
2723
|
|
|
|
|
|
|
# directory url. |
|
2724
|
|
|
|
|
|
|
# |
|
2725
|
|
|
|
|
|
|
# Returns 0 : normal termination |
|
2726
|
|
|
|
|
|
|
# -1 : insufficient number of arguments |
|
2727
|
|
|
|
|
|
|
# -2 : row or column out of range |
|
2728
|
|
|
|
|
|
|
# -3 : long string truncated to 32767 chars |
|
2729
|
|
|
|
|
|
|
# -4 : URL longer than 255 characters |
|
2730
|
|
|
|
|
|
|
# -5 : Exceeds limit of 65_530 urls per worksheet |
|
2731
|
|
|
|
|
|
|
# |
|
2732
|
|
|
|
|
|
|
sub write_url { |
|
2733
|
|
|
|
|
|
|
|
|
2734
|
83
|
|
|
83
|
0
|
678
|
my $self = shift; |
|
2735
|
|
|
|
|
|
|
|
|
2736
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
2737
|
83
|
100
|
|
|
|
507
|
if ( $_[0] =~ /^\D/ ) { |
|
2738
|
68
|
|
|
|
|
373
|
@_ = $self->_substitute_cellref( @_ ); |
|
2739
|
|
|
|
|
|
|
} |
|
2740
|
|
|
|
|
|
|
|
|
2741
|
83
|
50
|
|
|
|
305
|
if ( @_ < 3 ) { return -1 } # Check the number of args |
|
|
0
|
|
|
|
|
0
|
|
|
2742
|
|
|
|
|
|
|
|
|
2743
|
|
|
|
|
|
|
|
|
2744
|
|
|
|
|
|
|
# Reverse the order of $string and $format if necessary, for backward |
|
2745
|
|
|
|
|
|
|
# compatibility. We work on a copy in order to protect the callers |
|
2746
|
|
|
|
|
|
|
# args. We don't use "local @_" in case of perl50005 threads. |
|
2747
|
83
|
|
|
|
|
274
|
my @args = @_; |
|
2748
|
83
|
100
|
100
|
|
|
390
|
if (defined $args[3] and !ref $args[3]) { |
|
2749
|
13
|
|
|
|
|
43
|
( $args[3], $args[4] ) = ( $args[4], $args[3] ); |
|
2750
|
|
|
|
|
|
|
} |
|
2751
|
|
|
|
|
|
|
|
|
2752
|
83
|
|
|
|
|
186
|
my $row = $args[0]; # Zero indexed row |
|
2753
|
83
|
|
|
|
|
166
|
my $col = $args[1]; # Zero indexed column |
|
2754
|
83
|
|
|
|
|
164
|
my $url = $args[2]; # URL string |
|
2755
|
83
|
|
|
|
|
153
|
my $xf = $args[3]; # Cell format |
|
2756
|
83
|
|
|
|
|
159
|
my $str = $args[4]; # Alternative label |
|
2757
|
83
|
|
|
|
|
138
|
my $tip = $args[5]; # Tool tip |
|
2758
|
83
|
|
|
|
|
179
|
my $type = 'l'; # XML data type |
|
2759
|
83
|
|
|
|
|
163
|
my $link_type = 1; |
|
2760
|
83
|
|
|
|
|
149
|
my $external = 0; |
|
2761
|
|
|
|
|
|
|
|
|
2762
|
|
|
|
|
|
|
# The displayed string defaults to the url string. |
|
2763
|
83
|
100
|
|
|
|
260
|
$str = $url unless defined $str; |
|
2764
|
|
|
|
|
|
|
|
|
2765
|
|
|
|
|
|
|
# Remove the URI scheme from internal links. |
|
2766
|
83
|
100
|
|
|
|
304
|
if ( $url =~ s/^internal:// ) { |
|
2767
|
8
|
|
|
|
|
17
|
$str =~ s/^internal://; |
|
2768
|
8
|
|
|
|
|
15
|
$link_type = 2; |
|
2769
|
|
|
|
|
|
|
} |
|
2770
|
|
|
|
|
|
|
|
|
2771
|
|
|
|
|
|
|
# Remove the URI scheme from external links and change the directory |
|
2772
|
|
|
|
|
|
|
# separator from Unix to Dos. |
|
2773
|
83
|
100
|
|
|
|
302
|
if ( $url =~ s/^external:// ) { |
|
2774
|
15
|
|
|
|
|
60
|
$str =~ s/^external://; |
|
2775
|
15
|
|
|
|
|
46
|
$url =~ s[/][\\]g; |
|
2776
|
15
|
|
|
|
|
34
|
$str =~ s[/][\\]g; |
|
2777
|
15
|
|
|
|
|
23
|
$external = 1; |
|
2778
|
|
|
|
|
|
|
} |
|
2779
|
|
|
|
|
|
|
|
|
2780
|
|
|
|
|
|
|
# Strip the mailto header. |
|
2781
|
83
|
|
|
|
|
182
|
$str =~ s/^mailto://; |
|
2782
|
|
|
|
|
|
|
|
|
2783
|
|
|
|
|
|
|
# Check that row and col are valid and store max and min values |
|
2784
|
83
|
50
|
|
|
|
313
|
return -2 if $self->_check_dimensions( $row, $col ); |
|
2785
|
|
|
|
|
|
|
|
|
2786
|
|
|
|
|
|
|
# Check that the string is < 32767 chars |
|
2787
|
83
|
|
|
|
|
179
|
my $str_error = 0; |
|
2788
|
83
|
50
|
|
|
|
295
|
if ( length $str > $self->{_xls_strmax} ) { |
|
2789
|
0
|
|
|
|
|
0
|
$str = substr( $str, 0, $self->{_xls_strmax} ); |
|
2790
|
0
|
|
|
|
|
0
|
$str_error = -3; |
|
2791
|
|
|
|
|
|
|
} |
|
2792
|
|
|
|
|
|
|
|
|
2793
|
|
|
|
|
|
|
# Copy string for use in hyperlink elements. |
|
2794
|
83
|
|
|
|
|
192
|
my $url_str = $str; |
|
2795
|
|
|
|
|
|
|
|
|
2796
|
|
|
|
|
|
|
# External links to URLs and to other Excel workbooks have slightly |
|
2797
|
|
|
|
|
|
|
# different characteristics that we have to account for. |
|
2798
|
83
|
100
|
|
|
|
261
|
if ( $link_type == 1 ) { |
|
2799
|
|
|
|
|
|
|
|
|
2800
|
|
|
|
|
|
|
# Split url into the link and optional anchor/location. |
|
2801
|
75
|
|
|
|
|
323
|
( $url, $url_str ) = split /#/, $url, 2; |
|
2802
|
|
|
|
|
|
|
|
|
2803
|
75
|
|
|
|
|
276
|
$url = _escape_url( $url ); |
|
2804
|
|
|
|
|
|
|
|
|
2805
|
|
|
|
|
|
|
# Escape the anchor for hyperlink style urls only. |
|
2806
|
75
|
100
|
100
|
|
|
571
|
if ( $url_str && !$external ) { |
|
2807
|
4
|
|
|
|
|
18
|
$url_str = _escape_url( $url_str ); |
|
2808
|
|
|
|
|
|
|
} |
|
2809
|
|
|
|
|
|
|
|
|
2810
|
|
|
|
|
|
|
# Add the file:/// URI to the url for Windows style "C:/" link and |
|
2811
|
|
|
|
|
|
|
# Network shares. |
|
2812
|
75
|
100
|
100
|
|
|
486
|
if ( $url =~ m{^\w:} || $url =~ m{^\\\\} ) { |
|
2813
|
9
|
|
|
|
|
30
|
$url = 'file:///' . $url; |
|
2814
|
|
|
|
|
|
|
} |
|
2815
|
|
|
|
|
|
|
|
|
2816
|
|
|
|
|
|
|
# Convert a ./dir/file.xlsx link to dir/file.xlsx. |
|
2817
|
75
|
|
|
|
|
178
|
$url =~ s{^.\\}{}; |
|
2818
|
|
|
|
|
|
|
} |
|
2819
|
|
|
|
|
|
|
|
|
2820
|
|
|
|
|
|
|
# Excel limits the escaped URL and location/anchor to 255 characters. |
|
2821
|
83
|
|
100
|
|
|
380
|
my $tmp_url_str = $url_str || ''; |
|
2822
|
83
|
|
|
|
|
376
|
my $max_url = $self->{_max_url_length}; |
|
2823
|
|
|
|
|
|
|
|
|
2824
|
83
|
100
|
66
|
|
|
932
|
if ( length $url > $max_url || length $tmp_url_str > $max_url ) { |
|
2825
|
1
|
|
|
|
|
281
|
carp "Ignoring URL '$url' where link or anchor > $max_url characters " |
|
2826
|
|
|
|
|
|
|
. "since it exceeds Excel's limit for URLS. See LIMITATIONS " |
|
2827
|
|
|
|
|
|
|
. "section of the Excel::Writer::XLSX documentation."; |
|
2828
|
1
|
|
|
|
|
9
|
return -4; |
|
2829
|
|
|
|
|
|
|
} |
|
2830
|
|
|
|
|
|
|
|
|
2831
|
|
|
|
|
|
|
# Check the limit of URLS per worksheet. |
|
2832
|
82
|
|
|
|
|
723
|
$self->{_hlink_count}++; |
|
2833
|
|
|
|
|
|
|
|
|
2834
|
82
|
50
|
|
|
|
594
|
if ( $self->{_hlink_count} > 65_530 ) { |
|
2835
|
0
|
|
|
|
|
0
|
carp "Ignoring URL '$url' since it exceeds Excel's limit of 65,530 " |
|
2836
|
|
|
|
|
|
|
. "URLs per worksheet. See LIMITATIONS section of the " |
|
2837
|
|
|
|
|
|
|
. "Excel::Writer::XLSX documentation."; |
|
2838
|
0
|
|
|
|
|
0
|
return -5; |
|
2839
|
|
|
|
|
|
|
} |
|
2840
|
|
|
|
|
|
|
|
|
2841
|
|
|
|
|
|
|
# Write previous row if in in-line string optimization mode. |
|
2842
|
82
|
50
|
66
|
|
|
499
|
if ( $self->{_optimization} == 1 && $row > $self->{_previous_row} ) { |
|
2843
|
0
|
|
|
|
|
0
|
$self->_write_single_row( $row ); |
|
2844
|
|
|
|
|
|
|
} |
|
2845
|
|
|
|
|
|
|
|
|
2846
|
|
|
|
|
|
|
# Add the default URL format. |
|
2847
|
82
|
100
|
|
|
|
609
|
if ( !defined $xf ) { |
|
2848
|
65
|
|
|
|
|
1082
|
$xf = $self->{_default_url_format}; |
|
2849
|
|
|
|
|
|
|
} |
|
2850
|
|
|
|
|
|
|
|
|
2851
|
|
|
|
|
|
|
# Write the hyperlink string. |
|
2852
|
82
|
|
|
|
|
866
|
$self->write_string( $row, $col, $str, $xf ); |
|
2853
|
|
|
|
|
|
|
|
|
2854
|
|
|
|
|
|
|
# Store the hyperlink data in a separate structure. |
|
2855
|
82
|
|
|
|
|
448
|
$self->{_hyperlinks}->{$row}->{$col} = { |
|
2856
|
|
|
|
|
|
|
_link_type => $link_type, |
|
2857
|
|
|
|
|
|
|
_url => $url, |
|
2858
|
|
|
|
|
|
|
_str => $url_str, |
|
2859
|
|
|
|
|
|
|
_tip => $tip |
|
2860
|
|
|
|
|
|
|
}; |
|
2861
|
|
|
|
|
|
|
|
|
2862
|
82
|
|
|
|
|
301
|
return $str_error; |
|
2863
|
|
|
|
|
|
|
} |
|
2864
|
|
|
|
|
|
|
|
|
2865
|
|
|
|
|
|
|
|
|
2866
|
|
|
|
|
|
|
############################################################################### |
|
2867
|
|
|
|
|
|
|
# |
|
2868
|
|
|
|
|
|
|
# write_date_time ($row, $col, $string, $format) |
|
2869
|
|
|
|
|
|
|
# |
|
2870
|
|
|
|
|
|
|
# Write a datetime string in ISO8601 "yyyy-mm-ddThh:mm:ss.ss" format as a |
|
2871
|
|
|
|
|
|
|
# number representing an Excel date. $format is optional. |
|
2872
|
|
|
|
|
|
|
# |
|
2873
|
|
|
|
|
|
|
# Returns 0 : normal termination |
|
2874
|
|
|
|
|
|
|
# -1 : insufficient number of arguments |
|
2875
|
|
|
|
|
|
|
# -2 : row or column out of range |
|
2876
|
|
|
|
|
|
|
# -3 : Invalid date_time, written as string |
|
2877
|
|
|
|
|
|
|
# |
|
2878
|
|
|
|
|
|
|
sub write_date_time { |
|
2879
|
|
|
|
|
|
|
|
|
2880
|
129
|
|
|
129
|
0
|
814
|
my $self = shift; |
|
2881
|
|
|
|
|
|
|
|
|
2882
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
2883
|
129
|
100
|
|
|
|
460
|
if ( $_[0] =~ /^\D/ ) { |
|
2884
|
12
|
|
|
|
|
35
|
@_ = $self->_substitute_cellref( @_ ); |
|
2885
|
|
|
|
|
|
|
} |
|
2886
|
|
|
|
|
|
|
|
|
2887
|
129
|
50
|
|
|
|
316
|
if ( @_ < 3 ) { return -1 } # Check the number of args |
|
|
0
|
|
|
|
|
0
|
|
|
2888
|
|
|
|
|
|
|
|
|
2889
|
129
|
|
|
|
|
227
|
my $row = $_[0]; # Zero indexed row |
|
2890
|
129
|
|
|
|
|
205
|
my $col = $_[1]; # Zero indexed column |
|
2891
|
129
|
|
|
|
|
202
|
my $str = $_[2]; |
|
2892
|
129
|
|
|
|
|
212
|
my $xf = $_[3]; # The cell format |
|
2893
|
129
|
|
|
|
|
213
|
my $type = 'n'; # The data type |
|
2894
|
|
|
|
|
|
|
|
|
2895
|
|
|
|
|
|
|
|
|
2896
|
|
|
|
|
|
|
# Check that row and col are valid and store max and min values |
|
2897
|
129
|
50
|
|
|
|
287
|
return -2 if $self->_check_dimensions( $row, $col ); |
|
2898
|
|
|
|
|
|
|
|
|
2899
|
129
|
|
|
|
|
228
|
my $str_error = 0; |
|
2900
|
129
|
|
|
|
|
316
|
my $date_time = $self->convert_date_time( $str ); |
|
2901
|
|
|
|
|
|
|
|
|
2902
|
|
|
|
|
|
|
# If the date isn't valid then write it as a string. |
|
2903
|
129
|
50
|
|
|
|
400
|
if ( !defined $date_time ) { |
|
2904
|
0
|
|
|
|
|
0
|
return $self->write_string( @_ ); |
|
2905
|
|
|
|
|
|
|
} |
|
2906
|
|
|
|
|
|
|
|
|
2907
|
|
|
|
|
|
|
# Write previous row if in in-line string optimization mode. |
|
2908
|
129
|
50
|
33
|
|
|
346
|
if ( $self->{_optimization} == 1 && $row > $self->{_previous_row} ) { |
|
2909
|
0
|
|
|
|
|
0
|
$self->_write_single_row( $row ); |
|
2910
|
|
|
|
|
|
|
} |
|
2911
|
|
|
|
|
|
|
|
|
2912
|
129
|
|
|
|
|
540
|
$self->{_table}->{$row}->{$col} = [ $type, $date_time, $xf ]; |
|
2913
|
|
|
|
|
|
|
|
|
2914
|
129
|
|
|
|
|
357
|
return $str_error; |
|
2915
|
|
|
|
|
|
|
} |
|
2916
|
|
|
|
|
|
|
|
|
2917
|
|
|
|
|
|
|
|
|
2918
|
|
|
|
|
|
|
############################################################################### |
|
2919
|
|
|
|
|
|
|
# |
|
2920
|
|
|
|
|
|
|
# convert_date_time($date_time_string) |
|
2921
|
|
|
|
|
|
|
# |
|
2922
|
|
|
|
|
|
|
# The function takes a date and time in ISO8601 "yyyy-mm-ddThh:mm:ss.ss" format |
|
2923
|
|
|
|
|
|
|
# and converts it to a decimal number representing a valid Excel date. |
|
2924
|
|
|
|
|
|
|
# |
|
2925
|
|
|
|
|
|
|
# Dates and times in Excel are represented by real numbers. The integer part of |
|
2926
|
|
|
|
|
|
|
# the number stores the number of days since the epoch and the fractional part |
|
2927
|
|
|
|
|
|
|
# stores the percentage of the day in seconds. The epoch can be either 1900 or |
|
2928
|
|
|
|
|
|
|
# 1904. |
|
2929
|
|
|
|
|
|
|
# |
|
2930
|
|
|
|
|
|
|
# Parameter: Date and time string in one of the following formats: |
|
2931
|
|
|
|
|
|
|
# yyyy-mm-ddThh:mm:ss.ss # Standard |
|
2932
|
|
|
|
|
|
|
# yyyy-mm-ddT # Date only |
|
2933
|
|
|
|
|
|
|
# Thh:mm:ss.ss # Time only |
|
2934
|
|
|
|
|
|
|
# |
|
2935
|
|
|
|
|
|
|
# Returns: |
|
2936
|
|
|
|
|
|
|
# A decimal number representing a valid Excel date, or |
|
2937
|
|
|
|
|
|
|
# undef if the date is invalid. |
|
2938
|
|
|
|
|
|
|
# |
|
2939
|
|
|
|
|
|
|
sub convert_date_time { |
|
2940
|
|
|
|
|
|
|
|
|
2941
|
768
|
|
|
768
|
0
|
302707
|
my $self = shift; |
|
2942
|
768
|
|
|
|
|
1376
|
my $date_time = $_[0]; |
|
2943
|
|
|
|
|
|
|
|
|
2944
|
768
|
|
|
|
|
1161
|
my $days = 0; # Number of days since epoch |
|
2945
|
768
|
|
|
|
|
1147
|
my $seconds = 0; # Time expressed as fraction of 24h hours in seconds |
|
2946
|
|
|
|
|
|
|
|
|
2947
|
768
|
|
|
|
|
1878
|
my ( $year, $month, $day ); |
|
2948
|
768
|
|
|
|
|
0
|
my ( $hour, $min, $sec ); |
|
2949
|
|
|
|
|
|
|
|
|
2950
|
|
|
|
|
|
|
|
|
2951
|
|
|
|
|
|
|
# Strip leading and trailing whitespace. |
|
2952
|
768
|
|
|
|
|
1952
|
$date_time =~ s/^\s+//; |
|
2953
|
768
|
|
|
|
|
1620
|
$date_time =~ s/\s+$//; |
|
2954
|
|
|
|
|
|
|
|
|
2955
|
|
|
|
|
|
|
# Check for invalid date char. |
|
2956
|
768
|
100
|
|
|
|
2209
|
return if $date_time =~ /[^0-9T:\-\.Z]/; |
|
2957
|
|
|
|
|
|
|
|
|
2958
|
|
|
|
|
|
|
# Check for "T" after date or before time. |
|
2959
|
767
|
100
|
|
|
|
3149
|
return unless $date_time =~ /\dT|T\d/; |
|
2960
|
|
|
|
|
|
|
|
|
2961
|
|
|
|
|
|
|
# Strip trailing Z in ISO8601 date. |
|
2962
|
765
|
|
|
|
|
1279
|
$date_time =~ s/Z$//; |
|
2963
|
|
|
|
|
|
|
|
|
2964
|
|
|
|
|
|
|
|
|
2965
|
|
|
|
|
|
|
# Split into date and time. |
|
2966
|
765
|
|
|
|
|
2392
|
my ( $date, $time ) = split /T/, $date_time; |
|
2967
|
|
|
|
|
|
|
|
|
2968
|
|
|
|
|
|
|
|
|
2969
|
|
|
|
|
|
|
# We allow the time portion of the input DateTime to be optional. |
|
2970
|
765
|
100
|
|
|
|
1973
|
if ( $time ne '' ) { |
|
2971
|
|
|
|
|
|
|
|
|
2972
|
|
|
|
|
|
|
# Match hh:mm:ss.sss+ where the seconds are optional |
|
2973
|
206
|
50
|
|
|
|
904
|
if ( $time =~ /^(\d\d):(\d\d)(:(\d\d(\.\d+)?))?/ ) { |
|
2974
|
206
|
|
|
|
|
427
|
$hour = $1; |
|
2975
|
206
|
|
|
|
|
377
|
$min = $2; |
|
2976
|
206
|
|
100
|
|
|
553
|
$sec = $4 || 0; |
|
2977
|
|
|
|
|
|
|
} |
|
2978
|
|
|
|
|
|
|
else { |
|
2979
|
0
|
|
|
|
|
0
|
return undef; # Not a valid time format. |
|
2980
|
|
|
|
|
|
|
} |
|
2981
|
|
|
|
|
|
|
|
|
2982
|
|
|
|
|
|
|
# Some boundary checks |
|
2983
|
206
|
100
|
|
|
|
515
|
return if $hour >= 24; |
|
2984
|
205
|
100
|
|
|
|
401
|
return if $min >= 60; |
|
2985
|
204
|
100
|
|
|
|
527
|
return if $sec >= 60; |
|
2986
|
|
|
|
|
|
|
|
|
2987
|
|
|
|
|
|
|
# Excel expresses seconds as a fraction of the number in 24 hours. |
|
2988
|
202
|
|
|
|
|
482
|
$seconds = ( $hour * 60 * 60 + $min * 60 + $sec ) / ( 24 * 60 * 60 ); |
|
2989
|
|
|
|
|
|
|
} |
|
2990
|
|
|
|
|
|
|
|
|
2991
|
|
|
|
|
|
|
|
|
2992
|
|
|
|
|
|
|
# We allow the date portion of the input DateTime to be optional. |
|
2993
|
761
|
100
|
|
|
|
1664
|
return $seconds if $date eq ''; |
|
2994
|
|
|
|
|
|
|
|
|
2995
|
|
|
|
|
|
|
|
|
2996
|
|
|
|
|
|
|
# Match date as yyyy-mm-dd. |
|
2997
|
759
|
100
|
|
|
|
2796
|
if ( $date =~ /^(\d\d\d\d)-(\d\d)-(\d\d)$/ ) { |
|
2998
|
757
|
|
|
|
|
1731
|
$year = $1; |
|
2999
|
757
|
|
|
|
|
1384
|
$month = $2; |
|
3000
|
757
|
|
|
|
|
1291
|
$day = $3; |
|
3001
|
|
|
|
|
|
|
} |
|
3002
|
|
|
|
|
|
|
else { |
|
3003
|
2
|
|
|
|
|
9
|
return undef; # Not a valid date format. |
|
3004
|
|
|
|
|
|
|
} |
|
3005
|
|
|
|
|
|
|
|
|
3006
|
|
|
|
|
|
|
# Set the epoch as 1900 or 1904. Defaults to 1900. |
|
3007
|
757
|
|
|
|
|
1345
|
my $date_1904 = $self->{_date_1904}; |
|
3008
|
|
|
|
|
|
|
|
|
3009
|
|
|
|
|
|
|
|
|
3010
|
|
|
|
|
|
|
# Special cases for Excel. |
|
3011
|
757
|
100
|
|
|
|
1643
|
if ( not $date_1904 ) { |
|
3012
|
542
|
100
|
|
|
|
1314
|
return $seconds if $date eq '1899-12-31'; # Excel 1900 epoch |
|
3013
|
438
|
100
|
|
|
|
820
|
return $seconds if $date eq '1900-01-00'; # Excel 1900 epoch |
|
3014
|
437
|
100
|
|
|
|
892
|
return 60 + $seconds if $date eq '1900-02-29'; # Excel false leapday |
|
3015
|
|
|
|
|
|
|
} |
|
3016
|
|
|
|
|
|
|
|
|
3017
|
|
|
|
|
|
|
|
|
3018
|
|
|
|
|
|
|
# We calculate the date by calculating the number of days since the epoch |
|
3019
|
|
|
|
|
|
|
# and adjust for the number of leap days. We calculate the number of leap |
|
3020
|
|
|
|
|
|
|
# days by normalising the year in relation to the epoch. Thus the year 2000 |
|
3021
|
|
|
|
|
|
|
# becomes 100 for 4 and 100 year leapdays and 400 for 400 year leapdays. |
|
3022
|
|
|
|
|
|
|
# |
|
3023
|
651
|
100
|
|
|
|
1308
|
my $epoch = $date_1904 ? 1904 : 1900; |
|
3024
|
651
|
100
|
|
|
|
1208
|
my $offset = $date_1904 ? 4 : 0; |
|
3025
|
651
|
|
|
|
|
919
|
my $norm = 300; |
|
3026
|
651
|
|
|
|
|
1572
|
my $range = $year - $epoch; |
|
3027
|
|
|
|
|
|
|
|
|
3028
|
|
|
|
|
|
|
|
|
3029
|
|
|
|
|
|
|
# Set month days and check for leap year. |
|
3030
|
651
|
|
|
|
|
1564
|
my @mdays = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ); |
|
3031
|
651
|
|
|
|
|
937
|
my $leap = 0; |
|
3032
|
651
|
100
|
100
|
|
|
3298
|
$leap = 1 if $year % 4 == 0 and $year % 100 or $year % 400 == 0; |
|
|
|
|
100
|
|
|
|
|
|
3033
|
651
|
100
|
|
|
|
1410
|
$mdays[1] = 29 if $leap; |
|
3034
|
|
|
|
|
|
|
|
|
3035
|
|
|
|
|
|
|
|
|
3036
|
|
|
|
|
|
|
# Some boundary checks |
|
3037
|
651
|
100
|
66
|
|
|
2181
|
return if $year < $epoch or $year > 9999; |
|
3038
|
645
|
100
|
100
|
|
|
2074
|
return if $month < 1 or $month > 12; |
|
3039
|
639
|
100
|
100
|
|
|
2138
|
return if $day < 1 or $day > $mdays[ $month - 1 ]; |
|
3040
|
|
|
|
|
|
|
|
|
3041
|
|
|
|
|
|
|
# Accumulate the number of days since the epoch. |
|
3042
|
633
|
|
|
|
|
1137
|
$days = $day; # Add days for current month |
|
3043
|
633
|
|
|
|
|
2286
|
$days += $mdays[$_] for 0 .. $month - 2; # Add days for past months |
|
3044
|
633
|
|
|
|
|
1168
|
$days += $range * 365; # Add days for past years |
|
3045
|
633
|
|
|
|
|
1226
|
$days += int( ( $range ) / 4 ); # Add leapdays |
|
3046
|
633
|
|
|
|
|
1109
|
$days -= int( ( $range + $offset ) / 100 ); # Subtract 100 year leapdays |
|
3047
|
633
|
|
|
|
|
1058
|
$days += int( ( $range + $offset + $norm ) / 400 ); # Add 400 year leapdays |
|
3048
|
633
|
|
|
|
|
916
|
$days -= $leap; # Already counted above |
|
3049
|
|
|
|
|
|
|
|
|
3050
|
|
|
|
|
|
|
|
|
3051
|
|
|
|
|
|
|
# Adjust for Excel erroneously treating 1900 as a leap year. |
|
3052
|
633
|
100
|
100
|
|
|
1987
|
$days++ if $date_1904 == 0 and $days > 59; |
|
3053
|
|
|
|
|
|
|
|
|
3054
|
633
|
|
|
|
|
1963
|
return $days + $seconds; |
|
3055
|
|
|
|
|
|
|
} |
|
3056
|
|
|
|
|
|
|
|
|
3057
|
|
|
|
|
|
|
|
|
3058
|
|
|
|
|
|
|
############################################################################### |
|
3059
|
|
|
|
|
|
|
# |
|
3060
|
|
|
|
|
|
|
# set_row($row, $height, $XF, $hidden, $level, $collapsed) |
|
3061
|
|
|
|
|
|
|
# |
|
3062
|
|
|
|
|
|
|
# This method is used to set the height and XF format for a row. |
|
3063
|
|
|
|
|
|
|
# |
|
3064
|
|
|
|
|
|
|
sub set_row { |
|
3065
|
|
|
|
|
|
|
|
|
3066
|
382
|
|
|
382
|
0
|
2366
|
my $self = shift; |
|
3067
|
382
|
|
|
|
|
659
|
my $row = shift; # Row Number. |
|
3068
|
382
|
|
|
|
|
561
|
my $height = shift; # Row height. |
|
3069
|
382
|
|
|
|
|
585
|
my $xf = shift; # Format object. |
|
3070
|
382
|
|
100
|
|
|
980
|
my $hidden = shift || 0; # Hidden flag. |
|
3071
|
382
|
|
100
|
|
|
1063
|
my $level = shift || 0; # Outline level. |
|
3072
|
382
|
|
100
|
|
|
1042
|
my $collapsed = shift || 0; # Collapsed row. |
|
3073
|
382
|
|
|
|
|
573
|
my $min_col = 0; |
|
3074
|
|
|
|
|
|
|
|
|
3075
|
382
|
50
|
|
|
|
782
|
return unless defined $row; # Ensure at least $row is specified. |
|
3076
|
|
|
|
|
|
|
|
|
3077
|
|
|
|
|
|
|
# Get the default row height. |
|
3078
|
382
|
|
|
|
|
761
|
my $default_height = $self->{_default_row_height}; |
|
3079
|
|
|
|
|
|
|
|
|
3080
|
|
|
|
|
|
|
# Use min col in _check_dimensions(). Default to 0 if undefined. |
|
3081
|
382
|
100
|
|
|
|
848
|
if ( defined $self->{_dim_colmin} ) { |
|
3082
|
349
|
|
|
|
|
542
|
$min_col = $self->{_dim_colmin}; |
|
3083
|
|
|
|
|
|
|
} |
|
3084
|
|
|
|
|
|
|
|
|
3085
|
|
|
|
|
|
|
# Check that row is valid. |
|
3086
|
382
|
50
|
|
|
|
927
|
return -2 if $self->_check_dimensions( $row, $min_col ); |
|
3087
|
|
|
|
|
|
|
|
|
3088
|
382
|
100
|
|
|
|
1231
|
$height = $default_height if !defined $height; |
|
3089
|
|
|
|
|
|
|
|
|
3090
|
|
|
|
|
|
|
# If the height is 0 the row is hidden and the height is the default. |
|
3091
|
382
|
100
|
|
|
|
833
|
if ( $height == 0 ) { |
|
3092
|
1
|
|
|
|
|
2
|
$hidden = 1; |
|
3093
|
1
|
|
|
|
|
3
|
$height = $default_height; |
|
3094
|
|
|
|
|
|
|
} |
|
3095
|
|
|
|
|
|
|
|
|
3096
|
|
|
|
|
|
|
# Set the limits for the outline levels (0 <= x <= 7). |
|
3097
|
382
|
50
|
|
|
|
803
|
$level = 0 if $level < 0; |
|
3098
|
382
|
50
|
|
|
|
798
|
$level = 7 if $level > 7; |
|
3099
|
|
|
|
|
|
|
|
|
3100
|
382
|
100
|
|
|
|
901
|
if ( $level > $self->{_outline_row_level} ) { |
|
3101
|
11
|
|
|
|
|
24
|
$self->{_outline_row_level} = $level; |
|
3102
|
|
|
|
|
|
|
} |
|
3103
|
|
|
|
|
|
|
|
|
3104
|
|
|
|
|
|
|
# Store the row properties. |
|
3105
|
382
|
|
|
|
|
1324
|
$self->{_set_rows}->{$row} = [ $height, $xf, $hidden, $level, $collapsed ]; |
|
3106
|
|
|
|
|
|
|
|
|
3107
|
|
|
|
|
|
|
# Store the row change to allow optimisations. |
|
3108
|
382
|
|
|
|
|
724
|
$self->{_row_size_changed} = 1; |
|
3109
|
|
|
|
|
|
|
|
|
3110
|
|
|
|
|
|
|
# Store the row sizes for use when calculating image vertices. |
|
3111
|
382
|
|
|
|
|
1216
|
$self->{_row_sizes}->{$row} = [$height, $hidden]; |
|
3112
|
|
|
|
|
|
|
} |
|
3113
|
|
|
|
|
|
|
|
|
3114
|
|
|
|
|
|
|
|
|
3115
|
|
|
|
|
|
|
############################################################################### |
|
3116
|
|
|
|
|
|
|
# |
|
3117
|
|
|
|
|
|
|
# set_default_row() |
|
3118
|
|
|
|
|
|
|
# |
|
3119
|
|
|
|
|
|
|
# Set the default row properties |
|
3120
|
|
|
|
|
|
|
# |
|
3121
|
|
|
|
|
|
|
sub set_default_row { |
|
3122
|
|
|
|
|
|
|
|
|
3123
|
6
|
|
|
6
|
0
|
43
|
my $self = shift; |
|
3124
|
6
|
|
66
|
|
|
38
|
my $height = shift || $self->{_original_row_height}; |
|
3125
|
6
|
|
100
|
|
|
30
|
my $zero_height = shift || 0; |
|
3126
|
|
|
|
|
|
|
|
|
3127
|
6
|
100
|
|
|
|
52
|
if ( $height != $self->{_original_row_height} ) { |
|
3128
|
5
|
|
|
|
|
16
|
$self->{_default_row_height} = $height; |
|
3129
|
|
|
|
|
|
|
|
|
3130
|
|
|
|
|
|
|
# Store the row change to allow optimisations. |
|
3131
|
5
|
|
|
|
|
13
|
$self->{_row_size_changed} = 1; |
|
3132
|
|
|
|
|
|
|
} |
|
3133
|
|
|
|
|
|
|
|
|
3134
|
6
|
100
|
|
|
|
25
|
if ( $zero_height ) { |
|
3135
|
3
|
|
|
|
|
8
|
$self->{_default_row_zeroed} = 1; |
|
3136
|
|
|
|
|
|
|
} |
|
3137
|
|
|
|
|
|
|
} |
|
3138
|
|
|
|
|
|
|
|
|
3139
|
|
|
|
|
|
|
|
|
3140
|
|
|
|
|
|
|
############################################################################### |
|
3141
|
|
|
|
|
|
|
# |
|
3142
|
|
|
|
|
|
|
# merge_range($first_row, $first_col, $last_row, $last_col, $string, $format) |
|
3143
|
|
|
|
|
|
|
# |
|
3144
|
|
|
|
|
|
|
# Merge a range of cells. The first cell should contain the data and the others |
|
3145
|
|
|
|
|
|
|
# should be blank. All cells should contain the same format. |
|
3146
|
|
|
|
|
|
|
# |
|
3147
|
|
|
|
|
|
|
sub merge_range { |
|
3148
|
|
|
|
|
|
|
|
|
3149
|
20
|
|
|
20
|
0
|
187
|
my $self = shift; |
|
3150
|
|
|
|
|
|
|
|
|
3151
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
3152
|
20
|
100
|
|
|
|
97
|
if ( $_[0] =~ /^\D/ ) { |
|
3153
|
12
|
|
|
|
|
48
|
@_ = $self->_substitute_cellref( @_ ); |
|
3154
|
|
|
|
|
|
|
} |
|
3155
|
20
|
50
|
|
|
|
96
|
croak "Incorrect number of arguments" if @_ < 6; |
|
3156
|
20
|
50
|
|
|
|
72
|
croak "Fifth parameter must be a format object" unless ref $_[5]; |
|
3157
|
|
|
|
|
|
|
|
|
3158
|
20
|
|
|
|
|
41
|
my $row_first = shift; |
|
3159
|
20
|
|
|
|
|
39
|
my $col_first = shift; |
|
3160
|
20
|
|
|
|
|
45
|
my $row_last = shift; |
|
3161
|
20
|
|
|
|
|
128
|
my $col_last = shift; |
|
3162
|
20
|
|
|
|
|
99
|
my $string = shift; |
|
3163
|
20
|
|
|
|
|
108
|
my $format = shift; |
|
3164
|
20
|
|
|
|
|
54
|
my @extra_args = @_; # For write_url(). |
|
3165
|
|
|
|
|
|
|
|
|
3166
|
|
|
|
|
|
|
# Excel doesn't allow a single cell to be merged |
|
3167
|
20
|
50
|
66
|
|
|
113
|
if ( $row_first == $row_last and $col_first == $col_last ) { |
|
3168
|
0
|
|
|
|
|
0
|
croak "Can't merge single cell"; |
|
3169
|
|
|
|
|
|
|
} |
|
3170
|
|
|
|
|
|
|
|
|
3171
|
|
|
|
|
|
|
# Swap last row/col with first row/col as necessary |
|
3172
|
20
|
50
|
|
|
|
60
|
( $row_first, $row_last ) = ( $row_last, $row_first ) |
|
3173
|
|
|
|
|
|
|
if $row_first > $row_last; |
|
3174
|
20
|
50
|
|
|
|
54
|
( $col_first, $col_last ) = ( $col_last, $col_first ) |
|
3175
|
|
|
|
|
|
|
if $col_first > $col_last; |
|
3176
|
|
|
|
|
|
|
|
|
3177
|
|
|
|
|
|
|
# Check that column number is valid and store the max value |
|
3178
|
20
|
50
|
|
|
|
75
|
return if $self->_check_dimensions( $row_last, $col_last ); |
|
3179
|
|
|
|
|
|
|
|
|
3180
|
|
|
|
|
|
|
# Store the merge range. |
|
3181
|
20
|
|
|
|
|
53
|
push @{ $self->{_merge} }, [ $row_first, $col_first, $row_last, $col_last ]; |
|
|
20
|
|
|
|
|
243
|
|
|
3182
|
|
|
|
|
|
|
|
|
3183
|
|
|
|
|
|
|
# Write the first cell |
|
3184
|
20
|
|
|
|
|
247
|
$self->write( $row_first, $col_first, $string, $format, @extra_args ); |
|
3185
|
|
|
|
|
|
|
|
|
3186
|
|
|
|
|
|
|
# Pad out the rest of the area with formatted blank cells. |
|
3187
|
20
|
|
|
|
|
76
|
for my $row ( $row_first .. $row_last ) { |
|
3188
|
30
|
|
|
|
|
62
|
for my $col ( $col_first .. $col_last ) { |
|
3189
|
68
|
100
|
100
|
|
|
222
|
next if $row == $row_first and $col == $col_first; |
|
3190
|
48
|
|
|
|
|
231
|
$self->write_blank( $row, $col, $format ); |
|
3191
|
|
|
|
|
|
|
} |
|
3192
|
|
|
|
|
|
|
} |
|
3193
|
|
|
|
|
|
|
} |
|
3194
|
|
|
|
|
|
|
|
|
3195
|
|
|
|
|
|
|
|
|
3196
|
|
|
|
|
|
|
############################################################################### |
|
3197
|
|
|
|
|
|
|
# |
|
3198
|
|
|
|
|
|
|
# merge_range_type() |
|
3199
|
|
|
|
|
|
|
# |
|
3200
|
|
|
|
|
|
|
# Same as merge_range() above except the type of write() is specified. |
|
3201
|
|
|
|
|
|
|
# |
|
3202
|
|
|
|
|
|
|
sub merge_range_type { |
|
3203
|
|
|
|
|
|
|
|
|
3204
|
7
|
|
|
7
|
0
|
37
|
my $self = shift; |
|
3205
|
7
|
|
|
|
|
12
|
my $type = shift; |
|
3206
|
|
|
|
|
|
|
|
|
3207
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
3208
|
7
|
50
|
|
|
|
25
|
if ( $_[0] =~ /^\D/ ) { |
|
3209
|
7
|
|
|
|
|
21
|
@_ = $self->_substitute_cellref( @_ ); |
|
3210
|
|
|
|
|
|
|
} |
|
3211
|
|
|
|
|
|
|
|
|
3212
|
7
|
|
|
|
|
15
|
my $row_first = shift; |
|
3213
|
7
|
|
|
|
|
12
|
my $col_first = shift; |
|
3214
|
7
|
|
|
|
|
12
|
my $row_last = shift; |
|
3215
|
7
|
|
|
|
|
13
|
my $col_last = shift; |
|
3216
|
7
|
|
|
|
|
10
|
my $format; |
|
3217
|
|
|
|
|
|
|
|
|
3218
|
|
|
|
|
|
|
# Get the format. It can be in different positions for the different types. |
|
3219
|
7
|
100
|
66
|
|
|
37
|
if ( $type eq 'array_formula' |
|
|
|
|
100
|
|
|
|
|
|
3220
|
|
|
|
|
|
|
|| $type eq 'blank' |
|
3221
|
|
|
|
|
|
|
|| $type eq 'rich_string' ) |
|
3222
|
|
|
|
|
|
|
{ |
|
3223
|
|
|
|
|
|
|
|
|
3224
|
|
|
|
|
|
|
# The format is the last element. |
|
3225
|
2
|
|
|
|
|
17
|
$format = $_[-1]; |
|
3226
|
|
|
|
|
|
|
} |
|
3227
|
|
|
|
|
|
|
else { |
|
3228
|
|
|
|
|
|
|
|
|
3229
|
|
|
|
|
|
|
# Or else it is after the token. |
|
3230
|
5
|
|
|
|
|
11
|
$format = $_[1]; |
|
3231
|
|
|
|
|
|
|
} |
|
3232
|
|
|
|
|
|
|
|
|
3233
|
|
|
|
|
|
|
# Check that there is a format object. |
|
3234
|
7
|
50
|
|
|
|
19
|
croak "Format object missing or in an incorrect position" |
|
3235
|
|
|
|
|
|
|
unless ref $format; |
|
3236
|
|
|
|
|
|
|
|
|
3237
|
|
|
|
|
|
|
# Excel doesn't allow a single cell to be merged |
|
3238
|
7
|
50
|
33
|
|
|
25
|
if ( $row_first == $row_last and $col_first == $col_last ) { |
|
3239
|
0
|
|
|
|
|
0
|
croak "Can't merge single cell"; |
|
3240
|
|
|
|
|
|
|
} |
|
3241
|
|
|
|
|
|
|
|
|
3242
|
|
|
|
|
|
|
# Swap last row/col with first row/col as necessary |
|
3243
|
7
|
50
|
|
|
|
16
|
( $row_first, $row_last ) = ( $row_last, $row_first ) |
|
3244
|
|
|
|
|
|
|
if $row_first > $row_last; |
|
3245
|
7
|
50
|
|
|
|
23
|
( $col_first, $col_last ) = ( $col_last, $col_first ) |
|
3246
|
|
|
|
|
|
|
if $col_first > $col_last; |
|
3247
|
|
|
|
|
|
|
|
|
3248
|
|
|
|
|
|
|
# Check that column number is valid and store the max value |
|
3249
|
7
|
50
|
|
|
|
18
|
return if $self->_check_dimensions( $row_last, $col_last ); |
|
3250
|
|
|
|
|
|
|
|
|
3251
|
|
|
|
|
|
|
# Store the merge range. |
|
3252
|
7
|
|
|
|
|
14
|
push @{ $self->{_merge} }, [ $row_first, $col_first, $row_last, $col_last ]; |
|
|
7
|
|
|
|
|
26
|
|
|
3253
|
|
|
|
|
|
|
|
|
3254
|
|
|
|
|
|
|
# Write the first cell |
|
3255
|
7
|
100
|
|
|
|
38
|
if ( $type eq 'string' ) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
3256
|
1
|
|
|
|
|
9
|
$self->write_string( $row_first, $col_first, @_ ); |
|
3257
|
|
|
|
|
|
|
} |
|
3258
|
|
|
|
|
|
|
elsif ( $type eq 'number' ) { |
|
3259
|
1
|
|
|
|
|
5
|
$self->write_number( $row_first, $col_first, @_ ); |
|
3260
|
|
|
|
|
|
|
} |
|
3261
|
|
|
|
|
|
|
elsif ( $type eq 'blank' ) { |
|
3262
|
1
|
|
|
|
|
6
|
$self->write_blank( $row_first, $col_first, @_ ); |
|
3263
|
|
|
|
|
|
|
} |
|
3264
|
|
|
|
|
|
|
elsif ( $type eq 'date_time' ) { |
|
3265
|
1
|
|
|
|
|
5
|
$self->write_date_time( $row_first, $col_first, @_ ); |
|
3266
|
|
|
|
|
|
|
} |
|
3267
|
|
|
|
|
|
|
elsif ( $type eq 'rich_string' ) { |
|
3268
|
1
|
|
|
|
|
9
|
$self->write_rich_string( $row_first, $col_first, @_ ); |
|
3269
|
|
|
|
|
|
|
} |
|
3270
|
|
|
|
|
|
|
elsif ( $type eq 'url' ) { |
|
3271
|
1
|
|
|
|
|
4
|
$self->write_url( $row_first, $col_first, @_ ); |
|
3272
|
|
|
|
|
|
|
} |
|
3273
|
|
|
|
|
|
|
elsif ( $type eq 'formula' ) { |
|
3274
|
1
|
|
|
|
|
7
|
$self->write_formula( $row_first, $col_first, @_ ); |
|
3275
|
|
|
|
|
|
|
} |
|
3276
|
|
|
|
|
|
|
elsif ( $type eq 'array_formula' ) { |
|
3277
|
0
|
|
|
|
|
0
|
$self->write_formula_array( $row_first, $col_first, @_ ); |
|
3278
|
|
|
|
|
|
|
} |
|
3279
|
|
|
|
|
|
|
else { |
|
3280
|
0
|
|
|
|
|
0
|
croak "Unknown type '$type'"; |
|
3281
|
|
|
|
|
|
|
} |
|
3282
|
|
|
|
|
|
|
|
|
3283
|
|
|
|
|
|
|
# Pad out the rest of the area with formatted blank cells. |
|
3284
|
7
|
|
|
|
|
19
|
for my $row ( $row_first .. $row_last ) { |
|
3285
|
7
|
|
|
|
|
15
|
for my $col ( $col_first .. $col_last ) { |
|
3286
|
14
|
100
|
66
|
|
|
46
|
next if $row == $row_first and $col == $col_first; |
|
3287
|
7
|
|
|
|
|
22
|
$self->write_blank( $row, $col, $format ); |
|
3288
|
|
|
|
|
|
|
} |
|
3289
|
|
|
|
|
|
|
} |
|
3290
|
|
|
|
|
|
|
} |
|
3291
|
|
|
|
|
|
|
|
|
3292
|
|
|
|
|
|
|
|
|
3293
|
|
|
|
|
|
|
############################################################################### |
|
3294
|
|
|
|
|
|
|
# |
|
3295
|
|
|
|
|
|
|
# data_validation($row, $col, {...}) |
|
3296
|
|
|
|
|
|
|
# |
|
3297
|
|
|
|
|
|
|
# This method handles the interface to Excel data validation. |
|
3298
|
|
|
|
|
|
|
# Somewhat ironically this requires a lot of validation code since the |
|
3299
|
|
|
|
|
|
|
# interface is flexible and covers a several types of data validation. |
|
3300
|
|
|
|
|
|
|
# |
|
3301
|
|
|
|
|
|
|
# We allow data validation to be called on one cell or a range of cells. The |
|
3302
|
|
|
|
|
|
|
# hashref contains the validation parameters and must be the last param: |
|
3303
|
|
|
|
|
|
|
# data_validation($row, $col, {...}) |
|
3304
|
|
|
|
|
|
|
# data_validation($first_row, $first_col, $last_row, $last_col, {...}) |
|
3305
|
|
|
|
|
|
|
# |
|
3306
|
|
|
|
|
|
|
# Returns 0 : normal termination |
|
3307
|
|
|
|
|
|
|
# -1 : insufficient number of arguments |
|
3308
|
|
|
|
|
|
|
# -2 : row or column out of range |
|
3309
|
|
|
|
|
|
|
# -3 : incorrect parameter. |
|
3310
|
|
|
|
|
|
|
# |
|
3311
|
|
|
|
|
|
|
sub data_validation { |
|
3312
|
|
|
|
|
|
|
|
|
3313
|
68
|
|
|
68
|
0
|
1763
|
my $self = shift; |
|
3314
|
|
|
|
|
|
|
|
|
3315
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
3316
|
68
|
100
|
|
|
|
339
|
if ( $_[0] =~ /^\D/ ) { |
|
3317
|
63
|
|
|
|
|
205
|
@_ = $self->_substitute_cellref( @_ ); |
|
3318
|
|
|
|
|
|
|
} |
|
3319
|
|
|
|
|
|
|
|
|
3320
|
|
|
|
|
|
|
# Check for a valid number of args. |
|
3321
|
68
|
50
|
66
|
|
|
315
|
if ( @_ != 5 && @_ != 3 ) { return -1 } |
|
|
0
|
|
|
|
|
0
|
|
|
3322
|
|
|
|
|
|
|
|
|
3323
|
|
|
|
|
|
|
# The final hashref contains the validation parameters. |
|
3324
|
68
|
|
|
|
|
124
|
my $param = pop; |
|
3325
|
|
|
|
|
|
|
|
|
3326
|
|
|
|
|
|
|
# Make the last row/col the same as the first if not defined. |
|
3327
|
68
|
|
|
|
|
158
|
my ( $row1, $col1, $row2, $col2 ) = @_; |
|
3328
|
68
|
100
|
|
|
|
162
|
if ( !defined $row2 ) { |
|
3329
|
63
|
|
|
|
|
98
|
$row2 = $row1; |
|
3330
|
63
|
|
|
|
|
107
|
$col2 = $col1; |
|
3331
|
|
|
|
|
|
|
} |
|
3332
|
|
|
|
|
|
|
|
|
3333
|
|
|
|
|
|
|
# Check that row and col are valid without storing the values. |
|
3334
|
68
|
50
|
|
|
|
188
|
return -2 if $self->_check_dimensions( $row1, $col1, 1, 1 ); |
|
3335
|
68
|
50
|
|
|
|
167
|
return -2 if $self->_check_dimensions( $row2, $col2, 1, 1 ); |
|
3336
|
|
|
|
|
|
|
|
|
3337
|
|
|
|
|
|
|
|
|
3338
|
|
|
|
|
|
|
# Check that the last parameter is a hash list. |
|
3339
|
68
|
50
|
|
|
|
202
|
if ( ref $param ne 'HASH' ) { |
|
3340
|
0
|
|
|
|
|
0
|
carp "Last parameter '$param' in data_validation() must be a hash ref"; |
|
3341
|
0
|
|
|
|
|
0
|
return -3; |
|
3342
|
|
|
|
|
|
|
} |
|
3343
|
|
|
|
|
|
|
|
|
3344
|
|
|
|
|
|
|
# List of valid input parameters. |
|
3345
|
68
|
|
|
|
|
451
|
my %valid_parameter = ( |
|
3346
|
|
|
|
|
|
|
validate => 1, |
|
3347
|
|
|
|
|
|
|
criteria => 1, |
|
3348
|
|
|
|
|
|
|
value => 1, |
|
3349
|
|
|
|
|
|
|
source => 1, |
|
3350
|
|
|
|
|
|
|
minimum => 1, |
|
3351
|
|
|
|
|
|
|
maximum => 1, |
|
3352
|
|
|
|
|
|
|
ignore_blank => 1, |
|
3353
|
|
|
|
|
|
|
dropdown => 1, |
|
3354
|
|
|
|
|
|
|
show_input => 1, |
|
3355
|
|
|
|
|
|
|
input_title => 1, |
|
3356
|
|
|
|
|
|
|
input_message => 1, |
|
3357
|
|
|
|
|
|
|
show_error => 1, |
|
3358
|
|
|
|
|
|
|
error_title => 1, |
|
3359
|
|
|
|
|
|
|
error_message => 1, |
|
3360
|
|
|
|
|
|
|
error_type => 1, |
|
3361
|
|
|
|
|
|
|
other_cells => 1, |
|
3362
|
|
|
|
|
|
|
); |
|
3363
|
|
|
|
|
|
|
|
|
3364
|
|
|
|
|
|
|
# Check for valid input parameters. |
|
3365
|
68
|
|
|
|
|
275
|
for my $param_key ( keys %$param ) { |
|
3366
|
262
|
50
|
|
|
|
546
|
if ( not exists $valid_parameter{$param_key} ) { |
|
3367
|
0
|
|
|
|
|
0
|
carp "Unknown parameter '$param_key' in data_validation()"; |
|
3368
|
0
|
|
|
|
|
0
|
return -3; |
|
3369
|
|
|
|
|
|
|
} |
|
3370
|
|
|
|
|
|
|
} |
|
3371
|
|
|
|
|
|
|
|
|
3372
|
|
|
|
|
|
|
# Map alternative parameter names 'source' or 'minimum' to 'value'. |
|
3373
|
68
|
100
|
|
|
|
202
|
$param->{value} = $param->{source} if defined $param->{source}; |
|
3374
|
68
|
100
|
|
|
|
176
|
$param->{value} = $param->{minimum} if defined $param->{minimum}; |
|
3375
|
|
|
|
|
|
|
|
|
3376
|
|
|
|
|
|
|
# 'validate' is a required parameter. |
|
3377
|
68
|
50
|
|
|
|
181
|
if ( not exists $param->{validate} ) { |
|
3378
|
0
|
|
|
|
|
0
|
carp "Parameter 'validate' is required in data_validation()"; |
|
3379
|
0
|
|
|
|
|
0
|
return -3; |
|
3380
|
|
|
|
|
|
|
} |
|
3381
|
|
|
|
|
|
|
|
|
3382
|
|
|
|
|
|
|
|
|
3383
|
|
|
|
|
|
|
# List of valid validation types. |
|
3384
|
68
|
|
|
|
|
490
|
my %valid_type = ( |
|
3385
|
|
|
|
|
|
|
'any' => 'none', |
|
3386
|
|
|
|
|
|
|
'any value' => 'none', |
|
3387
|
|
|
|
|
|
|
'whole number' => 'whole', |
|
3388
|
|
|
|
|
|
|
'whole' => 'whole', |
|
3389
|
|
|
|
|
|
|
'integer' => 'whole', |
|
3390
|
|
|
|
|
|
|
'decimal' => 'decimal', |
|
3391
|
|
|
|
|
|
|
'list' => 'list', |
|
3392
|
|
|
|
|
|
|
'date' => 'date', |
|
3393
|
|
|
|
|
|
|
'time' => 'time', |
|
3394
|
|
|
|
|
|
|
'text length' => 'textLength', |
|
3395
|
|
|
|
|
|
|
'length' => 'textLength', |
|
3396
|
|
|
|
|
|
|
'custom' => 'custom', |
|
3397
|
|
|
|
|
|
|
); |
|
3398
|
|
|
|
|
|
|
|
|
3399
|
|
|
|
|
|
|
|
|
3400
|
|
|
|
|
|
|
# Check for valid validation types. |
|
3401
|
68
|
50
|
|
|
|
222
|
if ( not exists $valid_type{ lc( $param->{validate} ) } ) { |
|
3402
|
0
|
|
|
|
|
0
|
carp "Unknown validation type '$param->{validate}' for parameter " |
|
3403
|
|
|
|
|
|
|
. "'validate' in data_validation()"; |
|
3404
|
0
|
|
|
|
|
0
|
return -3; |
|
3405
|
|
|
|
|
|
|
} |
|
3406
|
|
|
|
|
|
|
else { |
|
3407
|
68
|
|
|
|
|
162
|
$param->{validate} = $valid_type{ lc( $param->{validate} ) }; |
|
3408
|
|
|
|
|
|
|
} |
|
3409
|
|
|
|
|
|
|
|
|
3410
|
|
|
|
|
|
|
# No action is required for validation type 'any' |
|
3411
|
|
|
|
|
|
|
# unless there are input messages. |
|
3412
|
68
|
100
|
100
|
|
|
192
|
if ( $param->{validate} eq 'none' |
|
|
|
|
66
|
|
|
|
|
|
3413
|
|
|
|
|
|
|
&& !defined $param->{input_message} |
|
3414
|
|
|
|
|
|
|
&& !defined $param->{input_title} ) |
|
3415
|
|
|
|
|
|
|
{ |
|
3416
|
1
|
|
|
|
|
7
|
return 0; |
|
3417
|
|
|
|
|
|
|
} |
|
3418
|
|
|
|
|
|
|
|
|
3419
|
|
|
|
|
|
|
# The any, list and custom validations don't have a criteria |
|
3420
|
|
|
|
|
|
|
# so we use a default of 'between'. |
|
3421
|
67
|
100
|
100
|
|
|
356
|
if ( $param->{validate} eq 'none' |
|
|
|
|
100
|
|
|
|
|
|
3422
|
|
|
|
|
|
|
|| $param->{validate} eq 'list' |
|
3423
|
|
|
|
|
|
|
|| $param->{validate} eq 'custom' ) |
|
3424
|
|
|
|
|
|
|
{ |
|
3425
|
18
|
|
|
|
|
54
|
$param->{criteria} = 'between'; |
|
3426
|
18
|
|
|
|
|
37
|
$param->{maximum} = undef; |
|
3427
|
|
|
|
|
|
|
} |
|
3428
|
|
|
|
|
|
|
|
|
3429
|
|
|
|
|
|
|
# 'criteria' is a required parameter. |
|
3430
|
67
|
50
|
|
|
|
156
|
if ( not exists $param->{criteria} ) { |
|
3431
|
0
|
|
|
|
|
0
|
carp "Parameter 'criteria' is required in data_validation()"; |
|
3432
|
0
|
|
|
|
|
0
|
return -3; |
|
3433
|
|
|
|
|
|
|
} |
|
3434
|
|
|
|
|
|
|
|
|
3435
|
|
|
|
|
|
|
|
|
3436
|
|
|
|
|
|
|
# List of valid criteria types. |
|
3437
|
67
|
|
|
|
|
580
|
my %criteria_type = ( |
|
3438
|
|
|
|
|
|
|
'between' => 'between', |
|
3439
|
|
|
|
|
|
|
'not between' => 'notBetween', |
|
3440
|
|
|
|
|
|
|
'equal to' => 'equal', |
|
3441
|
|
|
|
|
|
|
'=' => 'equal', |
|
3442
|
|
|
|
|
|
|
'==' => 'equal', |
|
3443
|
|
|
|
|
|
|
'not equal to' => 'notEqual', |
|
3444
|
|
|
|
|
|
|
'!=' => 'notEqual', |
|
3445
|
|
|
|
|
|
|
'<>' => 'notEqual', |
|
3446
|
|
|
|
|
|
|
'greater than' => 'greaterThan', |
|
3447
|
|
|
|
|
|
|
'>' => 'greaterThan', |
|
3448
|
|
|
|
|
|
|
'less than' => 'lessThan', |
|
3449
|
|
|
|
|
|
|
'<' => 'lessThan', |
|
3450
|
|
|
|
|
|
|
'greater than or equal to' => 'greaterThanOrEqual', |
|
3451
|
|
|
|
|
|
|
'>=' => 'greaterThanOrEqual', |
|
3452
|
|
|
|
|
|
|
'less than or equal to' => 'lessThanOrEqual', |
|
3453
|
|
|
|
|
|
|
'<=' => 'lessThanOrEqual', |
|
3454
|
|
|
|
|
|
|
); |
|
3455
|
|
|
|
|
|
|
|
|
3456
|
|
|
|
|
|
|
# Check for valid criteria types. |
|
3457
|
67
|
50
|
|
|
|
190
|
if ( not exists $criteria_type{ lc( $param->{criteria} ) } ) { |
|
3458
|
0
|
|
|
|
|
0
|
carp "Unknown criteria type '$param->{criteria}' for parameter " |
|
3459
|
|
|
|
|
|
|
. "'criteria' in data_validation()"; |
|
3460
|
0
|
|
|
|
|
0
|
return -3; |
|
3461
|
|
|
|
|
|
|
} |
|
3462
|
|
|
|
|
|
|
else { |
|
3463
|
67
|
|
|
|
|
149
|
$param->{criteria} = $criteria_type{ lc( $param->{criteria} ) }; |
|
3464
|
|
|
|
|
|
|
} |
|
3465
|
|
|
|
|
|
|
|
|
3466
|
|
|
|
|
|
|
|
|
3467
|
|
|
|
|
|
|
# 'Between' and 'Not between' criteria require 2 values. |
|
3468
|
67
|
100
|
100
|
|
|
209
|
if ( $param->{criteria} eq 'between' || $param->{criteria} eq 'notBetween' ) |
|
3469
|
|
|
|
|
|
|
{ |
|
3470
|
42
|
50
|
|
|
|
100
|
if ( not exists $param->{maximum} ) { |
|
3471
|
0
|
|
|
|
|
0
|
carp "Parameter 'maximum' is required in data_validation() " |
|
3472
|
|
|
|
|
|
|
. "when using 'between' or 'not between' criteria"; |
|
3473
|
0
|
|
|
|
|
0
|
return -3; |
|
3474
|
|
|
|
|
|
|
} |
|
3475
|
|
|
|
|
|
|
} |
|
3476
|
|
|
|
|
|
|
else { |
|
3477
|
25
|
|
|
|
|
48
|
$param->{maximum} = undef; |
|
3478
|
|
|
|
|
|
|
} |
|
3479
|
|
|
|
|
|
|
|
|
3480
|
|
|
|
|
|
|
|
|
3481
|
|
|
|
|
|
|
# List of valid error dialog types. |
|
3482
|
67
|
|
|
|
|
204
|
my %error_type = ( |
|
3483
|
|
|
|
|
|
|
'stop' => 0, |
|
3484
|
|
|
|
|
|
|
'warning' => 1, |
|
3485
|
|
|
|
|
|
|
'information' => 2, |
|
3486
|
|
|
|
|
|
|
); |
|
3487
|
|
|
|
|
|
|
|
|
3488
|
|
|
|
|
|
|
# Check for valid error dialog types. |
|
3489
|
67
|
100
|
|
|
|
158
|
if ( not exists $param->{error_type} ) { |
|
|
|
50
|
|
|
|
|
|
|
3490
|
65
|
|
|
|
|
118
|
$param->{error_type} = 0; |
|
3491
|
|
|
|
|
|
|
} |
|
3492
|
|
|
|
|
|
|
elsif ( not exists $error_type{ lc( $param->{error_type} ) } ) { |
|
3493
|
0
|
|
|
|
|
0
|
carp "Unknown criteria type '$param->{error_type}' for parameter " |
|
3494
|
|
|
|
|
|
|
. "'error_type' in data_validation()"; |
|
3495
|
0
|
|
|
|
|
0
|
return -3; |
|
3496
|
|
|
|
|
|
|
} |
|
3497
|
|
|
|
|
|
|
else { |
|
3498
|
2
|
|
|
|
|
6
|
$param->{error_type} = $error_type{ lc( $param->{error_type} ) }; |
|
3499
|
|
|
|
|
|
|
} |
|
3500
|
|
|
|
|
|
|
|
|
3501
|
|
|
|
|
|
|
|
|
3502
|
|
|
|
|
|
|
# Convert date/times value if required. |
|
3503
|
67
|
100
|
100
|
|
|
268
|
if ( $param->{validate} eq 'date' || $param->{validate} eq 'time' ) { |
|
3504
|
7
|
|
|
|
|
31
|
my $date_time = $self->convert_date_time( $param->{value} ); |
|
3505
|
|
|
|
|
|
|
|
|
3506
|
7
|
100
|
|
|
|
19
|
if ( defined $date_time ) { |
|
3507
|
5
|
|
|
|
|
11
|
$param->{value} = $date_time; |
|
3508
|
|
|
|
|
|
|
} |
|
3509
|
|
|
|
|
|
|
|
|
3510
|
7
|
100
|
|
|
|
76
|
if ( defined $param->{maximum} ) { |
|
3511
|
3
|
|
|
|
|
15
|
my $date_time = $self->convert_date_time( $param->{maximum} ); |
|
3512
|
|
|
|
|
|
|
|
|
3513
|
3
|
100
|
|
|
|
13
|
if ( defined $date_time ) { |
|
3514
|
2
|
|
|
|
|
5
|
$param->{maximum} = $date_time; |
|
3515
|
|
|
|
|
|
|
} |
|
3516
|
|
|
|
|
|
|
} |
|
3517
|
|
|
|
|
|
|
} |
|
3518
|
|
|
|
|
|
|
|
|
3519
|
|
|
|
|
|
|
# Check that the input title doesn't exceed the maximum length. |
|
3520
|
67
|
100
|
100
|
|
|
206
|
if ( $param->{input_title} and length $param->{input_title} > 32 ) { |
|
3521
|
1
|
|
|
|
|
279
|
carp "Length of input title '$param->{input_title}'" |
|
3522
|
|
|
|
|
|
|
. " exceeds Excel's limit of 32"; |
|
3523
|
1
|
|
|
|
|
15
|
return -3; |
|
3524
|
|
|
|
|
|
|
} |
|
3525
|
|
|
|
|
|
|
|
|
3526
|
|
|
|
|
|
|
# Check that the error title don't exceed the maximum length. |
|
3527
|
66
|
50
|
66
|
|
|
170
|
if ( $param->{error_title} and length $param->{error_title} > 32 ) { |
|
3528
|
0
|
|
|
|
|
0
|
carp "Length of error title '$param->{error_title}'" |
|
3529
|
|
|
|
|
|
|
. " exceeds Excel's limit of 32"; |
|
3530
|
0
|
|
|
|
|
0
|
return -3; |
|
3531
|
|
|
|
|
|
|
} |
|
3532
|
|
|
|
|
|
|
|
|
3533
|
|
|
|
|
|
|
# Check that the input message don't exceed the maximum length. |
|
3534
|
66
|
100
|
100
|
|
|
198
|
if ( $param->{input_message} and length $param->{input_message} > 255 ) { |
|
3535
|
1
|
|
|
|
|
239
|
carp "Length of input message '$param->{input_message}'" |
|
3536
|
|
|
|
|
|
|
. " exceeds Excel's limit of 255"; |
|
3537
|
1
|
|
|
|
|
15
|
return -3; |
|
3538
|
|
|
|
|
|
|
} |
|
3539
|
|
|
|
|
|
|
|
|
3540
|
|
|
|
|
|
|
# Check that the error message don't exceed the maximum length. |
|
3541
|
65
|
50
|
66
|
|
|
160
|
if ( $param->{error_message} and length $param->{error_message} > 255 ) { |
|
3542
|
0
|
|
|
|
|
0
|
carp "Length of error message '$param->{error_message}'" |
|
3543
|
|
|
|
|
|
|
. " exceeds Excel's limit of 255"; |
|
3544
|
0
|
|
|
|
|
0
|
return -3; |
|
3545
|
|
|
|
|
|
|
} |
|
3546
|
|
|
|
|
|
|
|
|
3547
|
|
|
|
|
|
|
# Check that the input list don't exceed the maximum length. |
|
3548
|
65
|
100
|
|
|
|
157
|
if ( $param->{validate} eq 'list' ) { |
|
3549
|
|
|
|
|
|
|
|
|
3550
|
13
|
100
|
|
|
|
61
|
if ( ref $param->{value} eq 'ARRAY' ) { |
|
3551
|
|
|
|
|
|
|
|
|
3552
|
11
|
|
|
|
|
27
|
my $formula = join ',', @{ $param->{value} }; |
|
|
11
|
|
|
|
|
52
|
|
|
3553
|
11
|
100
|
|
|
|
45
|
if ( length $formula > 255 ) { |
|
3554
|
1
|
|
|
|
|
235
|
carp "Length of list items '$formula' exceeds Excel's " |
|
3555
|
|
|
|
|
|
|
. "limit of 255, use a formula range instead"; |
|
3556
|
1
|
|
|
|
|
14
|
return -3; |
|
3557
|
|
|
|
|
|
|
} |
|
3558
|
|
|
|
|
|
|
} |
|
3559
|
|
|
|
|
|
|
} |
|
3560
|
|
|
|
|
|
|
|
|
3561
|
|
|
|
|
|
|
# Set some defaults if they haven't been defined by the user. |
|
3562
|
64
|
100
|
|
|
|
188
|
$param->{ignore_blank} = 1 if !defined $param->{ignore_blank}; |
|
3563
|
64
|
100
|
|
|
|
193
|
$param->{dropdown} = 1 if !defined $param->{dropdown}; |
|
3564
|
64
|
100
|
|
|
|
189
|
$param->{show_input} = 1 if !defined $param->{show_input}; |
|
3565
|
64
|
100
|
|
|
|
152
|
$param->{show_error} = 1 if !defined $param->{show_error}; |
|
3566
|
|
|
|
|
|
|
|
|
3567
|
|
|
|
|
|
|
|
|
3568
|
|
|
|
|
|
|
# These are the cells to which the validation is applied. |
|
3569
|
64
|
|
|
|
|
209
|
$param->{cells} = [ [ $row1, $col1, $row2, $col2 ] ]; |
|
3570
|
|
|
|
|
|
|
|
|
3571
|
|
|
|
|
|
|
# A (for now) undocumented parameter to pass additional cell ranges. |
|
3572
|
64
|
100
|
|
|
|
183
|
if ( exists $param->{other_cells} ) { |
|
3573
|
|
|
|
|
|
|
|
|
3574
|
3
|
|
|
|
|
5
|
push @{ $param->{cells} }, @{ $param->{other_cells} }; |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
16
|
|
|
3575
|
|
|
|
|
|
|
} |
|
3576
|
|
|
|
|
|
|
|
|
3577
|
|
|
|
|
|
|
# Store the validation information until we close the worksheet. |
|
3578
|
64
|
|
|
|
|
582
|
push @{ $self->{_validations} }, $param; |
|
|
64
|
|
|
|
|
980
|
|
|
3579
|
|
|
|
|
|
|
} |
|
3580
|
|
|
|
|
|
|
|
|
3581
|
|
|
|
|
|
|
|
|
3582
|
|
|
|
|
|
|
############################################################################### |
|
3583
|
|
|
|
|
|
|
# |
|
3584
|
|
|
|
|
|
|
# conditional_formatting($row, $col, {...}) |
|
3585
|
|
|
|
|
|
|
# |
|
3586
|
|
|
|
|
|
|
# This method handles the interface to Excel conditional formatting. |
|
3587
|
|
|
|
|
|
|
# |
|
3588
|
|
|
|
|
|
|
# We allow the format to be called on one cell or a range of cells. The |
|
3589
|
|
|
|
|
|
|
# hashref contains the formatting parameters and must be the last param: |
|
3590
|
|
|
|
|
|
|
# conditional_formatting($row, $col, {...}) |
|
3591
|
|
|
|
|
|
|
# conditional_formatting($first_row, $first_col, $last_row, $last_col, {...}) |
|
3592
|
|
|
|
|
|
|
# |
|
3593
|
|
|
|
|
|
|
# Returns 0 : normal termination |
|
3594
|
|
|
|
|
|
|
# -1 : insufficient number of arguments |
|
3595
|
|
|
|
|
|
|
# -2 : row or column out of range |
|
3596
|
|
|
|
|
|
|
# -3 : incorrect parameter. |
|
3597
|
|
|
|
|
|
|
# |
|
3598
|
|
|
|
|
|
|
sub conditional_formatting { |
|
3599
|
|
|
|
|
|
|
|
|
3600
|
149
|
|
|
149
|
0
|
1545
|
my $self = shift; |
|
3601
|
149
|
|
|
|
|
307
|
my $user_range = ''; |
|
3602
|
|
|
|
|
|
|
|
|
3603
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
3604
|
149
|
50
|
|
|
|
684
|
if ( $_[0] =~ /^\D/ ) { |
|
3605
|
|
|
|
|
|
|
|
|
3606
|
|
|
|
|
|
|
# Check for a user defined multiple range like B3:K6,B8:K11. |
|
3607
|
149
|
100
|
|
|
|
564
|
if ( $_[0] =~ /,/ ) { |
|
3608
|
1
|
|
|
|
|
4
|
$user_range = $_[0]; |
|
3609
|
1
|
|
|
|
|
5
|
$user_range =~ s/^=//; |
|
3610
|
1
|
|
|
|
|
10
|
$user_range =~ s/\s*,\s*/ /g; |
|
3611
|
1
|
|
|
|
|
6
|
$user_range =~ s/\$//g; |
|
3612
|
|
|
|
|
|
|
} |
|
3613
|
|
|
|
|
|
|
|
|
3614
|
149
|
|
|
|
|
512
|
@_ = $self->_substitute_cellref( @_ ); |
|
3615
|
|
|
|
|
|
|
} |
|
3616
|
|
|
|
|
|
|
|
|
3617
|
|
|
|
|
|
|
# The final hashref contains the validation parameters. |
|
3618
|
149
|
|
|
|
|
340
|
my $options = pop; |
|
3619
|
|
|
|
|
|
|
|
|
3620
|
|
|
|
|
|
|
# Make the last row/col the same as the first if not defined. |
|
3621
|
149
|
|
|
|
|
408
|
my ( $row1, $col1, $row2, $col2 ) = @_; |
|
3622
|
149
|
100
|
|
|
|
424
|
if ( !defined $row2 ) { |
|
3623
|
74
|
|
|
|
|
150
|
$row2 = $row1; |
|
3624
|
74
|
|
|
|
|
131
|
$col2 = $col1; |
|
3625
|
|
|
|
|
|
|
} |
|
3626
|
|
|
|
|
|
|
|
|
3627
|
|
|
|
|
|
|
# Check that row and col are valid without storing the values. |
|
3628
|
149
|
50
|
|
|
|
509
|
return -2 if $self->_check_dimensions( $row1, $col1, 1, 1 ); |
|
3629
|
149
|
50
|
|
|
|
610
|
return -2 if $self->_check_dimensions( $row2, $col2, 1, 1 ); |
|
3630
|
|
|
|
|
|
|
|
|
3631
|
|
|
|
|
|
|
|
|
3632
|
|
|
|
|
|
|
# Check that the last parameter is a hash list. |
|
3633
|
149
|
50
|
|
|
|
705
|
if ( ref $options ne 'HASH' ) { |
|
3634
|
0
|
|
|
|
|
0
|
carp "Last parameter in conditional_formatting() " |
|
3635
|
|
|
|
|
|
|
. "must be a hash ref"; |
|
3636
|
0
|
|
|
|
|
0
|
return -3; |
|
3637
|
|
|
|
|
|
|
} |
|
3638
|
|
|
|
|
|
|
|
|
3639
|
|
|
|
|
|
|
# Copy the user params. |
|
3640
|
149
|
|
|
|
|
762
|
my $param = {%$options}; |
|
3641
|
|
|
|
|
|
|
|
|
3642
|
|
|
|
|
|
|
# List of valid input parameters. |
|
3643
|
149
|
|
|
|
|
2846
|
my %valid_parameter = ( |
|
3644
|
|
|
|
|
|
|
type => 1, |
|
3645
|
|
|
|
|
|
|
format => 1, |
|
3646
|
|
|
|
|
|
|
criteria => 1, |
|
3647
|
|
|
|
|
|
|
value => 1, |
|
3648
|
|
|
|
|
|
|
minimum => 1, |
|
3649
|
|
|
|
|
|
|
maximum => 1, |
|
3650
|
|
|
|
|
|
|
stop_if_true => 1, |
|
3651
|
|
|
|
|
|
|
min_type => 1, |
|
3652
|
|
|
|
|
|
|
mid_type => 1, |
|
3653
|
|
|
|
|
|
|
max_type => 1, |
|
3654
|
|
|
|
|
|
|
min_value => 1, |
|
3655
|
|
|
|
|
|
|
mid_value => 1, |
|
3656
|
|
|
|
|
|
|
max_value => 1, |
|
3657
|
|
|
|
|
|
|
min_color => 1, |
|
3658
|
|
|
|
|
|
|
mid_color => 1, |
|
3659
|
|
|
|
|
|
|
max_color => 1, |
|
3660
|
|
|
|
|
|
|
bar_color => 1, |
|
3661
|
|
|
|
|
|
|
bar_negative_color => 1, |
|
3662
|
|
|
|
|
|
|
bar_negative_color_same => 1, |
|
3663
|
|
|
|
|
|
|
bar_solid => 1, |
|
3664
|
|
|
|
|
|
|
bar_border_color => 1, |
|
3665
|
|
|
|
|
|
|
bar_negative_border_color => 1, |
|
3666
|
|
|
|
|
|
|
bar_negative_border_color_same => 1, |
|
3667
|
|
|
|
|
|
|
bar_no_border => 1, |
|
3668
|
|
|
|
|
|
|
bar_direction => 1, |
|
3669
|
|
|
|
|
|
|
bar_axis_position => 1, |
|
3670
|
|
|
|
|
|
|
bar_axis_color => 1, |
|
3671
|
|
|
|
|
|
|
bar_only => 1, |
|
3672
|
|
|
|
|
|
|
icon_style => 1, |
|
3673
|
|
|
|
|
|
|
reverse_icons => 1, |
|
3674
|
|
|
|
|
|
|
icons_only => 1, |
|
3675
|
|
|
|
|
|
|
icons => 1, |
|
3676
|
|
|
|
|
|
|
data_bar_2010 => 1, |
|
3677
|
|
|
|
|
|
|
); |
|
3678
|
|
|
|
|
|
|
|
|
3679
|
|
|
|
|
|
|
# Check for valid input parameters. |
|
3680
|
149
|
|
|
|
|
1143
|
for my $param_key ( keys %$param ) { |
|
3681
|
492
|
50
|
|
|
|
1248
|
if ( not exists $valid_parameter{$param_key} ) { |
|
3682
|
0
|
|
|
|
|
0
|
carp "Unknown parameter '$param_key' in conditional_formatting()"; |
|
3683
|
0
|
|
|
|
|
0
|
return -3; |
|
3684
|
|
|
|
|
|
|
} |
|
3685
|
|
|
|
|
|
|
} |
|
3686
|
|
|
|
|
|
|
|
|
3687
|
|
|
|
|
|
|
# 'type' is a required parameter. |
|
3688
|
149
|
50
|
|
|
|
759
|
if ( not exists $param->{type} ) { |
|
3689
|
0
|
|
|
|
|
0
|
carp "Parameter 'type' is required in conditional_formatting()"; |
|
3690
|
0
|
|
|
|
|
0
|
return -3; |
|
3691
|
|
|
|
|
|
|
} |
|
3692
|
|
|
|
|
|
|
|
|
3693
|
|
|
|
|
|
|
# List of valid validation types. |
|
3694
|
149
|
|
|
|
|
1916
|
my %valid_type = ( |
|
3695
|
|
|
|
|
|
|
'cell' => 'cellIs', |
|
3696
|
|
|
|
|
|
|
'date' => 'date', |
|
3697
|
|
|
|
|
|
|
'time' => 'time', |
|
3698
|
|
|
|
|
|
|
'average' => 'aboveAverage', |
|
3699
|
|
|
|
|
|
|
'duplicate' => 'duplicateValues', |
|
3700
|
|
|
|
|
|
|
'unique' => 'uniqueValues', |
|
3701
|
|
|
|
|
|
|
'top' => 'top10', |
|
3702
|
|
|
|
|
|
|
'bottom' => 'top10', |
|
3703
|
|
|
|
|
|
|
'text' => 'text', |
|
3704
|
|
|
|
|
|
|
'time_period' => 'timePeriod', |
|
3705
|
|
|
|
|
|
|
'blanks' => 'containsBlanks', |
|
3706
|
|
|
|
|
|
|
'no_blanks' => 'notContainsBlanks', |
|
3707
|
|
|
|
|
|
|
'errors' => 'containsErrors', |
|
3708
|
|
|
|
|
|
|
'no_errors' => 'notContainsErrors', |
|
3709
|
|
|
|
|
|
|
'2_color_scale' => '2_color_scale', |
|
3710
|
|
|
|
|
|
|
'3_color_scale' => '3_color_scale', |
|
3711
|
|
|
|
|
|
|
'data_bar' => 'dataBar', |
|
3712
|
|
|
|
|
|
|
'formula' => 'expression', |
|
3713
|
|
|
|
|
|
|
'icon_set' => 'iconSet', |
|
3714
|
|
|
|
|
|
|
); |
|
3715
|
|
|
|
|
|
|
|
|
3716
|
|
|
|
|
|
|
|
|
3717
|
|
|
|
|
|
|
# Check for valid validation types. |
|
3718
|
149
|
50
|
|
|
|
627
|
if ( not exists $valid_type{ lc( $param->{type} ) } ) { |
|
3719
|
0
|
|
|
|
|
0
|
carp "Unknown validation type '$param->{type}' for parameter " |
|
3720
|
|
|
|
|
|
|
. "'type' in conditional_formatting()"; |
|
3721
|
0
|
|
|
|
|
0
|
return -3; |
|
3722
|
|
|
|
|
|
|
} |
|
3723
|
|
|
|
|
|
|
else { |
|
3724
|
149
|
100
|
|
|
|
630
|
$param->{direction} = 'bottom' if $param->{type} eq 'bottom'; |
|
3725
|
149
|
|
|
|
|
764
|
$param->{type} = $valid_type{ lc( $param->{type} ) }; |
|
3726
|
|
|
|
|
|
|
} |
|
3727
|
|
|
|
|
|
|
|
|
3728
|
|
|
|
|
|
|
|
|
3729
|
|
|
|
|
|
|
# List of valid criteria types. |
|
3730
|
149
|
|
|
|
|
2399
|
my %criteria_type = ( |
|
3731
|
|
|
|
|
|
|
'between' => 'between', |
|
3732
|
|
|
|
|
|
|
'not between' => 'notBetween', |
|
3733
|
|
|
|
|
|
|
'equal to' => 'equal', |
|
3734
|
|
|
|
|
|
|
'=' => 'equal', |
|
3735
|
|
|
|
|
|
|
'==' => 'equal', |
|
3736
|
|
|
|
|
|
|
'not equal to' => 'notEqual', |
|
3737
|
|
|
|
|
|
|
'!=' => 'notEqual', |
|
3738
|
|
|
|
|
|
|
'<>' => 'notEqual', |
|
3739
|
|
|
|
|
|
|
'greater than' => 'greaterThan', |
|
3740
|
|
|
|
|
|
|
'>' => 'greaterThan', |
|
3741
|
|
|
|
|
|
|
'less than' => 'lessThan', |
|
3742
|
|
|
|
|
|
|
'<' => 'lessThan', |
|
3743
|
|
|
|
|
|
|
'greater than or equal to' => 'greaterThanOrEqual', |
|
3744
|
|
|
|
|
|
|
'>=' => 'greaterThanOrEqual', |
|
3745
|
|
|
|
|
|
|
'less than or equal to' => 'lessThanOrEqual', |
|
3746
|
|
|
|
|
|
|
'<=' => 'lessThanOrEqual', |
|
3747
|
|
|
|
|
|
|
'containing' => 'containsText', |
|
3748
|
|
|
|
|
|
|
'not containing' => 'notContains', |
|
3749
|
|
|
|
|
|
|
'begins with' => 'beginsWith', |
|
3750
|
|
|
|
|
|
|
'ends with' => 'endsWith', |
|
3751
|
|
|
|
|
|
|
'yesterday' => 'yesterday', |
|
3752
|
|
|
|
|
|
|
'today' => 'today', |
|
3753
|
|
|
|
|
|
|
'last 7 days' => 'last7Days', |
|
3754
|
|
|
|
|
|
|
'last week' => 'lastWeek', |
|
3755
|
|
|
|
|
|
|
'this week' => 'thisWeek', |
|
3756
|
|
|
|
|
|
|
'next week' => 'nextWeek', |
|
3757
|
|
|
|
|
|
|
'last month' => 'lastMonth', |
|
3758
|
|
|
|
|
|
|
'this month' => 'thisMonth', |
|
3759
|
|
|
|
|
|
|
'next month' => 'nextMonth', |
|
3760
|
|
|
|
|
|
|
); |
|
3761
|
|
|
|
|
|
|
|
|
3762
|
|
|
|
|
|
|
# Check for valid criteria types. |
|
3763
|
149
|
100
|
100
|
|
|
727
|
if ( defined $param->{criteria} |
|
3764
|
|
|
|
|
|
|
&& exists $criteria_type{ lc( $param->{criteria} ) } ) |
|
3765
|
|
|
|
|
|
|
{ |
|
3766
|
53
|
|
|
|
|
159
|
$param->{criteria} = $criteria_type{ lc( $param->{criteria} ) }; |
|
3767
|
|
|
|
|
|
|
} |
|
3768
|
|
|
|
|
|
|
|
|
3769
|
|
|
|
|
|
|
# Convert date/times value if required. |
|
3770
|
149
|
100
|
66
|
|
|
813
|
if ( $param->{type} eq 'date' || $param->{type} eq 'time' ) { |
|
3771
|
2
|
|
|
|
|
5
|
$param->{type} = 'cellIs'; |
|
3772
|
|
|
|
|
|
|
|
|
3773
|
2
|
100
|
66
|
|
|
12
|
if ( defined $param->{value} && $param->{value} =~ /T/ ) { |
|
3774
|
1
|
|
|
|
|
5
|
my $date_time = $self->convert_date_time( $param->{value} ); |
|
3775
|
|
|
|
|
|
|
|
|
3776
|
1
|
50
|
|
|
|
3
|
if ( !defined $date_time ) { |
|
3777
|
0
|
|
|
|
|
0
|
carp "Invalid date/time value '$param->{value}' " |
|
3778
|
|
|
|
|
|
|
. "in conditional_formatting()"; |
|
3779
|
0
|
|
|
|
|
0
|
return -3; |
|
3780
|
|
|
|
|
|
|
} |
|
3781
|
|
|
|
|
|
|
else { |
|
3782
|
1
|
|
|
|
|
3
|
$param->{value} = $date_time; |
|
3783
|
|
|
|
|
|
|
} |
|
3784
|
|
|
|
|
|
|
} |
|
3785
|
|
|
|
|
|
|
|
|
3786
|
2
|
100
|
66
|
|
|
12
|
if ( defined $param->{minimum} && $param->{minimum} =~ /T/ ) { |
|
3787
|
1
|
|
|
|
|
6
|
my $date_time = $self->convert_date_time( $param->{minimum} ); |
|
3788
|
|
|
|
|
|
|
|
|
3789
|
1
|
50
|
|
|
|
4
|
if ( !defined $date_time ) { |
|
3790
|
0
|
|
|
|
|
0
|
carp "Invalid date/time value '$param->{minimum}' " |
|
3791
|
|
|
|
|
|
|
. "in conditional_formatting()"; |
|
3792
|
0
|
|
|
|
|
0
|
return -3; |
|
3793
|
|
|
|
|
|
|
} |
|
3794
|
|
|
|
|
|
|
else { |
|
3795
|
1
|
|
|
|
|
9
|
$param->{minimum} = $date_time; |
|
3796
|
|
|
|
|
|
|
} |
|
3797
|
|
|
|
|
|
|
} |
|
3798
|
|
|
|
|
|
|
|
|
3799
|
2
|
100
|
66
|
|
|
13
|
if ( defined $param->{maximum} && $param->{maximum} =~ /T/ ) { |
|
3800
|
1
|
|
|
|
|
3
|
my $date_time = $self->convert_date_time( $param->{maximum} ); |
|
3801
|
|
|
|
|
|
|
|
|
3802
|
1
|
50
|
|
|
|
3
|
if ( !defined $date_time ) { |
|
3803
|
0
|
|
|
|
|
0
|
carp "Invalid date/time value '$param->{maximum}' " |
|
3804
|
|
|
|
|
|
|
. "in conditional_formatting()"; |
|
3805
|
0
|
|
|
|
|
0
|
return -3; |
|
3806
|
|
|
|
|
|
|
} |
|
3807
|
|
|
|
|
|
|
else { |
|
3808
|
1
|
|
|
|
|
3
|
$param->{maximum} = $date_time; |
|
3809
|
|
|
|
|
|
|
} |
|
3810
|
|
|
|
|
|
|
} |
|
3811
|
|
|
|
|
|
|
} |
|
3812
|
|
|
|
|
|
|
|
|
3813
|
|
|
|
|
|
|
|
|
3814
|
|
|
|
|
|
|
# List of valid icon styles. |
|
3815
|
149
|
|
|
|
|
1521
|
my %icon_set_styles = ( |
|
3816
|
|
|
|
|
|
|
"3_arrows" => "3Arrows", # 1 |
|
3817
|
|
|
|
|
|
|
"3_flags" => "3Flags", # 2 |
|
3818
|
|
|
|
|
|
|
"3_traffic_lights_rimmed" => "3TrafficLights2", # 3 |
|
3819
|
|
|
|
|
|
|
"3_symbols_circled" => "3Symbols", # 4 |
|
3820
|
|
|
|
|
|
|
"4_arrows" => "4Arrows", # 5 |
|
3821
|
|
|
|
|
|
|
"4_red_to_black" => "4RedToBlack", # 6 |
|
3822
|
|
|
|
|
|
|
"4_traffic_lights" => "4TrafficLights", # 7 |
|
3823
|
|
|
|
|
|
|
"5_arrows_gray" => "5ArrowsGray", # 8 |
|
3824
|
|
|
|
|
|
|
"5_quarters" => "5Quarters", # 9 |
|
3825
|
|
|
|
|
|
|
"3_arrows_gray" => "3ArrowsGray", # 10 |
|
3826
|
|
|
|
|
|
|
"3_traffic_lights" => "3TrafficLights", # 11 |
|
3827
|
|
|
|
|
|
|
"3_signs" => "3Signs", # 12 |
|
3828
|
|
|
|
|
|
|
"3_symbols" => "3Symbols2", # 13 |
|
3829
|
|
|
|
|
|
|
"4_arrows_gray" => "4ArrowsGray", # 14 |
|
3830
|
|
|
|
|
|
|
"4_ratings" => "4Rating", # 15 |
|
3831
|
|
|
|
|
|
|
"5_arrows" => "5Arrows", # 16 |
|
3832
|
|
|
|
|
|
|
"5_ratings" => "5Rating", # 17 |
|
3833
|
|
|
|
|
|
|
); |
|
3834
|
|
|
|
|
|
|
|
|
3835
|
|
|
|
|
|
|
|
|
3836
|
|
|
|
|
|
|
# Set properties for icon sets. |
|
3837
|
149
|
100
|
|
|
|
439
|
if ( $param->{type} eq 'iconSet' ) { |
|
3838
|
|
|
|
|
|
|
|
|
3839
|
37
|
50
|
|
|
|
90
|
if ( !defined $param->{icon_style} ) { |
|
3840
|
0
|
|
|
|
|
0
|
carp "The 'icon_style' parameter must be specified when " |
|
3841
|
|
|
|
|
|
|
. "'type' == 'icon_set' in conditional_formatting()"; |
|
3842
|
0
|
|
|
|
|
0
|
return -3; |
|
3843
|
|
|
|
|
|
|
} |
|
3844
|
|
|
|
|
|
|
|
|
3845
|
|
|
|
|
|
|
# Check for valid icon styles. |
|
3846
|
37
|
50
|
|
|
|
88
|
if ( not exists $icon_set_styles{ $param->{icon_style} } ) { |
|
3847
|
0
|
|
|
|
|
0
|
carp "Unknown icon style '$param->{icon_style}' for parameter " |
|
3848
|
|
|
|
|
|
|
. "'icon_style' in conditional_formatting()"; |
|
3849
|
0
|
|
|
|
|
0
|
return -3; |
|
3850
|
|
|
|
|
|
|
} |
|
3851
|
|
|
|
|
|
|
else { |
|
3852
|
37
|
|
|
|
|
74
|
$param->{icon_style} = $icon_set_styles{ $param->{icon_style} }; |
|
3853
|
|
|
|
|
|
|
} |
|
3854
|
|
|
|
|
|
|
|
|
3855
|
|
|
|
|
|
|
# Set the number of icons for the icon style. |
|
3856
|
37
|
|
|
|
|
86
|
$param->{total_icons} = 3; |
|
3857
|
37
|
100
|
|
|
|
145
|
if ( $param->{icon_style} =~ /^4/ ) { |
|
|
|
100
|
|
|
|
|
|
|
3858
|
11
|
|
|
|
|
20
|
$param->{total_icons} = 4; |
|
3859
|
|
|
|
|
|
|
} |
|
3860
|
|
|
|
|
|
|
elsif ( $param->{icon_style} =~ /^5/ ) { |
|
3861
|
8
|
|
|
|
|
18
|
$param->{total_icons} = 5; |
|
3862
|
|
|
|
|
|
|
} |
|
3863
|
|
|
|
|
|
|
|
|
3864
|
|
|
|
|
|
|
$param->{icons} = |
|
3865
|
37
|
|
|
|
|
120
|
$self->_set_icon_properties( $param->{total_icons}, $param->{icons} ); |
|
3866
|
|
|
|
|
|
|
} |
|
3867
|
|
|
|
|
|
|
|
|
3868
|
|
|
|
|
|
|
|
|
3869
|
|
|
|
|
|
|
# Set the formatting range. |
|
3870
|
149
|
|
|
|
|
328
|
my $range = ''; |
|
3871
|
149
|
|
|
|
|
270
|
my $start_cell = ''; # Use for formulas. |
|
3872
|
|
|
|
|
|
|
|
|
3873
|
|
|
|
|
|
|
# Swap last row/col for first row/col as necessary |
|
3874
|
149
|
50
|
|
|
|
387
|
if ( $row1 > $row2 ) { |
|
3875
|
0
|
|
|
|
|
0
|
( $row1, $row2 ) = ( $row2, $row1 ); |
|
3876
|
|
|
|
|
|
|
} |
|
3877
|
|
|
|
|
|
|
|
|
3878
|
149
|
50
|
|
|
|
400
|
if ( $col1 > $col2 ) { |
|
3879
|
0
|
|
|
|
|
0
|
( $col1, $col2 ) = ( $col2, $col1 ); |
|
3880
|
|
|
|
|
|
|
} |
|
3881
|
|
|
|
|
|
|
|
|
3882
|
|
|
|
|
|
|
# If the first and last cell are the same write a single cell. |
|
3883
|
149
|
100
|
100
|
|
|
635
|
if ( ( $row1 == $row2 ) && ( $col1 == $col2 ) ) { |
|
3884
|
74
|
|
|
|
|
347
|
$range = xl_rowcol_to_cell( $row1, $col1 ); |
|
3885
|
74
|
|
|
|
|
155
|
$start_cell = $range; |
|
3886
|
|
|
|
|
|
|
} |
|
3887
|
|
|
|
|
|
|
else { |
|
3888
|
75
|
|
|
|
|
328
|
$range = xl_range( $row1, $row2, $col1, $col2 ); |
|
3889
|
75
|
|
|
|
|
228
|
$start_cell = xl_rowcol_to_cell( $row1, $col1 ); |
|
3890
|
|
|
|
|
|
|
} |
|
3891
|
|
|
|
|
|
|
|
|
3892
|
|
|
|
|
|
|
# Override with user defined multiple range if provided. |
|
3893
|
149
|
100
|
|
|
|
422
|
if ( $user_range ) { |
|
3894
|
1
|
|
|
|
|
3
|
$range = $user_range; |
|
3895
|
|
|
|
|
|
|
} |
|
3896
|
|
|
|
|
|
|
|
|
3897
|
|
|
|
|
|
|
# Get the dxf format index. |
|
3898
|
149
|
100
|
66
|
|
|
771
|
if ( defined $param->{format} && ref $param->{format} ) { |
|
3899
|
27
|
|
|
|
|
133
|
$param->{format} = $param->{format}->get_dxf_index(); |
|
3900
|
|
|
|
|
|
|
} |
|
3901
|
|
|
|
|
|
|
|
|
3902
|
|
|
|
|
|
|
# Set the priority based on the order of adding. |
|
3903
|
149
|
|
|
|
|
436
|
$param->{priority} = $self->{_dxf_priority}++; |
|
3904
|
|
|
|
|
|
|
|
|
3905
|
|
|
|
|
|
|
# Check for 2010 style data_bar parameters. |
|
3906
|
149
|
100
|
100
|
|
|
2776
|
if ( $self->{_use_data_bars_2010} |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
3907
|
|
|
|
|
|
|
|| $param->{data_bar_2010} |
|
3908
|
|
|
|
|
|
|
|| $param->{bar_solid} |
|
3909
|
|
|
|
|
|
|
|| $param->{bar_border_color} |
|
3910
|
|
|
|
|
|
|
|| $param->{bar_negative_color} |
|
3911
|
|
|
|
|
|
|
|| $param->{bar_negative_color_same} |
|
3912
|
|
|
|
|
|
|
|| $param->{bar_negative_border_color} |
|
3913
|
|
|
|
|
|
|
|| $param->{bar_negative_border_color_same} |
|
3914
|
|
|
|
|
|
|
|| $param->{bar_no_border} |
|
3915
|
|
|
|
|
|
|
|| $param->{bar_axis_position} |
|
3916
|
|
|
|
|
|
|
|| $param->{bar_axis_color} |
|
3917
|
|
|
|
|
|
|
|| $param->{bar_direction} ) |
|
3918
|
|
|
|
|
|
|
{ |
|
3919
|
25
|
|
|
|
|
59
|
$param->{_is_data_bar_2010} = 1; |
|
3920
|
|
|
|
|
|
|
} |
|
3921
|
|
|
|
|
|
|
|
|
3922
|
|
|
|
|
|
|
# Special handling of text criteria. |
|
3923
|
149
|
100
|
|
|
|
492
|
if ( $param->{type} eq 'text' ) { |
|
3924
|
|
|
|
|
|
|
|
|
3925
|
8
|
100
|
|
|
|
34
|
if ( $param->{criteria} eq 'containsText' ) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
3926
|
1
|
|
|
|
|
12
|
$param->{type} = 'containsText'; |
|
3927
|
|
|
|
|
|
|
$param->{formula} = sprintf 'NOT(ISERROR(SEARCH("%s",%s)))', |
|
3928
|
1
|
|
|
|
|
8
|
$param->{value}, $start_cell; |
|
3929
|
|
|
|
|
|
|
} |
|
3930
|
|
|
|
|
|
|
elsif ( $param->{criteria} eq 'notContains' ) { |
|
3931
|
1
|
|
|
|
|
3
|
$param->{type} = 'notContainsText'; |
|
3932
|
|
|
|
|
|
|
$param->{formula} = sprintf 'ISERROR(SEARCH("%s",%s))', |
|
3933
|
1
|
|
|
|
|
6
|
$param->{value}, $start_cell; |
|
3934
|
|
|
|
|
|
|
} |
|
3935
|
|
|
|
|
|
|
elsif ( $param->{criteria} eq 'beginsWith' ) { |
|
3936
|
3
|
|
|
|
|
8
|
$param->{type} = 'beginsWith'; |
|
3937
|
|
|
|
|
|
|
$param->{formula} = sprintf 'LEFT(%s,%d)="%s"', |
|
3938
|
3
|
|
|
|
|
15
|
$start_cell, length( $param->{value} ), $param->{value}; |
|
3939
|
|
|
|
|
|
|
} |
|
3940
|
|
|
|
|
|
|
elsif ( $param->{criteria} eq 'endsWith' ) { |
|
3941
|
3
|
|
|
|
|
6
|
$param->{type} = 'endsWith'; |
|
3942
|
|
|
|
|
|
|
$param->{formula} = sprintf 'RIGHT(%s,%d)="%s"', |
|
3943
|
3
|
|
|
|
|
14
|
$start_cell, length( $param->{value} ), $param->{value}; |
|
3944
|
|
|
|
|
|
|
} |
|
3945
|
|
|
|
|
|
|
else { |
|
3946
|
0
|
|
|
|
|
0
|
carp "Invalid text criteria '$param->{criteria}' " |
|
3947
|
|
|
|
|
|
|
. "in conditional_formatting()"; |
|
3948
|
|
|
|
|
|
|
} |
|
3949
|
|
|
|
|
|
|
} |
|
3950
|
|
|
|
|
|
|
|
|
3951
|
|
|
|
|
|
|
# Special handling of time time_period criteria. |
|
3952
|
149
|
100
|
|
|
|
404
|
if ( $param->{type} eq 'timePeriod' ) { |
|
3953
|
|
|
|
|
|
|
|
|
3954
|
10
|
100
|
|
|
|
71
|
if ( $param->{criteria} eq 'yesterday' ) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
3955
|
1
|
|
|
|
|
7
|
$param->{formula} = sprintf 'FLOOR(%s,1)=TODAY()-1', $start_cell; |
|
3956
|
|
|
|
|
|
|
} |
|
3957
|
|
|
|
|
|
|
elsif ( $param->{criteria} eq 'today' ) { |
|
3958
|
1
|
|
|
|
|
6
|
$param->{formula} = sprintf 'FLOOR(%s,1)=TODAY()', $start_cell; |
|
3959
|
|
|
|
|
|
|
} |
|
3960
|
|
|
|
|
|
|
elsif ( $param->{criteria} eq 'tomorrow' ) { |
|
3961
|
1
|
|
|
|
|
7
|
$param->{formula} = sprintf 'FLOOR(%s,1)=TODAY()+1', $start_cell; |
|
3962
|
|
|
|
|
|
|
} |
|
3963
|
|
|
|
|
|
|
elsif ( $param->{criteria} eq 'last7Days' ) { |
|
3964
|
|
|
|
|
|
|
$param->{formula} = |
|
3965
|
1
|
|
|
|
|
6
|
sprintf 'AND(TODAY()-FLOOR(%s,1)<=6,FLOOR(%s,1)<=TODAY())', |
|
3966
|
|
|
|
|
|
|
$start_cell, $start_cell; |
|
3967
|
|
|
|
|
|
|
} |
|
3968
|
|
|
|
|
|
|
elsif ( $param->{criteria} eq 'lastWeek' ) { |
|
3969
|
|
|
|
|
|
|
$param->{formula} = |
|
3970
|
1
|
|
|
|
|
6
|
sprintf 'AND(TODAY()-ROUNDDOWN(%s,0)>=(WEEKDAY(TODAY())),' |
|
3971
|
|
|
|
|
|
|
. 'TODAY()-ROUNDDOWN(%s,0)<(WEEKDAY(TODAY())+7))', |
|
3972
|
|
|
|
|
|
|
$start_cell, $start_cell; |
|
3973
|
|
|
|
|
|
|
} |
|
3974
|
|
|
|
|
|
|
elsif ( $param->{criteria} eq 'thisWeek' ) { |
|
3975
|
|
|
|
|
|
|
$param->{formula} = |
|
3976
|
1
|
|
|
|
|
6
|
sprintf 'AND(TODAY()-ROUNDDOWN(%s,0)<=WEEKDAY(TODAY())-1,' |
|
3977
|
|
|
|
|
|
|
. 'ROUNDDOWN(%s,0)-TODAY()<=7-WEEKDAY(TODAY()))', |
|
3978
|
|
|
|
|
|
|
$start_cell, $start_cell; |
|
3979
|
|
|
|
|
|
|
} |
|
3980
|
|
|
|
|
|
|
elsif ( $param->{criteria} eq 'nextWeek' ) { |
|
3981
|
|
|
|
|
|
|
$param->{formula} = |
|
3982
|
1
|
|
|
|
|
6
|
sprintf 'AND(ROUNDDOWN(%s,0)-TODAY()>(7-WEEKDAY(TODAY())),' |
|
3983
|
|
|
|
|
|
|
. 'ROUNDDOWN(%s,0)-TODAY()<(15-WEEKDAY(TODAY())))', |
|
3984
|
|
|
|
|
|
|
$start_cell, $start_cell; |
|
3985
|
|
|
|
|
|
|
} |
|
3986
|
|
|
|
|
|
|
elsif ( $param->{criteria} eq 'lastMonth' ) { |
|
3987
|
|
|
|
|
|
|
$param->{formula} = |
|
3988
|
1
|
|
|
|
|
8
|
sprintf |
|
3989
|
|
|
|
|
|
|
'AND(MONTH(%s)=MONTH(TODAY())-1,OR(YEAR(%s)=YEAR(TODAY()),' |
|
3990
|
|
|
|
|
|
|
. 'AND(MONTH(%s)=1,YEAR(A1)=YEAR(TODAY())-1)))', |
|
3991
|
|
|
|
|
|
|
$start_cell, $start_cell, $start_cell; |
|
3992
|
|
|
|
|
|
|
} |
|
3993
|
|
|
|
|
|
|
elsif ( $param->{criteria} eq 'thisMonth' ) { |
|
3994
|
|
|
|
|
|
|
$param->{formula} = |
|
3995
|
1
|
|
|
|
|
6
|
sprintf 'AND(MONTH(%s)=MONTH(TODAY()),YEAR(%s)=YEAR(TODAY()))', |
|
3996
|
|
|
|
|
|
|
$start_cell, $start_cell; |
|
3997
|
|
|
|
|
|
|
} |
|
3998
|
|
|
|
|
|
|
elsif ( $param->{criteria} eq 'nextMonth' ) { |
|
3999
|
|
|
|
|
|
|
$param->{formula} = |
|
4000
|
1
|
|
|
|
|
7
|
sprintf |
|
4001
|
|
|
|
|
|
|
'AND(MONTH(%s)=MONTH(TODAY())+1,OR(YEAR(%s)=YEAR(TODAY()),' |
|
4002
|
|
|
|
|
|
|
. 'AND(MONTH(%s)=12,YEAR(%s)=YEAR(TODAY())+1)))', |
|
4003
|
|
|
|
|
|
|
$start_cell, $start_cell, $start_cell, $start_cell; |
|
4004
|
|
|
|
|
|
|
} |
|
4005
|
|
|
|
|
|
|
else { |
|
4006
|
0
|
|
|
|
|
0
|
carp "Invalid time_period criteria '$param->{criteria}' " |
|
4007
|
|
|
|
|
|
|
. "in conditional_formatting()"; |
|
4008
|
|
|
|
|
|
|
} |
|
4009
|
|
|
|
|
|
|
} |
|
4010
|
|
|
|
|
|
|
|
|
4011
|
|
|
|
|
|
|
|
|
4012
|
|
|
|
|
|
|
# Special handling of blanks/error types. |
|
4013
|
149
|
100
|
|
|
|
412
|
if ( $param->{type} eq 'containsBlanks' ) { |
|
4014
|
1
|
|
|
|
|
7
|
$param->{formula} = sprintf 'LEN(TRIM(%s))=0', $start_cell; |
|
4015
|
|
|
|
|
|
|
} |
|
4016
|
|
|
|
|
|
|
|
|
4017
|
149
|
100
|
|
|
|
408
|
if ( $param->{type} eq 'notContainsBlanks' ) { |
|
4018
|
1
|
|
|
|
|
6
|
$param->{formula} = sprintf 'LEN(TRIM(%s))>0', $start_cell; |
|
4019
|
|
|
|
|
|
|
} |
|
4020
|
|
|
|
|
|
|
|
|
4021
|
149
|
100
|
|
|
|
376
|
if ( $param->{type} eq 'containsErrors' ) { |
|
4022
|
1
|
|
|
|
|
5
|
$param->{formula} = sprintf 'ISERROR(%s)', $start_cell; |
|
4023
|
|
|
|
|
|
|
} |
|
4024
|
|
|
|
|
|
|
|
|
4025
|
149
|
100
|
|
|
|
413
|
if ( $param->{type} eq 'notContainsErrors' ) { |
|
4026
|
1
|
|
|
|
|
5
|
$param->{formula} = sprintf 'NOT(ISERROR(%s))', $start_cell; |
|
4027
|
|
|
|
|
|
|
} |
|
4028
|
|
|
|
|
|
|
|
|
4029
|
|
|
|
|
|
|
|
|
4030
|
|
|
|
|
|
|
# Special handling for 2 color scale. |
|
4031
|
149
|
100
|
|
|
|
411
|
if ( $param->{type} eq '2_color_scale' ) { |
|
4032
|
1
|
|
|
|
|
2
|
$param->{type} = 'colorScale'; |
|
4033
|
|
|
|
|
|
|
|
|
4034
|
|
|
|
|
|
|
# Color scales don't use any additional formatting. |
|
4035
|
1
|
|
|
|
|
2
|
$param->{format} = undef; |
|
4036
|
|
|
|
|
|
|
|
|
4037
|
|
|
|
|
|
|
# Turn off 3 color parameters. |
|
4038
|
1
|
|
|
|
|
2
|
$param->{mid_type} = undef; |
|
4039
|
1
|
|
|
|
|
2
|
$param->{mid_color} = undef; |
|
4040
|
|
|
|
|
|
|
|
|
4041
|
1
|
|
50
|
|
|
4
|
$param->{min_type} ||= 'min'; |
|
4042
|
1
|
|
50
|
|
|
5
|
$param->{max_type} ||= 'max'; |
|
4043
|
1
|
|
50
|
|
|
5
|
$param->{min_value} ||= 0; |
|
4044
|
1
|
|
50
|
|
|
4
|
$param->{max_value} ||= 0; |
|
4045
|
1
|
|
50
|
|
|
5
|
$param->{min_color} ||= '#FF7128'; |
|
4046
|
1
|
|
50
|
|
|
5
|
$param->{max_color} ||= '#FFEF9C'; |
|
4047
|
|
|
|
|
|
|
|
|
4048
|
1
|
|
|
|
|
4
|
$param->{max_color} = $self->_get_palette_color( $param->{max_color} ); |
|
4049
|
1
|
|
|
|
|
3
|
$param->{min_color} = $self->_get_palette_color( $param->{min_color} ); |
|
4050
|
|
|
|
|
|
|
} |
|
4051
|
|
|
|
|
|
|
|
|
4052
|
|
|
|
|
|
|
|
|
4053
|
|
|
|
|
|
|
# Special handling for 3 color scale. |
|
4054
|
149
|
100
|
|
|
|
406
|
if ( $param->{type} eq '3_color_scale' ) { |
|
4055
|
4
|
|
|
|
|
13
|
$param->{type} = 'colorScale'; |
|
4056
|
|
|
|
|
|
|
|
|
4057
|
|
|
|
|
|
|
# Color scales don't use any additional formatting. |
|
4058
|
4
|
|
|
|
|
11
|
$param->{format} = undef; |
|
4059
|
|
|
|
|
|
|
|
|
4060
|
4
|
|
100
|
|
|
21
|
$param->{min_type} ||= 'min'; |
|
4061
|
4
|
|
100
|
|
|
24
|
$param->{mid_type} ||= 'percentile'; |
|
4062
|
4
|
|
100
|
|
|
28
|
$param->{max_type} ||= 'max'; |
|
4063
|
4
|
|
100
|
|
|
28
|
$param->{min_value} ||= 0; |
|
4064
|
4
|
100
|
|
|
|
22
|
$param->{mid_value} = 50 unless defined $param->{mid_value}; |
|
4065
|
4
|
|
100
|
|
|
35
|
$param->{max_value} ||= 0; |
|
4066
|
4
|
|
100
|
|
|
26
|
$param->{min_color} ||= '#F8696B'; |
|
4067
|
4
|
|
100
|
|
|
23
|
$param->{mid_color} ||= '#FFEB84'; |
|
4068
|
4
|
|
100
|
|
|
19
|
$param->{max_color} ||= '#63BE7B'; |
|
4069
|
|
|
|
|
|
|
|
|
4070
|
4
|
|
|
|
|
20
|
$param->{max_color} = $self->_get_palette_color( $param->{max_color} ); |
|
4071
|
4
|
|
|
|
|
18
|
$param->{mid_color} = $self->_get_palette_color( $param->{mid_color} ); |
|
4072
|
4
|
|
|
|
|
24
|
$param->{min_color} = $self->_get_palette_color( $param->{min_color} ); |
|
4073
|
|
|
|
|
|
|
} |
|
4074
|
|
|
|
|
|
|
|
|
4075
|
|
|
|
|
|
|
|
|
4076
|
|
|
|
|
|
|
# Special handling for data bar. |
|
4077
|
149
|
100
|
|
|
|
490
|
if ( $param->{type} eq 'dataBar' ) { |
|
4078
|
|
|
|
|
|
|
|
|
4079
|
|
|
|
|
|
|
# Excel 2007 data bars don't use any additional formatting. |
|
4080
|
29
|
|
|
|
|
75
|
$param->{format} = undef; |
|
4081
|
|
|
|
|
|
|
|
|
4082
|
29
|
100
|
|
|
|
113
|
if ( !defined $param->{min_type} ) { |
|
4083
|
22
|
|
|
|
|
61
|
$param->{min_type} = 'min'; |
|
4084
|
22
|
|
|
|
|
59
|
$param->{_x14_min_type} = 'autoMin'; |
|
4085
|
|
|
|
|
|
|
} |
|
4086
|
|
|
|
|
|
|
else { |
|
4087
|
7
|
|
|
|
|
25
|
$param->{_x14_min_type} = $param->{min_type}; |
|
4088
|
|
|
|
|
|
|
} |
|
4089
|
|
|
|
|
|
|
|
|
4090
|
29
|
100
|
|
|
|
89
|
if ( !defined $param->{max_type} ) { |
|
4091
|
23
|
|
|
|
|
69
|
$param->{max_type} = 'max'; |
|
4092
|
23
|
|
|
|
|
70
|
$param->{_x14_max_type} = 'autoMax'; |
|
4093
|
|
|
|
|
|
|
} |
|
4094
|
|
|
|
|
|
|
else { |
|
4095
|
6
|
|
|
|
|
13
|
$param->{_x14_max_type} = $param->{max_type}; |
|
4096
|
|
|
|
|
|
|
} |
|
4097
|
|
|
|
|
|
|
|
|
4098
|
29
|
|
100
|
|
|
149
|
$param->{min_value} ||= 0; |
|
4099
|
29
|
|
100
|
|
|
131
|
$param->{max_value} ||= 0; |
|
4100
|
29
|
|
100
|
|
|
127
|
$param->{bar_color} ||= '#638EC6'; |
|
4101
|
29
|
|
66
|
|
|
163
|
$param->{bar_border_color} ||= $param->{bar_color}; |
|
4102
|
29
|
|
100
|
|
|
152
|
$param->{bar_only} ||= 0; |
|
4103
|
29
|
|
100
|
|
|
178
|
$param->{bar_no_border} ||= 0; |
|
4104
|
29
|
|
100
|
|
|
149
|
$param->{bar_solid} ||= 0; |
|
4105
|
29
|
|
100
|
|
|
154
|
$param->{bar_direction} ||= ''; |
|
4106
|
29
|
|
100
|
|
|
163
|
$param->{bar_negative_color} ||= '#FF0000'; |
|
4107
|
29
|
|
100
|
|
|
144
|
$param->{bar_negative_border_color} ||= '#FF0000'; |
|
4108
|
29
|
|
100
|
|
|
149
|
$param->{bar_negative_color_same} ||= 0; |
|
4109
|
29
|
|
100
|
|
|
134
|
$param->{bar_negative_border_color_same} ||= 0; |
|
4110
|
29
|
|
100
|
|
|
139
|
$param->{bar_axis_position} ||= ''; |
|
4111
|
29
|
|
100
|
|
|
147
|
$param->{bar_axis_color} ||= '#000000'; |
|
4112
|
|
|
|
|
|
|
|
|
4113
|
|
|
|
|
|
|
$param->{bar_color} = |
|
4114
|
29
|
|
|
|
|
110
|
$self->_get_palette_color( $param->{bar_color} ); |
|
4115
|
|
|
|
|
|
|
|
|
4116
|
|
|
|
|
|
|
$param->{bar_border_color} = |
|
4117
|
29
|
|
|
|
|
109
|
$self->_get_palette_color( $param->{bar_border_color} ); |
|
4118
|
|
|
|
|
|
|
|
|
4119
|
|
|
|
|
|
|
$param->{bar_negative_color} = |
|
4120
|
29
|
|
|
|
|
89
|
$self->_get_palette_color( $param->{bar_negative_color} ); |
|
4121
|
|
|
|
|
|
|
|
|
4122
|
|
|
|
|
|
|
$param->{bar_negative_border_color} = |
|
4123
|
29
|
|
|
|
|
80
|
$self->_get_palette_color( $param->{bar_negative_border_color} ); |
|
4124
|
|
|
|
|
|
|
|
|
4125
|
|
|
|
|
|
|
$param->{bar_axis_color} = |
|
4126
|
29
|
|
|
|
|
97
|
$self->_get_palette_color( $param->{bar_axis_color} ); |
|
4127
|
|
|
|
|
|
|
|
|
4128
|
|
|
|
|
|
|
} |
|
4129
|
|
|
|
|
|
|
|
|
4130
|
|
|
|
|
|
|
# Adjust for 2010 style data_bar parameters. |
|
4131
|
149
|
100
|
|
|
|
446
|
if ( $param->{_is_data_bar_2010} ) { |
|
4132
|
|
|
|
|
|
|
|
|
4133
|
25
|
|
|
|
|
58
|
$self->{_excel_version} = 2010; |
|
4134
|
|
|
|
|
|
|
|
|
4135
|
25
|
100
|
66
|
|
|
126
|
if ( $param->{min_type} eq 'min' && $param->{min_value} == 0 ) { |
|
4136
|
20
|
|
|
|
|
62
|
$param->{min_value} = undef; |
|
4137
|
|
|
|
|
|
|
} |
|
4138
|
|
|
|
|
|
|
|
|
4139
|
25
|
100
|
66
|
|
|
134
|
if ( $param->{max_type} eq 'max' && $param->{max_value} == 0 ) { |
|
4140
|
21
|
|
|
|
|
43
|
$param->{max_value} = undef; |
|
4141
|
|
|
|
|
|
|
} |
|
4142
|
|
|
|
|
|
|
|
|
4143
|
|
|
|
|
|
|
# Store range for Excel 2010 data bars. |
|
4144
|
25
|
|
|
|
|
68
|
$param->{_range} = $range; |
|
4145
|
|
|
|
|
|
|
} |
|
4146
|
|
|
|
|
|
|
|
|
4147
|
|
|
|
|
|
|
# Strip the leading = from formulas. |
|
4148
|
149
|
100
|
|
|
|
441
|
$param->{min_value} =~ s/^=// if defined $param->{min_value}; |
|
4149
|
149
|
100
|
|
|
|
432
|
$param->{mid_value} =~ s/^=// if defined $param->{mid_value}; |
|
4150
|
149
|
100
|
|
|
|
417
|
$param->{max_value} =~ s/^=// if defined $param->{max_value}; |
|
4151
|
|
|
|
|
|
|
|
|
4152
|
|
|
|
|
|
|
# Store the validation information until we close the worksheet. |
|
4153
|
149
|
|
|
|
|
265
|
push @{ $self->{_cond_formats}->{$range} }, $param; |
|
|
149
|
|
|
|
|
2341
|
|
|
4154
|
|
|
|
|
|
|
} |
|
4155
|
|
|
|
|
|
|
|
|
4156
|
|
|
|
|
|
|
|
|
4157
|
|
|
|
|
|
|
############################################################################### |
|
4158
|
|
|
|
|
|
|
# |
|
4159
|
|
|
|
|
|
|
# Set the sub-properites for icons. |
|
4160
|
|
|
|
|
|
|
# |
|
4161
|
|
|
|
|
|
|
sub _set_icon_properties { |
|
4162
|
|
|
|
|
|
|
|
|
4163
|
37
|
|
|
37
|
|
59
|
my $self = shift; |
|
4164
|
37
|
|
|
|
|
50
|
my $total_icons = shift; |
|
4165
|
37
|
|
|
|
|
401
|
my $user_props = shift; |
|
4166
|
37
|
|
|
|
|
63
|
my $props = []; |
|
4167
|
|
|
|
|
|
|
|
|
4168
|
|
|
|
|
|
|
# Set the default icon properties. |
|
4169
|
37
|
|
|
|
|
102
|
for ( 0 .. $total_icons - 1 ) { |
|
4170
|
138
|
|
|
|
|
375
|
push @$props, |
|
4171
|
|
|
|
|
|
|
{ |
|
4172
|
|
|
|
|
|
|
criteria => 0, |
|
4173
|
|
|
|
|
|
|
value => 0, |
|
4174
|
|
|
|
|
|
|
type => 'percent' |
|
4175
|
|
|
|
|
|
|
}; |
|
4176
|
|
|
|
|
|
|
} |
|
4177
|
|
|
|
|
|
|
|
|
4178
|
|
|
|
|
|
|
# Set the default icon values based on the number of icons. |
|
4179
|
37
|
100
|
|
|
|
89
|
if ( $total_icons == 3 ) { |
|
4180
|
18
|
|
|
|
|
35
|
$props->[0]->{value} = 67; |
|
4181
|
18
|
|
|
|
|
33
|
$props->[1]->{value} = 33; |
|
4182
|
|
|
|
|
|
|
} |
|
4183
|
|
|
|
|
|
|
|
|
4184
|
37
|
100
|
|
|
|
73
|
if ( $total_icons == 4 ) { |
|
4185
|
11
|
|
|
|
|
21
|
$props->[0]->{value} = 75; |
|
4186
|
11
|
|
|
|
|
19
|
$props->[1]->{value} = 50; |
|
4187
|
11
|
|
|
|
|
19
|
$props->[2]->{value} = 25; |
|
4188
|
|
|
|
|
|
|
} |
|
4189
|
|
|
|
|
|
|
|
|
4190
|
37
|
100
|
|
|
|
76
|
if ( $total_icons == 5 ) { |
|
4191
|
8
|
|
|
|
|
13
|
$props->[0]->{value} = 80; |
|
4192
|
8
|
|
|
|
|
16
|
$props->[1]->{value} = 60; |
|
4193
|
8
|
|
|
|
|
12
|
$props->[2]->{value} = 40; |
|
4194
|
8
|
|
|
|
|
14
|
$props->[3]->{value} = 20; |
|
4195
|
|
|
|
|
|
|
} |
|
4196
|
|
|
|
|
|
|
|
|
4197
|
|
|
|
|
|
|
# Overwrite default properties with user defined properties. |
|
4198
|
37
|
100
|
|
|
|
74
|
if ( defined $user_props ) { |
|
4199
|
|
|
|
|
|
|
|
|
4200
|
|
|
|
|
|
|
# Ensure we don't set user properties for lowest icon. |
|
4201
|
13
|
|
|
|
|
23
|
my $max_data = @$user_props; |
|
4202
|
13
|
100
|
|
|
|
28
|
if ( $max_data >= $total_icons ) { |
|
4203
|
2
|
|
|
|
|
4
|
$max_data = $total_icons -1; |
|
4204
|
|
|
|
|
|
|
} |
|
4205
|
|
|
|
|
|
|
|
|
4206
|
13
|
|
|
|
|
30
|
for my $i ( 0 .. $max_data - 1 ) { |
|
4207
|
|
|
|
|
|
|
|
|
4208
|
|
|
|
|
|
|
# Set the user defined 'value' property. |
|
4209
|
30
|
100
|
|
|
|
79
|
if ( defined $user_props->[$i]->{value} ) { |
|
4210
|
24
|
|
|
|
|
47
|
$props->[$i]->{value} = $user_props->[$i]->{value}; |
|
4211
|
24
|
|
|
|
|
57
|
$props->[$i]->{value} =~ s/^=//; |
|
4212
|
|
|
|
|
|
|
} |
|
4213
|
|
|
|
|
|
|
|
|
4214
|
|
|
|
|
|
|
# Set the user defined 'type' property. |
|
4215
|
30
|
100
|
|
|
|
67
|
if ( defined $user_props->[$i]->{type} ) { |
|
4216
|
|
|
|
|
|
|
|
|
4217
|
14
|
|
|
|
|
25
|
my $type = $user_props->[$i]->{type}; |
|
4218
|
|
|
|
|
|
|
|
|
4219
|
14
|
50
|
100
|
|
|
86
|
if ( $type ne 'percent' |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
4220
|
|
|
|
|
|
|
&& $type ne 'percentile' |
|
4221
|
|
|
|
|
|
|
&& $type ne 'number' |
|
4222
|
|
|
|
|
|
|
&& $type ne 'formula' ) |
|
4223
|
|
|
|
|
|
|
{ |
|
4224
|
0
|
|
|
|
|
0
|
carp "Unknown icon property type '$props->{type}' for sub-" |
|
4225
|
|
|
|
|
|
|
. "property 'type' in conditional_formatting()"; |
|
4226
|
|
|
|
|
|
|
} |
|
4227
|
|
|
|
|
|
|
else { |
|
4228
|
14
|
|
|
|
|
25
|
$props->[$i]->{type} = $type; |
|
4229
|
|
|
|
|
|
|
|
|
4230
|
14
|
100
|
|
|
|
34
|
if ( $props->[$i]->{type} eq 'number' ) { |
|
4231
|
2
|
|
|
|
|
5
|
$props->[$i]->{type} = 'num'; |
|
4232
|
|
|
|
|
|
|
} |
|
4233
|
|
|
|
|
|
|
} |
|
4234
|
|
|
|
|
|
|
} |
|
4235
|
|
|
|
|
|
|
|
|
4236
|
|
|
|
|
|
|
# Set the user defined 'criteria' property. |
|
4237
|
30
|
100
|
100
|
|
|
98
|
if ( defined $user_props->[$i]->{criteria} |
|
4238
|
|
|
|
|
|
|
&& $user_props->[$i]->{criteria} eq '>' ) |
|
4239
|
|
|
|
|
|
|
{ |
|
4240
|
7
|
|
|
|
|
12
|
$props->[$i]->{criteria} = 1; |
|
4241
|
|
|
|
|
|
|
} |
|
4242
|
|
|
|
|
|
|
|
|
4243
|
|
|
|
|
|
|
} |
|
4244
|
|
|
|
|
|
|
|
|
4245
|
|
|
|
|
|
|
} |
|
4246
|
|
|
|
|
|
|
|
|
4247
|
37
|
|
|
|
|
79
|
return $props; |
|
4248
|
|
|
|
|
|
|
} |
|
4249
|
|
|
|
|
|
|
|
|
4250
|
|
|
|
|
|
|
|
|
4251
|
|
|
|
|
|
|
############################################################################### |
|
4252
|
|
|
|
|
|
|
# |
|
4253
|
|
|
|
|
|
|
# add_table() |
|
4254
|
|
|
|
|
|
|
# |
|
4255
|
|
|
|
|
|
|
# Add an Excel table to a worksheet. |
|
4256
|
|
|
|
|
|
|
# |
|
4257
|
|
|
|
|
|
|
sub add_table { |
|
4258
|
|
|
|
|
|
|
|
|
4259
|
48
|
|
|
48
|
0
|
486
|
my $self = shift; |
|
4260
|
48
|
|
|
|
|
155
|
my $user_range = ''; |
|
4261
|
48
|
|
|
|
|
124
|
my %table; |
|
4262
|
|
|
|
|
|
|
my @col_formats; |
|
4263
|
|
|
|
|
|
|
|
|
4264
|
|
|
|
|
|
|
# We would need to order the write statements very carefully within this |
|
4265
|
|
|
|
|
|
|
# function to support optimisation mode. Disable add_table() when it is |
|
4266
|
|
|
|
|
|
|
# on for now. |
|
4267
|
48
|
50
|
|
|
|
251
|
if ( $self->{_optimization} == 1 ) { |
|
4268
|
0
|
|
|
|
|
0
|
carp "add_table() isn't supported when set_optimization() is on"; |
|
4269
|
0
|
|
|
|
|
0
|
return -1; |
|
4270
|
|
|
|
|
|
|
} |
|
4271
|
|
|
|
|
|
|
|
|
4272
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
4273
|
48
|
50
|
33
|
|
|
455
|
if ( @_ && $_[0] =~ /^\D/ ) { |
|
4274
|
48
|
|
|
|
|
229
|
@_ = $self->_substitute_cellref( @_ ); |
|
4275
|
|
|
|
|
|
|
} |
|
4276
|
|
|
|
|
|
|
|
|
4277
|
|
|
|
|
|
|
# Check for a valid number of args. |
|
4278
|
48
|
50
|
|
|
|
225
|
if ( @_ < 4 ) { |
|
4279
|
0
|
|
|
|
|
0
|
carp "Not enough parameters to add_table()"; |
|
4280
|
0
|
|
|
|
|
0
|
return -1; |
|
4281
|
|
|
|
|
|
|
} |
|
4282
|
|
|
|
|
|
|
|
|
4283
|
48
|
|
|
|
|
167
|
my ( $row1, $col1, $row2, $col2 ) = @_; |
|
4284
|
|
|
|
|
|
|
|
|
4285
|
|
|
|
|
|
|
# Check that row and col are valid without storing the values. |
|
4286
|
48
|
50
|
|
|
|
197
|
return -2 if $self->_check_dimensions( $row1, $col1, 1, 1 ); |
|
4287
|
48
|
50
|
|
|
|
201
|
return -2 if $self->_check_dimensions( $row2, $col2, 1, 1 ); |
|
4288
|
|
|
|
|
|
|
|
|
4289
|
|
|
|
|
|
|
|
|
4290
|
|
|
|
|
|
|
# The final hashref contains the validation parameters. |
|
4291
|
48
|
|
100
|
|
|
271
|
my $param = $_[4] || {}; |
|
4292
|
|
|
|
|
|
|
|
|
4293
|
|
|
|
|
|
|
# Check that the last parameter is a hash list. |
|
4294
|
48
|
50
|
|
|
|
399
|
if ( ref $param ne 'HASH' ) { |
|
4295
|
0
|
|
|
|
|
0
|
carp "Last parameter '$param' in add_table() must be a hash ref"; |
|
4296
|
0
|
|
|
|
|
0
|
return -3; |
|
4297
|
|
|
|
|
|
|
} |
|
4298
|
|
|
|
|
|
|
|
|
4299
|
|
|
|
|
|
|
|
|
4300
|
|
|
|
|
|
|
# List of valid input parameters. |
|
4301
|
48
|
|
|
|
|
925
|
my %valid_parameter = ( |
|
4302
|
|
|
|
|
|
|
autofilter => 1, |
|
4303
|
|
|
|
|
|
|
banded_columns => 1, |
|
4304
|
|
|
|
|
|
|
banded_rows => 1, |
|
4305
|
|
|
|
|
|
|
columns => 1, |
|
4306
|
|
|
|
|
|
|
data => 1, |
|
4307
|
|
|
|
|
|
|
first_column => 1, |
|
4308
|
|
|
|
|
|
|
header_row => 1, |
|
4309
|
|
|
|
|
|
|
last_column => 1, |
|
4310
|
|
|
|
|
|
|
name => 1, |
|
4311
|
|
|
|
|
|
|
style => 1, |
|
4312
|
|
|
|
|
|
|
total_row => 1, |
|
4313
|
|
|
|
|
|
|
); |
|
4314
|
|
|
|
|
|
|
|
|
4315
|
|
|
|
|
|
|
# Check for valid input parameters. |
|
4316
|
48
|
|
|
|
|
395
|
for my $param_key ( keys %$param ) { |
|
4317
|
44
|
50
|
|
|
|
183
|
if ( not exists $valid_parameter{$param_key} ) { |
|
4318
|
0
|
|
|
|
|
0
|
carp "Unknown parameter '$param_key' in add_table()"; |
|
4319
|
0
|
|
|
|
|
0
|
return -3; |
|
4320
|
|
|
|
|
|
|
} |
|
4321
|
|
|
|
|
|
|
} |
|
4322
|
|
|
|
|
|
|
|
|
4323
|
|
|
|
|
|
|
# Turn on Excel's defaults. |
|
4324
|
48
|
100
|
|
|
|
995
|
$param->{banded_rows} = 1 if !defined $param->{banded_rows}; |
|
4325
|
48
|
100
|
|
|
|
1297
|
$param->{header_row} = 1 if !defined $param->{header_row}; |
|
4326
|
48
|
100
|
|
|
|
670
|
$param->{autofilter} = 1 if !defined $param->{autofilter}; |
|
4327
|
|
|
|
|
|
|
|
|
4328
|
|
|
|
|
|
|
# Set the table options. |
|
4329
|
48
|
100
|
|
|
|
210
|
$table{_show_first_col} = $param->{first_column} ? 1 : 0; |
|
4330
|
48
|
100
|
|
|
|
159
|
$table{_show_last_col} = $param->{last_column} ? 1 : 0; |
|
4331
|
48
|
100
|
|
|
|
169
|
$table{_show_row_stripes} = $param->{banded_rows} ? 1 : 0; |
|
4332
|
48
|
100
|
|
|
|
149
|
$table{_show_col_stripes} = $param->{banded_columns} ? 1 : 0; |
|
4333
|
48
|
100
|
|
|
|
163
|
$table{_header_row_count} = $param->{header_row} ? 1 : 0; |
|
4334
|
48
|
100
|
|
|
|
144
|
$table{_totals_row_shown} = $param->{total_row} ? 1 : 0; |
|
4335
|
|
|
|
|
|
|
|
|
4336
|
|
|
|
|
|
|
|
|
4337
|
|
|
|
|
|
|
# Set the table name. |
|
4338
|
48
|
100
|
|
|
|
163
|
if ( defined $param->{name} ) { |
|
4339
|
1
|
|
|
|
|
3
|
my $name = $param->{name}; |
|
4340
|
|
|
|
|
|
|
|
|
4341
|
|
|
|
|
|
|
# Warn if the name contains invalid chars as defined by Excel help. |
|
4342
|
1
|
50
|
33
|
|
|
11
|
if ( $name !~ m/^[\w\\][\w\\.]*$/ || $name =~ m/^\d/ ) { |
|
4343
|
0
|
|
|
|
|
0
|
carp "Invalid character in name '$name' used in add_table()"; |
|
4344
|
0
|
|
|
|
|
0
|
return -3; |
|
4345
|
|
|
|
|
|
|
} |
|
4346
|
|
|
|
|
|
|
|
|
4347
|
|
|
|
|
|
|
# Warn if the name looks like a cell name. |
|
4348
|
1
|
50
|
|
|
|
5
|
if ( $name =~ m/^[a-zA-Z][a-zA-Z]?[a-dA-D]?[0-9]+$/ ) { |
|
4349
|
0
|
|
|
|
|
0
|
carp "Invalid name '$name' looks like a cell name in add_table()"; |
|
4350
|
0
|
|
|
|
|
0
|
return -3; |
|
4351
|
|
|
|
|
|
|
} |
|
4352
|
|
|
|
|
|
|
|
|
4353
|
|
|
|
|
|
|
# Warn if the name looks like a R1C1. |
|
4354
|
1
|
50
|
33
|
|
|
16
|
if ( $name =~ m/^[rcRC]$/ || $name =~ m/^[rcRC]\d+[rcRC]\d+$/ ) { |
|
4355
|
0
|
|
|
|
|
0
|
carp "Invalid name '$name' like a RC cell ref in add_table()"; |
|
4356
|
0
|
|
|
|
|
0
|
return -3; |
|
4357
|
|
|
|
|
|
|
} |
|
4358
|
|
|
|
|
|
|
|
|
4359
|
1
|
|
|
|
|
6
|
$table{_name} = $param->{name}; |
|
4360
|
|
|
|
|
|
|
} |
|
4361
|
|
|
|
|
|
|
|
|
4362
|
|
|
|
|
|
|
# Set the table style. |
|
4363
|
48
|
100
|
|
|
|
166
|
if ( defined $param->{style} ) { |
|
4364
|
3
|
|
|
|
|
7
|
$table{_style} = $param->{style}; |
|
4365
|
|
|
|
|
|
|
|
|
4366
|
|
|
|
|
|
|
# Remove whitespace from style name. |
|
4367
|
3
|
|
|
|
|
19
|
$table{_style} =~ s/\s//g; |
|
4368
|
|
|
|
|
|
|
} |
|
4369
|
|
|
|
|
|
|
else { |
|
4370
|
45
|
|
|
|
|
126
|
$table{_style} = "TableStyleMedium9"; |
|
4371
|
|
|
|
|
|
|
} |
|
4372
|
|
|
|
|
|
|
|
|
4373
|
|
|
|
|
|
|
|
|
4374
|
|
|
|
|
|
|
# Swap last row/col for first row/col as necessary. |
|
4375
|
48
|
50
|
|
|
|
180
|
if ( $row1 > $row2 ) { |
|
4376
|
0
|
|
|
|
|
0
|
( $row1, $row2 ) = ( $row2, $row1 ); |
|
4377
|
|
|
|
|
|
|
} |
|
4378
|
|
|
|
|
|
|
|
|
4379
|
48
|
50
|
|
|
|
165
|
if ( $col1 > $col2 ) { |
|
4380
|
0
|
|
|
|
|
0
|
( $col1, $col2 ) = ( $col2, $col1 ); |
|
4381
|
|
|
|
|
|
|
} |
|
4382
|
|
|
|
|
|
|
|
|
4383
|
|
|
|
|
|
|
|
|
4384
|
|
|
|
|
|
|
# Set the data range rows (without the header and footer). |
|
4385
|
48
|
|
|
|
|
103
|
my $first_data_row = $row1; |
|
4386
|
48
|
|
|
|
|
89
|
my $last_data_row = $row2; |
|
4387
|
48
|
100
|
|
|
|
173
|
$first_data_row++ if $param->{header_row}; |
|
4388
|
48
|
100
|
|
|
|
168
|
$last_data_row-- if $param->{total_row}; |
|
4389
|
|
|
|
|
|
|
|
|
4390
|
|
|
|
|
|
|
|
|
4391
|
|
|
|
|
|
|
# Set the table and autofilter ranges. |
|
4392
|
48
|
|
|
|
|
263
|
$table{_range} = xl_range( $row1, $row2, $col1, $col2 ); |
|
4393
|
48
|
|
|
|
|
216
|
$table{_a_range} = xl_range( $row1, $last_data_row, $col1, $col2 ); |
|
4394
|
|
|
|
|
|
|
|
|
4395
|
|
|
|
|
|
|
|
|
4396
|
|
|
|
|
|
|
# If the header row if off the default is to turn autofilter off. |
|
4397
|
48
|
100
|
|
|
|
190
|
if ( !$param->{header_row} ) { |
|
4398
|
3
|
|
|
|
|
9
|
$param->{autofilter} = 0; |
|
4399
|
|
|
|
|
|
|
} |
|
4400
|
|
|
|
|
|
|
|
|
4401
|
|
|
|
|
|
|
# Set the autofilter range. |
|
4402
|
48
|
100
|
|
|
|
146
|
if ( $param->{autofilter} ) { |
|
4403
|
44
|
|
|
|
|
137
|
$table{_autofilter} = $table{_a_range}; |
|
4404
|
|
|
|
|
|
|
} |
|
4405
|
|
|
|
|
|
|
|
|
4406
|
|
|
|
|
|
|
# Add the table columns. |
|
4407
|
48
|
|
|
|
|
101
|
my %seen_names; |
|
4408
|
48
|
|
|
|
|
93
|
my $col_id = 1; |
|
4409
|
48
|
|
|
|
|
157
|
for my $col_num ( $col1 .. $col2 ) { |
|
4410
|
|
|
|
|
|
|
|
|
4411
|
|
|
|
|
|
|
# Set up the default column data. |
|
4412
|
212
|
|
|
|
|
1139
|
my $col_data = { |
|
4413
|
|
|
|
|
|
|
_id => $col_id, |
|
4414
|
|
|
|
|
|
|
_name => 'Column' . $col_id, |
|
4415
|
|
|
|
|
|
|
_total_string => '', |
|
4416
|
|
|
|
|
|
|
_total_function => '', |
|
4417
|
|
|
|
|
|
|
_formula => '', |
|
4418
|
|
|
|
|
|
|
_format => undef, |
|
4419
|
|
|
|
|
|
|
_name_format => undef, |
|
4420
|
|
|
|
|
|
|
}; |
|
4421
|
|
|
|
|
|
|
|
|
4422
|
|
|
|
|
|
|
# Overwrite the defaults with any use defined values. |
|
4423
|
212
|
100
|
|
|
|
538
|
if ( $param->{columns} ) { |
|
4424
|
|
|
|
|
|
|
|
|
4425
|
|
|
|
|
|
|
# Check if there are user defined values for this column. |
|
4426
|
85
|
100
|
|
|
|
248
|
if ( my $user_data = $param->{columns}->[ $col_id - 1 ] ) { |
|
4427
|
|
|
|
|
|
|
|
|
4428
|
|
|
|
|
|
|
# Map user defined values to internal values. |
|
4429
|
|
|
|
|
|
|
$col_data->{_name} = $user_data->{header} |
|
4430
|
84
|
100
|
|
|
|
197
|
if $user_data->{header}; |
|
4431
|
|
|
|
|
|
|
|
|
4432
|
|
|
|
|
|
|
# Excel requires unique case insensitive header names. |
|
4433
|
84
|
|
|
|
|
152
|
my $name = $col_data->{_name}; |
|
4434
|
84
|
|
|
|
|
169
|
my $key = lc $name; |
|
4435
|
84
|
100
|
|
|
|
190
|
if (exists $seen_names{$key}) { |
|
4436
|
1
|
|
|
|
|
265
|
carp "add_table() contains duplicate name: '$name'"; |
|
4437
|
1
|
|
|
|
|
48
|
return -1; |
|
4438
|
|
|
|
|
|
|
} |
|
4439
|
|
|
|
|
|
|
else { |
|
4440
|
83
|
|
|
|
|
213
|
$seen_names{$key} = 1; |
|
4441
|
|
|
|
|
|
|
} |
|
4442
|
|
|
|
|
|
|
|
|
4443
|
|
|
|
|
|
|
# Get the header format if defined. |
|
4444
|
83
|
|
|
|
|
163
|
$col_data->{_name_format} = $user_data->{header_format}; |
|
4445
|
|
|
|
|
|
|
|
|
4446
|
|
|
|
|
|
|
# Handle the column formula. |
|
4447
|
83
|
100
|
|
|
|
184
|
if ( $user_data->{formula} ) { |
|
4448
|
3
|
|
|
|
|
28
|
my $formula = $user_data->{formula}; |
|
4449
|
|
|
|
|
|
|
|
|
4450
|
|
|
|
|
|
|
# Remove the leading = from formula. |
|
4451
|
3
|
|
|
|
|
15
|
$formula =~ s/^=//; |
|
4452
|
|
|
|
|
|
|
|
|
4453
|
|
|
|
|
|
|
# Covert Excel 2010 "@" ref to 2007 "#This Row". |
|
4454
|
3
|
|
|
|
|
8
|
$formula =~ s/@/[#This Row],/g; |
|
4455
|
|
|
|
|
|
|
|
|
4456
|
3
|
|
|
|
|
7
|
$col_data->{_formula} = $formula; |
|
4457
|
|
|
|
|
|
|
|
|
4458
|
3
|
|
|
|
|
12
|
for my $row ( $first_data_row .. $last_data_row ) { |
|
4459
|
|
|
|
|
|
|
$self->write_formula( $row, $col_num, $formula, |
|
4460
|
24
|
|
|
|
|
56
|
$user_data->{format} ); |
|
4461
|
|
|
|
|
|
|
} |
|
4462
|
|
|
|
|
|
|
} |
|
4463
|
|
|
|
|
|
|
|
|
4464
|
|
|
|
|
|
|
# Handle the function for the total row. |
|
4465
|
83
|
100
|
|
|
|
225
|
if ( $user_data->{total_function} ) { |
|
|
|
100
|
|
|
|
|
|
|
4466
|
40
|
|
|
|
|
81
|
my $function = $user_data->{total_function}; |
|
4467
|
|
|
|
|
|
|
|
|
4468
|
|
|
|
|
|
|
# Massage the function name. |
|
4469
|
40
|
|
|
|
|
74
|
$function = lc $function; |
|
4470
|
40
|
|
|
|
|
102
|
$function =~ s/_//g; |
|
4471
|
40
|
|
|
|
|
94
|
$function =~ s/\s//g; |
|
4472
|
|
|
|
|
|
|
|
|
4473
|
40
|
100
|
|
|
|
107
|
$function = 'countNums' if $function eq 'countnums'; |
|
4474
|
40
|
100
|
|
|
|
98
|
$function = 'stdDev' if $function eq 'stddev'; |
|
4475
|
|
|
|
|
|
|
|
|
4476
|
40
|
|
|
|
|
72
|
$col_data->{_total_function} = $function; |
|
4477
|
|
|
|
|
|
|
|
|
4478
|
|
|
|
|
|
|
my $formula = _table_function_to_formula( |
|
4479
|
|
|
|
|
|
|
$function, |
|
4480
|
|
|
|
|
|
|
$col_data->{_name} |
|
4481
|
|
|
|
|
|
|
|
|
4482
|
40
|
|
|
|
|
106
|
); |
|
4483
|
|
|
|
|
|
|
|
|
4484
|
40
|
|
100
|
|
|
331
|
my $value = $user_data->{total_value} || 0; |
|
4485
|
|
|
|
|
|
|
|
|
4486
|
|
|
|
|
|
|
$self->write_formula( $row2, $col_num, $formula, |
|
4487
|
40
|
|
|
|
|
151
|
$user_data->{format}, $value ); |
|
4488
|
|
|
|
|
|
|
|
|
4489
|
|
|
|
|
|
|
} |
|
4490
|
|
|
|
|
|
|
elsif ( $user_data->{total_string} ) { |
|
4491
|
|
|
|
|
|
|
|
|
4492
|
|
|
|
|
|
|
# Total label only (not a function). |
|
4493
|
9
|
|
|
|
|
30
|
my $total_string = $user_data->{total_string}; |
|
4494
|
9
|
|
|
|
|
28
|
$col_data->{_total_string} = $total_string; |
|
4495
|
|
|
|
|
|
|
|
|
4496
|
|
|
|
|
|
|
$self->write_string( $row2, $col_num, $total_string, |
|
4497
|
9
|
|
|
|
|
51
|
$user_data->{format} ); |
|
4498
|
|
|
|
|
|
|
} |
|
4499
|
|
|
|
|
|
|
|
|
4500
|
|
|
|
|
|
|
# Get the dxf format index. |
|
4501
|
83
|
100
|
66
|
|
|
342
|
if ( defined $user_data->{format} && ref $user_data->{format} ) |
|
4502
|
|
|
|
|
|
|
{ |
|
4503
|
|
|
|
|
|
|
$col_data->{_format} = |
|
4504
|
9
|
|
|
|
|
191
|
$user_data->{format}->get_dxf_index(); |
|
4505
|
|
|
|
|
|
|
} |
|
4506
|
|
|
|
|
|
|
|
|
4507
|
|
|
|
|
|
|
# Store the column format for writing the cell data. |
|
4508
|
|
|
|
|
|
|
# It doesn't matter if it is undefined. |
|
4509
|
83
|
|
|
|
|
225
|
$col_formats[ $col_id - 1 ] = $user_data->{format}; |
|
4510
|
|
|
|
|
|
|
} |
|
4511
|
|
|
|
|
|
|
} |
|
4512
|
|
|
|
|
|
|
|
|
4513
|
|
|
|
|
|
|
# Store the column data. |
|
4514
|
211
|
|
|
|
|
330
|
push @{ $table{_columns} }, $col_data; |
|
|
211
|
|
|
|
|
484
|
|
|
4515
|
|
|
|
|
|
|
|
|
4516
|
|
|
|
|
|
|
# Write the column headers to the worksheet. |
|
4517
|
211
|
100
|
|
|
|
504
|
if ( $param->{header_row} ) { |
|
4518
|
|
|
|
|
|
|
$self->write_string( $row1, $col_num, $col_data->{_name}, |
|
4519
|
201
|
|
|
|
|
574
|
$col_data->{_name_format} ); |
|
4520
|
|
|
|
|
|
|
} |
|
4521
|
|
|
|
|
|
|
|
|
4522
|
211
|
|
|
|
|
487
|
$col_id++; |
|
4523
|
|
|
|
|
|
|
} # Table columns. |
|
4524
|
|
|
|
|
|
|
|
|
4525
|
|
|
|
|
|
|
|
|
4526
|
|
|
|
|
|
|
# Write the cell data if supplied. |
|
4527
|
47
|
100
|
|
|
|
218
|
if ( my $data = $param->{data} ) { |
|
4528
|
|
|
|
|
|
|
|
|
4529
|
6
|
|
|
|
|
12
|
my $i = 0; # For indexing the row data. |
|
4530
|
6
|
|
|
|
|
20
|
for my $row ( $first_data_row .. $last_data_row ) { |
|
4531
|
22
|
|
|
|
|
53
|
my $j = 0; # For indexing the col data. |
|
4532
|
|
|
|
|
|
|
|
|
4533
|
22
|
|
|
|
|
44
|
for my $col ( $col1 .. $col2 ) { |
|
4534
|
|
|
|
|
|
|
|
|
4535
|
84
|
|
|
|
|
142
|
my $token = $data->[$i]->[$j]; |
|
4536
|
|
|
|
|
|
|
|
|
4537
|
84
|
100
|
|
|
|
180
|
if ( defined $token ) { |
|
4538
|
77
|
|
|
|
|
173
|
$self->write( $row, $col, $token, $col_formats[$j] ); |
|
4539
|
|
|
|
|
|
|
} |
|
4540
|
|
|
|
|
|
|
|
|
4541
|
84
|
|
|
|
|
156
|
$j++; |
|
4542
|
|
|
|
|
|
|
} |
|
4543
|
22
|
|
|
|
|
40
|
$i++; |
|
4544
|
|
|
|
|
|
|
} |
|
4545
|
|
|
|
|
|
|
} |
|
4546
|
|
|
|
|
|
|
|
|
4547
|
|
|
|
|
|
|
|
|
4548
|
|
|
|
|
|
|
# Store the table data. |
|
4549
|
47
|
|
|
|
|
184
|
push @{ $self->{_tables} }, \%table; |
|
|
47
|
|
|
|
|
152
|
|
|
4550
|
|
|
|
|
|
|
|
|
4551
|
47
|
|
|
|
|
330
|
return \%table; |
|
4552
|
|
|
|
|
|
|
} |
|
4553
|
|
|
|
|
|
|
|
|
4554
|
|
|
|
|
|
|
|
|
4555
|
|
|
|
|
|
|
############################################################################### |
|
4556
|
|
|
|
|
|
|
# |
|
4557
|
|
|
|
|
|
|
# add_sparkline() |
|
4558
|
|
|
|
|
|
|
# |
|
4559
|
|
|
|
|
|
|
# Add sparklines to the worksheet. |
|
4560
|
|
|
|
|
|
|
# |
|
4561
|
|
|
|
|
|
|
sub add_sparkline { |
|
4562
|
|
|
|
|
|
|
|
|
4563
|
58
|
|
|
58
|
0
|
398
|
my $self = shift; |
|
4564
|
58
|
|
|
|
|
82
|
my $param = shift; |
|
4565
|
58
|
|
|
|
|
83
|
my $sparkline = {}; |
|
4566
|
|
|
|
|
|
|
|
|
4567
|
|
|
|
|
|
|
# Check that the last parameter is a hash list. |
|
4568
|
58
|
50
|
|
|
|
149
|
if ( ref $param ne 'HASH' ) { |
|
4569
|
0
|
|
|
|
|
0
|
carp "Parameter list in add_sparkline() must be a hash ref"; |
|
4570
|
0
|
|
|
|
|
0
|
return -1; |
|
4571
|
|
|
|
|
|
|
} |
|
4572
|
|
|
|
|
|
|
|
|
4573
|
|
|
|
|
|
|
# List of valid input parameters. |
|
4574
|
58
|
|
|
|
|
582
|
my %valid_parameter = ( |
|
4575
|
|
|
|
|
|
|
location => 1, |
|
4576
|
|
|
|
|
|
|
range => 1, |
|
4577
|
|
|
|
|
|
|
type => 1, |
|
4578
|
|
|
|
|
|
|
high_point => 1, |
|
4579
|
|
|
|
|
|
|
low_point => 1, |
|
4580
|
|
|
|
|
|
|
negative_points => 1, |
|
4581
|
|
|
|
|
|
|
first_point => 1, |
|
4582
|
|
|
|
|
|
|
last_point => 1, |
|
4583
|
|
|
|
|
|
|
markers => 1, |
|
4584
|
|
|
|
|
|
|
style => 1, |
|
4585
|
|
|
|
|
|
|
series_color => 1, |
|
4586
|
|
|
|
|
|
|
negative_color => 1, |
|
4587
|
|
|
|
|
|
|
markers_color => 1, |
|
4588
|
|
|
|
|
|
|
first_color => 1, |
|
4589
|
|
|
|
|
|
|
last_color => 1, |
|
4590
|
|
|
|
|
|
|
high_color => 1, |
|
4591
|
|
|
|
|
|
|
low_color => 1, |
|
4592
|
|
|
|
|
|
|
max => 1, |
|
4593
|
|
|
|
|
|
|
min => 1, |
|
4594
|
|
|
|
|
|
|
axis => 1, |
|
4595
|
|
|
|
|
|
|
reverse => 1, |
|
4596
|
|
|
|
|
|
|
empty_cells => 1, |
|
4597
|
|
|
|
|
|
|
show_hidden => 1, |
|
4598
|
|
|
|
|
|
|
plot_hidden => 1, |
|
4599
|
|
|
|
|
|
|
date_axis => 1, |
|
4600
|
|
|
|
|
|
|
weight => 1, |
|
4601
|
|
|
|
|
|
|
); |
|
4602
|
|
|
|
|
|
|
|
|
4603
|
|
|
|
|
|
|
# Check for valid input parameters. |
|
4604
|
58
|
|
|
|
|
231
|
for my $param_key ( keys %$param ) { |
|
4605
|
212
|
50
|
|
|
|
435
|
if ( not exists $valid_parameter{$param_key} ) { |
|
4606
|
0
|
|
|
|
|
0
|
carp "Unknown parameter '$param_key' in add_sparkline()"; |
|
4607
|
0
|
|
|
|
|
0
|
return -2; |
|
4608
|
|
|
|
|
|
|
} |
|
4609
|
|
|
|
|
|
|
} |
|
4610
|
|
|
|
|
|
|
|
|
4611
|
|
|
|
|
|
|
# 'location' is a required parameter. |
|
4612
|
58
|
50
|
|
|
|
138
|
if ( not exists $param->{location} ) { |
|
4613
|
0
|
|
|
|
|
0
|
carp "Parameter 'location' is required in add_sparkline()"; |
|
4614
|
0
|
|
|
|
|
0
|
return -3; |
|
4615
|
|
|
|
|
|
|
} |
|
4616
|
|
|
|
|
|
|
|
|
4617
|
|
|
|
|
|
|
# 'range' is a required parameter. |
|
4618
|
58
|
50
|
|
|
|
121
|
if ( not exists $param->{range} ) { |
|
4619
|
0
|
|
|
|
|
0
|
carp "Parameter 'range' is required in add_sparkline()"; |
|
4620
|
0
|
|
|
|
|
0
|
return -3; |
|
4621
|
|
|
|
|
|
|
} |
|
4622
|
|
|
|
|
|
|
|
|
4623
|
|
|
|
|
|
|
|
|
4624
|
|
|
|
|
|
|
# Handle the sparkline type. |
|
4625
|
58
|
|
100
|
|
|
181
|
my $type = $param->{type} || 'line'; |
|
4626
|
|
|
|
|
|
|
|
|
4627
|
58
|
50
|
100
|
|
|
170
|
if ( $type ne 'line' && $type ne 'column' && $type ne 'win_loss' ) { |
|
|
|
|
66
|
|
|
|
|
|
4628
|
0
|
|
|
|
|
0
|
carp "Parameter 'type' must be 'line', 'column' " |
|
4629
|
|
|
|
|
|
|
. "or 'win_loss' in add_sparkline()"; |
|
4630
|
0
|
|
|
|
|
0
|
return -4; |
|
4631
|
|
|
|
|
|
|
} |
|
4632
|
|
|
|
|
|
|
|
|
4633
|
58
|
100
|
|
|
|
116
|
$type = 'stacked' if $type eq 'win_loss'; |
|
4634
|
58
|
|
|
|
|
106
|
$sparkline->{_type} = $type; |
|
4635
|
|
|
|
|
|
|
|
|
4636
|
|
|
|
|
|
|
|
|
4637
|
|
|
|
|
|
|
# We handle single location/range values or array refs of values. |
|
4638
|
58
|
100
|
|
|
|
129
|
if ( ref $param->{location} ) { |
|
4639
|
2
|
|
|
|
|
7
|
$sparkline->{_locations} = $param->{location}; |
|
4640
|
2
|
|
|
|
|
7
|
$sparkline->{_ranges} = $param->{range}; |
|
4641
|
|
|
|
|
|
|
} |
|
4642
|
|
|
|
|
|
|
else { |
|
4643
|
56
|
|
|
|
|
120
|
$sparkline->{_locations} = [ $param->{location} ]; |
|
4644
|
56
|
|
|
|
|
106
|
$sparkline->{_ranges} = [ $param->{range} ]; |
|
4645
|
|
|
|
|
|
|
} |
|
4646
|
|
|
|
|
|
|
|
|
4647
|
58
|
|
|
|
|
85
|
my $range_count = @{ $sparkline->{_ranges} }; |
|
|
58
|
|
|
|
|
104
|
|
|
4648
|
58
|
|
|
|
|
81
|
my $location_count = @{ $sparkline->{_locations} }; |
|
|
58
|
|
|
|
|
89
|
|
|
4649
|
|
|
|
|
|
|
|
|
4650
|
|
|
|
|
|
|
# The ranges and locations must match. |
|
4651
|
58
|
50
|
|
|
|
122
|
if ( $range_count != $location_count ) { |
|
4652
|
0
|
|
|
|
|
0
|
carp "Must have the same number of location and range " |
|
4653
|
|
|
|
|
|
|
. "parameters in add_sparkline()"; |
|
4654
|
0
|
|
|
|
|
0
|
return -5; |
|
4655
|
|
|
|
|
|
|
} |
|
4656
|
|
|
|
|
|
|
|
|
4657
|
|
|
|
|
|
|
# Store the count. |
|
4658
|
58
|
|
|
|
|
76
|
$sparkline->{_count} = @{ $sparkline->{_locations} }; |
|
|
58
|
|
|
|
|
104
|
|
|
4659
|
|
|
|
|
|
|
|
|
4660
|
|
|
|
|
|
|
# Get the worksheet name for the range conversion below. |
|
4661
|
58
|
|
|
|
|
178
|
my $sheetname = quote_sheetname( $self->{_name} ); |
|
4662
|
|
|
|
|
|
|
|
|
4663
|
|
|
|
|
|
|
# Cleanup the input ranges. |
|
4664
|
58
|
|
|
|
|
149
|
for my $range ( @{ $sparkline->{_ranges} } ) { |
|
|
58
|
|
|
|
|
126
|
|
|
4665
|
|
|
|
|
|
|
|
|
4666
|
|
|
|
|
|
|
# Remove the absolute reference $ symbols. |
|
4667
|
59
|
|
|
|
|
127
|
$range =~ s{\$}{}g; |
|
4668
|
|
|
|
|
|
|
|
|
4669
|
|
|
|
|
|
|
# Remove the = from xl_range_formula(. |
|
4670
|
59
|
|
|
|
|
102
|
$range =~ s{^=}{}; |
|
4671
|
|
|
|
|
|
|
|
|
4672
|
|
|
|
|
|
|
# Convert a simple range into a full Sheet1!A1:D1 range. |
|
4673
|
59
|
100
|
|
|
|
141
|
if ( $range !~ /!/ ) { |
|
4674
|
54
|
|
|
|
|
129
|
$range = $sheetname . "!" . $range; |
|
4675
|
|
|
|
|
|
|
} |
|
4676
|
|
|
|
|
|
|
} |
|
4677
|
|
|
|
|
|
|
|
|
4678
|
|
|
|
|
|
|
# Cleanup the input locations. |
|
4679
|
58
|
|
|
|
|
88
|
for my $location ( @{ $sparkline->{_locations} } ) { |
|
|
58
|
|
|
|
|
106
|
|
|
4680
|
59
|
|
|
|
|
105
|
$location =~ s{\$}{}g; |
|
4681
|
|
|
|
|
|
|
} |
|
4682
|
|
|
|
|
|
|
|
|
4683
|
|
|
|
|
|
|
# Map options. |
|
4684
|
58
|
|
|
|
|
114
|
$sparkline->{_high} = $param->{high_point}; |
|
4685
|
58
|
|
|
|
|
88
|
$sparkline->{_low} = $param->{low_point}; |
|
4686
|
58
|
|
|
|
|
84
|
$sparkline->{_negative} = $param->{negative_points}; |
|
4687
|
58
|
|
|
|
|
124
|
$sparkline->{_first} = $param->{first_point}; |
|
4688
|
58
|
|
|
|
|
96
|
$sparkline->{_last} = $param->{last_point}; |
|
4689
|
58
|
|
|
|
|
100
|
$sparkline->{_markers} = $param->{markers}; |
|
4690
|
58
|
|
|
|
|
98
|
$sparkline->{_min} = $param->{min}; |
|
4691
|
58
|
|
|
|
|
88
|
$sparkline->{_max} = $param->{max}; |
|
4692
|
58
|
|
|
|
|
85
|
$sparkline->{_axis} = $param->{axis}; |
|
4693
|
58
|
|
|
|
|
83
|
$sparkline->{_reverse} = $param->{reverse}; |
|
4694
|
58
|
|
|
|
|
89
|
$sparkline->{_hidden} = $param->{show_hidden}; |
|
4695
|
58
|
|
|
|
|
143
|
$sparkline->{_weight} = $param->{weight}; |
|
4696
|
|
|
|
|
|
|
|
|
4697
|
|
|
|
|
|
|
# Map empty cells options. |
|
4698
|
58
|
|
100
|
|
|
201
|
my $empty = $param->{empty_cells} || ''; |
|
4699
|
|
|
|
|
|
|
|
|
4700
|
58
|
100
|
|
|
|
161
|
if ( $empty eq 'zero' ) { |
|
|
|
100
|
|
|
|
|
|
|
4701
|
1
|
|
|
|
|
2
|
$sparkline->{_empty} = 0; |
|
4702
|
|
|
|
|
|
|
} |
|
4703
|
|
|
|
|
|
|
elsif ( $empty eq 'connect' ) { |
|
4704
|
1
|
|
|
|
|
2
|
$sparkline->{_empty} = 'span'; |
|
4705
|
|
|
|
|
|
|
} |
|
4706
|
|
|
|
|
|
|
else { |
|
4707
|
56
|
|
|
|
|
94
|
$sparkline->{_empty} = 'gap'; |
|
4708
|
|
|
|
|
|
|
} |
|
4709
|
|
|
|
|
|
|
|
|
4710
|
|
|
|
|
|
|
|
|
4711
|
|
|
|
|
|
|
# Map the date axis range. |
|
4712
|
58
|
|
|
|
|
95
|
my $date_range = $param->{date_axis}; |
|
4713
|
|
|
|
|
|
|
|
|
4714
|
58
|
100
|
66
|
|
|
152
|
if ( $date_range && $date_range !~ /!/ ) { |
|
4715
|
1
|
|
|
|
|
3
|
$date_range = $sheetname . "!" . $date_range; |
|
4716
|
|
|
|
|
|
|
} |
|
4717
|
58
|
|
|
|
|
101
|
$sparkline->{_date_axis} = $date_range; |
|
4718
|
|
|
|
|
|
|
|
|
4719
|
|
|
|
|
|
|
|
|
4720
|
|
|
|
|
|
|
# Set the sparkline styles. |
|
4721
|
58
|
|
100
|
|
|
144
|
my $style_id = $param->{style} || 0; |
|
4722
|
58
|
|
|
|
|
119
|
my $style = $Excel::Writer::XLSX::Package::Theme::spark_styles[$style_id]; |
|
4723
|
|
|
|
|
|
|
|
|
4724
|
58
|
|
|
|
|
127
|
$sparkline->{_series_color} = $style->{series}; |
|
4725
|
58
|
|
|
|
|
120
|
$sparkline->{_negative_color} = $style->{negative}; |
|
4726
|
58
|
|
|
|
|
95
|
$sparkline->{_markers_color} = $style->{markers}; |
|
4727
|
58
|
|
|
|
|
106
|
$sparkline->{_first_color} = $style->{first}; |
|
4728
|
58
|
|
|
|
|
95
|
$sparkline->{_last_color} = $style->{last}; |
|
4729
|
58
|
|
|
|
|
97
|
$sparkline->{_high_color} = $style->{high}; |
|
4730
|
58
|
|
|
|
|
114
|
$sparkline->{_low_color} = $style->{low}; |
|
4731
|
|
|
|
|
|
|
|
|
4732
|
|
|
|
|
|
|
# Override the style colours with user defined colors. |
|
4733
|
58
|
|
|
|
|
175
|
$self->_set_spark_color( $sparkline, $param, 'series_color' ); |
|
4734
|
58
|
|
|
|
|
129
|
$self->_set_spark_color( $sparkline, $param, 'negative_color' ); |
|
4735
|
58
|
|
|
|
|
123
|
$self->_set_spark_color( $sparkline, $param, 'markers_color' ); |
|
4736
|
58
|
|
|
|
|
128
|
$self->_set_spark_color( $sparkline, $param, 'first_color' ); |
|
4737
|
58
|
|
|
|
|
140
|
$self->_set_spark_color( $sparkline, $param, 'last_color' ); |
|
4738
|
58
|
|
|
|
|
130
|
$self->_set_spark_color( $sparkline, $param, 'high_color' ); |
|
4739
|
58
|
|
|
|
|
110
|
$self->_set_spark_color( $sparkline, $param, 'low_color' ); |
|
4740
|
|
|
|
|
|
|
|
|
4741
|
58
|
|
|
|
|
75
|
push @{ $self->{_sparklines} }, $sparkline; |
|
|
58
|
|
|
|
|
311
|
|
|
4742
|
|
|
|
|
|
|
} |
|
4743
|
|
|
|
|
|
|
|
|
4744
|
|
|
|
|
|
|
|
|
4745
|
|
|
|
|
|
|
############################################################################### |
|
4746
|
|
|
|
|
|
|
# |
|
4747
|
|
|
|
|
|
|
# insert_button() |
|
4748
|
|
|
|
|
|
|
# |
|
4749
|
|
|
|
|
|
|
# Insert a button form object into the worksheet. |
|
4750
|
|
|
|
|
|
|
# |
|
4751
|
|
|
|
|
|
|
sub insert_button { |
|
4752
|
|
|
|
|
|
|
|
|
4753
|
28
|
|
|
28
|
0
|
203
|
my $self = shift; |
|
4754
|
|
|
|
|
|
|
|
|
4755
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column |
|
4756
|
28
|
50
|
|
|
|
181
|
if ( $_[0] =~ /^\D/ ) { |
|
4757
|
28
|
|
|
|
|
117
|
@_ = $self->_substitute_cellref( @_ ); |
|
4758
|
|
|
|
|
|
|
} |
|
4759
|
|
|
|
|
|
|
|
|
4760
|
|
|
|
|
|
|
# Check the number of args. |
|
4761
|
28
|
50
|
|
|
|
115
|
if ( @_ < 3 ) { return -1 } |
|
|
0
|
|
|
|
|
0
|
|
|
4762
|
|
|
|
|
|
|
|
|
4763
|
28
|
|
|
|
|
123
|
my $button = $self->_button_params( @_ ); |
|
4764
|
|
|
|
|
|
|
|
|
4765
|
28
|
|
|
|
|
54
|
push @{ $self->{_buttons_array} }, $button; |
|
|
28
|
|
|
|
|
73
|
|
|
4766
|
|
|
|
|
|
|
|
|
4767
|
28
|
|
|
|
|
122
|
$self->{_has_vml} = 1; |
|
4768
|
|
|
|
|
|
|
} |
|
4769
|
|
|
|
|
|
|
|
|
4770
|
|
|
|
|
|
|
|
|
4771
|
|
|
|
|
|
|
############################################################################### |
|
4772
|
|
|
|
|
|
|
# |
|
4773
|
|
|
|
|
|
|
# set_vba_name() |
|
4774
|
|
|
|
|
|
|
# |
|
4775
|
|
|
|
|
|
|
# Set the VBA name for the worksheet. |
|
4776
|
|
|
|
|
|
|
# |
|
4777
|
|
|
|
|
|
|
sub set_vba_name { |
|
4778
|
|
|
|
|
|
|
|
|
4779
|
6
|
|
|
6
|
0
|
28
|
my $self = shift; |
|
4780
|
6
|
|
|
|
|
14
|
my $vba_codemame = shift; |
|
4781
|
|
|
|
|
|
|
|
|
4782
|
6
|
100
|
|
|
|
27
|
if ( $vba_codemame ) { |
|
4783
|
2
|
|
|
|
|
19
|
$self->{_vba_codename} = $vba_codemame; |
|
4784
|
|
|
|
|
|
|
} |
|
4785
|
|
|
|
|
|
|
else { |
|
4786
|
4
|
|
|
|
|
20
|
$self->{_vba_codename} = $self->{_name}; |
|
4787
|
|
|
|
|
|
|
} |
|
4788
|
|
|
|
|
|
|
} |
|
4789
|
|
|
|
|
|
|
|
|
4790
|
|
|
|
|
|
|
|
|
4791
|
|
|
|
|
|
|
############################################################################### |
|
4792
|
|
|
|
|
|
|
# |
|
4793
|
|
|
|
|
|
|
# Internal methods. |
|
4794
|
|
|
|
|
|
|
# |
|
4795
|
|
|
|
|
|
|
############################################################################### |
|
4796
|
|
|
|
|
|
|
|
|
4797
|
|
|
|
|
|
|
|
|
4798
|
|
|
|
|
|
|
############################################################################### |
|
4799
|
|
|
|
|
|
|
# |
|
4800
|
|
|
|
|
|
|
# _table_function_to_formula |
|
4801
|
|
|
|
|
|
|
# |
|
4802
|
|
|
|
|
|
|
# Convert a table total function to a worksheet formula. |
|
4803
|
|
|
|
|
|
|
# |
|
4804
|
|
|
|
|
|
|
sub _table_function_to_formula { |
|
4805
|
|
|
|
|
|
|
|
|
4806
|
40
|
|
|
40
|
|
70
|
my $function = shift; |
|
4807
|
40
|
|
|
|
|
62
|
my $col_name = shift; |
|
4808
|
40
|
|
|
|
|
61
|
my $formula = ''; |
|
4809
|
|
|
|
|
|
|
|
|
4810
|
|
|
|
|
|
|
# Escape special characters, as required by Excel. |
|
4811
|
40
|
|
|
|
|
70
|
$col_name =~ s/'/''/g; |
|
4812
|
40
|
|
|
|
|
73
|
$col_name =~ s/#/'#/g; |
|
4813
|
40
|
|
|
|
|
71
|
$col_name =~ s/\[/'[/g; |
|
4814
|
40
|
|
|
|
|
67
|
$col_name =~ s/]/']/g; |
|
4815
|
|
|
|
|
|
|
|
|
4816
|
40
|
|
|
|
|
220
|
my %subtotals = ( |
|
4817
|
|
|
|
|
|
|
average => 101, |
|
4818
|
|
|
|
|
|
|
countNums => 102, |
|
4819
|
|
|
|
|
|
|
count => 103, |
|
4820
|
|
|
|
|
|
|
max => 104, |
|
4821
|
|
|
|
|
|
|
min => 105, |
|
4822
|
|
|
|
|
|
|
stdDev => 107, |
|
4823
|
|
|
|
|
|
|
sum => 109, |
|
4824
|
|
|
|
|
|
|
var => 110, |
|
4825
|
|
|
|
|
|
|
); |
|
4826
|
|
|
|
|
|
|
|
|
4827
|
40
|
50
|
|
|
|
134
|
if ( exists $subtotals{$function} ) { |
|
4828
|
40
|
|
|
|
|
71
|
my $func_num = $subtotals{$function}; |
|
4829
|
40
|
|
|
|
|
120
|
$formula = qq{SUBTOTAL($func_num,[$col_name])}; |
|
4830
|
|
|
|
|
|
|
} |
|
4831
|
|
|
|
|
|
|
else { |
|
4832
|
0
|
|
|
|
|
0
|
carp "Unsupported function '$function' in add_table()"; |
|
4833
|
|
|
|
|
|
|
} |
|
4834
|
|
|
|
|
|
|
|
|
4835
|
40
|
|
|
|
|
127
|
return $formula; |
|
4836
|
|
|
|
|
|
|
} |
|
4837
|
|
|
|
|
|
|
|
|
4838
|
|
|
|
|
|
|
|
|
4839
|
|
|
|
|
|
|
############################################################################### |
|
4840
|
|
|
|
|
|
|
# |
|
4841
|
|
|
|
|
|
|
# _set_spark_color() |
|
4842
|
|
|
|
|
|
|
# |
|
4843
|
|
|
|
|
|
|
# Set the sparkline colour. |
|
4844
|
|
|
|
|
|
|
# |
|
4845
|
|
|
|
|
|
|
sub _set_spark_color { |
|
4846
|
|
|
|
|
|
|
|
|
4847
|
406
|
|
|
406
|
|
509
|
my $self = shift; |
|
4848
|
406
|
|
|
|
|
472
|
my $sparkline = shift; |
|
4849
|
406
|
|
|
|
|
456
|
my $param = shift; |
|
4850
|
406
|
|
|
|
|
460
|
my $user_color = shift; |
|
4851
|
406
|
|
|
|
|
568
|
my $spark_color = '_' . $user_color; |
|
4852
|
|
|
|
|
|
|
|
|
4853
|
406
|
100
|
|
|
|
737
|
return unless $param->{$user_color}; |
|
4854
|
|
|
|
|
|
|
|
|
4855
|
|
|
|
|
|
|
$sparkline->{$spark_color} = |
|
4856
|
8
|
|
|
|
|
17
|
{ _rgb => $self->_get_palette_color( $param->{$user_color} ) }; |
|
4857
|
|
|
|
|
|
|
} |
|
4858
|
|
|
|
|
|
|
|
|
4859
|
|
|
|
|
|
|
|
|
4860
|
|
|
|
|
|
|
############################################################################### |
|
4861
|
|
|
|
|
|
|
# |
|
4862
|
|
|
|
|
|
|
# _get_palette_color() |
|
4863
|
|
|
|
|
|
|
# |
|
4864
|
|
|
|
|
|
|
# Convert from an Excel internal colour index to a XML style #RRGGBB index |
|
4865
|
|
|
|
|
|
|
# based on the default or user defined values in the Workbook palette. |
|
4866
|
|
|
|
|
|
|
# |
|
4867
|
|
|
|
|
|
|
sub _get_palette_color { |
|
4868
|
|
|
|
|
|
|
|
|
4869
|
173
|
|
|
173
|
|
295
|
my $self = shift; |
|
4870
|
173
|
|
|
|
|
277
|
my $index = shift; |
|
4871
|
173
|
|
|
|
|
273
|
my $palette = $self->{_palette}; |
|
4872
|
|
|
|
|
|
|
|
|
4873
|
|
|
|
|
|
|
# Handle colours in #XXXXXX RGB format. |
|
4874
|
173
|
100
|
|
|
|
617
|
if ( $index =~ m/^#([0-9A-F]{6})$/i ) { |
|
4875
|
167
|
|
|
|
|
605
|
return "FF" . uc( $1 ); |
|
4876
|
|
|
|
|
|
|
} |
|
4877
|
|
|
|
|
|
|
|
|
4878
|
|
|
|
|
|
|
# Adjust the colour index. |
|
4879
|
6
|
|
|
|
|
14
|
$index -= 8; |
|
4880
|
|
|
|
|
|
|
|
|
4881
|
|
|
|
|
|
|
# Palette is passed in from the Workbook class. |
|
4882
|
6
|
|
|
|
|
13
|
my @rgb = @{ $palette->[$index] }; |
|
|
6
|
|
|
|
|
20
|
|
|
4883
|
|
|
|
|
|
|
|
|
4884
|
6
|
|
|
|
|
47
|
return sprintf "FF%02X%02X%02X", @rgb[0, 1, 2]; |
|
4885
|
|
|
|
|
|
|
} |
|
4886
|
|
|
|
|
|
|
|
|
4887
|
|
|
|
|
|
|
|
|
4888
|
|
|
|
|
|
|
############################################################################### |
|
4889
|
|
|
|
|
|
|
# |
|
4890
|
|
|
|
|
|
|
# _substitute_cellref() |
|
4891
|
|
|
|
|
|
|
# |
|
4892
|
|
|
|
|
|
|
# Substitute an Excel cell reference in A1 notation for zero based row and |
|
4893
|
|
|
|
|
|
|
# column values in an argument list. |
|
4894
|
|
|
|
|
|
|
# |
|
4895
|
|
|
|
|
|
|
# Ex: ("A4", "Hello") is converted to (3, 0, "Hello"). |
|
4896
|
|
|
|
|
|
|
# |
|
4897
|
|
|
|
|
|
|
sub _substitute_cellref { |
|
4898
|
|
|
|
|
|
|
|
|
4899
|
2446
|
|
|
2446
|
|
4645
|
my $self = shift; |
|
4900
|
2446
|
|
|
|
|
6120
|
my $cell = uc( shift ); |
|
4901
|
|
|
|
|
|
|
|
|
4902
|
|
|
|
|
|
|
# Convert a column range: 'A:A' or 'B:G'. |
|
4903
|
|
|
|
|
|
|
# A range such as A:A is equivalent to A1:Rowmax, so add rows as required |
|
4904
|
2446
|
100
|
|
|
|
9607
|
if ( $cell =~ /\$?([A-Z]{1,3}):\$?([A-Z]{1,3})/ ) { |
|
4905
|
191
|
|
|
|
|
1182
|
my ( $row1, $col1 ) = $self->_cell_to_rowcol( $1 . '1' ); |
|
4906
|
|
|
|
|
|
|
my ( $row2, $col2 ) = |
|
4907
|
191
|
|
|
|
|
1365
|
$self->_cell_to_rowcol( $2 . $self->{_xls_rowmax} ); |
|
4908
|
191
|
|
|
|
|
911
|
return $row1, $col1, $row2, $col2, @_; |
|
4909
|
|
|
|
|
|
|
} |
|
4910
|
|
|
|
|
|
|
|
|
4911
|
|
|
|
|
|
|
# Convert a cell range: 'A1:B7' |
|
4912
|
2255
|
100
|
|
|
|
6908
|
if ( $cell =~ /\$?([A-Z]{1,3}\$?\d+):\$?([A-Z]{1,3}\$?\d+)/ ) { |
|
4913
|
194
|
|
|
|
|
645
|
my ( $row1, $col1 ) = $self->_cell_to_rowcol( $1 ); |
|
4914
|
194
|
|
|
|
|
737
|
my ( $row2, $col2 ) = $self->_cell_to_rowcol( $2 ); |
|
4915
|
194
|
|
|
|
|
1114
|
return $row1, $col1, $row2, $col2, @_; |
|
4916
|
|
|
|
|
|
|
} |
|
4917
|
|
|
|
|
|
|
|
|
4918
|
|
|
|
|
|
|
# Convert a cell reference: 'A1' or 'AD2000' |
|
4919
|
2061
|
50
|
|
|
|
10269
|
if ( $cell =~ /\$?([A-Z]{1,3}\$?\d+)/ ) { |
|
4920
|
2061
|
|
|
|
|
7182
|
my ( $row1, $col1 ) = $self->_cell_to_rowcol( $1 ); |
|
4921
|
2061
|
|
|
|
|
9548
|
return $row1, $col1, @_; |
|
4922
|
|
|
|
|
|
|
|
|
4923
|
|
|
|
|
|
|
} |
|
4924
|
|
|
|
|
|
|
|
|
4925
|
0
|
|
|
|
|
0
|
croak( "Unknown cell reference $cell" ); |
|
4926
|
|
|
|
|
|
|
} |
|
4927
|
|
|
|
|
|
|
|
|
4928
|
|
|
|
|
|
|
|
|
4929
|
|
|
|
|
|
|
############################################################################### |
|
4930
|
|
|
|
|
|
|
# |
|
4931
|
|
|
|
|
|
|
# _cell_to_rowcol($cell_ref) |
|
4932
|
|
|
|
|
|
|
# |
|
4933
|
|
|
|
|
|
|
# Convert an Excel cell reference in A1 notation to a zero based row and column |
|
4934
|
|
|
|
|
|
|
# reference; converts C1 to (0, 2). |
|
4935
|
|
|
|
|
|
|
# |
|
4936
|
|
|
|
|
|
|
# See also: http://www.perlmonks.org/index.pl?node_id=270352 |
|
4937
|
|
|
|
|
|
|
# |
|
4938
|
|
|
|
|
|
|
# Returns: ($row, $col, $row_absolute, $col_absolute) |
|
4939
|
|
|
|
|
|
|
# |
|
4940
|
|
|
|
|
|
|
# |
|
4941
|
|
|
|
|
|
|
sub _cell_to_rowcol { |
|
4942
|
|
|
|
|
|
|
|
|
4943
|
2831
|
|
|
2831
|
|
5270
|
my $self = shift; |
|
4944
|
|
|
|
|
|
|
|
|
4945
|
2831
|
|
|
|
|
7101
|
my $cell = $_[0]; |
|
4946
|
2831
|
|
|
|
|
9101
|
$cell =~ /(\$?)([A-Z]{1,3})(\$?)(\d+)/; |
|
4947
|
|
|
|
|
|
|
|
|
4948
|
2831
|
50
|
|
|
|
9306
|
my $col_abs = $1 eq "" ? 0 : 1; |
|
4949
|
2831
|
|
|
|
|
6306
|
my $col = $2; |
|
4950
|
2831
|
100
|
|
|
|
7962
|
my $row_abs = $3 eq "" ? 0 : 1; |
|
4951
|
2831
|
|
|
|
|
11187
|
my $row = $4; |
|
4952
|
|
|
|
|
|
|
|
|
4953
|
|
|
|
|
|
|
# Convert base26 column string to number |
|
4954
|
|
|
|
|
|
|
# All your Base are belong to us. |
|
4955
|
2831
|
|
|
|
|
9028
|
my @chars = split //, $col; |
|
4956
|
2831
|
|
|
|
|
5158
|
my $expn = 0; |
|
4957
|
2831
|
|
|
|
|
4955
|
$col = 0; |
|
4958
|
|
|
|
|
|
|
|
|
4959
|
2831
|
|
|
|
|
7784
|
while ( @chars ) { |
|
4960
|
2873
|
|
|
|
|
5978
|
my $char = pop( @chars ); # LS char first |
|
4961
|
2873
|
|
|
|
|
8984
|
$col += ( ord( $char ) - ord( 'A' ) + 1 ) * ( 26**$expn ); |
|
4962
|
2873
|
|
|
|
|
7199
|
$expn++; |
|
4963
|
|
|
|
|
|
|
} |
|
4964
|
|
|
|
|
|
|
|
|
4965
|
|
|
|
|
|
|
# Convert 1-index to zero-index |
|
4966
|
2831
|
|
|
|
|
7168
|
$row--; |
|
4967
|
2831
|
|
|
|
|
4652
|
$col--; |
|
4968
|
|
|
|
|
|
|
|
|
4969
|
|
|
|
|
|
|
# TODO Check row and column range |
|
4970
|
2831
|
|
|
|
|
9435
|
return $row, $col, $row_abs, $col_abs; |
|
4971
|
|
|
|
|
|
|
} |
|
4972
|
|
|
|
|
|
|
|
|
4973
|
|
|
|
|
|
|
|
|
4974
|
|
|
|
|
|
|
############################################################################### |
|
4975
|
|
|
|
|
|
|
# |
|
4976
|
|
|
|
|
|
|
# _xl_rowcol_to_cell($row, $col) |
|
4977
|
|
|
|
|
|
|
# |
|
4978
|
|
|
|
|
|
|
# Optimised version of xl_rowcol_to_cell from Utility.pm for the inner loop |
|
4979
|
|
|
|
|
|
|
# of _write_cell(). |
|
4980
|
|
|
|
|
|
|
# |
|
4981
|
|
|
|
|
|
|
|
|
4982
|
|
|
|
|
|
|
our @col_names = ( 'A' .. 'XFD' ); |
|
4983
|
|
|
|
|
|
|
|
|
4984
|
|
|
|
|
|
|
sub _xl_rowcol_to_cell { |
|
4985
|
10107
|
|
|
10107
|
|
25370
|
return $col_names[ $_[1] ] . ( $_[0] + 1 ); |
|
4986
|
|
|
|
|
|
|
} |
|
4987
|
|
|
|
|
|
|
|
|
4988
|
|
|
|
|
|
|
|
|
4989
|
|
|
|
|
|
|
############################################################################### |
|
4990
|
|
|
|
|
|
|
# |
|
4991
|
|
|
|
|
|
|
# _sort_pagebreaks() |
|
4992
|
|
|
|
|
|
|
# |
|
4993
|
|
|
|
|
|
|
# This is an internal method that is used to filter elements of the array of |
|
4994
|
|
|
|
|
|
|
# pagebreaks used in the _store_hbreak() and _store_vbreak() methods. It: |
|
4995
|
|
|
|
|
|
|
# 1. Removes duplicate entries from the list. |
|
4996
|
|
|
|
|
|
|
# 2. Sorts the list. |
|
4997
|
|
|
|
|
|
|
# 3. Removes 0 from the list if present. |
|
4998
|
|
|
|
|
|
|
# |
|
4999
|
|
|
|
|
|
|
sub _sort_pagebreaks { |
|
5000
|
|
|
|
|
|
|
|
|
5001
|
1990
|
|
|
1990
|
|
4009
|
my $self = shift; |
|
5002
|
|
|
|
|
|
|
|
|
5003
|
1990
|
100
|
|
|
|
7439
|
return () unless @_; |
|
5004
|
|
|
|
|
|
|
|
|
5005
|
11
|
|
|
|
|
25
|
my %hash; |
|
5006
|
|
|
|
|
|
|
my @array; |
|
5007
|
|
|
|
|
|
|
|
|
5008
|
11
|
|
|
|
|
837
|
@hash{@_} = undef; # Hash slice to remove duplicates |
|
5009
|
11
|
|
|
|
|
196
|
@array = sort { $a <=> $b } keys %hash; # Numerical sort |
|
|
9066
|
|
|
|
|
11817
|
|
|
5010
|
11
|
100
|
|
|
|
110
|
shift @array if $array[0] == 0; # Remove zero |
|
5011
|
|
|
|
|
|
|
|
|
5012
|
|
|
|
|
|
|
# The Excel 2007 specification says that the maximum number of page breaks |
|
5013
|
|
|
|
|
|
|
# is 1026. However, in practice it is actually 1023. |
|
5014
|
11
|
|
|
|
|
29
|
my $max_num_breaks = 1023; |
|
5015
|
11
|
100
|
|
|
|
39
|
splice( @array, $max_num_breaks ) if @array > $max_num_breaks; |
|
5016
|
|
|
|
|
|
|
|
|
5017
|
11
|
|
|
|
|
228
|
return @array; |
|
5018
|
|
|
|
|
|
|
} |
|
5019
|
|
|
|
|
|
|
|
|
5020
|
|
|
|
|
|
|
|
|
5021
|
|
|
|
|
|
|
############################################################################### |
|
5022
|
|
|
|
|
|
|
# |
|
5023
|
|
|
|
|
|
|
# _check_dimensions($row, $col, $ignore_row, $ignore_col) |
|
5024
|
|
|
|
|
|
|
# |
|
5025
|
|
|
|
|
|
|
# Check that $row and $col are valid and store max and min values for use in |
|
5026
|
|
|
|
|
|
|
# other methods/elements. |
|
5027
|
|
|
|
|
|
|
# |
|
5028
|
|
|
|
|
|
|
# The $ignore_row/$ignore_col flags is used to indicate that we wish to |
|
5029
|
|
|
|
|
|
|
# perform the dimension check without storing the value. |
|
5030
|
|
|
|
|
|
|
# |
|
5031
|
|
|
|
|
|
|
# The ignore flags are use by set_row() and data_validate. |
|
5032
|
|
|
|
|
|
|
# |
|
5033
|
|
|
|
|
|
|
sub _check_dimensions { |
|
5034
|
|
|
|
|
|
|
|
|
5035
|
16086
|
|
|
16086
|
|
23099
|
my $self = shift; |
|
5036
|
16086
|
|
|
|
|
24018
|
my $row = $_[0]; |
|
5037
|
16086
|
|
|
|
|
22142
|
my $col = $_[1]; |
|
5038
|
16086
|
|
|
|
|
22247
|
my $ignore_row = $_[2]; |
|
5039
|
16086
|
|
|
|
|
21802
|
my $ignore_col = $_[3]; |
|
5040
|
|
|
|
|
|
|
|
|
5041
|
|
|
|
|
|
|
|
|
5042
|
16086
|
50
|
|
|
|
29420
|
return -2 if not defined $row; |
|
5043
|
16086
|
50
|
|
|
|
31758
|
return -2 if $row >= $self->{_xls_rowmax}; |
|
5044
|
|
|
|
|
|
|
|
|
5045
|
16086
|
50
|
|
|
|
28624
|
return -2 if not defined $col; |
|
5046
|
16086
|
50
|
|
|
|
29971
|
return -2 if $col >= $self->{_xls_colmax}; |
|
5047
|
|
|
|
|
|
|
|
|
5048
|
|
|
|
|
|
|
# In optimization mode we don't change dimensions for rows that are |
|
5049
|
|
|
|
|
|
|
# already written. |
|
5050
|
16086
|
100
|
66
|
|
|
66251
|
if ( !$ignore_row && !$ignore_col && $self->{_optimization} == 1 ) { |
|
|
|
|
100
|
|
|
|
|
|
5051
|
308
|
100
|
|
|
|
683
|
return -2 if $row < $self->{_previous_row}; |
|
5052
|
|
|
|
|
|
|
} |
|
5053
|
|
|
|
|
|
|
|
|
5054
|
16085
|
100
|
|
|
|
29096
|
if ( !$ignore_row ) { |
|
5055
|
|
|
|
|
|
|
|
|
5056
|
15177
|
100
|
100
|
|
|
46767
|
if ( not defined $self->{_dim_rowmin} or $row < $self->{_dim_rowmin} ) { |
|
5057
|
806
|
|
|
|
|
2375
|
$self->{_dim_rowmin} = $row; |
|
5058
|
|
|
|
|
|
|
} |
|
5059
|
|
|
|
|
|
|
|
|
5060
|
15177
|
100
|
100
|
|
|
46118
|
if ( not defined $self->{_dim_rowmax} or $row > $self->{_dim_rowmax} ) { |
|
5061
|
4539
|
|
|
|
|
8869
|
$self->{_dim_rowmax} = $row; |
|
5062
|
|
|
|
|
|
|
} |
|
5063
|
|
|
|
|
|
|
} |
|
5064
|
|
|
|
|
|
|
|
|
5065
|
16085
|
100
|
|
|
|
28625
|
if ( !$ignore_col ) { |
|
5066
|
|
|
|
|
|
|
|
|
5067
|
15219
|
100
|
100
|
|
|
45410
|
if ( not defined $self->{_dim_colmin} or $col < $self->{_dim_colmin} ) { |
|
5068
|
819
|
|
|
|
|
2463
|
$self->{_dim_colmin} = $col; |
|
5069
|
|
|
|
|
|
|
} |
|
5070
|
|
|
|
|
|
|
|
|
5071
|
15219
|
100
|
100
|
|
|
45195
|
if ( not defined $self->{_dim_colmax} or $col > $self->{_dim_colmax} ) { |
|
5072
|
2204
|
|
|
|
|
4744
|
$self->{_dim_colmax} = $col; |
|
5073
|
|
|
|
|
|
|
} |
|
5074
|
|
|
|
|
|
|
} |
|
5075
|
|
|
|
|
|
|
|
|
5076
|
16085
|
|
|
|
|
35456
|
return 0; |
|
5077
|
|
|
|
|
|
|
} |
|
5078
|
|
|
|
|
|
|
|
|
5079
|
|
|
|
|
|
|
|
|
5080
|
|
|
|
|
|
|
############################################################################### |
|
5081
|
|
|
|
|
|
|
# |
|
5082
|
|
|
|
|
|
|
# _position_object_pixels() |
|
5083
|
|
|
|
|
|
|
# |
|
5084
|
|
|
|
|
|
|
# Calculate the vertices that define the position of a graphical object within |
|
5085
|
|
|
|
|
|
|
# the worksheet in pixels. |
|
5086
|
|
|
|
|
|
|
# |
|
5087
|
|
|
|
|
|
|
# +------------+------------+ |
|
5088
|
|
|
|
|
|
|
# | A | B | |
|
5089
|
|
|
|
|
|
|
# +-----+------------+------------+ |
|
5090
|
|
|
|
|
|
|
# | |(x1,y1) | | |
|
5091
|
|
|
|
|
|
|
# | 1 |(A1)._______|______ | |
|
5092
|
|
|
|
|
|
|
# | | | | | |
|
5093
|
|
|
|
|
|
|
# | | | | | |
|
5094
|
|
|
|
|
|
|
# +-----+----| Object |-----+ |
|
5095
|
|
|
|
|
|
|
# | | | | | |
|
5096
|
|
|
|
|
|
|
# | 2 | |______________. | |
|
5097
|
|
|
|
|
|
|
# | | | (B2)| |
|
5098
|
|
|
|
|
|
|
# | | | (x2,y2)| |
|
5099
|
|
|
|
|
|
|
# +---- +------------+------------+ |
|
5100
|
|
|
|
|
|
|
# |
|
5101
|
|
|
|
|
|
|
# Example of an object that covers some of the area from cell A1 to cell B2. |
|
5102
|
|
|
|
|
|
|
# |
|
5103
|
|
|
|
|
|
|
# Based on the width and height of the object we need to calculate 8 vars: |
|
5104
|
|
|
|
|
|
|
# |
|
5105
|
|
|
|
|
|
|
# $col_start, $row_start, $col_end, $row_end, $x1, $y1, $x2, $y2. |
|
5106
|
|
|
|
|
|
|
# |
|
5107
|
|
|
|
|
|
|
# We also calculate the absolute x and y position of the top left vertex of |
|
5108
|
|
|
|
|
|
|
# the object. This is required for images. |
|
5109
|
|
|
|
|
|
|
# |
|
5110
|
|
|
|
|
|
|
# $x_abs, $y_abs |
|
5111
|
|
|
|
|
|
|
# |
|
5112
|
|
|
|
|
|
|
# The width and height of the cells that the object occupies can be variable |
|
5113
|
|
|
|
|
|
|
# and have to be taken into account. |
|
5114
|
|
|
|
|
|
|
# |
|
5115
|
|
|
|
|
|
|
# The values of $col_start and $row_start are passed in from the calling |
|
5116
|
|
|
|
|
|
|
# function. The values of $col_end and $row_end are calculated by subtracting |
|
5117
|
|
|
|
|
|
|
# the width and height of the object from the width and height of the |
|
5118
|
|
|
|
|
|
|
# underlying cells. |
|
5119
|
|
|
|
|
|
|
# |
|
5120
|
|
|
|
|
|
|
# The anchor/object position defines how images are scaled for hidden rows and |
|
5121
|
|
|
|
|
|
|
# columns. For option 1 "Move and size with cells" the size of the hidden |
|
5122
|
|
|
|
|
|
|
# row/column is subtracted from the image. |
|
5123
|
|
|
|
|
|
|
# |
|
5124
|
|
|
|
|
|
|
sub _position_object_pixels { |
|
5125
|
|
|
|
|
|
|
|
|
5126
|
4705
|
|
|
4705
|
|
7686
|
my $self = shift; |
|
5127
|
|
|
|
|
|
|
|
|
5128
|
4705
|
|
|
|
|
32983
|
my $col_start; # Col containing upper left corner of object. |
|
5129
|
|
|
|
|
|
|
my $x1; # Distance to left side of object. |
|
5130
|
|
|
|
|
|
|
|
|
5131
|
4705
|
|
|
|
|
0
|
my $row_start; # Row containing top left corner of object. |
|
5132
|
4705
|
|
|
|
|
0
|
my $y1; # Distance to top of object. |
|
5133
|
|
|
|
|
|
|
|
|
5134
|
4705
|
|
|
|
|
0
|
my $col_end; # Col containing lower right corner of object. |
|
5135
|
4705
|
|
|
|
|
0
|
my $x2; # Distance to right side of object. |
|
5136
|
|
|
|
|
|
|
|
|
5137
|
4705
|
|
|
|
|
0
|
my $row_end; # Row containing bottom right corner of object. |
|
5138
|
4705
|
|
|
|
|
0
|
my $y2; # Distance to bottom of object. |
|
5139
|
|
|
|
|
|
|
|
|
5140
|
4705
|
|
|
|
|
0
|
my $width; # Width of object frame. |
|
5141
|
4705
|
|
|
|
|
0
|
my $height; # Height of object frame. |
|
5142
|
|
|
|
|
|
|
|
|
5143
|
4705
|
|
|
|
|
6891
|
my $x_abs = 0; # Absolute distance to left side of object. |
|
5144
|
4705
|
|
|
|
|
6847
|
my $y_abs = 0; # Absolute distance to top side of object. |
|
5145
|
|
|
|
|
|
|
|
|
5146
|
4705
|
|
|
|
|
7116
|
my $anchor; # The type of object positioning. |
|
5147
|
|
|
|
|
|
|
|
|
5148
|
4705
|
|
|
|
|
10704
|
( $col_start, $row_start, $x1, $y1, $width, $height, $anchor ) = @_; |
|
5149
|
|
|
|
|
|
|
|
|
5150
|
|
|
|
|
|
|
# Adjust start column for negative offsets. |
|
5151
|
4705
|
|
100
|
|
|
12532
|
while ( $x1 < 0 && $col_start > 0) { |
|
5152
|
8
|
|
|
|
|
42
|
$x1 += $self->_size_col( $col_start - 1); |
|
5153
|
8
|
|
|
|
|
28
|
$col_start--; |
|
5154
|
|
|
|
|
|
|
} |
|
5155
|
|
|
|
|
|
|
|
|
5156
|
|
|
|
|
|
|
# Adjust start row for negative offsets. |
|
5157
|
4705
|
|
100
|
|
|
11106
|
while ( $y1 < 0 && $row_start > 0) { |
|
5158
|
4
|
|
|
|
|
18
|
$y1 += $self->_size_row( $row_start - 1); |
|
5159
|
4
|
|
|
|
|
14
|
$row_start--; |
|
5160
|
|
|
|
|
|
|
} |
|
5161
|
|
|
|
|
|
|
|
|
5162
|
|
|
|
|
|
|
# Ensure that the image isn't shifted off the page at top left. |
|
5163
|
4705
|
100
|
|
|
|
9499
|
$x1 = 0 if $x1 < 0; |
|
5164
|
4705
|
100
|
|
|
|
9020
|
$y1 = 0 if $y1 < 0; |
|
5165
|
|
|
|
|
|
|
|
|
5166
|
|
|
|
|
|
|
# Calculate the absolute x offset of the top-left vertex. |
|
5167
|
4705
|
100
|
|
|
|
9529
|
if ( $self->{_col_size_changed} ) { |
|
5168
|
46
|
|
|
|
|
179
|
for my $col_id ( 0 .. $col_start -1 ) { |
|
5169
|
187
|
|
|
|
|
470
|
$x_abs += $self->_size_col( $col_id ); |
|
5170
|
|
|
|
|
|
|
} |
|
5171
|
|
|
|
|
|
|
} |
|
5172
|
|
|
|
|
|
|
else { |
|
5173
|
|
|
|
|
|
|
# Optimisation for when the column widths haven't changed. |
|
5174
|
4659
|
|
|
|
|
8103
|
$x_abs += $self->{_default_col_pixels} * $col_start; |
|
5175
|
|
|
|
|
|
|
} |
|
5176
|
|
|
|
|
|
|
|
|
5177
|
4705
|
|
|
|
|
6862
|
$x_abs += $x1; |
|
5178
|
|
|
|
|
|
|
|
|
5179
|
|
|
|
|
|
|
# Calculate the absolute y offset of the top-left vertex. |
|
5180
|
|
|
|
|
|
|
# Store the column change to allow optimisations. |
|
5181
|
4705
|
100
|
|
|
|
8685
|
if ( $self->{_row_size_changed} ) { |
|
5182
|
23
|
|
|
|
|
100
|
for my $row_id ( 0 .. $row_start -1 ) { |
|
5183
|
132
|
|
|
|
|
271
|
$y_abs += $self->_size_row( $row_id ); |
|
5184
|
|
|
|
|
|
|
} |
|
5185
|
|
|
|
|
|
|
} |
|
5186
|
|
|
|
|
|
|
else { |
|
5187
|
|
|
|
|
|
|
# Optimisation for when the row heights haven't changed. |
|
5188
|
4682
|
|
|
|
|
7740
|
$y_abs += $self->{_default_row_pixels} * $row_start; |
|
5189
|
|
|
|
|
|
|
} |
|
5190
|
|
|
|
|
|
|
|
|
5191
|
4705
|
|
|
|
|
7021
|
$y_abs += $y1; |
|
5192
|
|
|
|
|
|
|
|
|
5193
|
|
|
|
|
|
|
|
|
5194
|
|
|
|
|
|
|
# Adjust start column for offsets that are greater than the col width. |
|
5195
|
4705
|
100
|
|
|
|
10877
|
if ($self->_size_col( $col_start) > 0 ) { |
|
5196
|
4704
|
|
|
|
|
9787
|
while ( $x1 >= $self->_size_col( $col_start ) ) { |
|
5197
|
148
|
|
|
|
|
274
|
$x1 -= $self->_size_col( $col_start ); |
|
5198
|
148
|
|
|
|
|
297
|
$col_start++; |
|
5199
|
|
|
|
|
|
|
} |
|
5200
|
|
|
|
|
|
|
} |
|
5201
|
|
|
|
|
|
|
|
|
5202
|
|
|
|
|
|
|
# Adjust start row for offsets that are greater than the row height. |
|
5203
|
4705
|
100
|
|
|
|
11149
|
if ( $self->_size_row( $row_start ) > 0 ) { |
|
5204
|
4701
|
|
|
|
|
9381
|
while ( $y1 >= $self->_size_row( $row_start ) ) { |
|
5205
|
247
|
|
|
|
|
415
|
$y1 -= $self->_size_row( $row_start ); |
|
5206
|
247
|
|
|
|
|
416
|
$row_start++; |
|
5207
|
|
|
|
|
|
|
} |
|
5208
|
|
|
|
|
|
|
} |
|
5209
|
|
|
|
|
|
|
|
|
5210
|
|
|
|
|
|
|
# Initialise end cell to the same as the start cell. |
|
5211
|
4705
|
|
|
|
|
7993
|
$col_end = $col_start; |
|
5212
|
4705
|
|
|
|
|
7057
|
$row_end = $row_start; |
|
5213
|
|
|
|
|
|
|
|
|
5214
|
|
|
|
|
|
|
# Only offset the image in the cell if the row/col isn't hidden. |
|
5215
|
4705
|
100
|
|
|
|
9139
|
if ($self->_size_col( $col_start) > 0 ) { |
|
5216
|
4704
|
|
|
|
|
7515
|
$width = $width + $x1; |
|
5217
|
|
|
|
|
|
|
} |
|
5218
|
|
|
|
|
|
|
|
|
5219
|
4705
|
100
|
|
|
|
9282
|
if ( $self->_size_row( $row_start ) > 0 ) { |
|
5220
|
4701
|
|
|
|
|
7369
|
$height = $height + $y1; |
|
5221
|
|
|
|
|
|
|
} |
|
5222
|
|
|
|
|
|
|
|
|
5223
|
|
|
|
|
|
|
# Subtract the underlying cell widths to find the end cell of the object. |
|
5224
|
4705
|
|
|
|
|
10239
|
while ( $width >= $self->_size_col( $col_end, $anchor ) ) { |
|
5225
|
11097
|
|
|
|
|
19660
|
$width -= $self->_size_col( $col_end, $anchor ); |
|
5226
|
11097
|
|
|
|
|
18960
|
$col_end++; |
|
5227
|
|
|
|
|
|
|
} |
|
5228
|
|
|
|
|
|
|
|
|
5229
|
|
|
|
|
|
|
|
|
5230
|
|
|
|
|
|
|
# Subtract the underlying cell heights to find the end cell of the object. |
|
5231
|
4705
|
|
|
|
|
9822
|
while ( $height >= $self->_size_row( $row_end, $anchor ) ) { |
|
5232
|
22274
|
|
|
|
|
38207
|
$height -= $self->_size_row( $row_end, $anchor ); |
|
5233
|
22274
|
|
|
|
|
37868
|
$row_end++; |
|
5234
|
|
|
|
|
|
|
} |
|
5235
|
|
|
|
|
|
|
|
|
5236
|
|
|
|
|
|
|
# The end vertices are whatever is left from the width and height. |
|
5237
|
4705
|
|
|
|
|
7859
|
$x2 = $width; |
|
5238
|
4705
|
|
|
|
|
6689
|
$y2 = $height; |
|
5239
|
|
|
|
|
|
|
|
|
5240
|
|
|
|
|
|
|
return ( |
|
5241
|
4705
|
|
|
|
|
14021
|
$col_start, $row_start, $x1, $y1, |
|
5242
|
|
|
|
|
|
|
$col_end, $row_end, $x2, $y2, |
|
5243
|
|
|
|
|
|
|
$x_abs, $y_abs |
|
5244
|
|
|
|
|
|
|
|
|
5245
|
|
|
|
|
|
|
); |
|
5246
|
|
|
|
|
|
|
} |
|
5247
|
|
|
|
|
|
|
|
|
5248
|
|
|
|
|
|
|
|
|
5249
|
|
|
|
|
|
|
############################################################################### |
|
5250
|
|
|
|
|
|
|
# |
|
5251
|
|
|
|
|
|
|
# _position_object_emus() |
|
5252
|
|
|
|
|
|
|
# |
|
5253
|
|
|
|
|
|
|
# Calculate the vertices that define the position of a graphical object within |
|
5254
|
|
|
|
|
|
|
# the worksheet in EMUs. |
|
5255
|
|
|
|
|
|
|
# |
|
5256
|
|
|
|
|
|
|
# The vertices are expressed as English Metric Units (EMUs). There are 12,700 |
|
5257
|
|
|
|
|
|
|
# EMUs per point. Therefore, 12,700 * 3 /4 = 9,525 EMUs per pixel. |
|
5258
|
|
|
|
|
|
|
# |
|
5259
|
|
|
|
|
|
|
sub _position_object_emus { |
|
5260
|
|
|
|
|
|
|
|
|
5261
|
483
|
|
|
483
|
|
1234
|
my $self = shift; |
|
5262
|
|
|
|
|
|
|
|
|
5263
|
|
|
|
|
|
|
my ( |
|
5264
|
483
|
|
|
|
|
2203
|
$col_start, $row_start, $x1, $y1, |
|
5265
|
|
|
|
|
|
|
$col_end, $row_end, $x2, $y2, |
|
5266
|
|
|
|
|
|
|
$x_abs, $y_abs |
|
5267
|
|
|
|
|
|
|
|
|
5268
|
|
|
|
|
|
|
) = $self->_position_object_pixels( @_ ); |
|
5269
|
|
|
|
|
|
|
|
|
5270
|
|
|
|
|
|
|
# Convert the pixel values to EMUs. See above. |
|
5271
|
483
|
|
|
|
|
1866
|
$x1 = int( 0.5 + 9_525 * $x1 ); |
|
5272
|
483
|
|
|
|
|
1306
|
$y1 = int( 0.5 + 9_525 * $y1 ); |
|
5273
|
483
|
|
|
|
|
2268
|
$x2 = int( 0.5 + 9_525 * $x2 ); |
|
5274
|
483
|
|
|
|
|
1317
|
$y2 = int( 0.5 + 9_525 * $y2 ); |
|
5275
|
483
|
|
|
|
|
1265
|
$x_abs = int( 0.5 + 9_525 * $x_abs ); |
|
5276
|
483
|
|
|
|
|
1219
|
$y_abs = int( 0.5 + 9_525 * $y_abs ); |
|
5277
|
|
|
|
|
|
|
|
|
5278
|
|
|
|
|
|
|
return ( |
|
5279
|
483
|
|
|
|
|
2284
|
$col_start, $row_start, $x1, $y1, |
|
5280
|
|
|
|
|
|
|
$col_end, $row_end, $x2, $y2, |
|
5281
|
|
|
|
|
|
|
$x_abs, $y_abs |
|
5282
|
|
|
|
|
|
|
|
|
5283
|
|
|
|
|
|
|
); |
|
5284
|
|
|
|
|
|
|
} |
|
5285
|
|
|
|
|
|
|
|
|
5286
|
|
|
|
|
|
|
|
|
5287
|
|
|
|
|
|
|
############################################################################### |
|
5288
|
|
|
|
|
|
|
# |
|
5289
|
|
|
|
|
|
|
# _position_shape_emus() |
|
5290
|
|
|
|
|
|
|
# |
|
5291
|
|
|
|
|
|
|
# Calculate the vertices that define the position of a shape object within |
|
5292
|
|
|
|
|
|
|
# the worksheet in EMUs. Save the vertices with the object. |
|
5293
|
|
|
|
|
|
|
# |
|
5294
|
|
|
|
|
|
|
# The vertices are expressed as English Metric Units (EMUs). There are 12,700 |
|
5295
|
|
|
|
|
|
|
# EMUs per point. Therefore, 12,700 * 3 /4 = 9,525 EMUs per pixel. |
|
5296
|
|
|
|
|
|
|
# |
|
5297
|
|
|
|
|
|
|
sub _position_shape_emus { |
|
5298
|
|
|
|
|
|
|
|
|
5299
|
41
|
|
|
41
|
|
70
|
my $self = shift; |
|
5300
|
41
|
|
|
|
|
64
|
my $shape = shift; |
|
5301
|
|
|
|
|
|
|
|
|
5302
|
|
|
|
|
|
|
my ( |
|
5303
|
|
|
|
|
|
|
$col_start, $row_start, $x1, $y1, $col_end, |
|
5304
|
|
|
|
|
|
|
$row_end, $x2, $y2, $x_abs, $y_abs |
|
5305
|
|
|
|
|
|
|
) |
|
5306
|
|
|
|
|
|
|
= $self->_position_object_pixels( |
|
5307
|
|
|
|
|
|
|
$shape->{_column_start}, |
|
5308
|
|
|
|
|
|
|
$shape->{_row_start}, |
|
5309
|
|
|
|
|
|
|
$shape->{_x_offset}, |
|
5310
|
|
|
|
|
|
|
$shape->{_y_offset}, |
|
5311
|
|
|
|
|
|
|
$shape->{_width} * $shape->{_scale_x}, |
|
5312
|
|
|
|
|
|
|
$shape->{_height} * $shape->{_scale_y}, |
|
5313
|
|
|
|
|
|
|
$shape->{_drawing} |
|
5314
|
41
|
|
|
|
|
182
|
); |
|
5315
|
|
|
|
|
|
|
|
|
5316
|
|
|
|
|
|
|
# Now that x2/y2 have been calculated with a potentially negative |
|
5317
|
|
|
|
|
|
|
# width/height we use the absolute value and convert to EMUs. |
|
5318
|
41
|
|
|
|
|
129
|
$shape->{_width_emu} = int( abs( $shape->{_width} * 9_525 ) ); |
|
5319
|
41
|
|
|
|
|
98
|
$shape->{_height_emu} = int( abs( $shape->{_height} * 9_525 ) ); |
|
5320
|
|
|
|
|
|
|
|
|
5321
|
41
|
|
|
|
|
106
|
$shape->{_column_start} = int( $col_start ); |
|
5322
|
41
|
|
|
|
|
121
|
$shape->{_row_start} = int( $row_start ); |
|
5323
|
41
|
|
|
|
|
91
|
$shape->{_column_end} = int( $col_end ); |
|
5324
|
41
|
|
|
|
|
77
|
$shape->{_row_end} = int( $row_end ); |
|
5325
|
|
|
|
|
|
|
|
|
5326
|
|
|
|
|
|
|
# Convert the pixel values to EMUs. See above. |
|
5327
|
41
|
|
|
|
|
76
|
$shape->{_x1} = int( $x1 * 9_525 ); |
|
5328
|
41
|
|
|
|
|
66
|
$shape->{_y1} = int( $y1 * 9_525 ); |
|
5329
|
41
|
|
|
|
|
69
|
$shape->{_x2} = int( $x2 * 9_525 ); |
|
5330
|
41
|
|
|
|
|
77
|
$shape->{_y2} = int( $y2 * 9_525 ); |
|
5331
|
41
|
|
|
|
|
66
|
$shape->{_x_abs} = int( $x_abs * 9_525 ); |
|
5332
|
41
|
|
|
|
|
91
|
$shape->{_y_abs} = int( $y_abs * 9_525 ); |
|
5333
|
|
|
|
|
|
|
} |
|
5334
|
|
|
|
|
|
|
|
|
5335
|
|
|
|
|
|
|
############################################################################### |
|
5336
|
|
|
|
|
|
|
# |
|
5337
|
|
|
|
|
|
|
# _size_col($col) |
|
5338
|
|
|
|
|
|
|
# |
|
5339
|
|
|
|
|
|
|
# Convert the width of a cell from user's units to pixels. Excel rounds the |
|
5340
|
|
|
|
|
|
|
# column width to the nearest pixel. If the width hasn't been set by the user |
|
5341
|
|
|
|
|
|
|
# we use the default value. A hidden column is treated as having a width of |
|
5342
|
|
|
|
|
|
|
# zero unless it has the special "object_position" of 4 (size with cells). |
|
5343
|
|
|
|
|
|
|
# |
|
5344
|
|
|
|
|
|
|
sub _size_col { |
|
5345
|
|
|
|
|
|
|
|
|
5346
|
41504
|
|
|
41504
|
|
57710
|
my $self = shift; |
|
5347
|
41504
|
|
|
|
|
54706
|
my $col = shift; |
|
5348
|
41504
|
|
100
|
|
|
95827
|
my $anchor = shift || 0; |
|
5349
|
|
|
|
|
|
|
|
|
5350
|
41504
|
|
|
|
|
55113
|
my $max_digit_width = 7; # For Calabri 11. |
|
5351
|
41504
|
|
|
|
|
53649
|
my $padding = 5; |
|
5352
|
41504
|
|
|
|
|
52864
|
my $pixels; |
|
5353
|
|
|
|
|
|
|
|
|
5354
|
|
|
|
|
|
|
|
|
5355
|
|
|
|
|
|
|
# Look up the cell value to see if it has been changed. |
|
5356
|
41504
|
100
|
|
|
|
70045
|
if ( exists $self->{_col_sizes}->{$col} ) |
|
5357
|
|
|
|
|
|
|
{ |
|
5358
|
170
|
|
|
|
|
305
|
my $width = $self->{_col_sizes}->{$col}[0]; |
|
5359
|
170
|
|
|
|
|
290
|
my $hidden = $self->{_col_sizes}->{$col}[1]; |
|
5360
|
|
|
|
|
|
|
|
|
5361
|
|
|
|
|
|
|
# Convert to pixels. |
|
5362
|
170
|
100
|
100
|
|
|
620
|
if ( $hidden == 1 && $anchor != 4 ) { |
|
|
|
50
|
|
|
|
|
|
|
5363
|
8
|
|
|
|
|
18
|
$pixels = 0; |
|
5364
|
|
|
|
|
|
|
} |
|
5365
|
|
|
|
|
|
|
elsif ( $width < 1 ) { |
|
5366
|
0
|
|
|
|
|
0
|
$pixels = int( $width * ( $max_digit_width + $padding ) + 0.5 ); |
|
5367
|
|
|
|
|
|
|
} |
|
5368
|
|
|
|
|
|
|
else { |
|
5369
|
162
|
|
|
|
|
371
|
$pixels = int( $width * $max_digit_width + 0.5 ) + $padding; |
|
5370
|
|
|
|
|
|
|
} |
|
5371
|
|
|
|
|
|
|
} |
|
5372
|
|
|
|
|
|
|
else { |
|
5373
|
41334
|
|
|
|
|
57114
|
$pixels = $self->{_default_col_pixels}; |
|
5374
|
|
|
|
|
|
|
} |
|
5375
|
|
|
|
|
|
|
|
|
5376
|
41504
|
|
|
|
|
83347
|
return $pixels; |
|
5377
|
|
|
|
|
|
|
} |
|
5378
|
|
|
|
|
|
|
|
|
5379
|
|
|
|
|
|
|
|
|
5380
|
|
|
|
|
|
|
############################################################################### |
|
5381
|
|
|
|
|
|
|
# |
|
5382
|
|
|
|
|
|
|
# _size_row($row) |
|
5383
|
|
|
|
|
|
|
# |
|
5384
|
|
|
|
|
|
|
# Convert the height of a cell from user's units to pixels. If the height |
|
5385
|
|
|
|
|
|
|
# hasn't been set by the user we use the default value. A hidden row is |
|
5386
|
|
|
|
|
|
|
# treated as having a height of zero unless it has the special |
|
5387
|
|
|
|
|
|
|
# "object_position" of 4 (size with cells). |
|
5388
|
|
|
|
|
|
|
# |
|
5389
|
|
|
|
|
|
|
sub _size_row { |
|
5390
|
|
|
|
|
|
|
|
|
5391
|
63994
|
|
|
63994
|
|
89351
|
my $self = shift; |
|
5392
|
63994
|
|
|
|
|
85272
|
my $row = shift; |
|
5393
|
63994
|
|
100
|
|
|
140009
|
my $anchor = shift || 0; |
|
5394
|
63994
|
|
|
|
|
82776
|
my $pixels; |
|
5395
|
|
|
|
|
|
|
|
|
5396
|
|
|
|
|
|
|
# Look up the cell value to see if it has been changed |
|
5397
|
63994
|
100
|
|
|
|
108157
|
if ( exists $self->{_row_sizes}->{$row} ) { |
|
5398
|
84
|
|
|
|
|
161
|
my $height = $self->{_row_sizes}->{$row}[0]; |
|
5399
|
84
|
|
|
|
|
130
|
my $hidden = $self->{_row_sizes}->{$row}[1]; |
|
5400
|
|
|
|
|
|
|
|
|
5401
|
84
|
100
|
100
|
|
|
307
|
if ( $hidden == 1 && $anchor != 4 ) { |
|
5402
|
20
|
|
|
|
|
54
|
$pixels = 0; |
|
5403
|
|
|
|
|
|
|
} |
|
5404
|
|
|
|
|
|
|
else { |
|
5405
|
64
|
|
|
|
|
148
|
$pixels = int( 4 / 3 * $height ); |
|
5406
|
|
|
|
|
|
|
} |
|
5407
|
|
|
|
|
|
|
} |
|
5408
|
|
|
|
|
|
|
else { |
|
5409
|
63910
|
|
|
|
|
96336
|
$pixels = int( 4 / 3 * $self->{_default_row_height} ); |
|
5410
|
|
|
|
|
|
|
} |
|
5411
|
|
|
|
|
|
|
|
|
5412
|
63994
|
|
|
|
|
115920
|
return $pixels; |
|
5413
|
|
|
|
|
|
|
} |
|
5414
|
|
|
|
|
|
|
|
|
5415
|
|
|
|
|
|
|
|
|
5416
|
|
|
|
|
|
|
############################################################################### |
|
5417
|
|
|
|
|
|
|
# |
|
5418
|
|
|
|
|
|
|
# _get_shared_string_index() |
|
5419
|
|
|
|
|
|
|
# |
|
5420
|
|
|
|
|
|
|
# Add a string to the shared string table, if it isn't already there, and |
|
5421
|
|
|
|
|
|
|
# return the string index. |
|
5422
|
|
|
|
|
|
|
# |
|
5423
|
|
|
|
|
|
|
sub _get_shared_string_index { |
|
5424
|
|
|
|
|
|
|
|
|
5425
|
2714
|
|
|
2714
|
|
4437
|
my $self = shift; |
|
5426
|
2714
|
|
|
|
|
4363
|
my $str = shift; |
|
5427
|
|
|
|
|
|
|
|
|
5428
|
|
|
|
|
|
|
# Add the string to the shared string table. |
|
5429
|
2714
|
100
|
|
|
|
4006
|
if ( not exists ${ $self->{_str_table} }->{$str} ) { |
|
|
2714
|
|
|
|
|
7270
|
|
|
5430
|
1123
|
|
|
|
|
1674
|
${ $self->{_str_table} }->{$str} = ${ $self->{_str_unique} }++; |
|
|
1123
|
|
|
|
|
3697
|
|
|
|
1123
|
|
|
|
|
2932
|
|
|
5431
|
|
|
|
|
|
|
} |
|
5432
|
|
|
|
|
|
|
|
|
5433
|
2714
|
|
|
|
|
4573
|
${ $self->{_str_total} }++; |
|
|
2714
|
|
|
|
|
5132
|
|
|
5434
|
2714
|
|
|
|
|
4284
|
my $index = ${ $self->{_str_table} }->{$str}; |
|
|
2714
|
|
|
|
|
5314
|
|
|
5435
|
|
|
|
|
|
|
|
|
5436
|
2714
|
|
|
|
|
5796
|
return $index; |
|
5437
|
|
|
|
|
|
|
} |
|
5438
|
|
|
|
|
|
|
|
|
5439
|
|
|
|
|
|
|
|
|
5440
|
|
|
|
|
|
|
############################################################################### |
|
5441
|
|
|
|
|
|
|
# |
|
5442
|
|
|
|
|
|
|
# _get_drawing_rel_index() |
|
5443
|
|
|
|
|
|
|
# |
|
5444
|
|
|
|
|
|
|
# Get the index used to address a drawing rel link. |
|
5445
|
|
|
|
|
|
|
# |
|
5446
|
|
|
|
|
|
|
sub _get_drawing_rel_index { |
|
5447
|
|
|
|
|
|
|
|
|
5448
|
539
|
|
|
539
|
|
1250
|
my $self = shift; |
|
5449
|
539
|
|
|
|
|
1149
|
my $target = shift; |
|
5450
|
|
|
|
|
|
|
|
|
5451
|
539
|
100
|
|
|
|
2258
|
if ( ! defined $target ) { |
|
|
|
100
|
|
|
|
|
|
|
5452
|
|
|
|
|
|
|
# Undefined values for drawings like charts will always be unique. |
|
5453
|
415
|
|
|
|
|
1567
|
return ++$self->{_drawing_rels_id}; |
|
5454
|
|
|
|
|
|
|
} |
|
5455
|
|
|
|
|
|
|
elsif ( exists $self->{_drawing_rels}->{$target} ) { |
|
5456
|
3
|
|
|
|
|
16
|
return $self->{_drawing_rels}->{$target}; |
|
5457
|
|
|
|
|
|
|
} |
|
5458
|
|
|
|
|
|
|
else { |
|
5459
|
121
|
|
|
|
|
306
|
$self->{_drawing_rels}->{$target} = ++$self->{_drawing_rels_id}; |
|
5460
|
121
|
|
|
|
|
672
|
return $self->{_drawing_rels_id}; |
|
5461
|
|
|
|
|
|
|
} |
|
5462
|
|
|
|
|
|
|
} |
|
5463
|
|
|
|
|
|
|
|
|
5464
|
|
|
|
|
|
|
|
|
5465
|
|
|
|
|
|
|
############################################################################### |
|
5466
|
|
|
|
|
|
|
# |
|
5467
|
|
|
|
|
|
|
# _get_vml_drawing_rel_index() |
|
5468
|
|
|
|
|
|
|
# |
|
5469
|
|
|
|
|
|
|
# Get the index used to address a vml_drawing rel link. |
|
5470
|
|
|
|
|
|
|
# |
|
5471
|
|
|
|
|
|
|
sub _get_vml_drawing_rel_index { |
|
5472
|
|
|
|
|
|
|
|
|
5473
|
44
|
|
|
44
|
|
78
|
my $self = shift; |
|
5474
|
44
|
|
|
|
|
78
|
my $target = shift; |
|
5475
|
|
|
|
|
|
|
|
|
5476
|
44
|
100
|
|
|
|
124
|
if ( exists $self->{_vml_drawing_rels}->{$target} ) { |
|
5477
|
10
|
|
|
|
|
24
|
return $self->{_vml_drawing_rels}->{$target}; |
|
5478
|
|
|
|
|
|
|
} |
|
5479
|
|
|
|
|
|
|
else { |
|
5480
|
34
|
|
|
|
|
88
|
$self->{_vml_drawing_rels}->{$target} = ++$self->{_vml_drawing_rels_id}; |
|
5481
|
34
|
|
|
|
|
90
|
return $self->{_vml_drawing_rels_id}; |
|
5482
|
|
|
|
|
|
|
} |
|
5483
|
|
|
|
|
|
|
} |
|
5484
|
|
|
|
|
|
|
|
|
5485
|
|
|
|
|
|
|
|
|
5486
|
|
|
|
|
|
|
############################################################################### |
|
5487
|
|
|
|
|
|
|
# |
|
5488
|
|
|
|
|
|
|
# insert_chart( $row, $col, $chart, $x, $y, $x_scale, $y_scale ) |
|
5489
|
|
|
|
|
|
|
# |
|
5490
|
|
|
|
|
|
|
# Insert a chart into a worksheet. The $chart argument should be a Chart |
|
5491
|
|
|
|
|
|
|
# object or else it is assumed to be a filename of an external binary file. |
|
5492
|
|
|
|
|
|
|
# The latter is for backwards compatibility. |
|
5493
|
|
|
|
|
|
|
# |
|
5494
|
|
|
|
|
|
|
sub insert_chart { |
|
5495
|
|
|
|
|
|
|
|
|
5496
|
374
|
|
|
374
|
0
|
2963
|
my $self = shift; |
|
5497
|
|
|
|
|
|
|
|
|
5498
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column. |
|
5499
|
374
|
50
|
|
|
|
2315
|
if ( $_[0] =~ /^\D/ ) { |
|
5500
|
374
|
|
|
|
|
1778
|
@_ = $self->_substitute_cellref( @_ ); |
|
5501
|
|
|
|
|
|
|
} |
|
5502
|
|
|
|
|
|
|
|
|
5503
|
374
|
|
|
|
|
1149
|
my $row = $_[0]; |
|
5504
|
374
|
|
|
|
|
938
|
my $col = $_[1]; |
|
5505
|
374
|
|
|
|
|
830
|
my $chart = $_[2]; |
|
5506
|
374
|
|
|
|
|
2427
|
my $x_offset; |
|
5507
|
|
|
|
|
|
|
my $y_offset; |
|
5508
|
374
|
|
|
|
|
0
|
my $x_scale; |
|
5509
|
374
|
|
|
|
|
0
|
my $y_scale; |
|
5510
|
374
|
|
|
|
|
0
|
my $anchor; |
|
5511
|
|
|
|
|
|
|
|
|
5512
|
374
|
50
|
|
|
|
1845
|
croak "Insufficient arguments in insert_chart()" unless @_ >= 3; |
|
5513
|
|
|
|
|
|
|
|
|
5514
|
374
|
50
|
|
|
|
1785
|
if ( ref $chart ) { |
|
5515
|
|
|
|
|
|
|
|
|
5516
|
|
|
|
|
|
|
# Check for a Chart object. |
|
5517
|
374
|
50
|
|
|
|
4257
|
croak "Not a Chart object in insert_chart()" |
|
5518
|
|
|
|
|
|
|
unless $chart->isa( 'Excel::Writer::XLSX::Chart' ); |
|
5519
|
|
|
|
|
|
|
|
|
5520
|
|
|
|
|
|
|
# Check that the chart is an embedded style chart. |
|
5521
|
|
|
|
|
|
|
croak "Not a embedded style Chart object in insert_chart()" |
|
5522
|
374
|
50
|
|
|
|
2213
|
unless $chart->{_embedded}; |
|
5523
|
|
|
|
|
|
|
|
|
5524
|
|
|
|
|
|
|
} |
|
5525
|
|
|
|
|
|
|
|
|
5526
|
374
|
100
|
|
|
|
1742
|
if ( ref $_[3] eq 'HASH' ) { |
|
5527
|
|
|
|
|
|
|
# Newer hashref bashed options. |
|
5528
|
3
|
|
|
|
|
5
|
my $options = $_[3]; |
|
5529
|
3
|
|
50
|
|
|
16
|
$x_offset = $options->{x_offset} || 0; |
|
5530
|
3
|
|
50
|
|
|
13
|
$y_offset = $options->{y_offset} || 0; |
|
5531
|
3
|
|
100
|
|
|
36
|
$x_scale = $options->{x_scale} || 1; |
|
5532
|
3
|
|
100
|
|
|
15
|
$y_scale = $options->{y_scale} || 1; |
|
5533
|
3
|
|
100
|
|
|
12
|
$anchor = $options->{object_position} || 1; |
|
5534
|
|
|
|
|
|
|
} |
|
5535
|
|
|
|
|
|
|
else { |
|
5536
|
|
|
|
|
|
|
# Older parameter based options. |
|
5537
|
371
|
|
100
|
|
|
2459
|
$x_offset = $_[3] || 0; |
|
5538
|
371
|
|
100
|
|
|
2349
|
$y_offset = $_[4] || 0; |
|
5539
|
371
|
|
100
|
|
|
2880
|
$x_scale = $_[5] || 1; |
|
5540
|
371
|
|
100
|
|
|
1880
|
$y_scale = $_[6] || 1; |
|
5541
|
371
|
|
100
|
|
|
1947
|
$anchor = $_[7] || 1; |
|
5542
|
|
|
|
|
|
|
} |
|
5543
|
|
|
|
|
|
|
|
|
5544
|
|
|
|
|
|
|
# Ensure a chart isn't inserted more than once. |
|
5545
|
374
|
50
|
66
|
|
|
3197
|
if ( $chart->{_already_inserted} |
|
|
|
|
33
|
|
|
|
|
|
5546
|
|
|
|
|
|
|
|| $chart->{_combined} && $chart->{_combined}->{_already_inserted} ) |
|
5547
|
|
|
|
|
|
|
{ |
|
5548
|
0
|
|
|
|
|
0
|
carp "Chart cannot be inserted in a worksheet more than once"; |
|
5549
|
0
|
|
|
|
|
0
|
return; |
|
5550
|
|
|
|
|
|
|
} |
|
5551
|
|
|
|
|
|
|
else { |
|
5552
|
374
|
|
|
|
|
997
|
$chart->{_already_inserted} = 1; |
|
5553
|
|
|
|
|
|
|
|
|
5554
|
374
|
100
|
|
|
|
1394
|
if ( $chart->{_combined} ) { |
|
5555
|
10
|
|
|
|
|
34
|
$chart->{_combined}->{_already_inserted} = 1; |
|
5556
|
|
|
|
|
|
|
} |
|
5557
|
|
|
|
|
|
|
} |
|
5558
|
|
|
|
|
|
|
|
|
5559
|
|
|
|
|
|
|
# Use the values set with $chart->set_size(), if any. |
|
5560
|
374
|
100
|
|
|
|
1530
|
$x_scale = $chart->{_x_scale} if $chart->{_x_scale} != 1; |
|
5561
|
374
|
100
|
|
|
|
1379
|
$y_scale = $chart->{_y_scale} if $chart->{_y_scale} != 1; |
|
5562
|
374
|
100
|
|
|
|
1364
|
$x_offset = $chart->{_x_offset} if $chart->{_x_offset}; |
|
5563
|
374
|
100
|
|
|
|
1447
|
$y_offset = $chart->{_y_offset} if $chart->{_y_offset}; |
|
5564
|
|
|
|
|
|
|
|
|
5565
|
374
|
|
|
|
|
868
|
push @{ $self->{_charts} }, |
|
|
374
|
|
|
|
|
2703
|
|
|
5566
|
|
|
|
|
|
|
[ $row, $col, $chart, $x_offset, $y_offset, $x_scale, $y_scale, $anchor ]; |
|
5567
|
|
|
|
|
|
|
} |
|
5568
|
|
|
|
|
|
|
|
|
5569
|
|
|
|
|
|
|
|
|
5570
|
|
|
|
|
|
|
############################################################################### |
|
5571
|
|
|
|
|
|
|
# |
|
5572
|
|
|
|
|
|
|
# _prepare_chart() |
|
5573
|
|
|
|
|
|
|
# |
|
5574
|
|
|
|
|
|
|
# Set up chart/drawings. |
|
5575
|
|
|
|
|
|
|
# |
|
5576
|
|
|
|
|
|
|
sub _prepare_chart { |
|
5577
|
|
|
|
|
|
|
|
|
5578
|
374
|
|
|
374
|
|
982
|
my $self = shift; |
|
5579
|
374
|
|
|
|
|
825
|
my $index = shift; |
|
5580
|
374
|
|
|
|
|
779
|
my $chart_id = shift; |
|
5581
|
374
|
|
|
|
|
873
|
my $drawing_id = shift; |
|
5582
|
374
|
|
|
|
|
834
|
my $drawing_type = 1; |
|
5583
|
374
|
|
|
|
|
781
|
my $drawing; |
|
5584
|
|
|
|
|
|
|
|
|
5585
|
|
|
|
|
|
|
my ( $row, $col, $chart, $x_offset, $y_offset, $x_scale, $y_scale, $anchor ) |
|
5586
|
374
|
|
|
|
|
764
|
= @{ $self->{_charts}->[$index] }; |
|
|
374
|
|
|
|
|
1840
|
|
|
5587
|
|
|
|
|
|
|
|
|
5588
|
374
|
|
|
|
|
1248
|
$chart->{_id} = $chart_id - 1; |
|
5589
|
|
|
|
|
|
|
|
|
5590
|
|
|
|
|
|
|
# Use user specified dimensions, if any. |
|
5591
|
374
|
50
|
|
|
|
1728
|
my $width = $chart->{_width} if $chart->{_width}; |
|
5592
|
374
|
50
|
|
|
|
1504
|
my $height = $chart->{_height} if $chart->{_height}; |
|
5593
|
|
|
|
|
|
|
|
|
5594
|
374
|
|
|
|
|
1403
|
$width = int( 0.5 + ( $width * $x_scale ) ); |
|
5595
|
374
|
|
|
|
|
1045
|
$height = int( 0.5 + ( $height * $y_scale ) ); |
|
5596
|
|
|
|
|
|
|
|
|
5597
|
374
|
|
|
|
|
1883
|
my @dimensions = |
|
5598
|
|
|
|
|
|
|
$self->_position_object_emus( $col, $row, $x_offset, $y_offset, $width, |
|
5599
|
|
|
|
|
|
|
$height, $anchor); |
|
5600
|
|
|
|
|
|
|
|
|
5601
|
|
|
|
|
|
|
# Set the chart name for the embedded object if it has been specified. |
|
5602
|
374
|
|
|
|
|
1224
|
my $name = $chart->{_chart_name}; |
|
5603
|
|
|
|
|
|
|
|
|
5604
|
|
|
|
|
|
|
# Create a Drawing object to use with worksheet unless one already exists. |
|
5605
|
374
|
100
|
|
|
|
1733
|
if ( !$self->{_drawing} ) { |
|
5606
|
|
|
|
|
|
|
|
|
5607
|
362
|
|
|
|
|
3983
|
$drawing = Excel::Writer::XLSX::Drawing->new(); |
|
5608
|
362
|
|
|
|
|
2721
|
$drawing->{_embedded} = 1; |
|
5609
|
362
|
|
|
|
|
1064
|
$self->{_drawing} = $drawing; |
|
5610
|
|
|
|
|
|
|
|
|
5611
|
362
|
|
|
|
|
848
|
push @{ $self->{_external_drawing_links} }, |
|
|
362
|
|
|
|
|
2652
|
|
|
5612
|
|
|
|
|
|
|
[ '/drawing', '../drawings/drawing' . $drawing_id . '.xml' ]; |
|
5613
|
|
|
|
|
|
|
} |
|
5614
|
|
|
|
|
|
|
else { |
|
5615
|
12
|
|
|
|
|
30
|
$drawing = $self->{_drawing}; |
|
5616
|
|
|
|
|
|
|
} |
|
5617
|
|
|
|
|
|
|
|
|
5618
|
374
|
|
|
|
|
2726
|
my $drawing_object = $drawing->_add_drawing_object(); |
|
5619
|
|
|
|
|
|
|
|
|
5620
|
374
|
|
|
|
|
1151
|
$drawing_object->{_type} = $drawing_type; |
|
5621
|
374
|
|
|
|
|
1300
|
$drawing_object->{_dimensions} = \@dimensions; |
|
5622
|
374
|
|
|
|
|
882
|
$drawing_object->{_width} = 0; |
|
5623
|
374
|
|
|
|
|
999
|
$drawing_object->{_height} = 0; |
|
5624
|
374
|
|
|
|
|
947
|
$drawing_object->{_description} = $name; |
|
5625
|
374
|
|
|
|
|
902
|
$drawing_object->{_shape} = undef; |
|
5626
|
374
|
|
|
|
|
927
|
$drawing_object->{_anchor} = $anchor; |
|
5627
|
374
|
|
|
|
|
2126
|
$drawing_object->{_rel_index} = $self->_get_drawing_rel_index(); |
|
5628
|
374
|
|
|
|
|
921
|
$drawing_object->{_url_rel_index} = 0; |
|
5629
|
374
|
|
|
|
|
873
|
$drawing_object->{_tip} = undef; |
|
5630
|
|
|
|
|
|
|
|
|
5631
|
374
|
|
|
|
|
764
|
push @{ $self->{_drawing_links} }, |
|
|
374
|
|
|
|
|
3178
|
|
|
5632
|
|
|
|
|
|
|
[ '/chart', '../charts/chart' . $chart_id . '.xml' ]; |
|
5633
|
|
|
|
|
|
|
} |
|
5634
|
|
|
|
|
|
|
|
|
5635
|
|
|
|
|
|
|
|
|
5636
|
|
|
|
|
|
|
############################################################################### |
|
5637
|
|
|
|
|
|
|
# |
|
5638
|
|
|
|
|
|
|
# _get_range_data |
|
5639
|
|
|
|
|
|
|
# |
|
5640
|
|
|
|
|
|
|
# Returns a range of data from the worksheet _table to be used in chart |
|
5641
|
|
|
|
|
|
|
# cached data. Strings are returned as SST ids and decoded in the workbook. |
|
5642
|
|
|
|
|
|
|
# Return undefs for data that doesn't exist since Excel can chart series |
|
5643
|
|
|
|
|
|
|
# with data missing. |
|
5644
|
|
|
|
|
|
|
# |
|
5645
|
|
|
|
|
|
|
sub _get_range_data { |
|
5646
|
|
|
|
|
|
|
|
|
5647
|
1062
|
|
|
1062
|
|
2097
|
my $self = shift; |
|
5648
|
|
|
|
|
|
|
|
|
5649
|
1062
|
50
|
|
|
|
3053
|
return () if $self->{_optimization}; |
|
5650
|
|
|
|
|
|
|
|
|
5651
|
1062
|
|
|
|
|
1816
|
my @data; |
|
5652
|
1062
|
|
|
|
|
2772
|
my ( $row_start, $col_start, $row_end, $col_end ) = @_; |
|
5653
|
|
|
|
|
|
|
|
|
5654
|
|
|
|
|
|
|
# TODO. Check for worksheet limits. |
|
5655
|
|
|
|
|
|
|
|
|
5656
|
|
|
|
|
|
|
# Iterate through the table data. |
|
5657
|
1062
|
|
|
|
|
2953
|
for my $row_num ( $row_start .. $row_end ) { |
|
5658
|
|
|
|
|
|
|
|
|
5659
|
|
|
|
|
|
|
# Store undef if row doesn't exist. |
|
5660
|
5044
|
100
|
|
|
|
11204
|
if ( !exists $self->{_table}->{$row_num} ) { |
|
5661
|
5
|
|
|
|
|
11
|
push @data, undef; |
|
5662
|
5
|
|
|
|
|
10
|
next; |
|
5663
|
|
|
|
|
|
|
} |
|
5664
|
|
|
|
|
|
|
|
|
5665
|
5039
|
|
|
|
|
8362
|
for my $col_num ( $col_start .. $col_end ) { |
|
5666
|
|
|
|
|
|
|
|
|
5667
|
5039
|
100
|
|
|
|
11583
|
if ( my $cell = $self->{_table}->{$row_num}->{$col_num} ) { |
|
5668
|
|
|
|
|
|
|
|
|
5669
|
5035
|
|
|
|
|
7706
|
my $type = $cell->[0]; |
|
5670
|
5035
|
|
|
|
|
6949
|
my $token = $cell->[1]; |
|
5671
|
|
|
|
|
|
|
|
|
5672
|
|
|
|
|
|
|
|
|
5673
|
5035
|
100
|
|
|
|
9011
|
if ( $type eq 'n' ) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
5674
|
|
|
|
|
|
|
|
|
5675
|
|
|
|
|
|
|
# Store a number. |
|
5676
|
5010
|
|
|
|
|
11538
|
push @data, $token; |
|
5677
|
|
|
|
|
|
|
} |
|
5678
|
|
|
|
|
|
|
elsif ( $type eq 's' ) { |
|
5679
|
|
|
|
|
|
|
|
|
5680
|
|
|
|
|
|
|
# Store a string. |
|
5681
|
25
|
50
|
|
|
|
64
|
if ( $self->{_optimization} == 0 ) { |
|
5682
|
25
|
|
|
|
|
101
|
push @data, { 'sst_id' => $token }; |
|
5683
|
|
|
|
|
|
|
} |
|
5684
|
|
|
|
|
|
|
else { |
|
5685
|
0
|
|
|
|
|
0
|
push @data, $token; |
|
5686
|
|
|
|
|
|
|
} |
|
5687
|
|
|
|
|
|
|
} |
|
5688
|
|
|
|
|
|
|
elsif ( $type eq 'f' ) { |
|
5689
|
|
|
|
|
|
|
|
|
5690
|
|
|
|
|
|
|
# Store a formula. |
|
5691
|
0
|
|
0
|
|
|
0
|
push @data, $cell->[3] || 0; |
|
5692
|
|
|
|
|
|
|
} |
|
5693
|
|
|
|
|
|
|
elsif ( $type eq 'a' ) { |
|
5694
|
|
|
|
|
|
|
|
|
5695
|
|
|
|
|
|
|
# Store an array formula. |
|
5696
|
0
|
|
0
|
|
|
0
|
push @data, $cell->[4] || 0; |
|
5697
|
|
|
|
|
|
|
} |
|
5698
|
|
|
|
|
|
|
elsif ( $type eq 'b' ) { |
|
5699
|
|
|
|
|
|
|
|
|
5700
|
|
|
|
|
|
|
# Store a empty cell. |
|
5701
|
0
|
|
|
|
|
0
|
push @data, ''; |
|
5702
|
|
|
|
|
|
|
} |
|
5703
|
|
|
|
|
|
|
} |
|
5704
|
|
|
|
|
|
|
else { |
|
5705
|
|
|
|
|
|
|
|
|
5706
|
|
|
|
|
|
|
# Store undef if col doesn't exist. |
|
5707
|
4
|
|
|
|
|
23
|
push @data, undef; |
|
5708
|
|
|
|
|
|
|
} |
|
5709
|
|
|
|
|
|
|
} |
|
5710
|
|
|
|
|
|
|
} |
|
5711
|
|
|
|
|
|
|
|
|
5712
|
1062
|
|
|
|
|
4253
|
return @data; |
|
5713
|
|
|
|
|
|
|
} |
|
5714
|
|
|
|
|
|
|
|
|
5715
|
|
|
|
|
|
|
|
|
5716
|
|
|
|
|
|
|
############################################################################### |
|
5717
|
|
|
|
|
|
|
# |
|
5718
|
|
|
|
|
|
|
# insert_image( $row, $col, $filename, $options ) |
|
5719
|
|
|
|
|
|
|
# |
|
5720
|
|
|
|
|
|
|
# Insert an image into the worksheet. |
|
5721
|
|
|
|
|
|
|
# |
|
5722
|
|
|
|
|
|
|
sub insert_image { |
|
5723
|
|
|
|
|
|
|
|
|
5724
|
103
|
|
|
103
|
0
|
1004
|
my $self = shift; |
|
5725
|
|
|
|
|
|
|
|
|
5726
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column. |
|
5727
|
103
|
100
|
|
|
|
612
|
if ( $_[0] =~ /^\D/ ) { |
|
5728
|
101
|
|
|
|
|
474
|
@_ = $self->_substitute_cellref( @_ ); |
|
5729
|
|
|
|
|
|
|
} |
|
5730
|
|
|
|
|
|
|
|
|
5731
|
103
|
|
|
|
|
272
|
my $row = $_[0]; |
|
5732
|
103
|
|
|
|
|
264
|
my $col = $_[1]; |
|
5733
|
103
|
|
|
|
|
312
|
my $image = $_[2]; |
|
5734
|
103
|
|
|
|
|
848
|
my $x_offset; |
|
5735
|
|
|
|
|
|
|
my $y_offset; |
|
5736
|
103
|
|
|
|
|
0
|
my $x_scale; |
|
5737
|
103
|
|
|
|
|
0
|
my $y_scale; |
|
5738
|
103
|
|
|
|
|
0
|
my $anchor; |
|
5739
|
103
|
|
|
|
|
0
|
my $url; |
|
5740
|
103
|
|
|
|
|
0
|
my $tip; |
|
5741
|
|
|
|
|
|
|
|
|
5742
|
103
|
100
|
|
|
|
388
|
if ( ref $_[3] eq 'HASH' ) { |
|
5743
|
|
|
|
|
|
|
# Newer hashref bashed options. |
|
5744
|
24
|
|
|
|
|
46
|
my $options = $_[3]; |
|
5745
|
24
|
|
100
|
|
|
160
|
$x_offset = $options->{x_offset} || 0; |
|
5746
|
24
|
|
100
|
|
|
121
|
$y_offset = $options->{y_offset} || 0; |
|
5747
|
24
|
|
100
|
|
|
115
|
$x_scale = $options->{x_scale} || 1; |
|
5748
|
24
|
|
100
|
|
|
129
|
$y_scale = $options->{y_scale} || 1; |
|
5749
|
24
|
|
100
|
|
|
151
|
$anchor = $options->{object_position} || 2; |
|
5750
|
24
|
|
|
|
|
89
|
$url = $options->{url}; |
|
5751
|
24
|
|
|
|
|
70
|
$tip = $options->{tip}; |
|
5752
|
|
|
|
|
|
|
} |
|
5753
|
|
|
|
|
|
|
else { |
|
5754
|
|
|
|
|
|
|
# Older parameter based options. |
|
5755
|
79
|
|
100
|
|
|
419
|
$x_offset = $_[3] || 0; |
|
5756
|
79
|
|
100
|
|
|
359
|
$y_offset = $_[4] || 0; |
|
5757
|
79
|
|
100
|
|
|
385
|
$x_scale = $_[5] || 1; |
|
5758
|
79
|
|
100
|
|
|
358
|
$y_scale = $_[6] || 1; |
|
5759
|
79
|
|
100
|
|
|
330
|
$anchor = $_[7] || 2; |
|
5760
|
|
|
|
|
|
|
} |
|
5761
|
|
|
|
|
|
|
|
|
5762
|
103
|
50
|
|
|
|
407
|
croak "Insufficient arguments in insert_image()" unless @_ >= 3; |
|
5763
|
103
|
50
|
|
|
|
2215
|
croak "Couldn't locate $image: $!" unless -e $image; |
|
5764
|
|
|
|
|
|
|
|
|
5765
|
103
|
|
|
|
|
312
|
push @{ $self->{_images} }, |
|
|
103
|
|
|
|
|
1170
|
|
|
5766
|
|
|
|
|
|
|
[ |
|
5767
|
|
|
|
|
|
|
$row, $col, $image, $x_offset, $y_offset, |
|
5768
|
|
|
|
|
|
|
$x_scale, $y_scale, $url, $tip, $anchor |
|
5769
|
|
|
|
|
|
|
]; |
|
5770
|
|
|
|
|
|
|
} |
|
5771
|
|
|
|
|
|
|
|
|
5772
|
|
|
|
|
|
|
|
|
5773
|
|
|
|
|
|
|
############################################################################### |
|
5774
|
|
|
|
|
|
|
# |
|
5775
|
|
|
|
|
|
|
# _prepare_image() |
|
5776
|
|
|
|
|
|
|
# |
|
5777
|
|
|
|
|
|
|
# Set up image/drawings. |
|
5778
|
|
|
|
|
|
|
# |
|
5779
|
|
|
|
|
|
|
sub _prepare_image { |
|
5780
|
|
|
|
|
|
|
|
|
5781
|
103
|
|
|
103
|
|
245
|
my $self = shift; |
|
5782
|
103
|
|
|
|
|
228
|
my $index = shift; |
|
5783
|
103
|
|
|
|
|
195
|
my $image_id = shift; |
|
5784
|
103
|
|
|
|
|
191
|
my $drawing_id = shift; |
|
5785
|
103
|
|
|
|
|
188
|
my $width = shift; |
|
5786
|
103
|
|
|
|
|
190
|
my $height = shift; |
|
5787
|
103
|
|
|
|
|
204
|
my $name = shift; |
|
5788
|
103
|
|
|
|
|
197
|
my $image_type = shift; |
|
5789
|
103
|
|
|
|
|
172
|
my $x_dpi = shift; |
|
5790
|
103
|
|
|
|
|
207
|
my $y_dpi = shift; |
|
5791
|
103
|
|
|
|
|
223
|
my $md5 = shift; |
|
5792
|
103
|
|
|
|
|
202
|
my $drawing_type = 2; |
|
5793
|
103
|
|
|
|
|
175
|
my $drawing; |
|
5794
|
|
|
|
|
|
|
|
|
5795
|
|
|
|
|
|
|
my ( |
|
5796
|
|
|
|
|
|
|
$row, $col, $image, $x_offset, $y_offset, |
|
5797
|
|
|
|
|
|
|
$x_scale, $y_scale, $url, $tip, $anchor |
|
5798
|
103
|
|
|
|
|
186
|
) = @{ $self->{_images}->[$index] }; |
|
|
103
|
|
|
|
|
454
|
|
|
5799
|
|
|
|
|
|
|
|
|
5800
|
103
|
|
|
|
|
215
|
$width *= $x_scale; |
|
5801
|
103
|
|
|
|
|
212
|
$height *= $y_scale; |
|
5802
|
|
|
|
|
|
|
|
|
5803
|
103
|
|
|
|
|
317
|
$width *= 96 / $x_dpi; |
|
5804
|
103
|
|
|
|
|
242
|
$height *= 96 / $y_dpi; |
|
5805
|
|
|
|
|
|
|
|
|
5806
|
103
|
|
|
|
|
435
|
my @dimensions = |
|
5807
|
|
|
|
|
|
|
$self->_position_object_emus( $col, $row, $x_offset, $y_offset, $width, |
|
5808
|
|
|
|
|
|
|
$height, $anchor); |
|
5809
|
|
|
|
|
|
|
|
|
5810
|
|
|
|
|
|
|
# Convert from pixels to emus. |
|
5811
|
103
|
|
|
|
|
315
|
$width = int( 0.5 + ( $width * 9_525 ) ); |
|
5812
|
103
|
|
|
|
|
290
|
$height = int( 0.5 + ( $height * 9_525 ) ); |
|
5813
|
|
|
|
|
|
|
|
|
5814
|
|
|
|
|
|
|
# Create a Drawing object to use with worksheet unless one already exists. |
|
5815
|
103
|
100
|
|
|
|
540
|
if ( !$self->{_drawing} ) { |
|
5816
|
|
|
|
|
|
|
|
|
5817
|
77
|
|
|
|
|
797
|
$drawing = Excel::Writer::XLSX::Drawing->new(); |
|
5818
|
77
|
|
|
|
|
672
|
$drawing->{_embedded} = 1; |
|
5819
|
77
|
|
|
|
|
232
|
$self->{_drawing} = $drawing; |
|
5820
|
|
|
|
|
|
|
|
|
5821
|
77
|
|
|
|
|
187
|
push @{ $self->{_external_drawing_links} }, |
|
|
77
|
|
|
|
|
541
|
|
|
5822
|
|
|
|
|
|
|
[ '/drawing', '../drawings/drawing' . $drawing_id . '.xml' ]; |
|
5823
|
|
|
|
|
|
|
} |
|
5824
|
|
|
|
|
|
|
else { |
|
5825
|
26
|
|
|
|
|
53
|
$drawing = $self->{_drawing}; |
|
5826
|
|
|
|
|
|
|
} |
|
5827
|
|
|
|
|
|
|
|
|
5828
|
103
|
|
|
|
|
505
|
my $drawing_object = $drawing->_add_drawing_object(); |
|
5829
|
|
|
|
|
|
|
|
|
5830
|
103
|
|
|
|
|
281
|
$drawing_object->{_type} = $drawing_type; |
|
5831
|
103
|
|
|
|
|
290
|
$drawing_object->{_dimensions} = \@dimensions; |
|
5832
|
103
|
|
|
|
|
265
|
$drawing_object->{_width} = $width; |
|
5833
|
103
|
|
|
|
|
243
|
$drawing_object->{_height} = $height; |
|
5834
|
103
|
|
|
|
|
267
|
$drawing_object->{_description} = $name; |
|
5835
|
103
|
|
|
|
|
209
|
$drawing_object->{_shape} = undef; |
|
5836
|
103
|
|
|
|
|
253
|
$drawing_object->{_anchor} = $anchor; |
|
5837
|
103
|
|
|
|
|
244
|
$drawing_object->{_rel_index} = 0; |
|
5838
|
103
|
|
|
|
|
204
|
$drawing_object->{_url_rel_index} = 0; |
|
5839
|
103
|
|
|
|
|
223
|
$drawing_object->{_tip} = $tip; |
|
5840
|
|
|
|
|
|
|
|
|
5841
|
|
|
|
|
|
|
|
|
5842
|
103
|
100
|
|
|
|
338
|
if ( $url ) { |
|
5843
|
21
|
|
|
|
|
52
|
my $rel_type = '/hyperlink'; |
|
5844
|
21
|
|
|
|
|
44
|
my $target_mode = 'External'; |
|
5845
|
21
|
|
|
|
|
41
|
my $target; |
|
5846
|
|
|
|
|
|
|
|
|
5847
|
21
|
100
|
100
|
|
|
204
|
if ( $url =~ m{^[fh]tt?ps?://} || $url =~ m{^mailto:} ) { |
|
5848
|
16
|
|
|
|
|
70
|
$target = _escape_url( $url ); |
|
5849
|
|
|
|
|
|
|
} |
|
5850
|
|
|
|
|
|
|
|
|
5851
|
21
|
100
|
|
|
|
111
|
if ( $url =~ s{^external:}{file:///} ) { |
|
5852
|
3
|
|
|
|
|
26
|
$target = _escape_url( $url ); |
|
5853
|
|
|
|
|
|
|
|
|
5854
|
|
|
|
|
|
|
# Additional escape not required in worksheet hyperlinks. |
|
5855
|
3
|
|
|
|
|
11
|
$target =~ s/#/%23/g; |
|
5856
|
|
|
|
|
|
|
} |
|
5857
|
|
|
|
|
|
|
|
|
5858
|
21
|
100
|
|
|
|
84
|
if ( $url =~ s/^internal:/#/ ) { |
|
5859
|
2
|
|
|
|
|
4
|
$target = $url; |
|
5860
|
2
|
|
|
|
|
4
|
$target_mode = undef; |
|
5861
|
|
|
|
|
|
|
} |
|
5862
|
|
|
|
|
|
|
|
|
5863
|
21
|
|
|
|
|
56
|
my $max_url = $self->{_max_url_length}; |
|
5864
|
21
|
50
|
|
|
|
88
|
if ( length $target > $max_url ) { |
|
5865
|
0
|
|
|
|
|
0
|
carp "Ignoring URL '$url' where link or anchor > $max_url characters " |
|
5866
|
|
|
|
|
|
|
. "since it exceeds Excel's limit for URLS. See LIMITATIONS " |
|
5867
|
|
|
|
|
|
|
. "section of the Excel::Writer::XLSX documentation."; |
|
5868
|
|
|
|
|
|
|
} |
|
5869
|
|
|
|
|
|
|
else { |
|
5870
|
21
|
100
|
66
|
|
|
130
|
if ( $target && !exists $self->{_drawing_rels}->{$url} ) { |
|
5871
|
20
|
|
|
|
|
48
|
push @{ $self->{_drawing_links} }, |
|
|
20
|
|
|
|
|
87
|
|
|
5872
|
|
|
|
|
|
|
[ $rel_type, $target, $target_mode ]; |
|
5873
|
|
|
|
|
|
|
} |
|
5874
|
|
|
|
|
|
|
|
|
5875
|
|
|
|
|
|
|
$drawing_object->{_url_rel_index} = |
|
5876
|
21
|
|
|
|
|
74
|
$self->_get_drawing_rel_index( $url ); |
|
5877
|
|
|
|
|
|
|
} |
|
5878
|
|
|
|
|
|
|
} |
|
5879
|
|
|
|
|
|
|
|
|
5880
|
103
|
100
|
|
|
|
469
|
if ( !exists $self->{_drawing_rels}->{$md5} ) { |
|
5881
|
101
|
|
|
|
|
213
|
push @{ $self->{_drawing_links} }, |
|
|
101
|
|
|
|
|
552
|
|
|
5882
|
|
|
|
|
|
|
[ '/image', '../media/image' . $image_id . '.' . $image_type ]; |
|
5883
|
|
|
|
|
|
|
} |
|
5884
|
|
|
|
|
|
|
|
|
5885
|
103
|
|
|
|
|
464
|
$drawing_object->{_rel_index} = $self->_get_drawing_rel_index( $md5 ); |
|
5886
|
|
|
|
|
|
|
} |
|
5887
|
|
|
|
|
|
|
|
|
5888
|
|
|
|
|
|
|
|
|
5889
|
|
|
|
|
|
|
############################################################################### |
|
5890
|
|
|
|
|
|
|
# |
|
5891
|
|
|
|
|
|
|
# _prepare_header_image() |
|
5892
|
|
|
|
|
|
|
# |
|
5893
|
|
|
|
|
|
|
# Set up an image without a drawing object for header/footer images. |
|
5894
|
|
|
|
|
|
|
# |
|
5895
|
|
|
|
|
|
|
sub _prepare_header_image { |
|
5896
|
|
|
|
|
|
|
|
|
5897
|
44
|
|
|
44
|
|
85
|
my $self = shift; |
|
5898
|
44
|
|
|
|
|
75
|
my $image_id = shift; |
|
5899
|
44
|
|
|
|
|
76
|
my $width = shift; |
|
5900
|
44
|
|
|
|
|
76
|
my $height = shift; |
|
5901
|
44
|
|
|
|
|
75
|
my $name = shift; |
|
5902
|
44
|
|
|
|
|
78
|
my $image_type = shift; |
|
5903
|
44
|
|
|
|
|
72
|
my $position = shift; |
|
5904
|
44
|
|
|
|
|
71
|
my $x_dpi = shift; |
|
5905
|
44
|
|
|
|
|
70
|
my $y_dpi = shift; |
|
5906
|
44
|
|
|
|
|
69
|
my $md5 = shift; |
|
5907
|
|
|
|
|
|
|
|
|
5908
|
|
|
|
|
|
|
# Strip the extension from the filename. |
|
5909
|
44
|
|
|
|
|
286
|
$name =~ s/\.[^\.]+$//; |
|
5910
|
|
|
|
|
|
|
|
|
5911
|
44
|
100
|
|
|
|
169
|
if ( !exists $self->{_vml_drawing_rels}->{$md5} ) { |
|
5912
|
34
|
|
|
|
|
57
|
push @{ $self->{_vml_drawing_links} }, |
|
|
34
|
|
|
|
|
169
|
|
|
5913
|
|
|
|
|
|
|
[ '/image', '../media/image' . $image_id . '.' . $image_type ]; |
|
5914
|
|
|
|
|
|
|
} |
|
5915
|
|
|
|
|
|
|
|
|
5916
|
44
|
|
|
|
|
142
|
my $ref_id = $self->_get_vml_drawing_rel_index( $md5 ); |
|
5917
|
|
|
|
|
|
|
|
|
5918
|
44
|
|
|
|
|
80
|
push @{ $self->{_header_images_array} }, |
|
|
44
|
|
|
|
|
232
|
|
|
5919
|
|
|
|
|
|
|
[ $width, $height, $name, $position, $x_dpi, $y_dpi, $ref_id ]; |
|
5920
|
|
|
|
|
|
|
} |
|
5921
|
|
|
|
|
|
|
|
|
5922
|
|
|
|
|
|
|
|
|
5923
|
|
|
|
|
|
|
############################################################################### |
|
5924
|
|
|
|
|
|
|
# |
|
5925
|
|
|
|
|
|
|
# insert_shape( $row, $col, $shape, $x, $y, $x_scale, $y_scale ) |
|
5926
|
|
|
|
|
|
|
# |
|
5927
|
|
|
|
|
|
|
# Insert a shape into the worksheet. |
|
5928
|
|
|
|
|
|
|
# |
|
5929
|
|
|
|
|
|
|
sub insert_shape { |
|
5930
|
|
|
|
|
|
|
|
|
5931
|
45
|
|
|
45
|
0
|
211
|
my $self = shift; |
|
5932
|
|
|
|
|
|
|
|
|
5933
|
|
|
|
|
|
|
# Check for a cell reference in A1 notation and substitute row and column. |
|
5934
|
45
|
100
|
|
|
|
196
|
if ( $_[0] =~ /^\D/ ) { |
|
5935
|
41
|
|
|
|
|
136
|
@_ = $self->_substitute_cellref( @_ ); |
|
5936
|
|
|
|
|
|
|
} |
|
5937
|
|
|
|
|
|
|
|
|
5938
|
|
|
|
|
|
|
# Check the number of arguments. |
|
5939
|
45
|
50
|
|
|
|
451
|
croak "Insufficient arguments in insert_shape()" unless @_ >= 3; |
|
5940
|
|
|
|
|
|
|
|
|
5941
|
45
|
|
|
|
|
96
|
my $shape = $_[2]; |
|
5942
|
|
|
|
|
|
|
|
|
5943
|
|
|
|
|
|
|
# Verify we are being asked to insert a "shape" object. |
|
5944
|
45
|
50
|
|
|
|
312
|
croak "Not a Shape object in insert_shape()" |
|
5945
|
|
|
|
|
|
|
unless $shape->isa( 'Excel::Writer::XLSX::Shape' ); |
|
5946
|
|
|
|
|
|
|
|
|
5947
|
|
|
|
|
|
|
# Set the shape properties. |
|
5948
|
45
|
|
|
|
|
173
|
$shape->{_row_start} = $_[0]; |
|
5949
|
45
|
|
|
|
|
78
|
$shape->{_column_start} = $_[1]; |
|
5950
|
45
|
|
100
|
|
|
136
|
$shape->{_x_offset} = $_[3] || 0; |
|
5951
|
45
|
|
100
|
|
|
124
|
$shape->{_y_offset} = $_[4] || 0; |
|
5952
|
|
|
|
|
|
|
|
|
5953
|
|
|
|
|
|
|
# Override shape scale if supplied as an argument. Otherwise, use the |
|
5954
|
|
|
|
|
|
|
# existing shape scale factors. |
|
5955
|
45
|
100
|
|
|
|
104
|
$shape->{_scale_x} = $_[5] if defined $_[5]; |
|
5956
|
45
|
100
|
|
|
|
98
|
$shape->{_scale_y} = $_[6] if defined $_[6]; |
|
5957
|
45
|
|
50
|
|
|
164
|
$shape->{_anchor} = $_[7] || 1; |
|
5958
|
|
|
|
|
|
|
|
|
5959
|
|
|
|
|
|
|
# Assign a shape ID. |
|
5960
|
45
|
|
|
|
|
156
|
my $needs_id = 1; |
|
5961
|
45
|
|
|
|
|
102
|
while ( $needs_id ) { |
|
5962
|
90
|
|
100
|
|
|
229
|
my $id = $shape->{_id} || 0; |
|
5963
|
90
|
100
|
|
|
|
234
|
my $used = exists $self->{_shape_hash}->{$id} ? 1 : 0; |
|
5964
|
|
|
|
|
|
|
|
|
5965
|
|
|
|
|
|
|
# Test if shape ID is already used. Otherwise assign a new one. |
|
5966
|
90
|
100
|
100
|
|
|
299
|
if ( !$used && $id != 0 ) { |
|
5967
|
45
|
|
|
|
|
107
|
$needs_id = 0; |
|
5968
|
|
|
|
|
|
|
} |
|
5969
|
|
|
|
|
|
|
else { |
|
5970
|
45
|
|
|
|
|
121
|
$shape->{_id} = ++$self->{_last_shape_id}; |
|
5971
|
|
|
|
|
|
|
} |
|
5972
|
|
|
|
|
|
|
} |
|
5973
|
|
|
|
|
|
|
|
|
5974
|
45
|
|
|
|
|
71
|
$shape->{_element} = $#{ $self->{_shapes} } + 1; |
|
|
45
|
|
|
|
|
114
|
|
|
5975
|
|
|
|
|
|
|
|
|
5976
|
|
|
|
|
|
|
# Allow lookup of entry into shape array by shape ID. |
|
5977
|
45
|
|
|
|
|
162
|
$self->{_shape_hash}->{ $shape->{_id} } = $shape->{_element}; |
|
5978
|
|
|
|
|
|
|
|
|
5979
|
|
|
|
|
|
|
# Create link to Worksheet color palette. |
|
5980
|
45
|
|
|
|
|
83
|
$shape->{_palette} = $self->{_palette}; |
|
5981
|
|
|
|
|
|
|
|
|
5982
|
45
|
50
|
|
|
|
104
|
if ( $shape->{_stencil} ) { |
|
5983
|
|
|
|
|
|
|
|
|
5984
|
|
|
|
|
|
|
# Insert a copy of the shape, not a reference so that the shape is |
|
5985
|
|
|
|
|
|
|
# used as a stencil. Previously stamped copies don't get modified |
|
5986
|
|
|
|
|
|
|
# if the stencil is modified. |
|
5987
|
45
|
|
|
|
|
66
|
my $insert = { %{$shape} }; |
|
|
45
|
|
|
|
|
880
|
|
|
5988
|
|
|
|
|
|
|
|
|
5989
|
|
|
|
|
|
|
# For connectors change x/y coords based on location of connected shapes. |
|
5990
|
45
|
|
|
|
|
249
|
$self->_auto_locate_connectors( $insert ); |
|
5991
|
|
|
|
|
|
|
|
|
5992
|
|
|
|
|
|
|
# Bless the copy into this class, so AUTOLOADED _get, _set methods |
|
5993
|
|
|
|
|
|
|
#still work on the child. |
|
5994
|
45
|
|
|
|
|
113
|
bless $insert, ref $shape; |
|
5995
|
|
|
|
|
|
|
|
|
5996
|
45
|
|
|
|
|
76
|
push @{ $self->{_shapes} }, $insert; |
|
|
45
|
|
|
|
|
103
|
|
|
5997
|
45
|
|
|
|
|
157
|
return $insert; |
|
5998
|
|
|
|
|
|
|
} |
|
5999
|
|
|
|
|
|
|
else { |
|
6000
|
|
|
|
|
|
|
|
|
6001
|
|
|
|
|
|
|
# For connectors change x/y coords based on location of connected shapes. |
|
6002
|
0
|
|
|
|
|
0
|
$self->_auto_locate_connectors( $shape ); |
|
6003
|
|
|
|
|
|
|
|
|
6004
|
|
|
|
|
|
|
# Insert a link to the shape on the list of shapes. Connection to |
|
6005
|
|
|
|
|
|
|
# the parent shape is maintained |
|
6006
|
0
|
|
|
|
|
0
|
push @{ $self->{_shapes} }, $shape; |
|
|
0
|
|
|
|
|
0
|
|
|
6007
|
0
|
|
|
|
|
0
|
return $shape; |
|
6008
|
|
|
|
|
|
|
} |
|
6009
|
|
|
|
|
|
|
} |
|
6010
|
|
|
|
|
|
|
|
|
6011
|
|
|
|
|
|
|
|
|
6012
|
|
|
|
|
|
|
############################################################################### |
|
6013
|
|
|
|
|
|
|
# |
|
6014
|
|
|
|
|
|
|
# _prepare_shape() |
|
6015
|
|
|
|
|
|
|
# |
|
6016
|
|
|
|
|
|
|
# Set up drawing shapes |
|
6017
|
|
|
|
|
|
|
# |
|
6018
|
|
|
|
|
|
|
sub _prepare_shape { |
|
6019
|
|
|
|
|
|
|
|
|
6020
|
41
|
|
|
41
|
|
89
|
my $self = shift; |
|
6021
|
41
|
|
|
|
|
70
|
my $index = shift; |
|
6022
|
41
|
|
|
|
|
70
|
my $drawing_id = shift; |
|
6023
|
41
|
|
|
|
|
79
|
my $shape = $self->{_shapes}->[$index]; |
|
6024
|
41
|
|
|
|
|
59
|
my $drawing; |
|
6025
|
41
|
|
|
|
|
65
|
my $drawing_type = 3; |
|
6026
|
|
|
|
|
|
|
|
|
6027
|
|
|
|
|
|
|
# Create a Drawing object to use with worksheet unless one already exists. |
|
6028
|
41
|
100
|
|
|
|
110
|
if ( !$self->{_drawing} ) { |
|
6029
|
|
|
|
|
|
|
|
|
6030
|
10
|
|
|
|
|
100
|
$drawing = Excel::Writer::XLSX::Drawing->new(); |
|
6031
|
10
|
|
|
|
|
71
|
$drawing->{_embedded} = 1; |
|
6032
|
10
|
|
|
|
|
29
|
$self->{_drawing} = $drawing; |
|
6033
|
|
|
|
|
|
|
|
|
6034
|
10
|
|
|
|
|
20
|
push @{ $self->{_external_drawing_links} }, |
|
|
10
|
|
|
|
|
63
|
|
|
6035
|
|
|
|
|
|
|
[ '/drawing', '../drawings/drawing' . $drawing_id . '.xml' ]; |
|
6036
|
|
|
|
|
|
|
|
|
6037
|
10
|
|
|
|
|
36
|
$self->{_has_shapes} = 1; |
|
6038
|
|
|
|
|
|
|
} |
|
6039
|
|
|
|
|
|
|
else { |
|
6040
|
31
|
|
|
|
|
49
|
$drawing = $self->{_drawing}; |
|
6041
|
|
|
|
|
|
|
} |
|
6042
|
|
|
|
|
|
|
|
|
6043
|
|
|
|
|
|
|
# Validate the he shape against various rules. |
|
6044
|
41
|
|
|
|
|
188
|
$self->_validate_shape( $shape, $index ); |
|
6045
|
|
|
|
|
|
|
|
|
6046
|
41
|
|
|
|
|
143
|
$self->_position_shape_emus( $shape ); |
|
6047
|
|
|
|
|
|
|
|
|
6048
|
|
|
|
|
|
|
my @dimensions = ( |
|
6049
|
|
|
|
|
|
|
$shape->{_column_start}, $shape->{_row_start}, |
|
6050
|
|
|
|
|
|
|
$shape->{_x1}, $shape->{_y1}, |
|
6051
|
|
|
|
|
|
|
$shape->{_column_end}, $shape->{_row_end}, |
|
6052
|
|
|
|
|
|
|
$shape->{_x2}, $shape->{_y2}, |
|
6053
|
|
|
|
|
|
|
$shape->{_x_abs}, $shape->{_y_abs}, |
|
6054
|
41
|
|
|
|
|
164
|
); |
|
6055
|
|
|
|
|
|
|
|
|
6056
|
41
|
|
|
|
|
169
|
my $drawing_object = $drawing->_add_drawing_object(); |
|
6057
|
|
|
|
|
|
|
|
|
6058
|
41
|
|
|
|
|
87
|
$drawing_object->{_type} = $drawing_type; |
|
6059
|
41
|
|
|
|
|
87
|
$drawing_object->{_dimensions} = \@dimensions; |
|
6060
|
41
|
|
|
|
|
76
|
$drawing_object->{_width} = $shape->{_width_emu}; |
|
6061
|
41
|
|
|
|
|
72
|
$drawing_object->{_height} = $shape->{_height_emu}; |
|
6062
|
41
|
|
|
|
|
72
|
$drawing_object->{_description} = $shape->{_name}; |
|
6063
|
41
|
|
|
|
|
75
|
$drawing_object->{_shape} = $shape; |
|
6064
|
41
|
|
|
|
|
71
|
$drawing_object->{_anchor} = $shape->{_anchor}; |
|
6065
|
41
|
|
|
|
|
148
|
$drawing_object->{_rel_index} = $self->_get_drawing_rel_index(); |
|
6066
|
41
|
|
|
|
|
88
|
$drawing_object->{_url_rel_index} = 0; |
|
6067
|
41
|
|
|
|
|
135
|
$drawing_object->{_tip} = undef; |
|
6068
|
|
|
|
|
|
|
} |
|
6069
|
|
|
|
|
|
|
|
|
6070
|
|
|
|
|
|
|
|
|
6071
|
|
|
|
|
|
|
############################################################################### |
|
6072
|
|
|
|
|
|
|
# |
|
6073
|
|
|
|
|
|
|
# _auto_locate_connectors() |
|
6074
|
|
|
|
|
|
|
# |
|
6075
|
|
|
|
|
|
|
# Re-size connector shapes if they are connected to other shapes. |
|
6076
|
|
|
|
|
|
|
# |
|
6077
|
|
|
|
|
|
|
sub _auto_locate_connectors { |
|
6078
|
|
|
|
|
|
|
|
|
6079
|
45
|
|
|
45
|
|
75
|
my $self = shift; |
|
6080
|
45
|
|
|
|
|
73
|
my $shape = shift; |
|
6081
|
|
|
|
|
|
|
|
|
6082
|
|
|
|
|
|
|
# Valid connector shapes. |
|
6083
|
45
|
|
|
|
|
203
|
my $connector_shapes = { |
|
6084
|
|
|
|
|
|
|
straightConnector => 1, |
|
6085
|
|
|
|
|
|
|
Connector => 1, |
|
6086
|
|
|
|
|
|
|
bentConnector => 1, |
|
6087
|
|
|
|
|
|
|
curvedConnector => 1, |
|
6088
|
|
|
|
|
|
|
line => 1, |
|
6089
|
|
|
|
|
|
|
}; |
|
6090
|
|
|
|
|
|
|
|
|
6091
|
45
|
|
|
|
|
98
|
my $shape_base = $shape->{_type}; |
|
6092
|
|
|
|
|
|
|
|
|
6093
|
|
|
|
|
|
|
# Remove the number of segments from end of type. |
|
6094
|
45
|
|
|
|
|
98
|
chop $shape_base; |
|
6095
|
|
|
|
|
|
|
|
|
6096
|
45
|
100
|
|
|
|
115
|
$shape->{_connect} = $connector_shapes->{$shape_base} ? 1 : 0; |
|
6097
|
|
|
|
|
|
|
|
|
6098
|
45
|
100
|
|
|
|
162
|
return unless $shape->{_connect}; |
|
6099
|
|
|
|
|
|
|
|
|
6100
|
|
|
|
|
|
|
# Both ends have to be connected to size it. |
|
6101
|
12
|
50
|
33
|
|
|
88
|
return unless ( $shape->{_start} and $shape->{_end} ); |
|
6102
|
|
|
|
|
|
|
|
|
6103
|
|
|
|
|
|
|
# Both ends need to provide info about where to connect. |
|
6104
|
12
|
50
|
33
|
|
|
52
|
return unless ( $shape->{_start_side} and $shape->{_end_side} ); |
|
6105
|
|
|
|
|
|
|
|
|
6106
|
12
|
|
|
|
|
26
|
my $sid = $shape->{_start}; |
|
6107
|
12
|
|
|
|
|
26
|
my $eid = $shape->{_end}; |
|
6108
|
|
|
|
|
|
|
|
|
6109
|
12
|
|
|
|
|
32
|
my $slink_id = $self->{_shape_hash}->{$sid}; |
|
6110
|
12
|
|
|
|
|
29
|
my ( $sls, $els ); |
|
6111
|
12
|
100
|
|
|
|
48
|
if ( defined $slink_id ) { |
|
6112
|
11
|
|
|
|
|
24
|
$sls = $self->{_shapes}->[$slink_id]; # Start linked shape. |
|
6113
|
|
|
|
|
|
|
} |
|
6114
|
|
|
|
|
|
|
else { |
|
6115
|
1
|
|
|
|
|
11
|
warn "missing start connection for '$shape->{_name}', id=$sid\n"; |
|
6116
|
1
|
|
|
|
|
8
|
return; |
|
6117
|
|
|
|
|
|
|
} |
|
6118
|
|
|
|
|
|
|
|
|
6119
|
11
|
|
|
|
|
32
|
my $elink_id = $self->{_shape_hash}->{$eid}; |
|
6120
|
11
|
100
|
|
|
|
46
|
if ( defined $elink_id ) { |
|
6121
|
10
|
|
|
|
|
20
|
$els = $self->{_shapes}->[$elink_id]; # Start linked shape. |
|
6122
|
|
|
|
|
|
|
} |
|
6123
|
|
|
|
|
|
|
else { |
|
6124
|
1
|
|
|
|
|
10
|
warn "missing end connection for '$shape->{_name}', id=$eid\n"; |
|
6125
|
1
|
|
|
|
|
7
|
return; |
|
6126
|
|
|
|
|
|
|
} |
|
6127
|
|
|
|
|
|
|
|
|
6128
|
|
|
|
|
|
|
# Assume shape connections are to the middle of an object, and |
|
6129
|
|
|
|
|
|
|
# not a corner (for now). |
|
6130
|
10
|
|
|
|
|
28
|
my $connect_type = $shape->{_start_side} . $shape->{_end_side}; |
|
6131
|
10
|
|
|
|
|
36
|
my $smidx = $sls->{_x_offset} + $sls->{_width} / 2; |
|
6132
|
10
|
|
|
|
|
28
|
my $emidx = $els->{_x_offset} + $els->{_width} / 2; |
|
6133
|
10
|
|
|
|
|
22
|
my $smidy = $sls->{_y_offset} + $sls->{_height} / 2; |
|
6134
|
10
|
|
|
|
|
35
|
my $emidy = $els->{_y_offset} + $els->{_height} / 2; |
|
6135
|
10
|
|
|
|
|
24
|
my $netx = abs( $smidx - $emidx ); |
|
6136
|
10
|
|
|
|
|
17
|
my $nety = abs( $smidy - $emidy ); |
|
6137
|
|
|
|
|
|
|
|
|
6138
|
10
|
100
|
|
|
|
38
|
if ( $connect_type eq 'bt' ) { |
|
|
|
50
|
|
|
|
|
|
|
6139
|
5
|
|
|
|
|
11
|
my $sy = $sls->{_y_offset} + $sls->{_height}; |
|
6140
|
5
|
|
|
|
|
9
|
my $ey = $els->{_y_offset}; |
|
6141
|
|
|
|
|
|
|
|
|
6142
|
5
|
|
|
|
|
11
|
$shape->{_width} = abs( int( $emidx - $smidx ) ); |
|
6143
|
5
|
|
|
|
|
20
|
$shape->{_x_offset} = int( min( $smidx, $emidx ) ); |
|
6144
|
|
|
|
|
|
|
$shape->{_height} = |
|
6145
|
|
|
|
|
|
|
abs( |
|
6146
|
5
|
|
|
|
|
14
|
int( $els->{_y_offset} - ( $sls->{_y_offset} + $sls->{_height} ) ) |
|
6147
|
|
|
|
|
|
|
); |
|
6148
|
|
|
|
|
|
|
$shape->{_y_offset} = int( |
|
6149
|
5
|
|
|
|
|
16
|
min( ( $sls->{_y_offset} + $sls->{_height} ), $els->{_y_offset} ) ); |
|
6150
|
5
|
100
|
|
|
|
13
|
$shape->{_flip_h} = ( $smidx < $emidx ) ? 1 : 0; |
|
6151
|
5
|
|
|
|
|
10
|
$shape->{_rotation} = 90; |
|
6152
|
|
|
|
|
|
|
|
|
6153
|
5
|
100
|
|
|
|
20
|
if ( $sy > $ey ) { |
|
6154
|
2
|
|
|
|
|
6
|
$shape->{_flip_v} = 1; |
|
6155
|
|
|
|
|
|
|
|
|
6156
|
|
|
|
|
|
|
# Create 3 adjustments for an end shape vertically above a |
|
6157
|
|
|
|
|
|
|
# start shape. Adjustments count from the upper left object. |
|
6158
|
2
|
100
|
|
|
|
5
|
if ( $#{ $shape->{_adjustments} } < 0 ) { |
|
|
2
|
|
|
|
|
8
|
|
|
6159
|
1
|
|
|
|
|
4
|
$shape->{_adjustments} = [ -10, 50, 110 ]; |
|
6160
|
|
|
|
|
|
|
} |
|
6161
|
|
|
|
|
|
|
|
|
6162
|
2
|
|
|
|
|
6
|
$shape->{_type} = 'bentConnector5'; |
|
6163
|
|
|
|
|
|
|
} |
|
6164
|
|
|
|
|
|
|
} |
|
6165
|
|
|
|
|
|
|
elsif ( $connect_type eq 'rl' ) { |
|
6166
|
|
|
|
|
|
|
$shape->{_width} = |
|
6167
|
|
|
|
|
|
|
abs( |
|
6168
|
5
|
|
|
|
|
16
|
int( $els->{_x_offset} - ( $sls->{_x_offset} + $sls->{_width} ) ) ); |
|
6169
|
5
|
|
|
|
|
10
|
$shape->{_height} = abs( int( $emidy - $smidy ) ); |
|
6170
|
|
|
|
|
|
|
$shape->{_x_offset} = |
|
6171
|
5
|
|
|
|
|
24
|
min( $sls->{_x_offset} + $sls->{_width}, $els->{_x_offset} ); |
|
6172
|
5
|
|
|
|
|
13
|
$shape->{_y_offset} = min( $smidy, $emidy ); |
|
6173
|
|
|
|
|
|
|
|
|
6174
|
5
|
100
|
100
|
|
|
22
|
$shape->{_flip_h} = 1 if ( $smidx < $emidx ) and ( $smidy > $emidy ); |
|
6175
|
5
|
100
|
100
|
|
|
42
|
$shape->{_flip_h} = 1 if ( $smidx > $emidx ) and ( $smidy < $emidy ); |
|
6176
|
5
|
100
|
|
|
|
25
|
if ( $smidx > $emidx ) { |
|
6177
|
|
|
|
|
|
|
|
|
6178
|
|
|
|
|
|
|
# Create 3 adjustments if end shape is left of start |
|
6179
|
2
|
100
|
|
|
|
3
|
if ( $#{ $shape->{_adjustments} } < 0 ) { |
|
|
2
|
|
|
|
|
8
|
|
|
6180
|
1
|
|
|
|
|
2
|
$shape->{_adjustments} = [ -10, 50, 110 ]; |
|
6181
|
|
|
|
|
|
|
} |
|
6182
|
|
|
|
|
|
|
|
|
6183
|
2
|
|
|
|
|
7
|
$shape->{_type} = 'bentConnector5'; |
|
6184
|
|
|
|
|
|
|
} |
|
6185
|
|
|
|
|
|
|
} |
|
6186
|
|
|
|
|
|
|
else { |
|
6187
|
0
|
|
|
|
|
0
|
warn "Connection $connect_type not implemented yet\n"; |
|
6188
|
|
|
|
|
|
|
} |
|
6189
|
|
|
|
|
|
|
} |
|
6190
|
|
|
|
|
|
|
|
|
6191
|
|
|
|
|
|
|
|
|
6192
|
|
|
|
|
|
|
############################################################################### |
|
6193
|
|
|
|
|
|
|
# |
|
6194
|
|
|
|
|
|
|
# _validate_shape() |
|
6195
|
|
|
|
|
|
|
# |
|
6196
|
|
|
|
|
|
|
# Check shape attributes to ensure they are valid. |
|
6197
|
|
|
|
|
|
|
# |
|
6198
|
|
|
|
|
|
|
sub _validate_shape { |
|
6199
|
|
|
|
|
|
|
|
|
6200
|
41
|
|
|
41
|
|
66
|
my $self = shift; |
|
6201
|
41
|
|
|
|
|
77
|
my $shape = shift; |
|
6202
|
41
|
|
|
|
|
63
|
my $index = shift; |
|
6203
|
|
|
|
|
|
|
|
|
6204
|
41
|
50
|
|
|
|
566
|
if ( !grep ( /^$shape->{_align}$/, qw[l ctr r just] ) ) { |
|
6205
|
0
|
|
|
|
|
0
|
croak "Shape $index ($shape->{_type}) alignment ($shape->{align}), " |
|
6206
|
|
|
|
|
|
|
. "not in ('l', 'ctr', 'r', 'just')\n"; |
|
6207
|
|
|
|
|
|
|
} |
|
6208
|
|
|
|
|
|
|
|
|
6209
|
41
|
50
|
|
|
|
397
|
if ( !grep ( /^$shape->{_valign}$/, qw[t ctr b] ) ) { |
|
6210
|
0
|
|
|
|
|
0
|
croak "Shape $index ($shape->{_type}) vertical alignment " |
|
6211
|
|
|
|
|
|
|
. "($shape->{valign}), not ('t', 'ctr', 'b')\n"; |
|
6212
|
|
|
|
|
|
|
} |
|
6213
|
|
|
|
|
|
|
} |
|
6214
|
|
|
|
|
|
|
|
|
6215
|
|
|
|
|
|
|
|
|
6216
|
|
|
|
|
|
|
############################################################################### |
|
6217
|
|
|
|
|
|
|
# |
|
6218
|
|
|
|
|
|
|
# _prepare_vml_objects() |
|
6219
|
|
|
|
|
|
|
# |
|
6220
|
|
|
|
|
|
|
# Turn the HoH that stores the comments into an array for easier handling |
|
6221
|
|
|
|
|
|
|
# and set the external links for comments and buttons. |
|
6222
|
|
|
|
|
|
|
# |
|
6223
|
|
|
|
|
|
|
sub _prepare_vml_objects { |
|
6224
|
|
|
|
|
|
|
|
|
6225
|
53
|
|
|
53
|
|
128
|
my $self = shift; |
|
6226
|
53
|
|
|
|
|
129
|
my $vml_data_id = shift; |
|
6227
|
53
|
|
|
|
|
102
|
my $vml_shape_id = shift; |
|
6228
|
53
|
|
|
|
|
120
|
my $vml_drawing_id = shift; |
|
6229
|
53
|
|
|
|
|
107
|
my $comment_id = shift; |
|
6230
|
53
|
|
|
|
|
115
|
my @comments; |
|
6231
|
|
|
|
|
|
|
|
|
6232
|
|
|
|
|
|
|
|
|
6233
|
|
|
|
|
|
|
# We sort the comments by row and column but that isn't strictly required. |
|
6234
|
53
|
|
|
|
|
126
|
my @rows = sort { $a <=> $b } keys %{ $self->{_comments} }; |
|
|
1504
|
|
|
|
|
2010
|
|
|
|
53
|
|
|
|
|
363
|
|
|
6235
|
|
|
|
|
|
|
|
|
6236
|
53
|
|
|
|
|
177
|
for my $row ( @rows ) { |
|
6237
|
310
|
|
|
|
|
501
|
my @cols = sort { $a <=> $b } keys %{ $self->{_comments}->{$row} }; |
|
|
11311
|
|
|
|
|
16346
|
|
|
|
310
|
|
|
|
|
2800
|
|
|
6238
|
|
|
|
|
|
|
|
|
6239
|
310
|
|
|
|
|
849
|
for my $col ( @cols ) { |
|
6240
|
4153
|
|
|
|
|
8815
|
my $user_options = $self->{_comments}->{$row}->{$col}; |
|
6241
|
4153
|
|
|
|
|
10739
|
my $params = [ $self->_comment_params( @$user_options ) ]; |
|
6242
|
|
|
|
|
|
|
|
|
6243
|
4153
|
|
|
|
|
11951
|
$self->{_comments}->{$row}->{$col} = $params; |
|
6244
|
|
|
|
|
|
|
|
|
6245
|
|
|
|
|
|
|
# Set comment visibility if required and not already user defined. |
|
6246
|
4153
|
100
|
|
|
|
8847
|
if ( $self->{_comments_visible} ) { |
|
6247
|
10
|
100
|
|
|
|
24
|
if ( !defined $self->{_comments}->{$row}->{$col}->[4] ) { |
|
6248
|
8
|
|
|
|
|
14
|
$self->{_comments}->{$row}->{$col}->[4] = 1; |
|
6249
|
|
|
|
|
|
|
} |
|
6250
|
|
|
|
|
|
|
} |
|
6251
|
|
|
|
|
|
|
|
|
6252
|
|
|
|
|
|
|
# Set comment author if not already user defined. |
|
6253
|
4153
|
100
|
|
|
|
8990
|
if ( !defined $self->{_comments}->{$row}->{$col}->[3] ) { |
|
6254
|
|
|
|
|
|
|
$self->{_comments}->{$row}->{$col}->[3] = |
|
6255
|
4151
|
|
|
|
|
8295
|
$self->{_comments_author}; |
|
6256
|
|
|
|
|
|
|
} |
|
6257
|
|
|
|
|
|
|
|
|
6258
|
4153
|
|
|
|
|
11498
|
push @comments, $self->{_comments}->{$row}->{$col}; |
|
6259
|
|
|
|
|
|
|
} |
|
6260
|
|
|
|
|
|
|
} |
|
6261
|
|
|
|
|
|
|
|
|
6262
|
53
|
|
|
|
|
138
|
push @{ $self->{_external_vml_links} }, |
|
|
53
|
|
|
|
|
339
|
|
|
6263
|
|
|
|
|
|
|
[ '/vmlDrawing', '../drawings/vmlDrawing' . $vml_drawing_id . '.vml' ]; |
|
6264
|
|
|
|
|
|
|
|
|
6265
|
53
|
100
|
|
|
|
227
|
if ( $self->{_has_comments} ) { |
|
6266
|
|
|
|
|
|
|
|
|
6267
|
39
|
|
|
|
|
130
|
$self->{_comments_array} = \@comments; |
|
6268
|
|
|
|
|
|
|
|
|
6269
|
39
|
|
|
|
|
87
|
push @{ $self->{_external_comment_links} }, |
|
|
39
|
|
|
|
|
191
|
|
|
6270
|
|
|
|
|
|
|
[ '/comments', '../comments' . $comment_id . '.xml' ]; |
|
6271
|
|
|
|
|
|
|
} |
|
6272
|
|
|
|
|
|
|
|
|
6273
|
53
|
|
|
|
|
128
|
my $count = scalar @comments; |
|
6274
|
53
|
|
|
|
|
176
|
my $start_data_id = $vml_data_id; |
|
6275
|
|
|
|
|
|
|
|
|
6276
|
|
|
|
|
|
|
# The VML o:idmap data id contains a comma separated range when there is |
|
6277
|
|
|
|
|
|
|
# more than one 1024 block of comments, like this: data="1,2". |
|
6278
|
53
|
|
|
|
|
285
|
for my $i ( 1 .. int( $count / 1024 ) ) { |
|
6279
|
4
|
|
|
|
|
12
|
$vml_data_id = "$vml_data_id," . ( $start_data_id + $i ); |
|
6280
|
|
|
|
|
|
|
} |
|
6281
|
|
|
|
|
|
|
|
|
6282
|
53
|
|
|
|
|
172
|
$self->{_vml_data_id} = $vml_data_id; |
|
6283
|
53
|
|
|
|
|
139
|
$self->{_vml_shape_id} = $vml_shape_id; |
|
6284
|
|
|
|
|
|
|
|
|
6285
|
53
|
|
|
|
|
320
|
return $count; |
|
6286
|
|
|
|
|
|
|
} |
|
6287
|
|
|
|
|
|
|
|
|
6288
|
|
|
|
|
|
|
|
|
6289
|
|
|
|
|
|
|
############################################################################### |
|
6290
|
|
|
|
|
|
|
# |
|
6291
|
|
|
|
|
|
|
# _prepare_header_vml_objects() |
|
6292
|
|
|
|
|
|
|
# |
|
6293
|
|
|
|
|
|
|
# Set up external linkage for VML header/footer images. |
|
6294
|
|
|
|
|
|
|
# |
|
6295
|
|
|
|
|
|
|
sub _prepare_header_vml_objects { |
|
6296
|
|
|
|
|
|
|
|
|
6297
|
22
|
|
|
22
|
|
64
|
my $self = shift; |
|
6298
|
22
|
|
|
|
|
46
|
my $vml_header_id = shift; |
|
6299
|
22
|
|
|
|
|
396
|
my $vml_drawing_id = shift; |
|
6300
|
|
|
|
|
|
|
|
|
6301
|
22
|
|
|
|
|
244
|
$self->{_vml_header_id} = $vml_header_id; |
|
6302
|
|
|
|
|
|
|
|
|
6303
|
22
|
|
|
|
|
375
|
push @{ $self->{_external_vml_links} }, |
|
|
22
|
|
|
|
|
329
|
|
|
6304
|
|
|
|
|
|
|
[ '/vmlDrawing', '../drawings/vmlDrawing' . $vml_drawing_id . '.vml' ]; |
|
6305
|
|
|
|
|
|
|
} |
|
6306
|
|
|
|
|
|
|
|
|
6307
|
|
|
|
|
|
|
|
|
6308
|
|
|
|
|
|
|
############################################################################### |
|
6309
|
|
|
|
|
|
|
# |
|
6310
|
|
|
|
|
|
|
# _prepare_tables() |
|
6311
|
|
|
|
|
|
|
# |
|
6312
|
|
|
|
|
|
|
# Set the table ids for the worksheet tables. |
|
6313
|
|
|
|
|
|
|
# |
|
6314
|
|
|
|
|
|
|
sub _prepare_tables { |
|
6315
|
|
|
|
|
|
|
|
|
6316
|
39
|
|
|
39
|
|
188
|
my $self = shift; |
|
6317
|
39
|
|
|
|
|
87
|
my $table_id = shift; |
|
6318
|
39
|
|
|
|
|
83
|
my $seen = shift; |
|
6319
|
|
|
|
|
|
|
|
|
6320
|
|
|
|
|
|
|
|
|
6321
|
39
|
|
|
|
|
81
|
for my $table ( @{ $self->{_tables} } ) { |
|
|
39
|
|
|
|
|
140
|
|
|
6322
|
|
|
|
|
|
|
|
|
6323
|
47
|
|
|
|
|
125
|
$table-> {_id} = $table_id; |
|
6324
|
|
|
|
|
|
|
|
|
6325
|
|
|
|
|
|
|
# Set the table name unless defined by the user. |
|
6326
|
47
|
100
|
|
|
|
188
|
if ( !defined $table->{_name} ) { |
|
6327
|
|
|
|
|
|
|
|
|
6328
|
|
|
|
|
|
|
# Set a default name. |
|
6329
|
46
|
|
|
|
|
194
|
$table->{_name} = 'Table' . $table_id; |
|
6330
|
|
|
|
|
|
|
} |
|
6331
|
|
|
|
|
|
|
|
|
6332
|
|
|
|
|
|
|
# Check for duplicate table names. |
|
6333
|
47
|
|
|
|
|
156
|
my $name = lc $table->{_name}; |
|
6334
|
|
|
|
|
|
|
|
|
6335
|
47
|
50
|
|
|
|
184
|
if ( exists $seen->{$name} ) { |
|
6336
|
0
|
|
|
|
|
0
|
die "error: invalid duplicate table name '$table->{_name}' found"; |
|
6337
|
|
|
|
|
|
|
} |
|
6338
|
|
|
|
|
|
|
else { |
|
6339
|
47
|
|
|
|
|
154
|
$seen->{$name} = 1; |
|
6340
|
|
|
|
|
|
|
} |
|
6341
|
|
|
|
|
|
|
|
|
6342
|
|
|
|
|
|
|
# Store the link used for the rels file. |
|
6343
|
47
|
|
|
|
|
199
|
my $link = [ '/table', '../tables/table' . $table_id . '.xml' ]; |
|
6344
|
|
|
|
|
|
|
|
|
6345
|
47
|
|
|
|
|
112
|
push @{ $self->{_external_table_links} }, $link; |
|
|
47
|
|
|
|
|
161
|
|
|
6346
|
47
|
|
|
|
|
168
|
$table_id++; |
|
6347
|
|
|
|
|
|
|
} |
|
6348
|
|
|
|
|
|
|
} |
|
6349
|
|
|
|
|
|
|
|
|
6350
|
|
|
|
|
|
|
|
|
6351
|
|
|
|
|
|
|
############################################################################### |
|
6352
|
|
|
|
|
|
|
# |
|
6353
|
|
|
|
|
|
|
# _comment_params() |
|
6354
|
|
|
|
|
|
|
# |
|
6355
|
|
|
|
|
|
|
# This method handles the additional optional parameters to write_comment() as |
|
6356
|
|
|
|
|
|
|
# well as calculating the comment object position and vertices. |
|
6357
|
|
|
|
|
|
|
# |
|
6358
|
|
|
|
|
|
|
sub _comment_params { |
|
6359
|
|
|
|
|
|
|
|
|
6360
|
4153
|
|
|
4153
|
|
5797
|
my $self = shift; |
|
6361
|
|
|
|
|
|
|
|
|
6362
|
4153
|
|
|
|
|
6230
|
my $row = shift; |
|
6363
|
4153
|
|
|
|
|
5634
|
my $col = shift; |
|
6364
|
4153
|
|
|
|
|
5940
|
my $string = shift; |
|
6365
|
|
|
|
|
|
|
|
|
6366
|
4153
|
|
|
|
|
5791
|
my $default_width = 128; |
|
6367
|
4153
|
|
|
|
|
5682
|
my $default_height = 74; |
|
6368
|
|
|
|
|
|
|
|
|
6369
|
4153
|
|
|
|
|
21972
|
my %params = ( |
|
6370
|
|
|
|
|
|
|
author => undef, |
|
6371
|
|
|
|
|
|
|
color => 81, |
|
6372
|
|
|
|
|
|
|
start_cell => undef, |
|
6373
|
|
|
|
|
|
|
start_col => undef, |
|
6374
|
|
|
|
|
|
|
start_row => undef, |
|
6375
|
|
|
|
|
|
|
visible => undef, |
|
6376
|
|
|
|
|
|
|
width => $default_width, |
|
6377
|
|
|
|
|
|
|
height => $default_height, |
|
6378
|
|
|
|
|
|
|
x_offset => undef, |
|
6379
|
|
|
|
|
|
|
x_scale => 1, |
|
6380
|
|
|
|
|
|
|
y_offset => undef, |
|
6381
|
|
|
|
|
|
|
y_scale => 1, |
|
6382
|
|
|
|
|
|
|
font => 'Tahoma', |
|
6383
|
|
|
|
|
|
|
font_size => 8, |
|
6384
|
|
|
|
|
|
|
font_family => 2, |
|
6385
|
|
|
|
|
|
|
); |
|
6386
|
|
|
|
|
|
|
|
|
6387
|
|
|
|
|
|
|
|
|
6388
|
|
|
|
|
|
|
# Overwrite the defaults with any user supplied values. Incorrect or |
|
6389
|
|
|
|
|
|
|
# misspelled parameters are silently ignored. |
|
6390
|
4153
|
|
|
|
|
28902
|
%params = ( %params, @_ ); |
|
6391
|
|
|
|
|
|
|
|
|
6392
|
|
|
|
|
|
|
|
|
6393
|
|
|
|
|
|
|
# Ensure that a width and height have been set. |
|
6394
|
4153
|
50
|
|
|
|
11899
|
$params{width} = $default_width if not $params{width}; |
|
6395
|
4153
|
50
|
|
|
|
8266
|
$params{height} = $default_height if not $params{height}; |
|
6396
|
|
|
|
|
|
|
|
|
6397
|
|
|
|
|
|
|
|
|
6398
|
|
|
|
|
|
|
# Limit the string to the max number of chars. |
|
6399
|
4153
|
|
|
|
|
5944
|
my $max_len = 32767; |
|
6400
|
|
|
|
|
|
|
|
|
6401
|
4153
|
50
|
|
|
|
8086
|
if ( length( $string ) > $max_len ) { |
|
6402
|
0
|
|
|
|
|
0
|
$string = substr( $string, 0, $max_len ); |
|
6403
|
|
|
|
|
|
|
} |
|
6404
|
|
|
|
|
|
|
|
|
6405
|
|
|
|
|
|
|
|
|
6406
|
|
|
|
|
|
|
# Set the comment background colour. |
|
6407
|
4153
|
|
|
|
|
6491
|
my $color = $params{color}; |
|
6408
|
4153
|
|
|
|
|
10910
|
my $color_id = &Excel::Writer::XLSX::Format::_get_color( $color ); |
|
6409
|
|
|
|
|
|
|
|
|
6410
|
4153
|
50
|
|
|
|
11134
|
if ( $color_id =~ m/^#[0-9A-F]{6}$/i ) { |
|
|
|
100
|
|
|
|
|
|
|
6411
|
0
|
|
|
|
|
0
|
$params{color} = $color_id; |
|
6412
|
|
|
|
|
|
|
} |
|
6413
|
|
|
|
|
|
|
elsif ( $color_id == 0 ) { |
|
6414
|
4152
|
|
|
|
|
7880
|
$params{color} = '#ffffe1'; |
|
6415
|
|
|
|
|
|
|
} |
|
6416
|
|
|
|
|
|
|
else { |
|
6417
|
1
|
|
|
|
|
2
|
my $palette = $self->{_palette}; |
|
6418
|
|
|
|
|
|
|
|
|
6419
|
|
|
|
|
|
|
# Get the RGB color from the palette. |
|
6420
|
1
|
|
|
|
|
2
|
my @rgb = @{ $palette->[ $color_id - 8 ] }; |
|
|
1
|
|
|
|
|
3
|
|
|
6421
|
1
|
|
|
|
|
7
|
my $rgb_color = sprintf "%02x%02x%02x", @rgb[0, 1, 2]; |
|
6422
|
|
|
|
|
|
|
|
|
6423
|
|
|
|
|
|
|
# Minor modification to allow comparison testing. Change RGB colors |
|
6424
|
|
|
|
|
|
|
# from long format, ffcc00 to short format fc0 used by VML. |
|
6425
|
1
|
|
|
|
|
11
|
$rgb_color =~ s/^([0-9a-f])\1([0-9a-f])\2([0-9a-f])\3$/$1$2$3/; |
|
6426
|
|
|
|
|
|
|
|
|
6427
|
1
|
|
|
|
|
7
|
$params{color} = sprintf "#%s [%d]", $rgb_color, $color_id; |
|
6428
|
|
|
|
|
|
|
} |
|
6429
|
|
|
|
|
|
|
|
|
6430
|
|
|
|
|
|
|
|
|
6431
|
|
|
|
|
|
|
# Convert a cell reference to a row and column. |
|
6432
|
4153
|
50
|
|
|
|
8267
|
if ( defined $params{start_cell} ) { |
|
6433
|
0
|
|
|
|
|
0
|
my ( $row, $col ) = $self->_substitute_cellref( $params{start_cell} ); |
|
6434
|
0
|
|
|
|
|
0
|
$params{start_row} = $row; |
|
6435
|
0
|
|
|
|
|
0
|
$params{start_col} = $col; |
|
6436
|
|
|
|
|
|
|
} |
|
6437
|
|
|
|
|
|
|
|
|
6438
|
|
|
|
|
|
|
|
|
6439
|
|
|
|
|
|
|
# Set the default start cell and offsets for the comment. These are |
|
6440
|
|
|
|
|
|
|
# generally fixed in relation to the parent cell. However there are |
|
6441
|
|
|
|
|
|
|
# some edge cases for cells at the, er, edges. |
|
6442
|
|
|
|
|
|
|
# |
|
6443
|
4153
|
|
|
|
|
6622
|
my $row_max = $self->{_xls_rowmax}; |
|
6444
|
4153
|
|
|
|
|
6109
|
my $col_max = $self->{_xls_colmax}; |
|
6445
|
|
|
|
|
|
|
|
|
6446
|
4153
|
50
|
|
|
|
7964
|
if ( not defined $params{start_row} ) { |
|
6447
|
|
|
|
|
|
|
|
|
6448
|
4153
|
100
|
|
|
|
12445
|
if ( $row == 0 ) { $params{start_row} = 0 } |
|
|
51
|
50
|
|
|
|
96
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6449
|
0
|
|
|
|
|
0
|
elsif ( $row == $row_max - 3 ) { $params{start_row} = $row_max - 7 } |
|
6450
|
0
|
|
|
|
|
0
|
elsif ( $row == $row_max - 2 ) { $params{start_row} = $row_max - 6 } |
|
6451
|
1
|
|
|
|
|
3
|
elsif ( $row == $row_max - 1 ) { $params{start_row} = $row_max - 5 } |
|
6452
|
4101
|
|
|
|
|
6597
|
else { $params{start_row} = $row - 1 } |
|
6453
|
|
|
|
|
|
|
} |
|
6454
|
|
|
|
|
|
|
|
|
6455
|
4153
|
100
|
|
|
|
8339
|
if ( not defined $params{y_offset} ) { |
|
6456
|
|
|
|
|
|
|
|
|
6457
|
4152
|
100
|
|
|
|
11403
|
if ( $row == 0 ) { $params{y_offset} = 2 } |
|
|
51
|
50
|
|
|
|
108
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
6458
|
0
|
|
|
|
|
0
|
elsif ( $row == $row_max - 3 ) { $params{y_offset} = 16 } |
|
6459
|
0
|
|
|
|
|
0
|
elsif ( $row == $row_max - 2 ) { $params{y_offset} = 16 } |
|
6460
|
1
|
|
|
|
|
2
|
elsif ( $row == $row_max - 1 ) { $params{y_offset} = 14 } |
|
6461
|
4100
|
|
|
|
|
6355
|
else { $params{y_offset} = 10 } |
|
6462
|
|
|
|
|
|
|
} |
|
6463
|
|
|
|
|
|
|
|
|
6464
|
4153
|
50
|
|
|
|
8171
|
if ( not defined $params{start_col} ) { |
|
6465
|
|
|
|
|
|
|
|
|
6466
|
4153
|
50
|
|
|
|
9613
|
if ( $col == $col_max - 3 ) { $params{start_col} = $col_max - 6 } |
|
|
0
|
50
|
|
|
|
0
|
|
|
|
|
100
|
|
|
|
|
|
|
6467
|
0
|
|
|
|
|
0
|
elsif ( $col == $col_max - 2 ) { $params{start_col} = $col_max - 5 } |
|
6468
|
1
|
|
|
|
|
2
|
elsif ( $col == $col_max - 1 ) { $params{start_col} = $col_max - 4 } |
|
6469
|
4152
|
|
|
|
|
6611
|
else { $params{start_col} = $col + 1 } |
|
6470
|
|
|
|
|
|
|
} |
|
6471
|
|
|
|
|
|
|
|
|
6472
|
4153
|
50
|
|
|
|
8073
|
if ( not defined $params{x_offset} ) { |
|
6473
|
|
|
|
|
|
|
|
|
6474
|
4153
|
50
|
|
|
|
9920
|
if ( $col == $col_max - 3 ) { $params{x_offset} = 49 } |
|
|
0
|
50
|
|
|
|
0
|
|
|
|
|
100
|
|
|
|
|
|
|
6475
|
0
|
|
|
|
|
0
|
elsif ( $col == $col_max - 2 ) { $params{x_offset} = 49 } |
|
6476
|
1
|
|
|
|
|
2
|
elsif ( $col == $col_max - 1 ) { $params{x_offset} = 49 } |
|
6477
|
4152
|
|
|
|
|
6034
|
else { $params{x_offset} = 15 } |
|
6478
|
|
|
|
|
|
|
} |
|
6479
|
|
|
|
|
|
|
|
|
6480
|
|
|
|
|
|
|
|
|
6481
|
|
|
|
|
|
|
# Scale the size of the comment box if required. |
|
6482
|
4153
|
50
|
|
|
|
7913
|
if ( $params{x_scale} ) { |
|
6483
|
4153
|
|
|
|
|
7392
|
$params{width} = $params{width} * $params{x_scale}; |
|
6484
|
|
|
|
|
|
|
} |
|
6485
|
|
|
|
|
|
|
|
|
6486
|
4153
|
50
|
|
|
|
7202
|
if ( $params{y_scale} ) { |
|
6487
|
4153
|
|
|
|
|
6587
|
$params{height} = $params{height} * $params{y_scale}; |
|
6488
|
|
|
|
|
|
|
} |
|
6489
|
|
|
|
|
|
|
|
|
6490
|
|
|
|
|
|
|
# Round the dimensions to the nearest pixel. |
|
6491
|
4153
|
|
|
|
|
9072
|
$params{width} = int( 0.5 + $params{width} ); |
|
6492
|
4153
|
|
|
|
|
7025
|
$params{height} = int( 0.5 + $params{height} ); |
|
6493
|
|
|
|
|
|
|
|
|
6494
|
|
|
|
|
|
|
# Calculate the positions of comment object. |
|
6495
|
|
|
|
|
|
|
my @vertices = $self->_position_object_pixels( |
|
6496
|
|
|
|
|
|
|
$params{start_col}, $params{start_row}, $params{x_offset}, |
|
6497
|
|
|
|
|
|
|
$params{y_offset}, $params{width}, $params{height} |
|
6498
|
4153
|
|
|
|
|
11673
|
); |
|
6499
|
|
|
|
|
|
|
|
|
6500
|
|
|
|
|
|
|
# Add the width and height for VML. |
|
6501
|
4153
|
|
|
|
|
8924
|
push @vertices, ( $params{width}, $params{height} ); |
|
6502
|
|
|
|
|
|
|
|
|
6503
|
|
|
|
|
|
|
return ( |
|
6504
|
|
|
|
|
|
|
$row, |
|
6505
|
|
|
|
|
|
|
$col, |
|
6506
|
|
|
|
|
|
|
$string, |
|
6507
|
|
|
|
|
|
|
|
|
6508
|
|
|
|
|
|
|
$params{author}, |
|
6509
|
|
|
|
|
|
|
$params{visible}, |
|
6510
|
|
|
|
|
|
|
$params{color}, |
|
6511
|
|
|
|
|
|
|
$params{font}, |
|
6512
|
|
|
|
|
|
|
$params{font_size}, |
|
6513
|
|
|
|
|
|
|
$params{font_family}, |
|
6514
|
|
|
|
|
|
|
|
|
6515
|
4153
|
|
|
|
|
39245
|
[@vertices], |
|
6516
|
|
|
|
|
|
|
); |
|
6517
|
|
|
|
|
|
|
} |
|
6518
|
|
|
|
|
|
|
|
|
6519
|
|
|
|
|
|
|
|
|
6520
|
|
|
|
|
|
|
############################################################################### |
|
6521
|
|
|
|
|
|
|
# |
|
6522
|
|
|
|
|
|
|
# _button_params() |
|
6523
|
|
|
|
|
|
|
# |
|
6524
|
|
|
|
|
|
|
# This method handles the parameters passed to insert_button() as well as |
|
6525
|
|
|
|
|
|
|
# calculating the button object position and vertices. |
|
6526
|
|
|
|
|
|
|
# |
|
6527
|
|
|
|
|
|
|
sub _button_params { |
|
6528
|
|
|
|
|
|
|
|
|
6529
|
28
|
|
|
28
|
|
69
|
my $self = shift; |
|
6530
|
28
|
|
|
|
|
61
|
my $row = shift; |
|
6531
|
28
|
|
|
|
|
54
|
my $col = shift; |
|
6532
|
28
|
|
|
|
|
51
|
my $params = shift; |
|
6533
|
28
|
|
|
|
|
111
|
my $button = { _row => $row, _col => $col }; |
|
6534
|
|
|
|
|
|
|
|
|
6535
|
28
|
|
|
|
|
61
|
my $button_number = 1 + @{ $self->{_buttons_array} }; |
|
|
28
|
|
|
|
|
116
|
|
|
6536
|
|
|
|
|
|
|
|
|
6537
|
|
|
|
|
|
|
# Set the button caption. |
|
6538
|
28
|
|
|
|
|
94
|
my $caption = $params->{caption}; |
|
6539
|
|
|
|
|
|
|
|
|
6540
|
|
|
|
|
|
|
# Set a default caption if none was specified by user. |
|
6541
|
28
|
100
|
|
|
|
104
|
if ( !defined $caption ) { |
|
6542
|
24
|
|
|
|
|
63
|
$caption = 'Button ' . $button_number; |
|
6543
|
|
|
|
|
|
|
} |
|
6544
|
|
|
|
|
|
|
|
|
6545
|
28
|
|
|
|
|
113
|
$button->{_font}->{_caption} = $caption; |
|
6546
|
|
|
|
|
|
|
|
|
6547
|
|
|
|
|
|
|
|
|
6548
|
|
|
|
|
|
|
# Set the macro name. |
|
6549
|
28
|
100
|
|
|
|
94
|
if ( $params->{macro} ) { |
|
6550
|
5
|
|
|
|
|
25
|
$button->{_macro} = '[0]!' . $params->{macro}; |
|
6551
|
|
|
|
|
|
|
} |
|
6552
|
|
|
|
|
|
|
else { |
|
6553
|
23
|
|
|
|
|
89
|
$button->{_macro} = '[0]!Button' . $button_number . '_Click'; |
|
6554
|
|
|
|
|
|
|
} |
|
6555
|
|
|
|
|
|
|
|
|
6556
|
|
|
|
|
|
|
|
|
6557
|
|
|
|
|
|
|
# Ensure that a width and height have been set. |
|
6558
|
28
|
|
|
|
|
92
|
my $default_width = $self->{_default_col_pixels}; |
|
6559
|
28
|
|
|
|
|
58
|
my $default_height = $self->{_default_row_pixels}; |
|
6560
|
28
|
100
|
|
|
|
126
|
$params->{width} = $default_width if !$params->{width}; |
|
6561
|
28
|
100
|
|
|
|
116
|
$params->{height} = $default_height if !$params->{height}; |
|
6562
|
|
|
|
|
|
|
|
|
6563
|
|
|
|
|
|
|
# Set the x/y offsets. |
|
6564
|
28
|
100
|
|
|
|
94
|
$params->{x_offset} = 0 if !$params->{x_offset}; |
|
6565
|
28
|
100
|
|
|
|
97
|
$params->{y_offset} = 0 if !$params->{y_offset}; |
|
6566
|
|
|
|
|
|
|
|
|
6567
|
|
|
|
|
|
|
# Scale the size of the button box if required. |
|
6568
|
28
|
100
|
|
|
|
90
|
if ( $params->{x_scale} ) { |
|
6569
|
1
|
|
|
|
|
3
|
$params->{width} = $params->{width} * $params->{x_scale}; |
|
6570
|
|
|
|
|
|
|
} |
|
6571
|
|
|
|
|
|
|
|
|
6572
|
28
|
100
|
|
|
|
94
|
if ( $params->{y_scale} ) { |
|
6573
|
1
|
|
|
|
|
4
|
$params->{height} = $params->{height} * $params->{y_scale}; |
|
6574
|
|
|
|
|
|
|
} |
|
6575
|
|
|
|
|
|
|
|
|
6576
|
|
|
|
|
|
|
# Round the dimensions to the nearest pixel. |
|
6577
|
28
|
|
|
|
|
257
|
$params->{width} = int( 0.5 + $params->{width} ); |
|
6578
|
28
|
|
|
|
|
156
|
$params->{height} = int( 0.5 + $params->{height} ); |
|
6579
|
|
|
|
|
|
|
|
|
6580
|
28
|
|
|
|
|
345
|
$params->{start_row} = $row; |
|
6581
|
28
|
|
|
|
|
277
|
$params->{start_col} = $col; |
|
6582
|
|
|
|
|
|
|
|
|
6583
|
|
|
|
|
|
|
# Calculate the positions of button object. |
|
6584
|
|
|
|
|
|
|
my @vertices = $self->_position_object_pixels( |
|
6585
|
|
|
|
|
|
|
$params->{start_col}, $params->{start_row}, $params->{x_offset}, |
|
6586
|
|
|
|
|
|
|
$params->{y_offset}, $params->{width}, $params->{height} |
|
6587
|
28
|
|
|
|
|
158
|
); |
|
6588
|
|
|
|
|
|
|
|
|
6589
|
|
|
|
|
|
|
# Add the width and height for VML. |
|
6590
|
28
|
|
|
|
|
103
|
push @vertices, ( $params->{width}, $params->{height} ); |
|
6591
|
|
|
|
|
|
|
|
|
6592
|
28
|
|
|
|
|
67
|
$button->{_vertices} = \@vertices; |
|
6593
|
|
|
|
|
|
|
|
|
6594
|
28
|
|
|
|
|
79
|
return $button; |
|
6595
|
|
|
|
|
|
|
} |
|
6596
|
|
|
|
|
|
|
|
|
6597
|
|
|
|
|
|
|
|
|
6598
|
|
|
|
|
|
|
############################################################################### |
|
6599
|
|
|
|
|
|
|
# |
|
6600
|
|
|
|
|
|
|
# Deprecated methods for backwards compatibility. |
|
6601
|
|
|
|
|
|
|
# |
|
6602
|
|
|
|
|
|
|
############################################################################### |
|
6603
|
|
|
|
|
|
|
|
|
6604
|
|
|
|
|
|
|
|
|
6605
|
|
|
|
|
|
|
# This method was mainly only required for Excel 5. |
|
6606
|
|
|
|
0
|
0
|
|
sub write_url_range { } |
|
6607
|
|
|
|
|
|
|
|
|
6608
|
|
|
|
|
|
|
# Deprecated UTF-16 method required for the Excel 5 format. |
|
6609
|
|
|
|
|
|
|
sub write_utf16be_string { |
|
6610
|
|
|
|
|
|
|
|
|
6611
|
1
|
|
|
1
|
0
|
9
|
my $self = shift; |
|
6612
|
|
|
|
|
|
|
|
|
6613
|
|
|
|
|
|
|
# Convert A1 notation if present. |
|
6614
|
1
|
50
|
|
|
|
9
|
@_ = $self->_substitute_cellref( @_ ) if $_[0] =~ /^\D/; |
|
6615
|
|
|
|
|
|
|
|
|
6616
|
|
|
|
|
|
|
# Check the number of args. |
|
6617
|
1
|
50
|
|
|
|
5
|
return -1 if @_ < 3; |
|
6618
|
|
|
|
|
|
|
|
|
6619
|
|
|
|
|
|
|
# Convert UTF16 string to UTF8. |
|
6620
|
1
|
|
|
|
|
7
|
require Encode; |
|
6621
|
1
|
|
|
|
|
6
|
my $utf8_string = Encode::decode( 'UTF-16BE', $_[2] ); |
|
6622
|
|
|
|
|
|
|
|
|
6623
|
1
|
|
|
|
|
2847
|
return $self->write_string( $_[0], $_[1], $utf8_string, $_[3] ); |
|
6624
|
|
|
|
|
|
|
} |
|
6625
|
|
|
|
|
|
|
|
|
6626
|
|
|
|
|
|
|
# Deprecated UTF-16 method required for the Excel 5 format. |
|
6627
|
|
|
|
|
|
|
sub write_utf16le_string { |
|
6628
|
|
|
|
|
|
|
|
|
6629
|
1
|
|
|
1
|
0
|
6
|
my $self = shift; |
|
6630
|
|
|
|
|
|
|
|
|
6631
|
|
|
|
|
|
|
# Convert A1 notation if present. |
|
6632
|
1
|
50
|
|
|
|
9
|
@_ = $self->_substitute_cellref( @_ ) if $_[0] =~ /^\D/; |
|
6633
|
|
|
|
|
|
|
|
|
6634
|
|
|
|
|
|
|
# Check the number of args. |
|
6635
|
1
|
50
|
|
|
|
4
|
return -1 if @_ < 3; |
|
6636
|
|
|
|
|
|
|
|
|
6637
|
|
|
|
|
|
|
# Convert UTF16 string to UTF8. |
|
6638
|
1
|
|
|
|
|
5
|
require Encode; |
|
6639
|
1
|
|
|
|
|
5
|
my $utf8_string = Encode::decode( 'UTF-16LE', $_[2] ); |
|
6640
|
|
|
|
|
|
|
|
|
6641
|
1
|
|
|
|
|
50
|
return $self->write_string( $_[0], $_[1], $utf8_string, $_[3] ); |
|
6642
|
|
|
|
|
|
|
} |
|
6643
|
|
|
|
|
|
|
|
|
6644
|
|
|
|
|
|
|
# No longer required. Was used to avoid slow formula parsing. |
|
6645
|
|
|
|
|
|
|
sub store_formula { |
|
6646
|
|
|
|
|
|
|
|
|
6647
|
5
|
|
|
5
|
0
|
2495
|
my $self = shift; |
|
6648
|
5
|
|
|
|
|
9
|
my $string = shift; |
|
6649
|
|
|
|
|
|
|
|
|
6650
|
5
|
|
|
|
|
52
|
my @tokens = split /(\$?[A-I]?[A-Z]\$?\d+)/, $string; |
|
6651
|
|
|
|
|
|
|
|
|
6652
|
5
|
|
|
|
|
30
|
return \@tokens; |
|
6653
|
|
|
|
|
|
|
} |
|
6654
|
|
|
|
|
|
|
|
|
6655
|
|
|
|
|
|
|
# No longer required. Was used to avoid slow formula parsing. |
|
6656
|
|
|
|
|
|
|
sub repeat_formula { |
|
6657
|
|
|
|
|
|
|
|
|
6658
|
5
|
|
|
5
|
0
|
32
|
my $self = shift; |
|
6659
|
|
|
|
|
|
|
|
|
6660
|
|
|
|
|
|
|
# Convert A1 notation if present. |
|
6661
|
5
|
50
|
|
|
|
19
|
@_ = $self->_substitute_cellref( @_ ) if $_[0] =~ /^\D/; |
|
6662
|
|
|
|
|
|
|
|
|
6663
|
5
|
50
|
|
|
|
14
|
if ( @_ < 2 ) { return -1 } # Check the number of args |
|
|
0
|
|
|
|
|
0
|
|
|
6664
|
|
|
|
|
|
|
|
|
6665
|
5
|
|
|
|
|
9
|
my $row = shift; # Zero indexed row |
|
6666
|
5
|
|
|
|
|
10
|
my $col = shift; # Zero indexed column |
|
6667
|
5
|
|
|
|
|
8
|
my $formula_ref = shift; # Array ref with formula tokens |
|
6668
|
5
|
|
|
|
|
7
|
my $format = shift; # XF format |
|
6669
|
5
|
|
|
|
|
14
|
my @pairs = @_; # Pattern/replacement pairs |
|
6670
|
|
|
|
|
|
|
|
|
6671
|
|
|
|
|
|
|
|
|
6672
|
|
|
|
|
|
|
# Enforce an even number of arguments in the pattern/replacement list. |
|
6673
|
5
|
50
|
|
|
|
18
|
croak "Odd number of elements in pattern/replacement list" if @pairs % 2; |
|
6674
|
|
|
|
|
|
|
|
|
6675
|
|
|
|
|
|
|
# Check that $formula is an array ref. |
|
6676
|
5
|
50
|
|
|
|
17
|
croak "Not a valid formula" if ref $formula_ref ne 'ARRAY'; |
|
6677
|
|
|
|
|
|
|
|
|
6678
|
5
|
|
|
|
|
15
|
my @tokens = @$formula_ref; |
|
6679
|
|
|
|
|
|
|
|
|
6680
|
|
|
|
|
|
|
# Allow the user to specify the result of the formula by appending a |
|
6681
|
|
|
|
|
|
|
# result => $value pair to the end of the arguments. |
|
6682
|
5
|
|
|
|
|
11
|
my $value = undef; |
|
6683
|
5
|
50
|
66
|
|
|
22
|
if ( @pairs && $pairs[-2] eq 'result' ) { |
|
6684
|
0
|
|
|
|
|
0
|
$value = pop @pairs; |
|
6685
|
0
|
|
|
|
|
0
|
pop @pairs; |
|
6686
|
|
|
|
|
|
|
} |
|
6687
|
|
|
|
|
|
|
|
|
6688
|
|
|
|
|
|
|
# Make the substitutions. |
|
6689
|
5
|
|
|
|
|
14
|
while ( @pairs ) { |
|
6690
|
6
|
|
|
|
|
13
|
my $pattern = shift @pairs; |
|
6691
|
6
|
|
|
|
|
9
|
my $replace = shift @pairs; |
|
6692
|
|
|
|
|
|
|
|
|
6693
|
6
|
|
|
|
|
12
|
foreach my $token ( @tokens ) { |
|
6694
|
16
|
100
|
|
|
|
91
|
last if $token =~ s/$pattern/$replace/; |
|
6695
|
|
|
|
|
|
|
} |
|
6696
|
|
|
|
|
|
|
} |
|
6697
|
|
|
|
|
|
|
|
|
6698
|
5
|
|
|
|
|
15
|
my $formula = join '', @tokens; |
|
6699
|
|
|
|
|
|
|
|
|
6700
|
5
|
|
|
|
|
62
|
return $self->write_formula( $row, $col, $formula, $format, $value ); |
|
6701
|
|
|
|
|
|
|
} |
|
6702
|
|
|
|
|
|
|
|
|
6703
|
|
|
|
|
|
|
|
|
6704
|
|
|
|
|
|
|
############################################################################### |
|
6705
|
|
|
|
|
|
|
# |
|
6706
|
|
|
|
|
|
|
# XML writing methods. |
|
6707
|
|
|
|
|
|
|
# |
|
6708
|
|
|
|
|
|
|
############################################################################### |
|
6709
|
|
|
|
|
|
|
|
|
6710
|
|
|
|
|
|
|
|
|
6711
|
|
|
|
|
|
|
############################################################################### |
|
6712
|
|
|
|
|
|
|
# |
|
6713
|
|
|
|
|
|
|
# _write_worksheet() |
|
6714
|
|
|
|
|
|
|
# |
|
6715
|
|
|
|
|
|
|
# Write the element. This is the root element of Worksheet. |
|
6716
|
|
|
|
|
|
|
# |
|
6717
|
|
|
|
|
|
|
sub _write_worksheet { |
|
6718
|
|
|
|
|
|
|
|
|
6719
|
994
|
|
|
994
|
|
2718
|
my $self = shift; |
|
6720
|
994
|
|
|
|
|
2973
|
my $schema = 'http://schemas.openxmlformats.org/'; |
|
6721
|
994
|
|
|
|
|
4108
|
my $xmlns = $schema . 'spreadsheetml/2006/main'; |
|
6722
|
994
|
|
|
|
|
3131
|
my $xmlns_r = $schema . 'officeDocument/2006/relationships'; |
|
6723
|
994
|
|
|
|
|
3170
|
my $xmlns_mc = $schema . 'markup-compatibility/2006'; |
|
6724
|
|
|
|
|
|
|
|
|
6725
|
994
|
|
|
|
|
4159
|
my @attributes = ( |
|
6726
|
|
|
|
|
|
|
'xmlns' => $xmlns, |
|
6727
|
|
|
|
|
|
|
'xmlns:r' => $xmlns_r, |
|
6728
|
|
|
|
|
|
|
); |
|
6729
|
|
|
|
|
|
|
|
|
6730
|
994
|
100
|
|
|
|
5108
|
if ( $self->{_excel_version} == 2010 ) { |
|
6731
|
23
|
|
|
|
|
81
|
push @attributes, ( 'xmlns:mc' => $xmlns_mc ); |
|
6732
|
|
|
|
|
|
|
|
|
6733
|
23
|
|
|
|
|
79
|
push @attributes, |
|
6734
|
|
|
|
|
|
|
( 'xmlns:x14ac' => 'http://schemas.microsoft.com/' |
|
6735
|
|
|
|
|
|
|
. 'office/spreadsheetml/2009/9/ac' ); |
|
6736
|
|
|
|
|
|
|
|
|
6737
|
23
|
|
|
|
|
70
|
push @attributes, ( 'mc:Ignorable' => 'x14ac' ); |
|
6738
|
|
|
|
|
|
|
|
|
6739
|
|
|
|
|
|
|
} |
|
6740
|
|
|
|
|
|
|
|
|
6741
|
994
|
|
|
|
|
8530
|
$self->xml_start_tag( 'worksheet', @attributes ); |
|
6742
|
|
|
|
|
|
|
} |
|
6743
|
|
|
|
|
|
|
|
|
6744
|
|
|
|
|
|
|
|
|
6745
|
|
|
|
|
|
|
############################################################################### |
|
6746
|
|
|
|
|
|
|
# |
|
6747
|
|
|
|
|
|
|
# _write_sheet_pr() |
|
6748
|
|
|
|
|
|
|
# |
|
6749
|
|
|
|
|
|
|
# Write the element for Sheet level properties. |
|
6750
|
|
|
|
|
|
|
# |
|
6751
|
|
|
|
|
|
|
sub _write_sheet_pr { |
|
6752
|
|
|
|
|
|
|
|
|
6753
|
996
|
|
|
996
|
|
2356
|
my $self = shift; |
|
6754
|
996
|
|
|
|
|
2567
|
my @attributes = (); |
|
6755
|
|
|
|
|
|
|
|
|
6756
|
996
|
100
|
100
|
|
|
17040
|
if ( !$self->{_fit_page} |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
6757
|
|
|
|
|
|
|
&& !$self->{_filter_on} |
|
6758
|
|
|
|
|
|
|
&& !$self->{_tab_color} |
|
6759
|
|
|
|
|
|
|
&& !$self->{_outline_changed} |
|
6760
|
|
|
|
|
|
|
&& !$self->{_vba_codename} ) |
|
6761
|
|
|
|
|
|
|
{ |
|
6762
|
971
|
|
|
|
|
2664
|
return; |
|
6763
|
|
|
|
|
|
|
} |
|
6764
|
|
|
|
|
|
|
|
|
6765
|
|
|
|
|
|
|
|
|
6766
|
25
|
|
|
|
|
79
|
my $codename = $self->{_vba_codename}; |
|
6767
|
25
|
100
|
|
|
|
95
|
push @attributes, ( 'codeName' => $codename ) if $codename; |
|
6768
|
25
|
100
|
|
|
|
118
|
push @attributes, ( 'filterMode' => 1 ) if $self->{_filter_on}; |
|
6769
|
|
|
|
|
|
|
|
|
6770
|
25
|
100
|
100
|
|
|
243
|
if ( $self->{_fit_page} |
|
|
|
|
100
|
|
|
|
|
|
6771
|
|
|
|
|
|
|
|| $self->{_tab_color} |
|
6772
|
|
|
|
|
|
|
|| $self->{_outline_changed} ) |
|
6773
|
|
|
|
|
|
|
{ |
|
6774
|
11
|
|
|
|
|
53
|
$self->xml_start_tag( 'sheetPr', @attributes ); |
|
6775
|
11
|
|
|
|
|
62
|
$self->_write_tab_color(); |
|
6776
|
11
|
|
|
|
|
52
|
$self->_write_outline_pr(); |
|
6777
|
11
|
|
|
|
|
41
|
$self->_write_page_set_up_pr(); |
|
6778
|
11
|
|
|
|
|
77
|
$self->xml_end_tag( 'sheetPr' ); |
|
6779
|
|
|
|
|
|
|
} |
|
6780
|
|
|
|
|
|
|
else { |
|
6781
|
14
|
|
|
|
|
148
|
$self->xml_empty_tag( 'sheetPr', @attributes ); |
|
6782
|
|
|
|
|
|
|
} |
|
6783
|
|
|
|
|
|
|
} |
|
6784
|
|
|
|
|
|
|
|
|
6785
|
|
|
|
|
|
|
|
|
6786
|
|
|
|
|
|
|
############################################################################## |
|
6787
|
|
|
|
|
|
|
# |
|
6788
|
|
|
|
|
|
|
# _write_page_set_up_pr() |
|
6789
|
|
|
|
|
|
|
# |
|
6790
|
|
|
|
|
|
|
# Write the element. |
|
6791
|
|
|
|
|
|
|
# |
|
6792
|
|
|
|
|
|
|
sub _write_page_set_up_pr { |
|
6793
|
|
|
|
|
|
|
|
|
6794
|
13
|
|
|
13
|
|
44
|
my $self = shift; |
|
6795
|
|
|
|
|
|
|
|
|
6796
|
13
|
100
|
|
|
|
43
|
return unless $self->{_fit_page}; |
|
6797
|
|
|
|
|
|
|
|
|
6798
|
9
|
|
|
|
|
37
|
my @attributes = ( 'fitToPage' => 1 ); |
|
6799
|
|
|
|
|
|
|
|
|
6800
|
9
|
|
|
|
|
96
|
$self->xml_empty_tag( 'pageSetUpPr', @attributes ); |
|
6801
|
|
|
|
|
|
|
} |
|
6802
|
|
|
|
|
|
|
|
|
6803
|
|
|
|
|
|
|
|
|
6804
|
|
|
|
|
|
|
############################################################################### |
|
6805
|
|
|
|
|
|
|
# |
|
6806
|
|
|
|
|
|
|
# _write_dimension() |
|
6807
|
|
|
|
|
|
|
# |
|
6808
|
|
|
|
|
|
|
# Write the element. This specifies the range of cells in the |
|
6809
|
|
|
|
|
|
|
# worksheet. As a special case, empty spreadsheets use 'A1' as a range. |
|
6810
|
|
|
|
|
|
|
# |
|
6811
|
|
|
|
|
|
|
sub _write_dimension { |
|
6812
|
|
|
|
|
|
|
|
|
6813
|
1003
|
|
|
1003
|
|
2674
|
my $self = shift; |
|
6814
|
1003
|
|
|
|
|
2371
|
my $ref; |
|
6815
|
|
|
|
|
|
|
|
|
6816
|
1003
|
100
|
100
|
|
|
12838
|
if ( !defined $self->{_dim_rowmin} && !defined $self->{_dim_colmin} ) { |
|
|
|
100
|
66
|
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
6817
|
|
|
|
|
|
|
|
|
6818
|
|
|
|
|
|
|
# If the min dims are undefined then no dimensions have been set |
|
6819
|
|
|
|
|
|
|
# and we use the default 'A1'. |
|
6820
|
248
|
|
|
|
|
675
|
$ref = 'A1'; |
|
6821
|
|
|
|
|
|
|
} |
|
6822
|
|
|
|
|
|
|
elsif ( !defined $self->{_dim_rowmin} && defined $self->{_dim_colmin} ) { |
|
6823
|
|
|
|
|
|
|
|
|
6824
|
|
|
|
|
|
|
# If the row dims aren't set but the column dims are then they |
|
6825
|
|
|
|
|
|
|
# have been changed via set_column(). |
|
6826
|
|
|
|
|
|
|
|
|
6827
|
6
|
100
|
|
|
|
38
|
if ( $self->{_dim_colmin} == $self->{_dim_colmax} ) { |
|
6828
|
|
|
|
|
|
|
|
|
6829
|
|
|
|
|
|
|
# The dimensions are a single cell and not a range. |
|
6830
|
3
|
|
|
|
|
16
|
$ref = xl_rowcol_to_cell( 0, $self->{_dim_colmin} ); |
|
6831
|
|
|
|
|
|
|
} |
|
6832
|
|
|
|
|
|
|
else { |
|
6833
|
|
|
|
|
|
|
|
|
6834
|
|
|
|
|
|
|
# The dimensions are a cell range. |
|
6835
|
3
|
|
|
|
|
26
|
my $cell_1 = xl_rowcol_to_cell( 0, $self->{_dim_colmin} ); |
|
6836
|
3
|
|
|
|
|
13
|
my $cell_2 = xl_rowcol_to_cell( 0, $self->{_dim_colmax} ); |
|
6837
|
|
|
|
|
|
|
|
|
6838
|
3
|
|
|
|
|
10
|
$ref = $cell_1 . ':' . $cell_2; |
|
6839
|
|
|
|
|
|
|
} |
|
6840
|
|
|
|
|
|
|
|
|
6841
|
|
|
|
|
|
|
} |
|
6842
|
|
|
|
|
|
|
elsif ($self->{_dim_rowmin} == $self->{_dim_rowmax} |
|
6843
|
|
|
|
|
|
|
&& $self->{_dim_colmin} == $self->{_dim_colmax} ) |
|
6844
|
|
|
|
|
|
|
{ |
|
6845
|
|
|
|
|
|
|
|
|
6846
|
|
|
|
|
|
|
# The dimensions are a single cell and not a range. |
|
6847
|
134
|
|
|
|
|
757
|
$ref = xl_rowcol_to_cell( $self->{_dim_rowmin}, $self->{_dim_colmin} ); |
|
6848
|
|
|
|
|
|
|
} |
|
6849
|
|
|
|
|
|
|
else { |
|
6850
|
|
|
|
|
|
|
|
|
6851
|
|
|
|
|
|
|
# The dimensions are a cell range. |
|
6852
|
|
|
|
|
|
|
my $cell_1 = |
|
6853
|
615
|
|
|
|
|
3989
|
xl_rowcol_to_cell( $self->{_dim_rowmin}, $self->{_dim_colmin} ); |
|
6854
|
|
|
|
|
|
|
my $cell_2 = |
|
6855
|
615
|
|
|
|
|
3015
|
xl_rowcol_to_cell( $self->{_dim_rowmax}, $self->{_dim_colmax} ); |
|
6856
|
|
|
|
|
|
|
|
|
6857
|
615
|
|
|
|
|
2681
|
$ref = $cell_1 . ':' . $cell_2; |
|
6858
|
|
|
|
|
|
|
} |
|
6859
|
|
|
|
|
|
|
|
|
6860
|
|
|
|
|
|
|
|
|
6861
|
1003
|
|
|
|
|
3685
|
my @attributes = ( 'ref' => $ref ); |
|
6862
|
|
|
|
|
|
|
|
|
6863
|
1003
|
|
|
|
|
8058
|
$self->xml_empty_tag( 'dimension', @attributes ); |
|
6864
|
|
|
|
|
|
|
} |
|
6865
|
|
|
|
|
|
|
|
|
6866
|
|
|
|
|
|
|
|
|
6867
|
|
|
|
|
|
|
############################################################################### |
|
6868
|
|
|
|
|
|
|
# |
|
6869
|
|
|
|
|
|
|
# _write_sheet_views() |
|
6870
|
|
|
|
|
|
|
# |
|
6871
|
|
|
|
|
|
|
# Write the element. |
|
6872
|
|
|
|
|
|
|
# |
|
6873
|
|
|
|
|
|
|
sub _write_sheet_views { |
|
6874
|
|
|
|
|
|
|
|
|
6875
|
1066
|
|
|
1066
|
|
2728
|
my $self = shift; |
|
6876
|
|
|
|
|
|
|
|
|
6877
|
1066
|
|
|
|
|
2780
|
my @attributes = (); |
|
6878
|
|
|
|
|
|
|
|
|
6879
|
1066
|
|
|
|
|
4758
|
$self->xml_start_tag( 'sheetViews', @attributes ); |
|
6880
|
1066
|
|
|
|
|
4961
|
$self->_write_sheet_view(); |
|
6881
|
1066
|
|
|
|
|
7755
|
$self->xml_end_tag( 'sheetViews' ); |
|
6882
|
|
|
|
|
|
|
} |
|
6883
|
|
|
|
|
|
|
|
|
6884
|
|
|
|
|
|
|
|
|
6885
|
|
|
|
|
|
|
############################################################################### |
|
6886
|
|
|
|
|
|
|
# |
|
6887
|
|
|
|
|
|
|
# _write_sheet_view() |
|
6888
|
|
|
|
|
|
|
# |
|
6889
|
|
|
|
|
|
|
# Write the element. |
|
6890
|
|
|
|
|
|
|
# |
|
6891
|
|
|
|
|
|
|
# Sample structure: |
|
6892
|
|
|
|
|
|
|
#
|
|
6893
|
|
|
|
|
|
|
# showGridLines="0" |
|
6894
|
|
|
|
|
|
|
# showRowColHeaders="0" |
|
6895
|
|
|
|
|
|
|
# showZeros="0" |
|
6896
|
|
|
|
|
|
|
# rightToLeft="1" |
|
6897
|
|
|
|
|
|
|
# tabSelected="1" |
|
6898
|
|
|
|
|
|
|
# showRuler="0" |
|
6899
|
|
|
|
|
|
|
# showOutlineSymbols="0" |
|
6900
|
|
|
|
|
|
|
# view="pageLayout" |
|
6901
|
|
|
|
|
|
|
# zoomScale="121" |
|
6902
|
|
|
|
|
|
|
# zoomScaleNormal="121" |
|
6903
|
|
|
|
|
|
|
# workbookViewId="0" |
|
6904
|
|
|
|
|
|
|
# /> |
|
6905
|
|
|
|
|
|
|
# |
|
6906
|
|
|
|
|
|
|
sub _write_sheet_view { |
|
6907
|
|
|
|
|
|
|
|
|
6908
|
1073
|
|
|
1073
|
|
2781
|
my $self = shift; |
|
6909
|
1073
|
|
|
|
|
2919
|
my $gridlines = $self->{_screen_gridlines}; |
|
6910
|
1073
|
|
|
|
|
2852
|
my $show_zeros = $self->{_show_zeros}; |
|
6911
|
1073
|
|
|
|
|
2720
|
my $right_to_left = $self->{_right_to_left}; |
|
6912
|
1073
|
|
|
|
|
2852
|
my $tab_selected = $self->{_selected}; |
|
6913
|
1073
|
|
|
|
|
2713
|
my $view = $self->{_page_view}; |
|
6914
|
1073
|
|
|
|
|
2673
|
my $zoom = $self->{_zoom}; |
|
6915
|
1073
|
|
|
|
|
2749
|
my $row_col_headers = $self->{_hide_row_col_headers}; |
|
6916
|
1073
|
|
|
|
|
2532
|
my $workbook_view_id = 0; |
|
6917
|
1073
|
|
|
|
|
3137
|
my @attributes = (); |
|
6918
|
|
|
|
|
|
|
|
|
6919
|
|
|
|
|
|
|
# Hide screen gridlines if required. |
|
6920
|
1073
|
100
|
|
|
|
4530
|
if ( !$gridlines ) { |
|
6921
|
3
|
|
|
|
|
25
|
push @attributes, ( 'showGridLines' => 0 ); |
|
6922
|
|
|
|
|
|
|
} |
|
6923
|
|
|
|
|
|
|
|
|
6924
|
|
|
|
|
|
|
# Hide the row/column headers. |
|
6925
|
1073
|
100
|
|
|
|
4425
|
if ( $row_col_headers ) { |
|
6926
|
1
|
|
|
|
|
4
|
push @attributes, ( 'showRowColHeaders' => 0 ); |
|
6927
|
|
|
|
|
|
|
} |
|
6928
|
|
|
|
|
|
|
|
|
6929
|
|
|
|
|
|
|
# Hide zeroes in cells. |
|
6930
|
1073
|
100
|
|
|
|
4469
|
if ( !$show_zeros ) { |
|
6931
|
1
|
|
|
|
|
3
|
push @attributes, ( 'showZeros' => 0 ); |
|
6932
|
|
|
|
|
|
|
} |
|
6933
|
|
|
|
|
|
|
|
|
6934
|
|
|
|
|
|
|
# Display worksheet right to left for Hebrew, Arabic and others. |
|
6935
|
1073
|
100
|
|
|
|
3925
|
if ( $right_to_left ) { |
|
6936
|
1
|
|
|
|
|
3
|
push @attributes, ( 'rightToLeft' => 1 ); |
|
6937
|
|
|
|
|
|
|
} |
|
6938
|
|
|
|
|
|
|
|
|
6939
|
|
|
|
|
|
|
# Show that the sheet tab is selected. |
|
6940
|
1073
|
100
|
|
|
|
4345
|
if ( $tab_selected ) { |
|
6941
|
924
|
|
|
|
|
3613
|
push @attributes, ( 'tabSelected' => 1 ); |
|
6942
|
|
|
|
|
|
|
} |
|
6943
|
|
|
|
|
|
|
|
|
6944
|
|
|
|
|
|
|
|
|
6945
|
|
|
|
|
|
|
# Turn outlines off. Also required in the outlinePr element. |
|
6946
|
1073
|
100
|
|
|
|
4736
|
if ( !$self->{_outline_on} ) { |
|
6947
|
1
|
|
|
|
|
3
|
push @attributes, ( "showOutlineSymbols" => 0 ); |
|
6948
|
|
|
|
|
|
|
} |
|
6949
|
|
|
|
|
|
|
|
|
6950
|
|
|
|
|
|
|
# Set the page view/layout mode if required. |
|
6951
|
|
|
|
|
|
|
# TODO. Add pageBreakPreview mode when requested. |
|
6952
|
1073
|
100
|
|
|
|
4303
|
if ( $view ) { |
|
6953
|
2
|
|
|
|
|
5
|
push @attributes, ( 'view' => 'pageLayout' ); |
|
6954
|
|
|
|
|
|
|
} |
|
6955
|
|
|
|
|
|
|
|
|
6956
|
|
|
|
|
|
|
# Set the zoom level. |
|
6957
|
1073
|
100
|
|
|
|
4442
|
if ( $zoom != 100 ) { |
|
6958
|
2
|
50
|
|
|
|
9
|
push @attributes, ( 'zoomScale' => $zoom ) unless $view; |
|
6959
|
|
|
|
|
|
|
push @attributes, ( 'zoomScaleNormal' => $zoom ) |
|
6960
|
2
|
100
|
|
|
|
6
|
if $self->{_zoom_scale_normal}; |
|
6961
|
|
|
|
|
|
|
} |
|
6962
|
|
|
|
|
|
|
|
|
6963
|
1073
|
|
|
|
|
3442
|
push @attributes, ( 'workbookViewId' => $workbook_view_id ); |
|
6964
|
|
|
|
|
|
|
|
|
6965
|
1073
|
100
|
100
|
|
|
2229
|
if ( @{ $self->{_panes} } || @{ $self->{_selections} } ) { |
|
|
1073
|
|
|
|
|
5599
|
|
|
|
1021
|
|
|
|
|
4901
|
|
|
6966
|
69
|
|
|
|
|
246
|
$self->xml_start_tag( 'sheetView', @attributes ); |
|
6967
|
69
|
|
|
|
|
239
|
$self->_write_panes(); |
|
6968
|
69
|
|
|
|
|
257
|
$self->_write_selections(); |
|
6969
|
69
|
|
|
|
|
246
|
$self->xml_end_tag( 'sheetView' ); |
|
6970
|
|
|
|
|
|
|
} |
|
6971
|
|
|
|
|
|
|
else { |
|
6972
|
1004
|
|
|
|
|
5054
|
$self->xml_empty_tag( 'sheetView', @attributes ); |
|
6973
|
|
|
|
|
|
|
} |
|
6974
|
|
|
|
|
|
|
} |
|
6975
|
|
|
|
|
|
|
|
|
6976
|
|
|
|
|
|
|
|
|
6977
|
|
|
|
|
|
|
############################################################################### |
|
6978
|
|
|
|
|
|
|
# |
|
6979
|
|
|
|
|
|
|
# _write_selections() |
|
6980
|
|
|
|
|
|
|
# |
|
6981
|
|
|
|
|
|
|
# Write the elements. |
|
6982
|
|
|
|
|
|
|
# |
|
6983
|
|
|
|
|
|
|
sub _write_selections { |
|
6984
|
|
|
|
|
|
|
|
|
6985
|
69
|
|
|
69
|
|
107
|
my $self = shift; |
|
6986
|
|
|
|
|
|
|
|
|
6987
|
69
|
|
|
|
|
106
|
for my $selection ( @{ $self->{_selections} } ) { |
|
|
69
|
|
|
|
|
176
|
|
|
6988
|
105
|
|
|
|
|
240
|
$self->_write_selection( @$selection ); |
|
6989
|
|
|
|
|
|
|
} |
|
6990
|
|
|
|
|
|
|
} |
|
6991
|
|
|
|
|
|
|
|
|
6992
|
|
|
|
|
|
|
|
|
6993
|
|
|
|
|
|
|
############################################################################### |
|
6994
|
|
|
|
|
|
|
# |
|
6995
|
|
|
|
|
|
|
# _write_selection() |
|
6996
|
|
|
|
|
|
|
# |
|
6997
|
|
|
|
|
|
|
# Write the element. |
|
6998
|
|
|
|
|
|
|
# |
|
6999
|
|
|
|
|
|
|
sub _write_selection { |
|
7000
|
|
|
|
|
|
|
|
|
7001
|
106
|
|
|
106
|
|
170
|
my $self = shift; |
|
7002
|
106
|
|
|
|
|
186
|
my $pane = shift; |
|
7003
|
106
|
|
|
|
|
175
|
my $active_cell = shift; |
|
7004
|
106
|
|
|
|
|
159
|
my $sqref = shift; |
|
7005
|
106
|
|
|
|
|
189
|
my @attributes = (); |
|
7006
|
|
|
|
|
|
|
|
|
7007
|
106
|
100
|
|
|
|
256
|
push @attributes, ( 'pane' => $pane ) if $pane; |
|
7008
|
106
|
100
|
|
|
|
255
|
push @attributes, ( 'activeCell' => $active_cell ) if $active_cell; |
|
7009
|
106
|
100
|
|
|
|
297
|
push @attributes, ( 'sqref' => $sqref ) if $sqref; |
|
7010
|
|
|
|
|
|
|
|
|
7011
|
106
|
|
|
|
|
286
|
$self->xml_empty_tag( 'selection', @attributes ); |
|
7012
|
|
|
|
|
|
|
} |
|
7013
|
|
|
|
|
|
|
|
|
7014
|
|
|
|
|
|
|
|
|
7015
|
|
|
|
|
|
|
############################################################################### |
|
7016
|
|
|
|
|
|
|
# |
|
7017
|
|
|
|
|
|
|
# _write_sheet_format_pr() |
|
7018
|
|
|
|
|
|
|
# |
|
7019
|
|
|
|
|
|
|
# Write the element. |
|
7020
|
|
|
|
|
|
|
# |
|
7021
|
|
|
|
|
|
|
sub _write_sheet_format_pr { |
|
7022
|
|
|
|
|
|
|
|
|
7023
|
994
|
|
|
994
|
|
2843
|
my $self = shift; |
|
7024
|
994
|
|
|
|
|
2353
|
my $base_col_width = 10; |
|
7025
|
994
|
|
|
|
|
2906
|
my $default_row_height = $self->{_default_row_height}; |
|
7026
|
994
|
|
|
|
|
2697
|
my $row_level = $self->{_outline_row_level}; |
|
7027
|
994
|
|
|
|
|
2547
|
my $col_level = $self->{_outline_col_level}; |
|
7028
|
994
|
|
|
|
|
2577
|
my $zero_height = $self->{_default_row_zeroed}; |
|
7029
|
|
|
|
|
|
|
|
|
7030
|
994
|
|
|
|
|
3473
|
my @attributes = ( 'defaultRowHeight' => $default_row_height ); |
|
7031
|
|
|
|
|
|
|
|
|
7032
|
994
|
100
|
|
|
|
4783
|
if ( $self->{_default_row_height} != $self->{_original_row_height} ) { |
|
7033
|
4
|
|
|
|
|
21
|
push @attributes, ( 'customHeight' => 1 ); |
|
7034
|
|
|
|
|
|
|
} |
|
7035
|
|
|
|
|
|
|
|
|
7036
|
994
|
100
|
|
|
|
4145
|
if ( $self->{_default_row_zeroed} ) { |
|
7037
|
3
|
|
|
|
|
11
|
push @attributes, ( 'zeroHeight' => 1 ); |
|
7038
|
|
|
|
|
|
|
} |
|
7039
|
|
|
|
|
|
|
|
|
7040
|
994
|
100
|
|
|
|
3764
|
push @attributes, ( 'outlineLevelRow' => $row_level ) if $row_level; |
|
7041
|
994
|
100
|
|
|
|
3696
|
push @attributes, ( 'outlineLevelCol' => $col_level ) if $col_level; |
|
7042
|
|
|
|
|
|
|
|
|
7043
|
994
|
100
|
|
|
|
4318
|
if ( $self->{_excel_version} == 2010 ) { |
|
7044
|
23
|
|
|
|
|
62
|
push @attributes, ( 'x14ac:dyDescent' => '0.25' ); |
|
7045
|
|
|
|
|
|
|
} |
|
7046
|
|
|
|
|
|
|
|
|
7047
|
994
|
|
|
|
|
4438
|
$self->xml_empty_tag( 'sheetFormatPr', @attributes ); |
|
7048
|
|
|
|
|
|
|
} |
|
7049
|
|
|
|
|
|
|
|
|
7050
|
|
|
|
|
|
|
|
|
7051
|
|
|
|
|
|
|
############################################################################## |
|
7052
|
|
|
|
|
|
|
# |
|
7053
|
|
|
|
|
|
|
# _write_cols() |
|
7054
|
|
|
|
|
|
|
# |
|
7055
|
|
|
|
|
|
|
# Write the element and sub elements. |
|
7056
|
|
|
|
|
|
|
# |
|
7057
|
|
|
|
|
|
|
sub _write_cols { |
|
7058
|
|
|
|
|
|
|
|
|
7059
|
993
|
|
|
993
|
|
2544
|
my $self = shift; |
|
7060
|
|
|
|
|
|
|
|
|
7061
|
|
|
|
|
|
|
# Exit unless some column have been formatted. |
|
7062
|
993
|
100
|
|
|
|
2123
|
return unless %{ $self->{_colinfo} }; |
|
|
993
|
|
|
|
|
4570
|
|
|
7063
|
|
|
|
|
|
|
|
|
7064
|
100
|
|
|
|
|
543
|
$self->xml_start_tag( 'cols' ); |
|
7065
|
|
|
|
|
|
|
|
|
7066
|
100
|
|
|
|
|
329
|
for my $col ( sort keys %{ $self->{_colinfo} } ) { |
|
|
100
|
|
|
|
|
761
|
|
|
7067
|
186
|
|
|
|
|
384
|
$self->_write_col_info( @{ $self->{_colinfo}->{$col} } ); |
|
|
186
|
|
|
|
|
800
|
|
|
7068
|
|
|
|
|
|
|
} |
|
7069
|
|
|
|
|
|
|
|
|
7070
|
100
|
|
|
|
|
512
|
$self->xml_end_tag( 'cols' ); |
|
7071
|
|
|
|
|
|
|
} |
|
7072
|
|
|
|
|
|
|
|
|
7073
|
|
|
|
|
|
|
|
|
7074
|
|
|
|
|
|
|
############################################################################## |
|
7075
|
|
|
|
|
|
|
# |
|
7076
|
|
|
|
|
|
|
# _write_col_info() |
|
7077
|
|
|
|
|
|
|
# |
|
7078
|
|
|
|
|
|
|
# Write the element. |
|
7079
|
|
|
|
|
|
|
# |
|
7080
|
|
|
|
|
|
|
sub _write_col_info { |
|
7081
|
|
|
|
|
|
|
|
|
7082
|
192
|
|
|
192
|
|
597
|
my $self = shift; |
|
7083
|
192
|
|
100
|
|
|
713
|
my $min = $_[0] || 0; # First formatted column. |
|
7084
|
192
|
|
100
|
|
|
698
|
my $max = $_[1] || 0; # Last formatted column. |
|
7085
|
192
|
|
|
|
|
425
|
my $width = $_[2]; # Col width in user units. |
|
7086
|
192
|
|
|
|
|
334
|
my $format = $_[3]; # Format index. |
|
7087
|
192
|
|
100
|
|
|
851
|
my $hidden = $_[4] || 0; # Hidden flag. |
|
7088
|
192
|
|
100
|
|
|
775
|
my $level = $_[5] || 0; # Outline level. |
|
7089
|
192
|
|
50
|
|
|
832
|
my $collapsed = $_[6] || 0; # Outline level. |
|
7090
|
192
|
|
|
|
|
355
|
my $custom_width = 1; |
|
7091
|
192
|
|
|
|
|
316
|
my $xf_index = 0; |
|
7092
|
|
|
|
|
|
|
|
|
7093
|
|
|
|
|
|
|
# Get the format index. |
|
7094
|
192
|
100
|
|
|
|
603
|
if ( ref( $format ) ) { |
|
7095
|
20
|
|
|
|
|
147
|
$xf_index = $format->get_xf_index(); |
|
7096
|
|
|
|
|
|
|
} |
|
7097
|
|
|
|
|
|
|
|
|
7098
|
|
|
|
|
|
|
# Set the Excel default col width. |
|
7099
|
192
|
100
|
|
|
|
578
|
if ( !defined $width ) { |
|
7100
|
26
|
100
|
|
|
|
89
|
if ( !$hidden ) { |
|
7101
|
17
|
|
|
|
|
38
|
$width = 8.43; |
|
7102
|
17
|
|
|
|
|
34
|
$custom_width = 0; |
|
7103
|
|
|
|
|
|
|
} |
|
7104
|
|
|
|
|
|
|
else { |
|
7105
|
9
|
|
|
|
|
24
|
$width = 0; |
|
7106
|
|
|
|
|
|
|
} |
|
7107
|
|
|
|
|
|
|
} |
|
7108
|
|
|
|
|
|
|
else { |
|
7109
|
|
|
|
|
|
|
|
|
7110
|
|
|
|
|
|
|
# Width is defined but same as default. |
|
7111
|
166
|
100
|
|
|
|
595
|
if ( $width == 8.43 ) { |
|
7112
|
1
|
|
|
|
|
2
|
$custom_width = 0; |
|
7113
|
|
|
|
|
|
|
} |
|
7114
|
|
|
|
|
|
|
} |
|
7115
|
|
|
|
|
|
|
|
|
7116
|
|
|
|
|
|
|
|
|
7117
|
|
|
|
|
|
|
# Convert column width from user units to character width. |
|
7118
|
192
|
|
|
|
|
361
|
my $max_digit_width = 7; # For Calabri 11. |
|
7119
|
192
|
|
|
|
|
406
|
my $padding = 5; |
|
7120
|
|
|
|
|
|
|
|
|
7121
|
192
|
100
|
|
|
|
611
|
if ( $width > 0 ) { |
|
7122
|
183
|
100
|
|
|
|
558
|
if ( $width < 1 ) { |
|
7123
|
22
|
|
|
|
|
52
|
$width = |
|
7124
|
|
|
|
|
|
|
int( ( int( $width * ($max_digit_width + $padding) + 0.5 ) ) / |
|
7125
|
|
|
|
|
|
|
$max_digit_width * |
|
7126
|
|
|
|
|
|
|
256 ) / 256; |
|
7127
|
|
|
|
|
|
|
} |
|
7128
|
|
|
|
|
|
|
else { |
|
7129
|
161
|
|
|
|
|
817
|
$width = |
|
7130
|
|
|
|
|
|
|
int( ( int( $width * $max_digit_width + 0.5 ) + $padding ) / |
|
7131
|
|
|
|
|
|
|
$max_digit_width * |
|
7132
|
|
|
|
|
|
|
256 ) / 256; |
|
7133
|
|
|
|
|
|
|
} |
|
7134
|
|
|
|
|
|
|
} |
|
7135
|
|
|
|
|
|
|
|
|
7136
|
192
|
|
|
|
|
732
|
my @attributes = ( |
|
7137
|
|
|
|
|
|
|
'min' => $min + 1, |
|
7138
|
|
|
|
|
|
|
'max' => $max + 1, |
|
7139
|
|
|
|
|
|
|
'width' => $width, |
|
7140
|
|
|
|
|
|
|
); |
|
7141
|
|
|
|
|
|
|
|
|
7142
|
192
|
100
|
|
|
|
628
|
push @attributes, ( 'style' => $xf_index ) if $xf_index; |
|
7143
|
192
|
100
|
|
|
|
617
|
push @attributes, ( 'hidden' => 1 ) if $hidden; |
|
7144
|
192
|
100
|
|
|
|
676
|
push @attributes, ( 'customWidth' => 1 ) if $custom_width; |
|
7145
|
192
|
100
|
|
|
|
514
|
push @attributes, ( 'outlineLevel' => $level ) if $level; |
|
7146
|
192
|
50
|
|
|
|
515
|
push @attributes, ( 'collapsed' => 1 ) if $collapsed; |
|
7147
|
|
|
|
|
|
|
|
|
7148
|
|
|
|
|
|
|
|
|
7149
|
192
|
|
|
|
|
757
|
$self->xml_empty_tag( 'col', @attributes ); |
|
7150
|
|
|
|
|
|
|
} |
|
7151
|
|
|
|
|
|
|
|
|
7152
|
|
|
|
|
|
|
|
|
7153
|
|
|
|
|
|
|
############################################################################### |
|
7154
|
|
|
|
|
|
|
# |
|
7155
|
|
|
|
|
|
|
# _write_sheet_data() |
|
7156
|
|
|
|
|
|
|
# |
|
7157
|
|
|
|
|
|
|
# Write the element. |
|
7158
|
|
|
|
|
|
|
# |
|
7159
|
|
|
|
|
|
|
sub _write_sheet_data { |
|
7160
|
|
|
|
|
|
|
|
|
7161
|
986
|
|
|
986
|
|
2519
|
my $self = shift; |
|
7162
|
|
|
|
|
|
|
|
|
7163
|
986
|
100
|
|
|
|
4343
|
if ( not defined $self->{_dim_rowmin} ) { |
|
7164
|
|
|
|
|
|
|
|
|
7165
|
|
|
|
|
|
|
# If the dimensions aren't defined then there is no data to write. |
|
7166
|
254
|
|
|
|
|
941
|
$self->xml_empty_tag( 'sheetData' ); |
|
7167
|
|
|
|
|
|
|
} |
|
7168
|
|
|
|
|
|
|
else { |
|
7169
|
732
|
|
|
|
|
3549
|
$self->xml_start_tag( 'sheetData' ); |
|
7170
|
732
|
|
|
|
|
4134
|
$self->_write_rows(); |
|
7171
|
732
|
|
|
|
|
3012
|
$self->xml_end_tag( 'sheetData' ); |
|
7172
|
|
|
|
|
|
|
|
|
7173
|
|
|
|
|
|
|
} |
|
7174
|
|
|
|
|
|
|
|
|
7175
|
|
|
|
|
|
|
} |
|
7176
|
|
|
|
|
|
|
|
|
7177
|
|
|
|
|
|
|
|
|
7178
|
|
|
|
|
|
|
############################################################################### |
|
7179
|
|
|
|
|
|
|
# |
|
7180
|
|
|
|
|
|
|
# _write_optimized_sheet_data() |
|
7181
|
|
|
|
|
|
|
# |
|
7182
|
|
|
|
|
|
|
# Write the element when the memory optimisation is on. In which |
|
7183
|
|
|
|
|
|
|
# case we read the data stored in the temp file and rewrite it to the XML |
|
7184
|
|
|
|
|
|
|
# sheet file. |
|
7185
|
|
|
|
|
|
|
# |
|
7186
|
|
|
|
|
|
|
sub _write_optimized_sheet_data { |
|
7187
|
|
|
|
|
|
|
|
|
7188
|
8
|
|
|
8
|
|
17
|
my $self = shift; |
|
7189
|
|
|
|
|
|
|
|
|
7190
|
8
|
50
|
|
|
|
38
|
if ( not defined $self->{_dim_rowmin} ) { |
|
7191
|
|
|
|
|
|
|
|
|
7192
|
|
|
|
|
|
|
# If the dimensions aren't defined then there is no data to write. |
|
7193
|
0
|
|
|
|
|
0
|
$self->xml_empty_tag( 'sheetData' ); |
|
7194
|
|
|
|
|
|
|
} |
|
7195
|
|
|
|
|
|
|
else { |
|
7196
|
|
|
|
|
|
|
|
|
7197
|
8
|
|
|
|
|
33
|
$self->xml_start_tag( 'sheetData' ); |
|
7198
|
|
|
|
|
|
|
|
|
7199
|
8
|
|
|
|
|
62
|
my $xlsx_fh = $self->xml_get_fh(); |
|
7200
|
8
|
|
|
|
|
17
|
my $cell_fh = $self->{_cell_data_fh}; |
|
7201
|
|
|
|
|
|
|
|
|
7202
|
8
|
|
|
|
|
23
|
my $buffer; |
|
7203
|
|
|
|
|
|
|
|
|
7204
|
|
|
|
|
|
|
# Rewind the temp file. |
|
7205
|
8
|
|
|
|
|
356
|
seek $cell_fh, 0, 0; |
|
7206
|
|
|
|
|
|
|
|
|
7207
|
8
|
|
|
|
|
272
|
while ( read( $cell_fh, $buffer, 4_096 ) ) { |
|
7208
|
12
|
|
|
|
|
49
|
local $\ = undef; # Protect print from -l on commandline. |
|
7209
|
12
|
|
|
|
|
442
|
print $xlsx_fh $buffer; |
|
7210
|
|
|
|
|
|
|
} |
|
7211
|
|
|
|
|
|
|
|
|
7212
|
8
|
|
|
|
|
39
|
$self->xml_end_tag( 'sheetData' ); |
|
7213
|
|
|
|
|
|
|
} |
|
7214
|
|
|
|
|
|
|
} |
|
7215
|
|
|
|
|
|
|
|
|
7216
|
|
|
|
|
|
|
|
|
7217
|
|
|
|
|
|
|
############################################################################### |
|
7218
|
|
|
|
|
|
|
# |
|
7219
|
|
|
|
|
|
|
# _write_rows() |
|
7220
|
|
|
|
|
|
|
# |
|
7221
|
|
|
|
|
|
|
# Write out the worksheet data as a series of rows and cells. |
|
7222
|
|
|
|
|
|
|
# |
|
7223
|
|
|
|
|
|
|
sub _write_rows { |
|
7224
|
|
|
|
|
|
|
|
|
7225
|
732
|
|
|
732
|
|
2125
|
my $self = shift; |
|
7226
|
|
|
|
|
|
|
|
|
7227
|
732
|
|
|
|
|
3830
|
$self->_calculate_spans(); |
|
7228
|
|
|
|
|
|
|
|
|
7229
|
732
|
|
|
|
|
2905
|
for my $row_num ( $self->{_dim_rowmin} .. $self->{_dim_rowmax} ) { |
|
7230
|
|
|
|
|
|
|
|
|
7231
|
|
|
|
|
|
|
# Skip row if it doesn't contain row formatting, cell data or a comment. |
|
7232
|
1052822
|
100
|
100
|
|
|
3764416
|
if ( !$self->{_set_rows}->{$row_num} |
|
|
|
|
100
|
|
|
|
|
|
7233
|
|
|
|
|
|
|
&& !$self->{_table}->{$row_num} |
|
7234
|
|
|
|
|
|
|
&& !$self->{_comments}->{$row_num} ) |
|
7235
|
|
|
|
|
|
|
{ |
|
7236
|
1048846
|
|
|
|
|
1478430
|
next; |
|
7237
|
|
|
|
|
|
|
} |
|
7238
|
|
|
|
|
|
|
|
|
7239
|
3976
|
|
|
|
|
9777
|
my $span_index = int( $row_num / 16 ); |
|
7240
|
3976
|
|
|
|
|
7454
|
my $span = $self->{_row_spans}->[$span_index]; |
|
7241
|
|
|
|
|
|
|
|
|
7242
|
|
|
|
|
|
|
# Write the cells if the row contains data. |
|
7243
|
3976
|
100
|
|
|
|
10062
|
if ( my $row_ref = $self->{_table}->{$row_num} ) { |
|
|
|
100
|
|
|
|
|
|
|
7244
|
|
|
|
|
|
|
|
|
7245
|
3610
|
100
|
|
|
|
8420
|
if ( !$self->{_set_rows}->{$row_num} ) { |
|
7246
|
3292
|
|
|
|
|
8725
|
$self->_write_row( $row_num, $span ); |
|
7247
|
|
|
|
|
|
|
} |
|
7248
|
|
|
|
|
|
|
else { |
|
7249
|
|
|
|
|
|
|
$self->_write_row( $row_num, $span, |
|
7250
|
318
|
|
|
|
|
533
|
@{ $self->{_set_rows}->{$row_num} } ); |
|
|
318
|
|
|
|
|
897
|
|
|
7251
|
|
|
|
|
|
|
} |
|
7252
|
|
|
|
|
|
|
|
|
7253
|
|
|
|
|
|
|
|
|
7254
|
3610
|
|
|
|
|
9929
|
for my $col_num ( $self->{_dim_colmin} .. $self->{_dim_colmax} ) { |
|
7255
|
26693
|
100
|
|
|
|
59136
|
if ( my $col_ref = $self->{_table}->{$row_num}->{$col_num} ) { |
|
7256
|
9797
|
|
|
|
|
20256
|
$self->_write_cell( $row_num, $col_num, $col_ref ); |
|
7257
|
|
|
|
|
|
|
} |
|
7258
|
|
|
|
|
|
|
} |
|
7259
|
|
|
|
|
|
|
|
|
7260
|
3610
|
|
|
|
|
9735
|
$self->xml_end_tag( 'row' ); |
|
7261
|
|
|
|
|
|
|
} |
|
7262
|
|
|
|
|
|
|
elsif ( $self->{_comments}->{$row_num} ) { |
|
7263
|
|
|
|
|
|
|
|
|
7264
|
|
|
|
|
|
|
$self->_write_empty_row( $row_num, $span, |
|
7265
|
304
|
|
|
|
|
460
|
@{ $self->{_set_rows}->{$row_num} } ); |
|
|
304
|
|
|
|
|
1064
|
|
|
7266
|
|
|
|
|
|
|
} |
|
7267
|
|
|
|
|
|
|
else { |
|
7268
|
|
|
|
|
|
|
|
|
7269
|
|
|
|
|
|
|
# Row attributes only. |
|
7270
|
|
|
|
|
|
|
$self->_write_empty_row( $row_num, $span, |
|
7271
|
62
|
|
|
|
|
108
|
@{ $self->{_set_rows}->{$row_num} } ); |
|
|
62
|
|
|
|
|
220
|
|
|
7272
|
|
|
|
|
|
|
} |
|
7273
|
|
|
|
|
|
|
} |
|
7274
|
|
|
|
|
|
|
} |
|
7275
|
|
|
|
|
|
|
|
|
7276
|
|
|
|
|
|
|
|
|
7277
|
|
|
|
|
|
|
############################################################################### |
|
7278
|
|
|
|
|
|
|
# |
|
7279
|
|
|
|
|
|
|
# _write_single_row() |
|
7280
|
|
|
|
|
|
|
# |
|
7281
|
|
|
|
|
|
|
# Write out the worksheet data as a single row with cells. This method is |
|
7282
|
|
|
|
|
|
|
# used when memory optimisation is on. A single row is written and the data |
|
7283
|
|
|
|
|
|
|
# table is reset. That way only one row of data is kept in memory at any one |
|
7284
|
|
|
|
|
|
|
# time. We don't write span data in the optimised case since it is optional. |
|
7285
|
|
|
|
|
|
|
# |
|
7286
|
|
|
|
|
|
|
sub _write_single_row { |
|
7287
|
|
|
|
|
|
|
|
|
7288
|
296
|
|
|
296
|
|
442
|
my $self = shift; |
|
7289
|
296
|
|
100
|
|
|
639
|
my $current_row = shift || 0; |
|
7290
|
296
|
|
|
|
|
490
|
my $row_num = $self->{_previous_row}; |
|
7291
|
|
|
|
|
|
|
|
|
7292
|
|
|
|
|
|
|
# Set the new previous row as the current row. |
|
7293
|
296
|
|
|
|
|
485
|
$self->{_previous_row} = $current_row; |
|
7294
|
|
|
|
|
|
|
|
|
7295
|
|
|
|
|
|
|
# Skip row if it doesn't contain row formatting, cell data or a comment. |
|
7296
|
296
|
0
|
66
|
|
|
1019
|
if ( !$self->{_set_rows}->{$row_num} |
|
|
|
|
33
|
|
|
|
|
|
7297
|
|
|
|
|
|
|
&& !$self->{_table}->{$row_num} |
|
7298
|
|
|
|
|
|
|
&& !$self->{_comments}->{$row_num} ) |
|
7299
|
|
|
|
|
|
|
{ |
|
7300
|
0
|
|
|
|
|
0
|
return; |
|
7301
|
|
|
|
|
|
|
} |
|
7302
|
|
|
|
|
|
|
|
|
7303
|
|
|
|
|
|
|
# Write the cells if the row contains data. |
|
7304
|
296
|
50
|
|
|
|
626
|
if ( my $row_ref = $self->{_table}->{$row_num} ) { |
|
7305
|
|
|
|
|
|
|
|
|
7306
|
296
|
100
|
|
|
|
559
|
if ( !$self->{_set_rows}->{$row_num} ) { |
|
7307
|
295
|
|
|
|
|
635
|
$self->_write_row( $row_num ); |
|
7308
|
|
|
|
|
|
|
} |
|
7309
|
|
|
|
|
|
|
else { |
|
7310
|
|
|
|
|
|
|
$self->_write_row( $row_num, undef, |
|
7311
|
1
|
|
|
|
|
2
|
@{ $self->{_set_rows}->{$row_num} } ); |
|
|
1
|
|
|
|
|
21
|
|
|
7312
|
|
|
|
|
|
|
} |
|
7313
|
|
|
|
|
|
|
|
|
7314
|
296
|
|
|
|
|
728
|
for my $col_num ( $self->{_dim_colmin} .. $self->{_dim_colmax} ) { |
|
7315
|
325
|
100
|
|
|
|
894
|
if ( my $col_ref = $self->{_table}->{$row_num}->{$col_num} ) { |
|
7316
|
305
|
|
|
|
|
624
|
$self->_write_cell( $row_num, $col_num, $col_ref ); |
|
7317
|
|
|
|
|
|
|
} |
|
7318
|
|
|
|
|
|
|
} |
|
7319
|
|
|
|
|
|
|
|
|
7320
|
296
|
|
|
|
|
763
|
$self->xml_end_tag( 'row' ); |
|
7321
|
|
|
|
|
|
|
} |
|
7322
|
|
|
|
|
|
|
else { |
|
7323
|
|
|
|
|
|
|
|
|
7324
|
|
|
|
|
|
|
# Row attributes or comments only. |
|
7325
|
|
|
|
|
|
|
$self->_write_empty_row( $row_num, undef, |
|
7326
|
0
|
|
|
|
|
0
|
@{ $self->{_set_rows}->{$row_num} } ); |
|
|
0
|
|
|
|
|
0
|
|
|
7327
|
|
|
|
|
|
|
} |
|
7328
|
|
|
|
|
|
|
|
|
7329
|
|
|
|
|
|
|
# Reset table. |
|
7330
|
296
|
|
|
|
|
936
|
$self->{_table} = {}; |
|
7331
|
|
|
|
|
|
|
|
|
7332
|
|
|
|
|
|
|
} |
|
7333
|
|
|
|
|
|
|
|
|
7334
|
|
|
|
|
|
|
|
|
7335
|
|
|
|
|
|
|
############################################################################### |
|
7336
|
|
|
|
|
|
|
# |
|
7337
|
|
|
|
|
|
|
# _calculate_spans() |
|
7338
|
|
|
|
|
|
|
# |
|
7339
|
|
|
|
|
|
|
# Calculate the "spans" attribute of the tag. This is an XLSX |
|
7340
|
|
|
|
|
|
|
# optimisation and isn't strictly required. However, it makes comparing |
|
7341
|
|
|
|
|
|
|
# files easier. |
|
7342
|
|
|
|
|
|
|
# |
|
7343
|
|
|
|
|
|
|
# The span is the same for each block of 16 rows. |
|
7344
|
|
|
|
|
|
|
# |
|
7345
|
|
|
|
|
|
|
sub _calculate_spans { |
|
7346
|
|
|
|
|
|
|
|
|
7347
|
750
|
|
|
750
|
|
1986
|
my $self = shift; |
|
7348
|
|
|
|
|
|
|
|
|
7349
|
750
|
|
|
|
|
3211
|
my @spans; |
|
7350
|
|
|
|
|
|
|
my $span_min; |
|
7351
|
750
|
|
|
|
|
0
|
my $span_max; |
|
7352
|
|
|
|
|
|
|
|
|
7353
|
750
|
|
|
|
|
3397
|
for my $row_num ( $self->{_dim_rowmin} .. $self->{_dim_rowmax} ) { |
|
7354
|
|
|
|
|
|
|
|
|
7355
|
|
|
|
|
|
|
# Calculate spans for cell data. |
|
7356
|
1053128
|
100
|
|
|
|
1958938
|
if ( my $row_ref = $self->{_table}->{$row_num} ) { |
|
7357
|
|
|
|
|
|
|
|
|
7358
|
3916
|
|
|
|
|
8379
|
for my $col_num ( $self->{_dim_colmin} .. $self->{_dim_colmax} ) { |
|
7359
|
31895
|
100
|
|
|
|
63969
|
if ( my $col_ref = $self->{_table}->{$row_num}->{$col_num} ) { |
|
7360
|
|
|
|
|
|
|
|
|
7361
|
10103
|
100
|
|
|
|
17528
|
if ( !defined $span_min ) { |
|
7362
|
790
|
|
|
|
|
2009
|
$span_min = $col_num; |
|
7363
|
790
|
|
|
|
|
2450
|
$span_max = $col_num; |
|
7364
|
|
|
|
|
|
|
} |
|
7365
|
|
|
|
|
|
|
else { |
|
7366
|
9313
|
100
|
|
|
|
16672
|
$span_min = $col_num if $col_num < $span_min; |
|
7367
|
9313
|
100
|
|
|
|
19718
|
$span_max = $col_num if $col_num > $span_max; |
|
7368
|
|
|
|
|
|
|
} |
|
7369
|
|
|
|
|
|
|
} |
|
7370
|
|
|
|
|
|
|
} |
|
7371
|
|
|
|
|
|
|
} |
|
7372
|
|
|
|
|
|
|
|
|
7373
|
|
|
|
|
|
|
# Calculate spans for comments. |
|
7374
|
1053128
|
100
|
|
|
|
1791128
|
if ( defined $self->{_comments}->{$row_num} ) { |
|
7375
|
|
|
|
|
|
|
|
|
7376
|
310
|
|
|
|
|
632
|
for my $col_num ( $self->{_dim_colmin} .. $self->{_dim_colmax} ) { |
|
7377
|
36973
|
100
|
|
|
|
69377
|
if ( defined $self->{_comments}->{$row_num}->{$col_num} ) { |
|
7378
|
|
|
|
|
|
|
|
|
7379
|
4153
|
100
|
|
|
|
6353
|
if ( !defined $span_min ) { |
|
7380
|
33
|
|
|
|
|
90
|
$span_min = $col_num; |
|
7381
|
33
|
|
|
|
|
81
|
$span_max = $col_num; |
|
7382
|
|
|
|
|
|
|
} |
|
7383
|
|
|
|
|
|
|
else { |
|
7384
|
4120
|
50
|
|
|
|
6834
|
$span_min = $col_num if $col_num < $span_min; |
|
7385
|
4120
|
100
|
|
|
|
7614
|
$span_max = $col_num if $col_num > $span_max; |
|
7386
|
|
|
|
|
|
|
} |
|
7387
|
|
|
|
|
|
|
} |
|
7388
|
|
|
|
|
|
|
} |
|
7389
|
|
|
|
|
|
|
} |
|
7390
|
|
|
|
|
|
|
|
|
7391
|
1053128
|
100
|
100
|
|
|
2867715
|
if ( ( ( $row_num + 1 ) % 16 == 0 ) |
|
7392
|
|
|
|
|
|
|
|| $row_num == $self->{_dim_rowmax} ) |
|
7393
|
|
|
|
|
|
|
{ |
|
7394
|
66374
|
|
|
|
|
105505
|
my $span_index = int( $row_num / 16 ); |
|
7395
|
|
|
|
|
|
|
|
|
7396
|
66374
|
100
|
|
|
|
124282
|
if ( defined $span_min ) { |
|
7397
|
823
|
|
|
|
|
1969
|
$span_min++; |
|
7398
|
823
|
|
|
|
|
1819
|
$span_max++; |
|
7399
|
823
|
|
|
|
|
4027
|
$spans[$span_index] = "$span_min:$span_max"; |
|
7400
|
823
|
|
|
|
|
2608
|
$span_min = undef; |
|
7401
|
|
|
|
|
|
|
} |
|
7402
|
|
|
|
|
|
|
} |
|
7403
|
|
|
|
|
|
|
} |
|
7404
|
|
|
|
|
|
|
|
|
7405
|
750
|
|
|
|
|
2997
|
$self->{_row_spans} = \@spans; |
|
7406
|
|
|
|
|
|
|
} |
|
7407
|
|
|
|
|
|
|
|
|
7408
|
|
|
|
|
|
|
|
|
7409
|
|
|
|
|
|
|
############################################################################### |
|
7410
|
|
|
|
|
|
|
# |
|
7411
|
|
|
|
|
|
|
# _write_row() |
|
7412
|
|
|
|
|
|
|
# |
|
7413
|
|
|
|
|
|
|
# Write the element. |
|
7414
|
|
|
|
|
|
|
# |
|
7415
|
|
|
|
|
|
|
sub _write_row { |
|
7416
|
|
|
|
|
|
|
|
|
7417
|
4280
|
|
|
4280
|
|
7011
|
my $self = shift; |
|
7418
|
4280
|
|
|
|
|
6944
|
my $r = shift; |
|
7419
|
4280
|
|
|
|
|
6902
|
my $spans = shift; |
|
7420
|
4280
|
|
|
|
|
6477
|
my $height = shift; |
|
7421
|
4280
|
|
|
|
|
6585
|
my $format = shift; |
|
7422
|
4280
|
|
100
|
|
|
12701
|
my $hidden = shift || 0; |
|
7423
|
4280
|
|
100
|
|
|
12354
|
my $level = shift || 0; |
|
7424
|
4280
|
|
100
|
|
|
11933
|
my $collapsed = shift || 0; |
|
7425
|
4280
|
|
100
|
|
|
11383
|
my $empty_row = shift || 0; |
|
7426
|
4280
|
|
|
|
|
6487
|
my $xf_index = 0; |
|
7427
|
|
|
|
|
|
|
|
|
7428
|
4280
|
100
|
|
|
|
10516
|
$height = $self->{_default_row_height} if !defined $height; |
|
7429
|
|
|
|
|
|
|
|
|
7430
|
4280
|
|
|
|
|
9747
|
my @attributes = ( 'r' => $r + 1 ); |
|
7431
|
|
|
|
|
|
|
|
|
7432
|
|
|
|
|
|
|
# Get the format index. |
|
7433
|
4280
|
100
|
|
|
|
9517
|
if ( ref( $format ) ) { |
|
7434
|
11
|
|
|
|
|
48
|
$xf_index = $format->get_xf_index(); |
|
7435
|
|
|
|
|
|
|
} |
|
7436
|
|
|
|
|
|
|
|
|
7437
|
4280
|
100
|
|
|
|
11669
|
push @attributes, ( 'spans' => $spans ) if defined $spans; |
|
7438
|
4280
|
100
|
|
|
|
8742
|
push @attributes, ( 's' => $xf_index ) if $xf_index; |
|
7439
|
4280
|
100
|
|
|
|
8800
|
push @attributes, ( 'customFormat' => 1 ) if $format; |
|
7440
|
|
|
|
|
|
|
|
|
7441
|
4280
|
100
|
|
|
|
9932
|
if ( $height != $self->{_original_row_height} ) { |
|
7442
|
67
|
|
|
|
|
169
|
push @attributes, ( 'ht' => $height ); |
|
7443
|
|
|
|
|
|
|
} |
|
7444
|
|
|
|
|
|
|
|
|
7445
|
4280
|
100
|
|
|
|
8859
|
push @attributes, ( 'hidden' => 1 ) if $hidden; |
|
7446
|
|
|
|
|
|
|
|
|
7447
|
4280
|
100
|
|
|
|
9745
|
if ( $height != $self->{_original_row_height} ) { |
|
7448
|
67
|
|
|
|
|
153
|
push @attributes, ( 'customHeight' => 1 ); |
|
7449
|
|
|
|
|
|
|
} |
|
7450
|
|
|
|
|
|
|
|
|
7451
|
4280
|
100
|
|
|
|
8514
|
push @attributes, ( 'outlineLevel' => $level ) if $level; |
|
7452
|
4280
|
100
|
|
|
|
8514
|
push @attributes, ( 'collapsed' => 1 ) if $collapsed; |
|
7453
|
|
|
|
|
|
|
|
|
7454
|
4280
|
100
|
|
|
|
9887
|
if ( $self->{_excel_version} == 2010 ) { |
|
7455
|
60
|
|
|
|
|
110
|
push @attributes, ( 'x14ac:dyDescent' => '0.25' ); |
|
7456
|
|
|
|
|
|
|
} |
|
7457
|
|
|
|
|
|
|
|
|
7458
|
4280
|
100
|
|
|
|
9018
|
if ( $empty_row ) { |
|
7459
|
367
|
|
|
|
|
1205
|
$self->xml_empty_tag_unencoded( 'row', @attributes ); |
|
7460
|
|
|
|
|
|
|
} |
|
7461
|
|
|
|
|
|
|
else { |
|
7462
|
3913
|
|
|
|
|
13776
|
$self->xml_start_tag_unencoded( 'row', @attributes ); |
|
7463
|
|
|
|
|
|
|
} |
|
7464
|
|
|
|
|
|
|
} |
|
7465
|
|
|
|
|
|
|
|
|
7466
|
|
|
|
|
|
|
|
|
7467
|
|
|
|
|
|
|
############################################################################### |
|
7468
|
|
|
|
|
|
|
# |
|
7469
|
|
|
|
|
|
|
# _write_empty_row() |
|
7470
|
|
|
|
|
|
|
# |
|
7471
|
|
|
|
|
|
|
# Write and empty element, i.e., attributes only, no cell data. |
|
7472
|
|
|
|
|
|
|
# |
|
7473
|
|
|
|
|
|
|
sub _write_empty_row { |
|
7474
|
|
|
|
|
|
|
|
|
7475
|
367
|
|
|
367
|
|
631
|
my $self = shift; |
|
7476
|
|
|
|
|
|
|
|
|
7477
|
|
|
|
|
|
|
# Set the $empty_row parameter. |
|
7478
|
367
|
|
|
|
|
662
|
$_[7] = 1; |
|
7479
|
|
|
|
|
|
|
|
|
7480
|
367
|
|
|
|
|
905
|
$self->_write_row( @_ ); |
|
7481
|
|
|
|
|
|
|
} |
|
7482
|
|
|
|
|
|
|
|
|
7483
|
|
|
|
|
|
|
|
|
7484
|
|
|
|
|
|
|
############################################################################### |
|
7485
|
|
|
|
|
|
|
# |
|
7486
|
|
|
|
|
|
|
# _write_cell() |
|
7487
|
|
|
|
|
|
|
# |
|
7488
|
|
|
|
|
|
|
# Write the | element. This is the innermost loop so efficiency is | |
|
7489
|
|
|
|
|
|
|
# important where possible. The basic methodology is that the data of every |
|
7490
|
|
|
|
|
|
|
# cell type is passed in as follows: |
|
7491
|
|
|
|
|
|
|
# |
|
7492
|
|
|
|
|
|
|
# [ $row, $col, $aref] |
|
7493
|
|
|
|
|
|
|
# |
|
7494
|
|
|
|
|
|
|
# The aref, called $cell below, contains the following structure in all types: |
|
7495
|
|
|
|
|
|
|
# |
|
7496
|
|
|
|
|
|
|
# [ $type, $token, $xf, @args ] |
|
7497
|
|
|
|
|
|
|
# |
|
7498
|
|
|
|
|
|
|
# Where $type: represents the cell type, such as string, number, formula, etc. |
|
7499
|
|
|
|
|
|
|
# $token: is the actual data for the string, number, formula, etc. |
|
7500
|
|
|
|
|
|
|
# $xf: is the XF format object. |
|
7501
|
|
|
|
|
|
|
# @args: additional args relevant to the specific data type. |
|
7502
|
|
|
|
|
|
|
# |
|
7503
|
|
|
|
|
|
|
sub _write_cell { |
|
7504
|
|
|
|
|
|
|
|
|
7505
|
10107
|
|
|
10107
|
|
15097
|
my $self = shift; |
|
7506
|
10107
|
|
|
|
|
15170
|
my $row = shift; |
|
7507
|
10107
|
|
|
|
|
14615
|
my $col = shift; |
|
7508
|
10107
|
|
|
|
|
13669
|
my $cell = shift; |
|
7509
|
10107
|
|
|
|
|
16717
|
my $type = $cell->[0]; |
|
7510
|
10107
|
|
|
|
|
14264
|
my $token = $cell->[1]; |
|
7511
|
10107
|
|
|
|
|
14305
|
my $xf = $cell->[2]; |
|
7512
|
10107
|
|
|
|
|
13808
|
my $xf_index = 0; |
|
7513
|
|
|
|
|
|
|
|
|
7514
|
10107
|
|
|
|
|
33264
|
my %error_codes = ( |
|
7515
|
|
|
|
|
|
|
'#DIV/0!' => 1, |
|
7516
|
|
|
|
|
|
|
'#N/A' => 1, |
|
7517
|
|
|
|
|
|
|
'#NAME?' => 1, |
|
7518
|
|
|
|
|
|
|
'#NULL!' => 1, |
|
7519
|
|
|
|
|
|
|
'#NUM!' => 1, |
|
7520
|
|
|
|
|
|
|
'#REF!' => 1, |
|
7521
|
|
|
|
|
|
|
'#VALUE!' => 1, |
|
7522
|
|
|
|
|
|
|
); |
|
7523
|
|
|
|
|
|
|
|
|
7524
|
10107
|
|
|
|
|
19625
|
my %boolean = ( 'TRUE' => 1, 'FALSE' => 0 ); |
|
7525
|
|
|
|
|
|
|
|
|
7526
|
|
|
|
|
|
|
# Get the format index. |
|
7527
|
10107
|
100
|
|
|
|
19573
|
if ( ref( $xf ) ) { |
|
7528
|
410
|
|
|
|
|
1335
|
$xf_index = $xf->get_xf_index(); |
|
7529
|
|
|
|
|
|
|
} |
|
7530
|
|
|
|
|
|
|
|
|
7531
|
10107
|
|
|
|
|
20004
|
my $range = _xl_rowcol_to_cell( $row, $col ); |
|
7532
|
10107
|
|
|
|
|
21238
|
my @attributes = ( 'r' => $range ); |
|
7533
|
|
|
|
|
|
|
|
|
7534
|
|
|
|
|
|
|
# Add the cell format index. |
|
7535
|
10107
|
100
|
66
|
|
|
36908
|
if ( $xf_index ) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
7536
|
410
|
|
|
|
|
954
|
push @attributes, ( 's' => $xf_index ); |
|
7537
|
|
|
|
|
|
|
} |
|
7538
|
|
|
|
|
|
|
elsif ( $self->{_set_rows}->{$row} && $self->{_set_rows}->{$row}->[1] ) { |
|
7539
|
11
|
|
|
|
|
25
|
my $row_xf = $self->{_set_rows}->{$row}->[1]; |
|
7540
|
11
|
|
|
|
|
30
|
push @attributes, ( 's' => $row_xf->get_xf_index() ); |
|
7541
|
|
|
|
|
|
|
} |
|
7542
|
|
|
|
|
|
|
elsif ( $self->{_col_formats}->{$col} ) { |
|
7543
|
17
|
|
|
|
|
35
|
my $col_xf = $self->{_col_formats}->{$col}; |
|
7544
|
17
|
|
|
|
|
65
|
push @attributes, ( 's' => $col_xf->get_xf_index() ); |
|
7545
|
|
|
|
|
|
|
} |
|
7546
|
|
|
|
|
|
|
|
|
7547
|
|
|
|
|
|
|
|
|
7548
|
|
|
|
|
|
|
# Write the various cell types. |
|
7549
|
10107
|
100
|
|
|
|
21198
|
if ( $type eq 'n' ) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
7550
|
|
|
|
|
|
|
|
|
7551
|
|
|
|
|
|
|
# Write a number. |
|
7552
|
7025
|
|
|
|
|
18676
|
$self->xml_number_element( $token, @attributes ); |
|
7553
|
|
|
|
|
|
|
} |
|
7554
|
|
|
|
|
|
|
elsif ( $type eq 's' ) { |
|
7555
|
|
|
|
|
|
|
|
|
7556
|
|
|
|
|
|
|
# Write a string. |
|
7557
|
2940
|
100
|
|
|
|
5865
|
if ( $self->{_optimization} == 0 ) { |
|
7558
|
2642
|
|
|
|
|
7665
|
$self->xml_string_element( $token, @attributes ); |
|
7559
|
|
|
|
|
|
|
} |
|
7560
|
|
|
|
|
|
|
else { |
|
7561
|
|
|
|
|
|
|
|
|
7562
|
298
|
|
|
|
|
430
|
my $string = $token; |
|
7563
|
|
|
|
|
|
|
|
|
7564
|
|
|
|
|
|
|
# Escape control characters. See SharedString.pm for details. |
|
7565
|
298
|
|
|
|
|
581
|
$string =~ s/(_x[0-9a-fA-F]{4}_)/_x005F$1/g; |
|
7566
|
298
|
|
|
|
|
620
|
$string =~ s/([\x00-\x08\x0B-\x1F])/sprintf "_x%04X_", ord($1)/eg; |
|
|
30
|
|
|
|
|
127
|
|
|
7567
|
|
|
|
|
|
|
|
|
7568
|
|
|
|
|
|
|
# Write any rich strings without further tags. |
|
7569
|
298
|
100
|
66
|
|
|
731
|
if ( $string =~ m{^} && $string =~ m{$} ) { |
|
7570
|
|
|
|
|
|
|
|
|
7571
|
8
|
|
|
|
|
41
|
$self->xml_rich_inline_string( $string, @attributes ); |
|
7572
|
|
|
|
|
|
|
} |
|
7573
|
|
|
|
|
|
|
else { |
|
7574
|
|
|
|
|
|
|
|
|
7575
|
|
|
|
|
|
|
# Add attribute to preserve leading or trailing whitespace. |
|
7576
|
290
|
|
|
|
|
417
|
my $preserve = 0; |
|
7577
|
290
|
100
|
66
|
|
|
1233
|
if ( $string =~ /^\s/ || $string =~ /\s$/ ) { |
|
7578
|
3
|
|
|
|
|
6
|
$preserve = 1; |
|
7579
|
|
|
|
|
|
|
} |
|
7580
|
|
|
|
|
|
|
|
|
7581
|
290
|
|
|
|
|
905
|
$self->xml_inline_string( $string, $preserve, @attributes ); |
|
7582
|
|
|
|
|
|
|
} |
|
7583
|
|
|
|
|
|
|
} |
|
7584
|
|
|
|
|
|
|
} |
|
7585
|
|
|
|
|
|
|
elsif ( $type eq 'f' ) { |
|
7586
|
|
|
|
|
|
|
|
|
7587
|
|
|
|
|
|
|
# Write a formula. |
|
7588
|
75
|
|
100
|
|
|
252
|
my $value = $cell->[3] || 0; |
|
7589
|
|
|
|
|
|
|
|
|
7590
|
|
|
|
|
|
|
# Check if the formula value is a string. |
|
7591
|
75
|
100
|
100
|
|
|
461
|
if ( $value |
|
7592
|
|
|
|
|
|
|
&& $value !~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/ ) |
|
7593
|
|
|
|
|
|
|
{ |
|
7594
|
17
|
100
|
|
|
|
50
|
if ( exists $boolean{$value} ) { |
|
|
|
100
|
|
|
|
|
|
|
7595
|
2
|
|
|
|
|
5
|
push @attributes, ( 't' => 'b' ); |
|
7596
|
2
|
|
|
|
|
4
|
$value = $boolean{$value}; |
|
7597
|
|
|
|
|
|
|
} |
|
7598
|
|
|
|
|
|
|
elsif ( exists $error_codes{$value} ) { |
|
7599
|
8
|
|
|
|
|
16
|
push @attributes, ( 't' => 'e' ); |
|
7600
|
|
|
|
|
|
|
} |
|
7601
|
|
|
|
|
|
|
else { |
|
7602
|
7
|
|
|
|
|
26
|
push @attributes, ( 't' => 'str' ); |
|
7603
|
7
|
|
|
|
|
26
|
$value = Excel::Writer::XLSX::Package::XMLwriter::_escape_data( |
|
7604
|
|
|
|
|
|
|
$value ); |
|
7605
|
|
|
|
|
|
|
} |
|
7606
|
|
|
|
|
|
|
} |
|
7607
|
|
|
|
|
|
|
|
|
7608
|
75
|
|
|
|
|
390
|
$self->xml_formula_element( $token, $value, @attributes ); |
|
7609
|
|
|
|
|
|
|
|
|
7610
|
|
|
|
|
|
|
} |
|
7611
|
|
|
|
|
|
|
elsif ( $type eq 'a' ) { |
|
7612
|
|
|
|
|
|
|
|
|
7613
|
|
|
|
|
|
|
# Write an array formula. |
|
7614
|
8
|
|
|
|
|
41
|
$self->xml_start_tag( 'c', @attributes ); |
|
7615
|
8
|
|
|
|
|
53
|
$self->_write_cell_array_formula( $token, $cell->[3] ); |
|
7616
|
8
|
|
|
|
|
38
|
$self->_write_cell_value( $cell->[4] ); |
|
7617
|
8
|
|
|
|
|
41
|
$self->xml_end_tag( 'c' ); |
|
7618
|
|
|
|
|
|
|
} |
|
7619
|
|
|
|
|
|
|
elsif ( $type eq 'l' ) { |
|
7620
|
|
|
|
|
|
|
|
|
7621
|
|
|
|
|
|
|
# Write a boolean value. |
|
7622
|
4
|
|
|
|
|
9
|
push @attributes, ( 't' => 'b' ); |
|
7623
|
|
|
|
|
|
|
|
|
7624
|
4
|
|
|
|
|
17
|
$self->xml_start_tag( 'c', @attributes ); |
|
7625
|
4
|
|
|
|
|
15
|
$self->_write_cell_value( $cell->[1] ); |
|
7626
|
4
|
|
|
|
|
12
|
$self->xml_end_tag( 'c' ); |
|
7627
|
|
|
|
|
|
|
} |
|
7628
|
|
|
|
|
|
|
elsif ( $type eq 'b' ) { |
|
7629
|
|
|
|
|
|
|
|
|
7630
|
|
|
|
|
|
|
# Write a empty cell. |
|
7631
|
55
|
|
|
|
|
177
|
$self->xml_empty_tag( 'c', @attributes ); |
|
7632
|
|
|
|
|
|
|
} |
|
7633
|
|
|
|
|
|
|
} |
|
7634
|
|
|
|
|
|
|
|
|
7635
|
|
|
|
|
|
|
|
|
7636
|
|
|
|
|
|
|
############################################################################### |
|
7637
|
|
|
|
|
|
|
# |
|
7638
|
|
|
|
|
|
|
# _write_cell_value() |
|
7639
|
|
|
|
|
|
|
# |
|
7640
|
|
|
|
|
|
|
# Write the cell value element. |
|
7641
|
|
|
|
|
|
|
# |
|
7642
|
|
|
|
|
|
|
sub _write_cell_value { |
|
7643
|
|
|
|
|
|
|
|
|
7644
|
13
|
|
|
13
|
|
40
|
my $self = shift; |
|
7645
|
13
|
50
|
|
|
|
45
|
my $value = defined $_[0] ? $_[0] : ''; |
|
7646
|
|
|
|
|
|
|
|
|
7647
|
13
|
|
|
|
|
64
|
$self->xml_data_element( 'v', $value ); |
|
7648
|
|
|
|
|
|
|
} |
|
7649
|
|
|
|
|
|
|
|
|
7650
|
|
|
|
|
|
|
|
|
7651
|
|
|
|
|
|
|
############################################################################### |
|
7652
|
|
|
|
|
|
|
# |
|
7653
|
|
|
|
|
|
|
# _write_cell_formula() |
|
7654
|
|
|
|
|
|
|
# |
|
7655
|
|
|
|
|
|
|
# Write the cell formula element. |
|
7656
|
|
|
|
|
|
|
# |
|
7657
|
|
|
|
|
|
|
sub _write_cell_formula { |
|
7658
|
|
|
|
|
|
|
|
|
7659
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
|
7660
|
0
|
0
|
|
|
|
0
|
my $formula = defined $_[0] ? $_[0] : ''; |
|
7661
|
|
|
|
|
|
|
|
|
7662
|
0
|
|
|
|
|
0
|
$self->xml_data_element( 'f', $formula ); |
|
7663
|
|
|
|
|
|
|
} |
|
7664
|
|
|
|
|
|
|
|
|
7665
|
|
|
|
|
|
|
|
|
7666
|
|
|
|
|
|
|
############################################################################### |
|
7667
|
|
|
|
|
|
|
# |
|
7668
|
|
|
|
|
|
|
# _write_cell_array_formula() |
|
7669
|
|
|
|
|
|
|
# |
|
7670
|
|
|
|
|
|
|
# Write the cell array formula element. |
|
7671
|
|
|
|
|
|
|
# |
|
7672
|
|
|
|
|
|
|
sub _write_cell_array_formula { |
|
7673
|
|
|
|
|
|
|
|
|
7674
|
8
|
|
|
8
|
|
21
|
my $self = shift; |
|
7675
|
8
|
|
|
|
|
22
|
my $formula = shift; |
|
7676
|
8
|
|
|
|
|
29
|
my $range = shift; |
|
7677
|
|
|
|
|
|
|
|
|
7678
|
8
|
|
|
|
|
28
|
my @attributes = ( 't' => 'array', 'ref' => $range ); |
|
7679
|
|
|
|
|
|
|
|
|
7680
|
8
|
|
|
|
|
59
|
$self->xml_data_element( 'f', $formula, @attributes ); |
|
7681
|
|
|
|
|
|
|
} |
|
7682
|
|
|
|
|
|
|
|
|
7683
|
|
|
|
|
|
|
|
|
7684
|
|
|
|
|
|
|
############################################################################## |
|
7685
|
|
|
|
|
|
|
# |
|
7686
|
|
|
|
|
|
|
# _write_sheet_calc_pr() |
|
7687
|
|
|
|
|
|
|
# |
|
7688
|
|
|
|
|
|
|
# Write the element for the worksheet calculation properties. |
|
7689
|
|
|
|
|
|
|
# |
|
7690
|
|
|
|
|
|
|
sub _write_sheet_calc_pr { |
|
7691
|
|
|
|
|
|
|
|
|
7692
|
1
|
|
|
1
|
|
9
|
my $self = shift; |
|
7693
|
1
|
|
|
|
|
3
|
my $full_calc_on_load = 1; |
|
7694
|
|
|
|
|
|
|
|
|
7695
|
1
|
|
|
|
|
4
|
my @attributes = ( 'fullCalcOnLoad' => $full_calc_on_load ); |
|
7696
|
|
|
|
|
|
|
|
|
7697
|
1
|
|
|
|
|
9
|
$self->xml_empty_tag( 'sheetCalcPr', @attributes ); |
|
7698
|
|
|
|
|
|
|
} |
|
7699
|
|
|
|
|
|
|
|
|
7700
|
|
|
|
|
|
|
|
|
7701
|
|
|
|
|
|
|
############################################################################### |
|
7702
|
|
|
|
|
|
|
# |
|
7703
|
|
|
|
|
|
|
# _write_phonetic_pr() |
|
7704
|
|
|
|
|
|
|
# |
|
7705
|
|
|
|
|
|
|
# Write the element. |
|
7706
|
|
|
|
|
|
|
# |
|
7707
|
|
|
|
|
|
|
sub _write_phonetic_pr { |
|
7708
|
|
|
|
|
|
|
|
|
7709
|
9
|
|
|
9
|
|
28
|
my $self = shift; |
|
7710
|
9
|
|
|
|
|
24
|
my $font_id = 0; |
|
7711
|
9
|
|
|
|
|
23
|
my $type = 'noConversion'; |
|
7712
|
|
|
|
|
|
|
|
|
7713
|
9
|
|
|
|
|
35
|
my @attributes = ( |
|
7714
|
|
|
|
|
|
|
'fontId' => $font_id, |
|
7715
|
|
|
|
|
|
|
'type' => $type, |
|
7716
|
|
|
|
|
|
|
); |
|
7717
|
|
|
|
|
|
|
|
|
7718
|
9
|
|
|
|
|
37
|
$self->xml_empty_tag( 'phoneticPr', @attributes ); |
|
7719
|
|
|
|
|
|
|
} |
|
7720
|
|
|
|
|
|
|
|
|
7721
|
|
|
|
|
|
|
|
|
7722
|
|
|
|
|
|
|
############################################################################### |
|
7723
|
|
|
|
|
|
|
# |
|
7724
|
|
|
|
|
|
|
# _write_page_margins() |
|
7725
|
|
|
|
|
|
|
# |
|
7726
|
|
|
|
|
|
|
# Write the element. |
|
7727
|
|
|
|
|
|
|
# |
|
7728
|
|
|
|
|
|
|
sub _write_page_margins { |
|
7729
|
|
|
|
|
|
|
|
|
7730
|
1025
|
|
|
1025
|
|
2505
|
my $self = shift; |
|
7731
|
|
|
|
|
|
|
|
|
7732
|
|
|
|
|
|
|
my @attributes = ( |
|
7733
|
|
|
|
|
|
|
'left' => $self->{_margin_left}, |
|
7734
|
|
|
|
|
|
|
'right' => $self->{_margin_right}, |
|
7735
|
|
|
|
|
|
|
'top' => $self->{_margin_top}, |
|
7736
|
|
|
|
|
|
|
'bottom' => $self->{_margin_bottom}, |
|
7737
|
|
|
|
|
|
|
'header' => $self->{_margin_header}, |
|
7738
|
|
|
|
|
|
|
'footer' => $self->{_margin_footer}, |
|
7739
|
1025
|
|
|
|
|
6478
|
); |
|
7740
|
|
|
|
|
|
|
|
|
7741
|
1025
|
|
|
|
|
5335
|
$self->xml_empty_tag( 'pageMargins', @attributes ); |
|
7742
|
|
|
|
|
|
|
} |
|
7743
|
|
|
|
|
|
|
|
|
7744
|
|
|
|
|
|
|
|
|
7745
|
|
|
|
|
|
|
############################################################################### |
|
7746
|
|
|
|
|
|
|
# |
|
7747
|
|
|
|
|
|
|
# _write_page_setup() |
|
7748
|
|
|
|
|
|
|
# |
|
7749
|
|
|
|
|
|
|
# Write the element. |
|
7750
|
|
|
|
|
|
|
# |
|
7751
|
|
|
|
|
|
|
# The following is an example taken from Excel. |
|
7752
|
|
|
|
|
|
|
# |
|
7753
|
|
|
|
|
|
|
#
|
|
7754
|
|
|
|
|
|
|
# paperSize="9" |
|
7755
|
|
|
|
|
|
|
# scale="110" |
|
7756
|
|
|
|
|
|
|
# fitToWidth="2" |
|
7757
|
|
|
|
|
|
|
# fitToHeight="2" |
|
7758
|
|
|
|
|
|
|
# pageOrder="overThenDown" |
|
7759
|
|
|
|
|
|
|
# orientation="portrait" |
|
7760
|
|
|
|
|
|
|
# blackAndWhite="1" |
|
7761
|
|
|
|
|
|
|
# draft="1" |
|
7762
|
|
|
|
|
|
|
# horizontalDpi="200" |
|
7763
|
|
|
|
|
|
|
# verticalDpi="200" |
|
7764
|
|
|
|
|
|
|
# r:id="rId1" |
|
7765
|
|
|
|
|
|
|
# /> |
|
7766
|
|
|
|
|
|
|
# |
|
7767
|
|
|
|
|
|
|
sub _write_page_setup { |
|
7768
|
|
|
|
|
|
|
|
|
7769
|
1019
|
|
|
1019
|
|
2669
|
my $self = shift; |
|
7770
|
1019
|
|
|
|
|
2602
|
my @attributes = (); |
|
7771
|
|
|
|
|
|
|
|
|
7772
|
1019
|
100
|
|
|
|
4220
|
return unless $self->{_page_setup_changed}; |
|
7773
|
|
|
|
|
|
|
|
|
7774
|
|
|
|
|
|
|
# Set paper size. |
|
7775
|
23
|
100
|
|
|
|
79
|
if ( $self->{_paper_size} ) { |
|
7776
|
19
|
|
|
|
|
70
|
push @attributes, ( 'paperSize' => $self->{_paper_size} ); |
|
7777
|
|
|
|
|
|
|
} |
|
7778
|
|
|
|
|
|
|
|
|
7779
|
|
|
|
|
|
|
# Set the print_scale |
|
7780
|
23
|
100
|
|
|
|
139
|
if ( $self->{_print_scale} != 100 ) { |
|
7781
|
3
|
|
|
|
|
27
|
push @attributes, ( 'scale' => $self->{_print_scale} ); |
|
7782
|
|
|
|
|
|
|
} |
|
7783
|
|
|
|
|
|
|
|
|
7784
|
|
|
|
|
|
|
# Set the "Fit to page" properties. |
|
7785
|
23
|
100
|
100
|
|
|
131
|
if ( $self->{_fit_page} && $self->{_fit_width} != 1 ) { |
|
7786
|
3
|
|
|
|
|
9
|
push @attributes, ( 'fitToWidth' => $self->{_fit_width} ); |
|
7787
|
|
|
|
|
|
|
} |
|
7788
|
|
|
|
|
|
|
|
|
7789
|
23
|
100
|
100
|
|
|
122
|
if ( $self->{_fit_page} && $self->{_fit_height} != 1 ) { |
|
7790
|
4
|
|
|
|
|
14
|
push @attributes, ( 'fitToHeight' => $self->{_fit_height} ); |
|
7791
|
|
|
|
|
|
|
} |
|
7792
|
|
|
|
|
|
|
|
|
7793
|
|
|
|
|
|
|
# Set the page print direction. |
|
7794
|
23
|
100
|
|
|
|
99
|
if ( $self->{_page_order} ) { |
|
7795
|
2
|
|
|
|
|
5
|
push @attributes, ( 'pageOrder' => "overThenDown" ); |
|
7796
|
|
|
|
|
|
|
} |
|
7797
|
|
|
|
|
|
|
|
|
7798
|
|
|
|
|
|
|
# Set start page. |
|
7799
|
23
|
100
|
|
|
|
132
|
if ( $self->{_page_start} > 1 ) { |
|
7800
|
2
|
|
|
|
|
8
|
push @attributes, ( 'firstPageNumber' => $self->{_page_start} ); |
|
7801
|
|
|
|
|
|
|
} |
|
7802
|
|
|
|
|
|
|
|
|
7803
|
|
|
|
|
|
|
# Set page orientation. |
|
7804
|
23
|
100
|
|
|
|
109
|
if ( $self->{_orientation} == 0 ) { |
|
7805
|
2
|
|
|
|
|
7
|
push @attributes, ( 'orientation' => 'landscape' ); |
|
7806
|
|
|
|
|
|
|
} |
|
7807
|
|
|
|
|
|
|
else { |
|
7808
|
21
|
|
|
|
|
84
|
push @attributes, ( 'orientation' => 'portrait' ); |
|
7809
|
|
|
|
|
|
|
} |
|
7810
|
|
|
|
|
|
|
|
|
7811
|
|
|
|
|
|
|
# Set print in black and white option. |
|
7812
|
23
|
100
|
|
|
|
113
|
if ( $self->{_black_white} ) { |
|
7813
|
1
|
|
|
|
|
3
|
push @attributes, ( 'blackAndWhite' => 1 ); |
|
7814
|
|
|
|
|
|
|
} |
|
7815
|
|
|
|
|
|
|
|
|
7816
|
|
|
|
|
|
|
# Set start page. |
|
7817
|
23
|
100
|
|
|
|
141
|
if ( $self->{_page_start} != 0 ) { |
|
7818
|
3
|
|
|
|
|
9
|
push @attributes, ( 'useFirstPageNumber' => 1 ); |
|
7819
|
|
|
|
|
|
|
} |
|
7820
|
|
|
|
|
|
|
|
|
7821
|
|
|
|
|
|
|
# Set the DPI. Mainly only for testing. |
|
7822
|
23
|
50
|
|
|
|
73
|
if ( $self->{_horizontal_dpi} ) { |
|
7823
|
0
|
|
|
|
|
0
|
push @attributes, ( 'horizontalDpi' => $self->{_horizontal_dpi} ); |
|
7824
|
|
|
|
|
|
|
} |
|
7825
|
|
|
|
|
|
|
|
|
7826
|
23
|
100
|
|
|
|
77
|
if ( $self->{_vertical_dpi} ) { |
|
7827
|
5
|
|
|
|
|
19
|
push @attributes, ( 'verticalDpi' => $self->{_vertical_dpi} ); |
|
7828
|
|
|
|
|
|
|
} |
|
7829
|
|
|
|
|
|
|
|
|
7830
|
|
|
|
|
|
|
|
|
7831
|
23
|
|
|
|
|
99
|
$self->xml_empty_tag( 'pageSetup', @attributes ); |
|
7832
|
|
|
|
|
|
|
} |
|
7833
|
|
|
|
|
|
|
|
|
7834
|
|
|
|
|
|
|
|
|
7835
|
|
|
|
|
|
|
############################################################################## |
|
7836
|
|
|
|
|
|
|
# |
|
7837
|
|
|
|
|
|
|
# _write_merge_cells() |
|
7838
|
|
|
|
|
|
|
# |
|
7839
|
|
|
|
|
|
|
# Write the element. |
|
7840
|
|
|
|
|
|
|
# |
|
7841
|
|
|
|
|
|
|
sub _write_merge_cells { |
|
7842
|
|
|
|
|
|
|
|
|
7843
|
996
|
|
|
996
|
|
2808
|
my $self = shift; |
|
7844
|
996
|
|
|
|
|
2639
|
my $merged_cells = $self->{_merge}; |
|
7845
|
996
|
|
|
|
|
2739
|
my $count = @$merged_cells; |
|
7846
|
|
|
|
|
|
|
|
|
7847
|
996
|
100
|
|
|
|
4066
|
return unless $count; |
|
7848
|
|
|
|
|
|
|
|
|
7849
|
14
|
|
|
|
|
47
|
my @attributes = ( 'count' => $count ); |
|
7850
|
|
|
|
|
|
|
|
|
7851
|
14
|
|
|
|
|
72
|
$self->xml_start_tag( 'mergeCells', @attributes ); |
|
7852
|
|
|
|
|
|
|
|
|
7853
|
14
|
|
|
|
|
52
|
for my $merged_range ( @$merged_cells ) { |
|
7854
|
|
|
|
|
|
|
|
|
7855
|
|
|
|
|
|
|
# Write the mergeCell element. |
|
7856
|
27
|
|
|
|
|
94
|
$self->_write_merge_cell( $merged_range ); |
|
7857
|
|
|
|
|
|
|
} |
|
7858
|
|
|
|
|
|
|
|
|
7859
|
14
|
|
|
|
|
88
|
$self->xml_end_tag( 'mergeCells' ); |
|
7860
|
|
|
|
|
|
|
} |
|
7861
|
|
|
|
|
|
|
|
|
7862
|
|
|
|
|
|
|
|
|
7863
|
|
|
|
|
|
|
############################################################################## |
|
7864
|
|
|
|
|
|
|
# |
|
7865
|
|
|
|
|
|
|
# _write_merge_cell() |
|
7866
|
|
|
|
|
|
|
# |
|
7867
|
|
|
|
|
|
|
# Write the element. |
|
7868
|
|
|
|
|
|
|
# |
|
7869
|
|
|
|
|
|
|
sub _write_merge_cell { |
|
7870
|
|
|
|
|
|
|
|
|
7871
|
28
|
|
|
28
|
|
64
|
my $self = shift; |
|
7872
|
28
|
|
|
|
|
60
|
my $merged_range = shift; |
|
7873
|
28
|
|
|
|
|
111
|
my ( $row_min, $col_min, $row_max, $col_max ) = @$merged_range; |
|
7874
|
|
|
|
|
|
|
|
|
7875
|
|
|
|
|
|
|
|
|
7876
|
|
|
|
|
|
|
# Convert the merge dimensions to a cell range. |
|
7877
|
28
|
|
|
|
|
95
|
my $cell_1 = xl_rowcol_to_cell( $row_min, $col_min ); |
|
7878
|
28
|
|
|
|
|
90
|
my $cell_2 = xl_rowcol_to_cell( $row_max, $col_max ); |
|
7879
|
28
|
|
|
|
|
75
|
my $ref = $cell_1 . ':' . $cell_2; |
|
7880
|
|
|
|
|
|
|
|
|
7881
|
28
|
|
|
|
|
90
|
my @attributes = ( 'ref' => $ref ); |
|
7882
|
|
|
|
|
|
|
|
|
7883
|
28
|
|
|
|
|
95
|
$self->xml_empty_tag( 'mergeCell', @attributes ); |
|
7884
|
|
|
|
|
|
|
} |
|
7885
|
|
|
|
|
|
|
|
|
7886
|
|
|
|
|
|
|
|
|
7887
|
|
|
|
|
|
|
############################################################################## |
|
7888
|
|
|
|
|
|
|
# |
|
7889
|
|
|
|
|
|
|
# _write_print_options() |
|
7890
|
|
|
|
|
|
|
# |
|
7891
|
|
|
|
|
|
|
# Write the element. |
|
7892
|
|
|
|
|
|
|
# |
|
7893
|
|
|
|
|
|
|
sub _write_print_options { |
|
7894
|
|
|
|
|
|
|
|
|
7895
|
1022
|
|
|
1022
|
|
2502
|
my $self = shift; |
|
7896
|
1022
|
|
|
|
|
2660
|
my @attributes = (); |
|
7897
|
|
|
|
|
|
|
|
|
7898
|
1022
|
100
|
|
|
|
4430
|
return unless $self->{_print_options_changed}; |
|
7899
|
|
|
|
|
|
|
|
|
7900
|
|
|
|
|
|
|
# Set horizontal centering. |
|
7901
|
10
|
100
|
|
|
|
28
|
if ( $self->{_hcenter} ) { |
|
7902
|
4
|
|
|
|
|
11
|
push @attributes, ( 'horizontalCentered' => 1 ); |
|
7903
|
|
|
|
|
|
|
} |
|
7904
|
|
|
|
|
|
|
|
|
7905
|
|
|
|
|
|
|
# Set vertical centering. |
|
7906
|
10
|
100
|
|
|
|
29
|
if ( $self->{_vcenter} ) { |
|
7907
|
4
|
|
|
|
|
9
|
push @attributes, ( 'verticalCentered' => 1 ); |
|
7908
|
|
|
|
|
|
|
} |
|
7909
|
|
|
|
|
|
|
|
|
7910
|
|
|
|
|
|
|
# Enable row and column headers. |
|
7911
|
10
|
100
|
|
|
|
26
|
if ( $self->{_print_headers} ) { |
|
7912
|
2
|
|
|
|
|
8
|
push @attributes, ( 'headings' => 1 ); |
|
7913
|
|
|
|
|
|
|
} |
|
7914
|
|
|
|
|
|
|
|
|
7915
|
|
|
|
|
|
|
# Set printed gridlines. |
|
7916
|
10
|
100
|
|
|
|
26
|
if ( $self->{_print_gridlines} ) { |
|
7917
|
4
|
|
|
|
|
10
|
push @attributes, ( 'gridLines' => 1 ); |
|
7918
|
|
|
|
|
|
|
} |
|
7919
|
|
|
|
|
|
|
|
|
7920
|
|
|
|
|
|
|
|
|
7921
|
10
|
|
|
|
|
45
|
$self->xml_empty_tag( 'printOptions', @attributes ); |
|
7922
|
|
|
|
|
|
|
} |
|
7923
|
|
|
|
|
|
|
|
|
7924
|
|
|
|
|
|
|
|
|
7925
|
|
|
|
|
|
|
############################################################################## |
|
7926
|
|
|
|
|
|
|
# |
|
7927
|
|
|
|
|
|
|
# _write_header_footer() |
|
7928
|
|
|
|
|
|
|
# |
|
7929
|
|
|
|
|
|
|
# Write the element. |
|
7930
|
|
|
|
|
|
|
# |
|
7931
|
|
|
|
|
|
|
sub _write_header_footer { |
|
7932
|
|
|
|
|
|
|
|
|
7933
|
1017
|
|
|
1017
|
|
2426
|
my $self = shift; |
|
7934
|
1017
|
|
|
|
|
2604
|
my @attributes = (); |
|
7935
|
|
|
|
|
|
|
|
|
7936
|
1017
|
100
|
|
|
|
4197
|
if ( !$self->{_header_footer_scales} ) { |
|
7937
|
2
|
|
|
|
|
8
|
push @attributes, ( 'scaleWithDoc' => 0 ); |
|
7938
|
|
|
|
|
|
|
} |
|
7939
|
|
|
|
|
|
|
|
|
7940
|
1017
|
100
|
|
|
|
4082
|
if ( !$self->{_header_footer_aligns} ) { |
|
7941
|
10
|
|
|
|
|
32
|
push @attributes, ( 'alignWithMargins' => 0 ); |
|
7942
|
|
|
|
|
|
|
} |
|
7943
|
|
|
|
|
|
|
|
|
7944
|
1017
|
100
|
|
|
|
6357
|
if ( $self->{_header_footer_changed} ) { |
|
|
|
100
|
|
|
|
|
|
|
7945
|
32
|
|
|
|
|
154
|
$self->xml_start_tag( 'headerFooter', @attributes ); |
|
7946
|
32
|
100
|
|
|
|
259
|
$self->_write_odd_header() if $self->{_header}; |
|
7947
|
32
|
100
|
|
|
|
163
|
$self->_write_odd_footer() if $self->{_footer}; |
|
7948
|
32
|
|
|
|
|
137
|
$self->xml_end_tag( 'headerFooter' ); |
|
7949
|
|
|
|
|
|
|
} |
|
7950
|
|
|
|
|
|
|
elsif ( $self->{_excel2003_style} ) { |
|
7951
|
7
|
|
|
|
|
30
|
$self->xml_empty_tag( 'headerFooter', @attributes ); |
|
7952
|
|
|
|
|
|
|
} |
|
7953
|
|
|
|
|
|
|
} |
|
7954
|
|
|
|
|
|
|
|
|
7955
|
|
|
|
|
|
|
|
|
7956
|
|
|
|
|
|
|
############################################################################## |
|
7957
|
|
|
|
|
|
|
# |
|
7958
|
|
|
|
|
|
|
# _write_odd_header() |
|
7959
|
|
|
|
|
|
|
# |
|
7960
|
|
|
|
|
|
|
# Write the element. |
|
7961
|
|
|
|
|
|
|
# |
|
7962
|
|
|
|
|
|
|
sub _write_odd_header { |
|
7963
|
|
|
|
|
|
|
|
|
7964
|
30
|
|
|
30
|
|
87
|
my $self = shift; |
|
7965
|
30
|
|
|
|
|
78
|
my $data = $self->{_header}; |
|
7966
|
|
|
|
|
|
|
|
|
7967
|
30
|
|
|
|
|
207
|
$self->xml_data_element( 'oddHeader', $data ); |
|
7968
|
|
|
|
|
|
|
} |
|
7969
|
|
|
|
|
|
|
|
|
7970
|
|
|
|
|
|
|
|
|
7971
|
|
|
|
|
|
|
############################################################################## |
|
7972
|
|
|
|
|
|
|
# |
|
7973
|
|
|
|
|
|
|
# _write_odd_footer() |
|
7974
|
|
|
|
|
|
|
# |
|
7975
|
|
|
|
|
|
|
# Write the element. |
|
7976
|
|
|
|
|
|
|
# |
|
7977
|
|
|
|
|
|
|
sub _write_odd_footer { |
|
7978
|
|
|
|
|
|
|
|
|
7979
|
14
|
|
|
14
|
|
33
|
my $self = shift; |
|
7980
|
14
|
|
|
|
|
32
|
my $data = $self->{_footer}; |
|
7981
|
|
|
|
|
|
|
|
|
7982
|
14
|
|
|
|
|
63
|
$self->xml_data_element( 'oddFooter', $data ); |
|
7983
|
|
|
|
|
|
|
} |
|
7984
|
|
|
|
|
|
|
|
|
7985
|
|
|
|
|
|
|
|
|
7986
|
|
|
|
|
|
|
############################################################################## |
|
7987
|
|
|
|
|
|
|
# |
|
7988
|
|
|
|
|
|
|
# _write_row_breaks() |
|
7989
|
|
|
|
|
|
|
# |
|
7990
|
|
|
|
|
|
|
# Write the element. |
|
7991
|
|
|
|
|
|
|
# |
|
7992
|
|
|
|
|
|
|
sub _write_row_breaks { |
|
7993
|
|
|
|
|
|
|
|
|
7994
|
995
|
|
|
995
|
|
2513
|
my $self = shift; |
|
7995
|
|
|
|
|
|
|
|
|
7996
|
995
|
|
|
|
|
2615
|
my @page_breaks = $self->_sort_pagebreaks( @{ $self->{_hbreaks} } ); |
|
|
995
|
|
|
|
|
5078
|
|
|
7997
|
995
|
|
|
|
|
2723
|
my $count = scalar @page_breaks; |
|
7998
|
|
|
|
|
|
|
|
|
7999
|
995
|
100
|
|
|
|
3845
|
return unless @page_breaks; |
|
8000
|
|
|
|
|
|
|
|
|
8001
|
6
|
|
|
|
|
27
|
my @attributes = ( |
|
8002
|
|
|
|
|
|
|
'count' => $count, |
|
8003
|
|
|
|
|
|
|
'manualBreakCount' => $count, |
|
8004
|
|
|
|
|
|
|
); |
|
8005
|
|
|
|
|
|
|
|
|
8006
|
6
|
|
|
|
|
34
|
$self->xml_start_tag( 'rowBreaks', @attributes ); |
|
8007
|
|
|
|
|
|
|
|
|
8008
|
6
|
|
|
|
|
24
|
for my $row_num ( @page_breaks ) { |
|
8009
|
1035
|
|
|
|
|
1964
|
$self->_write_brk( $row_num, 16383 ); |
|
8010
|
|
|
|
|
|
|
} |
|
8011
|
|
|
|
|
|
|
|
|
8012
|
6
|
|
|
|
|
30
|
$self->xml_end_tag( 'rowBreaks' ); |
|
8013
|
|
|
|
|
|
|
} |
|
8014
|
|
|
|
|
|
|
|
|
8015
|
|
|
|
|
|
|
|
|
8016
|
|
|
|
|
|
|
############################################################################## |
|
8017
|
|
|
|
|
|
|
# |
|
8018
|
|
|
|
|
|
|
# _write_col_breaks() |
|
8019
|
|
|
|
|
|
|
# |
|
8020
|
|
|
|
|
|
|
# Write the element. |
|
8021
|
|
|
|
|
|
|
# |
|
8022
|
|
|
|
|
|
|
sub _write_col_breaks { |
|
8023
|
|
|
|
|
|
|
|
|
8024
|
995
|
|
|
995
|
|
2507
|
my $self = shift; |
|
8025
|
|
|
|
|
|
|
|
|
8026
|
995
|
|
|
|
|
2745
|
my @page_breaks = $self->_sort_pagebreaks( @{ $self->{_vbreaks} } ); |
|
|
995
|
|
|
|
|
4038
|
|
|
8027
|
995
|
|
|
|
|
2694
|
my $count = scalar @page_breaks; |
|
8028
|
|
|
|
|
|
|
|
|
8029
|
995
|
100
|
|
|
|
3797
|
return unless @page_breaks; |
|
8030
|
|
|
|
|
|
|
|
|
8031
|
5
|
|
|
|
|
16
|
my @attributes = ( |
|
8032
|
|
|
|
|
|
|
'count' => $count, |
|
8033
|
|
|
|
|
|
|
'manualBreakCount' => $count, |
|
8034
|
|
|
|
|
|
|
); |
|
8035
|
|
|
|
|
|
|
|
|
8036
|
5
|
|
|
|
|
28
|
$self->xml_start_tag( 'colBreaks', @attributes ); |
|
8037
|
|
|
|
|
|
|
|
|
8038
|
5
|
|
|
|
|
14
|
for my $col_num ( @page_breaks ) { |
|
8039
|
11
|
|
|
|
|
29
|
$self->_write_brk( $col_num, 1048575 ); |
|
8040
|
|
|
|
|
|
|
} |
|
8041
|
|
|
|
|
|
|
|
|
8042
|
5
|
|
|
|
|
19
|
$self->xml_end_tag( 'colBreaks' ); |
|
8043
|
|
|
|
|
|
|
} |
|
8044
|
|
|
|
|
|
|
|
|
8045
|
|
|
|
|
|
|
|
|
8046
|
|
|
|
|
|
|
############################################################################## |
|
8047
|
|
|
|
|
|
|
# |
|
8048
|
|
|
|
|
|
|
# _write_brk() |
|
8049
|
|
|
|
|
|
|
# |
|
8050
|
|
|
|
|
|
|
# Write the element. |
|
8051
|
|
|
|
|
|
|
# |
|
8052
|
|
|
|
|
|
|
sub _write_brk { |
|
8053
|
|
|
|
|
|
|
|
|
8054
|
1047
|
|
|
1047
|
|
1537
|
my $self = shift; |
|
8055
|
1047
|
|
|
|
|
1521
|
my $id = shift; |
|
8056
|
1047
|
|
|
|
|
1354
|
my $max = shift; |
|
8057
|
1047
|
|
|
|
|
1434
|
my $man = 1; |
|
8058
|
|
|
|
|
|
|
|
|
8059
|
1047
|
|
|
|
|
2096
|
my @attributes = ( |
|
8060
|
|
|
|
|
|
|
'id' => $id, |
|
8061
|
|
|
|
|
|
|
'max' => $max, |
|
8062
|
|
|
|
|
|
|
'man' => $man, |
|
8063
|
|
|
|
|
|
|
); |
|
8064
|
|
|
|
|
|
|
|
|
8065
|
1047
|
|
|
|
|
2193
|
$self->xml_empty_tag( 'brk', @attributes ); |
|
8066
|
|
|
|
|
|
|
} |
|
8067
|
|
|
|
|
|
|
|
|
8068
|
|
|
|
|
|
|
|
|
8069
|
|
|
|
|
|
|
############################################################################## |
|
8070
|
|
|
|
|
|
|
# |
|
8071
|
|
|
|
|
|
|
# _write_auto_filter() |
|
8072
|
|
|
|
|
|
|
# |
|
8073
|
|
|
|
|
|
|
# Write the element. |
|
8074
|
|
|
|
|
|
|
# |
|
8075
|
|
|
|
|
|
|
sub _write_auto_filter { |
|
8076
|
|
|
|
|
|
|
|
|
8077
|
1014
|
|
|
1014
|
|
2837
|
my $self = shift; |
|
8078
|
1014
|
|
|
|
|
3060
|
my $ref = $self->{_autofilter_ref}; |
|
8079
|
|
|
|
|
|
|
|
|
8080
|
1014
|
100
|
|
|
|
3960
|
return unless $ref; |
|
8081
|
|
|
|
|
|
|
|
|
8082
|
32
|
|
|
|
|
98
|
my @attributes = ( 'ref' => $ref ); |
|
8083
|
|
|
|
|
|
|
|
|
8084
|
32
|
100
|
|
|
|
86
|
if ( $self->{_filter_on} ) { |
|
8085
|
|
|
|
|
|
|
|
|
8086
|
|
|
|
|
|
|
# Autofilter defined active filters. |
|
8087
|
29
|
|
|
|
|
122
|
$self->xml_start_tag( 'autoFilter', @attributes ); |
|
8088
|
|
|
|
|
|
|
|
|
8089
|
29
|
|
|
|
|
124
|
$self->_write_autofilters(); |
|
8090
|
|
|
|
|
|
|
|
|
8091
|
29
|
|
|
|
|
153
|
$self->xml_end_tag( 'autoFilter' ); |
|
8092
|
|
|
|
|
|
|
|
|
8093
|
|
|
|
|
|
|
} |
|
8094
|
|
|
|
|
|
|
else { |
|
8095
|
|
|
|
|
|
|
|
|
8096
|
|
|
|
|
|
|
# Autofilter defined without active filters. |
|
8097
|
3
|
|
|
|
|
18
|
$self->xml_empty_tag( 'autoFilter', @attributes ); |
|
8098
|
|
|
|
|
|
|
} |
|
8099
|
|
|
|
|
|
|
|
|
8100
|
|
|
|
|
|
|
} |
|
8101
|
|
|
|
|
|
|
|
|
8102
|
|
|
|
|
|
|
|
|
8103
|
|
|
|
|
|
|
############################################################################### |
|
8104
|
|
|
|
|
|
|
# |
|
8105
|
|
|
|
|
|
|
# _write_autofilters() |
|
8106
|
|
|
|
|
|
|
# |
|
8107
|
|
|
|
|
|
|
# Function to iterate through the columns that form part of an autofilter |
|
8108
|
|
|
|
|
|
|
# range and write the appropriate filters. |
|
8109
|
|
|
|
|
|
|
# |
|
8110
|
|
|
|
|
|
|
sub _write_autofilters { |
|
8111
|
|
|
|
|
|
|
|
|
8112
|
29
|
|
|
29
|
|
57
|
my $self = shift; |
|
8113
|
|
|
|
|
|
|
|
|
8114
|
29
|
|
|
|
|
57
|
my ( $col1, $col2 ) = @{ $self->{_filter_range} }; |
|
|
29
|
|
|
|
|
95
|
|
|
8115
|
|
|
|
|
|
|
|
|
8116
|
29
|
|
|
|
|
117
|
for my $col ( $col1 .. $col2 ) { |
|
8117
|
|
|
|
|
|
|
|
|
8118
|
|
|
|
|
|
|
# Skip if column doesn't have an active filter. |
|
8119
|
116
|
100
|
|
|
|
332
|
next unless $self->{_filter_cols}->{$col}; |
|
8120
|
|
|
|
|
|
|
|
|
8121
|
|
|
|
|
|
|
# Retrieve the filter tokens and write the autofilter records. |
|
8122
|
30
|
|
|
|
|
65
|
my @tokens = @{ $self->{_filter_cols}->{$col} }; |
|
|
30
|
|
|
|
|
100
|
|
|
8123
|
30
|
|
|
|
|
71
|
my $type = $self->{_filter_type}->{$col}; |
|
8124
|
|
|
|
|
|
|
|
|
8125
|
|
|
|
|
|
|
# Filters are relative to first column in the autofilter. |
|
8126
|
30
|
|
|
|
|
163
|
$self->_write_filter_column( $col - $col1, $type, \@tokens ); |
|
8127
|
|
|
|
|
|
|
} |
|
8128
|
|
|
|
|
|
|
} |
|
8129
|
|
|
|
|
|
|
|
|
8130
|
|
|
|
|
|
|
|
|
8131
|
|
|
|
|
|
|
############################################################################## |
|
8132
|
|
|
|
|
|
|
# |
|
8133
|
|
|
|
|
|
|
# _write_filter_column() |
|
8134
|
|
|
|
|
|
|
# |
|
8135
|
|
|
|
|
|
|
# Write the element. |
|
8136
|
|
|
|
|
|
|
# |
|
8137
|
|
|
|
|
|
|
sub _write_filter_column { |
|
8138
|
|
|
|
|
|
|
|
|
8139
|
31
|
|
|
31
|
|
79
|
my $self = shift; |
|
8140
|
31
|
|
|
|
|
48
|
my $col_id = shift; |
|
8141
|
31
|
|
|
|
|
60
|
my $type = shift; |
|
8142
|
31
|
|
|
|
|
47
|
my $filters = shift; |
|
8143
|
|
|
|
|
|
|
|
|
8144
|
31
|
|
|
|
|
86
|
my @attributes = ( 'colId' => $col_id ); |
|
8145
|
|
|
|
|
|
|
|
|
8146
|
31
|
|
|
|
|
123
|
$self->xml_start_tag( 'filterColumn', @attributes ); |
|
8147
|
|
|
|
|
|
|
|
|
8148
|
|
|
|
|
|
|
|
|
8149
|
31
|
100
|
|
|
|
99
|
if ( $type == 1 ) { |
|
8150
|
|
|
|
|
|
|
|
|
8151
|
|
|
|
|
|
|
# Type == 1 is the new XLSX style filter. |
|
8152
|
15
|
|
|
|
|
75
|
$self->_write_filters( @$filters ); |
|
8153
|
|
|
|
|
|
|
|
|
8154
|
|
|
|
|
|
|
} |
|
8155
|
|
|
|
|
|
|
else { |
|
8156
|
|
|
|
|
|
|
|
|
8157
|
|
|
|
|
|
|
# Type == 0 is the classic "custom" filter. |
|
8158
|
16
|
|
|
|
|
42
|
$self->_write_custom_filters( @$filters ); |
|
8159
|
|
|
|
|
|
|
} |
|
8160
|
|
|
|
|
|
|
|
|
8161
|
31
|
|
|
|
|
173
|
$self->xml_end_tag( 'filterColumn' ); |
|
8162
|
|
|
|
|
|
|
} |
|
8163
|
|
|
|
|
|
|
|
|
8164
|
|
|
|
|
|
|
|
|
8165
|
|
|
|
|
|
|
############################################################################## |
|
8166
|
|
|
|
|
|
|
# |
|
8167
|
|
|
|
|
|
|
# _write_filters() |
|
8168
|
|
|
|
|
|
|
# |
|
8169
|
|
|
|
|
|
|
# Write the element. |
|
8170
|
|
|
|
|
|
|
# |
|
8171
|
|
|
|
|
|
|
sub _write_filters { |
|
8172
|
|
|
|
|
|
|
|
|
8173
|
18
|
|
|
18
|
|
102
|
my $self = shift; |
|
8174
|
18
|
|
|
|
|
54
|
my @filters = @_; |
|
8175
|
18
|
|
|
|
|
60
|
my @non_blanks = grep { !/^blanks$/i } @filters; |
|
|
31
|
|
|
|
|
124
|
|
|
8176
|
18
|
|
|
|
|
54
|
my @attributes = (); |
|
8177
|
|
|
|
|
|
|
|
|
8178
|
18
|
100
|
|
|
|
96
|
if ( @filters != @non_blanks ) { |
|
8179
|
4
|
|
|
|
|
14
|
@attributes = ( 'blank' => 1 ); |
|
8180
|
|
|
|
|
|
|
} |
|
8181
|
|
|
|
|
|
|
|
|
8182
|
18
|
100
|
100
|
|
|
109
|
if ( @filters == 1 && @non_blanks == 0 ) { |
|
8183
|
|
|
|
|
|
|
|
|
8184
|
|
|
|
|
|
|
# Special case for blank cells only. |
|
8185
|
2
|
|
|
|
|
9
|
$self->xml_empty_tag( 'filters', @attributes ); |
|
8186
|
|
|
|
|
|
|
} |
|
8187
|
|
|
|
|
|
|
else { |
|
8188
|
|
|
|
|
|
|
|
|
8189
|
|
|
|
|
|
|
# General case. |
|
8190
|
16
|
|
|
|
|
156
|
$self->xml_start_tag( 'filters', @attributes ); |
|
8191
|
|
|
|
|
|
|
|
|
8192
|
16
|
|
|
|
|
94
|
for my $filter ( sort @non_blanks ) { |
|
8193
|
27
|
|
|
|
|
73
|
$self->_write_filter( $filter ); |
|
8194
|
|
|
|
|
|
|
} |
|
8195
|
|
|
|
|
|
|
|
|
8196
|
16
|
|
|
|
|
76
|
$self->xml_end_tag( 'filters' ); |
|
8197
|
|
|
|
|
|
|
} |
|
8198
|
|
|
|
|
|
|
} |
|
8199
|
|
|
|
|
|
|
|
|
8200
|
|
|
|
|
|
|
|
|
8201
|
|
|
|
|
|
|
############################################################################## |
|
8202
|
|
|
|
|
|
|
# |
|
8203
|
|
|
|
|
|
|
# _write_filter() |
|
8204
|
|
|
|
|
|
|
# |
|
8205
|
|
|
|
|
|
|
# Write the element. |
|
8206
|
|
|
|
|
|
|
# |
|
8207
|
|
|
|
|
|
|
sub _write_filter { |
|
8208
|
|
|
|
|
|
|
|
|
8209
|
28
|
|
|
28
|
|
74
|
my $self = shift; |
|
8210
|
28
|
|
|
|
|
45
|
my $val = shift; |
|
8211
|
|
|
|
|
|
|
|
|
8212
|
28
|
|
|
|
|
110
|
my @attributes = ( 'val' => $val ); |
|
8213
|
|
|
|
|
|
|
|
|
8214
|
28
|
|
|
|
|
142
|
$self->xml_empty_tag( 'filter', @attributes ); |
|
8215
|
|
|
|
|
|
|
} |
|
8216
|
|
|
|
|
|
|
|
|
8217
|
|
|
|
|
|
|
|
|
8218
|
|
|
|
|
|
|
############################################################################## |
|
8219
|
|
|
|
|
|
|
# |
|
8220
|
|
|
|
|
|
|
# _write_custom_filters() |
|
8221
|
|
|
|
|
|
|
# |
|
8222
|
|
|
|
|
|
|
# Write the element. |
|
8223
|
|
|
|
|
|
|
# |
|
8224
|
|
|
|
|
|
|
sub _write_custom_filters { |
|
8225
|
|
|
|
|
|
|
|
|
8226
|
18
|
|
|
18
|
|
65
|
my $self = shift; |
|
8227
|
18
|
|
|
|
|
52
|
my @tokens = @_; |
|
8228
|
|
|
|
|
|
|
|
|
8229
|
18
|
100
|
|
|
|
53
|
if ( @tokens == 2 ) { |
|
8230
|
|
|
|
|
|
|
|
|
8231
|
|
|
|
|
|
|
# One filter expression only. |
|
8232
|
14
|
|
|
|
|
53
|
$self->xml_start_tag( 'customFilters' ); |
|
8233
|
14
|
|
|
|
|
45
|
$self->_write_custom_filter( @tokens ); |
|
8234
|
14
|
|
|
|
|
45
|
$self->xml_end_tag( 'customFilters' ); |
|
8235
|
|
|
|
|
|
|
|
|
8236
|
|
|
|
|
|
|
} |
|
8237
|
|
|
|
|
|
|
else { |
|
8238
|
|
|
|
|
|
|
|
|
8239
|
|
|
|
|
|
|
# Two filter expressions. |
|
8240
|
|
|
|
|
|
|
|
|
8241
|
4
|
|
|
|
|
8
|
my @attributes; |
|
8242
|
|
|
|
|
|
|
|
|
8243
|
|
|
|
|
|
|
# Check if the "join" operand is "and" or "or". |
|
8244
|
4
|
50
|
|
|
|
24
|
if ( $tokens[2] == 0 ) { |
|
8245
|
4
|
|
|
|
|
11
|
@attributes = ( 'and' => 1 ); |
|
8246
|
|
|
|
|
|
|
} |
|
8247
|
|
|
|
|
|
|
else { |
|
8248
|
0
|
|
|
|
|
0
|
@attributes = ( 'and' => 0 ); |
|
8249
|
|
|
|
|
|
|
} |
|
8250
|
|
|
|
|
|
|
|
|
8251
|
|
|
|
|
|
|
# Write the two custom filters. |
|
8252
|
4
|
|
|
|
|
107
|
$self->xml_start_tag( 'customFilters', @attributes ); |
|
8253
|
4
|
|
|
|
|
22
|
$self->_write_custom_filter( $tokens[0], $tokens[1] ); |
|
8254
|
4
|
|
|
|
|
16
|
$self->_write_custom_filter( $tokens[3], $tokens[4] ); |
|
8255
|
4
|
|
|
|
|
12
|
$self->xml_end_tag( 'customFilters' ); |
|
8256
|
|
|
|
|
|
|
} |
|
8257
|
|
|
|
|
|
|
} |
|
8258
|
|
|
|
|
|
|
|
|
8259
|
|
|
|
|
|
|
|
|
8260
|
|
|
|
|
|
|
############################################################################## |
|
8261
|
|
|
|
|
|
|
# |
|
8262
|
|
|
|
|
|
|
# _write_custom_filter() |
|
8263
|
|
|
|
|
|
|
# |
|
8264
|
|
|
|
|
|
|
# Write the element. |
|
8265
|
|
|
|
|
|
|
# |
|
8266
|
|
|
|
|
|
|
sub _write_custom_filter { |
|
8267
|
|
|
|
|
|
|
|
|
8268
|
23
|
|
|
23
|
|
48
|
my $self = shift; |
|
8269
|
23
|
|
|
|
|
42
|
my $operator = shift; |
|
8270
|
23
|
|
|
|
|
38
|
my $val = shift; |
|
8271
|
23
|
|
|
|
|
43
|
my @attributes = (); |
|
8272
|
|
|
|
|
|
|
|
|
8273
|
23
|
|
|
|
|
190
|
my %operators = ( |
|
8274
|
|
|
|
|
|
|
1 => 'lessThan', |
|
8275
|
|
|
|
|
|
|
2 => 'equal', |
|
8276
|
|
|
|
|
|
|
3 => 'lessThanOrEqual', |
|
8277
|
|
|
|
|
|
|
4 => 'greaterThan', |
|
8278
|
|
|
|
|
|
|
5 => 'notEqual', |
|
8279
|
|
|
|
|
|
|
6 => 'greaterThanOrEqual', |
|
8280
|
|
|
|
|
|
|
22 => 'equal', |
|
8281
|
|
|
|
|
|
|
); |
|
8282
|
|
|
|
|
|
|
|
|
8283
|
|
|
|
|
|
|
|
|
8284
|
|
|
|
|
|
|
# Convert the operator from a number to a descriptive string. |
|
8285
|
23
|
50
|
|
|
|
72
|
if ( defined $operators{$operator} ) { |
|
8286
|
23
|
|
|
|
|
48
|
$operator = $operators{$operator}; |
|
8287
|
|
|
|
|
|
|
} |
|
8288
|
|
|
|
|
|
|
else { |
|
8289
|
0
|
|
|
|
|
0
|
croak "Unknown operator = $operator\n"; |
|
8290
|
|
|
|
|
|
|
} |
|
8291
|
|
|
|
|
|
|
|
|
8292
|
|
|
|
|
|
|
# The 'equal' operator is the default attribute and isn't stored. |
|
8293
|
23
|
100
|
|
|
|
81
|
push @attributes, ( 'operator' => $operator ) unless $operator eq 'equal'; |
|
8294
|
23
|
|
|
|
|
50
|
push @attributes, ( 'val' => $val ); |
|
8295
|
|
|
|
|
|
|
|
|
8296
|
23
|
|
|
|
|
114
|
$self->xml_empty_tag( 'customFilter', @attributes ); |
|
8297
|
|
|
|
|
|
|
} |
|
8298
|
|
|
|
|
|
|
|
|
8299
|
|
|
|
|
|
|
|
|
8300
|
|
|
|
|
|
|
############################################################################## |
|
8301
|
|
|
|
|
|
|
# |
|
8302
|
|
|
|
|
|
|
# _write_hyperlinks() |
|
8303
|
|
|
|
|
|
|
# |
|
8304
|
|
|
|
|
|
|
# Process any stored hyperlinks in row/col order and write the |
|
8305
|
|
|
|
|
|
|
# element. The attributes are different for internal and external links. |
|
8306
|
|
|
|
|
|
|
# |
|
8307
|
|
|
|
|
|
|
sub _write_hyperlinks { |
|
8308
|
|
|
|
|
|
|
|
|
8309
|
993
|
|
|
993
|
|
2556
|
my $self = shift; |
|
8310
|
993
|
|
|
|
|
2315
|
my @hlink_refs; |
|
8311
|
|
|
|
|
|
|
|
|
8312
|
|
|
|
|
|
|
# Sort the hyperlinks into row order. |
|
8313
|
993
|
|
|
|
|
2682
|
my @row_nums = sort { $a <=> $b } keys %{ $self->{_hyperlinks} }; |
|
|
48
|
|
|
|
|
140
|
|
|
|
993
|
|
|
|
|
5060
|
|
|
8314
|
|
|
|
|
|
|
|
|
8315
|
|
|
|
|
|
|
# Exit if there are no hyperlinks to process. |
|
8316
|
993
|
100
|
|
|
|
4135
|
return if !@row_nums; |
|
8317
|
|
|
|
|
|
|
|
|
8318
|
|
|
|
|
|
|
# Iterate over the rows. |
|
8319
|
49
|
|
|
|
|
256
|
for my $row_num ( @row_nums ) { |
|
8320
|
|
|
|
|
|
|
|
|
8321
|
|
|
|
|
|
|
# Sort the hyperlinks into column order. |
|
8322
|
1
|
|
|
|
|
13
|
my @col_nums = sort { $a <=> $b } |
|
8323
|
81
|
|
|
|
|
152
|
keys %{ $self->{_hyperlinks}->{$row_num} }; |
|
|
81
|
|
|
|
|
376
|
|
|
8324
|
|
|
|
|
|
|
|
|
8325
|
|
|
|
|
|
|
# Iterate over the columns. |
|
8326
|
81
|
|
|
|
|
209
|
for my $col_num ( @col_nums ) { |
|
8327
|
|
|
|
|
|
|
|
|
8328
|
|
|
|
|
|
|
# Get the link data for this cell. |
|
8329
|
82
|
|
|
|
|
189
|
my $link = $self->{_hyperlinks}->{$row_num}->{$col_num}; |
|
8330
|
82
|
|
|
|
|
174
|
my $link_type = $link->{_link_type}; |
|
8331
|
|
|
|
|
|
|
|
|
8332
|
|
|
|
|
|
|
|
|
8333
|
|
|
|
|
|
|
# If the cell isn't a string then we have to add the url as |
|
8334
|
|
|
|
|
|
|
# the string to display. |
|
8335
|
82
|
|
|
|
|
148
|
my $display; |
|
8336
|
82
|
50
|
66
|
|
|
789
|
if ( $self->{_table} |
|
|
|
|
66
|
|
|
|
|
|
8337
|
|
|
|
|
|
|
&& $self->{_table}->{$row_num} |
|
8338
|
|
|
|
|
|
|
&& $self->{_table}->{$row_num}->{$col_num} ) |
|
8339
|
|
|
|
|
|
|
{ |
|
8340
|
81
|
|
|
|
|
184
|
my $cell = $self->{_table}->{$row_num}->{$col_num}; |
|
8341
|
81
|
100
|
|
|
|
308
|
$display = $link->{_url} if $cell->[0] ne 's'; |
|
8342
|
|
|
|
|
|
|
} |
|
8343
|
|
|
|
|
|
|
|
|
8344
|
|
|
|
|
|
|
|
|
8345
|
82
|
100
|
|
|
|
268
|
if ( $link_type == 1 ) { |
|
8346
|
|
|
|
|
|
|
|
|
8347
|
|
|
|
|
|
|
# External link with rel file relationship. |
|
8348
|
|
|
|
|
|
|
push @hlink_refs, |
|
8349
|
|
|
|
|
|
|
[ |
|
8350
|
|
|
|
|
|
|
$link_type, $row_num, |
|
8351
|
|
|
|
|
|
|
$col_num, ++$self->{_rel_count}, |
|
8352
|
|
|
|
|
|
|
$link->{_str}, $display, |
|
8353
|
|
|
|
|
|
|
$link->{_tip} |
|
8354
|
74
|
|
|
|
|
322
|
]; |
|
8355
|
|
|
|
|
|
|
|
|
8356
|
|
|
|
|
|
|
# Links for use by the packager. |
|
8357
|
74
|
|
|
|
|
343
|
push @{ $self->{_external_hyper_links} }, |
|
8358
|
74
|
|
|
|
|
135
|
[ '/hyperlink', $link->{_url}, 'External' ]; |
|
8359
|
|
|
|
|
|
|
} |
|
8360
|
|
|
|
|
|
|
else { |
|
8361
|
|
|
|
|
|
|
|
|
8362
|
|
|
|
|
|
|
# Internal link with rel file relationship. |
|
8363
|
|
|
|
|
|
|
push @hlink_refs, |
|
8364
|
|
|
|
|
|
|
[ |
|
8365
|
|
|
|
|
|
|
$link_type, $row_num, $col_num, |
|
8366
|
|
|
|
|
|
|
$link->{_url}, $link->{_str}, $link->{_tip} |
|
8367
|
8
|
|
|
|
|
29
|
]; |
|
8368
|
|
|
|
|
|
|
} |
|
8369
|
|
|
|
|
|
|
} |
|
8370
|
|
|
|
|
|
|
} |
|
8371
|
|
|
|
|
|
|
|
|
8372
|
|
|
|
|
|
|
# Write the hyperlink elements. |
|
8373
|
49
|
|
|
|
|
243
|
$self->xml_start_tag( 'hyperlinks' ); |
|
8374
|
|
|
|
|
|
|
|
|
8375
|
49
|
|
|
|
|
151
|
for my $aref ( @hlink_refs ) { |
|
8376
|
82
|
|
|
|
|
280
|
my ( $type, @args ) = @$aref; |
|
8377
|
|
|
|
|
|
|
|
|
8378
|
82
|
100
|
|
|
|
364
|
if ( $type == 1 ) { |
|
|
|
50
|
|
|
|
|
|
|
8379
|
74
|
|
|
|
|
299
|
$self->_write_hyperlink_external( @args ); |
|
8380
|
|
|
|
|
|
|
} |
|
8381
|
|
|
|
|
|
|
elsif ( $type == 2 ) { |
|
8382
|
8
|
|
|
|
|
33
|
$self->_write_hyperlink_internal( @args ); |
|
8383
|
|
|
|
|
|
|
} |
|
8384
|
|
|
|
|
|
|
} |
|
8385
|
|
|
|
|
|
|
|
|
8386
|
49
|
|
|
|
|
273
|
$self->xml_end_tag( 'hyperlinks' ); |
|
8387
|
|
|
|
|
|
|
} |
|
8388
|
|
|
|
|
|
|
|
|
8389
|
|
|
|
|
|
|
|
|
8390
|
|
|
|
|
|
|
############################################################################## |
|
8391
|
|
|
|
|
|
|
# |
|
8392
|
|
|
|
|
|
|
# _write_hyperlink_external() |
|
8393
|
|
|
|
|
|
|
# |
|
8394
|
|
|
|
|
|
|
# Write the element for external links. |
|
8395
|
|
|
|
|
|
|
# |
|
8396
|
|
|
|
|
|
|
sub _write_hyperlink_external { |
|
8397
|
|
|
|
|
|
|
|
|
8398
|
75
|
|
|
75
|
|
155
|
my $self = shift; |
|
8399
|
75
|
|
|
|
|
147
|
my $row = shift; |
|
8400
|
75
|
|
|
|
|
139
|
my $col = shift; |
|
8401
|
75
|
|
|
|
|
135
|
my $id = shift; |
|
8402
|
75
|
|
|
|
|
151
|
my $location = shift; |
|
8403
|
75
|
|
|
|
|
276
|
my $display = shift; |
|
8404
|
75
|
|
|
|
|
143
|
my $tooltip = shift; |
|
8405
|
|
|
|
|
|
|
|
|
8406
|
75
|
|
|
|
|
305
|
my $ref = xl_rowcol_to_cell( $row, $col ); |
|
8407
|
75
|
|
|
|
|
216
|
my $r_id = 'rId' . $id; |
|
8408
|
|
|
|
|
|
|
|
|
8409
|
75
|
|
|
|
|
276
|
my @attributes = ( |
|
8410
|
|
|
|
|
|
|
'ref' => $ref, |
|
8411
|
|
|
|
|
|
|
'r:id' => $r_id, |
|
8412
|
|
|
|
|
|
|
); |
|
8413
|
|
|
|
|
|
|
|
|
8414
|
75
|
100
|
|
|
|
291
|
push @attributes, ( 'location' => $location ) if defined $location; |
|
8415
|
75
|
100
|
|
|
|
229
|
push @attributes, ( 'display' => $display ) if defined $display; |
|
8416
|
75
|
100
|
|
|
|
223
|
push @attributes, ( 'tooltip' => $tooltip ) if defined $tooltip; |
|
8417
|
|
|
|
|
|
|
|
|
8418
|
75
|
|
|
|
|
301
|
$self->xml_empty_tag( 'hyperlink', @attributes ); |
|
8419
|
|
|
|
|
|
|
} |
|
8420
|
|
|
|
|
|
|
|
|
8421
|
|
|
|
|
|
|
|
|
8422
|
|
|
|
|
|
|
############################################################################## |
|
8423
|
|
|
|
|
|
|
# |
|
8424
|
|
|
|
|
|
|
# _write_hyperlink_internal() |
|
8425
|
|
|
|
|
|
|
# |
|
8426
|
|
|
|
|
|
|
# Write the element for internal links. |
|
8427
|
|
|
|
|
|
|
# |
|
8428
|
|
|
|
|
|
|
sub _write_hyperlink_internal { |
|
8429
|
|
|
|
|
|
|
|
|
8430
|
11
|
|
|
11
|
|
86
|
my $self = shift; |
|
8431
|
11
|
|
|
|
|
16
|
my $row = shift; |
|
8432
|
11
|
|
|
|
|
19
|
my $col = shift; |
|
8433
|
11
|
|
|
|
|
17
|
my $location = shift; |
|
8434
|
11
|
|
|
|
|
18
|
my $display = shift; |
|
8435
|
11
|
|
|
|
|
19
|
my $tooltip = shift; |
|
8436
|
|
|
|
|
|
|
|
|
8437
|
11
|
|
|
|
|
87
|
my $ref = xl_rowcol_to_cell( $row, $col ); |
|
8438
|
|
|
|
|
|
|
|
|
8439
|
11
|
|
|
|
|
32
|
my @attributes = ( 'ref' => $ref, 'location' => $location ); |
|
8440
|
|
|
|
|
|
|
|
|
8441
|
11
|
100
|
|
|
|
29
|
push @attributes, ( 'tooltip' => $tooltip ) if defined $tooltip; |
|
8442
|
11
|
|
|
|
|
22
|
push @attributes, ( 'display' => $display ); |
|
8443
|
|
|
|
|
|
|
|
|
8444
|
11
|
|
|
|
|
43
|
$self->xml_empty_tag( 'hyperlink', @attributes ); |
|
8445
|
|
|
|
|
|
|
} |
|
8446
|
|
|
|
|
|
|
|
|
8447
|
|
|
|
|
|
|
|
|
8448
|
|
|
|
|
|
|
############################################################################## |
|
8449
|
|
|
|
|
|
|
# |
|
8450
|
|
|
|
|
|
|
# _write_panes() |
|
8451
|
|
|
|
|
|
|
# |
|
8452
|
|
|
|
|
|
|
# Write the frozen or split elements. |
|
8453
|
|
|
|
|
|
|
# |
|
8454
|
|
|
|
|
|
|
sub _write_panes { |
|
8455
|
|
|
|
|
|
|
|
|
8456
|
83
|
|
|
83
|
|
197
|
my $self = shift; |
|
8457
|
83
|
|
|
|
|
127
|
my @panes = @{ $self->{_panes} }; |
|
|
83
|
|
|
|
|
235
|
|
|
8458
|
|
|
|
|
|
|
|
|
8459
|
83
|
100
|
|
|
|
208
|
return unless @panes; |
|
8460
|
|
|
|
|
|
|
|
|
8461
|
66
|
100
|
|
|
|
219
|
if ( $panes[4] == 2 ) { |
|
8462
|
38
|
|
|
|
|
105
|
$self->_write_split_panes( @panes ); |
|
8463
|
|
|
|
|
|
|
} |
|
8464
|
|
|
|
|
|
|
else { |
|
8465
|
28
|
|
|
|
|
78
|
$self->_write_freeze_panes( @panes ); |
|
8466
|
|
|
|
|
|
|
} |
|
8467
|
|
|
|
|
|
|
} |
|
8468
|
|
|
|
|
|
|
|
|
8469
|
|
|
|
|
|
|
|
|
8470
|
|
|
|
|
|
|
############################################################################## |
|
8471
|
|
|
|
|
|
|
# |
|
8472
|
|
|
|
|
|
|
# _write_freeze_panes() |
|
8473
|
|
|
|
|
|
|
# |
|
8474
|
|
|
|
|
|
|
# Write the element for freeze panes. |
|
8475
|
|
|
|
|
|
|
# |
|
8476
|
|
|
|
|
|
|
sub _write_freeze_panes { |
|
8477
|
|
|
|
|
|
|
|
|
8478
|
28
|
|
|
28
|
|
45
|
my $self = shift; |
|
8479
|
28
|
|
|
|
|
39
|
my @attributes; |
|
8480
|
|
|
|
|
|
|
|
|
8481
|
28
|
|
|
|
|
81
|
my ( $row, $col, $top_row, $left_col, $type ) = @_; |
|
8482
|
|
|
|
|
|
|
|
|
8483
|
28
|
|
|
|
|
51
|
my $y_split = $row; |
|
8484
|
28
|
|
|
|
|
44
|
my $x_split = $col; |
|
8485
|
28
|
|
|
|
|
78
|
my $top_left_cell = xl_rowcol_to_cell( $top_row, $left_col ); |
|
8486
|
28
|
|
|
|
|
109
|
my $active_pane; |
|
8487
|
|
|
|
|
|
|
my $state; |
|
8488
|
28
|
|
|
|
|
0
|
my $active_cell; |
|
8489
|
28
|
|
|
|
|
0
|
my $sqref; |
|
8490
|
|
|
|
|
|
|
|
|
8491
|
|
|
|
|
|
|
# Move user cell selection to the panes. |
|
8492
|
28
|
100
|
|
|
|
41
|
if ( @{ $self->{_selections} } ) { |
|
|
28
|
|
|
|
|
74
|
|
|
8493
|
7
|
|
|
|
|
12
|
( undef, $active_cell, $sqref ) = @{ $self->{_selections}->[0] }; |
|
|
7
|
|
|
|
|
21
|
|
|
8494
|
7
|
|
|
|
|
17
|
$self->{_selections} = []; |
|
8495
|
|
|
|
|
|
|
} |
|
8496
|
|
|
|
|
|
|
|
|
8497
|
|
|
|
|
|
|
# Set the active pane. |
|
8498
|
28
|
100
|
100
|
|
|
134
|
if ( $row && $col ) { |
|
|
|
100
|
|
|
|
|
|
|
8499
|
13
|
|
|
|
|
30
|
$active_pane = 'bottomRight'; |
|
8500
|
|
|
|
|
|
|
|
|
8501
|
13
|
|
|
|
|
67
|
my $row_cell = xl_rowcol_to_cell( $row, 0 ); |
|
8502
|
13
|
|
|
|
|
39
|
my $col_cell = xl_rowcol_to_cell( 0, $col ); |
|
8503
|
|
|
|
|
|
|
|
|
8504
|
13
|
|
|
|
|
29
|
push @{ $self->{_selections} }, |
|
|
13
|
|
|
|
|
74
|
|
|
8505
|
|
|
|
|
|
|
( |
|
8506
|
|
|
|
|
|
|
[ 'topRight', $col_cell, $col_cell ], |
|
8507
|
|
|
|
|
|
|
[ 'bottomLeft', $row_cell, $row_cell ], |
|
8508
|
|
|
|
|
|
|
[ 'bottomRight', $active_cell, $sqref ] |
|
8509
|
|
|
|
|
|
|
); |
|
8510
|
|
|
|
|
|
|
} |
|
8511
|
|
|
|
|
|
|
elsif ( $col ) { |
|
8512
|
7
|
|
|
|
|
13
|
$active_pane = 'topRight'; |
|
8513
|
7
|
|
|
|
|
19
|
push @{ $self->{_selections} }, [ 'topRight', $active_cell, $sqref ]; |
|
|
7
|
|
|
|
|
27
|
|
|
8514
|
|
|
|
|
|
|
} |
|
8515
|
|
|
|
|
|
|
else { |
|
8516
|
8
|
|
|
|
|
20
|
$active_pane = 'bottomLeft'; |
|
8517
|
8
|
|
|
|
|
13
|
push @{ $self->{_selections} }, [ 'bottomLeft', $active_cell, $sqref ]; |
|
|
8
|
|
|
|
|
43
|
|
|
8518
|
|
|
|
|
|
|
} |
|
8519
|
|
|
|
|
|
|
|
|
8520
|
|
|
|
|
|
|
# Set the pane type. |
|
8521
|
28
|
100
|
|
|
|
76
|
if ( $type == 0 ) { |
|
|
|
50
|
|
|
|
|
|
|
8522
|
25
|
|
|
|
|
52
|
$state = 'frozen'; |
|
8523
|
|
|
|
|
|
|
} |
|
8524
|
|
|
|
|
|
|
elsif ( $type == 1 ) { |
|
8525
|
3
|
|
|
|
|
8
|
$state = 'frozenSplit'; |
|
8526
|
|
|
|
|
|
|
} |
|
8527
|
|
|
|
|
|
|
else { |
|
8528
|
0
|
|
|
|
|
0
|
$state = 'split'; |
|
8529
|
|
|
|
|
|
|
} |
|
8530
|
|
|
|
|
|
|
|
|
8531
|
|
|
|
|
|
|
|
|
8532
|
28
|
100
|
|
|
|
73
|
push @attributes, ( 'xSplit' => $x_split ) if $x_split; |
|
8533
|
28
|
100
|
|
|
|
70
|
push @attributes, ( 'ySplit' => $y_split ) if $y_split; |
|
8534
|
|
|
|
|
|
|
|
|
8535
|
28
|
|
|
|
|
54
|
push @attributes, ( 'topLeftCell' => $top_left_cell ); |
|
8536
|
28
|
|
|
|
|
51
|
push @attributes, ( 'activePane' => $active_pane ); |
|
8537
|
28
|
|
|
|
|
59
|
push @attributes, ( 'state' => $state ); |
|
8538
|
|
|
|
|
|
|
|
|
8539
|
|
|
|
|
|
|
|
|
8540
|
28
|
|
|
|
|
105
|
$self->xml_empty_tag( 'pane', @attributes ); |
|
8541
|
|
|
|
|
|
|
} |
|
8542
|
|
|
|
|
|
|
|
|
8543
|
|
|
|
|
|
|
|
|
8544
|
|
|
|
|
|
|
############################################################################## |
|
8545
|
|
|
|
|
|
|
# |
|
8546
|
|
|
|
|
|
|
# _write_split_panes() |
|
8547
|
|
|
|
|
|
|
# |
|
8548
|
|
|
|
|
|
|
# Write the element for split panes. |
|
8549
|
|
|
|
|
|
|
# |
|
8550
|
|
|
|
|
|
|
# See also, implementers note for split_panes(). |
|
8551
|
|
|
|
|
|
|
# |
|
8552
|
|
|
|
|
|
|
sub _write_split_panes { |
|
8553
|
|
|
|
|
|
|
|
|
8554
|
38
|
|
|
38
|
|
53
|
my $self = shift; |
|
8555
|
38
|
|
|
|
|
90
|
my @attributes; |
|
8556
|
|
|
|
|
|
|
my $y_split; |
|
8557
|
38
|
|
|
|
|
0
|
my $x_split; |
|
8558
|
38
|
|
|
|
|
56
|
my $has_selection = 0; |
|
8559
|
38
|
|
|
|
|
85
|
my $active_pane; |
|
8560
|
|
|
|
|
|
|
my $active_cell; |
|
8561
|
38
|
|
|
|
|
0
|
my $sqref; |
|
8562
|
|
|
|
|
|
|
|
|
8563
|
38
|
|
|
|
|
86
|
my ( $row, $col, $top_row, $left_col, $type ) = @_; |
|
8564
|
38
|
|
|
|
|
106
|
$y_split = $row; |
|
8565
|
38
|
|
|
|
|
55
|
$x_split = $col; |
|
8566
|
|
|
|
|
|
|
|
|
8567
|
|
|
|
|
|
|
# Move user cell selection to the panes. |
|
8568
|
38
|
100
|
|
|
|
70
|
if ( @{ $self->{_selections} } ) { |
|
|
38
|
|
|
|
|
92
|
|
|
8569
|
8
|
|
|
|
|
10
|
( undef, $active_cell, $sqref ) = @{ $self->{_selections}->[0] }; |
|
|
8
|
|
|
|
|
20
|
|
|
8570
|
8
|
|
|
|
|
16
|
$self->{_selections} = []; |
|
8571
|
8
|
|
|
|
|
11
|
$has_selection = 1; |
|
8572
|
|
|
|
|
|
|
} |
|
8573
|
|
|
|
|
|
|
|
|
8574
|
|
|
|
|
|
|
# Convert the row and col to 1/20 twip units with padding. |
|
8575
|
38
|
100
|
|
|
|
105
|
$y_split = int( 20 * $y_split + 300 ) if $y_split; |
|
8576
|
38
|
100
|
|
|
|
117
|
$x_split = $self->_calculate_x_split_width( $x_split ) if $x_split; |
|
8577
|
|
|
|
|
|
|
|
|
8578
|
|
|
|
|
|
|
# For non-explicit topLeft definitions, estimate the cell offset based |
|
8579
|
|
|
|
|
|
|
# on the pixels dimensions. This is only a workaround and doesn't take |
|
8580
|
|
|
|
|
|
|
# adjusted cell dimensions into account. |
|
8581
|
38
|
100
|
100
|
|
|
147
|
if ( $top_row == $row && $left_col == $col ) { |
|
8582
|
26
|
|
|
|
|
70
|
$top_row = int( 0.5 + ( $y_split - 300 ) / 20 / 15 ); |
|
8583
|
26
|
|
|
|
|
67
|
$left_col = int( 0.5 + ( $x_split - 390 ) / 20 / 3 * 4 / 64 ); |
|
8584
|
|
|
|
|
|
|
} |
|
8585
|
|
|
|
|
|
|
|
|
8586
|
38
|
|
|
|
|
125
|
my $top_left_cell = xl_rowcol_to_cell( $top_row, $left_col ); |
|
8587
|
|
|
|
|
|
|
|
|
8588
|
|
|
|
|
|
|
# If there is no selection set the active cell to the top left cell. |
|
8589
|
38
|
100
|
|
|
|
81
|
if ( !$has_selection ) { |
|
8590
|
30
|
|
|
|
|
51
|
$active_cell = $top_left_cell; |
|
8591
|
30
|
|
|
|
|
46
|
$sqref = $top_left_cell; |
|
8592
|
|
|
|
|
|
|
} |
|
8593
|
|
|
|
|
|
|
|
|
8594
|
|
|
|
|
|
|
# Set the Cell selections. |
|
8595
|
38
|
100
|
100
|
|
|
136
|
if ( $row && $col ) { |
|
|
|
100
|
|
|
|
|
|
|
8596
|
10
|
|
|
|
|
20
|
$active_pane = 'bottomRight'; |
|
8597
|
|
|
|
|
|
|
|
|
8598
|
10
|
|
|
|
|
26
|
my $row_cell = xl_rowcol_to_cell( $top_row, 0 ); |
|
8599
|
10
|
|
|
|
|
26
|
my $col_cell = xl_rowcol_to_cell( 0, $left_col ); |
|
8600
|
|
|
|
|
|
|
|
|
8601
|
10
|
|
|
|
|
23
|
push @{ $self->{_selections} }, |
|
|
10
|
|
|
|
|
56
|
|
|
8602
|
|
|
|
|
|
|
( |
|
8603
|
|
|
|
|
|
|
[ 'topRight', $col_cell, $col_cell ], |
|
8604
|
|
|
|
|
|
|
[ 'bottomLeft', $row_cell, $row_cell ], |
|
8605
|
|
|
|
|
|
|
[ 'bottomRight', $active_cell, $sqref ] |
|
8606
|
|
|
|
|
|
|
); |
|
8607
|
|
|
|
|
|
|
} |
|
8608
|
|
|
|
|
|
|
elsif ( $col ) { |
|
8609
|
14
|
|
|
|
|
28
|
$active_pane = 'topRight'; |
|
8610
|
14
|
|
|
|
|
22
|
push @{ $self->{_selections} }, [ 'topRight', $active_cell, $sqref ]; |
|
|
14
|
|
|
|
|
48
|
|
|
8611
|
|
|
|
|
|
|
} |
|
8612
|
|
|
|
|
|
|
else { |
|
8613
|
14
|
|
|
|
|
34
|
$active_pane = 'bottomLeft'; |
|
8614
|
14
|
|
|
|
|
21
|
push @{ $self->{_selections} }, [ 'bottomLeft', $active_cell, $sqref ]; |
|
|
14
|
|
|
|
|
53
|
|
|
8615
|
|
|
|
|
|
|
} |
|
8616
|
|
|
|
|
|
|
|
|
8617
|
38
|
100
|
|
|
|
102
|
push @attributes, ( 'xSplit' => $x_split ) if $x_split; |
|
8618
|
38
|
100
|
|
|
|
90
|
push @attributes, ( 'ySplit' => $y_split ) if $y_split; |
|
8619
|
38
|
|
|
|
|
76
|
push @attributes, ( 'topLeftCell' => $top_left_cell ); |
|
8620
|
38
|
100
|
|
|
|
77
|
push @attributes, ( 'activePane' => $active_pane ) if $has_selection; |
|
8621
|
|
|
|
|
|
|
|
|
8622
|
38
|
|
|
|
|
121
|
$self->xml_empty_tag( 'pane', @attributes ); |
|
8623
|
|
|
|
|
|
|
} |
|
8624
|
|
|
|
|
|
|
|
|
8625
|
|
|
|
|
|
|
|
|
8626
|
|
|
|
|
|
|
############################################################################## |
|
8627
|
|
|
|
|
|
|
# |
|
8628
|
|
|
|
|
|
|
# _calculate_x_split_width() |
|
8629
|
|
|
|
|
|
|
# |
|
8630
|
|
|
|
|
|
|
# Convert column width from user units to pane split width. |
|
8631
|
|
|
|
|
|
|
# |
|
8632
|
|
|
|
|
|
|
sub _calculate_x_split_width { |
|
8633
|
|
|
|
|
|
|
|
|
8634
|
24
|
|
|
24
|
|
44
|
my $self = shift; |
|
8635
|
24
|
|
|
|
|
39
|
my $width = shift; |
|
8636
|
|
|
|
|
|
|
|
|
8637
|
24
|
|
|
|
|
37
|
my $max_digit_width = 7; # For Calabri 11. |
|
8638
|
24
|
|
|
|
|
36
|
my $padding = 5; |
|
8639
|
24
|
|
|
|
|
34
|
my $pixels; |
|
8640
|
|
|
|
|
|
|
|
|
8641
|
|
|
|
|
|
|
# Convert to pixels. |
|
8642
|
24
|
50
|
|
|
|
68
|
if ( $width < 1 ) { |
|
8643
|
0
|
|
|
|
|
0
|
$pixels = int( $width * ( $max_digit_width + $padding ) + 0.5 ); |
|
8644
|
|
|
|
|
|
|
} |
|
8645
|
|
|
|
|
|
|
else { |
|
8646
|
24
|
|
|
|
|
66
|
$pixels = int( $width * $max_digit_width + 0.5 ) + $padding; |
|
8647
|
|
|
|
|
|
|
} |
|
8648
|
|
|
|
|
|
|
|
|
8649
|
|
|
|
|
|
|
# Convert to points. |
|
8650
|
24
|
|
|
|
|
52
|
my $points = $pixels * 3 / 4; |
|
8651
|
|
|
|
|
|
|
|
|
8652
|
|
|
|
|
|
|
# Convert to twips (twentieths of a point). |
|
8653
|
24
|
|
|
|
|
40
|
my $twips = $points * 20; |
|
8654
|
|
|
|
|
|
|
|
|
8655
|
|
|
|
|
|
|
# Add offset/padding. |
|
8656
|
24
|
|
|
|
|
40
|
$width = $twips + 390; |
|
8657
|
|
|
|
|
|
|
|
|
8658
|
24
|
|
|
|
|
46
|
return $width; |
|
8659
|
|
|
|
|
|
|
} |
|
8660
|
|
|
|
|
|
|
|
|
8661
|
|
|
|
|
|
|
|
|
8662
|
|
|
|
|
|
|
############################################################################## |
|
8663
|
|
|
|
|
|
|
# |
|
8664
|
|
|
|
|
|
|
# _write_tab_color() |
|
8665
|
|
|
|
|
|
|
# |
|
8666
|
|
|
|
|
|
|
# Write the element. |
|
8667
|
|
|
|
|
|
|
# |
|
8668
|
|
|
|
|
|
|
sub _write_tab_color { |
|
8669
|
|
|
|
|
|
|
|
|
8670
|
13
|
|
|
13
|
|
58
|
my $self = shift; |
|
8671
|
13
|
|
|
|
|
33
|
my $color_index = $self->{_tab_color}; |
|
8672
|
|
|
|
|
|
|
|
|
8673
|
13
|
100
|
|
|
|
42
|
return unless $color_index; |
|
8674
|
|
|
|
|
|
|
|
|
8675
|
5
|
|
|
|
|
19
|
my $rgb = $self->_get_palette_color( $color_index ); |
|
8676
|
|
|
|
|
|
|
|
|
8677
|
5
|
|
|
|
|
16
|
my @attributes = ( 'rgb' => $rgb ); |
|
8678
|
|
|
|
|
|
|
|
|
8679
|
5
|
|
|
|
|
28
|
$self->xml_empty_tag( 'tabColor', @attributes ); |
|
8680
|
|
|
|
|
|
|
} |
|
8681
|
|
|
|
|
|
|
|
|
8682
|
|
|
|
|
|
|
|
|
8683
|
|
|
|
|
|
|
############################################################################## |
|
8684
|
|
|
|
|
|
|
# |
|
8685
|
|
|
|
|
|
|
# _write_outline_pr() |
|
8686
|
|
|
|
|
|
|
# |
|
8687
|
|
|
|
|
|
|
# Write the element. |
|
8688
|
|
|
|
|
|
|
# |
|
8689
|
|
|
|
|
|
|
sub _write_outline_pr { |
|
8690
|
|
|
|
|
|
|
|
|
8691
|
11
|
|
|
11
|
|
25
|
my $self = shift; |
|
8692
|
11
|
|
|
|
|
28
|
my @attributes = (); |
|
8693
|
|
|
|
|
|
|
|
|
8694
|
11
|
100
|
|
|
|
52
|
return unless $self->{_outline_changed}; |
|
8695
|
|
|
|
|
|
|
|
|
8696
|
1
|
50
|
|
|
|
6
|
push @attributes, ( "applyStyles" => 1 ) if $self->{_outline_style}; |
|
8697
|
1
|
50
|
|
|
|
5
|
push @attributes, ( "summaryBelow" => 0 ) if !$self->{_outline_below}; |
|
8698
|
1
|
50
|
|
|
|
4
|
push @attributes, ( "summaryRight" => 0 ) if !$self->{_outline_right}; |
|
8699
|
1
|
50
|
|
|
|
4
|
push @attributes, ( "showOutlineSymbols" => 0 ) if !$self->{_outline_on}; |
|
8700
|
|
|
|
|
|
|
|
|
8701
|
1
|
|
|
|
|
20
|
$self->xml_empty_tag( 'outlinePr', @attributes ); |
|
8702
|
|
|
|
|
|
|
} |
|
8703
|
|
|
|
|
|
|
|
|
8704
|
|
|
|
|
|
|
|
|
8705
|
|
|
|
|
|
|
############################################################################## |
|
8706
|
|
|
|
|
|
|
# |
|
8707
|
|
|
|
|
|
|
# _write_sheet_protection() |
|
8708
|
|
|
|
|
|
|
# |
|
8709
|
|
|
|
|
|
|
# Write the element. |
|
8710
|
|
|
|
|
|
|
# |
|
8711
|
|
|
|
|
|
|
sub _write_sheet_protection { |
|
8712
|
|
|
|
|
|
|
|
|
8713
|
1039
|
|
|
1039
|
|
2890
|
my $self = shift; |
|
8714
|
1039
|
|
|
|
|
2642
|
my @attributes; |
|
8715
|
|
|
|
|
|
|
|
|
8716
|
1039
|
100
|
|
|
|
6361
|
return unless $self->{_protect}; |
|
8717
|
|
|
|
|
|
|
|
|
8718
|
27
|
|
|
|
|
42
|
my %arg = %{ $self->{_protect} }; |
|
|
27
|
|
|
|
|
192
|
|
|
8719
|
|
|
|
|
|
|
|
|
8720
|
27
|
100
|
|
|
|
99
|
push @attributes, ( "password" => $arg{password} ) if $arg{password}; |
|
8721
|
27
|
100
|
|
|
|
93
|
push @attributes, ( "sheet" => 1 ) if $arg{sheet}; |
|
8722
|
27
|
100
|
|
|
|
72
|
push @attributes, ( "content" => 1 ) if $arg{content}; |
|
8723
|
27
|
100
|
|
|
|
68
|
push @attributes, ( "objects" => 1 ) if !$arg{objects}; |
|
8724
|
27
|
100
|
|
|
|
69
|
push @attributes, ( "scenarios" => 1 ) if !$arg{scenarios}; |
|
8725
|
27
|
100
|
|
|
|
57
|
push @attributes, ( "formatCells" => 0 ) if $arg{format_cells}; |
|
8726
|
27
|
100
|
|
|
|
57
|
push @attributes, ( "formatColumns" => 0 ) if $arg{format_columns}; |
|
8727
|
27
|
100
|
|
|
|
62
|
push @attributes, ( "formatRows" => 0 ) if $arg{format_rows}; |
|
8728
|
27
|
100
|
|
|
|
51
|
push @attributes, ( "insertColumns" => 0 ) if $arg{insert_columns}; |
|
8729
|
27
|
100
|
|
|
|
56
|
push @attributes, ( "insertRows" => 0 ) if $arg{insert_rows}; |
|
8730
|
27
|
100
|
|
|
|
58
|
push @attributes, ( "insertHyperlinks" => 0 ) if $arg{insert_hyperlinks}; |
|
8731
|
27
|
100
|
|
|
|
58
|
push @attributes, ( "deleteColumns" => 0 ) if $arg{delete_columns}; |
|
8732
|
27
|
100
|
|
|
|
63
|
push @attributes, ( "deleteRows" => 0 ) if $arg{delete_rows}; |
|
8733
|
|
|
|
|
|
|
|
|
8734
|
|
|
|
|
|
|
push @attributes, ( "selectLockedCells" => 1 ) |
|
8735
|
27
|
100
|
|
|
|
58
|
if !$arg{select_locked_cells}; |
|
8736
|
|
|
|
|
|
|
|
|
8737
|
27
|
100
|
|
|
|
54
|
push @attributes, ( "sort" => 0 ) if $arg{sort}; |
|
8738
|
27
|
100
|
|
|
|
58
|
push @attributes, ( "autoFilter" => 0 ) if $arg{autofilter}; |
|
8739
|
27
|
100
|
|
|
|
61
|
push @attributes, ( "pivotTables" => 0 ) if $arg{pivot_tables}; |
|
8740
|
|
|
|
|
|
|
|
|
8741
|
|
|
|
|
|
|
push @attributes, ( "selectUnlockedCells" => 1 ) |
|
8742
|
27
|
100
|
|
|
|
62
|
if !$arg{select_unlocked_cells}; |
|
8743
|
|
|
|
|
|
|
|
|
8744
|
|
|
|
|
|
|
|
|
8745
|
27
|
|
|
|
|
140
|
$self->xml_empty_tag( 'sheetProtection', @attributes ); |
|
8746
|
|
|
|
|
|
|
} |
|
8747
|
|
|
|
|
|
|
|
|
8748
|
|
|
|
|
|
|
|
|
8749
|
|
|
|
|
|
|
############################################################################## |
|
8750
|
|
|
|
|
|
|
# |
|
8751
|
|
|
|
|
|
|
# _write_drawings() |
|
8752
|
|
|
|
|
|
|
# |
|
8753
|
|
|
|
|
|
|
# Write the elements. |
|
8754
|
|
|
|
|
|
|
# |
|
8755
|
|
|
|
|
|
|
sub _write_drawings { |
|
8756
|
|
|
|
|
|
|
|
|
8757
|
1014
|
|
|
1014
|
|
2320
|
my $self = shift; |
|
8758
|
|
|
|
|
|
|
|
|
8759
|
1014
|
100
|
|
|
|
4332
|
return unless $self->{_drawing}; |
|
8760
|
|
|
|
|
|
|
|
|
8761
|
470
|
|
|
|
|
2419
|
$self->_write_drawing( ++$self->{_rel_count} ); |
|
8762
|
|
|
|
|
|
|
} |
|
8763
|
|
|
|
|
|
|
|
|
8764
|
|
|
|
|
|
|
|
|
8765
|
|
|
|
|
|
|
############################################################################## |
|
8766
|
|
|
|
|
|
|
# |
|
8767
|
|
|
|
|
|
|
# _write_drawing() |
|
8768
|
|
|
|
|
|
|
# |
|
8769
|
|
|
|
|
|
|
# Write the element. |
|
8770
|
|
|
|
|
|
|
# |
|
8771
|
|
|
|
|
|
|
sub _write_drawing { |
|
8772
|
|
|
|
|
|
|
|
|
8773
|
470
|
|
|
470
|
|
1285
|
my $self = shift; |
|
8774
|
470
|
|
|
|
|
1135
|
my $id = shift; |
|
8775
|
470
|
|
|
|
|
1707
|
my $r_id = 'rId' . $id; |
|
8776
|
|
|
|
|
|
|
|
|
8777
|
470
|
|
|
|
|
1749
|
my @attributes = ( 'r:id' => $r_id ); |
|
8778
|
|
|
|
|
|
|
|
|
8779
|
470
|
|
|
|
|
2363
|
$self->xml_empty_tag( 'drawing', @attributes ); |
|
8780
|
|
|
|
|
|
|
} |
|
8781
|
|
|
|
|
|
|
|
|
8782
|
|
|
|
|
|
|
|
|
8783
|
|
|
|
|
|
|
############################################################################## |
|
8784
|
|
|
|
|
|
|
# |
|
8785
|
|
|
|
|
|
|
# _write_legacy_drawing() |
|
8786
|
|
|
|
|
|
|
# |
|
8787
|
|
|
|
|
|
|
# Write the element. |
|
8788
|
|
|
|
|
|
|
# |
|
8789
|
|
|
|
|
|
|
sub _write_legacy_drawing { |
|
8790
|
|
|
|
|
|
|
|
|
8791
|
994
|
|
|
994
|
|
2464
|
my $self = shift; |
|
8792
|
994
|
|
|
|
|
2183
|
my $id; |
|
8793
|
|
|
|
|
|
|
|
|
8794
|
994
|
100
|
|
|
|
4388
|
return unless $self->{_has_vml}; |
|
8795
|
|
|
|
|
|
|
|
|
8796
|
|
|
|
|
|
|
# Increment the relationship id for any drawings or comments. |
|
8797
|
54
|
|
|
|
|
155
|
$id = ++$self->{_rel_count}; |
|
8798
|
|
|
|
|
|
|
|
|
8799
|
54
|
|
|
|
|
381
|
my @attributes = ( 'r:id' => 'rId' . $id ); |
|
8800
|
|
|
|
|
|
|
|
|
8801
|
54
|
|
|
|
|
356
|
$self->xml_empty_tag( 'legacyDrawing', @attributes ); |
|
8802
|
|
|
|
|
|
|
} |
|
8803
|
|
|
|
|
|
|
|
|
8804
|
|
|
|
|
|
|
|
|
8805
|
|
|
|
|
|
|
|
|
8806
|
|
|
|
|
|
|
############################################################################## |
|
8807
|
|
|
|
|
|
|
# |
|
8808
|
|
|
|
|
|
|
# _write_legacy_drawing_hf() |
|
8809
|
|
|
|
|
|
|
# |
|
8810
|
|
|
|
|
|
|
# Write the element. |
|
8811
|
|
|
|
|
|
|
# |
|
8812
|
|
|
|
|
|
|
sub _write_legacy_drawing_hf { |
|
8813
|
|
|
|
|
|
|
|
|
8814
|
993
|
|
|
993
|
|
2629
|
my $self = shift; |
|
8815
|
993
|
|
|
|
|
2157
|
my $id; |
|
8816
|
|
|
|
|
|
|
|
|
8817
|
993
|
100
|
|
|
|
3958
|
return unless $self->{_has_header_vml}; |
|
8818
|
|
|
|
|
|
|
|
|
8819
|
|
|
|
|
|
|
# Increment the relationship id for any drawings or comments. |
|
8820
|
22
|
|
|
|
|
55
|
$id = ++$self->{_rel_count}; |
|
8821
|
|
|
|
|
|
|
|
|
8822
|
22
|
|
|
|
|
91
|
my @attributes = ( 'r:id' => 'rId' . $id ); |
|
8823
|
|
|
|
|
|
|
|
|
8824
|
22
|
|
|
|
|
87
|
$self->xml_empty_tag( 'legacyDrawingHF', @attributes ); |
|
8825
|
|
|
|
|
|
|
} |
|
8826
|
|
|
|
|
|
|
|
|
8827
|
|
|
|
|
|
|
|
|
8828
|
|
|
|
|
|
|
# |
|
8829
|
|
|
|
|
|
|
# Note, the following font methods are, more or less, duplicated from the |
|
8830
|
|
|
|
|
|
|
# Excel::Writer::XLSX::Package::Styles class. I will look at implementing |
|
8831
|
|
|
|
|
|
|
# this is a cleaner encapsulated mode at a later stage. |
|
8832
|
|
|
|
|
|
|
# |
|
8833
|
|
|
|
|
|
|
|
|
8834
|
|
|
|
|
|
|
|
|
8835
|
|
|
|
|
|
|
############################################################################## |
|
8836
|
|
|
|
|
|
|
# |
|
8837
|
|
|
|
|
|
|
# _write_font() |
|
8838
|
|
|
|
|
|
|
# |
|
8839
|
|
|
|
|
|
|
# Write the element. |
|
8840
|
|
|
|
|
|
|
# |
|
8841
|
|
|
|
|
|
|
sub _write_font { |
|
8842
|
|
|
|
|
|
|
|
|
8843
|
56
|
|
|
56
|
|
102
|
my $self = shift; |
|
8844
|
56
|
|
|
|
|
103
|
my $format = shift; |
|
8845
|
|
|
|
|
|
|
|
|
8846
|
56
|
|
|
|
|
168
|
$self->{_rstring}->xml_start_tag( 'rPr' ); |
|
8847
|
|
|
|
|
|
|
|
|
8848
|
56
|
100
|
|
|
|
228
|
$self->{_rstring}->xml_empty_tag( 'b' ) if $format->{_bold}; |
|
8849
|
56
|
100
|
|
|
|
176
|
$self->{_rstring}->xml_empty_tag( 'i' ) if $format->{_italic}; |
|
8850
|
56
|
50
|
|
|
|
164
|
$self->{_rstring}->xml_empty_tag( 'strike' ) if $format->{_font_strikeout}; |
|
8851
|
56
|
50
|
|
|
|
144
|
$self->{_rstring}->xml_empty_tag( 'outline' ) if $format->{_font_outline}; |
|
8852
|
56
|
50
|
|
|
|
160
|
$self->{_rstring}->xml_empty_tag( 'shadow' ) if $format->{_font_shadow}; |
|
8853
|
|
|
|
|
|
|
|
|
8854
|
|
|
|
|
|
|
# Handle the underline variants. |
|
8855
|
56
|
50
|
|
|
|
145
|
$self->_write_underline( $format->{_underline} ) if $format->{_underline}; |
|
8856
|
|
|
|
|
|
|
|
|
8857
|
56
|
50
|
|
|
|
164
|
$self->_write_vert_align( 'superscript' ) if $format->{_font_script} == 1; |
|
8858
|
56
|
50
|
|
|
|
142
|
$self->_write_vert_align( 'subscript' ) if $format->{_font_script} == 2; |
|
8859
|
|
|
|
|
|
|
|
|
8860
|
56
|
|
|
|
|
225
|
$self->{_rstring}->xml_empty_tag( 'sz', 'val', $format->{_size} ); |
|
8861
|
|
|
|
|
|
|
|
|
8862
|
56
|
50
|
|
|
|
222
|
if ( my $theme = $format->{_theme} ) { |
|
|
|
100
|
|
|
|
|
|
|
8863
|
0
|
|
|
|
|
0
|
$self->_write_rstring_color( 'theme' => $theme ); |
|
8864
|
|
|
|
|
|
|
} |
|
8865
|
|
|
|
|
|
|
elsif ( my $color = $format->{_color} ) { |
|
8866
|
1
|
|
|
|
|
4
|
$color = $self->_get_palette_color( $color ); |
|
8867
|
|
|
|
|
|
|
|
|
8868
|
1
|
|
|
|
|
7
|
$self->_write_rstring_color( 'rgb' => $color ); |
|
8869
|
|
|
|
|
|
|
} |
|
8870
|
|
|
|
|
|
|
else { |
|
8871
|
55
|
|
|
|
|
182
|
$self->_write_rstring_color( 'theme' => 1 ); |
|
8872
|
|
|
|
|
|
|
} |
|
8873
|
|
|
|
|
|
|
|
|
8874
|
56
|
|
|
|
|
247
|
$self->{_rstring}->xml_empty_tag( 'rFont', 'val', $format->{_font} ); |
|
8875
|
|
|
|
|
|
|
$self->{_rstring} |
|
8876
|
56
|
|
|
|
|
237
|
->xml_empty_tag( 'family', 'val', $format->{_font_family} ); |
|
8877
|
|
|
|
|
|
|
|
|
8878
|
56
|
50
|
33
|
|
|
346
|
if ( $format->{_font} eq 'Calibri' && !$format->{_hyperlink} ) { |
|
8879
|
|
|
|
|
|
|
$self->{_rstring} |
|
8880
|
56
|
|
|
|
|
166
|
->xml_empty_tag( 'scheme', 'val', $format->{_font_scheme} ); |
|
8881
|
|
|
|
|
|
|
} |
|
8882
|
|
|
|
|
|
|
|
|
8883
|
56
|
|
|
|
|
183
|
$self->{_rstring}->xml_end_tag( 'rPr' ); |
|
8884
|
|
|
|
|
|
|
} |
|
8885
|
|
|
|
|
|
|
|
|
8886
|
|
|
|
|
|
|
|
|
8887
|
|
|
|
|
|
|
############################################################################### |
|
8888
|
|
|
|
|
|
|
# |
|
8889
|
|
|
|
|
|
|
# _write_underline() |
|
8890
|
|
|
|
|
|
|
# |
|
8891
|
|
|
|
|
|
|
# Write the underline font element. |
|
8892
|
|
|
|
|
|
|
# |
|
8893
|
|
|
|
|
|
|
sub _write_underline { |
|
8894
|
|
|
|
|
|
|
|
|
8895
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
|
8896
|
0
|
|
|
|
|
0
|
my $underline = shift; |
|
8897
|
0
|
|
|
|
|
0
|
my @attributes; |
|
8898
|
|
|
|
|
|
|
|
|
8899
|
|
|
|
|
|
|
# Handle the underline variants. |
|
8900
|
0
|
0
|
|
|
|
0
|
if ( $underline == 2 ) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
8901
|
0
|
|
|
|
|
0
|
@attributes = ( val => 'double' ); |
|
8902
|
|
|
|
|
|
|
} |
|
8903
|
|
|
|
|
|
|
elsif ( $underline == 33 ) { |
|
8904
|
0
|
|
|
|
|
0
|
@attributes = ( val => 'singleAccounting' ); |
|
8905
|
|
|
|
|
|
|
} |
|
8906
|
|
|
|
|
|
|
elsif ( $underline == 34 ) { |
|
8907
|
0
|
|
|
|
|
0
|
@attributes = ( val => 'doubleAccounting' ); |
|
8908
|
|
|
|
|
|
|
} |
|
8909
|
|
|
|
|
|
|
else { |
|
8910
|
0
|
|
|
|
|
0
|
@attributes = (); # Default to single underline. |
|
8911
|
|
|
|
|
|
|
} |
|
8912
|
|
|
|
|
|
|
|
|
8913
|
0
|
|
|
|
|
0
|
$self->{_rstring}->xml_empty_tag( 'u', @attributes ); |
|
8914
|
|
|
|
|
|
|
|
|
8915
|
|
|
|
|
|
|
} |
|
8916
|
|
|
|
|
|
|
|
|
8917
|
|
|
|
|
|
|
|
|
8918
|
|
|
|
|
|
|
############################################################################## |
|
8919
|
|
|
|
|
|
|
# |
|
8920
|
|
|
|
|
|
|
# _write_vert_align() |
|
8921
|
|
|
|
|
|
|
# |
|
8922
|
|
|
|
|
|
|
# Write the font sub-element. |
|
8923
|
|
|
|
|
|
|
# |
|
8924
|
|
|
|
|
|
|
sub _write_vert_align { |
|
8925
|
|
|
|
|
|
|
|
|
8926
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
|
8927
|
0
|
|
|
|
|
0
|
my $val = shift; |
|
8928
|
|
|
|
|
|
|
|
|
8929
|
0
|
|
|
|
|
0
|
my @attributes = ( 'val' => $val ); |
|
8930
|
|
|
|
|
|
|
|
|
8931
|
0
|
|
|
|
|
0
|
$self->{_rstring}->xml_empty_tag( 'vertAlign', @attributes ); |
|
8932
|
|
|
|
|
|
|
} |
|
8933
|
|
|
|
|
|
|
|
|
8934
|
|
|
|
|
|
|
|
|
8935
|
|
|
|
|
|
|
############################################################################## |
|
8936
|
|
|
|
|
|
|
# |
|
8937
|
|
|
|
|
|
|
# _write_rstring_color() |
|
8938
|
|
|
|
|
|
|
# |
|
8939
|
|
|
|
|
|
|
# Write the element. |
|
8940
|
|
|
|
|
|
|
# |
|
8941
|
|
|
|
|
|
|
sub _write_rstring_color { |
|
8942
|
|
|
|
|
|
|
|
|
8943
|
56
|
|
|
56
|
|
100
|
my $self = shift; |
|
8944
|
56
|
|
|
|
|
104
|
my $name = shift; |
|
8945
|
56
|
|
|
|
|
138
|
my $value = shift; |
|
8946
|
|
|
|
|
|
|
|
|
8947
|
56
|
|
|
|
|
143
|
my @attributes = ( $name => $value ); |
|
8948
|
|
|
|
|
|
|
|
|
8949
|
56
|
|
|
|
|
161
|
$self->{_rstring}->xml_empty_tag( 'color', @attributes ); |
|
8950
|
|
|
|
|
|
|
} |
|
8951
|
|
|
|
|
|
|
|
|
8952
|
|
|
|
|
|
|
|
|
8953
|
|
|
|
|
|
|
# |
|
8954
|
|
|
|
|
|
|
# End font duplication code. |
|
8955
|
|
|
|
|
|
|
# |
|
8956
|
|
|
|
|
|
|
|
|
8957
|
|
|
|
|
|
|
|
|
8958
|
|
|
|
|
|
|
############################################################################## |
|
8959
|
|
|
|
|
|
|
# |
|
8960
|
|
|
|
|
|
|
# _write_data_validations() |
|
8961
|
|
|
|
|
|
|
# |
|
8962
|
|
|
|
|
|
|
# Write the element. |
|
8963
|
|
|
|
|
|
|
# |
|
8964
|
|
|
|
|
|
|
sub _write_data_validations { |
|
8965
|
|
|
|
|
|
|
|
|
8966
|
1049
|
|
|
1049
|
|
2846
|
my $self = shift; |
|
8967
|
1049
|
|
|
|
|
2775
|
my @validations = @{ $self->{_validations} }; |
|
|
1049
|
|
|
|
|
3382
|
|
|
8968
|
1049
|
|
|
|
|
2815
|
my $count = @validations; |
|
8969
|
|
|
|
|
|
|
|
|
8970
|
1049
|
100
|
|
|
|
3902
|
return unless $count; |
|
8971
|
|
|
|
|
|
|
|
|
8972
|
62
|
|
|
|
|
141
|
my @attributes = ( 'count' => $count ); |
|
8973
|
|
|
|
|
|
|
|
|
8974
|
62
|
|
|
|
|
259
|
$self->xml_start_tag( 'dataValidations', @attributes ); |
|
8975
|
|
|
|
|
|
|
|
|
8976
|
62
|
|
|
|
|
149
|
for my $validation ( @validations ) { |
|
8977
|
|
|
|
|
|
|
|
|
8978
|
|
|
|
|
|
|
# Write the dataValidation element. |
|
8979
|
64
|
|
|
|
|
168
|
$self->_write_data_validation( $validation ); |
|
8980
|
|
|
|
|
|
|
} |
|
8981
|
|
|
|
|
|
|
|
|
8982
|
62
|
|
|
|
|
184
|
$self->xml_end_tag( 'dataValidations' ); |
|
8983
|
|
|
|
|
|
|
} |
|
8984
|
|
|
|
|
|
|
|
|
8985
|
|
|
|
|
|
|
|
|
8986
|
|
|
|
|
|
|
############################################################################## |
|
8987
|
|
|
|
|
|
|
# |
|
8988
|
|
|
|
|
|
|
# _write_data_validation() |
|
8989
|
|
|
|
|
|
|
# |
|
8990
|
|
|
|
|
|
|
# Write the element. |
|
8991
|
|
|
|
|
|
|
# |
|
8992
|
|
|
|
|
|
|
sub _write_data_validation { |
|
8993
|
|
|
|
|
|
|
|
|
8994
|
64
|
|
|
64
|
|
92
|
my $self = shift; |
|
8995
|
64
|
|
|
|
|
99
|
my $param = shift; |
|
8996
|
64
|
|
|
|
|
115
|
my $sqref = ''; |
|
8997
|
64
|
|
|
|
|
123
|
my @attributes = (); |
|
8998
|
|
|
|
|
|
|
|
|
8999
|
|
|
|
|
|
|
|
|
9000
|
|
|
|
|
|
|
# Set the cell range(s) for the data validation. |
|
9001
|
64
|
|
|
|
|
108
|
for my $cells ( @{ $param->{cells} } ) { |
|
|
64
|
|
|
|
|
142
|
|
|
9002
|
|
|
|
|
|
|
|
|
9003
|
|
|
|
|
|
|
# Add a space between multiple cell ranges. |
|
9004
|
68
|
100
|
|
|
|
180
|
$sqref .= ' ' if $sqref ne ''; |
|
9005
|
|
|
|
|
|
|
|
|
9006
|
68
|
|
|
|
|
158
|
my ( $row_first, $col_first, $row_last, $col_last ) = @$cells; |
|
9007
|
|
|
|
|
|
|
|
|
9008
|
|
|
|
|
|
|
# Swap last row/col for first row/col as necessary |
|
9009
|
68
|
50
|
|
|
|
149
|
if ( $row_first > $row_last ) { |
|
9010
|
0
|
|
|
|
|
0
|
( $row_first, $row_last ) = ( $row_last, $row_first ); |
|
9011
|
|
|
|
|
|
|
} |
|
9012
|
|
|
|
|
|
|
|
|
9013
|
68
|
50
|
|
|
|
145
|
if ( $col_first > $col_last ) { |
|
9014
|
0
|
|
|
|
|
0
|
( $col_first, $col_last ) = ( $col_last, $col_first ); |
|
9015
|
|
|
|
|
|
|
} |
|
9016
|
|
|
|
|
|
|
|
|
9017
|
|
|
|
|
|
|
# If the first and last cell are the same write a single cell. |
|
9018
|
68
|
100
|
66
|
|
|
247
|
if ( ( $row_first == $row_last ) && ( $col_first == $col_last ) ) { |
|
9019
|
65
|
|
|
|
|
245
|
$sqref .= xl_rowcol_to_cell( $row_first, $col_first ); |
|
9020
|
|
|
|
|
|
|
} |
|
9021
|
|
|
|
|
|
|
else { |
|
9022
|
3
|
|
|
|
|
16
|
$sqref .= xl_range( $row_first, $row_last, $col_first, $col_last ); |
|
9023
|
|
|
|
|
|
|
} |
|
9024
|
|
|
|
|
|
|
} |
|
9025
|
|
|
|
|
|
|
|
|
9026
|
|
|
|
|
|
|
|
|
9027
|
64
|
100
|
|
|
|
187
|
if ( $param->{validate} ne 'none' ) { |
|
9028
|
|
|
|
|
|
|
|
|
9029
|
62
|
|
|
|
|
139
|
push @attributes, ( 'type' => $param->{validate} ); |
|
9030
|
|
|
|
|
|
|
|
|
9031
|
62
|
100
|
|
|
|
147
|
if ( $param->{criteria} ne 'between' ) { |
|
9032
|
26
|
|
|
|
|
48
|
push @attributes, ( 'operator' => $param->{criteria} ); |
|
9033
|
|
|
|
|
|
|
} |
|
9034
|
|
|
|
|
|
|
|
|
9035
|
|
|
|
|
|
|
} |
|
9036
|
|
|
|
|
|
|
|
|
9037
|
64
|
100
|
|
|
|
173
|
if ( $param->{error_type} ) { |
|
9038
|
|
|
|
|
|
|
push @attributes, ( 'errorStyle' => 'warning' ) |
|
9039
|
2
|
100
|
|
|
|
8
|
if $param->{error_type} == 1; |
|
9040
|
|
|
|
|
|
|
push @attributes, ( 'errorStyle' => 'information' ) |
|
9041
|
2
|
100
|
|
|
|
6
|
if $param->{error_type} == 2; |
|
9042
|
|
|
|
|
|
|
} |
|
9043
|
|
|
|
|
|
|
|
|
9044
|
64
|
100
|
|
|
|
177
|
push @attributes, ( 'allowBlank' => 1 ) if $param->{ignore_blank}; |
|
9045
|
64
|
100
|
|
|
|
153
|
push @attributes, ( 'showDropDown' => 1 ) if !$param->{dropdown}; |
|
9046
|
64
|
100
|
|
|
|
180
|
push @attributes, ( 'showInputMessage' => 1 ) if $param->{show_input}; |
|
9047
|
64
|
100
|
|
|
|
181
|
push @attributes, ( 'showErrorMessage' => 1 ) if $param->{show_error}; |
|
9048
|
|
|
|
|
|
|
|
|
9049
|
|
|
|
|
|
|
push @attributes, ( 'errorTitle' => $param->{error_title} ) |
|
9050
|
64
|
100
|
|
|
|
173
|
if $param->{error_title}; |
|
9051
|
|
|
|
|
|
|
|
|
9052
|
|
|
|
|
|
|
push @attributes, ( 'error' => $param->{error_message} ) |
|
9053
|
64
|
100
|
|
|
|
139
|
if $param->{error_message}; |
|
9054
|
|
|
|
|
|
|
|
|
9055
|
|
|
|
|
|
|
push @attributes, ( 'promptTitle' => $param->{input_title} ) |
|
9056
|
64
|
100
|
|
|
|
153
|
if $param->{input_title}; |
|
9057
|
|
|
|
|
|
|
|
|
9058
|
|
|
|
|
|
|
push @attributes, ( 'prompt' => $param->{input_message} ) |
|
9059
|
64
|
100
|
|
|
|
147
|
if $param->{input_message}; |
|
9060
|
|
|
|
|
|
|
|
|
9061
|
64
|
|
|
|
|
134
|
push @attributes, ( 'sqref' => $sqref ); |
|
9062
|
|
|
|
|
|
|
|
|
9063
|
64
|
100
|
|
|
|
164
|
if ( $param->{validate} eq 'none' ) { |
|
9064
|
2
|
|
|
|
|
16
|
$self->xml_empty_tag( 'dataValidation', @attributes ); |
|
9065
|
|
|
|
|
|
|
} |
|
9066
|
|
|
|
|
|
|
else { |
|
9067
|
62
|
|
|
|
|
222
|
$self->xml_start_tag( 'dataValidation', @attributes ); |
|
9068
|
|
|
|
|
|
|
|
|
9069
|
|
|
|
|
|
|
# Write the formula1 element. |
|
9070
|
62
|
|
|
|
|
205
|
$self->_write_formula_1( $param->{value} ); |
|
9071
|
|
|
|
|
|
|
|
|
9072
|
|
|
|
|
|
|
# Write the formula2 element. |
|
9073
|
|
|
|
|
|
|
$self->_write_formula_2( $param->{maximum} ) |
|
9074
|
62
|
100
|
|
|
|
195
|
if defined $param->{maximum}; |
|
9075
|
|
|
|
|
|
|
|
|
9076
|
62
|
|
|
|
|
175
|
$self->xml_end_tag( 'dataValidation' ); |
|
9077
|
|
|
|
|
|
|
} |
|
9078
|
|
|
|
|
|
|
} |
|
9079
|
|
|
|
|
|
|
|
|
9080
|
|
|
|
|
|
|
|
|
9081
|
|
|
|
|
|
|
############################################################################## |
|
9082
|
|
|
|
|
|
|
# |
|
9083
|
|
|
|
|
|
|
# _write_formula_1() |
|
9084
|
|
|
|
|
|
|
# |
|
9085
|
|
|
|
|
|
|
# Write the element. |
|
9086
|
|
|
|
|
|
|
# |
|
9087
|
|
|
|
|
|
|
sub _write_formula_1 { |
|
9088
|
|
|
|
|
|
|
|
|
9089
|
62
|
|
|
62
|
|
113
|
my $self = shift; |
|
9090
|
62
|
|
|
|
|
96
|
my $formula = shift; |
|
9091
|
|
|
|
|
|
|
|
|
9092
|
|
|
|
|
|
|
# Convert a list array ref into a comma separated string. |
|
9093
|
62
|
100
|
|
|
|
159
|
if ( ref $formula eq 'ARRAY' ) { |
|
9094
|
10
|
|
|
|
|
41
|
$formula = join ',', @$formula; |
|
9095
|
10
|
|
|
|
|
32
|
$formula = qq("$formula"); |
|
9096
|
|
|
|
|
|
|
} |
|
9097
|
|
|
|
|
|
|
|
|
9098
|
62
|
|
|
|
|
170
|
$formula =~ s/^=//; # Remove formula symbol. |
|
9099
|
|
|
|
|
|
|
|
|
9100
|
62
|
|
|
|
|
204
|
$self->xml_data_element( 'formula1', $formula ); |
|
9101
|
|
|
|
|
|
|
} |
|
9102
|
|
|
|
|
|
|
|
|
9103
|
|
|
|
|
|
|
|
|
9104
|
|
|
|
|
|
|
############################################################################## |
|
9105
|
|
|
|
|
|
|
# |
|
9106
|
|
|
|
|
|
|
# _write_formula_2() |
|
9107
|
|
|
|
|
|
|
# |
|
9108
|
|
|
|
|
|
|
# Write the element. |
|
9109
|
|
|
|
|
|
|
# |
|
9110
|
|
|
|
|
|
|
sub _write_formula_2 { |
|
9111
|
|
|
|
|
|
|
|
|
9112
|
24
|
|
|
24
|
|
43
|
my $self = shift; |
|
9113
|
24
|
|
|
|
|
34
|
my $formula = shift; |
|
9114
|
|
|
|
|
|
|
|
|
9115
|
24
|
|
|
|
|
53
|
$formula =~ s/^=//; # Remove formula symbol. |
|
9116
|
|
|
|
|
|
|
|
|
9117
|
24
|
|
|
|
|
54
|
$self->xml_data_element( 'formula2', $formula ); |
|
9118
|
|
|
|
|
|
|
} |
|
9119
|
|
|
|
|
|
|
|
|
9120
|
|
|
|
|
|
|
|
|
9121
|
|
|
|
|
|
|
############################################################################## |
|
9122
|
|
|
|
|
|
|
# |
|
9123
|
|
|
|
|
|
|
# _write_conditional_formats() |
|
9124
|
|
|
|
|
|
|
# |
|
9125
|
|
|
|
|
|
|
# Write the Worksheet conditional formats. |
|
9126
|
|
|
|
|
|
|
# |
|
9127
|
|
|
|
|
|
|
sub _write_conditional_formats { |
|
9128
|
|
|
|
|
|
|
|
|
9129
|
997
|
|
|
997
|
|
2417
|
my $self = shift; |
|
9130
|
997
|
|
|
|
|
2555
|
my @ranges = sort keys %{ $self->{_cond_formats} }; |
|
|
997
|
|
|
|
|
5380
|
|
|
9131
|
|
|
|
|
|
|
|
|
9132
|
997
|
100
|
|
|
|
4047
|
return unless scalar @ranges; |
|
9133
|
|
|
|
|
|
|
|
|
9134
|
63
|
|
|
|
|
206
|
for my $range ( @ranges ) { |
|
9135
|
|
|
|
|
|
|
$self->_write_conditional_formatting( $range, |
|
9136
|
110
|
|
|
|
|
392
|
$self->{_cond_formats}->{$range} ); |
|
9137
|
|
|
|
|
|
|
} |
|
9138
|
|
|
|
|
|
|
} |
|
9139
|
|
|
|
|
|
|
|
|
9140
|
|
|
|
|
|
|
|
|
9141
|
|
|
|
|
|
|
############################################################################## |
|
9142
|
|
|
|
|
|
|
# |
|
9143
|
|
|
|
|
|
|
# _write_conditional_formatting() |
|
9144
|
|
|
|
|
|
|
# |
|
9145
|
|
|
|
|
|
|
# Write the element. |
|
9146
|
|
|
|
|
|
|
# |
|
9147
|
|
|
|
|
|
|
sub _write_conditional_formatting { |
|
9148
|
|
|
|
|
|
|
|
|
9149
|
110
|
|
|
110
|
|
213
|
my $self = shift; |
|
9150
|
110
|
|
|
|
|
239
|
my $range = shift; |
|
9151
|
110
|
|
|
|
|
187
|
my $params = shift; |
|
9152
|
|
|
|
|
|
|
|
|
9153
|
110
|
|
|
|
|
291
|
my @attributes = ( 'sqref' => $range ); |
|
9154
|
|
|
|
|
|
|
|
|
9155
|
110
|
|
|
|
|
435
|
$self->xml_start_tag( 'conditionalFormatting', @attributes ); |
|
9156
|
|
|
|
|
|
|
|
|
9157
|
110
|
|
|
|
|
303
|
for my $param ( @$params ) { |
|
9158
|
|
|
|
|
|
|
|
|
9159
|
|
|
|
|
|
|
# Write the cfRule element. |
|
9160
|
149
|
|
|
|
|
436
|
$self->_write_cf_rule( $param ); |
|
9161
|
|
|
|
|
|
|
} |
|
9162
|
|
|
|
|
|
|
|
|
9163
|
110
|
|
|
|
|
402
|
$self->xml_end_tag( 'conditionalFormatting' ); |
|
9164
|
|
|
|
|
|
|
} |
|
9165
|
|
|
|
|
|
|
|
|
9166
|
|
|
|
|
|
|
############################################################################## |
|
9167
|
|
|
|
|
|
|
# |
|
9168
|
|
|
|
|
|
|
# _write_cf_rule() |
|
9169
|
|
|
|
|
|
|
# |
|
9170
|
|
|
|
|
|
|
# Write the element. |
|
9171
|
|
|
|
|
|
|
# |
|
9172
|
|
|
|
|
|
|
sub _write_cf_rule { |
|
9173
|
|
|
|
|
|
|
|
|
9174
|
149
|
|
|
149
|
|
316
|
my $self = shift; |
|
9175
|
149
|
|
|
|
|
248
|
my $param = shift; |
|
9176
|
|
|
|
|
|
|
|
|
9177
|
149
|
|
|
|
|
398
|
my @attributes = ( 'type' => $param->{type} ); |
|
9178
|
|
|
|
|
|
|
|
|
9179
|
|
|
|
|
|
|
push @attributes, ( 'dxfId' => $param->{format} ) |
|
9180
|
149
|
100
|
|
|
|
477
|
if defined $param->{format}; |
|
9181
|
|
|
|
|
|
|
|
|
9182
|
149
|
|
|
|
|
399
|
push @attributes, ( 'priority' => $param->{priority} ); |
|
9183
|
|
|
|
|
|
|
|
|
9184
|
|
|
|
|
|
|
push @attributes, ( 'stopIfTrue' => 1 ) |
|
9185
|
149
|
100
|
|
|
|
432
|
if $param->{stop_if_true}; |
|
9186
|
|
|
|
|
|
|
|
|
9187
|
149
|
100
|
100
|
|
|
2232
|
if ( $param->{type} eq 'cellIs' ) { |
|
|
|
100
|
100
|
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
9188
|
36
|
|
|
|
|
153
|
push @attributes, ( 'operator' => $param->{criteria} ); |
|
9189
|
|
|
|
|
|
|
|
|
9190
|
36
|
|
|
|
|
173
|
$self->xml_start_tag( 'cfRule', @attributes ); |
|
9191
|
|
|
|
|
|
|
|
|
9192
|
36
|
100
|
66
|
|
|
210
|
if ( defined $param->{minimum} && defined $param->{maximum} ) { |
|
9193
|
5
|
|
|
|
|
23
|
$self->_write_formula( $param->{minimum} ); |
|
9194
|
5
|
|
|
|
|
26
|
$self->_write_formula( $param->{maximum} ); |
|
9195
|
|
|
|
|
|
|
} |
|
9196
|
|
|
|
|
|
|
else { |
|
9197
|
31
|
|
|
|
|
94
|
my $value = $param->{value}; |
|
9198
|
|
|
|
|
|
|
|
|
9199
|
|
|
|
|
|
|
# String "Cell" values must be quoted, apart from ranges. |
|
9200
|
31
|
100
|
100
|
|
|
429
|
if ( $value !~ /(\$?)([A-Z]{1,3})(\$?)(\d+)/ |
|
9201
|
|
|
|
|
|
|
&& $value !~ |
|
9202
|
|
|
|
|
|
|
/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/ ) |
|
9203
|
|
|
|
|
|
|
{ |
|
9204
|
2
|
100
|
|
|
|
12
|
if ( $value !~ /^".*"$/ ) { |
|
9205
|
1
|
|
|
|
|
4
|
$value = qq("$value"); |
|
9206
|
|
|
|
|
|
|
} |
|
9207
|
|
|
|
|
|
|
} |
|
9208
|
|
|
|
|
|
|
|
|
9209
|
31
|
|
|
|
|
139
|
$self->_write_formula( $value ); |
|
9210
|
|
|
|
|
|
|
} |
|
9211
|
|
|
|
|
|
|
|
|
9212
|
36
|
|
|
|
|
206
|
$self->xml_end_tag( 'cfRule' ); |
|
9213
|
|
|
|
|
|
|
} |
|
9214
|
|
|
|
|
|
|
elsif ( $param->{type} eq 'aboveAverage' ) { |
|
9215
|
10
|
100
|
|
|
|
27
|
if ( $param->{criteria} =~ /below/ ) { |
|
9216
|
5
|
|
|
|
|
11
|
push @attributes, ( 'aboveAverage' => 0 ); |
|
9217
|
|
|
|
|
|
|
} |
|
9218
|
|
|
|
|
|
|
|
|
9219
|
10
|
100
|
|
|
|
24
|
if ( $param->{criteria} =~ /equal/ ) { |
|
9220
|
2
|
|
|
|
|
5
|
push @attributes, ( 'equalAverage' => 1 ); |
|
9221
|
|
|
|
|
|
|
} |
|
9222
|
|
|
|
|
|
|
|
|
9223
|
10
|
100
|
|
|
|
30
|
if ( $param->{criteria} =~ /([123]) std dev/ ) { |
|
9224
|
6
|
|
|
|
|
15
|
push @attributes, ( 'stdDev' => $1 ); |
|
9225
|
|
|
|
|
|
|
} |
|
9226
|
|
|
|
|
|
|
|
|
9227
|
10
|
|
|
|
|
24
|
$self->xml_empty_tag( 'cfRule', @attributes ); |
|
9228
|
|
|
|
|
|
|
} |
|
9229
|
|
|
|
|
|
|
elsif ( $param->{type} eq 'top10' ) { |
|
9230
|
4
|
100
|
66
|
|
|
16
|
if ( defined $param->{criteria} && $param->{criteria} eq '%' ) { |
|
9231
|
2
|
|
|
|
|
4
|
push @attributes, ( 'percent' => 1 ); |
|
9232
|
|
|
|
|
|
|
} |
|
9233
|
|
|
|
|
|
|
|
|
9234
|
4
|
100
|
|
|
|
10
|
if ( $param->{direction} ) { |
|
9235
|
2
|
|
|
|
|
5
|
push @attributes, ( 'bottom' => 1 ); |
|
9236
|
|
|
|
|
|
|
} |
|
9237
|
|
|
|
|
|
|
|
|
9238
|
4
|
|
50
|
|
|
10
|
my $rank = $param->{value} || 10; |
|
9239
|
4
|
|
|
|
|
8
|
push @attributes, ( 'rank' => $rank ); |
|
9240
|
|
|
|
|
|
|
|
|
9241
|
4
|
|
|
|
|
22
|
$self->xml_empty_tag( 'cfRule', @attributes ); |
|
9242
|
|
|
|
|
|
|
} |
|
9243
|
|
|
|
|
|
|
elsif ( $param->{type} eq 'duplicateValues' ) { |
|
9244
|
1
|
|
|
|
|
5
|
$self->xml_empty_tag( 'cfRule', @attributes ); |
|
9245
|
|
|
|
|
|
|
} |
|
9246
|
|
|
|
|
|
|
elsif ( $param->{type} eq 'uniqueValues' ) { |
|
9247
|
1
|
|
|
|
|
5
|
$self->xml_empty_tag( 'cfRule', @attributes ); |
|
9248
|
|
|
|
|
|
|
} |
|
9249
|
|
|
|
|
|
|
elsif ($param->{type} eq 'containsText' |
|
9250
|
|
|
|
|
|
|
|| $param->{type} eq 'notContainsText' |
|
9251
|
|
|
|
|
|
|
|| $param->{type} eq 'beginsWith' |
|
9252
|
|
|
|
|
|
|
|| $param->{type} eq 'endsWith' ) |
|
9253
|
|
|
|
|
|
|
{ |
|
9254
|
8
|
|
|
|
|
19
|
push @attributes, ( 'operator' => $param->{criteria} ); |
|
9255
|
8
|
|
|
|
|
15
|
push @attributes, ( 'text' => $param->{value} ); |
|
9256
|
|
|
|
|
|
|
|
|
9257
|
8
|
|
|
|
|
22
|
$self->xml_start_tag( 'cfRule', @attributes ); |
|
9258
|
8
|
|
|
|
|
25
|
$self->_write_formula( $param->{formula} ); |
|
9259
|
8
|
|
|
|
|
21
|
$self->xml_end_tag( 'cfRule' ); |
|
9260
|
|
|
|
|
|
|
} |
|
9261
|
|
|
|
|
|
|
elsif ( $param->{type} eq 'timePeriod' ) { |
|
9262
|
10
|
|
|
|
|
21
|
push @attributes, ( 'timePeriod' => $param->{criteria} ); |
|
9263
|
|
|
|
|
|
|
|
|
9264
|
10
|
|
|
|
|
28
|
$self->xml_start_tag( 'cfRule', @attributes ); |
|
9265
|
10
|
|
|
|
|
35
|
$self->_write_formula( $param->{formula} ); |
|
9266
|
10
|
|
|
|
|
29
|
$self->xml_end_tag( 'cfRule' ); |
|
9267
|
|
|
|
|
|
|
} |
|
9268
|
|
|
|
|
|
|
elsif ($param->{type} eq 'containsBlanks' |
|
9269
|
|
|
|
|
|
|
|| $param->{type} eq 'notContainsBlanks' |
|
9270
|
|
|
|
|
|
|
|| $param->{type} eq 'containsErrors' |
|
9271
|
|
|
|
|
|
|
|| $param->{type} eq 'notContainsErrors' ) |
|
9272
|
|
|
|
|
|
|
{ |
|
9273
|
4
|
|
|
|
|
17
|
$self->xml_start_tag( 'cfRule', @attributes ); |
|
9274
|
4
|
|
|
|
|
13
|
$self->_write_formula( $param->{formula} ); |
|
9275
|
4
|
|
|
|
|
12
|
$self->xml_end_tag( 'cfRule' ); |
|
9276
|
|
|
|
|
|
|
} |
|
9277
|
|
|
|
|
|
|
elsif ( $param->{type} eq 'colorScale' ) { |
|
9278
|
|
|
|
|
|
|
|
|
9279
|
5
|
|
|
|
|
26
|
$self->xml_start_tag( 'cfRule', @attributes ); |
|
9280
|
5
|
|
|
|
|
34
|
$self->_write_color_scale( $param ); |
|
9281
|
5
|
|
|
|
|
17
|
$self->xml_end_tag( 'cfRule' ); |
|
9282
|
|
|
|
|
|
|
} |
|
9283
|
|
|
|
|
|
|
elsif ( $param->{type} eq 'dataBar' ) { |
|
9284
|
|
|
|
|
|
|
|
|
9285
|
29
|
|
|
|
|
116
|
$self->xml_start_tag( 'cfRule', @attributes ); |
|
9286
|
|
|
|
|
|
|
|
|
9287
|
29
|
|
|
|
|
126
|
$self->_write_data_bar( $param ); |
|
9288
|
|
|
|
|
|
|
|
|
9289
|
29
|
100
|
|
|
|
106
|
if ($param->{_is_data_bar_2010}) { |
|
9290
|
25
|
|
|
|
|
74
|
$self->_write_data_bar_ext( $param ); |
|
9291
|
|
|
|
|
|
|
} |
|
9292
|
|
|
|
|
|
|
|
|
9293
|
29
|
|
|
|
|
95
|
$self->xml_end_tag( 'cfRule' ); |
|
9294
|
|
|
|
|
|
|
} |
|
9295
|
|
|
|
|
|
|
elsif ( $param->{type} eq 'expression' ) { |
|
9296
|
|
|
|
|
|
|
|
|
9297
|
4
|
|
|
|
|
14
|
$self->xml_start_tag( 'cfRule', @attributes ); |
|
9298
|
4
|
|
|
|
|
14
|
$self->_write_formula( $param->{criteria} ); |
|
9299
|
4
|
|
|
|
|
13
|
$self->xml_end_tag( 'cfRule' ); |
|
9300
|
|
|
|
|
|
|
} |
|
9301
|
|
|
|
|
|
|
elsif ( $param->{type} eq 'iconSet' ) { |
|
9302
|
|
|
|
|
|
|
|
|
9303
|
37
|
|
|
|
|
117
|
$self->xml_start_tag( 'cfRule', @attributes ); |
|
9304
|
37
|
|
|
|
|
119
|
$self->_write_icon_set( $param ); |
|
9305
|
37
|
|
|
|
|
84
|
$self->xml_end_tag( 'cfRule' ); |
|
9306
|
|
|
|
|
|
|
} |
|
9307
|
|
|
|
|
|
|
} |
|
9308
|
|
|
|
|
|
|
|
|
9309
|
|
|
|
|
|
|
|
|
9310
|
|
|
|
|
|
|
############################################################################## |
|
9311
|
|
|
|
|
|
|
# |
|
9312
|
|
|
|
|
|
|
# _write_icon_set() |
|
9313
|
|
|
|
|
|
|
# |
|
9314
|
|
|
|
|
|
|
# Write the element. |
|
9315
|
|
|
|
|
|
|
# |
|
9316
|
|
|
|
|
|
|
sub _write_icon_set { |
|
9317
|
|
|
|
|
|
|
|
|
9318
|
37
|
|
|
37
|
|
63
|
my $self = shift; |
|
9319
|
37
|
|
|
|
|
54
|
my $param = shift; |
|
9320
|
37
|
|
|
|
|
68
|
my $icon_style = $param->{icon_style}; |
|
9321
|
37
|
|
|
|
|
64
|
my $total_icons = $param->{total_icons}; |
|
9322
|
37
|
|
|
|
|
55
|
my $icons = $param->{icons}; |
|
9323
|
37
|
|
|
|
|
48
|
my $i; |
|
9324
|
|
|
|
|
|
|
|
|
9325
|
37
|
|
|
|
|
52
|
my @attributes = (); |
|
9326
|
|
|
|
|
|
|
|
|
9327
|
|
|
|
|
|
|
# Don't set attribute for default style. |
|
9328
|
37
|
100
|
|
|
|
81
|
if ( $icon_style ne '3TrafficLights' ) { |
|
9329
|
36
|
|
|
|
|
76
|
@attributes = ( 'iconSet' => $icon_style ); |
|
9330
|
|
|
|
|
|
|
} |
|
9331
|
|
|
|
|
|
|
|
|
9332
|
37
|
50
|
66
|
|
|
111
|
if ( exists $param->{'icons_only'} && $param->{'icons_only'} ) { |
|
9333
|
4
|
|
|
|
|
10
|
push @attributes, ( 'showValue' => 0 ); |
|
9334
|
|
|
|
|
|
|
} |
|
9335
|
|
|
|
|
|
|
|
|
9336
|
37
|
50
|
66
|
|
|
82
|
if ( exists $param->{'reverse_icons'} && $param->{'reverse_icons'} ) { |
|
9337
|
6
|
|
|
|
|
14
|
push @attributes, ( 'reverse' => 1 ); |
|
9338
|
|
|
|
|
|
|
} |
|
9339
|
|
|
|
|
|
|
|
|
9340
|
37
|
|
|
|
|
99
|
$self->xml_start_tag( 'iconSet', @attributes ); |
|
9341
|
|
|
|
|
|
|
|
|
9342
|
|
|
|
|
|
|
# Write the properites for different icon styles. |
|
9343
|
37
|
|
|
|
|
56
|
for my $icon ( reverse @{ $param->{icons} } ) { |
|
|
37
|
|
|
|
|
85
|
|
|
9344
|
|
|
|
|
|
|
$self->_write_cfvo( |
|
9345
|
|
|
|
|
|
|
$icon->{'type'}, |
|
9346
|
|
|
|
|
|
|
$icon->{'value'}, |
|
9347
|
138
|
|
|
|
|
293
|
$icon->{'criteria'} |
|
9348
|
|
|
|
|
|
|
); |
|
9349
|
|
|
|
|
|
|
} |
|
9350
|
|
|
|
|
|
|
|
|
9351
|
37
|
|
|
|
|
94
|
$self->xml_end_tag( 'iconSet' ); |
|
9352
|
|
|
|
|
|
|
} |
|
9353
|
|
|
|
|
|
|
|
|
9354
|
|
|
|
|
|
|
############################################################################## |
|
9355
|
|
|
|
|
|
|
# |
|
9356
|
|
|
|
|
|
|
# _write_formula() |
|
9357
|
|
|
|
|
|
|
# |
|
9358
|
|
|
|
|
|
|
# Write the element. |
|
9359
|
|
|
|
|
|
|
# |
|
9360
|
|
|
|
|
|
|
sub _write_formula { |
|
9361
|
|
|
|
|
|
|
|
|
9362
|
67
|
|
|
67
|
|
132
|
my $self = shift; |
|
9363
|
67
|
|
|
|
|
127
|
my $data = shift; |
|
9364
|
|
|
|
|
|
|
|
|
9365
|
|
|
|
|
|
|
# Remove equality from formula. |
|
9366
|
67
|
|
|
|
|
158
|
$data =~ s/^=//; |
|
9367
|
|
|
|
|
|
|
|
|
9368
|
67
|
|
|
|
|
316
|
$self->xml_data_element( 'formula', $data ); |
|
9369
|
|
|
|
|
|
|
} |
|
9370
|
|
|
|
|
|
|
|
|
9371
|
|
|
|
|
|
|
|
|
9372
|
|
|
|
|
|
|
############################################################################## |
|
9373
|
|
|
|
|
|
|
# |
|
9374
|
|
|
|
|
|
|
# _write_color_scale() |
|
9375
|
|
|
|
|
|
|
# |
|
9376
|
|
|
|
|
|
|
# Write the element. |
|
9377
|
|
|
|
|
|
|
# |
|
9378
|
|
|
|
|
|
|
sub _write_color_scale { |
|
9379
|
|
|
|
|
|
|
|
|
9380
|
5
|
|
|
5
|
|
19
|
my $self = shift; |
|
9381
|
5
|
|
|
|
|
10
|
my $param = shift; |
|
9382
|
|
|
|
|
|
|
|
|
9383
|
5
|
|
|
|
|
18
|
$self->xml_start_tag( 'colorScale' ); |
|
9384
|
|
|
|
|
|
|
|
|
9385
|
5
|
|
|
|
|
28
|
$self->_write_cfvo( $param->{min_type}, $param->{min_value} ); |
|
9386
|
|
|
|
|
|
|
|
|
9387
|
5
|
100
|
|
|
|
23
|
if ( defined $param->{mid_type} ) { |
|
9388
|
4
|
|
|
|
|
13
|
$self->_write_cfvo( $param->{mid_type}, $param->{mid_value} ); |
|
9389
|
|
|
|
|
|
|
} |
|
9390
|
|
|
|
|
|
|
|
|
9391
|
5
|
|
|
|
|
28
|
$self->_write_cfvo( $param->{max_type}, $param->{max_value} ); |
|
9392
|
|
|
|
|
|
|
|
|
9393
|
5
|
|
|
|
|
27
|
$self->_write_color( 'rgb' => $param->{min_color} ); |
|
9394
|
|
|
|
|
|
|
|
|
9395
|
5
|
100
|
|
|
|
20
|
if ( defined $param->{mid_color} ) { |
|
9396
|
4
|
|
|
|
|
20
|
$self->_write_color( 'rgb' => $param->{mid_color} ); |
|
9397
|
|
|
|
|
|
|
} |
|
9398
|
|
|
|
|
|
|
|
|
9399
|
5
|
|
|
|
|
27
|
$self->_write_color( 'rgb' => $param->{max_color} ); |
|
9400
|
|
|
|
|
|
|
|
|
9401
|
5
|
|
|
|
|
21
|
$self->xml_end_tag( 'colorScale' ); |
|
9402
|
|
|
|
|
|
|
} |
|
9403
|
|
|
|
|
|
|
|
|
9404
|
|
|
|
|
|
|
|
|
9405
|
|
|
|
|
|
|
############################################################################## |
|
9406
|
|
|
|
|
|
|
# |
|
9407
|
|
|
|
|
|
|
# _write_data_bar() |
|
9408
|
|
|
|
|
|
|
# |
|
9409
|
|
|
|
|
|
|
# Write the element. |
|
9410
|
|
|
|
|
|
|
# |
|
9411
|
|
|
|
|
|
|
sub _write_data_bar { |
|
9412
|
|
|
|
|
|
|
|
|
9413
|
29
|
|
|
29
|
|
68
|
my $self = shift; |
|
9414
|
29
|
|
|
|
|
56
|
my $data_bar = shift; |
|
9415
|
29
|
|
|
|
|
58
|
my @attributes = (); |
|
9416
|
|
|
|
|
|
|
|
|
9417
|
29
|
100
|
|
|
|
110
|
if ( $data_bar->{bar_only} ) { |
|
9418
|
2
|
|
|
|
|
6
|
push @attributes, ( 'showValue', 0 ); |
|
9419
|
|
|
|
|
|
|
} |
|
9420
|
|
|
|
|
|
|
|
|
9421
|
29
|
|
|
|
|
129
|
$self->xml_start_tag( 'dataBar', @attributes ); |
|
9422
|
|
|
|
|
|
|
|
|
9423
|
29
|
|
|
|
|
132
|
$self->_write_cfvo( $data_bar->{min_type}, $data_bar->{min_value} ); |
|
9424
|
29
|
|
|
|
|
116
|
$self->_write_cfvo( $data_bar->{max_type}, $data_bar->{max_value} ); |
|
9425
|
|
|
|
|
|
|
|
|
9426
|
29
|
|
|
|
|
124
|
$self->_write_color( 'rgb' => $data_bar->{bar_color} ); |
|
9427
|
|
|
|
|
|
|
|
|
9428
|
29
|
|
|
|
|
104
|
$self->xml_end_tag( 'dataBar' ); |
|
9429
|
|
|
|
|
|
|
} |
|
9430
|
|
|
|
|
|
|
|
|
9431
|
|
|
|
|
|
|
|
|
9432
|
|
|
|
|
|
|
############################################################################## |
|
9433
|
|
|
|
|
|
|
# |
|
9434
|
|
|
|
|
|
|
# _write_data_bar_ext() |
|
9435
|
|
|
|
|
|
|
# |
|
9436
|
|
|
|
|
|
|
# Write the dataBar extension element. |
|
9437
|
|
|
|
|
|
|
# |
|
9438
|
|
|
|
|
|
|
sub _write_data_bar_ext { |
|
9439
|
|
|
|
|
|
|
|
|
9440
|
25
|
|
|
25
|
|
60
|
my $self = shift; |
|
9441
|
25
|
|
|
|
|
39
|
my $param = shift; |
|
9442
|
|
|
|
|
|
|
|
|
9443
|
|
|
|
|
|
|
# Create a pseudo GUID for each unique Excel 2010 data bar. |
|
9444
|
25
|
|
|
|
|
57
|
my $worksheet_count = $self->{_index} + 1; |
|
9445
|
25
|
|
|
|
|
41
|
my $data_bar_count = @{ $self->{_data_bars_2010} } + 1; |
|
|
25
|
|
|
|
|
67
|
|
|
9446
|
|
|
|
|
|
|
|
|
9447
|
25
|
|
|
|
|
139
|
my $guid = sprintf "{DA7ABA51-AAAA-BBBB-%04X-%012X}", $worksheet_count, |
|
9448
|
|
|
|
|
|
|
$data_bar_count; |
|
9449
|
|
|
|
|
|
|
|
|
9450
|
|
|
|
|
|
|
# Store the 2010 data bar parameters to write the extLst elements. |
|
9451
|
25
|
|
|
|
|
65
|
$param->{_guid} = $guid; |
|
9452
|
25
|
|
|
|
|
60
|
push @{$self->{_data_bars_2010}}, $param; |
|
|
25
|
|
|
|
|
59
|
|
|
9453
|
|
|
|
|
|
|
|
|
9454
|
25
|
|
|
|
|
94
|
$self->xml_start_tag( 'extLst' ); |
|
9455
|
25
|
|
|
|
|
103
|
$self->_write_ext('{B025F937-C7B1-47D3-B67F-A62EFF666E3E}'); |
|
9456
|
|
|
|
|
|
|
|
|
9457
|
25
|
|
|
|
|
162
|
$self->xml_data_element( 'x14:id', $guid); |
|
9458
|
|
|
|
|
|
|
|
|
9459
|
25
|
|
|
|
|
86
|
$self->xml_end_tag( 'ext' ); |
|
9460
|
25
|
|
|
|
|
70
|
$self->xml_end_tag( 'extLst' ); |
|
9461
|
|
|
|
|
|
|
} |
|
9462
|
|
|
|
|
|
|
|
|
9463
|
|
|
|
|
|
|
|
|
9464
|
|
|
|
|
|
|
############################################################################## |
|
9465
|
|
|
|
|
|
|
# |
|
9466
|
|
|
|
|
|
|
# _write_cfvo() |
|
9467
|
|
|
|
|
|
|
# |
|
9468
|
|
|
|
|
|
|
# Write the element. |
|
9469
|
|
|
|
|
|
|
# |
|
9470
|
|
|
|
|
|
|
sub _write_cfvo { |
|
9471
|
|
|
|
|
|
|
|
|
9472
|
210
|
|
|
210
|
|
319
|
my $self = shift; |
|
9473
|
210
|
|
|
|
|
379
|
my $type = shift; |
|
9474
|
210
|
|
|
|
|
295
|
my $value = shift; |
|
9475
|
210
|
|
|
|
|
285
|
my $criteria = shift; |
|
9476
|
|
|
|
|
|
|
|
|
9477
|
210
|
|
|
|
|
412
|
my @attributes = ( 'type' => $type ); |
|
9478
|
|
|
|
|
|
|
|
|
9479
|
210
|
100
|
|
|
|
468
|
if ( defined $value ) { |
|
9480
|
169
|
|
|
|
|
312
|
push @attributes, ( 'val', $value ); |
|
9481
|
|
|
|
|
|
|
} |
|
9482
|
|
|
|
|
|
|
|
|
9483
|
210
|
100
|
|
|
|
401
|
if ( $criteria ) { |
|
9484
|
7
|
|
|
|
|
17
|
push @attributes, ( 'gte', 0 ); |
|
9485
|
|
|
|
|
|
|
} |
|
9486
|
|
|
|
|
|
|
|
|
9487
|
210
|
|
|
|
|
500
|
$self->xml_empty_tag( 'cfvo', @attributes ); |
|
9488
|
|
|
|
|
|
|
} |
|
9489
|
|
|
|
|
|
|
|
|
9490
|
|
|
|
|
|
|
|
|
9491
|
|
|
|
|
|
|
############################################################################## |
|
9492
|
|
|
|
|
|
|
# |
|
9493
|
|
|
|
|
|
|
# _write_x14_cfvo() |
|
9494
|
|
|
|
|
|
|
# |
|
9495
|
|
|
|
|
|
|
# Write the element. |
|
9496
|
|
|
|
|
|
|
# |
|
9497
|
|
|
|
|
|
|
sub _write_x14_cfvo { |
|
9498
|
|
|
|
|
|
|
|
|
9499
|
50
|
|
|
50
|
|
81
|
my $self = shift; |
|
9500
|
50
|
|
|
|
|
85
|
my $type = shift; |
|
9501
|
50
|
|
|
|
|
86
|
my $value = shift; |
|
9502
|
|
|
|
|
|
|
|
|
9503
|
50
|
|
|
|
|
110
|
my @attributes = ( 'type' => $type ); |
|
9504
|
|
|
|
|
|
|
|
|
9505
|
50
|
100
|
100
|
|
|
332
|
if ( $type eq 'min' |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
9506
|
|
|
|
|
|
|
|| $type eq 'max' |
|
9507
|
|
|
|
|
|
|
|| $type eq 'autoMin' |
|
9508
|
|
|
|
|
|
|
|| $type eq 'autoMax' ) |
|
9509
|
|
|
|
|
|
|
{ |
|
9510
|
41
|
|
|
|
|
114
|
$self->xml_empty_tag( 'x14:cfvo', @attributes ); |
|
9511
|
|
|
|
|
|
|
} |
|
9512
|
|
|
|
|
|
|
else { |
|
9513
|
9
|
|
|
|
|
29
|
$self->xml_start_tag( 'x14:cfvo', @attributes ); |
|
9514
|
9
|
|
|
|
|
29
|
$self->xml_data_element( 'xm:f', $value ); |
|
9515
|
9
|
|
|
|
|
23
|
$self->xml_end_tag( 'x14:cfvo' ); |
|
9516
|
|
|
|
|
|
|
} |
|
9517
|
|
|
|
|
|
|
} |
|
9518
|
|
|
|
|
|
|
|
|
9519
|
|
|
|
|
|
|
|
|
9520
|
|
|
|
|
|
|
############################################################################## |
|
9521
|
|
|
|
|
|
|
# |
|
9522
|
|
|
|
|
|
|
# _write_color() |
|
9523
|
|
|
|
|
|
|
# |
|
9524
|
|
|
|
|
|
|
# Write the element. |
|
9525
|
|
|
|
|
|
|
# |
|
9526
|
|
|
|
|
|
|
sub _write_color { |
|
9527
|
|
|
|
|
|
|
|
|
9528
|
43
|
|
|
43
|
|
81
|
my $self = shift; |
|
9529
|
43
|
|
|
|
|
91
|
my $name = shift; |
|
9530
|
43
|
|
|
|
|
74
|
my $value = shift; |
|
9531
|
|
|
|
|
|
|
|
|
9532
|
43
|
|
|
|
|
110
|
my @attributes = ( $name => $value ); |
|
9533
|
|
|
|
|
|
|
|
|
9534
|
43
|
|
|
|
|
134
|
$self->xml_empty_tag( 'color', @attributes ); |
|
9535
|
|
|
|
|
|
|
} |
|
9536
|
|
|
|
|
|
|
|
|
9537
|
|
|
|
|
|
|
|
|
9538
|
|
|
|
|
|
|
############################################################################## |
|
9539
|
|
|
|
|
|
|
# |
|
9540
|
|
|
|
|
|
|
# _write_table_parts() |
|
9541
|
|
|
|
|
|
|
# |
|
9542
|
|
|
|
|
|
|
# Write the element. |
|
9543
|
|
|
|
|
|
|
# |
|
9544
|
|
|
|
|
|
|
sub _write_table_parts { |
|
9545
|
|
|
|
|
|
|
|
|
9546
|
993
|
|
|
993
|
|
2520
|
my $self = shift; |
|
9547
|
993
|
|
|
|
|
2351
|
my @tables = @{ $self->{_tables} }; |
|
|
993
|
|
|
|
|
3408
|
|
|
9548
|
993
|
|
|
|
|
2608
|
my $count = scalar @tables; |
|
9549
|
|
|
|
|
|
|
|
|
9550
|
|
|
|
|
|
|
# Return if worksheet doesn't contain any tables. |
|
9551
|
993
|
100
|
|
|
|
3687
|
return unless $count; |
|
9552
|
|
|
|
|
|
|
|
|
9553
|
27
|
|
|
|
|
119
|
my @attributes = ( 'count' => $count, ); |
|
9554
|
|
|
|
|
|
|
|
|
9555
|
27
|
|
|
|
|
131
|
$self->xml_start_tag( 'tableParts', @attributes ); |
|
9556
|
|
|
|
|
|
|
|
|
9557
|
27
|
|
|
|
|
95
|
for my $table ( @tables ) { |
|
9558
|
|
|
|
|
|
|
|
|
9559
|
|
|
|
|
|
|
# Write the tablePart element. |
|
9560
|
35
|
|
|
|
|
143
|
$self->_write_table_part( ++$self->{_rel_count} ); |
|
9561
|
|
|
|
|
|
|
|
|
9562
|
|
|
|
|
|
|
} |
|
9563
|
|
|
|
|
|
|
|
|
9564
|
27
|
|
|
|
|
113
|
$self->xml_end_tag( 'tableParts' ); |
|
9565
|
|
|
|
|
|
|
} |
|
9566
|
|
|
|
|
|
|
|
|
9567
|
|
|
|
|
|
|
|
|
9568
|
|
|
|
|
|
|
############################################################################## |
|
9569
|
|
|
|
|
|
|
# |
|
9570
|
|
|
|
|
|
|
# _write_table_part() |
|
9571
|
|
|
|
|
|
|
# |
|
9572
|
|
|
|
|
|
|
# Write the element. |
|
9573
|
|
|
|
|
|
|
# |
|
9574
|
|
|
|
|
|
|
sub _write_table_part { |
|
9575
|
|
|
|
|
|
|
|
|
9576
|
35
|
|
|
35
|
|
75
|
my $self = shift; |
|
9577
|
35
|
|
|
|
|
76
|
my $id = shift; |
|
9578
|
35
|
|
|
|
|
98
|
my $r_id = 'rId' . $id; |
|
9579
|
|
|
|
|
|
|
|
|
9580
|
35
|
|
|
|
|
127
|
my @attributes = ( 'r:id' => $r_id, ); |
|
9581
|
|
|
|
|
|
|
|
|
9582
|
35
|
|
|
|
|
127
|
$self->xml_empty_tag( 'tablePart', @attributes ); |
|
9583
|
|
|
|
|
|
|
} |
|
9584
|
|
|
|
|
|
|
|
|
9585
|
|
|
|
|
|
|
|
|
9586
|
|
|
|
|
|
|
############################################################################## |
|
9587
|
|
|
|
|
|
|
# |
|
9588
|
|
|
|
|
|
|
# _write_ext_list() |
|
9589
|
|
|
|
|
|
|
# |
|
9590
|
|
|
|
|
|
|
# Write the element for data bars and sparklines. |
|
9591
|
|
|
|
|
|
|
# |
|
9592
|
|
|
|
|
|
|
sub _write_ext_list { |
|
9593
|
|
|
|
|
|
|
|
|
9594
|
993
|
|
|
993
|
|
2475
|
my $self = shift; |
|
9595
|
993
|
|
|
|
|
2118
|
my $has_data_bars = scalar @{ $self->{_data_bars_2010} }; |
|
|
993
|
|
|
|
|
3166
|
|
|
9596
|
993
|
|
|
|
|
2124
|
my $has_sparklines = scalar @{ $self->{_sparklines} }; |
|
|
993
|
|
|
|
|
2637
|
|
|
9597
|
|
|
|
|
|
|
|
|
9598
|
993
|
100
|
100
|
|
|
6921
|
if ( !$has_data_bars and !$has_sparklines ) { |
|
9599
|
971
|
|
|
|
|
3678
|
return; |
|
9600
|
|
|
|
|
|
|
} |
|
9601
|
|
|
|
|
|
|
|
|
9602
|
|
|
|
|
|
|
# Write the extLst element. |
|
9603
|
22
|
|
|
|
|
104
|
$self->xml_start_tag( 'extLst' ); |
|
9604
|
|
|
|
|
|
|
|
|
9605
|
22
|
100
|
|
|
|
83
|
if ( $has_data_bars ) { |
|
9606
|
11
|
|
|
|
|
52
|
$self->_write_ext_list_data_bars(); |
|
9607
|
|
|
|
|
|
|
} |
|
9608
|
|
|
|
|
|
|
|
|
9609
|
22
|
100
|
|
|
|
112
|
if ( $has_sparklines ) { |
|
9610
|
12
|
|
|
|
|
52
|
$self->_write_ext_list_sparklines(); |
|
9611
|
|
|
|
|
|
|
} |
|
9612
|
|
|
|
|
|
|
|
|
9613
|
22
|
|
|
|
|
257
|
$self->xml_end_tag( 'extLst' ); |
|
9614
|
|
|
|
|
|
|
} |
|
9615
|
|
|
|
|
|
|
|
|
9616
|
|
|
|
|
|
|
|
|
9617
|
|
|
|
|
|
|
############################################################################## |
|
9618
|
|
|
|
|
|
|
# |
|
9619
|
|
|
|
|
|
|
# _write_ext_list_data_bars() |
|
9620
|
|
|
|
|
|
|
# |
|
9621
|
|
|
|
|
|
|
# Write the Excel 2010 data_bar subelements. |
|
9622
|
|
|
|
|
|
|
# |
|
9623
|
|
|
|
|
|
|
sub _write_ext_list_data_bars { |
|
9624
|
|
|
|
|
|
|
|
|
9625
|
11
|
|
|
11
|
|
35
|
my $self = shift; |
|
9626
|
11
|
|
|
|
|
20
|
my @data_bars = @{ $self->{_data_bars_2010} }; |
|
|
11
|
|
|
|
|
49
|
|
|
9627
|
|
|
|
|
|
|
|
|
9628
|
|
|
|
|
|
|
# Write the ext element. |
|
9629
|
11
|
|
|
|
|
51
|
$self->_write_ext('{78C0D931-6437-407d-A8EE-F0AAD7539E65}'); |
|
9630
|
|
|
|
|
|
|
|
|
9631
|
|
|
|
|
|
|
|
|
9632
|
11
|
|
|
|
|
49
|
$self->xml_start_tag( 'x14:conditionalFormattings' ); |
|
9633
|
|
|
|
|
|
|
|
|
9634
|
|
|
|
|
|
|
# Write each of the Excel 2010 conditional formatting data bar elements. |
|
9635
|
11
|
|
|
|
|
39
|
for my $data_bar (@data_bars) { |
|
9636
|
|
|
|
|
|
|
|
|
9637
|
|
|
|
|
|
|
# Write the x14:conditionalFormatting element. |
|
9638
|
25
|
|
|
|
|
78
|
$self->_write_conditional_formatting_2010($data_bar); |
|
9639
|
|
|
|
|
|
|
} |
|
9640
|
|
|
|
|
|
|
|
|
9641
|
11
|
|
|
|
|
69
|
$self->xml_end_tag( 'x14:conditionalFormattings' ); |
|
9642
|
11
|
|
|
|
|
41
|
$self->xml_end_tag( 'ext' ); |
|
9643
|
|
|
|
|
|
|
|
|
9644
|
|
|
|
|
|
|
|
|
9645
|
|
|
|
|
|
|
} |
|
9646
|
|
|
|
|
|
|
|
|
9647
|
|
|
|
|
|
|
|
|
9648
|
|
|
|
|
|
|
############################################################################## |
|
9649
|
|
|
|
|
|
|
# |
|
9650
|
|
|
|
|
|
|
# _write_conditional_formatting() |
|
9651
|
|
|
|
|
|
|
# |
|
9652
|
|
|
|
|
|
|
# Write the element. |
|
9653
|
|
|
|
|
|
|
# |
|
9654
|
|
|
|
|
|
|
sub _write_conditional_formatting_2010 { |
|
9655
|
|
|
|
|
|
|
|
|
9656
|
25
|
|
|
25
|
|
53
|
my $self = shift; |
|
9657
|
25
|
|
|
|
|
53
|
my $data_bar = shift; |
|
9658
|
25
|
|
|
|
|
45
|
my $xmlns_xm = 'http://schemas.microsoft.com/office/excel/2006/main'; |
|
9659
|
|
|
|
|
|
|
|
|
9660
|
25
|
|
|
|
|
58
|
my @attributes = ( 'xmlns:xm' => $xmlns_xm ); |
|
9661
|
|
|
|
|
|
|
|
|
9662
|
25
|
|
|
|
|
96
|
$self->xml_start_tag( 'x14:conditionalFormatting', @attributes ); |
|
9663
|
|
|
|
|
|
|
|
|
9664
|
|
|
|
|
|
|
# Write the '
|
|
9665
|
25
|
|
|
|
|
126
|
$self->_write_x14_cf_rule( $data_bar ); |
|
9666
|
|
|
|
|
|
|
|
|
9667
|
|
|
|
|
|
|
# Write the x14:dataBar element. |
|
9668
|
25
|
|
|
|
|
114
|
$self->_write_x14_data_bar( $data_bar ); |
|
9669
|
|
|
|
|
|
|
|
|
9670
|
|
|
|
|
|
|
# Write the x14 max and min data bars. |
|
9671
|
|
|
|
|
|
|
$self->_write_x14_cfvo( $data_bar->{_x14_min_type}, |
|
9672
|
25
|
|
|
|
|
105
|
$data_bar->{min_value} ); |
|
9673
|
|
|
|
|
|
|
|
|
9674
|
|
|
|
|
|
|
$self->_write_x14_cfvo( $data_bar->{_x14_max_type}, |
|
9675
|
25
|
|
|
|
|
107
|
$data_bar->{max_value} ); |
|
9676
|
|
|
|
|
|
|
|
|
9677
|
|
|
|
|
|
|
# Write the x14:borderColor element. |
|
9678
|
25
|
100
|
|
|
|
84
|
if ( !$data_bar->{bar_no_border} ) { |
|
9679
|
24
|
|
|
|
|
94
|
$self->_write_x14_border_color( $data_bar->{bar_border_color} ); |
|
9680
|
|
|
|
|
|
|
} |
|
9681
|
|
|
|
|
|
|
|
|
9682
|
|
|
|
|
|
|
# Write the x14:negativeFillColor element. |
|
9683
|
25
|
100
|
|
|
|
91
|
if ( !$data_bar->{bar_negative_color_same} ) { |
|
9684
|
|
|
|
|
|
|
$self->_write_x14_negative_fill_color( |
|
9685
|
24
|
|
|
|
|
128
|
$data_bar->{bar_negative_color} ); |
|
9686
|
|
|
|
|
|
|
} |
|
9687
|
|
|
|
|
|
|
|
|
9688
|
|
|
|
|
|
|
# Write the x14:negativeBorderColor element. |
|
9689
|
25
|
100
|
100
|
|
|
164
|
if ( !$data_bar->{bar_no_border} |
|
9690
|
|
|
|
|
|
|
&& !$data_bar->{bar_negative_border_color_same} ) |
|
9691
|
|
|
|
|
|
|
{ |
|
9692
|
|
|
|
|
|
|
$self->_write_x14_negative_border_color( |
|
9693
|
23
|
|
|
|
|
82
|
$data_bar->{bar_negative_border_color} ); |
|
9694
|
|
|
|
|
|
|
} |
|
9695
|
|
|
|
|
|
|
|
|
9696
|
|
|
|
|
|
|
# Write the x14:axisColor element. |
|
9697
|
25
|
100
|
|
|
|
102
|
if ( $data_bar->{bar_axis_position} ne 'none') { |
|
9698
|
24
|
|
|
|
|
75
|
$self->_write_x14_axis_color($data_bar->{bar_axis_color}); |
|
9699
|
|
|
|
|
|
|
} |
|
9700
|
|
|
|
|
|
|
|
|
9701
|
|
|
|
|
|
|
# Write closing elements. |
|
9702
|
25
|
|
|
|
|
141
|
$self->xml_end_tag( 'x14:dataBar' ); |
|
9703
|
25
|
|
|
|
|
84
|
$self->xml_end_tag( 'x14:cfRule' ); |
|
9704
|
|
|
|
|
|
|
|
|
9705
|
|
|
|
|
|
|
# Add the conditional format range. |
|
9706
|
25
|
|
|
|
|
241
|
$self->xml_data_element( 'xm:sqref', $data_bar->{_range} ); |
|
9707
|
|
|
|
|
|
|
|
|
9708
|
25
|
|
|
|
|
84
|
$self->xml_end_tag( 'x14:conditionalFormatting' ); |
|
9709
|
|
|
|
|
|
|
} |
|
9710
|
|
|
|
|
|
|
|
|
9711
|
|
|
|
|
|
|
|
|
9712
|
|
|
|
|
|
|
############################################################################## |
|
9713
|
|
|
|
|
|
|
# |
|
9714
|
|
|
|
|
|
|
# _write_x14_cf_rule() |
|
9715
|
|
|
|
|
|
|
# |
|
9716
|
|
|
|
|
|
|
# Write the <' element. |
|
9717
|
|
|
|
|
|
|
# |
|
9718
|
|
|
|
|
|
|
sub _write_x14_cf_rule { |
|
9719
|
|
|
|
|
|
|
|
|
9720
|
25
|
|
|
25
|
|
58
|
my $self = shift; |
|
9721
|
25
|
|
|
|
|
42
|
my $data_bar = shift; |
|
9722
|
25
|
|
|
|
|
46
|
my $type = 'dataBar'; |
|
9723
|
25
|
|
|
|
|
65
|
my $id = $data_bar->{_guid}; |
|
9724
|
|
|
|
|
|
|
|
|
9725
|
25
|
|
|
|
|
81
|
my @attributes = ( |
|
9726
|
|
|
|
|
|
|
'type' => $type, |
|
9727
|
|
|
|
|
|
|
'id' => $id, |
|
9728
|
|
|
|
|
|
|
); |
|
9729
|
|
|
|
|
|
|
|
|
9730
|
25
|
|
|
|
|
75
|
$self->xml_start_tag( 'x14:cfRule', @attributes ); |
|
9731
|
|
|
|
|
|
|
|
|
9732
|
|
|
|
|
|
|
} |
|
9733
|
|
|
|
|
|
|
|
|
9734
|
|
|
|
|
|
|
|
|
9735
|
|
|
|
|
|
|
############################################################################## |
|
9736
|
|
|
|
|
|
|
# |
|
9737
|
|
|
|
|
|
|
# _write_x14_data_bar() |
|
9738
|
|
|
|
|
|
|
# |
|
9739
|
|
|
|
|
|
|
# Write the element. |
|
9740
|
|
|
|
|
|
|
# |
|
9741
|
|
|
|
|
|
|
sub _write_x14_data_bar { |
|
9742
|
|
|
|
|
|
|
|
|
9743
|
25
|
|
|
25
|
|
51
|
my $self = shift; |
|
9744
|
25
|
|
|
|
|
49
|
my $data_bar = shift; |
|
9745
|
25
|
|
|
|
|
47
|
my $min_length = 0; |
|
9746
|
25
|
|
|
|
|
41
|
my $max_length = 100; |
|
9747
|
|
|
|
|
|
|
|
|
9748
|
25
|
|
|
|
|
69
|
my @attributes = ( |
|
9749
|
|
|
|
|
|
|
'minLength' => $min_length, |
|
9750
|
|
|
|
|
|
|
'maxLength' => $max_length, |
|
9751
|
|
|
|
|
|
|
); |
|
9752
|
|
|
|
|
|
|
|
|
9753
|
25
|
100
|
|
|
|
70
|
if ( !$data_bar->{bar_no_border} ) { |
|
9754
|
24
|
|
|
|
|
66
|
push @attributes, ( 'border', 1 ); |
|
9755
|
|
|
|
|
|
|
} |
|
9756
|
|
|
|
|
|
|
|
|
9757
|
25
|
100
|
|
|
|
78
|
if ( $data_bar->{bar_solid} ) { |
|
9758
|
1
|
|
|
|
|
3
|
push @attributes, ( 'gradient', 0 ); |
|
9759
|
|
|
|
|
|
|
} |
|
9760
|
|
|
|
|
|
|
|
|
9761
|
25
|
100
|
|
|
|
88
|
if ( $data_bar->{bar_direction} eq 'left' ) { |
|
9762
|
1
|
|
|
|
|
3
|
push @attributes, ( 'direction', 'leftToRight' ); |
|
9763
|
|
|
|
|
|
|
} |
|
9764
|
|
|
|
|
|
|
|
|
9765
|
25
|
100
|
|
|
|
127
|
if ( $data_bar->{bar_direction} eq 'right' ) { |
|
9766
|
1
|
|
|
|
|
2
|
push @attributes, ( 'direction', 'rightToLeft' ); |
|
9767
|
|
|
|
|
|
|
} |
|
9768
|
|
|
|
|
|
|
|
|
9769
|
25
|
100
|
|
|
|
86
|
if ( $data_bar->{bar_negative_color_same} ) { |
|
9770
|
1
|
|
|
|
|
3
|
push @attributes, ( 'negativeBarColorSameAsPositive', 1 ); |
|
9771
|
|
|
|
|
|
|
} |
|
9772
|
|
|
|
|
|
|
|
|
9773
|
25
|
100
|
100
|
|
|
133
|
if ( !$data_bar->{bar_no_border} |
|
9774
|
|
|
|
|
|
|
&& !$data_bar->{bar_negative_border_color_same} ) |
|
9775
|
|
|
|
|
|
|
{ |
|
9776
|
23
|
|
|
|
|
67
|
push @attributes, ( 'negativeBarBorderColorSameAsPositive', 0 ); |
|
9777
|
|
|
|
|
|
|
} |
|
9778
|
|
|
|
|
|
|
|
|
9779
|
25
|
100
|
|
|
|
83
|
if ( $data_bar->{bar_axis_position} eq 'middle') { |
|
9780
|
1
|
|
|
|
|
3
|
push @attributes, ( 'axisPosition', 'middle' ); |
|
9781
|
|
|
|
|
|
|
} |
|
9782
|
|
|
|
|
|
|
|
|
9783
|
25
|
100
|
|
|
|
150
|
if ( $data_bar->{bar_axis_position} eq 'none') { |
|
9784
|
1
|
|
|
|
|
3
|
push @attributes, ( 'axisPosition', 'none' ); |
|
9785
|
|
|
|
|
|
|
} |
|
9786
|
|
|
|
|
|
|
|
|
9787
|
25
|
|
|
|
|
89
|
$self->xml_start_tag( 'x14:dataBar', @attributes ); |
|
9788
|
|
|
|
|
|
|
} |
|
9789
|
|
|
|
|
|
|
|
|
9790
|
|
|
|
|
|
|
|
|
9791
|
|
|
|
|
|
|
############################################################################## |
|
9792
|
|
|
|
|
|
|
# |
|
9793
|
|
|
|
|
|
|
# _write_x14_border_color() |
|
9794
|
|
|
|
|
|
|
# |
|
9795
|
|
|
|
|
|
|
# Write the element. |
|
9796
|
|
|
|
|
|
|
# |
|
9797
|
|
|
|
|
|
|
sub _write_x14_border_color { |
|
9798
|
|
|
|
|
|
|
|
|
9799
|
24
|
|
|
24
|
|
61
|
my $self = shift; |
|
9800
|
24
|
|
|
|
|
55
|
my $rgb = shift; |
|
9801
|
|
|
|
|
|
|
|
|
9802
|
24
|
|
|
|
|
62
|
my @attributes = ( 'rgb' => $rgb ); |
|
9803
|
|
|
|
|
|
|
|
|
9804
|
24
|
|
|
|
|
100
|
$self->xml_empty_tag( 'x14:borderColor', @attributes ); |
|
9805
|
|
|
|
|
|
|
} |
|
9806
|
|
|
|
|
|
|
|
|
9807
|
|
|
|
|
|
|
|
|
9808
|
|
|
|
|
|
|
############################################################################## |
|
9809
|
|
|
|
|
|
|
# |
|
9810
|
|
|
|
|
|
|
# _write_x14_negative_fill_color() |
|
9811
|
|
|
|
|
|
|
# |
|
9812
|
|
|
|
|
|
|
# Write the element. |
|
9813
|
|
|
|
|
|
|
# |
|
9814
|
|
|
|
|
|
|
sub _write_x14_negative_fill_color { |
|
9815
|
|
|
|
|
|
|
|
|
9816
|
24
|
|
|
24
|
|
53
|
my $self = shift; |
|
9817
|
24
|
|
|
|
|
43
|
my $rgb = shift; |
|
9818
|
|
|
|
|
|
|
|
|
9819
|
24
|
|
|
|
|
61
|
my @attributes = ( 'rgb' => $rgb ); |
|
9820
|
|
|
|
|
|
|
|
|
9821
|
24
|
|
|
|
|
82
|
$self->xml_empty_tag( 'x14:negativeFillColor', @attributes ); |
|
9822
|
|
|
|
|
|
|
} |
|
9823
|
|
|
|
|
|
|
|
|
9824
|
|
|
|
|
|
|
|
|
9825
|
|
|
|
|
|
|
############################################################################## |
|
9826
|
|
|
|
|
|
|
# |
|
9827
|
|
|
|
|
|
|
# _write_x14_negative_border_color() |
|
9828
|
|
|
|
|
|
|
# |
|
9829
|
|
|
|
|
|
|
# Write the element. |
|
9830
|
|
|
|
|
|
|
# |
|
9831
|
|
|
|
|
|
|
sub _write_x14_negative_border_color { |
|
9832
|
|
|
|
|
|
|
|
|
9833
|
23
|
|
|
23
|
|
43
|
my $self = shift; |
|
9834
|
23
|
|
|
|
|
42
|
my $rgb = shift; |
|
9835
|
|
|
|
|
|
|
|
|
9836
|
23
|
|
|
|
|
58
|
my @attributes = ( 'rgb' => $rgb ); |
|
9837
|
|
|
|
|
|
|
|
|
9838
|
23
|
|
|
|
|
84
|
$self->xml_empty_tag( 'x14:negativeBorderColor', @attributes ); |
|
9839
|
|
|
|
|
|
|
} |
|
9840
|
|
|
|
|
|
|
|
|
9841
|
|
|
|
|
|
|
|
|
9842
|
|
|
|
|
|
|
############################################################################## |
|
9843
|
|
|
|
|
|
|
# |
|
9844
|
|
|
|
|
|
|
# _write_x14_axis_color() |
|
9845
|
|
|
|
|
|
|
# |
|
9846
|
|
|
|
|
|
|
# Write the element. |
|
9847
|
|
|
|
|
|
|
# |
|
9848
|
|
|
|
|
|
|
sub _write_x14_axis_color { |
|
9849
|
|
|
|
|
|
|
|
|
9850
|
24
|
|
|
24
|
|
49
|
my $self = shift; |
|
9851
|
24
|
|
|
|
|
41
|
my $rgb = shift; |
|
9852
|
|
|
|
|
|
|
|
|
9853
|
24
|
|
|
|
|
54
|
my @attributes = ( 'rgb' => $rgb ); |
|
9854
|
|
|
|
|
|
|
|
|
9855
|
24
|
|
|
|
|
92
|
$self->xml_empty_tag( 'x14:axisColor', @attributes ); |
|
9856
|
|
|
|
|
|
|
} |
|
9857
|
|
|
|
|
|
|
|
|
9858
|
|
|
|
|
|
|
|
|
9859
|
|
|
|
|
|
|
############################################################################## |
|
9860
|
|
|
|
|
|
|
# |
|
9861
|
|
|
|
|
|
|
# _write_ext_list_sparklines() |
|
9862
|
|
|
|
|
|
|
# |
|
9863
|
|
|
|
|
|
|
# Write the sparkline subelements. |
|
9864
|
|
|
|
|
|
|
# |
|
9865
|
|
|
|
|
|
|
sub _write_ext_list_sparklines { |
|
9866
|
|
|
|
|
|
|
|
|
9867
|
12
|
|
|
12
|
|
29
|
my $self = shift; |
|
9868
|
12
|
|
|
|
|
21
|
my @sparklines = @{ $self->{_sparklines} }; |
|
|
12
|
|
|
|
|
41
|
|
|
9869
|
12
|
|
|
|
|
27
|
my $count = scalar @sparklines; |
|
9870
|
|
|
|
|
|
|
|
|
9871
|
|
|
|
|
|
|
# Write the ext element. |
|
9872
|
12
|
|
|
|
|
57
|
$self->_write_ext('{05C60535-1F16-4fd2-B633-F4F36F0B64E0}'); |
|
9873
|
|
|
|
|
|
|
|
|
9874
|
|
|
|
|
|
|
# Write the x14:sparklineGroups element. |
|
9875
|
12
|
|
|
|
|
55
|
$self->_write_sparkline_groups(); |
|
9876
|
|
|
|
|
|
|
|
|
9877
|
|
|
|
|
|
|
# Write the sparkline elements. |
|
9878
|
12
|
|
|
|
|
39
|
for my $sparkline ( reverse @sparklines ) { |
|
9879
|
|
|
|
|
|
|
|
|
9880
|
|
|
|
|
|
|
# Write the x14:sparklineGroup element. |
|
9881
|
58
|
|
|
|
|
173
|
$self->_write_sparkline_group( $sparkline ); |
|
9882
|
|
|
|
|
|
|
|
|
9883
|
|
|
|
|
|
|
# Write the x14:colorSeries element. |
|
9884
|
58
|
|
|
|
|
219
|
$self->_write_color_series( $sparkline->{_series_color} ); |
|
9885
|
|
|
|
|
|
|
|
|
9886
|
|
|
|
|
|
|
# Write the x14:colorNegative element. |
|
9887
|
58
|
|
|
|
|
184
|
$self->_write_color_negative( $sparkline->{_negative_color} ); |
|
9888
|
|
|
|
|
|
|
|
|
9889
|
|
|
|
|
|
|
# Write the x14:colorAxis element. |
|
9890
|
58
|
|
|
|
|
150
|
$self->_write_color_axis(); |
|
9891
|
|
|
|
|
|
|
|
|
9892
|
|
|
|
|
|
|
# Write the x14:colorMarkers element. |
|
9893
|
58
|
|
|
|
|
183
|
$self->_write_color_markers( $sparkline->{_markers_color} ); |
|
9894
|
|
|
|
|
|
|
|
|
9895
|
|
|
|
|
|
|
# Write the x14:colorFirst element. |
|
9896
|
58
|
|
|
|
|
153
|
$self->_write_color_first( $sparkline->{_first_color} ); |
|
9897
|
|
|
|
|
|
|
|
|
9898
|
|
|
|
|
|
|
# Write the x14:colorLast element. |
|
9899
|
58
|
|
|
|
|
168
|
$self->_write_color_last( $sparkline->{_last_color} ); |
|
9900
|
|
|
|
|
|
|
|
|
9901
|
|
|
|
|
|
|
# Write the x14:colorHigh element. |
|
9902
|
58
|
|
|
|
|
146
|
$self->_write_color_high( $sparkline->{_high_color} ); |
|
9903
|
|
|
|
|
|
|
|
|
9904
|
|
|
|
|
|
|
# Write the x14:colorLow element. |
|
9905
|
58
|
|
|
|
|
175
|
$self->_write_color_low( $sparkline->{_low_color} ); |
|
9906
|
|
|
|
|
|
|
|
|
9907
|
58
|
100
|
|
|
|
187
|
if ( $sparkline->{_date_axis} ) { |
|
9908
|
1
|
|
|
|
|
7
|
$self->xml_data_element( 'xm:f', $sparkline->{_date_axis} ); |
|
9909
|
|
|
|
|
|
|
} |
|
9910
|
|
|
|
|
|
|
|
|
9911
|
58
|
|
|
|
|
154
|
$self->_write_sparklines( $sparkline ); |
|
9912
|
|
|
|
|
|
|
|
|
9913
|
58
|
|
|
|
|
112
|
$self->xml_end_tag( 'x14:sparklineGroup' ); |
|
9914
|
|
|
|
|
|
|
} |
|
9915
|
|
|
|
|
|
|
|
|
9916
|
|
|
|
|
|
|
|
|
9917
|
12
|
|
|
|
|
56
|
$self->xml_end_tag( 'x14:sparklineGroups' ); |
|
9918
|
12
|
|
|
|
|
98
|
$self->xml_end_tag( 'ext' ); |
|
9919
|
|
|
|
|
|
|
} |
|
9920
|
|
|
|
|
|
|
|
|
9921
|
|
|
|
|
|
|
|
|
9922
|
|
|
|
|
|
|
############################################################################## |
|
9923
|
|
|
|
|
|
|
# |
|
9924
|
|
|
|
|
|
|
# _write_sparklines() |
|
9925
|
|
|
|
|
|
|
# |
|
9926
|
|
|
|
|
|
|
# Write the element and subelements. |
|
9927
|
|
|
|
|
|
|
# |
|
9928
|
|
|
|
|
|
|
sub _write_sparklines { |
|
9929
|
|
|
|
|
|
|
|
|
9930
|
58
|
|
|
58
|
|
112
|
my $self = shift; |
|
9931
|
58
|
|
|
|
|
101
|
my $sparkline = shift; |
|
9932
|
|
|
|
|
|
|
|
|
9933
|
|
|
|
|
|
|
# Write the sparkline elements. |
|
9934
|
58
|
|
|
|
|
177
|
$self->xml_start_tag( 'x14:sparklines' ); |
|
9935
|
|
|
|
|
|
|
|
|
9936
|
58
|
|
|
|
|
173
|
for my $i ( 0 .. $sparkline->{_count} - 1 ) { |
|
9937
|
59
|
|
|
|
|
107
|
my $range = $sparkline->{_ranges}->[$i]; |
|
9938
|
59
|
|
|
|
|
114
|
my $location = $sparkline->{_locations}->[$i]; |
|
9939
|
|
|
|
|
|
|
|
|
9940
|
59
|
|
|
|
|
163
|
$self->xml_start_tag( 'x14:sparkline' ); |
|
9941
|
59
|
|
|
|
|
200
|
$self->xml_data_element( 'xm:f', $range ); |
|
9942
|
59
|
|
|
|
|
147
|
$self->xml_data_element( 'xm:sqref', $location ); |
|
9943
|
59
|
|
|
|
|
137
|
$self->xml_end_tag( 'x14:sparkline' ); |
|
9944
|
|
|
|
|
|
|
} |
|
9945
|
|
|
|
|
|
|
|
|
9946
|
|
|
|
|
|
|
|
|
9947
|
58
|
|
|
|
|
127
|
$self->xml_end_tag( 'x14:sparklines' ); |
|
9948
|
|
|
|
|
|
|
} |
|
9949
|
|
|
|
|
|
|
|
|
9950
|
|
|
|
|
|
|
|
|
9951
|
|
|
|
|
|
|
############################################################################## |
|
9952
|
|
|
|
|
|
|
# |
|
9953
|
|
|
|
|
|
|
# _write_ext() |
|
9954
|
|
|
|
|
|
|
# |
|
9955
|
|
|
|
|
|
|
# Write the element for sparklines. |
|
9956
|
|
|
|
|
|
|
# |
|
9957
|
|
|
|
|
|
|
sub _write_ext { |
|
9958
|
|
|
|
|
|
|
|
|
9959
|
48
|
|
|
48
|
|
105
|
my $self = shift; |
|
9960
|
48
|
|
|
|
|
87
|
my $uri = shift; |
|
9961
|
48
|
|
|
|
|
91
|
my $schema = 'http://schemas.microsoft.com/office/'; |
|
9962
|
48
|
|
|
|
|
128
|
my $xmlns_x14 = $schema . 'spreadsheetml/2009/9/main'; |
|
9963
|
|
|
|
|
|
|
|
|
9964
|
48
|
|
|
|
|
145
|
my @attributes = ( |
|
9965
|
|
|
|
|
|
|
'xmlns:x14' => $xmlns_x14, |
|
9966
|
|
|
|
|
|
|
'uri' => $uri, |
|
9967
|
|
|
|
|
|
|
); |
|
9968
|
|
|
|
|
|
|
|
|
9969
|
48
|
|
|
|
|
173
|
$self->xml_start_tag( 'ext', @attributes ); |
|
9970
|
|
|
|
|
|
|
} |
|
9971
|
|
|
|
|
|
|
|
|
9972
|
|
|
|
|
|
|
|
|
9973
|
|
|
|
|
|
|
############################################################################## |
|
9974
|
|
|
|
|
|
|
# |
|
9975
|
|
|
|
|
|
|
# _write_sparkline_groups() |
|
9976
|
|
|
|
|
|
|
# |
|
9977
|
|
|
|
|
|
|
# Write the element. |
|
9978
|
|
|
|
|
|
|
# |
|
9979
|
|
|
|
|
|
|
sub _write_sparkline_groups { |
|
9980
|
|
|
|
|
|
|
|
|
9981
|
12
|
|
|
12
|
|
28
|
my $self = shift; |
|
9982
|
12
|
|
|
|
|
23
|
my $xmlns_xm = 'http://schemas.microsoft.com/office/excel/2006/main'; |
|
9983
|
|
|
|
|
|
|
|
|
9984
|
12
|
|
|
|
|
40
|
my @attributes = ( 'xmlns:xm' => $xmlns_xm ); |
|
9985
|
|
|
|
|
|
|
|
|
9986
|
12
|
|
|
|
|
56
|
$self->xml_start_tag( 'x14:sparklineGroups', @attributes ); |
|
9987
|
|
|
|
|
|
|
|
|
9988
|
|
|
|
|
|
|
} |
|
9989
|
|
|
|
|
|
|
|
|
9990
|
|
|
|
|
|
|
|
|
9991
|
|
|
|
|
|
|
############################################################################## |
|
9992
|
|
|
|
|
|
|
# |
|
9993
|
|
|
|
|
|
|
# _write_sparkline_group() |
|
9994
|
|
|
|
|
|
|
# |
|
9995
|
|
|
|
|
|
|
# Write the element. |
|
9996
|
|
|
|
|
|
|
# |
|
9997
|
|
|
|
|
|
|
# Example for order. |
|
9998
|
|
|
|
|
|
|
# |
|
9999
|
|
|
|
|
|
|
#
|
|
10000
|
|
|
|
|
|
|
# manualMax="0" |
|
10001
|
|
|
|
|
|
|
# manualMin="0" |
|
10002
|
|
|
|
|
|
|
# lineWeight="2.25" |
|
10003
|
|
|
|
|
|
|
# type="column" |
|
10004
|
|
|
|
|
|
|
# dateAxis="1" |
|
10005
|
|
|
|
|
|
|
# displayEmptyCellsAs="span" |
|
10006
|
|
|
|
|
|
|
# markers="1" |
|
10007
|
|
|
|
|
|
|
# high="1" |
|
10008
|
|
|
|
|
|
|
# low="1" |
|
10009
|
|
|
|
|
|
|
# first="1" |
|
10010
|
|
|
|
|
|
|
# last="1" |
|
10011
|
|
|
|
|
|
|
# negative="1" |
|
10012
|
|
|
|
|
|
|
# displayXAxis="1" |
|
10013
|
|
|
|
|
|
|
# displayHidden="1" |
|
10014
|
|
|
|
|
|
|
# minAxisType="custom" |
|
10015
|
|
|
|
|
|
|
# maxAxisType="custom" |
|
10016
|
|
|
|
|
|
|
# rightToLeft="1"> |
|
10017
|
|
|
|
|
|
|
# |
|
10018
|
|
|
|
|
|
|
sub _write_sparkline_group { |
|
10019
|
|
|
|
|
|
|
|
|
10020
|
58
|
|
|
58
|
|
97
|
my $self = shift; |
|
10021
|
58
|
|
|
|
|
87
|
my $opts = shift; |
|
10022
|
58
|
|
|
|
|
91
|
my $empty = $opts->{_empty}; |
|
10023
|
58
|
|
|
|
|
97
|
my $user_max = 0; |
|
10024
|
58
|
|
|
|
|
81
|
my $user_min = 0; |
|
10025
|
58
|
|
|
|
|
74
|
my @a; |
|
10026
|
|
|
|
|
|
|
|
|
10027
|
58
|
100
|
|
|
|
127
|
if ( defined $opts->{_max} ) { |
|
10028
|
|
|
|
|
|
|
|
|
10029
|
4
|
100
|
|
|
|
14
|
if ( $opts->{_max} eq 'group' ) { |
|
10030
|
2
|
|
|
|
|
5
|
$opts->{_cust_max} = 'group'; |
|
10031
|
|
|
|
|
|
|
} |
|
10032
|
|
|
|
|
|
|
else { |
|
10033
|
2
|
|
|
|
|
5
|
push @a, ( 'manualMax' => $opts->{_max} ); |
|
10034
|
2
|
|
|
|
|
5
|
$opts->{_cust_max} = 'custom'; |
|
10035
|
|
|
|
|
|
|
} |
|
10036
|
|
|
|
|
|
|
} |
|
10037
|
|
|
|
|
|
|
|
|
10038
|
58
|
100
|
|
|
|
127
|
if ( defined $opts->{_min} ) { |
|
10039
|
|
|
|
|
|
|
|
|
10040
|
4
|
100
|
|
|
|
12
|
if ( $opts->{_min} eq 'group' ) { |
|
10041
|
1
|
|
|
|
|
2
|
$opts->{_cust_min} = 'group'; |
|
10042
|
|
|
|
|
|
|
} |
|
10043
|
|
|
|
|
|
|
else { |
|
10044
|
3
|
|
|
|
|
7
|
push @a, ( 'manualMin' => $opts->{_min} ); |
|
10045
|
3
|
|
|
|
|
7
|
$opts->{_cust_min} = 'custom'; |
|
10046
|
|
|
|
|
|
|
} |
|
10047
|
|
|
|
|
|
|
} |
|
10048
|
|
|
|
|
|
|
|
|
10049
|
|
|
|
|
|
|
|
|
10050
|
|
|
|
|
|
|
# Ignore the default type attribute (line). |
|
10051
|
58
|
100
|
|
|
|
139
|
if ( $opts->{_type} ne 'line' ) { |
|
10052
|
9
|
|
|
|
|
22
|
push @a, ( 'type' => $opts->{_type} ); |
|
10053
|
|
|
|
|
|
|
} |
|
10054
|
|
|
|
|
|
|
|
|
10055
|
58
|
100
|
|
|
|
125
|
push @a, ( 'lineWeight' => $opts->{_weight} ) if $opts->{_weight}; |
|
10056
|
58
|
100
|
|
|
|
132
|
push @a, ( 'dateAxis' => 1 ) if $opts->{_date_axis}; |
|
10057
|
58
|
100
|
|
|
|
137
|
push @a, ( 'displayEmptyCellsAs' => $empty ) if $empty; |
|
10058
|
|
|
|
|
|
|
|
|
10059
|
58
|
100
|
|
|
|
116
|
push @a, ( 'markers' => 1 ) if $opts->{_markers}; |
|
10060
|
58
|
100
|
|
|
|
125
|
push @a, ( 'high' => 1 ) if $opts->{_high}; |
|
10061
|
58
|
100
|
|
|
|
152
|
push @a, ( 'low' => 1 ) if $opts->{_low}; |
|
10062
|
58
|
100
|
|
|
|
118
|
push @a, ( 'first' => 1 ) if $opts->{_first}; |
|
10063
|
58
|
100
|
|
|
|
115
|
push @a, ( 'last' => 1 ) if $opts->{_last}; |
|
10064
|
58
|
100
|
|
|
|
115
|
push @a, ( 'negative' => 1 ) if $opts->{_negative}; |
|
10065
|
58
|
100
|
|
|
|
114
|
push @a, ( 'displayXAxis' => 1 ) if $opts->{_axis}; |
|
10066
|
58
|
100
|
|
|
|
118
|
push @a, ( 'displayHidden' => 1 ) if $opts->{_hidden}; |
|
10067
|
58
|
100
|
|
|
|
118
|
push @a, ( 'minAxisType' => $opts->{_cust_min} ) if $opts->{_cust_min}; |
|
10068
|
58
|
100
|
|
|
|
125
|
push @a, ( 'maxAxisType' => $opts->{_cust_max} ) if $opts->{_cust_max}; |
|
10069
|
58
|
100
|
|
|
|
113
|
push @a, ( 'rightToLeft' => 1 ) if $opts->{_reverse}; |
|
10070
|
|
|
|
|
|
|
|
|
10071
|
58
|
|
|
|
|
171
|
$self->xml_start_tag( 'x14:sparklineGroup', @a ); |
|
10072
|
|
|
|
|
|
|
} |
|
10073
|
|
|
|
|
|
|
|
|
10074
|
|
|
|
|
|
|
|
|
10075
|
|
|
|
|
|
|
############################################################################## |
|
10076
|
|
|
|
|
|
|
# |
|
10077
|
|
|
|
|
|
|
# _write_spark_color() |
|
10078
|
|
|
|
|
|
|
# |
|
10079
|
|
|
|
|
|
|
# Helper function for the sparkline color functions below. |
|
10080
|
|
|
|
|
|
|
# |
|
10081
|
|
|
|
|
|
|
sub _write_spark_color { |
|
10082
|
|
|
|
|
|
|
|
|
10083
|
464
|
|
|
464
|
|
583
|
my $self = shift; |
|
10084
|
464
|
|
|
|
|
571
|
my $element = shift; |
|
10085
|
464
|
|
|
|
|
541
|
my $color = shift; |
|
10086
|
464
|
|
|
|
|
529
|
my @attr; |
|
10087
|
|
|
|
|
|
|
|
|
10088
|
464
|
100
|
|
|
|
945
|
push @attr, ( 'rgb' => $color->{_rgb} ) if defined $color->{_rgb}; |
|
10089
|
464
|
100
|
|
|
|
963
|
push @attr, ( 'theme' => $color->{_theme} ) if defined $color->{_theme}; |
|
10090
|
464
|
100
|
|
|
|
798
|
push @attr, ( 'tint' => $color->{_tint} ) if defined $color->{_tint}; |
|
10091
|
|
|
|
|
|
|
|
|
10092
|
464
|
|
|
|
|
898
|
$self->xml_empty_tag( $element, @attr ); |
|
10093
|
|
|
|
|
|
|
} |
|
10094
|
|
|
|
|
|
|
|
|
10095
|
|
|
|
|
|
|
|
|
10096
|
|
|
|
|
|
|
############################################################################## |
|
10097
|
|
|
|
|
|
|
# |
|
10098
|
|
|
|
|
|
|
# _write_color_series() |
|
10099
|
|
|
|
|
|
|
# |
|
10100
|
|
|
|
|
|
|
# Write the element. |
|
10101
|
|
|
|
|
|
|
# |
|
10102
|
|
|
|
|
|
|
sub _write_color_series { |
|
10103
|
|
|
|
|
|
|
|
|
10104
|
58
|
|
|
58
|
|
90
|
my $self = shift; |
|
10105
|
|
|
|
|
|
|
|
|
10106
|
58
|
|
|
|
|
141
|
$self->_write_spark_color( 'x14:colorSeries', @_ ); |
|
10107
|
|
|
|
|
|
|
} |
|
10108
|
|
|
|
|
|
|
|
|
10109
|
|
|
|
|
|
|
|
|
10110
|
|
|
|
|
|
|
############################################################################## |
|
10111
|
|
|
|
|
|
|
# |
|
10112
|
|
|
|
|
|
|
# _write_color_negative() |
|
10113
|
|
|
|
|
|
|
# |
|
10114
|
|
|
|
|
|
|
# Write the element. |
|
10115
|
|
|
|
|
|
|
# |
|
10116
|
|
|
|
|
|
|
sub _write_color_negative { |
|
10117
|
|
|
|
|
|
|
|
|
10118
|
58
|
|
|
58
|
|
93
|
my $self = shift; |
|
10119
|
|
|
|
|
|
|
|
|
10120
|
58
|
|
|
|
|
109
|
$self->_write_spark_color( 'x14:colorNegative', @_ ); |
|
10121
|
|
|
|
|
|
|
} |
|
10122
|
|
|
|
|
|
|
|
|
10123
|
|
|
|
|
|
|
|
|
10124
|
|
|
|
|
|
|
############################################################################## |
|
10125
|
|
|
|
|
|
|
# |
|
10126
|
|
|
|
|
|
|
# _write_color_axis() |
|
10127
|
|
|
|
|
|
|
# |
|
10128
|
|
|
|
|
|
|
# Write the element. |
|
10129
|
|
|
|
|
|
|
# |
|
10130
|
|
|
|
|
|
|
sub _write_color_axis { |
|
10131
|
|
|
|
|
|
|
|
|
10132
|
58
|
|
|
58
|
|
82
|
my $self = shift; |
|
10133
|
|
|
|
|
|
|
|
|
10134
|
58
|
|
|
|
|
143
|
$self->_write_spark_color( 'x14:colorAxis', { _rgb => 'FF000000' } ); |
|
10135
|
|
|
|
|
|
|
} |
|
10136
|
|
|
|
|
|
|
|
|
10137
|
|
|
|
|
|
|
|
|
10138
|
|
|
|
|
|
|
############################################################################## |
|
10139
|
|
|
|
|
|
|
# |
|
10140
|
|
|
|
|
|
|
# _write_color_markers() |
|
10141
|
|
|
|
|
|
|
# |
|
10142
|
|
|
|
|
|
|
# Write the element. |
|
10143
|
|
|
|
|
|
|
# |
|
10144
|
|
|
|
|
|
|
sub _write_color_markers { |
|
10145
|
|
|
|
|
|
|
|
|
10146
|
58
|
|
|
58
|
|
87
|
my $self = shift; |
|
10147
|
|
|
|
|
|
|
|
|
10148
|
58
|
|
|
|
|
107
|
$self->_write_spark_color( 'x14:colorMarkers', @_ ); |
|
10149
|
|
|
|
|
|
|
} |
|
10150
|
|
|
|
|
|
|
|
|
10151
|
|
|
|
|
|
|
|
|
10152
|
|
|
|
|
|
|
############################################################################## |
|
10153
|
|
|
|
|
|
|
# |
|
10154
|
|
|
|
|
|
|
# _write_color_first() |
|
10155
|
|
|
|
|
|
|
# |
|
10156
|
|
|
|
|
|
|
# Write the element. |
|
10157
|
|
|
|
|
|
|
# |
|
10158
|
|
|
|
|
|
|
sub _write_color_first { |
|
10159
|
|
|
|
|
|
|
|
|
10160
|
58
|
|
|
58
|
|
95
|
my $self = shift; |
|
10161
|
|
|
|
|
|
|
|
|
10162
|
58
|
|
|
|
|
115
|
$self->_write_spark_color( 'x14:colorFirst', @_ ); |
|
10163
|
|
|
|
|
|
|
} |
|
10164
|
|
|
|
|
|
|
|
|
10165
|
|
|
|
|
|
|
|
|
10166
|
|
|
|
|
|
|
############################################################################## |
|
10167
|
|
|
|
|
|
|
# |
|
10168
|
|
|
|
|
|
|
# _write_color_last() |
|
10169
|
|
|
|
|
|
|
# |
|
10170
|
|
|
|
|
|
|
# Write the element. |
|
10171
|
|
|
|
|
|
|
# |
|
10172
|
|
|
|
|
|
|
sub _write_color_last { |
|
10173
|
|
|
|
|
|
|
|
|
10174
|
58
|
|
|
58
|
|
80
|
my $self = shift; |
|
10175
|
|
|
|
|
|
|
|
|
10176
|
58
|
|
|
|
|
104
|
$self->_write_spark_color( 'x14:colorLast', @_ ); |
|
10177
|
|
|
|
|
|
|
} |
|
10178
|
|
|
|
|
|
|
|
|
10179
|
|
|
|
|
|
|
|
|
10180
|
|
|
|
|
|
|
############################################################################## |
|
10181
|
|
|
|
|
|
|
# |
|
10182
|
|
|
|
|
|
|
# _write_color_high() |
|
10183
|
|
|
|
|
|
|
# |
|
10184
|
|
|
|
|
|
|
# Write the element. |
|
10185
|
|
|
|
|
|
|
# |
|
10186
|
|
|
|
|
|
|
sub _write_color_high { |
|
10187
|
|
|
|
|
|
|
|
|
10188
|
58
|
|
|
58
|
|
86
|
my $self = shift; |
|
10189
|
|
|
|
|
|
|
|
|
10190
|
58
|
|
|
|
|
114
|
$self->_write_spark_color( 'x14:colorHigh', @_ ); |
|
10191
|
|
|
|
|
|
|
} |
|
10192
|
|
|
|
|
|
|
|
|
10193
|
|
|
|
|
|
|
|
|
10194
|
|
|
|
|
|
|
############################################################################## |
|
10195
|
|
|
|
|
|
|
# |
|
10196
|
|
|
|
|
|
|
# _write_color_low() |
|
10197
|
|
|
|
|
|
|
# |
|
10198
|
|
|
|
|
|
|
# Write the element. |
|
10199
|
|
|
|
|
|
|
# |
|
10200
|
|
|
|
|
|
|
sub _write_color_low { |
|
10201
|
|
|
|
|
|
|
|
|
10202
|
58
|
|
|
58
|
|
77
|
my $self = shift; |
|
10203
|
|
|
|
|
|
|
|
|
10204
|
58
|
|
|
|
|
129
|
$self->_write_spark_color( 'x14:colorLow', @_ ); |
|
10205
|
|
|
|
|
|
|
} |
|
10206
|
|
|
|
|
|
|
|
|
10207
|
|
|
|
|
|
|
|
|
10208
|
|
|
|
|
|
|
1; |
|
10209
|
|
|
|
|
|
|
|
|
10210
|
|
|
|
|
|
|
|
|
10211
|
|
|
|
|
|
|
__END__ |