File Coverage

blib/lib/UI/Various/container.pm
Criterion Covered Total %
statement 79 79 100.0
branch 34 34 100.0
condition 6 6 100.0
subroutine 14 14 100.0
pod 5 5 100.0
total 138 138 100.0


line stmt bran cond sub pod time code
1             package UI::Various::container;
2              
3             # Author, Copyright and License: see end of file
4              
5             =head1 NAME
6              
7             UI::Various::container - abstract container class for UI elements
8              
9             =head1 SYNOPSIS
10              
11             # This module should never be used directly!
12             # It is used indirectly via the following:
13             use UI::Various::...;
14              
15             =head1 ABSTRACT
16              
17             This module is the common abstract container class for all kinds UI elements
18             that may contain other UI elements (e.g. C>,
19             C> or C>).
20              
21             =head1 DESCRIPTION
22              
23             The documentation of this module is mainly intended for developers of the
24             package itself.
25              
26             All container classes share the following common attributes (inherited from
27             C):
28              
29             =head2 Attributes
30              
31             =over
32              
33             =cut
34              
35             #########################################################################
36              
37 22     22   576 use v5.14;
  22         64  
38 22     22   101 use strictures;
  22         37  
  22         107  
39 22     22   3082 no indirect 'fatal';
  22         41  
  22         179  
40 22     22   1251 no multidimensional;
  22         44  
  22         129  
41 22     22   848 use warnings 'once';
  22         52  
  22         1272  
42              
43             our $VERSION = '0.22';
44              
45 22     22   157 use UI::Various::core;
  22         47  
  22         119  
46 22     22   8234 use UI::Various::widget;
  22         50  
  22         1899  
47              
48             require Exporter;
49             our @ISA = qw(UI::Various::widget);
50             our @EXPORT_OK = qw();
51              
52             #########################################################################
53              
54             =item children [private]
55              
56             a list with the children of the container UI element, which must not be
57             directly accessed (use C
58             them>> for access and iteration, use C
59             of children>> to get their quantity and use C
60             children>> and C> for manipulation)
61              
62             =cut
63              
64             #########################################################################
65             #
66             # internal constants and data:
67              
68 22     22   128 use constant ALLOWED_PARAMETERS => qw();
  22         38  
  22         1074  
69 22     22   103 use constant DEFAULT_ATTRIBUTES => (children => []);
  22         40  
  22         22671  
