File Coverage

blib/lib/Script/Toolbox/Util/Menus.pm
Criterion Covered Total %
statement 6 233 2.5
branch 0 98 0.0
condition 0 6 0.0
subroutine 2 36 5.5
pod 0 25 0.0
total 8 398 2.0


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