File Coverage

blib/lib/Wx/Perl/TreeView.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Wx::Perl::TreeView;
2              
3             =head1 NAME
4              
5             Wx::Perl::TreeView - virtual tree control interface
6              
7             =head1 DESCRIPTION
8              
9             C provides a "virtual" tree control, similar to
10             a virtual C. All the data access methods are contained
11             inside C. C forwards
12             all unknown method calls to the contained C.
13              
14             =cut
15              
16 1     1   1399 use Wx;
  0            
  0            
17              
18             use strict;
19             use base qw(Wx::EvtHandler);
20              
21             our $VERSION = '0.02';
22              
23             use Wx::Event qw(EVT_TREE_ITEM_EXPANDING);
24              
25             =head2 new
26              
27             my $treeview = Wx::Perl::TreeView->new( $tree_control, $model );
28              
29             Constructs a new C instance using the previously
30             constructed tree control and model.
31              
32             =cut
33              
34             sub new {
35             my( $class, $tree, $model ) = @_;
36             my $self = $class->SUPER::new;
37              
38             $self->{treectrl} = $tree;
39             $self->{model} = $model;
40              
41             $tree->PushEventHandler( $self );
42              
43             # FIXME work around wxWidgets bug :-(
44             my $target = Wx::wxMSW || Wx::wxVERSION >= 2.009 ?
45             $self : $tree;
46             EVT_TREE_ITEM_EXPANDING( $target, $tree,
47             sub { $self->_on_item_expanding( $_[1]->GetItem );
48             $_[1]->Skip;
49             } );
50              
51             $self->reload;
52              
53             return $self;
54             }
55              
56             sub _on_item_expanding {
57             my( $self, $item ) = @_;
58             my $tree = $self->treectrl;
59             my $model = $self->model;
60             my $cookie = $tree->GetPlData( $item )->{cookie};
61              
62             $tree->DeleteChildren( $item );
63              
64             my $count = $model->get_child_count( $cookie );
65             if( $count == 0 ) {
66             $tree->SetItemHasChildren( $item, 0 );
67             return;
68             }
69              
70             for( my $i = 0; $i < $count; ++$i ) {
71             my( $ccookie, $cstring, $cimage, $ccdata ) =
72             $model->get_child( $cookie, $i );
73              
74             my $child = $tree->AppendItem
75             ( $item, $cstring, ( defined $cimage ? $cimage : -1 ), -1,
76             Wx::TreeItemData->new( { cookie => $ccookie, data => $ccdata } ) );
77             $tree->SetItemHasChildren( $child, $model->has_children( $ccookie ) );
78             }
79             }
80              
81             =head2 reload
82              
83             $treeview->reload;
84              
85             Deletes all tree items and readds root node(s) from the model.
86              
87             =cut
88              
89             sub reload {
90             my( $self ) = @_;
91             my( $model, $tree ) = ( $self->model, $self->treectrl );
92             $self->DeleteAllItems;
93              
94             my( $cookie, $string, $image, $data ) = $model->get_root;
95             my $root = $tree->AddRoot
96             ( $string, ( defined $image ? $image : -1 ), -1,
97             Wx::TreeItemData->new( { cookie => $cookie, data => $data } ) );
98             $tree->SetItemHasChildren( $root, $model->has_children( $cookie ) );
99              
100             if( $tree->GetWindowStyleFlag & Wx::wxTR_HIDE_ROOT() ) {
101             $self->_on_item_expanding( $root );
102             }
103             }
104              
105             =head2 refresh
106              
107             my $refreshed = $treeview->refresh;
108             my $refreshed = $treeview->refresh( [ $treeitemid1, $treeitemid2, ... ] );
109              
110             Walks the tree and refreshes data from the expanded tree
111             branches. Returns C on success.
112              
113             If one of the expanded nodes has a different child count in the model
114             and in the tree, calls C and returns C.
115              
116             If a list of C is passed as argument, te child count
117             of these nodes is not checked against the model, and after refreshing
118             these nodes are expanded.
119              
120             =cut
121              
122             sub refresh {
123             my( $self, $is_expanding ) = @_;
124             $is_expanding ||= [];
125              
126             my( $model, $tree ) = ( $self->model, $self->treectrl );
127              
128             my( $cookie, $string, $image ) = $model->get_root;
129             my( $can_refresh, $data ) = $self->_check( $tree->GetRootItem, $cookie,
130             $string, $image,
131             $is_expanding );
132             if( $can_refresh ) {
133             $self->_refresh( $tree->GetRootItem, $data );
134             } else {
135             $self->reload;
136             }
137             $self->_on_item_expanding( $_ ) foreach @$is_expanding;
138              
139             return $can_refresh;
140             }
141              
142             sub _check {
143             my( $self, $pitem, $pcookie, $pstring, $pimage, $pcdata,
144             $is_expanding ) = @_;
145             my( $model, $tree ) = ( $self->model, $self->treectrl );
146             my $data = { text => $pstring,
147             image => $pimage,
148             cookie => $pcookie,
149             data => $pcdata,
150             childs => [],
151             };
152             return ( 1, $data ) if grep $_ == $pitem, @$is_expanding;
153             return ( 1, $data ) unless $tree->IsExpanded( $pitem );
154             my $cchilds = $tree->GetChildrenCount( $pitem, 0 );
155             my $mchilds = $model->get_child_count( $pcookie );
156              
157             return ( 0, undef ) if $cchilds != $mchilds;
158              
159             my( $child, $cookie ) = $tree->GetFirstChild( $pitem );
160             my $index = 0;
161             while( $child->IsOk ) {
162             my( $ccookie, $cstring, $cimage, $ccdata ) =
163             $model->get_child( $pcookie, $index );
164             my( $can_refresh, $cdata ) = $self->_check
165             ( $child, $ccookie, $cstring, $cimage, $ccdata, $is_expanding );
166             return ( 0, undef ) unless $can_refresh;
167             push @{$data->{childs}}, $cdata;
168             ( $child, $cookie ) = $tree->GetNextChild( $pitem, $cookie );
169             ++$index;
170             }
171              
172             return ( 1, $data );
173             }
174              
175             sub _refresh {
176             my( $self, $item, $data ) = @_;
177             my $tree = $self->treectrl;
178              
179             $tree->SetItemText( $item, $data->{text} );
180             $tree->SetItemImage( $item, defined $data->{image} ? $data->{image} : -1 );
181             $tree->SetPlData( $item, { cookie => $data->{cookie},
182             data => $data->{data},
183             } );
184              
185             return unless $tree->IsExpanded( $item );
186              
187             my( $child, $cookie ) = $tree->GetFirstChild( $item );
188             my $index = 0;
189             while( $child->IsOk ) {
190             $self->_refresh( $child, $data->{childs}[$index] );
191             ( $child, $cookie ) = $tree->GetNextChild( $item, $cookie );
192             ++$index;
193             }
194             }
195              
196             =head2 get_cookie
197              
198             my $cookie = $treeview->get_cookie( $treeitemid );
199              
200             Returns the cookie associated with the given C.
201              
202             =cut
203              
204             sub get_cookie {
205             my( $self, $item ) = @_;
206              
207             return $self->treectrl->GetPlData( $item )->{cookie};
208             }
209              
210             =head2 treectrl
211              
212             my $treectrl = $treeview->treectrl;
213              
214             =head2 model
215              
216             my $model = $treeview->model;
217              
218             =cut
219              
220             sub treectrl { $_[0]->{treectrl} }
221             sub model { $_[0]->{model} }
222              
223             sub GetPlData {
224             my( $self, $item ) = @_;
225              
226             return $self->treectrl->GetPlData( $item )->{data};
227             }
228              
229             sub SetPlData {
230             my( $self, $item, $data ) = @_;
231              
232             $self->treectrl->GetPlData( $item )->{data} = $data;
233             }
234              
235             our $AUTOLOAD;
236             sub AUTOLOAD {
237             my( $self ) = shift;
238             ( my $name = $AUTOLOAD ) =~ s/.*:://;
239             return unless $self->{treectrl}; # global destruction
240             $self->{treectrl}->$name( @_ );
241             }
242              
243             1;
244              
245             __END__