File Coverage

blib/lib/Circle/Session/Tabbed.pm
Criterion Covered Total %
statement 52 190 27.3
branch 3 76 3.9
condition 0 14 0.0
subroutine 15 29 51.7
pod 1 16 6.2
total 71 325 21.8


line stmt bran cond sub pod time code
1             # You may distribute under the terms of the GNU General Public License
2             #
3             # (C) Paul Evans, 2008-2014 -- leonerd@leonerd.org.uk
4              
5             package Circle::Session::Tabbed;
6              
7 3     3   5705 use strict;
  3         6  
  3         154  
8 3     3   18 use base qw( Tangence::Object Circle::Commandable Circle::Configurable );
  3         8  
  3         509  
9 3     3   21 use Carp;
  3         6  
  3         4954  
10              
11             sub _session_type
12             {
13 2     2   3 my ( $opts ) = @_;
14              
15 2 50       16 keys %$opts or return __PACKAGE__;
16              
17 0         0 print STDERR "Need Tabbed FE session for extra options:\n";
18 0         0 print STDERR " ".join( "|", sort keys %$opts )."\n";
19              
20 0         0 return undef;
21             }
22              
23             sub new
24             {
25 2     2 0 68 my $class = shift;
26 2         26 my %args = @_;
27              
28 2         24 my $self = $class->SUPER::new( %args );
29              
30 2         451 $self->{root} = $args{root};
31 2         5 $self->{identity} = $args{identity};
32              
33             # Start with just the root object in first tab
34              
35 2         13 $self->set_prop_tabs( [ $args{root} ] );
36 2         23 $self->{items} = {};
37              
38 2         8 return $self;
39             }
40              
41             sub items
42             {
43 2     2 0 4 my $self = shift;
44 2         6 return @{ $self->get_prop_tabs };
  2         11  
45             }
46              
47             sub describe
48             {
49 2     2 1 173 my $self = shift;
50 2         15 return __PACKAGE__."[$self->{identity}]";
51             }
52              
53             sub _item_to_index
54             {
55 0     0   0 my $self = shift;
56 0         0 my ( $item ) = @_;
57              
58 0         0 my @items = $self->items;
59 0   0     0 $items[$_] == $item and return $_ for 0 .. $#items;
60              
61 0         0 return undef;
62             }
63              
64             sub show_item
65             {
66 2     2 0 5 my $self = shift;
67 2         5 my ( $item ) = @_;
68              
69 2 50       10 return if grep { $_ == $item } $self->items;
  2         24  
70              
71 2         12 $self->push_prop_tabs( $item );
72             }
73              
74             sub unshow_item
75             {
76 0     0 0 0 my $self = shift;
77 0         0 my ( $item ) = @_;
78              
79 0         0 my $index;
80 0 0       0 if( ref $item ) {
81 0         0 $index = $self->_item_to_index( $item );
82 0 0       0 return unless defined $index;
83             }
84             else {
85 0         0 $index = $item;
86             }
87              
88 0         0 $self->splice_prop_tabs( $index, 1, () );
89             }
90              
91             sub new_item
92             {
93 2     2 0 5 my $self = shift;
94 2         5 my ( $item ) = @_;
95              
96             # Did we know about it?
97 2 50       13 return if exists $self->{items}->{$item};
98              
99 2         8 $self->{items}->{$item} = 1;
100 2         11 $self->show_item( $item );
101             }
102              
103             sub delete_item
104             {
105 0     0 0   my $self = shift;
106 0           my ( $item ) = @_;
107              
108 0           delete $self->{items}->{$item};
109 0           $self->unshow_item( $item );
110             }
111              
112             sub clonefrom
113             {
114 0     0 0   my $self = shift;
115 0           my ( $src ) = @_;
116              
117 0           my @srcitems = $src->items;
118              
119 0           foreach my $index ( 0 .. $#srcitems ) {
120 0           my $item = $srcitems[$index];
121              
122 0           my $curindex = $self->_item_to_index( $item );
123 0 0         if( !defined $curindex ) {
    0          
124 0           $self->splice_prop_tabs( $index, 0, $item );
125             }
126             elsif( $curindex != $index ) {
127 0           $self->move_prop_tabs( $curindex, $index - $curindex );
128             }
129             }
130              
131 0           $self->splice_prop_tabs( scalar @srcitems, scalar $self->items - scalar @srcitems, () );
132             }
133              
134             sub _get_item
135             {
136 0     0     my $self = shift;
137 0           my ( $path, $curitem, $create ) = @_;
138              
139 0 0 0       $curitem or $path =~ m{^/} or croak "Cannot walk a relative path without a start item";
140              
141 0 0         $curitem = $self->{root} if $path =~ s{^/}{};
142              
143 0           foreach ( split( m{/}, $path ) ) {
144 0 0         next unless length $_; # skip empty path elements
145              
146 0           my $nextitem;
147 0 0         if( $curitem->can( "get_item" ) ) {
    0          
148 0           $nextitem = $curitem->get_item( $_, $create );
149             }
150             elsif( $curitem->can( "enumerate_items" ) ) {
151 0           $nextitem = $curitem->enumerate_items->{$_};
152             }
153             else {
154 0           die "@{[ $curitem->describe ]} has no child items\n";
  0            
155             }
156              
157 0 0         defined $nextitem or die "@{[ $curitem->describe ]} has no child item called $_\n";
  0            
158              
159 0           $curitem = $nextitem;
160             }
161              
162 0           return $curitem;
163             }
164              
165             sub _cat_path
166             {
167 0     0     my ( $p, $q ) = @_;
168              
169 0 0         return $q if $p eq "";
170 0 0         return "/$q" if $p eq "/";
171 0           return "$p/$q";
172             }
173              
174             sub load_configuration
175             {
176 0     0 0   my $self = shift;
177 0           my ( $ynode ) = @_;
178              
179 0           $self->set_prop_tabs( [] );
180              
181 0           foreach my $tab ( @{ $ynode->{tabs} } ) {
  0            
182 0           my $item = $self->_get_item( $tab, $self->{root}, 1 );
183 0           $self->push_prop_tabs( $item );
184             }
185             }
186              
187             sub store_configuration
188             {
189 0     0 0   my $self = shift;
190 0           my ( $ynode ) = @_;
191              
192 0           $ynode->{tabs} = [ map {
193 0           my $item = $_;
194 0           my @components;
195 0           while( $item ) {
196 0           unshift @components, $item->enumerable_name;
197 0           $item = $item->parent;
198             }
199 0           join "/", @components;
200             } $self->items ];
201             }
202              
203             sub command_list
204             : Command_description("List showable window items")
205             : Command_arg('path?')
206             : Command_opt('all=+', desc => "list all the items")
207             {
208 0     0 0 0 my $self = shift;
209 0         0 my ( $itempath, $opts, $cinv ) = @_;
210              
211 0         0 my @items;
212            
213 0 0       0 if( $opts->{all} ) {
214 0         0 @items = ( [ "/" => $self->{root} ] );
215             }
216             else {
217 0         0 @items = ( [ "" => $cinv->invocant ] );
218             }
219              
220 0 0       0 if( defined $itempath ) {
221 0 0       0 if( $itempath =~ m{^/} ) {
222 0         0 $items[0]->[0] = $itempath;
223             }
224             else {
225 0         0 $items[0]->[0] .= $itempath;
226             }
227 0         0 $items[0]->[1] = $self->_get_item( $itempath, $items[0]->[1] );
228             }
229              
230 0 0       0 $cinv->respond( "The following items exist" . ( defined $itempath ? " from path $itempath" : "" ) );
231              
232             # Walk a tree without using a recursive function
233 0         0 my @table;
234 0         0 while( my $i = pop @items ) {
235 0         0 my ( $name, $item ) = @$i;
236              
237 0 0       0 push @table, [ " $name", ref($item) ] if length $name;
238              
239 0 0 0     0 if( my $subitems = $item->can( "enumerate_items" ) && $item->enumerate_items ) {
240 0         0 push @items, [ _cat_path( $name, $_ ) => $subitems->{$_} ] for reverse sort keys %$subitems;
241             }
242             }
243              
244 0         0 $cinv->respond_table( \@table, colsep => " - " );
245              
246 0         0 return;
247 3     3   28 }
  3         6  
  3         37  
