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   520 use v5.14;
  22         50  
38 22     22   86 use strictures;
  22         40  
  22         90  
39 22     22   2736 no indirect 'fatal';
  22         47  
  22         145  
40 22     22   1038 no multidimensional;
  22         35  
  22         112  
41 22     22   676 use warnings 'once';
  22         46  
  22         1020  
42              
43             our $VERSION = '0.23';
44              
45 22     22   112 use UI::Various::core;
  22         35  
  22         98  
46 22     22   6895 use UI::Various::widget;
  22         50  
  22         1856  
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   108 use constant ALLOWED_PARAMETERS => qw();
  22         35  
  22         1060  
69 22     22   94 use constant DEFAULT_ATTRIBUTES => (children => []);
  22         32  
  22         19679  
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 2969 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 5880 my $self = shift;
132              
133             # sanity checks:
134 124 100       320 $self->isa(__PACKAGE__)
135             or fatal('invalid_object__1_in_call_to__2__3',
136             ref($self), __PACKAGE__, 'add');
137              
138 123         148 local $_;
139 123         167 my $n = 0;
140 123         184 foreach (@_)
141             {
142 127 100       303 $_->isa('UI::Various::widget')
143             or fatal('invalid_object__1_in_call_to__2__3',
144             ref($_), __PACKAGE__, 'add');
145 126         417 my $parent = $_->parent();
146 126 100       395 if (defined $parent)
147             {
148 5 100       18 unless ($parent->remove($_))
149             {
150 2         12 error('can_t_remove__1_from_old_parent__2', $_, $parent);
151 2         7 return $n;
152             }
153             }
154 124         271 $_->parent($self);
155 124         295 $n++;
156             }
157 120 100       344 defined $self->{children} or $self->{children} = [];
158 120         137 push @{$self->{children}}, @_;
  120         201  
159 120         253 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 10741 my $self = shift;
191              
192             # sanity checks:
193 101 100       229 $self->isa(__PACKAGE__)
194             or fatal('invalid_object__1_in_call_to__2__3',
195             ref($self), __PACKAGE__, 'remove');
196              
197 100         134 my $children = $self->{children};
198 100         115 my $removed = undef;
199 100         109 local $_;
200             CHILD:
201 100         147 foreach my $child (@_)
202             {
203 101 100       210 $child->isa('UI::Various::widget')
204             or fatal('invalid_object__1_in_call_to__2__3',
205             ref($child), __PACKAGE__, 'remove');
206 100         116 foreach (0..$#{$children})
  100         189  
207             {
208 111 100       248 next unless $children->[$_] eq $child;
209 97         112 $removed = splice @{$children}, $_, 1;
  97         144  
210             # instead of: $child->parent(undef);
211             # we need direct assignment for Perl < 5.20 here:
212 97         128 $child->{parent} = undef;
213             defined $self->{_index} and $_ < $self->{_index} and
214 97 100 100     311 $self->{_index}--;
215 97         183 next CHILD;
216             }
217 3         11 return error('can_t_remove__1_no_such_node_in__2',
218             ref($child), ref($self));
219             }
220 96         252 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 1546 my $self = shift;
243 84         88 return scalar(@{$self->{children}});
  84         230  
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 9057 my ($self, $index) = @_;
300              
301             # sanity checks:
302 535 100       1059 $self->isa(__PACKAGE__)
303             or fatal('invalid_object__1_in_call_to__2__3',
304             ref($self), __PACKAGE__, 'child');
305              
306 534         600 local $_ = undef;
307             # called with index:
308 534 100 100     1037 if (defined $index and $index ne '')
    100          
309             {
310 20 100       103 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         34 { $_ = $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       10 defined $self->{_index} and delete $self->{_index};
327             }
328             # iterate:
329             else
330             {
331 512 100       828 defined $self->{_index} or $self->{_index}=0;
332 512 100       785 if (exists $self->{children}[$self->{_index}])
333             {
334 373         551 $_ = $self->{children}[$self->{_index}];
335 373         384 $self->{_index}++;
336             }
337             else
338 139         230 { delete $self->{_index}; }
339             }
340 534         1115 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