File Coverage

blib/lib/Tk/Carp.pm
Criterion Covered Total %
statement 55 112 49.1
branch 8 44 18.1
condition 5 9 55.5
subroutine 17 23 73.9
pod 0 4 0.0
total 85 192 44.2


line stmt bran cond sub pod time code
1             package Tk::Carp;
2              
3 1     1   43452 use strict;
  1         2  
  1         51  
4             require 5.005;
5              
6 1     1   5 use vars qw/$VERSION/;
  1         2  
  1         61  
7             $VERSION='1.2';
8              
9 1     1   6 use Exporter;
  1         5  
  1         42  
10 1     1   9 use Carp;
  1         2  
  1         154  
11              
12 1     1   5 use vars qw/@ISA @EXPORT @EXPORT_FAIL @EXPORT_OK/;
  1         2  
  1         116  
13             @ISA = qw(Exporter);
14             @EXPORT = qw(confess croak carp); # from Carp (also cluck)
15             @EXPORT_FAIL = qw(
16             fatalsToDialog
17             warningsToDialog
18             immediateWarnings
19             useTkDialog
20             tkDeathsNonFatal
21             );
22             @EXPORT_OK = (@EXPORT_FAIL, qw/ cluck tkdie tkwarn tkwarnnow /);
23              
24 1     1   5 use vars qw/$MainWindow $Dialog @WARNINGS/;
  1         1  
  1         55  
25             tie $MainWindow, 'Tk::Carp::_mainWindowTie';
26              
27 1     1   4 use vars qw/$ImmediateWarnings $FatalsToDialog $WarningsToDialog/;
  1         2  
  1         50  
28 1     1   4 use vars qw/$DieIcon $DieTitle $WarnIcon $WarnTitle/;
  1         2  
  1         61  
29 1     1   4 use vars qw/$UseTkDialog/;
  1         2  
  1         46  
30             $DieIcon = 'error'; # Valid icons: error, info, question or warning
31             $DieTitle = 'Error';
32             $WarnIcon = 'warning';
33             $WarnTitle = 'Warning';
34              
35 1     1   12 use vars qw/$OLDDIE $OLDWARN/; # play nice with others
  1         1  
  1         1359  
