File Coverage

blib/lib/RTF/Writer/TableRowDecl.pm
Criterion Covered Total %
statement 102 128 79.6
branch 46 82 56.1
condition 22 42 52.3
subroutine 10 13 76.9
pod 0 8 0.0
total 180 273 65.9


line stmt bran cond sub pod time code
1              
2             require 5;
3             package RTF::Writer::TableRowDecl;
4 6     6   28 use strict; # Time-stamp: "2003-09-23 21:26:40 ADT"
  6         9  
  6         184  
5 6     6   30 use Carp ();
  6         11  
  6         681  
6              
7             BEGIN {
8 6 50   6   42 if(defined &DEBUG) { } # nil
    50          
9 6         169 elsif(defined &RTF::Writer::DEBUG) { *DEBUG = \&RTF::Writer::DEBUG }
10 0         0 else { *DEBUG = sub(){0} }
11             }
12             #--------------------------------------------------------------------------
13              
14 6     6   29 use vars qw($DEFAULT_BORDER_WIDTH %Directions %Align_Directions);
  6         11  
  6         15612  
15             $DEFAULT_BORDER_WIDTH ||= 15;
16              
17             unless(keys %Directions) {
18             @Directions{qw(N S E W)} = (0 .. 3);
19             @Directions{qw(n s e w)} = (0 .. 3);
20             @Directions{qw(T B R L)} = (0 .. 3);
21             @Directions{qw(t b r l)} = (0 .. 3);
22             }
23             # N S E W
24             my(@tabledirs) = qw( t b r l );
25              
26             unless(keys %Align_Directions) { for my $d (\%Align_Directions) {
27             # First char is vertical, second is horiz
28              
29             @$d{qw(NW N NE)} = qw(tl tc tr);
30             @$d{qw(W C E)} = qw(cl cc cr);
31             @$d{qw(SW S SE)} = qw(bl bc br);
32              
33             @$d{qw(WN EN)} = qw(tl tr);
34             @$d{qw(WS ES)} = qw(bl br);
35              
36             @$d{qw(TL T TR)} = qw(tl tc tr);
37             @$d{qw(L C R)} = qw(cl cc cr);
38             @$d{qw(BL B BR)} = qw(bl bc br);
39              
40             @$d{qw(LT RT)} = qw(tl tr);
41             @$d{qw(LB RB)} = qw(bl br);
42              
43             @$d{map lc($_), keys %$d}
44             = values %$d;
45             }}
46              
47             #--------------------------------------------------------------------------
48             # INSIDES:
49             # 0: the right-ends table
50             # 1: the left-margin setting
51             # 2: the inbetween setting
52             # 3: a list of border settings
53             # 4: a list of valign settings
54             # 5: a list of halign settings
55             # 6: the cached decl string
56              
57             sub new {
58 5     5 0 53 my($it, %h) = @_;
59 5         7 my $new;
60              
61             my(@reaches);
62 5 50       13 if(ref $it) { # clone
63 0         0 $new = $it->clone();
64             } else {
65 5   50     84 $new = bless [
      50        
66             \@reaches,
67             int( $h{'left_start'}||0 ) || 0,
68             int( $h{'inbetween' }||0 ) || 120, # 6 points, 1/12th-inch, about 2mm
69             ];
70             }
71            
72 5         7 my $x; # scratch
73 5 50       31 if($x = $h{'widths'}) {
    50          
74 0 0       0 Carp::croak("'widths' value has to be an arrayref")
75             unless ref($x) eq 'ARRAY';
76 0         0 my $start = $new->[1];
77 0         0 foreach my $w (map int($_), @$x) {
78 0 0       0 push @reaches, ($start += ($w < 1 ) ? 1 : $w);
79             }
80             } elsif($x = $h{'reaches'}) {
81 0 0       0 Carp::croak("'reaches' value has to be an arrayref")
82             unless ref($h{'reaches'}) eq 'ARRAY';
83 0         0 @reaches = sort {$a <=> $b} map int($_), @$x;
  0         0  
84             }
85              
86             $new->make_border_decl(
87 5 100       26 defined($h{'borders'}) ? $h{'borders'} : $h{'border'}
88             );
89 5 100       28 $new->make_alignment_decl(
90             defined($h{'align'}) ? $h{'align'} : $h{'alignment'}
91             );
92 5         28 return $new;
93             }
94              
95             #--------------------------------------------------------------------------
96              
97             sub clone {
98             # sufficient to our task, I think
99 0         0 bless [ map {;
100 0 0       0 (!defined $_) ? undef
    0          
    0          
101             : (ref($_) eq 'ARRAY') ? [@$_]
102             : (ref($_) eq 'HASH' ) ? {%$_}
103             : $_
104 0     0 0 0 } @{$_[0]}
105             ],
106             ref $_[0];
107             }
108              
109             #--------------------------------------------------------------------------
110              
111             sub make_border_decl {
112 5     5 0 19 my($it, @params) = @_;
113 5         7 my @borders;
114              
115 5         20 $it->[3] = \@borders;
116              
117 5 100 66     42 unless( @params and grep defined($_), @params ) {
118 3         7 @params = ('1');
119             }
120              
121 5 50 33     30 @params = @{$params[0]} if @params == 1 and ref $params[0];
  0         0  
122             # I.e., if they passed border => [...]
123 5 100 66     43 @params = "all-$DEFAULT_BORDER_WIDTH-s"
124             if @params == 1 and $params[0] eq '1';
125             # if they passed just border => 1
126            
127 5         10 foreach my $spec (@params) {
128 5         18 push @borders, $it->_borderspec2bordercode($spec);
129             }
130            
131 5         11 return;
132             }
133             #--------------------------------------------------------------------------
134              
135             sub make_alignment_decl {
136 5     5 0 12 my($it,@alignments) = @_;
137 5         14 my(@valign, @halign);
138 5         12 $it->[4] = \@valign;
139 5         13 $it->[5] = \@halign;
140              
141 5 100 66     36 unless(@alignments and grep defined($_), @alignments) {
142             # most common case: nothing
143 1         2 push @valign, '';
144 1         3 push @halign, '';
145 1         3 return;
146             }
147            
148 4 50       13 if( @alignments != 1) {
    50          
149             # Pass thru (altho normally impossible)
150             } elsif( ref $alignments[0] ) {
151 4         5 @alignments = @{$alignments[0]}
  4         15  
152             # I.e., they passed align => [...]
153             } else {
154 0         0 @alignments = grep length($_), split m/(?:\s*,\s*)|\s+/, $alignments[0];
155             # I.e., they passed in align => 'sw c c t' or 'sw, c, t' or whatever.
156             }
157            
158 4         8 my($x, $v, $h);
159 4         6 foreach my $spec (@alignments) {
160 16 100 66     80 unless(defined $spec and length $spec) {
161 1         9 push @valign, '';
162 1         2 push @halign, '';
163 1         2 DEBUG and printf " - => valign - halign -\n";
164 1         2 next;
165             }
166 15         31 $x = $Align_Directions{$spec};
167 15 50       30 unless($x) {
168 0         0 require Carp;
169 0         0 Carp::croak "Unintelligible alignment spec \"$spec\"";
170             }
171 15 50       39 die "WHAAAAA? [$x]" unless 2 == length $x; # sanity
172 15         42 my($v,$h) = split '', $x;
173 15         34 push @valign, "\\clvertal$v";
174 15         60 push @halign, "\\q$h";
175 15         23 DEBUG and printf "% 2s => valign %s halign %s\n",
176             $spec, $valign[-1], $halign[-1];
177             }
178            
179 4         20 return;
180             }
181              
182             #--------------------------------------------------------------------------
183             sub _borderspec2bordercode {
184              
185 5     5   9 my($it, $spec) = @_;
186              
187 5 50 33     30 $spec = 'all' unless defined $spec and length $spec;
188 5 100       25 return '' if lc($spec) eq 'none';
189            
190 4 50       19 $spec = "all-$spec-s" if $spec =~ m/^\d+$/s;
191              
192 4         13 my @widths = (undef, undef, undef, undef);
193 4         15 my @styles = (undef, undef, undef, undef);
194              
195 4         5 my($dir, $width, $style);
196 4         75 my @specs = split m/(?:,|\s+)/, $spec;
197            
198 4         11 foreach my $it (@specs) {
199 5 50       11 next unless $it;
200              
201 5 50       43 unless( ($dir, $width, $style) = $it =~
202             m/
203             ^\s*
204             (all|[nsewNSEWtbrlTBRL])
205             (?:-(\d+))?
206             (?:-([a-z]+))?
207             \s*
208             $
209             /xs
210             ) {
211 0         0 require Carp;
212 0         0 Carp::croak "Unintelligible cell-border spec \"$spec\"";
213             }
214            
215 5 50 33     43 $width = $DEFAULT_BORDER_WIDTH unless defined $width and length $width;
216              
217             #print " $it => [$dir] [$width] [$style]\n";
218              
219 5   100     15 $style ||= 's';
220            
221 5 100       13 if($dir eq 'all') {
222 3         11 @widths = ($width) x 4;
223 3         13 @styles = ($style) x 4;
224             } else {
225 2         11 $dir = $Directions{$dir};
226 2         4 $widths[$dir] = $width;
227 2         5 $styles[$dir] = $style;
228             }
229             }
230              
231 4         6 my @out;
232 4         12 foreach my $i (0 .. 3) {
233 16 100       36 next unless $styles[$i];
234 14         57 push @out, sprintf '\clbrdr%s\brdrw%s\brdr%s',
235             $tabledirs[$i],
236             $widths[$i],
237             $styles[$i],
238             ;
239             }
240 4         27 return join "\n", @out;
241             }
242              
243             #--------------------------------------------------------------------------
244              
245             sub new_auto_for_rows {
246 0     0 0 0 my $class = shift;
247 0         0 my $max_cols = 1;
248 0         0 foreach my $r (@_) {
249 0 0 0     0 next unless defined $r and ref $r eq 'ARRAY';
250 0 0       0 $max_cols = @$r if @$r > $max_cols;
251             }
252             return
253 0         0 $class->new( 'width' => [ ((6.5 * 1440) / $max_cols) x scalar(@_) ] );
254             }
255              
256             #--------------------------------------------------------------------------
257              
258 0     0 0 0 sub row_count { return scalar @{ $_[0][0] } }
  0         0  
