3 # Implementation of the bgerror procedure. It posts a dialog box with
4 # the error message and gives the user a chance to see a more detailed
5 # stack trace, and possible do something more interesting with that
6 # trace (like save it to a log). This is adapted from work done by
9 # Copyright (c) 1998-2000 by Ajuba Solutions.
10 # Copyright (c) 2007 by ActiveState Software Inc.
11 # Copyright (c) 2007 Daniel A. Steffen <das@users.sourceforge.net>
13 namespace eval ::tk::dialog::error {
14 namespace import
-force ::tk::msgcat::*
15 namespace export
bgerror
16 option add
*ErrorDialog.function.
text [mc
"Save To Log"] \
18 option add
*ErrorDialog.function.command
[namespace code SaveToLog
]
19 option add
*ErrorDialog
*Label.
font TkCaptionFont widgetDefault
20 if {[tk windowingsystem
] eq
"aqua"} {
21 option add
*ErrorDialog
*background systemAlertBackgroundActive
\
23 option add
*ErrorDialog
*info.
text.background white widgetDefault
24 option add
*ErrorDialog
*Button.highlightBackground
\
25 systemAlertBackgroundActive widgetDefault
29 proc ::tk::dialog::error::Return {} {
32 .bgerrorDialog.ok configure
-state active
-relief sunken
38 proc ::tk::dialog::error::Details {} {
40 set caption
[option get
$w.function
text {}]
41 set command
[option get
$w.function command
{}]
42 if { ($caption eq
"") ||
($command eq
"") } {
43 grid forget
$w.function
45 lappend command
[$w.top.
info.
text get
1.0 end-1c
]
46 $w.function configure
-text $caption -command $command
47 grid $w.top.
info - -sticky nsew
-padx 3m
-pady 3m
50 proc ::tk::dialog::error::SaveToLog {text} {
51 if { $::tcl_platform(platform
) eq
"windows" } {
57 [list [mc
"Log Files"] .log
] \
58 [list [mc
"Text Files"] .txt
] \
59 [list [mc
"All Files"] $allFiles] \
61 set filename [tk_getSaveFile -title [mc
"Select Log File"] \
62 -filetypes $types -defaultextension .log
-parent .bgerrorDialog
]
63 if {![string length
$filename]} {
66 set f
[open $filename w
]
67 puts -nonewline $f $text
71 proc ::tk::dialog::error::Destroy {w
} {
72 if {$w eq
".bgerrorDialog"} {
78 # ::tk::dialog::error::bgerror --
79 # This is the default version of bgerror.
80 # It tries to execute tkerror, if that fails it posts a dialog box containing
81 # the error message and gives the user a chance to ask to see a stack
84 # err - The error message.
86 proc ::tk::dialog::error::bgerror err
{
87 global errorInfo tcl_platform
92 set ret
[catch {::tkerror $err} msg
];
93 if {$ret != 1} {return -code $ret $msg}
95 # Ok the application's tkerror either failed or was not found
96 # we use the default dialog then :
97 set windowingsystem
[tk windowingsystem
]
98 if {$windowingsystem eq
"aqua"} {
104 # Truncate the message if it is too wide (>maxLine characters) or
105 # too tall (>4 lines). Truncation occurs at the first point at
106 # which one of those conditions is met.
110 foreach line
[split $err \n] {
111 if { [string length
$line] > $maxLine } {
112 append displayedErr
"[string range $line 0 [expr {$maxLine-3}]]..."
116 append displayedErr
"..."
119 append displayedErr
"${line}\n"
124 set title
[mc
"Application Error"]
125 set text [mc
"Error: %1\$s" $displayedErr]
126 set buttons
[list ok
$ok dismiss
[mc
"Skip Messages"] \
127 function
[mc
"Details >>"]]
129 # 1. Create the top-level window and divide it into top
132 set dlg .bgerrorDialog
134 toplevel $dlg -class ErrorDialog
137 wm iconname
$dlg ErrorDialog
138 wm protocol
$dlg WM_DELETE_WINDOW
{ }
140 if {$windowingsystem eq
"aqua"} {
141 ::tk::unsupported::MacWindowStyle style
$dlg moveableAlert
{}
142 } elseif
{$windowingsystem eq
"x11"} {
143 wm attributes
$dlg -type dialog
148 if {$windowingsystem eq
"x11"} {
149 $dlg.bot configure
-relief raised
-bd 1
150 $dlg.top configure
-relief raised
-bd 1
152 pack $dlg.bot
-side bottom
-fill both
153 pack $dlg.top
-side top
-fill both
-expand 1
155 set W
[frame $dlg.top.
info]
156 text $W.
text -setgrid true
-height 10 -wrap char
\
157 -yscrollcommand [list $W.scroll
set]
158 if {$windowingsystem ne
"aqua"} {
159 $W.
text configure
-width 40
162 scrollbar $W.scroll
-command [list $W.
text yview
]
163 pack $W.scroll
-side right
-fill y
164 pack $W.
text -side left
-expand yes
-fill both
165 $W.
text insert
0.0 "$err\n$info"
166 $W.
text mark
set insert
0.0
167 bind $W.
text <ButtonPress-1
> { focus %W
}
168 $W.
text configure
-state disabled
170 # 2. Fill the top part with bitmap and message
172 # Max-width of message is the width of the screen...
173 set wrapwidth
[winfo screenwidth
$dlg]
174 # ...minus the width of the icon, padding and a fudge factor for
175 # the window manager decorations and aesthetics.
176 set wrapwidth
[expr {$wrapwidth-60-[winfo pixels
$dlg 9m
]}]
177 label $dlg.msg
-justify left
-text $text -wraplength $wrapwidth
178 if {$windowingsystem eq
"aqua"} {
179 # On the Macintosh, use the stop bitmap
180 label $dlg.
bitmap -bitmap stop
182 # On other platforms, make the error icon
183 canvas $dlg.
bitmap -width 32 -height 32 -highlightthickness 0
184 $dlg.
bitmap create oval
0 0 31 31 -fill red
-outline black
185 $dlg.
bitmap create line
9 9 23 23 -fill white
-width 4
186 $dlg.
bitmap create line
9 23 23 9 -fill white
-width 4
188 grid $dlg.
bitmap $dlg.msg
-in $dlg.top
-row 0 -padx 3m
-pady 3m
189 grid configure
$dlg.msg
-sticky nsw
-padx {0 3m
}
190 grid rowconfigure
$dlg.top
1 -weight 1
191 grid columnconfigure
$dlg.top
1 -weight 1
193 # 3. Create a row of buttons at the bottom of the dialog.
196 foreach {name caption
} $buttons {
197 button $dlg.
$name -text $caption -default normal
\
198 -command [namespace code
[list set button $i]]
199 grid $dlg.
$name -in $dlg.bot
-column $i -row 0 -sticky ew
-padx 10
200 grid columnconfigure
$dlg.bot
$i -weight 1
201 # We boost the size of some Mac buttons for l&f
202 if {$windowingsystem eq
"aqua"} {
203 if {($name eq
"ok") ||
($name eq
"dismiss")} {
204 grid columnconfigure
$dlg.bot
$i -minsize 90
206 grid configure
$dlg.
$name -pady 7
210 # The "OK" button is the default for this dialog.
211 $dlg.ok configure
-default active
213 bind $dlg <Return
> [namespace code Return
]
214 bind $dlg <Destroy
> [namespace code
[list Destroy
%W
]]
215 $dlg.function configure
-command [namespace code Details
]
217 # 6. Withdraw the window, then update all the geometry information
218 # so we know how big it wants to be, then center the window in the
219 # display (Motif style) and de-iconify it.
221 ::tk::PlaceWindow $dlg
223 # 7. Ensure that we are topmost.
226 if {[tk windowingsystem
] eq
"win32"} {
227 # Place it topmost if we aren't at the top of the stacking
228 # order to ensure that it's seen
229 if {[lindex [wm stackorder .
] end
] ne
"$dlg"} {
230 wm attributes
$dlg -topmost 1
234 # 8. Set a grab and claim the focus too.
236 ::tk::SetFocusGrab $dlg $dlg.ok
238 # 9. Wait for the user to respond, then restore the focus and
239 # return the index of the selected button. Restore the focus
240 # before deleting the window, since otherwise the window manager
241 # may take the focus away so we can't redirect it. Finally,
242 # restore any grab that was in effect.
244 vwait [namespace which
-variable button]
245 set copy
$button; # Save a copy...
247 ::tk::RestoreFocusGrab $dlg $dlg.ok
destroy
258 namespace import
::tk::dialog::error::bgerror