File Coverage

blib/lib/Wx/Perl/DataWalker.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Wx::Perl::DataWalker;
2 1     1   24583 use 5.008001;
  1         4  
  1         41  
3 1     1   6 use strict;
  1         1  
  1         56  
4 1     1   5 use warnings;
  1         12  
  1         61  
5              
6             our $VERSION = '0.02';
7             our @ISA = qw(Wx::Frame);
8              
9 1     1   6 use Scalar::Util qw(reftype blessed refaddr);
  1         2  
  1         133  
10 1     1   3403 use Devel::Size ();
  0            
  0            
11             use Wx ':everything';
12             use Wx::Event ':everything';
13             require Wx::Perl::DataWalker::CurrentLevel;
14              
15             use Class::XSAccessor
16             getters => {
17             stack => 'stack',
18             },
19             accessors => {
20             current_head => 'current_head',
21             };
22              
23              
24             sub new {
25             my $class = shift;
26             my $config = shift;
27             my $self = $class->SUPER::new(@_);
28              
29             $self->{global_head} = $config->{data} or die "Invalid data";
30             my $rtype = reftype($self->{global_head});
31             die "top-level display of CODE refs not supported!" if defined $rtype and $rtype eq 'CODE';
32              
33             $self->{show_size} = $config->{show_size} || 0;
34             $self->{show_recur_size} = $config->{show_recur_size} || 0;
35            
36             my $hsizer = Wx::BoxSizer->new(Wx::wxHORIZONTAL);
37              
38             # tree view here...
39             # $self->{current_level2} = Wx::Button->new(
40             # $self, -1, "FOOO",
41             # Wx::wxDefaultPosition,
42             # Wx::wxDefaultSize,
43             # );
44             # $hsizer->Add($self->{current_level2}, Wx::wxEXPAND, Wx::wxEXPAND, Wx::wxALL, 2);
45              
46             my $buttonsizer = Wx::BoxSizer->new(Wx::wxHORIZONTAL);
47              
48             $self->{back_button} = Wx::Button->new( $self, -1, "<--" );
49             $self->{reset_button} = Wx::Button->new( $self, -1, "Reset" );
50             EVT_BUTTON( $self, $self->{back_button}, sub { $self->go_back(); } );
51             EVT_BUTTON( $self, $self->{reset_button}, sub { $self->reset_head(); } );
52             $buttonsizer->Add($self->{back_button}, 0, Wx::wxALL|Wx::wxALIGN_CENTER_VERTICAL, 2);
53             $buttonsizer->Add($self->{reset_button}, 0, Wx::wxALL|Wx::wxALIGN_CENTER_VERTICAL, 2);
54              
55             # show-size radio boxes
56             $self->{size_radio_box} = Wx::RadioBox->new(
57             $self, -1, "Show approx. size",
58             Wx::wxDefaultPosition, Wx::wxDefaultSize,
59             [qw(No Yes Total)],
60             Wx::wxRA_SPECIFY_COLS,
61             );
62             EVT_RADIOBOX(
63             $self, $self->{size_radio_box}, sub {
64             my $flag = $_[1]->GetInt();
65             $self->{show_size} = $flag ? 1 : 0;
66             $self->{show_recur_size} = $flag==2 ? 1 : 0;
67             $self->update_size();
68             }
69             );
70             $buttonsizer->Add($self->{size_radio_box}, 0, Wx::wxLEFT|Wx::wxALIGN_CENTER_VERTICAL|Wx::wxALIGN_RIGHT, 10);
71              
72             my $vsizer = Wx::BoxSizer->new(Wx::wxVERTICAL);
73             $vsizer->Add($buttonsizer, 0, Wx::wxEXPAND|Wx::wxALL, 2);
74            
75             # the current level in the tree...
76             my $curl = $self->{current_level} = Wx::Perl::DataWalker::CurrentLevel->new( $self, -1, );
77             $self->update_size();
78             $vsizer->Add($self->{current_level}, Wx::wxEXPAND, Wx::wxEXPAND|Wx::wxALL, 2);
79            
80             $hsizer->Add($vsizer, Wx::wxEXPAND, Wx::wxEXPAND|Wx::wxALL, 2);
81             $self->SetSizer( $hsizer );
82             $hsizer->SetSizeHints( $self );
83              
84             $self->reset_head();
85              
86             return $self;
87             }
88              
89             sub update_size {
90             my $self = shift;
91              
92             my $curl = $self->{current_level};
93             $curl->show_size($self->{show_size});
94             $curl->show_recur_size($self->{show_recur_size});
95             $curl->refresh();
96             }
97              
98             sub go_down {
99             my $self = shift;
100             my $where = shift;
101              
102             my $data = $self->current_head;
103             my $target;
104             my $reftype = reftype($data);
105             if (!$reftype) {
106             return();
107             }
108             elsif ($reftype eq 'SCALAR') {
109             $target = $$data;
110             }
111             elsif ($reftype eq 'HASH') {
112             $target = $data->{$where};
113             }
114             elsif ($reftype eq 'ARRAY') {
115             $target = $data->[$where];
116             }
117             elsif ($reftype eq 'REF') {
118             $target = $$data;
119             }
120             elsif ($reftype eq 'GLOB') {
121             $target = *{$data}{$where};
122             }
123             else {
124             return();
125             }
126              
127             my $treftype = reftype($target);
128             if (not $treftype and reftype(\$target) eq 'GLOB') {
129             # work around my sucky understanding of GLOBS. Damn you, GLOB, damn you!
130             # $self->current_head(\$target);
131             # push @{$self->stack}, \$target;
132             # $self->{current_level}->set_data(\$target);
133             # return(1);
134             # with kudos to Yves!
135             no strict 'refs';
136             $target = \*{"$target"};
137             $treftype = reftype($target);
138             }
139             return() if not $treftype or $treftype eq 'CODE';
140             # avoid direct recursion into self
141             return() if $treftype eq $reftype and refaddr($target) eq refaddr($data);
142              
143             $self->current_head($target);
144             push @{$self->stack}, $target;
145             $self->{current_level}->set_data($target);
146             return(1);
147             }
148              
149             sub go_back {
150             my $self = shift;
151             my $stack = $self->stack;
152              
153             return() if @$stack == 1;
154            
155             pop(@$stack);
156             $self->current_head($stack->[-1]);
157             $self->{current_level}->set_data($stack->[-1]);
158            
159             return(1);
160             }
161              
162              
163             sub reset_head {
164             my $self = shift;
165             $self->{stack} = [$self->{global_head}];
166             $self->current_head($self->{global_head});
167             $self->{current_level}->set_data($self->current_head);
168             }
169              
170             1;
171             __END__