File Coverage

blib/lib/Spreadsheet/WriteExcel/Worksheet/SheetProtection.pm
Criterion Covered Total %
statement 48 48 100.0
branch 10 12 83.3
condition n/a
subroutine 9 9 100.0
pod 1 1 100.0
total 68 70 97.1


line stmt bran cond sub pod time code
1             package Spreadsheet::WriteExcel::Worksheet::SheetProtection;
2              
3 1     1   138041 use 5.005;
  1         5  
  1         41  
4 1     1   6 use strict;
  1         1  
  1         41  
5              
6 1     1   5 use vars '$VERSION';
  1         7  
  1         47  
7              
8             $VERSION = '0.03';
9              
10             BEGIN {
11 1     1   4 use Spreadsheet::WriteExcel::Worksheet;
  1         1  
  1         33  
12 1     1   4 no strict 'refs';
  1         9  
  1         77  
13              
14             ## HACK ALERT!
15             ## Add a _store_eof method to Spreadsheet::WriteExcel::Worksheet to be able to
16             ## add the SHEETPROTECTION record when streaming out file
17 1         10 *{"Spreadsheet::WriteExcel::Worksheet::_store_eof"} = sub {
18 1     1   3852 _store_sheet_protection(@_);
19 1         17 Spreadsheet::WriteExcel::BIFFwriter::_store_eof(@_);
20 1     1   6 } ;
21              
22             ## Add sheet_protection method
23 1         3 *{"Spreadsheet::WriteExcel::Worksheet::sheet_protection"} = \&sheet_protection;
  1         395  
24             }
25              
26              
27             =head1 NAME
28              
29             Spreadsheet::WriteExcel::Worksheet::SheetProtection - Sheet Protection extension
30             for Spreadsheet::WriteExcel::Worksheet
31              
32             =head1 SYNOPSIS
33              
34             use Spreadsheet::WriteExcel;
35             use Spreadsheet::WriteExcel::Worksheet::SheetProtection;
36              
37             my $workbook = new Spreadsheet::WriteExcel("file.xls");
38             my $worksheet = $workbook->add_worksheet;
39            
40             ...
41              
42             # Protect workseet
43             $worksheet->protect;
44            
45             ## Specify protection settings
46             ## Disallow selection of locked cells but allow column formatting
47             $worksheet->sheet_protection(
48             -select_locked_cells => 0,
49             -format_columns => 1 );
50              
51             =head1 DESCRIPTION
52              
53             This module allows you to specify the sheet protection attribute available in recent
54             versions of Microsoft Excel (Menu item: Tools > Protection > Protect Sheet...).
55              
56             It extends the L class by adding a
57             C method which you use to specify the protection attributes.
58              
59             =head2 Protection Flags
60              
61             The following flags can be set (or cleared) to specify which aspects of a
62             worksheet are protected.
63              
64             SelectLockedCells (Default set)
65             SelectUnlockedCells (Default set)
66              
67             FormatCells
68             FormatColumns
69             FormatRows
70              
71             InsertColumns
72             InsertRows
73             InsertHyperlinks
74              
75             DeleteColumns
76             DeleteRows
77              
78             Sort
79              
80             UseAutoFilters
81             UsePivotTableReports
82              
83             EditObjects
84             EditScenarios
85              
86             The flag names are case insensitive and non-letter characters are ignored, so
87             the following are all valid and equivalent:
88              
89             SelectLockedCells
90             "select locked cells"
91             -select_locked_cells
92              
93             =cut
94              
95             my $default_protection = 0x4400; ## 'Select Locked Cells' and 'Select Unlocked Cells'
96             my %protection_flags = (
97             EDITOBJECTS => 0x0001,
98             EDITSCENARIOS => 0x0002,
99             FORMATCELLS => 0x0004,
100             FORMATCOLUMNS => 0x0008,
101              
102             FORMATROWS => 0x0010,
103             INSERTCOLUMNS => 0x0020,
104             INSERTROWS => 0x0040,
105             INSERTHYPERLINKS => 0x0080,
106              
107             DELETECOLUMNS => 0x0100,
108             DELETEROWS => 0x0200,
109             SELECTLOCKEDCELLS => 0x0400,
110             SORT => 0x0800,
111            
112             USEAUTOFILTERS => 0x1000,
113             USEPIVOTTABLEREPORTS => 0x2000,
114             SELECTUNLOCKEDCELLS => 0x4000
115             );
116              
117             =head1 METHODS
118              
119             =head2 sheet_protection()
120              
121             The sheet_protection method sets or returns the current sheetprotection settings.
122              
123             print "0x%04x\n", $worksheet->sheet_protection; ## Default protection is 0x4400
124            
125             ## Allow column formatting but disallow selection of locked cells
126             $worksheet->sheet_protection(0x4008);
127              
128             print "0x%04x\n", $worksheet->sheet_protection; ## Protection is now 0x4008
129              
130             Protection settings can also be specified as a hash. If the value is true, the
131             specified protection is enabled, otherwise it's disabled.
132              
133             ## Allow column formatting but disallow selection of locked cells
134             $worksheet->sheet_protection(
135             -select_locked_cells => 0,
136             -format_columns => 1 );
137              
138             print "0x%04x\n", $worksheet->sheet_protection; ## Protection is now 0x4008
139              
140             $worksheet->sheet_protection( -sort => 1 );
141              
142             print "0x%04x\n", $worksheet->sheet_protection; ## Protection is now 0x4808
143              
144             =cut
145              
146             sub sheet_protection {
147 6     6 1 15680 my $self = shift;
148 6 100       21 my $protection = defined($self->{_sheet_protection})
149             ? $self->{_sheet_protection} : $default_protection;
150              
151 6 100       63 return $protection unless @_;
152              
153 2 100       6 if(scalar (@_) == 1) {
154 1         2 $protection = shift;
155             } else {
156 1         6 my %settings = @_;
157 1         10 while (my ($flag, $value) = each %settings) {
158 2         5 my $key = $flag;
159 2         12 $key =~ s/[^a-z]//gi; # Normalize
160 2         6 $key =~ tr/a-z/A-Z/;
161              
162 2 50       9 my $mask = $protection_flags{$key} or die "Unkown protection setting '$flag'";
163 2 100       6 if($value) {
164 1         6 $protection |= $mask;
165             } else {
166 1         6 $protection &= ~$mask;
167             }
168             }
169             }
170              
171 2         4 $protection &= 0xffff;
172              
173 2         6 $self->{_sheet_protection} = $protection;
174             }
175              
176             sub _store_sheet_protection {
177 1     1   2 my $self = shift;
178              
179             # Exit unless sheet protection has been specified
180 1 50       3 return if $self->sheet_protection == $default_protection;
181              
182 1         3 my $record = 0x0867; # Record identifier
183 1         3 my $data = '';
184              
185 1         3 $data = pack("v", $record); # Repeated record identifier
186 1         3 $data .= pack "x10"; # Not used (OpenOffice spec incorrectly claims 9 bytes)
187 1         2 $data .= pack "C7", 0x02, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff; # Unkown data (OpenOffice spec incorrect)
188 1         4 $data .= pack "v", $self->{_sheet_protection};
189 1         2 $data .= pack "x2"; # Not used
190              
191 1         2 my $header = pack("vv", $record, length($data));
192              
193 1         6 $self->_append($header, $data);
194             }
195              
196             =head1 CAVEATS
197              
198             This module depends on the internal workings of L and has
199             only been tested with version 2.13. It may or may not work with previous version.
200              
201             It would be better if the functionality of this module were directly incorporated
202             into Spreadsheet::WriteExcel::Worksheet, when that happens this module will become
203             obsolete.
204              
205             =head1 SEE ALSO
206              
207             L and L
208              
209             The BIFF record format is based on documentation in L.
210             However, that documentation (as of 5/29/2005) contains some errors.
211              
212             =head1 AUTHOR
213              
214             Stepan Riha, Esriha@cpan.org
215              
216             =head1 COPYRIGHT AND LICENSE
217              
218             Copyright 2005 by Stepan Riha
219              
220             This library is free software; you can redistribute it and/or modify
221             it under the same terms as Perl itself.
222              
223             =cut
224              
225             1;
226              
227             __END__