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 23     23   553 use v5.14;
  23         65  
38 23     23   100 use strictures;
  23         35  
  23         104  
39 23     23   3149 no indirect 'fatal';
  23         40  
  23         102  
40 23     23   1158 no multidimensional;
  23         50  
  23         121  
41 23     23   789 use warnings 'once';
  23         35  
  23         1205  
42              
43             our $VERSION = '0.24';
44              
45 23     23   127 use UI::Various::core;
  23         30  
  23         119  
46 23     23   8240 use UI::Various::widget;
  23         49  
  23         1830  
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 23     23   123 use constant ALLOWED_PARAMETERS => qw();
  23         36  
  23         1165  
69 23     23   104 use constant DEFAULT_ATTRIBUTES => (children => []);
  23         37  
  23         22897  
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 4001 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 126     126 1 9683 my $self = shift;
132              
133             # sanity checks:
134 126 100       406 $self->isa(__PACKAGE__)
135             or fatal('invalid_object__1_in_call_to__2__3',
136             ref($self), __PACKAGE__, 'add');
137              
138 125         166 local $_;
139 125         193 my $n = 0;
140 125         229 foreach (@_)
141             {
142 129 100       368 $_->isa('UI::Various::widget')
143             or fatal('invalid_object__1_in_call_to__2__3',
144             ref($_), __PACKAGE__, 'add');
145 128         448 my $parent = $_->parent();
146 128 100       443 if (defined $parent)
147             {
148 5 100       26 unless ($parent->remove($_))
149             {
150 2         15 error('can_t_remove__1_from_old_parent__2', $_, $parent);
151 2         14 return $n;
152             }
153             }
154 126         346 $_->parent($self);
155 126         322 $n++;
156             }
157 122 100       333 defined $self->{children} or $self->{children} = [];
158 122         163 push @{$self->{children}}, @_;
  122         232  
159 122         256 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 11943 my $self = shift;
191              
192             # sanity checks:
193 101 100       287 $self->isa(__PACKAGE__)
194             or fatal('invalid_object__1_in_call_to__2__3',
195             ref($self), __PACKAGE__, 'remove');
196              
197 100         142 my $children = $self->{children};
198 100         140 my $removed = undef;
199 100         123 local $_;
200             CHILD:
201 100         178 foreach my $child (@_)
202             {
203 101 100       254 $child->isa('UI::Various::widget')
204             or fatal('invalid_object__1_in_call_to__2__3',
205             ref($child), __PACKAGE__, 'remove');
206 100         128 foreach (0..$#{$children})
  100         217  
207             {
208 111 100       269 next unless $children->[$_] eq $child;
209 97         118 $removed = splice @{$children}, $_, 1;
  97         158  
210             # instead of: $child->parent(undef);
211             # we need direct assignment for Perl < 5.20 here:
212 97         158 $child->{parent} = undef;
213             defined $self->{_index} and $_ < $self->{_index} and
214 97 100 100     302 $self->{_index}--;
215 97         210 next CHILD;
216             }
217 3         17 return error('can_t_remove__1_no_such_node_in__2',
218             ref($child), ref($self));
219             }
220 96         303 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 1699 my $self = shift;
243 84         93 return scalar(@{$self->{children}});
  84         266  
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 9896 my ($self, $index) = @_;
300              
301             # sanity checks:
302 535 100       1242 $self->isa(__PACKAGE__)
303             or fatal('invalid_object__1_in_call_to__2__3',
304             ref($self), __PACKAGE__, 'child');
305              
306 534         644 local $_ = undef;
307             # called with index:
308 534 100 100     1193 if (defined $index and $index ne '')
    100          
309             {
310 20 100       123 if ($index !~ m/^-?\d+$/)
    100          
311             {
312 1         5 error('invalid_parameter__1_in_call_to__2__3',
313             $index, __PACKAGE__, 'child');
314             }
315             elsif (exists $self->{children}[$index])
316 18         33 { $_ = $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       13 defined $self->{_index} and delete $self->{_index};
327             }
328             # iterate:
329             else
330             {
331 512 100       958 defined $self->{_index} or $self->{_index}=0;
332 512 100       821 if (exists $self->{children}[$self->{_index}])
333             {
334 373         539 $_ = $self->{children}[$self->{_index}];
335 373         427 $self->{_index}++;
336             }
337             else
338 139         233 { delete $self->{_index}; }
339             }
340 534         1270 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