File Coverage

blib/lib/Tk/DataTree.pm
Criterion Covered Total %
statement 16 19 84.2
branch 3 6 50.0
condition n/a
subroutine 4 4 100.0
pod n/a
total 23 29 79.3


line stmt bran cond sub pod time code
1             ################################################################################
2             #
3             # MODULE: Tk::DataTree
4             #
5             ################################################################################
6             #
7             # DESCRIPTION: Tk::DataTree Perl extension module
8             #
9             ################################################################################
10             #
11             # $Project: /Tk-DataTree $
12             # $Author: mhx $
13             # $Date: 2008/01/11 00:18:49 +0100 $
14             # $Revision: 10 $
15             # $Snapshot: /Tk-DataTree/0.06 $
16             # $Source: /lib/Tk/DataTree.pm $
17             #
18             ################################################################################
19             #
20             # Copyright (c) 2004-2008 Marcus Holland-Moritz. All rights reserved.
21             # This program is free software; you can redistribute it and/or modify
22             # it under the same terms as Perl itself.
23             #
24             ################################################################################
25              
26             package Tk::DataTree;
27              
28 1     1   6699 use strict;
  1         3  
  1         43  
29 1     1   5 use vars qw($VERSION);
  1         1  
  1         357  
30              
31             BEGIN {
32 1 50   1   2 $VERSION = do { my @r = '$Snapshot: /Tk-DataTree/0.06 $' =~ /(\d+\.\d+(?:_\d+)?)/; @r ? $r[0] : '9.99' };
  1         14  
  1         6  
33 1         2 eval {
34 1 50       11 local $ENV{PERL_DL_NONLAZY} = 0 if $ENV{PERL_DL_NONLAZY};
35 1         6 require DynaLoader;
36 1         25 local @Tk::DataTree::ISA = qw(DynaLoader);
37 1         425 bootstrap Tk::DataTree $VERSION;
38             };
39              
40             # use a rather simple approximation if we don't have the XS...
41 1 50       30 $@ and *_getval = sub { $_[0] };
  0         0  
42             }
43              
44 1     1   1686 use Tk;
  0            
  0            