248              
249             sub command_show
250             : Command_description("Show a window item")
251             : Command_arg("path")
252             {
253 0     0 0 0 my $self = shift;
254 0         0 my ( $itempath, $cinv ) = @_;
255              
256 0         0 my $item = $self->_get_item( $itempath, $cinv->invocant );
257              
258 0         0 $self->show_item( $item );
259              
260 0         0 return;
261 3     3   821 }
  3         7  
  3         27  
262              
263             sub command_hide
264             : Command_description("Hide a window item")
265             {
266 0     0 0 0 my $self = shift;
267 0         0 my ( $cinv ) = @_;
268              
269 0         0 my $item = $cinv->invocant;
270              
271 0 0       0 if( $item->isa( "Circle::RootObj" ) ) {
272 0         0 $cinv->responderr( "Cannot hide the global tab" );
273 0         0 return;
274             }
275              
276 0         0 $self->unshow_item( $item );
277              
278 0         0 return;
279 3     3   681 }
  3         8  
  3         15  
280              
281             sub command_tab
282             : Command_description("Manipulate window item tabs")
283 0     0 0 0 {
284 3     3   472 }
  3         8  
  3         16  
285              
286             sub command_tab_move
287             : Command_description("Move the tab to elsewhere in the window ordering\n".
288             "POSITION may be an absolute number starting from 1,\n".
289             " a relative number with a leading + or -,\n".
290             " one of first | left | right | last")
291             : Command_subof('tab')
292             : Command_arg('position')
293             {
294 0     0 0 0 my $self = shift;
295 0         0 my ( $position, $cinv ) = @_;
296              
297 0         0 my $tabs = $self->get_prop_tabs;
298              
299 0         0 my $item = $cinv->invocant;
300              
301 0         0 my $index;
302 0   0     0 $tabs->[$_] eq $item and ( $index = $_, last ) for 0 .. $#$tabs;
303              
304 0 0       0 defined $index or return $cinv->responderr( "Cannot find current index of item" );
305              
306 0 0       0 $position = "+1" if $position eq "right";
307 0 0       0 $position = "-1" if $position eq "left";
308 0 0       0 $position = "1" if $position eq "first"; # 1-based
309 0 0       0 $position = @$tabs if $position eq "last"; # 1-based
310              
311 0         0 my $delta;
312 0 0       0 if( $position =~ m/^[+-]/ ) {
    0          
313             # relative
314 0         0 $delta = $position+0;
315             }
316             elsif( $position =~ m/^\d+$/ ) {
317             # absolute; but input from user was 1-based.
318 0         0 $position -= 1;
319 0         0 $delta = $position - $index;
320             }
321             else {
322 0         0 return $cinv->responderr( "Unrecognised position/movement specification: $position" );
323             }
324              
325 0 0       0 return $cinv->responderr( "Cannot move that far left" ) if $index + $delta < 0;
326 0 0       0 return $cinv->responderr( "Cannot move that far right" ) if $index + $delta > $#$tabs;
327              
328 0         0 $self->move_prop_tabs( $index, $delta );
329 0         0 return;
330 3     3   1293 }
  3         8  
  3         15  
