File Coverage

blib/lib/Tk/ApplicationNest.pm
Criterion Covered Total %
statement 6 6 100.0
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 8 8 100.0


line stmt bran cond sub pod time code
1             package Tk::ApplicationNest;
2             #------------------------------------------------
3             # automagically updated versioning variables -- CVS modifies these!
4             #------------------------------------------------
5             our $Revision = '$Revision: 1.1 $';
6             our $CheckinDate = '$Date: 2003/11/06 17:55:04 $';
7             our $CheckinUser = '$Author: xpix $';
8             # we need to clean these up right here
9             $Revision =~ s/^\$\S+:\s*(.*?)\s*\$$/$1/sx;
10             $CheckinDate =~ s/^\$\S+:\s*(.*?)\s*\$$/$1/sx;
11             $CheckinUser =~ s/^\$\S+:\s*(.*?)\s*\$$/$1/sx;
12             #-------------------------------------------------
13             #-- package Tk::DBI::Tree -----------------------
14             #-------------------------------------------------
15              
16 1     1   2502 use vars qw($VERSION);
  1         2  
  1         55  
17             $VERSION = '0.01';
18              
19 1     1   4 use base qw(Tk::MainWindow);
  1         2  
  1         1648  
20             use strict;
21              
22             use IO::File;
23             use Tk::Balloon;
24             use Tk::Getopt;
25             use Tk::ToolBar;
26             use Tk::DialogBox;
27             use Tk::ROText;
28              
29             use Data::Dumper;
30             use Pod::Text;
31              
32             Construct Tk::Widget 'Program';
33              
34             # ------------------------------------------
35             sub ClassInit
36             # ------------------------------------------
37             {
38             my($class,$mw) = @_;
39              
40             Tk::CmdLine::SetArguments(); # Tk::CmdLine->SetArguments() works too
41            
42             }
43              
44              
45             # ------------------------------------------
46             sub Populate {
47             # ------------------------------------------
48             my ($obj, $args) = @_;
49              
50             $obj->{app} = delete $args->{'-app'} || 'Program';
51             $obj->{cfg} = delete $args->{'-cfg'} || sprintf( '%s/.%s.cfg', ($ENV{HOME} ? $ENV{HOME} : $ENV{HOMEDRIVE}.$ENV{HOMEPATH}), $obj->{app} );
52             $obj->{add_prefs} = delete $args->{'-add_prefs'};
53             $obj->{about} = delete $args->{'-about'};
54             $obj->{help} = delete $args->{'-help'} || $0;
55              
56             $obj->SUPER::Populate($args);
57            
58             $obj->ConfigSpecs(
59             -set_logo => ["METHOD", "set_logo", "Set_Logo", undef],
60             -set_icon => ["METHOD", "set_icon", "Set_Icon", undef],
61              
62             -init_menu => ["METHOD", "init_menu", "Init_Menu", undef],
63             -init_prefs => ["METHOD", "init_prefs", "Init_Prefs", undef],
64             -init_main => ["METHOD", "init_main", "Init_Main", undef],
65             -init_status => ["METHOD", "init_status", "Init_Status", undef],
66              
67             -add_status => ["METHOD", "add_status", "Add_Status", undef],
68             -add_toolbar => ["METHOD", "add_toolbar", "Add_Toolbar", undef],
69              
70             -config => ["METHOD", "config", "Config", undef],
71             -skin => ["METHOD", "skin", "Skin", undef],
72             -prefs => ["METHOD", "prefs", "Prefs", undef],
73             -splash => ["METHOD", "splash", "Splash", undef],
74             -exit => ["METHOD", "exit", "Exit", undef],
75              
76             -exit_cb => ["CALLBACK", "exit_cb", "Exit_Cb", undef],
77             );
78            
79             $obj->bind( "", sub{ $obj->{opt}->{'Geometry'} = $obj->geometry } );
80             $obj->bind( "", sub { $obj->exit } );
81              
82             $obj->Icon('-image' => $obj->Photo( -file => $obj->{icon} ) ) if($obj->{icon});
83             $obj->optionAdd("*tearOff", "false");
84             $obj->configure(-title => $obj->{app});
85              
86             $obj->init_menu();
87             $obj->init_main();
88             $obj->init_status();
89              
90             $obj->packall();
91              
92             $obj->Advertise('menu' => $obj->{menu});
93             $obj->Advertise('main' => $obj->{main});
94             $obj->Advertise('status' => $obj->{status});
95              
96             $obj->init_prefs();
97             $obj->update;
98             }
99              
100             # ------------------------------------------
101             sub exit {
102             # ------------------------------------------
103             my $obj = shift || return error('No Object');
104             $obj->Callback(-exit_cb);
105             $obj->save_prefs;
106             exit;
107             }
108              
109             # ------------------------------------------
110             sub set_icon {
111             # ------------------------------------------
112             my $obj = shift || return error('No Object');
113             $obj->{icon} = shift || return $obj->{icon};
114            
115             my $image = $obj->{icon};
116             $image = $obj->Photo( -file => $obj->{icon} )
117             unless(ref $obj->{icon});
118             $obj->Icon('-image' => $image );
119             }
120              
121              
122             # ------------------------------------------
123             sub set_logo {
124             # ------------------------------------------
125             my $obj = shift || return error('No Object');
126             $obj->{logo} = shift || $obj->{logo};
127              
128             my $image = $obj->{logo};
129             $image = $obj->Photo( -file => $obj->{logo} )
130             unless(ref $obj->{logo});
131             return $image;
132             }
133              
134             # ------------------------------------------
135             sub help {
136             # ------------------------------------------
137             my $obj = shift || return error('No Object');
138             my $pod = $obj->{help};
139              
140             unless(defined $obj->{pod_text}) {
141             $obj->{pod_text} = `pod2text $pod`;
142             }
143              
144             $obj->{pod_window}->{dialog} = my $dialog = $obj->DialogBox(
145             -title => sprintf('Help for %s:', $obj->{app}),
146             -buttons => [ 'Ok' ],
147             -default_button => 'Ok'
148             );
149             my $e = $dialog->Scrolled(
150             'ROText',
151             -scrollbars => 'osoe',
152             )->pack(-expand => 1, -fill => 'both');
153              
154             $obj->{pod_text} =~ s/\r//sig;
155             $e->insert('end', $obj->{pod_text});
156              
157             my $answer = $dialog->Show;
158             }
159              
160             # ------------------------------------------
161             sub about {
162             # ------------------------------------------
163             my $obj = shift || return error('No Object');
164             my $text = shift || $obj->{about};
165            
166             $obj->splash(4000, $text);
167             }
168              
169             # ------------------------------------------
170             sub splash {
171             # ------------------------------------------
172             my $obj = shift || return error('No Object');
173             my $mseconds = shift || 0;
174             my $text = shift;
175            
176             if($obj->{splash} and ! $mseconds) {
177             $obj->{splash}->destroy();
178             } elsif(defined $obj->{logo} or defined $text) {
179             $obj->{splash} = $obj->Toplevel;
180              
181             $obj->{splash}->Label(
182             -image => $obj->set_logo,
183             )->pack();
184              
185             $obj->{splash}->Label(
186             -textvariable => $text,
187             )->pack() if($text);
188              
189             if($mseconds) {
190             my $des = $obj->after($mseconds,
191             sub{ $obj->{splash}->destroy() }
192             );
193             $obj->{splash}->OnDestroy(sub{ $des->cancel });
194             }
195              
196             return $obj->{splash};
197             } else {
198             return error('Can\'t find a logo or text to display. Please define first -set_logo!');
199             }
200              
201             }
202              
203             # ------------------------------------------
204             sub prefs {
205             # ------------------------------------------
206             my $obj = shift || return error('No Object');
207             return error('Please call Tk::ApplicationNest::init_prefs before call prefs')
208             unless defined $obj->{optobj};
209             my $w = $obj->{optobj}->option_editor(
210             $obj,
211             -buttons => [qw/ok save cancel defaults/],
212             -delaypagecreate => 0,
213             -wait => 1,
214             -transient => $obj,
215             );
216             }
217              
218             # ------------------------------------------
219             sub packall {
220             # ------------------------------------------
221             my $obj = shift || return error('No Object');
222              
223             $obj->{status} ->pack( -side => 'bottom', -fill => 'x');
224             $obj->{main} ->pack( -side => 'top', -expand => 1, -fill => 'both');
225             }
226              
227             # ------------------------------------------
228             sub init_main {
229             # ------------------------------------------
230             my $obj = shift || return error('No Object');
231             $obj->{main} = shift || $obj->Frame();
232              
233             return $obj->{main};
234             }
235              
236             # ------------------------------------------
237             sub init_status {
238             # ------------------------------------------
239             my $obj = shift || return error('No Object');
240             return $obj->{status} if(defined $obj->{status});
241              
242             # Statusframe
243             $obj->{status} = $obj->Frame();
244              
245             return $obj->{status};
246             }
247              
248             # ------------------------------------------
249             sub config {
250             # ------------------------------------------
251             my $obj = shift || return error('No Object');
252             my $name = shift;
253             my $cfg = shift;
254              
255             $obj->{'UserCfg'} = {}
256             unless(ref $obj->{'UserCfg'});
257              
258             return $obj->{'UserCfg'}->{$name}
259             unless( $cfg );
260              
261             $obj->{'UserCfg'}->{$name} = $cfg;
262             $obj->{opt}->{'UserCfg'} = Data::Dumper->Dump([$obj->{'UserCfg'}]);
263             $obj->{optobj}->save_options;
264             return $obj->{'UserCfg'}->{$name};
265             }
266              
267             # ------------------------------------------
268             sub add_toolbar {
269             # ------------------------------------------
270             my $obj = shift || return error('No Object');
271             my $typ = shift || return error('No Type!');
272             my @par = @_;
273              
274             unless(defined $obj->{toolbar}) {
275             $obj->{toolbar} = $obj->ToolBar(
276             -movable => 1,
277             -side => 'top',
278             );
279             $obj->Advertise('toolbar' => $obj->{toolbar});
280             }
281             $obj->{toolbar}->$typ(@par);
282             }
283              
284              
285             # ------------------------------------------
286             sub add_status {
287             # ------------------------------------------
288             my $obj = shift || return error('No Object');
289             my $name = shift || return error('No Name');
290             my $value = shift || return error('No Value');
291             my $w;
292              
293             return $obj->{status}->{$name}
294             if(defined $obj->{status}->{$name});
295            
296             $obj->{status} = $obj->init_status()
297             unless(defined $obj->{status});
298              
299             if(ref $$value) {
300             $w = $$value->pack(
301             -side => 'left',
302             -fill => 'x',
303             -expand => 1,
304             );
305             } else {
306             $w = $obj->{status}->Label(
307             -textvariable => $value,
308             -relief => 'sunken',
309             -borderwidth => 2,
310             -padx => 5,
311             -anchor => 'w')->pack(
312             -side => 'left',
313             -fill => 'x',
314             -expand => 1,
315             );
316             }
317             $obj->Advertise('status_'.$name => $w);
318             }
319              
320             # ------------------------------------------
321             sub init_prefs {
322             # ------------------------------------------
323             my $obj = shift || return error('No Object');
324             return $obj->{optobj} if defined $obj->{optobj};
325              
326             my $optionen = shift || $obj->get_prefs($obj->{add_prefs});
327             my %opts;
328             $obj->{opt} = \%opts;
329            
330             $obj->{optobj} = Tk::Getopt->new(
331             -opttable => $optionen,
332             -options => \%opts,
333             -filename => $obj->{cfg}
334             );
335             $obj->{optobj}->set_defaults;
336             $obj->{optobj}->load_options;
337             if (! $obj->{optobj}->get_options) {
338             die $obj->{optobj}->usage;
339             }
340             $obj->{optobj}->process_options;
341             return $obj->{opt};
342             }
343              
344             # ------------------------------------------
345             sub save_prefs {
346             # ------------------------------------------
347             my $obj = shift || return error('No Object');
348             return $obj->{optobj}->save_options()
349             if defined $obj->{optobj};
350             }
351              
352              
353             # ------------------------------------------
354             sub get_prefs {
355             # ------------------------------------------
356             my $obj = shift || return error('No Object');
357             my $to_add = shift || [];
358              
359             if(! ref $to_add and -e $to_add) {
360             $to_add = $obj->load_config($to_add);
361             }
362              
363              
364             my $default =
365             [
366             'Display',
367             ['Geometry', '=s', '640x480',
368             'help' => 'Set geometry from Programm',
369             'subtype' => 'geometry',
370             'callback' => sub {
371             if (my $geo = $obj->{opt}->{'Geometry'}) {
372             $obj->geometry($geo);
373             $obj->update;
374             }
375             },
376             ],
377             ['Color', '=s', 'gray85',
378             'help' => 'Set color palette to Program',
379             'subtype' => 'color',
380             'callback' => sub {
381             if (my $col = $obj->{opt}->{'Color'}) {
382             $obj->setPalette($col);
383             $obj->update;
384             }
385             },
386             ],
387             ['Font', '=s', 'Helvetica 10 normal',
388             'callback-interactive' => sub{
389             $obj->messageBox(
390             -message => 'Please restart program to apply changes!',
391             -title => 'My title',
392             -type => 'Ok',
393             -default => 'Ok');
394             $obj->{optobj}->save_options();
395             },
396             'callback' => sub {
397             if (my $font = $obj->{opt}->{'Font'}) {
398             $obj->optionAdd("*font", $font);
399             $obj->optionAdd("*Font", $font);
400             $obj->Walk(
401             sub {
402             #XXX Uiee, böser Hack ;-)
403             if( exists $_[0]->{Configure}->{'-font'} ) {
404             $_[0]->configure(-font => $font)
405             }
406             } );
407             $obj->update;
408             }
409             },
410             'subtype' => 'font',
411             'help' => 'Default font',
412             ],
413             ['UserCfg', '=s', undef,
414             'nogui' => 1,
415             'callback' => sub {
416             if (my $str = $obj->{opt}->{'UserCfg'}) {
417             my $VAR1;
418             $obj->{'UserCfg'} = eval($str);
419             return error($@) if($@);
420             }
421             },
422             ],
423             ['debug', '=i', undef,
424             'nogui' => 1,
425             ],
426             @$to_add
427             ];
428             return $default;
429             }
430              
431             # ------------------------------------------
432             sub init_menu {
433             # ------------------------------------------
434             my $obj = shift || return error('No Object');
435             return $obj->{menu} if defined $obj->{menu};
436             my $menuitems = shift || [
437             [Cascade => "File", -menuitems =>
438             [
439             [Button => "Prefs", -command => sub{ $obj->prefs() } ],
440             [Button => "Quit", -command => sub{ $obj->exit }],
441             ]
442             ],
443            
444            
445             [Cascade => "Help", -menuitems =>
446             [
447             [Button => "Help", -command => sub{ $obj->help() } ],
448             [Button => "About", -command => sub{ $obj->about() } ],
449             ]
450             ],
451             ];
452              
453             # Menu
454             if ($Tk::VERSION >= 800) {
455             $obj->{menu} = $obj->Menu(
456             -menuitems => $menuitems,
457             -tearoff => 0,
458             );
459             $obj->configure(-menu => $obj->{menu});
460             } else {
461             $obj->{menu} = $obj->Menubutton(-text => "Pseudo menubar",
462             -menuitems => $menuitems)->pack;
463             }
464              
465             return $obj->{menu};
466             }
467              
468             # ------------------------------------------
469             sub load_config {
470             # ------------------------------------------
471             my $obj = shift || return error('No Object');
472             my $file = shift || return error('No Configfile');
473              
474             my @VAR = eval( _load_file($file) );
475              
476             return \@VAR;
477             }
478              
479             #--------------------------------------------------------
480             sub _load_file {
481             #--------------------------------------------------------
482             my $file = shift || die "Kein File bei Loader $!";
483             my $fh = IO::File->new("< $file")
484             or return debug("Can't open File $file $! ");
485             my $data;
486             while ( defined (my $l = <$fh>) ) {
487             $data .= $l;
488             }
489             $fh->close;
490             return $data;
491             }
492              
493              
494             #-------------------------------------------------
495             sub error {
496             #-------------------------------------------------
497             my $obj = shift;
498             my $msg = shift || return;
499             my ($package, $filename, $line, $subroutine, $hasargs,
500             $wantarray, $evaltext, $is_require, $hints, $bitmask) = caller(1);
501             warn sprintf("ERROR in %s:%s #%d: %s",
502             $package, $subroutine, $line, sprintf($msg, @_));
503             return undef;
504             }
505              
506             # ------------------------------------------
507             sub debug {
508             # ------------------------------------------
509             my $obj = shift;
510             my $msg = shift || return;
511             my ($package, $filename, $line, $subroutine, $hasargs,
512             $wantarray, $evaltext, $is_require, $hints, $bitmask) = caller(1);
513             print $package, '::', $filename, '::', $line, '::',
514             sprintf($msg, @_), "\n"
515             if($obj->{opt}->{debug});
516             }
517              
518              
519             1;
520              
521             =head1 NAME
522            
523             Tk::ApplicationNest - MainWindow Widget with special features.
524            
525             =head1 SYNOPSIS
526            
527             use Tk;
528             use Tk::ApplicationNest;
529            
530             my $top = Tk::ApplicationNest->new(
531             -app => 'xpix',
532             -cfg => './testconfig.cfg',
533             -set_icon => './icon.gif',
534             -set_logo => './logo.gif',
535             -about => \$about,
536             -help => '../Tk/Program.pm',
537             -add_prefs => [
538             'Tools',
539             ['acrobat', '=s', '/usr/local/bin/acroread',
540             { 'subtype' => 'file',
541             'help' => 'Path to acrobat reader.'
542             } ],
543             ],
544             );
545            
546             MainLoop;
547            
548             =head1 DESCRIPTION
549            
550             This is a megawidget to display a program window. I was tired of creating
551             menues, prefs dialogues, about dialogues,... for every new application..... I
552             searched for a generic way wrote this module. This modules stores the main
553             window's font, size and position and embodies the fucntions from the
554             Tk::Mainwindow module.
555            
556            
557             =head1 WIDGET-SPECIFIC OPTIONS
558            
559             =head2 -app => $Applikation_Name
560            
561             Set a Application name, default is I
562            
563             =head2 -set_icon => $Path_to_icon_image
564            
565             Set a Application Icon, please give this in 32x32 pixel and in gif format.
566            
567             =head2 -cfg => $path_to_config_file;
568            
569             Set the path to the config file, default:
570            
571             $HOME/.$Application_Name.cfg
572              
573             =head2 -add_prefs => $arrey_ref_more_prefs or $path_to_cfg_file;
574            
575             This allows to include your Preferences into default:
576            
577             -add_prefs => [
578             'Tools',
579             ['acrobat', '=s', '/usr/local/bin/acroread',
580             { 'subtype' => 'file',
581             'help' => 'Path to acrobat reader.'
582             } ],
583             ],
584            
585             Also you can use a config file as parameter:
586            
587             -add_prefs => $path_to_cfg_file;
588            
589             =head2 -set_logo => $image_file;
590            
591             One logo for one program This picture will be use from the Splash and About
592             Method.
593             Carefully, if not defined in the Splash then an error is returned.
594            
595             =head2 -help => $pod_file;
596            
597             This includes a Help function as a topwindow with Poddisplay. Look for more
598             Information on Tk::Pod. Default is the program source ($0).
599            
600            
601             =head1 METHODS
602            
603             These are the methods you can use with this Widget.
604            
605             =head2 $top->init_prefs( I<$prefs> );
606            
607             This will initialize the user or default preferences. It returns a
608             reference to the options hash. More information about the prefsobject look at
609             B from
610             slaven. The Program which uses this Module has a configuration dialog in tk
611             and on the commandline with the following standard options:
612            
613             =over 4
614            
615             =item I: Save the geometry (size and position) from mainwindow.
616            
617             =item I: Save the font from mainwindow.
618            
619             =item I: Save the color from mainwindow.
620            
621             =back
622            
623             In the Standard menu you find the preferences dialog under I.
624            
625             I.E.:
626            
627             my $opt = $top->init_prefs();
628             print $opt->{Geometry};
629             ....
630            
631             =head2 $top->prefs();
632            
633             Display the Configuration dialog.
634              
635             =head2 $top->set_icon( I<$path_to_icon> );
636            
637             Set a new Icon at runtime.
638              
639             =head2 $top->set_logo( I<$path_to_logo> );
640            
641             Set a new Logo at runtime.
642              
643            
644             =head2 $top->init_menu( I<$menuitems> );
645            
646             Initialize the user or default Menu and return the Menuobject. You can set
647             your own menu with the first parameter. the other (clever) way: you add your own
648             menu to the standart menu.
649             I.E:
650            
651             # New menu item
652             my $edit_menu = $mw->Menu();
653             $edit_menu->command(-label => '~Copy', -command => sub{ print "Choice Copy\n" });
654             $edit_menu->command(-label => '~Cut', -command => sub{ print "Choice Cut\n" });
655             # ....
656            
657             my $menu = $mw->init_menu();
658             $menu->insert(1, 'cascade', -label => 'Edit', -menu => $edit_menu);
659            
660            
661             =head2 $top->splash( I<$milliseconds> );
662            
663             Display the Splashscreen for (optional) x milliseconds. The -set_logo option
664             is
665             required to initialize with a Picture. Also you can use this as Switch,
666             without any Parameter:
667            
668             $top->splash(); # Splash on
669             ....
670             working
671             ...
672             $top->splash(); # Splash off
673              
674             =head2 $top->config( I, I<$value> );
675            
676             You have data from your widgets and you will make this data persistent? No Problem:
677              
678             $top->config( 'Info', $new_ref_with_importand_informations )
679             ...
680             my $info = $top->config( 'Info' );
681            
682             =head2 $top->add_status( I<$name>, I<\$value> or I<\$widget> );
683            
684             Display a Status text field or a widget in the status bar, if you first call
685             add_status then will Tk::ApplicationNest create a status bar:
686              
687             my $widget = $mw->init_status()->Entry();
688             $widget->insert('end', 'Exampletext ....');
689            
690             my $status = {
691             One => 'Status one',
692             Full => 'Full sentence ....',
693             Time => sprintf('%d seconds', time),
694             Widget => $widget,
695             };
696            
697             # Add Status fields
698             foreach (sort keys %$status) {
699             $mw->add_status($_, \$status->{$_}) ;
700             }
701              
702             =head2 $top->add_toolar( I<$typ>, I<$options> );
703            
704             Display the ToolbarWidget at first call and include the Widget ($typ) with options ($options):
705            
706             # Add Button to toolbar
707             $mw->add_toolbar('Button',
708             -text => 'Button',
709             -tip => 'tool tip',
710             -command => sub { print "hi\n" });
711             $mw->add_toolbar('Label', -text => 'Label');
712             $mw->add_toolbar('separator');
713              
714             Look for more Information on Tk::ToolBar.
715              
716             =head2 $top->exit( );
717            
718             Close the program, you can include your code (before call the exit command) with:
719              
720             ...
721             $mw->configure(-exit_cb => sub{ .... })
722             $mw->exit;
723            
724             =head1 ADVERTISED WIDGETS
725            
726             You can use the advertise widget with the following command '$top->Subwidget('name_from_adv_widget')'.
727            
728             =head2 B: Menubar
729            
730             =head2 B
: Mainframe
731            
732             =head2 B: Statusframe
733            
734             =head2 B>: StatusEntry from $top->add_status
735              
736             =head2 B: Toolbar, if created
737            
738             =head1 BINDINGS
739              
740             =head2 I: Exit the Programm
741              
742             =head1 CHANGES
743            
744             $Log: ApplicationNest.pm,v $
745             Revision 1.1 2003/11/06 17:55:04 xpix
746             * new Modulname Tk::ApplicationNest
747             - little bug fixes and doku changes
748              
749             Revision 1.10 2003/08/18 11:26:39 xpix
750             * better debug routine
751              
752            
753             =head1 AUTHOR
754            
755             Copyright (C) 2003 , Frank (xpix) Herrmann. All rights reserved.
756            
757             http://xpix.dieserver.de
758            
759             This program is free software; you can redistribute it and/or
760             modify it under the same terms as Perl itself.
761            
762             =head1 KEYWORDS
763            
764             Tk, Tk::MainWindow