45             use Tk::ItemStyle;
46             use Tk::widgets qw(Tree);
47             use base qw(Tk::Tree);
48             use constant ROOTTYPE => 'TYPE';
49              
50             Construct Tk::Widget 'DataTree';
51              
52             my %ICON = (
53             file => <<'FILE',
54             /* XPM */
55             static char *file[] = {
56             /* width height num_colors chars_per_pixel */
57             " 17 18 17 1",
58             /* colors */
59             " c None",
60             ". c #000000",
61             "# c #808080",
62             "a c #800000",
63             "b c #808000",
64             "c c #008000",
65             "d c #008080",
66             "e c #000080",
67             "f c #800080",
68             "g c #ffffff",
69             "h c #c0c0c0",
70             "i c #ff0000",
71             "j c #ffff00",
72             "k c #00ff00",
73             "l c #00ffff",
74             "m c #0000ff",
75             "n c #ff00ff",
76             /* pixels */
77             " ",
78             " . . . . . ",
79             " .g#g#g#g#g. ",
80             " #g.g.g.g.g.g. ",
81             " #ggggggggggh. ",
82             " #ggggggggggh. ",
83             " #gg...g..ggh. ",
84             " #ggggggggggh. ",
85             " #gg......ggh. ",
86             " #ggggggggggh. ",
87             " #gg......ggh. ",
88             " #ggggggggggh. ",
89             " #gg......ggh. ",
90             " #ggggggggggh. ",
91             " #ggggggggggh. ",
92             " #hhhhhhhhhhh. ",
93             " ........... ",
94             " "
95             };
96             FILE
97              
98             folder => <<'FOLDER',
99             /* XPM */
100             static char *folder[] = {
101             /* width height num_colors chars_per_pixel */
102             " 17 15 17 1",
103             /* colors */
104             " c none",
105             ". c #000000",
106             "# c #808080",
107             "a c #800000",
108             "b c #808000",
109             "c c #008000",
110             "d c #008080",
111             "e c #000080",
112             "f c #800080",
113             "g c #ffffff",
114             "h c #c0c0c0",
115             "i c #ff0000",
116             "j c #ffff00",
117             "k c #00ff00",
118             "l c #00ffff",
119             "m c #0000ff",
120             "n c #ff00ff",
121             /* pixels */
122             " ",
123             " ##### ",
124             " #hjhjh# ",
125             " #hjhjhjh###### ",
126             " #gggggggggggg#. ",
127             " #gjhjhjhjhjhj#. ",
128             " #ghjhjhjhjhjh#. ",
129             " #gjhjhjhjhjhj#. ",
130             " #ghjhjhjhjhjh#. ",
131             " #gjhjhjhjhjhj#. ",
132             " #ghjhjhjhjhjh#. ",
133             " #gjhjhjhjhjhj#. ",
134             " ##############. ",
135             " .............. ",
136             " ",
137             };
138             FOLDER
139             );
140              
141             sub ClassInit
142             {
143             my($class, $mw) = @_;
144             $class->SUPER::ClassInit($mw);
145             $mw->bind($class, '', 'Destroyer');
146             return $class;
147             }
148              
149             sub Populate
150             {
151             my($self, $args) = @_;
152              
153             $args->{-selectmode} ||= 'none';
154             $args->{-itemtype} ||= 'imagetext';
155             $args->{-separator} ||= '/';
156              
157             $self->SUPER::Populate($args);
158              
159             for my $pix (keys %ICON) {
160             $self->Pixmap($pix, data => $ICON{$pix});
161             }
162              
163             for my $style (qw(node normal active undef)) {
164             $self->{"_s$style"} = $self->ItemStyle('imagetext');
165             $self->Advertise("${style}style" => $self->{"_s$style"});
166             }
167              
168             $self->ConfigSpecs(
169             '-data' => ['METHOD', undef, undef, undef],
170             '-typename' => ['METHOD', undef, undef, undef],
171             '-activecolor' => ['METHOD', undef, undef, '#FF0000'],
172             '-undefcolor' => ['METHOD', undef, undef, '#0080FF'],
173             );
174             }
175              
176             sub Destroyer
177             {
178             my $self = shift;
179             for my $style (qw(node normal active undef)) {
180             $self->{"_s$style"}->delete;
181             }
182             }
183              
184             sub typename
185             {
186             my($self, $val) = @_;
187             if (@_ > 1) {
188             if ($self->info('exists', ROOTTYPE) &&
189             $self->itemCget(ROOTTYPE, 0, '-text') eq $self->{_oldtype}) {
190             $self->itemConfigure(ROOTTYPE, 0, -text => $val);
191             }
192             $self->{_typename} = $val;
193             }
194             $self->{_typename};
195             }
196              
197             sub activecolor
198             {
199             my($self, $val) = @_;
200             if (@_ > 1) {
201             $self->{_sactive}->configure(-fg => $val);
202             }
203             $self->{_sactive}->cget('-fg');
204             }
205              
206             sub undefcolor
207             {
208             my($self, $val) = @_;
209             if (@_ > 1) {
210             $self->{_sundef}->configure(-fg => $val);
211             }
212             $self->{_sundef}->cget('-fg');
213             }
214              
215             sub data
216             {
217             my($self, $data) = @_;
218              
219             if (@_ > 1) {
220             my $t = $self->{_typename} || (ref $data ? "$data" : ROOTTYPE);
221              
222             if (exists $self->{_old}) {
223             $self->{_old} = $self->_cleanup(ROOTTYPE, $data, $self->{_old});
224             }
225              
226             my $isnode = ref($data) =~ /^(?:ARRAY|HASH)$/;
227              
228             $self->info('exists', ROOTTYPE) or $self->add(ROOTTYPE);
229             $self->itemConfigure(ROOTTYPE, 0, -text => $t,
230             -image => $isnode ? 'folder' : 'file',
231             -style => $isnode ? $self->{_snode} : $self->{_snormal});
232              
233             $self->{_data} = $data;
234             $self->{_old} = $self->_refresh(ROOTTYPE, $data, $self->{_old});
235             $self->{_oldtype} = $t;
236             }
237             $self->{_data};
238             }
239              
240             sub _cleanup
241             {
242             my($self, $pre, $val, $old) = @_;
243              
244             my $r = ref $old;
245             my $useval = $val && $r eq ref $val;
246              
247             if ($r eq 'HASH') {
248             for my $k (keys %$old) {
249             my $path = "$pre/$k";
250             if ($useval && exists $val->{$k}) {
251             if (ref $val->{$k} or ref $old->{$k}) {
252             $old->{$k} = $self->_cleanup($path, $val->{$k}, $old->{$k});
253             }
254             }
255             else {
256             $self->delete('entry', $path);
257             delete $old->{$k};
258             }
259             }
260             }
261             elsif ($r eq 'ARRAY') {
262             for my $k (0 .. $#$old) {
263             my $path = "$pre/$k";
264             if ($useval && $k < @$val) {
265             if (ref $val->[$k] or ref $old->[$k]) {
266             $old->[$k] = $self->_cleanup($path, $val->[$k], $old->[$k]);
267             }
268             }
269             else {
270             $self->delete('entry', $path);
271             }
272             }
273             if ($useval && @$val < @$old) {
274             $#$old = $#$val;
275             }
276             }
277              
278             unless ($useval) {
279             $self->delete( 'entry', $pre );
280             return undef;
281             }
282              
283             return $old;
284             }
285            
286             sub _refresh
287             {
288             my($self, $pre, $val, $old, $key) = @_;
289              
290             my $r = ref $val;
291             my $req = $r eq ref $old;
292              
293             if ($r eq 'HASH') {
294             while (my($k,$v) = each %$val) {
295             my $o = $req ? $old->{$k} : undef;
296             my $path = "$pre/$k";
297             if (ref $v) {
298             $self->info('exists', $path)
299             or $self->add($path, -text => $k, -image => 'folder', -style => $self->{_snode});
300             }
301             $old->{$k} = $self->_refresh($path, $v, $o, $k);
302             }
303             }
304             elsif ($r eq 'ARRAY') {
305             for my $k (0 .. $#$val) {
306             my $path = "$pre/$k";
307             if (ref $val->[$k]) {
308             $self->info('exists', $path)
309             or $self->add($path, -text => "[$k]", -image => 'folder', -style => $self->{_snode});
310             }
311             $old->[$k] = $self->_refresh($path, $val->[$k], $req ? $old->[$k] : undef, "[$k]");
312             }
313             }
314             else {
315             my($v, $style);
316             if (defined $val) {
317             $v = _getval($val);
318             $style = defined($old) && $v eq $old ? $self->{_snormal} : $self->{_sactive};
319             }
320             else {
321             $v = '[undef]';
322             $style = $self->{_sundef};
323             }
324             unless ($self->info('exists', $pre)) {
325             $self->add($pre, -image => 'file');
326             }
327             $self->itemConfigure($pre, 0, -text => defined $key ? "$key: $v" : $v,
328             -style => $style);
329             $old = $v;
330             }
331              
332             return $old;
333             }
334              
335             1;
336              
337             __END__