File Coverage

blib/lib/Spreadsheet/WriteExcelXML/Format.pm
Criterion Covered Total %
statement 221 236 93.6
branch 180 208 86.5
condition 18 20 90.0
subroutine 26 28 92.8
pod 0 19 0.0
total 445 511 87.0


line stmt bran cond sub pod time code
1             package Spreadsheet::WriteExcelXML::Format;
2              
3             ###############################################################################
4             #
5             # Format - A class for defining Excel formatting.
6             #
7             #
8             # Used in conjunction with Spreadsheet::WriteExcelXML
9             #
10             # Copyright 2000-2010, John McNamara, jmcnamara@cpan.org
11             #
12             # Documentation after __END__
13             #
14              
15 23     23   152 use Exporter;
  23         50  
  23         925  
16 23     23   124 use strict;
  23         47  
  23         418  
17 23     23   101 use Carp;
  23         59  
  23         1522  
18              
19              
20              
21              
22              
23              
24              
25 23     23   157 use vars qw($AUTOLOAD $VERSION @ISA);
  23         67  
  23         66311  
26             @ISA = qw(Exporter);
27              
28             $VERSION = '0.15';
29              
30             ###############################################################################
31             #
32             # new()
33             #
34             # Constructor
35             #
36             sub new {
37              
38 237     237 0 470 my $class = shift;
39              
40 237   100     4272 my $self = {
41             _xf_index => shift || 0,
42             _palette => shift,
43              
44             _font_index => 0,
45             _font => 'Arial',
46             _size => 10,
47             _bold => 0,
48             _italic => 0,
49             _color => 0x0,
50             _underline => 0,
51             _font_strikeout => 0,
52             _font_outline => 0,
53             _font_shadow => 0,
54             _font_script => 0,
55             _font_family => 0,
56             _font_charset => 0,
57              
58             _num_format => undef,
59              
60             _hidden => 0,
61             _locked => 1,
62              
63             _text_h_align => 0,
64             _text_wrap => 0,
65             _text_v_align => -1,
66             _text_justlast => 0,
67             _rotation => 0,
68             _text_vertical => 0,
69              
70             _fg_color => 0x00,
71             _bg_color => 0x00,
72              
73             _pattern => 0,
74              
75             _bottom => 0,
76             _top => 0,
77             _left => 0,
78             _right => 0,
79              
80             _bottom_color => 0x0,
81             _top_color => 0x0,
82             _left_color => 0x0,
83             _right_color => 0x0,
84              
85             _indent => 0,
86             _shrink => 0,
87             _merge_range => 0,
88             _reading_order => 0,
89              
90             _diag_type => 0,
91             _diag_color => 0x0,
92             _diag_border => 0,
93              
94             _just_distrib => 0,
95              
96             };
97              
98 237         584 bless $self, $class;
99              
100             # Set properties passed to Workbook::add_format()
101 237 100       620 $self->set_properties(@_) if @_;
102              
103 237         586 return $self;
104             }
105              
106              
107             ###############################################################################
108             #
109             # copy($format)
110             #
111             # Copy the attributes of another Spreadsheet::WriteExcelXML::Format object.
112             #
113             sub copy {
114 0     0 0 0 my $self = shift;
115 0         0 my $other = $_[0];
116              
117              
118 0 0       0 return unless defined $other;
119 0 0       0 return unless (ref($self) eq ref($other));
120              
121              
122 0         0 my $xf = $self->{_xf_index}; # Store XF index assigned by Workbook.pm
123 0         0 my $palette = $self->{_palette}; # Store palette assigned by Workbook.pm
124 0         0 %$self = %$other; # Copy properties
125 0         0 $self->{_xf_index} = $xf; # Restore XF index
126 0         0 $self->{_palette} = $palette; # Restore palette
127             }
128              
129              
130             ###############################################################################
131             #
132             # convert_to_html_color()
133             #
134             # Convert from an Excel internal colour index to a Html style #RRGGBB index
135             # based on the default or user defined values in the Workbook palette.
136             #
137             sub convert_to_html_color {
138              
139 123     123 0 202 my $self = shift;
140 123         214 my $index = $_[0];
141              
142 123 100       275 return 0 unless $index;
143              
144 89         145 $index -=8; # Adjust colour index
145              
146             # _palette is a reference to the colour palette in the Workbook module
147 89         141 my @rgb = @{${$self->{_palette}}->[$index]}[0,1,2];
  89         136  
  89         313  
148              
149 89         510 return sprintf "#%02X%02X%02X", @rgb;
150             }
151              
152              
153             ###############################################################################
154             #
155             # get_align_properties()
156             #
157             # Return properties for an Excel XML element.
158             #
159             # Excels handling of the vertical align "Bottom" property is different from
160             # other properties. It is on by default if any non-vertical property is set.
161             # Therefore we set the undefined _text_v_align value to -1 so that we can
162             # detect if it has been set by the user. If it hasn't been set then we supply
163             # the default "Bottom" value.
164             #
165             #
166             sub get_align_properties {
167              
168 53     53 0 161 my $self = shift;
169              
170 53         92 my @align; # Attributes to return
171              
172             # Check if any alignment options in the format have been changed.
173             my $changed = (
174             $self->{_text_h_align} != 0 ||
175             $self->{_text_v_align} != -1 ||
176             $self->{_indent} != 0 ||
177             $self->{_rotation} != 0 ||
178             $self->{_text_vertical} != 0 ||
179             $self->{_text_wrap} != 0 ||
180             $self->{_shrink} != 0 ||
181 53 100 100     708 $self->{_reading_order} != 0) ? 1 : 0;
182              
183              
184 53 100       221 return unless $changed;
185              
186             # Excel sets 'ss:Vertical="Bottom"' even when it is the default.
187 32 100       71 $self->{_text_v_align} = 2 if $self->{_text_v_align} == -1;
188              
189              
190             # Check for properties that are mutually exclusive.
191 32 100       71 $self->{_rotation} = 0 if $self->{_text_vertical};
192 32 100       68 $self->{_shrink} = 0 if $self->{_text_wrap};
193 32 100       75 $self->{_shrink} = 0 if $self->{_text_h_align} == 4; # Fill
194 32 100       69 $self->{_shrink} = 0 if $self->{_text_h_align} == 5; # Justify
195 32 100       86 $self->{_shrink} = 0 if $self->{_text_h_align} == 7; # Distributed
196 32 100       90 $self->{_just_distrib} = 0 if $self->{_text_h_align} != 7; # Distributed TODO
197              
198              
199 32 100       74 push @align, 'ss:Horizontal', 'Left' if $self->{_text_h_align} == 1;
200 32 100       75 push @align, 'ss:Horizontal', 'Center' if $self->{_text_h_align} == 2;
201 32 100       72 push @align, 'ss:Horizontal', 'Right' if $self->{_text_h_align} == 3;
202 32 100       69 push @align, 'ss:Horizontal', 'Fill' if $self->{_text_h_align} == 4;
203 32 100       79 push @align, 'ss:Horizontal', 'Justify' if $self->{_text_h_align} == 5;
204             push @align, 'ss:Horizontal', 'CenterAcrossSelection'
205 32 100       69 if $self->{_text_h_align} == 6;
206 32 100       66 push @align, 'ss:Horizontal', 'Distributed' if $self->{_text_h_align} == 7;
207              
208 32 100       61 push @align, 'ss:Vertical', 'Top' if $self->{_text_v_align} == 0;
209 32 100       66 push @align, 'ss:Vertical', 'Center' if $self->{_text_v_align} == 1;
210 32 100       99 push @align, 'ss:Vertical', 'Bottom' if $self->{_text_v_align} == 2;
211 32 100       64 push @align, 'ss:Vertical', 'Justify' if $self->{_text_v_align} == 3;
212 32 100       75 push @align, 'ss:Vertical', 'Distributed' if $self->{_text_v_align} == 4;
213              
214 32 100       69 push @align, 'ss:Indent', $self->{_indent} if $self->{_indent};
215 32 100       78 push @align, 'ss:Rotate', $self->{_rotation} if $self->{_rotation};
216              
217 32 100       69 push @align, 'ss:VerticalText',1 if $self->{_text_vertical};
218 32 100       71 push @align, 'ss:WrapText', 1 if $self->{_text_wrap};
219 32 100       63 push @align, 'ss:ShrinkToFit', 1 if $self->{_shrink};
220              
221             # 'Context' is default property for ReadingOrder.
222 32 100       124 push @align, 'ss:ReadingOrder','LeftToRight' if $self->{_reading_order}==1;
223 32 100       70 push @align, 'ss:ReadingOrder','RightToLeft' if $self->{_reading_order}==2;
224              
225              
226             # TODO
227             # ss:Horizontal="JustifyDistributed" ss:Vertical="Bottom"
228              
229 32         127 return @align;
230             }
231              
232              
233             ###############################################################################
234             #
235             # get_border_properties()
236             #
237             # Return properties for an Excel XML element.
238             #
239             sub get_border_properties {
240              
241 48     48 0 157 my $self = shift;
242              
243 48         85 my @border; # Attributes to return
244              
245              
246 48         832 my %linetypes =(
247             1 => ['ss:LineStyle' => 'Continuous', 'ss:Weight' => 1],
248             2 => ['ss:LineStyle' => 'Continuous', 'ss:Weight' => 2],
249             3 => ['ss:LineStyle' => 'Dash', 'ss:Weight' => 1],
250             4 => ['ss:LineStyle' => 'Dot', 'ss:Weight' => 1],
251             5 => ['ss:LineStyle' => 'Continuous', 'ss:Weight' => 3],
252             6 => ['ss:LineStyle' => 'Double', 'ss:Weight' => 3],
253             7 => ['ss:LineStyle' => 'Continuous' ],
254             8 => ['ss:LineStyle' => 'Dash', 'ss:Weight' => 2],
255             9 => ['ss:LineStyle' => 'DashDot', 'ss:Weight' => 1],
256             10 => ['ss:LineStyle' => 'DashDot', 'ss:Weight' => 2],
257             11 => ['ss:LineStyle' => 'DashDotDot', 'ss:Weight' => 1],
258             12 => ['ss:LineStyle' => 'DashDotDot', 'ss:Weight' => 2],
259             13 => ['ss:LineStyle' => 'SlantDashDot', 'ss:Weight' => 2],
260             );
261              
262              
263 48         146 for my $position ('_bottom', '_left', '_right', '_top') {
264              
265 192         663 (my $type = $position) =~ s/^_//;
266 192         501 my @attribs = ('ss:Position', ucfirst $type);
267 192         350 my $position_color = $position . '_color';
268              
269 192 100       579 if (exists $linetypes{$self->{$position}}) {
270              
271 33         51 push @attribs, @{$linetypes{$self->{$position}}};
  33         91  
272              
273 33 100       86 if (my $color = $self->{$position_color}) {
274 5         12 $color = $self->convert_to_html_color($color);
275 5         12 push @attribs, 'ss:Color', $color;
276             }
277              
278 33         114 push @border, [@attribs];
279             }
280             }
281              
282              
283             # Handle diagonal borders. Note that in Excel it is only possible to have
284             # one line type and one colour when both diagonals are in use.
285 48 100       165 if (my $diag_type = $self->{_diag_type}) {
286              
287             # Set a default diagonal border style if none was specified.
288 7 100       18 $self->{_diag_border} = 1 if not $self->{_diag_border};
289              
290              
291 7         13 my @attribs = @{$linetypes{$self->{_diag_border}}};
  7         19  
292              
293 7 100       20 if (my $color = $self->{_diag_color}) {
294 3         9 $color = $self->convert_to_html_color($color);
295 3         9 push @attribs, 'ss:Color', $color;
296             }
297              
298 7 100 100     33 if ($diag_type == 1 or $diag_type == 3) {
299 5         15 push @border, ["ss:Position", "DiagonalLeft", @attribs];
300             }
301              
302 7 100 100     27 if ($diag_type == 2 or $diag_type == 3) {
303 4         13 push @border, ["ss:Position", "DiagonalRight", @attribs];
304             }
305             }
306              
307 48         339 return @border;
308             }
309              
310              
311             ###############################################################################
312             #
313             # get_font_properties()
314             #
315             # Return properties for an Excel XML element.
316             #
317             sub get_font_properties {
318              
319 71     71 0 240 my $self = shift;
320              
321 71         125 my @font; # Attributes to return
322              
323 71         198 my $color = $self->convert_to_html_color($self->{_color});
324              
325              
326 71 100       247 push @font, 'ss:FontName', $self->{_font} if $self->{_font} ne 'Arial';
327 71 100       197 push @font, 'ss:Size', $self->{_size} if $self->{_size} != 10;
328 71 100       191 push @font, 'ss:Color', $color if $self->{_color};
329 71 100       176 push @font, 'ss:Bold', 1 if $self->{_bold};
330 71 100       169 push @font, 'ss:Italic', 1 if $self->{_italic};
331              
332 71 100       176 push @font, 'ss:StrikeThrough', 1 if $self->{_font_strikeout};
333 71 100       170 push @font, 'ss:Outline', 1 if $self->{_font_outline};
334 71 100       197 push @font, 'ss:Shadow', 1 if $self->{_font_shadow};
335              
336 71 100       195 push @font, 'ss:VerticalAlign', 'Superscript' if $self->{_font_script} == 1;
337 71 100       182 push @font, 'ss:VerticalAlign', 'Subscript' if $self->{_font_script} == 2;
338              
339 71 100       181 push @font, 'ss:Underline', 'Single' if $self->{_underline} == 1;
340 71 100       183 push @font, 'ss:Underline', 'Double' if $self->{_underline} == 2;
341 71 100       178 push @font, 'ss:Underline', 'SingleAccounting'if $self->{_underline} == 33;
342 71 50       151 push @font, 'ss:Underline', 'DoubleAccounting'if $self->{_underline} == 34;
343              
344 71 100       174 push @font, 'x:Family', $self->{_font_family} if $self->{_font_family};
345 71 100       159 push @font, 'x:CharSet', $self->{_font_charset} if $self->{_font_charset};
346              
347 71         342 return @font;
348             }
349              
350              
351             ###############################################################################
352             #
353             # get_interior_properties()
354             #
355             # Return properties for an Excel XML element.
356             #
357             sub get_interior_properties {
358              
359 49     49 0 168 my $self = shift;
360              
361             # Return undef if the background and foreground colours haven't been set
362             # and the pattern hasn't been set or if it has only been set to solid.
363             # Other patterns will be handled with the default colours.
364             #
365             return if $self->{_fg_color} == 0x00 and
366             $self->{_bg_color} == 0x00 and
367 49 100 100     405 $self->{_pattern} <= 0x01;
      100        
368              
369              
370             # Note for XML:
371             # ss:Color = _bg_color
372             # ss:PatternColor = _fg_color
373              
374              
375             # The following logical statements take care of special cases in relation
376             # to cell colours and patterns:
377             # 1. For a solid fill (_pattern == 1) Excel reverses the role of foreground
378             # and background colours.
379             # 2. If the user specifies a foreground or background colour without a
380             # pattern they probably wanted a solid fill, so we fill in the defaults.
381             #
382 26 100       67 if ($self->{_pattern} <= 0x01) {
383 6 100       16 if ($self->{_bg_color}) {
384             return 'ss:Color',
385 3         8 $self->convert_to_html_color($self->{_bg_color}),
386             'ss:Pattern',
387             'Solid';
388             }
389             else {
390             return 'ss:Color',
391 3         10 $self->convert_to_html_color($self->{_fg_color}),
392             'ss:Pattern',
393             'Solid';
394             }
395             }
396              
397              
398             # Set default colours if they haven't been set.
399 20 100       53 $self->{_bg_color} = 0x09 if $self->{_bg_color} == 0x00; # 0x09 = white
400 20 100       46 $self->{_fg_color} = 0x08 if $self->{_fg_color} == 0x00; # 0x08 = black
401              
402 20         170 my %patterns = (
403             1 => 'Solid',
404             2 => 'Gray50',
405             3 => 'Gray75',
406             4 => 'Gray25',
407             5 => 'HorzStripe',
408             6 => 'VertStripe',
409             7 => 'ReverseDiagStripe',
410             8 => 'DiagStripe',
411             9 => 'DiagCross',
412             10 => 'ThickDiagCross',
413             11 => 'ThinHorzStripe',
414             12 => 'ThinVertStripe',
415             13 => 'ThinReverseDiagStripe',
416             14 => 'ThinDiagStripe',
417             15 => 'ThinHorzCross',
418             16 => 'ThinDiagCross',
419             17 => 'Gray125',
420             18 => 'Gray0625',
421             );
422              
423 20 100       56 return unless exists $patterns{$self->{_pattern}};
424              
425             return 'ss:Color',
426             $self->convert_to_html_color($self->{_bg_color}),
427             'ss:Pattern',
428             $patterns{$self->{_pattern}},
429             'ss:PatternColor',
430 19         44 $self->convert_to_html_color($self->{_fg_color});
431             }
432              
433              
434             ###############################################################################
435             #
436             # get_num_format_properties()
437             #
438             # Return properties for an Excel XML element.
439             #
440             sub get_num_format_properties {
441              
442 78     78 0 267 my $self = shift;
443              
444 78 100       258 return unless defined $self->{_num_format};
445              
446              
447             # This hash is here mainly to cater for Spreadsheet::WriteExcel programs
448             # and Excel files that use the in-built format codes. ExcelXML users
449             # should specify the format explicitly.
450             #
451 58         879 my %num_format = (
452             1 => '0',
453             2 => 'Fixed',
454             3 => '#,##0',
455             4 => 'Standard',
456             5 => '$#,##0;\-$#,##0',
457             6 => '$#,##0;[Red]\-$#,##0',
458             7 => '$#,##0.00;\-$#,##0.00',
459             8 => 'Currency',
460             9 => '0%',
461             10 => 'Percent',
462             11 => 'Scientific',
463             12 => '#\ ?/?',
464             13 => '#\ ??/??',
465             14 => 'Short Date',
466             15 => 'Medium Date',
467             16 => 'dd\-mmm',
468             17 => 'mmm\-yy',
469             18 => 'Medium Time',
470             19 => 'Long Time',
471             20 => 'Short Time',
472             21 => 'hh:mm:ss',
473             22 => 'General Date',
474             37 => '#,##0;\-#,##0',
475             38 => '#,##0;[Red]\-#,##0',
476             39 => '#,##0.00;\-#,##0.00',
477             40 => '#,##0.00;[Red]\-#,##0.00',
478             41 => '_-* #,##0_-;\-* #,##0_-;_-* "-"_-;_-@_-',
479             42 => '_-$* #,##0_-;\-$* #,##0_-;_-$* "-"_-;_-@_-',
480             43 => '_-* #,##0.00_-;\-* #,##0.00_-;_-* "-"??_-;_-@_-',
481             44 => '_-$* #,##0.00_-;\-$* #,##0.00_-;_-$* "-"??_-;_-@_-',
482             45 => 'mm:ss',
483             46 => '[h]:mm:ss',
484             47 => 'mm:ss.0',
485             48 => '##0.0E+0',
486             49 => '@',
487             );
488              
489 58         97 my $num_format;
490              
491             # Num_format is either a built-in code or a user specified string.
492 58 100       157 if (exists $num_format{$self->{_num_format}}) {
493 35         69 $num_format = $num_format{$self->{_num_format}};
494             }
495             else {
496 23         46 $num_format = $self->{_num_format};
497             }
498              
499 58         379 return 'ss:Format', $num_format;
500             }
501              
502              
503             ###############################################################################
504             #
505             # get_protection_properties()
506             #
507             # Return properties for an Excel XML element.
508             #
509             sub get_protection_properties {
510              
511 26     26 0 76 my $self = shift;
512              
513 26         49 my @attribs; # Attributes to return
514              
515 26 100       81 push @attribs, 'x:HideFormula', 1 if $self->{_hidden};
516 26 100       105 push @attribs, 'ss:Protected', 0 if not $self->{_locked};
517              
518 26         106 return @attribs;
519             }
520              
521              
522             ###############################################################################
523             #
524             # get_xf_index()
525             #
526             # Returns the index used by Worksheet->_XF()
527             #
528             sub get_xf_index {
529 86     86 0 179 my $self = shift;
530              
531 86         342 return $self->{_xf_index};
532             }
533              
534              
535             ###############################################################################
536             #
537             # _get_color()
538             #
539             # Used in conjunction with the set_xxx_color methods to convert a color
540             # string into a number. Color range is 0..63 but we will restrict it
541             # to 8..63 to comply with Gnumeric. Colors 0..7 are repeated in 8..15.
542             #
543             sub _get_color {
544              
545 57     57   465 my %colors = (
546             aqua => 0x0F,
547             cyan => 0x0F,
548             black => 0x08,
549             blue => 0x0C,
550             brown => 0x10,
551             magenta => 0x0E,
552             fuchsia => 0x0E,
553             gray => 0x17,
554             grey => 0x17,
555             green => 0x11,
556             lime => 0x0B,
557             navy => 0x12,
558             orange => 0x35,
559             purple => 0x14,
560             red => 0x0A,
561             silver => 0x16,
562             white => 0x09,
563             yellow => 0x0D,
564             );
565              
566             # Return the default color if undef,
567 57 50       149 return 0x00 unless defined $_[0];
568              
569             # or the color string converted to an integer,
570 57 100       438 return $colors{lc($_[0])} if exists $colors{lc($_[0])};
571              
572             # or the default color if string is unrecognised,
573 15 50       42 return 0x00 if ($_[0] =~ m/\D/);
574              
575             # or an index < 8 mapped into the correct range,
576 15 50       50 return $_[0] + 8 if $_[0] < 8;
577              
578             # or the default color if arg is outside range,
579 15 50       33 return 0x00 if $_[0] > 63;
580              
581             # or an integer in the valid range
582 15         156 return $_[0];
583             }
584              
585              
586             ###############################################################################
587             #
588             # set_align()
589             #
590             # Set cell alignment.
591             #
592             sub set_align {
593              
594 21     21 0 50 my $self = shift;
595 21         41 my $location = $_[0];
596              
597 21 50       54 return if not defined $location; # No default
598 21 50       62 return if $location =~ m/\d/; # Ignore numbers
599              
600 21         49 $location = lc($location);
601              
602 21 100       65 $self->set_text_h_align(1) if ($location eq 'left');
603 21 50       46 $self->set_text_h_align(2) if ($location eq 'centre');
604 21 100       53 $self->set_text_h_align(2) if ($location eq 'center');
605 21 100       45 $self->set_text_h_align(3) if ($location eq 'right');
606 21 100       43 $self->set_text_h_align(4) if ($location eq 'fill');
607 21 100       56 $self->set_text_h_align(5) if ($location eq 'justify');
608 21 100       64 $self->set_text_h_align(6) if ($location eq 'center_across');
609 21 50       52 $self->set_text_h_align(6) if ($location eq 'centre_across');
610 21 50       46 $self->set_text_h_align(6) if ($location eq 'merge'); # S:WE name
611 21 100       42 $self->set_text_h_align(7) if ($location eq 'distributed');
612 21 50       43 $self->set_text_h_align(7) if ($location eq 'equal_space'); # ParseExcel
613              
614              
615 21 100       51 $self->set_text_v_align(0) if ($location eq 'top');
616 21 50       47 $self->set_text_v_align(1) if ($location eq 'vcentre');
617 21 100       65 $self->set_text_v_align(1) if ($location eq 'vcenter');
618 21 100       49 $self->set_text_v_align(2) if ($location eq 'bottom');
619 21 100       45 $self->set_text_v_align(3) if ($location eq 'vjustify');
620 21 100       51 $self->set_text_v_align(4) if ($location eq 'vdistributed');
621 21 50       188 $self->set_text_v_align(4) if ($location eq 'vequal_space'); # ParseExcel
622             }
623              
624              
625             ###############################################################################
626             #
627             # set_valign()
628             #
629             # Set vertical cell alignment. This is required by the set_properties() method
630             # to differentiate between the vertical and horizontal properties.
631             #
632             sub set_valign {
633              
634 1     1 0 3 my $self = shift;
635 1         4 $self->set_align(@_);
636             }
637              
638              
639             ###############################################################################
640             #
641             # set_center_across()
642             #
643             # Implements the Excel5 style "merge".
644             #
645             sub set_center_across {
646              
647 0     0 0 0 my $self = shift;
648              
649 0         0 $self->set_text_h_align(6);
650             }
651              
652              
653             ###############################################################################
654             #
655             # set_merge()
656             #
657             # This was the way to implement a merge in Excel5. However it should have been
658             # called "center_across" and not "merge".
659             # This is now deprecated. Use set_center_across() or better merge_range().
660             #
661             #
662             sub set_merge {
663              
664 1     1 0 4 my $self = shift;
665              
666 1         7 $self->set_text_h_align(6);
667             }
668              
669              
670             ###############################################################################
671             #
672             # set_bold()
673             #
674             # Unlike the binary format in Spreadsheet::WriteExcel bold cannot have a
675             # "weight". In the XML format it is either on or off.
676             #
677             sub set_bold {
678              
679 13     13 0 36 my $self = shift;
680 13         26 my $bold = shift;
681              
682 13 50       49 $bold = 1 if not defined $bold;
683              
684 13 50       144 $self->{_bold} = $bold ? 1 : 0;
685             }
686              
687              
688             ###############################################################################
689             #
690             # set_border($style)
691             #
692             # Set cells borders to the same style
693             #
694             sub set_border {
695              
696 4     4 0 11 my $self = shift;
697 4         10 my $style = $_[0];
698              
699 4         30 $self->set_bottom($style);
700 4         34 $self->set_top($style);
701 4         21 $self->set_left($style);
702 4         16 $self->set_right($style);
703             }
704              
705              
706             ###############################################################################
707             #
708             # set_border_color($color)
709             #
710             # Set cells border to the same color
711             #
712             sub set_border_color {
713              
714 1     1 0 3 my $self = shift;
715 1         3 my $color = $_[0];
716              
717 1         10 $self->set_bottom_color($color);
718 1         8 $self->set_top_color($color);
719 1         9 $self->set_left_color($color);
720 1         6 $self->set_right_color($color);
721             }
722              
723              
724             ###############################################################################
725             #
726             # set_rotation($angle)
727             #
728             # Set the rotation angle of the text. An alignment property.
729             #
730             sub set_rotation {
731              
732 6     6 0 13 my $self = shift;
733 6         12 my $rotation = $_[0];
734              
735             # Argument should be a number
736 6 50       39 return if $rotation !~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/;
737              
738             # The arg type can be a double but the Excel dialog only allows integers.
739 6         58 $rotation = int $rotation;
740              
741 6 100 33     63 if ($rotation == 270) {
    50          
742             # Special case inherited from the S::WE interface.
743 1         3 $self->{_text_vertical} = 1;
744 1         3 $self->{_rotation} = 0;
745             return
746 1         7 }
747             elsif ($rotation < -90 or $rotation > 90) {
748 0         0 carp "Rotation $rotation outside range: -90 <= angle <= 90";
749 0         0 $self->{_rotation} = 0;
750 0         0 return;
751             }
752              
753             # Rotation and vertical text are mutually exclusive
754 5         13 $self->{_text_vertical} = 0;
755 5         39 $self->{_rotation} = $rotation;
756             }
757              
758              
759             ###############################################################################
760             #
761             # set_properties()
762             #
763             # Convert hashes of properties to method calls.
764             #
765             sub set_properties {
766              
767 214     214 0 1587 my $self = shift;
768              
769 214         532 while (@_) {
770 257         469 my $key = shift @_;
771 257         408 my $value = shift @_;
772              
773             # Strip leading "-" from Tk style properties eg. -color => 'red'.
774 257         549 $key =~ s/^-//;
775              
776              
777             # Make sure method names are alphanumeric characters only, in case
778             # tainted data is passed to the eval().
779             #
780 257 50       1008 die "Unknown method: \$self->set_$key\n" if $key =~ /\W/;
781              
782              
783             # Evaling $value as a string gets around the problem of some
784             # numerical format strings being evaluated as numbers, for example
785             # "00000" for a zip code.
786             #
787 257 50       615 if (defined $value) {
788 257         16385 eval "\$self->set_$key('$value')";
789             }
790             else {
791 0         0 eval "\$self->set_$key(undef)";
792             }
793              
794 257 50       1382 die $@ if $@; # Re-throw the eval error.
795             }
796             }
797              
798              
799             ###############################################################################
800             #
801             # AUTOLOAD. Deus ex machina.
802             #
803             # Dynamically create set methods that aren't already defined.
804             #
805             sub AUTOLOAD {
806              
807 299     299   604 my $self = shift;
808              
809             # Ignore calls to DESTROY
810 299 100       6298 return if $AUTOLOAD =~ /::DESTROY$/;
811              
812             # Check for a valid method names, ie. "set_xxx_yyy".
813 62 50       349 $AUTOLOAD =~ /.*::set(\w+)/ or die "Unknown method: $AUTOLOAD\n";
814              
815             # Match the attribute, ie. "_xxx_yyy".
816 62         190 my $attribute = $1;
817              
818             # Check that the attribute exists
819 62 50       199 exists $self->{$attribute} or die "Unknown method: $AUTOLOAD\n";
820              
821             # The attribute value
822 62         99 my $value;
823              
824              
825             # There are two types of set methods: set_property() and
826             # set_property_color(). When a method is AUTOLOADED we store a new anonymous
827             # sub in the appropriate slot in the symbol table. The speeds up subsequent
828             # calls to the same method.
829             #
830 23     23   268 no strict 'refs'; # To allow symbol table hackery
  23         60  
  23         5191  
831              
832 62 100       189 if ($AUTOLOAD =~ /.*::set\w+color$/) {
833             # For "set_property_color" methods
834 12         39 $value = _get_color($_[0]);
835              
836 12         56 *{$AUTOLOAD} = sub {
837 45     45   99 my $self = shift;
838              
839 45         117 $self->{$attribute} = _get_color($_[0]);
840 12         53 };
841             }
842             else {
843              
844 50         119 $value = $_[0];
845 50 50       110 $value = 1 if not defined $value; # The default value is always 1
846              
847 50         256 *{$AUTOLOAD} = sub {
848 146     146   323 my $self = shift;
849 146         223 my $value = shift;
850              
851 146 50       353 $value = 1 if not defined $value;
852 146         973 $self->{$attribute} = $value;
853 50         217 };
854             }
855              
856              
857 62         612 $self->{$attribute} = $value;
858             }
859              
860              
861             1;
862              
863              
864             __END__