70              
71             #########################################################################
72             #########################################################################
73              
74             =back
75              
76             =head1 METHODS
77              
78             Besides the common methods inherited from C the
79             following additional ones are available in all C
80             container classes (UI elements containing other UI elements):
81              
82             =cut
83              
84             #########################################################################
85              
86             =head2 B - constructor
87              
88             see L
89             constructor for UI elements>
90              
91             =cut
92              
93             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
94              
95             sub new($;\[@$])
96             {
97 7     7 1 3321 return construct({ (DEFAULT_ATTRIBUTES) },
98             '^(?:' . join('|', ALLOWED_PARAMETERS) . ')$',
99             @_);
100             }
101              
102             #########################################################################
103              
104             =head2 B - add new children
105              
106             $ui_container->add($other_ui_element, ...);
107              
108             =head3 example:
109              
110             $self->add($that);
111             $self->add($foo, $bar);
112              
113             =head3 parameters:
114              
115             $other_ui_element one ore more UI elements to be added to container
116              
117             =head3 description:
118              
119             This method adds new children to a container element. Note that children
120             already having a parent are removed from their old parent first.
121              
122             =head3 returns:
123              
124             number of elements added
125              
126             =cut
127              
128             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
129             sub add($@)
130             {
131 124     124 1 6738 my $self = shift;
132              
133             # sanity checks:
134 124 100       406 $self->isa(__PACKAGE__)
135             or fatal('invalid_object__1_in_call_to__2__3',
136             ref($self), __PACKAGE__, 'add');
137              
138 123         168 local $_;
139 123         193 my $n = 0;
140 123         220 foreach (@_)
141             {
142 127 100       327 $_->isa('UI::Various::widget')
143             or fatal('invalid_object__1_in_call_to__2__3',
144             ref($_), __PACKAGE__, 'add');
145 126         506 my $parent = $_->parent();
146 126 100       467 if (defined $parent)
147             {
148 5 100       27 unless ($parent->remove($_))
149             {
150 2         17 error('can_t_remove__1_from_old_parent__2', $_, $parent);
151 2         10 return $n;
152             }
153             }
154 124         301 $_->parent($self);
155 124         324 $n++;
156             }
157 120 100       349 defined $self->{children} or $self->{children} = [];
158 120         152 push @{$self->{children}}, @_;
  120         223  
159 120         274 return $n;
160             }
161              
162             #########################################################################
163              
164             =head2 B - remove children
165              
166             $ui_container->remove($other_ui_element, ...);
167              
168             =head3 example:
169              
170             $self->remove($that);
171             $self->remove($foo, $bar);
172              
173             =head3 parameters:
174              
175             $other_ui_element one ore more UI elements to be removed from container
176              
177             =head3 description:
178              
179             This method removes children from a container element.
180              
181             =head3 returns:
182              
183             the last node that has been removed or C if nothing could be removed
184              
185             =cut
186              
187             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
188             sub remove($@)
189             {
190 101     101 1 12696 my $self = shift;
191              
192             # sanity checks:
193 101 100       271 $self->isa(__PACKAGE__)
194             or fatal('invalid_object__1_in_call_to__2__3',
195             ref($self), __PACKAGE__, 'remove');
196              
197 100         150 my $children = $self->{children};
198 100         138 my $removed = undef;
199 100         122 local $_;
200             CHILD:
201 100         189 foreach my $child (@_)
202             {
203 101 100       239 $child->isa('UI::Various::widget')
204             or fatal('invalid_object__1_in_call_to__2__3',
205             ref($child), __PACKAGE__, 'remove');
206 100         140 foreach (0..$#{$children})
  100         220  
207             {
208 111 100       282 next unless $children->[$_] eq $child;
209 97         121 $removed = splice @{$children}, $_, 1;
  97         156  
210             # instead of: $child->parent(undef);
211             # we need direct assignment for Perl < 5.20 here:
212 97         161 $child->{parent} = undef;
213             defined $self->{_index} and $_ < $self->{_index} and
214 97 100 100     280 $self->{_index}--;
215 97         203 next CHILD;
216             }
217 3         18 return error('can_t_remove__1_no_such_node_in__2',
218             ref($child), ref($self));
219             }
220 96         334 return $removed;
221             }
222              
223             #########################################################################
224              
225             =head2 B - return number of children
226              
227             $_ = $ui_container->children;
228              
229             =head3 description:
230              
231             This method returns the number of children a container element has.
232              
233             =head3 returns:
234              
235             number of children
236              
237             =cut
238              
239             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
240             sub children($)
241             {
242 84     84 1 2382 my $self = shift;
243 84         94 return scalar(@{$self->{children}});
  84         258  
244             }
245              
246             #########################################################################
247              
248             =head2 B - access children or iterate through them
249              
250             $ui_element = $ui_container->child($index);
251             $ui_element = $ui_container->child();
252             $ui_container->child(undef);
253              
254             =head3 example:
255              
256             $ui_element = $self->child(0);
257             while ($_ = $self->child())
258             {
259             ...
260             if ($abort)
261             {
262             $self->child(undef);
263             last;
264             }
265             ...
266             }
267              
268             =head3 parameters:
269              
270             $index optional index for direct access,
271             C for reset of iterator
272              
273             =head3 description:
274              
275             When called with a (positive or negative) numeric index this method returns
276             the container's element at that index. When called without parameter this
277             method iterates over all elements until the end, when it returns C
278             and automatically resets the iterator. Calling the method with an explicit
279             C resets the iterator before it reaches the end. An empty string
280             instead of C is also possible to allow avoiding Perl bugs #7508 and
281             #109726 in Perl versions prior to 5.20.
282              
283             Note that removing takes care of keeping the index valid, so it's perfectly
284             possible to use a loop to remove some or all children of a container.
285              
286             Note that each container object can only have one active iterator at any
287             time.
288              
289             =head3 returns:
290              
291             element at index or iterator, or C if not existing or at end of
292             iteration
293              
294             =cut
295              
296             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
297             sub child($;$)
298             {
299 535     535 1 9919 my ($self, $index) = @_;
300              
301             # sanity checks:
302 535 100       1227 $self->isa(__PACKAGE__)
303             or fatal('invalid_object__1_in_call_to__2__3',
304             ref($self), __PACKAGE__, 'child');
305              
306 534         723 local $_ = undef;
307             # called with index:
308 534 100 100     1222 if (defined $index and $index ne '')
    100          
309             {
310 20 100       137 if ($index !~ m/^-?\d+$/)
    100          
311             {
312 1         4 error('invalid_parameter__1_in_call_to__2__3',
313             $index, __PACKAGE__, 'child');
314             }
315             elsif (exists $self->{children}[$index])
316 18         32 { $_ = $self->{children}[$index]; }
317             else
318             {
319             # TODO: Do we really want this warning or is the empty $_ enough?
320 1         4 warning('no_element_found_for_index__1', $index);
321             }
322             }
323             # called with undef -> reset iterator:
324             elsif (exists $_[1]) # $index can't distinguish undef / missing!
325             {
326 2 100       11 defined $self->{_index} and delete $self->{_index};
327             }
328             # iterate:
329             else
330             {
331 512 100       963 defined $self->{_index} or $self->{_index}=0;
332 512 100       881 if (exists $self->{children}[$self->{_index}])
333             {
334 373         583 $_ = $self->{children}[$self->{_index}];
335 373         473 $self->{_index}++;
336             }
337             else
338 139         263 { delete $self->{_index}; }
339             }
340 534         1353 return $_;
341             }
342              
343             1;
344              
345             #########################################################################
346             #########################################################################
347              
348             =head1 SEE ALSO
349              
350             L
351              
352             =head1 LICENSE
353              
354             Copyright (C) Thomas Dorner.
355              
356             This library is free software; you can redistribute it and/or modify it
357             under the same terms as Perl itself. See LICENSE file for more details.
358              
359             =head1 AUTHOR
360              
361             Thomas Dorner Edorner (at) cpan (dot) orgE
362              
363             =cut