File Coverage

blib/lib/Script/Toolbox/Util/Menus.pm
Criterion Covered Total %
statement 6 251 2.3
branch 0 102 0.0
condition 0 6 0.0
subroutine 2 38 5.2
pod 0 27 0.0
total 8 424 1.8


line stmt bran cond sub pod time code
1             package Script::Toolbox::Util::Menus;
2              
3 10     10   75 use strict;
  10         23  
  10         369  
4 10     10   169 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
  10         21  
  10         33531  
5              
6             require Exporter;
7              
8             @ISA = qw(Exporter);
9             # Items to export into callers namespace by default. Note: do not export
10             # names by default without a very good reason. Use EXPORT_OK instead.
11             # Do not simply export all your public functions/methods/constants.
12             @EXPORT = qw(
13            
14             );
15              
16              
17             # Preloaded methods go here.
18              
19             #-----------------------------------------------------------------------------
20             # {'menueName>' =>[{label=>,value=>,jump=>,argv=>},...]}
21             #-----------------------------------------------------------------------------
22             sub new
23             {
24 0     0 0   my $classname = shift;
25 0           my $self = {};
26 0           bless( $self, $classname );
27 0           $self->_init( @_ );
28 0           return $self;
29             }
30              
31             #-----------------------------------------------------------------------------
32             # {'' =>[{label=>,value=>,jump=>,argv=>},...]}
33             #-----------------------------------------------------------------------------
34             sub _init
35             {
36 0     0     my ($self, $newDef) = @_;
37              
38 0           $self->{'def'} = {};
39 0 0         return if( ref $newDef ne 'HASH' );
40 0           $self->addMenu($newDef);
41             }
42              
43             #------------------------------------------------------------------------------
44             #------------------------------------------------------------------------------
45             sub _getHead($){
46 0     0     my ($self,$def) = @_;
47 0           my $s = '';
48 0           foreach my $k ( @{$def} ) {
  0            
49 0 0         next if( ! defined $k->{'header'} );
50 0           $s .= sprintf "%s", $k->{'header'};
51             }
52 0 0         return $s ne '' ? $s : undef;
53             }
54             #------------------------------------------------------------------------------
55             #------------------------------------------------------------------------------
56             sub _getFoot($){
57 0     0     my ($self,$def) = @_;
58 0           my $s = '';
59 0           foreach my $k ( @{$def} ) {
  0            
60 0 0         next if( ! defined $k->{'footer'} );
61 0           $s .= sprintf "%s", $k->{'footer'};
62             }
63 0 0         return $s ne '' ? $s : undef;
64             }
65              
66             #------------------------------------------------------------------------------
67             # ...
68             # {'label'=>'Call the submenue 1','jump'=>'SubMenu1'}
69             # SubMenu1: is the name of a previous defined menue in the same menues container
70             #------------------------------------------------------------------------------
71             sub _resolveSubmenue($){
72 0     0     my ($self,$opt) = @_;
73              
74 0 0         return if( !defined $opt->{'jump'} );
75 0 0         return if( ref \$opt->{'jump'} ne 'SCALAR' );
76              
77 0           my $subName = $opt->{'jump'};
78 0           $opt->{'jump'} = \&Script::Toolbox::Util::Menus::run;
79 0           $opt->{'argv'} = [$self,$subName];
80 0           return;
81             }
82              
83             #------------------------------------------------------------------------------
84             # [{label=>,value=>,jump=>,argv=>},...]}
85             #------------------------------------------------------------------------------
86             sub _getOpts($){
87 0     0     my ($self,$def) = @_;
88 0           my @s;
89 0           foreach my $k ( @{$def} ) {
  0            
90 0 0         next if( ! defined $k->{'label'} );
91 0           $self->_resolveSubmenue($k);
92 0           push @s, $k;
93             }
94 0           return \@s;
95             }
96              
97             #------------------------------------------------------------------------------
98             # , [{label=>,value=>,jump=>,argv=>},...]}
99             #------------------------------------------------------------------------------
100             sub addMenu($){
101 0     0 0   my ($self,$newDef) = @_;
102              
103 0 0         return if( ref $newDef ne 'HASH' );
104              
105 0           foreach my $name ( keys %{$newDef} ){
  0            
106 0           my $def = $newDef->{$name};
107 0           $self->{'def'}{$name}{'head'} = $self->_getHead($def);
108 0           $self->{'def'}{$name}{'foot'} = $self->_getFoot($def);
109 0           $self->{'def'}{$name}{'opts'} = $self->_getOpts($def);
110             }
111 0           return;
112             }
113              
114             #------------------------------------------------------------------------------
115             # ,
116             #------------------------------------------------------------------------------
117             sub setHeader($$){
118 0     0 0   my ($self,$name,$head) = @_;
119              
120 0           $self->{'def'}{$name}{'head'} = $head;
121 0           return;
122             }
123              
124              
125             #------------------------------------------------------------------------------
126             # ,
127             #------------------------------------------------------------------------------
128             sub setAutoHeader($){
129 0     0 0   my ($self,$name) = @_;
130            
131 0 0         if( defined $name) {
132 0           $self->{'def'}{$name}{'autohead'} = 1;
133 0           return;
134             }
135 0           foreach my $n (keys %{$self->{'def'}} ){
  0            
136 0           $self->{'def'}{$n}{'autohead'} = 1;
137             }
138             }
139              
140             #------------------------------------------------------------------------------
141             #------------------------------------------------------------------------------
142             sub _delAutoHead($){
143 0     0     my ($ah) = @_;
144 0 0         delete $ah->{'autohead'} if( defined $ah->{'autohead'} );
145             }
146              
147             #------------------------------------------------------------------------------
148             # ,
149             #------------------------------------------------------------------------------
150             sub delAutoHeader($){
151 0     0 0   my ($self,$name) = @_;
152              
153 0 0         if( defined $name) {
154 0           _delAutoHead( $self->{'def'}{$name} );
155 0           return;
156             }
157 0           foreach my $n (keys %{$self->{'def'}} ){
  0            
158 0           _delAutoHead( $self->{'def'}{$n} );
159             }
160             }
161              
162             #------------------------------------------------------------------------------
163             # ,
164             #------------------------------------------------------------------------------
165             sub getHeader($){
166 0     0 0   my ($self,$name) = @_;
167              
168 0           my $autoHead = $self->{'def'}{$name}{'autohead'};
169 0           my $H;
170 0           my $h = $self->{'def'}{$name}{'head'};
171 0 0 0       $h = "Menu: $name" if(!defined $h && defined $autoHead);
172 0 0         $H = {'header' => $h} if( defined $h );
173              
174 0           return $H;
175             }
176              
177             #------------------------------------------------------------------------------
178             # ,
179             #------------------------------------------------------------------------------
180             sub setFooter($$){
181 0     0 0   my ($self,$name,$foot) = @_;
182              
183 0           $self->{'def'}{$name}{'foot'} = $foot;
184 0           return;
185             }
186              
187             #------------------------------------------------------------------------------
188             # ,
189             #------------------------------------------------------------------------------
190             sub getFooter($){
191 0     0 0   my ($self,$name) = @_;
192              
193 0           my $foot = $self->{'def'}{$name}{'foot'} ;
194 0 0         return {'footer'=> $foot} if(defined $foot);
195 0           return undef;
196             }
197              
198             #------------------------------------------------------------------------------
199             # , {label=>,value=>,jump=>,argv=>}
200             #------------------------------------------------------------------------------
201             sub addOption($$){
202 0     0 0   my ($self,$name,$opt) = @_;
203              
204 0 0         $self->{'def'}{$name}{'opts'} = [] if( ! defined $self->{'def'}{$name}{'opts'} );
205              
206 0           $self->_resolveSubmenue($opt);
207 0           push @{$self->{'def'}{$name}{'opts'}}, $opt;
  0            
208 0           return;
209             }
210              
211             #------------------------------------------------------------------------------
212             #------------------------------------------------------------------------------
213             sub _getParams($){
214 0     0     my ($self,$name) = @_;
215              
216 0           my @p;
217 0 0         my $s = $self->getHeader($name); push @p, $s if( defined $s );
  0            
218 0 0         $s = $self->getFooter($name); push @p, $s if( defined $s );
  0            
219 0           push @p, {'label'=>'RETURN'};
220             map {
221 0           push @p, $_;
222 0           } @{$self->{'def'}{$name}{'opts'}};
  0            
223              
224 0           return \@p;
225             }
226              
227             #------------------------------------------------------------------------------
228             # Validate parameters and rearrange parameters in case of internal menue call
229             # ( submenue call by name).
230             # Return 0 if parameters invalid.
231             #------------------------------------------------------------------------------
232             sub validateParams($$){
233 0     0 0   my ($self,$name) = @_;
234 0 0         return 0 if( ! defined $$self );
235 0 0         if( ref $$self eq 'ARRAY' ) {
236 0 0         return 0 if( ref $$self->[0] ne 'Script::Toolbox::Util::Menus' );
237 0           $$name = $$self->[1];
238 0           $$self = $$self->[0];
239             }
240 0 0         return 1 if( defined $$self->{'def'}{$$name} );
241 0           Script::Toolbox::Util::Log("\nWARNING: Submenue $$name is not defined!");
242 0           sleep 5;
243 0           return 0;
244             }
245              
246             #------------------------------------------------------------------------------
247             # 0 HASH(0x7f98e5350ed0)
248             # 'label' => 'test10'
249             # 'readOnly' => 1
250             # 'value' => 'x'
251             #------------------------------------------------------------------------------
252             sub _toggleRO($){
253 0     0     my ($opt) = @_;
254 0 0         return if( ! $opt->{'readOnly'});
255              
256 0           my $v = $opt->{'value'};
257 0           my $d = $opt->{'default'};
258              
259 0 0 0       if( $d && $v ) { $opt->{'value'} = $d; $opt->{'default'} = $v }
  0 0          
  0 0          
260 0           elsif( $d ) { $opt->{'value'} = $d; $opt->{'default'} = '' }
  0            
261 0           elsif( $v ) { $opt->{'value'} = ''; $opt->{'default'} = $v }
  0            
262 0           else { $opt->{'value'} = 'x';$opt->{'default'} = '' }
  0            
263             }
264              
265             #------------------------------------------------------------------------------
266             # Run the named menue as long as $cnt is true. $cnt will be decremented by each
267             # loop. That means if $cnt starts with 0 we have an endless loop.
268             # Return the number of the last selected option.
269             # The option 'RETURN' will be created automaticly and has option number 0 by
270             # default.
271             #------------------------------------------------------------------------------
272             sub run($$){
273 0     0 0   my ($self,$name,$cnt) = @_;
274              
275 0 0         return if( ! validateParams(\$self,\$name) );
276 0 0         $cnt = 1 if( ! defined $cnt);
277 0 0         $cnt = 1 if( $cnt !~ /^[-]?\d+$/ );
278 0 0         $cnt = -1 if( $cnt == 0 );
279 0           $self->{'_cnt'} = $cnt;
280 0           my $o; my $m;
281 0           while($self->{'_cnt'}--) {
282 0           my $p = $self->_getParams($name);
283 0           ($o,$m) = Script::Toolbox::Util::Menu($p);
284 0           $self->{'def'}{$name}{'selected'}{'num'} = $o;
285 0           $self->{'def'}{$name}{'selected'}{'opt'} = $m->[$o];
286 0 0         _toggleRO($m->[$o]) if($self->{'_cnt'} < 0);
287 0 0         return $o if( $o == 0 );
288             }
289 0           return $o;
290             }
291              
292             #------------------------------------------------------------------------------
293             # Return the current value of internal menu running counter.
294             #------------------------------------------------------------------------------
295             sub getRunCnt($$){
296 0     0 0   my ($self,$menName) = @_;
297              
298 0           return $self->{$menName}{'_cnt'};
299             }
300              
301             #------------------------------------------------------------------------------
302             # Return current number of selected option.
303             #------------------------------------------------------------------------------
304             sub currNumber($){
305 0     0 0   my ($self,$name) = @_;
306              
307             Script::Toolbox::Util::Exit(1,"Undefined menu: $name",
308 0 0         __FILE__ , __LINE__) if( ! defined $self->{'def'}{$name} );
309              
310 0           return $self->{'def'}{$name}{'selected'}{'num'};
311             }
312              
313             #------------------------------------------------------------------------------
314             # Return current label of selected option.
315             #------------------------------------------------------------------------------
316             sub currLabel($){
317 0     0 0   my ($self,$name) = @_;
318 0           return $self->{'def'}{$name}{'selected'}{'opt'}{'label'};
319             }
320              
321             #------------------------------------------------------------------------------
322             # Return current value of selected option.
323             #------------------------------------------------------------------------------
324             sub currValue($){
325 0     0 0   my ($self,$name) = @_;
326 0           return $self->{'def'}{$name}{'selected'}{'opt'}{'value'};
327             }
328              
329             #------------------------------------------------------------------------------
330             # Return the callback address and argv address of selected option.
331             #------------------------------------------------------------------------------
332             sub currJump($){
333 0     0 0   my ($self,$name) = @_;
334              
335 0           my $call = $self->{'def'}{$name}{'selected'}{'opt'}{'jump'};
336 0           my $args = $self->{'def'}{$name}{'selected'}{'opt'}{'argv'};
337            
338 0           return $call,$args;
339             }
340              
341             #------------------------------------------------------------------------------
342             # Set a new default for current selected option. Return old default.
343             #------------------------------------------------------------------------------
344             sub setCurrDefault($$){
345 0     0 0   my ($self,$name,$newDefault) = @_;
346              
347 0           my $cn = $self->currNumber($name) -1;
348 0           my $ol = $self->{'def'}{$name}{'opts'}[$cn]{'default'};
349 0           $self->{'def'}{$name}{'opts'}[$cn]{'default'} = $newDefault;
350 0           return $ol;
351             }
352              
353             #------------------------------------------------------------------------------
354             # Set a new default for current selected option. Return old default.
355             #------------------------------------------------------------------------------
356             sub setCurrReadOnly($$){
357 0     0 0   my ($self,$name,$newRo) = @_;
358            
359 0 0         if( ! defined $newRo ) { $newRo = 0 }
  0 0          
360 0           elsif( $newRo =~ /(0|false)/i ){ $newRo = 0 }
361 0           else { $newRo = 1 }
362 0           my $cn = $self->currNumber($name) -1;
363 0           my $ol = $self->{'def'}{$name}{'opts'}[$cn]{'readOnly'};
364 0           $self->{'def'}{$name}{'opts'}[$cn]{'readOnly'} = $newRo;
365 0           return $ol;
366             }
367              
368             #------------------------------------------------------------------------------
369             # Set a new label for current selected option. Return old label.
370             #------------------------------------------------------------------------------
371             sub setCurrLabel($$){
372 0     0 0   my ($self,$name,$newLabel) = @_;
373              
374 0           my $cn = $self->currNumber($name) -1;
375 0           my $ol = $self->{'def'}{$name}{'opts'}[$cn]{'label'};
376 0           $self->{'def'}{$name}{'opts'}[$cn]{'label'} = $newLabel;
377 0           return $ol;
378             }
379              
380             #------------------------------------------------------------------------------
381             # Set a new value for current selected option. Return old value.
382             #------------------------------------------------------------------------------
383             sub setCurrValue($$){
384 0     0 0   my ($self,$name,$newValue) = @_;
385              
386 0           my $cn = $self->currNumber($name) -1;
387 0           my $ov = $self->{'def'}{$name}{'opts'}[$cn]{'value'};
388 0           $self->{'def'}{$name}{'opts'}[$cn]{'value'} = $newValue;
389 0           return $ov;
390             }
391              
392             #------------------------------------------------------------------------------
393             # Set new callback address und argv for the current selected option.
394             #------------------------------------------------------------------------------
395             sub setCurrJump($$$){
396 0     0 0   my ($self,$name,$callBack,$argv) = @_;
397              
398 0           my $cn = $self->currNumber($name) -1;
399 0           $self->{'def'}{$name}{'opts'}[$cn]{'jump'} = $callBack;
400 0           $self->{'def'}{$name}{'opts'}[$cn]{'argv'} = $argv;
401 0           return $callBack,$argv;
402             }
403              
404             #------------------------------------------------------------------------------
405             #------------------------------------------------------------------------------
406             sub _invalidParam($$$$$){
407 0     0     my ($self,$name,$pattern,$search,$return) = @_;
408 0 0         return 1 if( !defined $pattern );
409 0 0         return 1 if( !defined $search );
410 0 0         return 1 if( !defined $return );
411 0 0         return 1 if( !defined $self->{'def'}{$name}{'opts'});
412 0 0         return 1 if( $search !~ /(number|value|label)/ );
413 0 0         return 1 if( $return !~ /(number|value|label)/ );
414 0           return 0;
415             }
416              
417             #------------------------------------------------------------------------------
418             # Search the labels array for $pattern matching in $search. If matching return
419             # value of type return.
420             # $pattern='[Mm]ax' $search='value' $return='label'
421             # => returns all labels where value column matching Max or max.
422             # search: /(label,number,value)/
423             # return: /(label,number,value)/
424             #------------------------------------------------------------------------------
425             sub getMatching($$$$){
426 0     0 0   my ($self,$name,$pattern,$search,$return) = @_;
427 0 0         return '' if( _invalidParam($self,$name,$pattern,$search,$return));
428              
429 0           my $L = $self->{'def'}{$name}{'opts'};
430 0           my @R;
431 0           my $i=1;
432 0           foreach my $l ( @{$L} ){
  0            
433 0 0         if( $search eq 'number' ){
434 0 0         push @R, $l->{$return} if( $i =~ /$pattern/);
435 0           $i++;
436             }else{
437 0 0         next if( !defined $l->{$search} );
438 0 0         next if( $l->{$search} !~ /$pattern/ );
439 0           push @R, $l->{$return};
440             }
441             }
442 0           return \@R;
443             }
444              
445             #------------------------------------------------------------------------------
446             # Useful for DataMenus.
447             # Return all Label-Value pairs in a hash structure.
448             #------------------------------------------------------------------------------
449             sub getLabelValueHash($$){
450 0     0 0   my ($self,$name) = @_;
451              
452 0           my $L = $self->{'def'}{$name}{'opts'};
453 0           my $lvh;
454 0           foreach my $x (@{$L}) {
  0            
455 0           my $l = $x->{'label'};
456 0           my $v = $x->{'value'};
457 0 0         next if( ! defined $v );
458 0           $lvh->{$l} = $v;
459             }
460 0           return $lvh;
461             }
462              
463             #------------------------------------------------------------------------------
464             # Take a value hash {
465             # Copy the value of the value hash to the value of the menu option
466             # if they have the same label.
467             #------------------------------------------------------------------------------
468             sub setValues($$$){
469 0     0 0   my ($self,$name,$values) = @_;
470              
471 0           my $L = $self->{'def'}{$name}{'opts'};
472 0           my $lvh;
473 0           foreach my $x (@{$L}) {
  0            
474 0           my $l = $x->{'label'};
475 0           my $v = $values->{$l};
476 0 0         next if( ! defined $v );
477 0           $x->{'value'} = $v;
478             }
479             }
480              
481             #------------------------------------------------------------------------------
482             # Take a value hash {
483             # Copy the value of the value hash to the default field of the menu option
484             # if they have the same label.
485             #------------------------------------------------------------------------------
486             sub setDefaults($$$){
487 0     0 0   my ($self,$name,$defaults) = @_;
488              
489 0           my $L = $self->{'def'}{$name}{'opts'};
490 0           my $lvh;
491 0           foreach my $x (@{$L}) {
  0            
492 0           my $l = $x->{'label'};
493 0           my $v = $defaults->{$l};
494 0 0         next if( ! defined $v );
495 0           $x->{'default'} = $v;
496             }
497             }
498              
499             #------------------------------------------------------------------------------
500             # Take a hash {
501             # Copy the jumpTarget to the jump field of the menu option
502             # if they have the same label.
503             #------------------------------------------------------------------------------
504             sub setJumps($$$){
505 0     0 0   my ($self,$name,$jumps) = @_;
506              
507 0           my $L = $self->{'def'}{$name}{'opts'};
508 0           my $lvh;
509 0           foreach my $x (@{$L}) {
  0            
510 0           my $l = $x->{'label'};
511 0           my $v = $jumps->{$l};
512 0 0         next if( ! defined $v );
513 0           $x->{'jump'} = $v;
514             }
515             }
516              
517             #------------------------------------------------------------------------------
518             # Take a hash {
519             # Copy the readOnly to the readOnly field of the menu option
520             # if they have the same label.
521             #------------------------------------------------------------------------------
522             sub setReadOnlys($$$){
523 0     0 0   my ($self,$name,$readOnly) = @_;
524              
525 0           my $L = $self->{'def'}{$name}{'opts'};
526 0           my $lvh;
527 0           foreach my $x (@{$L}) {
  0            
528 0           my $l = $x->{'label'};
529 0           my $v = $readOnly->{$l};
530 0 0         next if( ! defined $v );
531 0           $x->{'readOnly'} = $v;
532             }
533             }
534              
535             1;
536             __END__