File Coverage

blib/lib/App/Asciio/Setup.pm
Criterion Covered Total %
statement 36 217 16.5
branch 0 86 0.0
condition 0 38 0.0
subroutine 12 26 46.1
pod 0 9 0.0
total 48 376 12.7


line stmt bran cond sub pod time code
1              
2             package App::Asciio ;
3              
4             $|++ ;
5              
6 4     4   29 use strict;
  4         11  
  4         215  
7 4     4   26 use warnings;
  4         10  
  4         352  
8 4     4   38 use utf8 ;
  4         11  
  4         122  
9              
10 4     4   229 use Data::TreeDumper ;
  4         95  
  4         437  
11 4     4   3228 use Eval::Context ;
  4         106750  
  4         302  
12 4     4   45 use Carp ;
  4         6  
  4         406  
13 4     4   2877 use Module::Util qw(find_installed) ;
  4         16985  
  4         392  
14 4     4   37 use File::Basename ;
  4         7  
  4         4016  
15              
16             #------------------------------------------------------------------------------------------------------
17              
18             sub setup
19             {
20 0     0 0   my($self, $setup_ini_files) = @_ ;
21              
22 0           for my $setup_file (@{$setup_ini_files})
  0            
23             {
24 0 0         print "Initializing with '$setup_file'\n" if $self->{DISPLAY_SETUP_INFORMATION};
25 0 0 0       warn "Asciio: Warning: can't find setup data '$setup_file'\n" and next unless -e $setup_file ;
26            
27 0           push @{$self->{SETUP_PATHS}}, $setup_file ;
  0            
28            
29 0           my ($setup_name, $setup_path, $setup_ext) = File::Basename::fileparse($setup_file, ('\..*')) ;
30            
31 0           my $ini_files ;
32            
33             {
34 0           my $context = new Eval::Context() ;
  0            
35             $ini_files = $context->eval
36             (
37             PRE_CODE => "use strict;\nuse warnings;\n",
38 0           INSTALL_VARIABLES =>[[ '$ASCIIO_UI' => $self->{UI}]] ,
39             CODE_FROM_FILE => $setup_file,
40             ) ;
41            
42 0 0         warn "can't load '$setup_file': $! $@\n" if $@ ;
43             }
44            
45 0   0       $self->setup_object_options($setup_path, $ini_files->{ASCIIO_OBJECT_SETUP} || []) ;
46 0   0       $self->setup_stencils($setup_path, $ini_files->{STENCILS} || []) ;
47 0   0       $self->setup_hooks($setup_path, $ini_files->{HOOK_FILES} || []) ;
48 0   0       $self->setup_action_handlers($setup_path, $ini_files->{ACTION_FILES} || []) ;
49 0   0       $self->setup_import_export_handlers($setup_path, $ini_files->{IMPORT_EXPORT} || []) ;
50             }
51             }
52              
53             #------------------------------------------------------------------------------------------------------
54              
55             sub setup_stencils
56             {
57 0     0 0   my($self, $setup_path, $stencils) = @_ ;
58              
59 0           for my $stencil (@{$stencils})
  0            
60             {
61 0 0         if(-e "$setup_path/$stencil")
62             {
63 0 0         if(-f "$setup_path/$stencil")
    0          
64             {
65 0 0         print "loading stencil '$setup_path/$stencil'\n" if $self->{DISPLAY_SETUP_INFORMATION} ;
66 0           $self->load_elements("$setup_path/$stencil", $stencil) ;
67             }
68             elsif(-d "$setup_path/$stencil")
69             {
70 0           for(glob("$setup_path/$stencil/*"))
71             {
72 0 0         print "batch loading stencil '$setup_path/$stencil/$_'\n" if $self->{DISPLAY_SETUP_INFORMATION} ;
73 0           $self->load_elements($_, $stencil) ;
74             }
75             }
76             else
77             {
78 0           print "Unknown type '$setup_path/$stencil'!\n" ;
79             }
80             }
81             else
82             {
83 0           print "Can't find '$setup_path/$stencil'!\n" ;
84             }
85             }
86             }
87              
88             #------------------------------------------------------------------------------------------------------
89              
90             sub setup_hooks
91             {
92 0     0 0   my($self, $setup_path, $hook_files) = @_ ;
93              
94 0           for my $hook_file (@{ $hook_files })
  0            
95             {
96 0           my $context = new Eval::Context() ;
97            
98 0           my @hooks ;
99            
100             $context->eval
101             (
102             REMOVE_PACKAGE_AFTER_EVAL => 0, # VERY IMPORTANT as we return code references that will cease to exist otherwise
103 0     0     INSTALL_SUBS => {register_hooks => sub{@hooks = @_}},
104 0           PRE_CODE => "use strict;\nuse warnings;\n",
105             CODE_FROM_FILE => "$setup_path/$hook_file" ,
106             ) ;
107            
108 0 0         die "Asciio: can't load hook file '$hook_file ': $! $@\n" if $@ ;
109            
110 0           for my $hook (@hooks)
111             {
112 0           while (my ($name, $hook_sub) = each %$hook)
113             {
114 0           $self->{HOOKS}{$name} = $hook_sub ;
115             }
116             }
117             }
118             }
119              
120             #------------------------------------------------------------------------------------------------------
121              
122             sub setup_action_handlers
123             {
124 0     0 0   my($self, $setup_path, $action_files) = @_ ;
125              
126 4     4   40 use strict ; use warnings ;
  4     4   8  
  4         164  
  4         25  
  4         9  
  4         303  
127              
128 4     4   27 use Module::Util qw(find_installed) ;
  4         7  
  4         263  
129 4     4   25 use File::Basename ;
  4         7  
  4         12472  
130              
131 0           my $installed = find_installed('App::Asciio') ;
132 0           my ($basename, $path, $ext) = File::Basename::fileparse($installed, ('\..*')) ;
133 0           my $asciio_setup_path = $path . $basename . '/setup/' ;
134              
135 0           for my $action_file (@{ $action_files })
  0            
136             {
137 0           my $context = new Eval::Context() ;
138            
139 0           my (%action_handlers, $remove_old_shortcuts) ;
140            
141 0 0         if($action_file =~ /^$asciio_setup_path/)
142             {
143 0           $setup_path = $asciio_setup_path ;
144 0           substr($action_file, 0, length("$asciio_setup_path/")) = ''
145             }
146            
147 0 0         my $location = $action_file =~ /^\// ? $action_file : "$setup_path/$action_file" ;
148            
149             $context->eval
150             (
151             REMOVE_PACKAGE_AFTER_EVAL => 0, # VERY IMPORTANT as we return code references that will cease to exist otherwise
152             INSTALL_SUBS => {
153 0     0     register_action_handlers => sub { %action_handlers = @_ ; },
154 0     0     register_action_handlers_remove_old_shortcuts => sub { %action_handlers = @_ ; $remove_old_shortcuts++ ; },
  0            
155             },
156 0           PRE_CODE => "use strict;\nuse warnings;\n",
157             CODE_FROM_FILE => $location,
158             ) ;
159            
160 0 0         die "Asciio: can't load setup file '$action_file': $! $@\n" if $@ ;
161            
162 0           for my $name (keys %action_handlers)
163             {
164 0           my $action_handler_definition = $action_handlers{$name} ;
165 0           my $action_handler ;
166             my $group_name ;
167            
168 0           my $shortcuts_definition ;
169            
170 0 0         if('HASH' eq ref $action_handler_definition)
    0          
171             {
172 0           $shortcuts_definition = $action_handler_definition->{SHORTCUTS} ;
173             # print "\e[31maction_handler: '$name' is group $shortcuts_definition\e[m\n" ;
174            
175 0           $action_handler = $self->get_group_action_handler($setup_path, $action_file, $name, $action_handler_definition) ;
176             }
177             elsif('ARRAY' eq ref $action_handler_definition)
178             {
179 0           my %action_handler_hash ; # transform the definition from array into hash
180 0           @action_handler_hash{'SHORTCUTS', 'CODE', 'ARGUMENTS', 'CONTEXT_MENU_SUB', 'CONTEXT_MENU_ARGUMENTS', 'NAME', 'ORIGIN'}
181             = @$action_handler_definition ;
182            
183 0           $shortcuts_definition = $action_handler_hash{SHORTCUTS} ;
184 0           $action_handler_hash{NAME} = $name ;
185 0           $action_handler_hash{ORIGIN} = $action_file ;
186            
187 0           $self->check_action_by_name($setup_path, $action_file, \%action_handler_hash, \%action_handlers) ;
188            
189 0           $action_handler = \%action_handler_hash ;
190             }
191             else
192             {
193             # print "ignoring '$name'\n" ;
194 0           next ;
195             }
196            
197 0           $self->{ACTIONS_BY_NAME}{$name} = $action_handler ;
198 0           $self->{ACTIONS_BY_NAME}{ORIGINS}{$name}{ORIGIN} = $action_file ;
199            
200 0 0         if($remove_old_shortcuts)
201             {
202 0           for my $shortcut (keys %{$self->{ACTIONS}})
  0            
203             {
204 0           my $action = $self->{ACTIONS}{$shortcut} ;
205            
206 0 0         if($action->{IS_GROUP})
207             {
208 0           for my $group_shortcut (grep {'HASH' eq ref $action->{$_} } keys %$action)
  0            
209             {
210 0 0         if($action_handler->{IS_GROUP})
211             {
212 0           for my $group_action (grep {'HASH' eq ref $action_handler->{$_} } keys %$action_handler )
  0            
213             {
214             delete $action->{$group_shortcut}
215             if exists $action->{$group_shortcut} &&
216 0 0 0       $action->{$group_shortcut}{NAME} eq $action_handler->{$group_action}{NAME} ;
217             }
218             }
219             else
220             {
221             delete $action->{$group_shortcut}
222             if exists $action->{$group_shortcut} &&
223 0 0 0       $action->{$group_shortcut}{NAME} eq $action_handler->{NAME} ;
224             }
225             }
226             }
227             else
228             {
229 0 0         if($action_handler->{IS_GROUP})
230             {
231 0           for my $group_action (grep {'HASH' eq ref $action_handler->{$_} } keys %$action_handler )
  0            
232             {
233             delete $self->{ACTIONS}{$shortcut}
234             if exists $self->{ACTIONS}{$shortcut} &&
235 0 0 0       $self->{ACTIONS}{$shortcut}{NAME} eq $action_handler->{$group_action}{NAME} ;
236             }
237             }
238             else
239             {
240             delete $self->{ACTIONS}{$shortcut}
241 0 0         if $action->{NAME} eq $action_handler->{NAME} ;
242             }
243             }
244             }
245             }
246            
247 0 0         for my $shortcut ('ARRAY' eq ref $shortcuts_definition ? @$shortcuts_definition : ($shortcuts_definition))
248             {
249 0 0         if(exists $self->{ACTIONS}{$shortcut})
250             {
251 0           print "Overriding shortcut '$shortcut'\n" ;
252 0           print "\tnew is '$name' defined in file '$setup_path/$action_file'\n" ;
253 0           print "\told was '$self->{ACTIONS}{$shortcut}{NAME}' defined in file '$self->{ACTIONS}{$shortcut}{ORIGIN}'\n" ;
254             }
255            
256 0           $self->{ACTIONS}{$shortcut} = $action_handler ;
257            
258 0 0 0       if (! defined $action_handler->{CODE} && ! defined $action_handler->{CONTEXT_MENU_SUB})
259             {
260 0           print "\e[33mNo action for action_handler: '$name', file: '$setup_path/$action_file'\e[m\n" ;
261 0           delete $self->{ACTIONS}{$shortcut} ;
262             }
263            
264 0 0         $self->{ACTIONS}{$shortcut}{GROUP_NAME} = $group_name if defined $group_name ;
265             }
266             }
267             }
268             }
269              
270             #------------------------------------------------------------------------------------------------------
271              
272             sub check_action_by_name
273             {
274 0     0 0   my ($self, $setup_path, $action_file, $action_handler, $action_handlers) = @_ ;
275 0           my $name = $action_handler->{NAME} ;
276              
277 0 0         if(exists $self->{ACTIONS_BY_NAME}{$name})
278             {
279 0   0       print "\e[33mOverriding action: '$name', file: '$action_file', old_file: '" . ($self->{ACTIONS_BY_NAME}{ORIGINS}{$name}{ORIGIN} // 'unknown') ;
280            
281 0           my $old_handler = $self->{ACTIONS_BY_NAME}{$name} ;
282            
283 0 0         if(! defined $action_handler->{SHORTCUTS})
284             {
285 0           die "\tno shortcuts in definition\n" ;
286             }
287            
288 0           my $reused = '' ;
289 0 0 0       if(! defined $action_handler->{CODE} && defined $old_handler->{CODE})
290             {
291 0           $reused .= ", reused code" ;
292 0           $action_handler->{CODE} = $old_handler->{CODE} ;
293             }
294            
295 0 0 0       if(! defined $action_handler->{ARGUMENTS} && defined $old_handler->{ARGUMENTS})
296             {
297 0           $reused .= ", reused arguments" ;
298 0           $action_handler->{ARGUMENTS} = $old_handler->{ARGUMENTS} ;
299             }
300            
301 0 0 0       if(! defined $action_handler->{CONTEXT_MENU_SUB} && defined $old_handler->{CONTEXT_MENU_SUB})
302             {
303 0           $reused .= "reused context menu" ;
304 0           $action_handler->{CONTEXT_MENU_SUB} = $old_handler->{CONTEXT_MENU_SUB} ;
305             }
306            
307 0 0 0       if(! defined $action_handler->{CONTEXT_MENU_ARGUMENTS} && defined $old_handler->{CONTEXT_MENU_ARGUMENTS})
308             {
309 0           $reused .= "reused contet menu arguments" ;
310 0           $action_handler->{CONTEXT_MENU_ARGUMENTS} = $old_handler->{CONTEXT_MENU_ARGUMENTS} ;
311             }
312            
313 0           print "$reused\e[m\n" ;
314             }
315             }
316              
317             #------------------------------------------------------------------------------------------------------
318              
319             sub get_group_action_handler
320             {
321 0     0 0   my ($self, $setup_path, $action_file, $group_name, $group_definition) = @_ ;
322              
323 0           my %handler ;
324              
325             die "Asciio: group '$group_name' is without shortcuts in '$action_file'.\n"
326 0 0         unless exists $group_definition->{SHORTCUTS} ;
327              
328 0           my $escape_key = $group_definition->{ESCAPE_KEY} ;
329              
330 0           for my $name (keys %{$group_definition})
  0            
331             {
332 0           my $action_handler ;
333            
334             my $shortcuts_definition ;
335 0 0         if('HASH' eq ref $group_definition->{$name})
    0          
336             {
337 0           $shortcuts_definition = $group_definition->{$name}{SHORTCUTS} ;
338 0           $group_definition->{$name}{GROUP_NAME} = $name ;
339 0           $group_definition->{$name}{ORIGIN} = $action_file ;
340            
341 0           $action_handler = $self->get_group_action_handler($setup_path, $action_file, $name, $group_definition->{$name}) ;
342             }
343             elsif('ARRAY' eq ref $group_definition->{$name})
344             {
345 0           my %action_handler_hash ; # transform the definition from array into hash
346             @action_handler_hash{'SHORTCUTS', 'CODE', 'ARGUMENTS', 'CONTEXT_MENU_SUB', 'CONTEXT_MENU_ARGUMENTS', 'NAME', 'ORIGIN'}
347 0           = @{$group_definition->{$name}} ;
  0            
348            
349 0           $shortcuts_definition = $action_handler_hash{SHORTCUTS} ;
350 0           $action_handler_hash{NAME} = $name ;
351 0           $action_handler_hash{GROUP_NAME} = $group_name ;
352 0           $action_handler_hash{ORIGIN} = $action_file ;
353            
354 0           $self->check_action_by_name($setup_path, $action_file, \%action_handler_hash, $group_definition) ;
355            
356 0           $action_handler = \%action_handler_hash ;
357             }
358             else
359             {
360             # print "ignoring '$name'\n" ;
361 0           next ;
362             }
363            
364 0           $self->{ACTIONS_BY_NAME}{$name} = $action_handler ;
365 0           $self->{ACTIONS_BY_NAME}{ORIGINS}{$name}{ORIGIN} = "$action_file" ;
366            
367 0 0         for my $shortcut ('ARRAY' eq ref $shortcuts_definition ? @$shortcuts_definition : ($shortcuts_definition))
368             {
369             print "Overriding action group '$shortcut' with definition from file '$setup_path/$action_file'!\n"
370 0 0         if exists $handler{$shortcut} ;
371            
372             # print "\e[32maction_handler: '$name' shortcut: $shortcut\e[m\n" ;
373 0           $handler{$shortcut} = $action_handler ;
374            
375 0 0         $handler{$shortcut}{GROUP_NAME} = $group_name if defined $group_name ;
376             }
377             }
378              
379             @handler{'IS_GROUP', 'ENTER_GROUP', 'ESCAPE_KEY', 'SHORTCUTS', 'CODE', 'NAME', 'ORIGIN'} =
380             (
381             1,
382             $group_definition->{ENTER_GROUP},
383             $escape_key,
384             $group_definition->{SHORTCUTS},
385 0     0     sub { $_[0]->{CURRENT_ACTIONS} = \%handler },
386 0           $group_name,
387             $action_file
388             ) ;
389              
390 0           return \%handler ;
391             }
392              
393             #------------------------------------------------------------------------------------------------------
394              
395             sub setup_import_export_handlers
396             {
397 0     0 0   my($self, $setup_path, $import_export_files) = @_ ;
398              
399 0           for my $import_export_file (@{ $import_export_files })
  0            
400             {
401 0           my $context = new Eval::Context() ;
402            
403 0           my %import_export_handlers ;
404             $context->eval
405             (
406             REMOVE_PACKAGE_AFTER_EVAL => 0, # VERY IMPORTANT as we return code references that will cease to exist otherwise
407 0     0     INSTALL_SUBS => {register_import_export_handlers => sub{%import_export_handlers = @_}},
408 0           PRE_CODE => <
409             use strict;
410             use warnings;
411            
412             EOC
413             CODE_FROM_FILE => "$setup_path/$import_export_file",
414             ) ;
415            
416 0 0         die "Asciio: can't load import/export handler defintion file '$import_export_file': $! $@\n" if $@ ;
417            
418 0           for my $extension (keys %import_export_handlers)
419             {
420 0 0         if(exists $self->{IMPORT_EXPORT_HANDLERS}{$extension})
421             {
422 0           print "Overriding import/export handler for extension '$extension' in file '$setup_path/$import_export_file'\n" ;
423             }
424            
425 0           $self->{IMPORT_EXPORT_HANDLERS}{$extension} = $import_export_handlers{$extension} ;
426             }
427             }
428             }
429              
430             #------------------------------------------------------------------------------------------------------
431              
432             sub setup_object_options
433             {
434 0     0 0   my($self, $setup_path, $options_files) = @_ ;
435              
436 0           for my $options_file (@{ $options_files })
  0            
437             {
438 0           my $context = new Eval::Context() ;
439            
440 0           my %options =
441             $context->eval
442             (
443             PRE_CODE => "use strict;\nuse warnings;\n",
444             CODE_FROM_FILE => "$setup_path/$options_file",
445             ) ;
446            
447 0           for my $option_name (keys %options)
448             {
449 0           $self->{$option_name} = $options{$option_name} ;
450             }
451            
452 0           $self->{COLORS} = $options{COLOR_SCHEMES}{system} ;
453            
454 0 0         die "Asciio: can't load setup file '$options_file': $! $@\n" if $@ ;
455             }
456              
457 0           $self->event_options_changed() ;
458             }
459              
460             #------------------------------------------------------------------------------------------------------
461              
462             sub run_script
463             {
464 0     0 0   my($self, $script) = @_ ;
465              
466 0 0         if(defined $script)
467             {
468 0           my $context = new Eval::Context() ;
469            
470 0           $context->eval
471             (
472             PRE_CODE => "use strict;\nuse warnings;\n",
473             CODE_FROM_FILE => $script,
474             INSTALL_VARIABLES =>
475             [
476             [ '$self' => $self => $Eval::Context::SHARED ],
477             ] ,
478             ) ;
479            
480 0 0         die "Asciio: can't load setup file '$script': $! $@\n" if $@ ;
481             }
482             }
483              
484             #------------------------------------------------------------------------------------------------------
485              
486             1 ;
487