259             # How many rows we were declared to handle
260              
261             #--------------------------------------------------------------------------
262              
263             sub decl_code {
264 5     5 0 7 my $it = shift;
265 5 100       21 return $it->[6] if defined $it->[6];
266            
267 4         6 my $reaches = $it->[0];
268 4   50     24 my $cell_count = int($_[0] || 0) || scalar @$reaches;
269            
270 4 50       14 if($cell_count > @$reaches) {
271             # Uncommon case -- we need to ad-hoc pad this decl.
272 4         8 $reaches = [@$reaches]; # so we won't mutate the original
273 4         14 while(@$reaches < $cell_count) {
274 16 100       40 if(@$reaches == 0) {
    100          
275 4         15 push @$reaches, $it->[1] + 1440;
276             # sane and noticeable default width, I think: 1 inch, 2.54cm
277             } elsif(@$reaches == 1) {
278 4         22 push @$reaches, 2 * $reaches->[0] - $it->[1];
279             # The left-margin setting
280             } else {
281 8         27 push @$reaches, 2 * $reaches->[-1] - $reaches->[-2];
282             # i.e., last + (last - one_before)
283             # DEBUG and printf "Improvised the width %d based on %d,%d\n",
284             # $reaches->[-1], $reaches->[-3], $reaches->[-2];
285             }
286             }
287             }
288 4 50       6 my @borders = @{ $it->[3] || [] };
  4         35  
289 4 50 33     38 push @borders, ($borders[-1]) x ($cell_count - @borders)
290             if @borders > 0 and @borders < $cell_count;
291            
292 4 50       6 my @valign = @{ $it->[4] || [] };
  4         20  
293 4 100 66     27 push @valign , ($valign[-1] ) x ($cell_count - @valign )
294             if @valign > 0 and @valign < $cell_count;
295             # Or should I have it default to a lack of any alignment code?
296            
297 4   50     115 $it->[6] = \join '',
      100        
298             # Cache it for next time (and there usually are many next-times)
299             sprintf("\\trowd\\trleft%d\\trgaph%d\n", $it->[1], int($it->[2] / 2) ),
300             map(
301             sprintf("%s%s\\cellx%d\n",
302             (shift(@borders) ||''),
303             (shift(@valign ) ||''),
304             $_,
305             ),
306             @$reaches
307             ),
308             ;
309 4         10 DEBUG and print "Init code:\n", ${ $it->[6] }, "\n\n";
310 4         33 return $it->[6];
311             }
312              
313             #--------------------------------------------------------------------------
314             sub cell_content_init {
315 5 50   5 0 8 return @{ $_[0][5] || [] };
  5         32  
316             }
317              
318             #--------------------------------------------------------------------------
319             1;
320              
321             __END__