File Coverage

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