36             $OLDDIE = $SIG{__DIE__}; $SIG{__DIE__} = \&Tk::Carp::died;
37             $OLDWARN = $SIG{__WARN__}; $SIG{__WARN__} = \&Tk::Carp::warned;
38              
39             # handle special directives... well, specially
40             sub export_fail {
41 0     0 0 0 my $pkg = shift;
42 0         0 my @unknown;
43              
44 0         0 for my $failed (@_) {
45 0 0       0 if ($failed eq 'fatalsToDialog') { $FatalsToDialog = 1 }
  0 0       0  
    0          
    0          
    0          
46 0         0 elsif($failed eq 'warningsToDialog') { $WarningsToDialog = 1 }
47 0         0 elsif($failed eq 'immediateWarnings') { $ImmediateWarnings = 1 }
48 0         0 elsif($failed eq 'useTkDialog') { $UseTkDialog = 1 }
49 0         0 elsif($failed eq 'tkDeathsNonFatal') { undef &Tk::Error }
50 0         0 else { push @unknown, $failed }
51             }
52              
53 0         0 return @unknown;
54             }
55              
56             sub tkdie {
57 4     4   20 local $SIG{__DIE__}; # Suppress handling of death temporarily
58              
59 4 50       18 if($OLDDIE) {
60 0         0 eval { $OLDDIE->(@_) }; # invoke the old handler
  0         0  
61 0 0       0 if($@) { @_ = ($@) } # check for death in old handler; use as new message
  0         0  
62             }
63              
64 4         26 my $diehandler = (caller(1))[3] eq 'Tk::Carp::died';
65              
66             # Ignore die inside of evals, as it will be
67             # caught and propagated up to us if desired.
68 4 50 66     27 die @_ if $^S and $diehandler;
69              
70 4 100 100     26 if($FatalsToDialog or not $diehandler) {
71 2         8 dodialog($DieIcon, $DieTitle, @WARNINGS, @_); # show any warnings
72 2         6 @WARNINGS = (); # remove warnings so they're not accidentally shown twice
73             }
74              
75 4         45 die(@_);
76             }
77              
78             sub died {
79 4     4 0 1805 tkdie(@_);
80             }
81              
82             # Copied and modified from Tk.pm
83             # This lets us ignore die inside of evals, while still
84             # catching errors in Tk callbacks properly.
85             sub Tk::Error {
86 0     0   0 my ($w, $err, @msgs) = @_;
87              
88 0 0       0 if (Tk::Exists($w)) {
89 0         0 my $grab = $w->grab('current');
90 0 0       0 $grab->Unbusy if (defined $grab);
91             }
92 0         0 chomp($err);
93 0         0 $err = "Tk::Error: $err\n " . join("\n ",@msgs)."\n";
94              
95 0 0       0 if($FatalsToDialog) {
96 0         0 dodialog($DieIcon, $DieTitle, @WARNINGS, $err); # show any warnings
97 0         0 @WARNINGS = (); # remove warnings so they're not accidentally shown twice
98             }
99              
100             # Suppress handling of warnings or we would get the error
101             # reported twice (once as an error, and once as a warning).
102 0         0 local $SIG{__WARN__};
103 0         0 warn($err);
104             }
105              
106             sub tkwarn {
107 2     2   11 my $oldwarn_death;
108 2 50       8 if($OLDWARN) {
109 2         3 my @new_warns;
110 2         4 eval {
111 2     0   14 local $SIG{__WARN__} = sub { push @new_warns, @_ };
  0         0  
112 2         7 local $SIG{__DIE__}; # suppress handlers; we propagate any death later
113 2         7 $OLDWARN->(@_); # invoke the old handler
114             };
115 2         14 $oldwarn_death = $@; # get warnings out of the way first
116              
117             # Look for warnings from handler.
118             # If none, and there _is_ a handler,
119             # we have to suppress this warning,
120             # since that's what would happen if
121             # we weren't here to notice.
122 2 50       16 @_ = @new_warns ? @new_warns : goto SUPPRESS_WARNING;
123             }
124              
125 0 0 0     0 if($WarningsToDialog or (caller(1))[3] ne 'Tk::Carp::warned') {
126 0 0       0 if($ImmediateWarnings) {
127 0         0 dodialog($WarnIcon, $WarnTitle, @_);
128             } else {
129 0         0 push @WARNINGS, @_;
130             }
131             }
132              
133             {
134 0         0 local $SIG{__WARN__}; # Suppress handling of warning temporarily
  0         0  
135 0         0 warn(@_);
136             }
137              
138             SUPPRESS_WARNING:
139 2 50       10 die($oldwarn_death) if($oldwarn_death); # propagate any death in old handler
140             }
141              
142             sub tkwarnnow {
143 0     0 0 0 local $ImmediateWarnings = 1;
144 0         0 tkwarn(@_);
145             }
146              
147             sub warned {
148 2     2 0 564 tkwarn(@_);
149             }
150              
151             sub END {
152             # show any pending warnings
153 1 50   1   546 dodialog($WarnIcon, $WarnTitle, @WARNINGS) if(@WARNINGS);
154             }
155              
156             sub dodialog {
157 0     0     my $icon = shift;
158 0           my $title = shift;
159              
160 0           require Tk;
161 0           require Tk::Dialog;
162              
163 0 0         if($UseTkDialog) {
164              
165             # create MainWindow if it hasn't been already
166 0 0         unless($MainWindow) {
167 0           $MainWindow = MainWindow->new(
168             -title => 'Tk::Carp',
169             -name => 'winTkCarp',
170             );
171 0           $MainWindow->withdraw();
172             }
173              
174             # create the dialog if it hasn't been already
175 0 0         unless($Dialog) {
176 0           $Dialog = $MainWindow->Dialog(
177             -justify => 'left',
178             -default_button => 'Ok',
179             -buttons => ['Ok'],
180             );
181             }
182              
183             $Dialog->configure(
184 0           -bitmap => $icon,
185             -title => $title,
186             -text => join('', @_),
187             );
188 0           $Dialog->Show();
189              
190             } else {
191              
192             # On Win32 (at least), there is sometimes a problem if
193             # the user sets $Tk::Carp::MainWindow to their own MainWindow,
194             # and messageBox is called on it before MainLoop is entered.
195             # For some reason, it seems to cause all the widgets in the
196             # MainWindow to not respond to events. Of course, this
197             # can only happen if they specify immediateWarnings and
198             # trigger a warning during initialization, so it shouldn't
199             # often be an issue. Just in case, though, we create a
200             # fresh MainWindow every time... Seems wasteful. :-(
201 0           my $mw = MainWindow->new(
202             -name => 'winTkCarp_messageBox',
203             -title => 'Tk::Carp',
204             );
205 0           $mw->withdraw();
206 0           $mw->messageBox(
207             -icon => $icon,
208             -title => $title,
209             -type => 'OK',
210             -message => join('', @_),
211             );
212 0           $mw->destroy();
213              
214             }
215             }
216              
217             package Tk::Carp::_mainWindowTie;
218              
219 1     1   1285 use Tie::Scalar;
  1         825  
  1         36  