331              
332             sub command_tab_goto
333             : Command_description("Activate a numbered tab\n".
334             "POSITION may be an absolute number starting from 1,\n".
335             " a relative number with a leading + or -,\n".
336             " one of first | left | right | last")
337             : Command_subof('tab')
338             : Command_arg('position')
339             {
340 0     0 0 0 my $self = shift;
341 0         0 my ( $position, $cinv ) = @_;
342              
343 0         0 my $tabs = $self->get_prop_tabs;
344              
345 0         0 my $item = $cinv->invocant;
346              
347 0         0 my $index;
348 0   0     0 $tabs->[$_] eq $item and ( $index = $_, last ) for 0 .. $#$tabs;
349              
350 0 0       0 defined $index or return $cinv->responderr( "Cannot find current index of item" );
351              
352 0 0       0 $position = "+1" if $position eq "right";
353 0 0       0 $position = "-1" if $position eq "left";
354 0 0       0 $position = "1" if $position eq "first"; # 1-based
355 0 0       0 $position = @$tabs if $position eq "last"; # 1-based
356              
357 0 0       0 if( $position =~ m/^[+-]/ ) {
    0          
358             # relative
359 0         0 $index += $position;
360             }
361             elsif( $position =~ m/^\d+$/ ) {
362             # absolute; but input from user was 1-based.
363 0         0 $index = $position - 1;
364             }
365             else {
366 0         0 return $cinv->responderr( "Unrecognised position/movement specification: $position" );
367             }
368              
369 0         0 $self->get_prop_tabs->[$index]->fire_event( raise => () );
370 0         0 return;
371 3     3   1406 }
  3         8  
  3         19  
372              
373             0x55AA;