220 1     1   252 BEGIN { @Tk::Carp::_mainWindowTie::ISA = ('Tie::StdScalar') }
221              
222             sub STORE {
223 0     0     my $self = shift;
224             # If they overwrite $Tk::Carp::MainWindow with their own MainWindow
225             # and we've already created our own MainWindow, ours will stay
226             # around indefinately and keep the application open. Bad mojo.
227             # So, we destroy it first (and hope they haven't made a copy of it
228             # somewhere else for some strange reason).
229 0 0         if(defined $$self) {
230 0           $$self->destroy(); # $Tk::Carp::Dialog MUST be a child of the
231 0           undef $Tk::Carp::Dialog; # new MainWindow. We will recreate it later.
232             }
233 0           $$self = shift;
234             }
235              
236             1;
237              
238              
239             =head1 NAME
240              
241             Tk::Carp - Redirect warnings and errors to Tk Dialogs
242              
243             =head1 SYNOPSIS
244              
245             use Tk::Carp qw/cluck/;
246              
247             croak "Ribbit!";
248             confess "It was me: $!";
249             carp "How could you do that?";
250             warn "Duck!";
251             die "There's no hope...";
252             cluck "Don't do it.";
253              
254             use Tk::Carp qw/warningsToDialog/;
255             warn "Warnings will be displayed in a pop-up dialog.";
256              
257             use Tk::Carp qw/fatalsToDialog/;
258             die "Fatal error messages will be displayed in a pop-up dialog.";
259              
260             use Tk::Carp qw/tkwarn tkdie/;
261             tkwarn "Warning in dialog.";
262             tkdie "Death in dialog.";
263              
264             =head1 DESCRIPTION
265              
266             When Perl programs are run in a GUI environment, it is often desirable
267             to have them run with no console attached. Unfortunately, this causes
268             any warnings or errors to be lost. Worse, fatal errors can cause your
269             program to silently disappear, forcing you to restart the program,
270             attached to a console, and hope you can reproduce the error.
271              
272             This module makes it easy to see any errors or warnings your console-less
273             program might produce by catching any errors and/or warnings and displaying
274             them in a pop-up dialog box using Tk. It is similar in spirit to CGI::Carp's
275             C and C special import directives.
276              
277             To cause errors or warnings to be displayed in a dialog, simply specify one
278             or more of the following options on the C line, as shown in the
279             L.
280              
281             =head1 IMPORT OPTIONS
282              
283             =head2 C
284              
285             Show any warnings in a pop-up dialog box.
286              
287             This option will cause a dialog box to be displayed containing the
288             text of the warnings. The type and style of the dialog box can be
289             configured (see L<"CONFIGURATION">). Note that warnings are still
290             sent to C as well.
291              
292             This option can also be activated or deactivated by setting
293             C<$Tk::Carp::WarningsToDialog> to true or false, respectively.
294              
295             =head2 C
296              
297             Show any fatal errors in a pop-up dialog box.
298              
299             This option will cause a dialog box to be displayed containing the
300             text of the fatal error. The type and style of the dialog box can
301             be configured (see L<"CONFIGURATION">). Note that errors are still
302             sent to C as well.
303              
304             This option can also be activated or deactivated by setting
305             C<$Tk::Carp::FatalsToDialog> to true or false, respectively.
306              
307             =head2 C
308              
309             This option controls whether all errors and warnings are displayed
310             in a single dialog box or each get their own.
311              
312             By default, warnings are buffered and not shown until just before
313             the program terminates. At that point, any warnings and errors
314             are shown together in a single dialog box. This is to cut down
315             on the number of dialogs that have to be clicked through, although
316             it means that you can't tell when a particular warning occurred.
317              
318             If this option is specified, each warning and error message will get
319             its own dialog box which will be displayed as soon as the warning
320             or error occurs. Note that warnings are always printed to C
321             as soon as they occur, regardless of the state of this option.
322              
323             Care should be taken when setting this option as it can cause
324             a large number of dialog boxes to be created.
325              
326             This option can also be activated or deactivated by setting
327             C<$Tk::Carp::ImmediateWarnings> to true or false, respectively.
328              
329             =head2 C
330              
331             This option controls whether the dialog is displayed using
332             CmessageBox()> or C<$Tk::Carp::ShowTkDialog-E()>.
333              
334             By default, the dialog that is displayed when errors or warnings
335             are raised is done using CmessageBox()>. Under Win32,
336             this type of dialog seems to be implemented more natively than
337             C, and so has better support of focus-taking and icons.
338             Unfortunately, this type of dialog must be recreated, along with
339             a parenting C.
340              
341             If this option is specified, the dialog box will instead be displayed
342             using C<$Tk::Carp::ShowTkDialog-E()> which, by default, displays a
343             C object. Unlike C, the C
344             object is only created the first time it is used. This is more
345             efficient when used with the L
346             option. You can also manipulate or set the C object
347             used directly, gaining better control over the display. You can
348             even use a completely different type of object instead
349             (see L<"$Tk::Carp::Dialog"> and L<"$Tk::Carp::ShowTkDialog">).
350              
351             This option can also be activated or deactivated by setting
352             C<$Tk::Carp::UseTkDialog> to true or false, respectively.
353              
354             =head2 C
355              
356             This option causes errors generated in Tk callbacks to be treated as
357             warnings.
358              
359             The default Tk::Error handler converts fatal errors in callbacks to
360             warnings. Unless this option is specified, this module defines a
361             custom Tk::Error handler to allow them to be treated as fatal errors
362             (ie, use the icon and title associated with fatal errors, and displayed
363             immediately, regardless of the state of C<$Tk::Carp::ImmediateWarnings>).
364              
365             =head1 FUNCTIONS
366              
367             =head2 C
368              
369             Raises a warning, using a dialog. This function ignores the state
370             of C, although all other options are observed.
371              
372             =head2 C
373              
374             Raises a fatal error, using a dialog. This function ignores the state
375             of C, although all other options are observed.
376              
377             =head1 CONFIGURATION
378              
379             The following variables control the style and type of dialog box used.
380              
381             =head2 C<$Tk::Carp::DieIcon>
382              
383             Changes the icon displayed in the dialog box for fatal errors. Valid values
384             are any that could be used as the C<-icon> parameter to C, or
385             as the C<-bitmap> parameter to the Cconfigure()> method.
386              
387             The most common values are: C<'error'>, C<'info'>, C<'question'>
388             and C<'warning'>. The default value is C<'error'>.
389              
390             =head2 C<$Tk::Carp::DieTitle>
391              
392             A string that will be used as the title of the dialog box for fatal errors.
393              
394             =head2 C<$Tk::Carp::WarnIcon>
395              
396             Changes the icon displayed in the dialog box for warnings. Valid values
397             are the same as for C<$Tk::Carp::DieIcon>.
398              
399             The default value is C<'warning'>.
400              
401             =head2 C<$Tk::Carp::WarnTitle>
402              
403             A string that will be used as the title of the dialog box for warnings.
404              
405             =head2 C<$Tk::Carp::MainWindow>
406              
407             The C object used to create the dialog box. If not
408             defined, one will be created as needed. If your program has a Tk
409             MainWindow, you should set this variable to it.
410              
411             B If you create a C and enter C I
412             setting this variable to your C, and a warning or error is
413             raised with C enabled, you B call
414             C<$Tk::Carp::MainWindow-Edestroy()> when your C is closed,
415             or your application I. It will remain open but without
416             any visible windows. Really, it's just better to make sure you set
417             this variable to your C if you use C.
418              
419             =head2 C<$Tk::Carp::Dialog>
420              
421             The C object used if L<"$Tk::Carp::UseMessageBox"> is not
422             true. If not defined, one will be created as needed.
423              
424             You can use this variable to change the configuration, such as the font
425             or justification, of the object. You can also set this variable to a
426             totally different type of object (such as a C, or
427             C), though you must also set the
428             L<$Tk::Carp::ShowTkDialog|"$Tk::Carp::ShowTkDialog">
429             variable, lest you get "Bad option" errors (or worse).
430              
431             =head2 C<$Tk::Carp::ShowTkDialog>
432              
433             A pointer to a subroutine that is called to display the dialog box if
434             L<$Tk::Carp::UseMessageBox|"$Tk::Carp::UseMessageBox"> is false.
435             This subroutine should accept a list of strings to be displayed in the
436             dialog box. It should probably also use the
437             L<$Tk::Carp::DialogIcon|"$Tk::Carp::DialogIcon">,
438             L<$Tk::Carp::DialogTitle|"$Tk::Carp::DialogTitle">,
439             and L<$Tk::Carp::MainWindow|"$Tk::Carp::MainWindow"> variables.
440              
441             When used in conjunction with L<$Tk::Carp::Dialog|"$Tk::Carp::Dialog">,
442             changing this variable allows you to use a different type of object as
443             the dialog. For example, you could use a C to be able
444             to place other widgets in the dialog box, or a C to gain
445             complete control over the appearance of the dialog.
446              
447             The default subroutine (C<&Tk::Carp::ShowTkDialog()>) creates (if
448             necessary) a C object in L<$Tk::Carp::Dialog|"$Tk::Carp::Dialog">
449             and calls its C and C methods.
450              
451             =head1 BUGS
452              
453             This module installs a signal handler for both C<__DIE__> and C<__WARN__>.
454             While it does save any previous handlers and chain them properly, any new
455             handler that is installed will effectively disable the C
456             and C options, respectively. Tk seems to do this
457             during some of its object initializations. This can occasionally cause
458             errors or warnings generated inside Tk widget code to be lost.
459             (Note: this was probably fixed by the use of a Tk::Error sub, but see
460             the next bug.)
461              
462             The introduction of a Tk::Error sub means that if code that uses this
463             module defines its own Tk::Error sub it will generate a "Subroutine
464             redefined at..." warning. Worse, if the sub is defined before this
465             module is Cd, this module's Tk::Error sub will not only generate
466             a redefinition warning, but will overwrite the user's sub. If you
467             want to use a custom Tk::Error sub and still want errors to be sent
468             to a dialog, you can use the following (somewhat convoluted) code:
469             use Tk::Carp;
470             BEGIN {
471             $OldTkError = \&Tk::Error;
472             no warnings 'redefine'; # only works in >= 5.6.0
473             *Tk::Error = sub {
474             $OldTkError->(@_); # Call Tk::Carp's handler so dialog is shown
475             # your code here
476             }
477             }
478              
479             By default, C, C and C are exported from
480             C. If nothing is specified in the import list (including the
481             special C<*ToDialog>, C, and C options),
482             then C also exports those functions. As soon as I is
483             given in the import list, however, C stops exporting the things
484             in C<@EXPORT>, meaning the aforementioned functions.
485              
486             =head1 AUTHORS
487              
488             Copyright 2001, Cory Johns. All rights reserved.
489              
490             This module is free software; you can redistribute and/or modify
491             it under the same terms as Perl itself.
492              
493             Address bug reports and comments to: johnsca@cpan.org
494              
495             =head1 SEE ALSO
496              
497             Carp, CGI::Carp, Tk, Tk::Dialog
498