OSDN Git Service

Updated to tk 8.4.1
[pf3gnuchains/sourceware.git] / tk / library / bgerror.tcl
index e5f47f3..1407b55 100644 (file)
@@ -1,19 +1,79 @@
 # bgerror.tcl --
 #
-# This file contains a default version of the bgerror procedure.  It
-# posts a dialog box with the error message and gives the user a chance
-# to see a more detailed stack trace.
+#      Implementation of the bgerror procedure.  It posts a dialog box with
+#      the error message and gives the user a chance to see a more detailed
+#      stack trace, and possible do something more interesting with that
+#      trace (like save it to a log).  This is adapted from work done by
+#      Donal K. Fellows.
 #
+# Copyright (c) 1998-2000 by Ajuba Solutions.
+# All rights reserved.
+# 
 # RCS: @(#) $Id$
-#
-# Copyright (c) 1992-1994 The Regents of the University of California.
-# Copyright (c) 1994-1996 Sun Microsystems, Inc.
-#
-# See the file "license.terms" for information on usage and redistribution
-# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# $Id$
 
+namespace eval ::tk {
+    namespace eval dialog {
+       namespace eval error {
+           namespace import ::tk::msgcat::*
+           namespace export bgerror
+           option add *ErrorDialog.function.text [mc "Save To Log"] \
+                   widgetDefault
+           option add *ErrorDialog.function.command [namespace code SaveToLog]
+       }
+    }
+}
 
-# bgerror --
+proc ::tk::dialog::error::Return {} {
+    variable button
+    
+    .bgerrorDialog.ok configure -state active -relief sunken
+    update idletasks
+    after 100
+    set button 0
+}
+
+proc ::tk::dialog::error::Details {} {
+    set w .bgerrorDialog
+    set caption [option get $w.function text {}]
+    set command [option get $w.function command {}]
+    if { ($caption eq "") || ($command eq "") } {
+       grid forget $w.function
+    }
+    $w.function configure -text $caption -command \
+       "$command [list [.bgerrorDialog.top.info.text get 1.0 end]]"
+    grid $w.top.info - -sticky nsew -padx 3m -pady 3m
+}
+
+proc ::tk::dialog::error::SaveToLog {text} {
+    if { $::tcl_platform(platform) eq "windows" } {
+       set allFiles *.*
+    } else {
+       set allFiles *
+    }
+    set types [list    \
+           [list [mc "Log Files"] .log]        \
+           [list [mc "Text Files"] .txt]       \
+           [list [mc "All Files"] $allFiles] \
+           ]
+    set filename [tk_getSaveFile -title [mc "Select Log File"] \
+           -filetypes $types -defaultextension .log -parent .bgerrorDialog]
+    if {![string length $filename]} {
+       return
+    }
+    set f [open $filename w]
+    puts -nonewline $f $text
+    close $f
+}
+
+proc ::tk::dialog::error::Destroy {w} {
+    if {$w eq ".bgerrorDialog"} {
+       variable button
+       set button -1
+    }
+}
+
+# ::tk::dialog::error::bgerror --
 # This is the default version of bgerror. 
 # It tries to execute tkerror, if that fails it posts a dialog box containing
 # the error message and gives the user a chance to ask to see a stack
 # Arguments:
 # err -                        The error message.
 
-proc bgerror err {
+proc ::tk::dialog::error::bgerror err {
     global errorInfo tcl_platform
-    
-    # save errorInfo which would be erased in the catch below otherwise.
-    set info $errorInfo ;
-
-    # For backward compatibility :
-    # Let's try to execute "tkerror" (using catch {tkerror ...} 
-    # instead of searching it with info procs so the application gets
-    # a chance to auto load it using its favorite "unknown" mecanism.
-    # (we do the default dialog only if we get a TCL_ERROR (=1) return
-    #  code from the tkerror trial, other ret codes are passed back
-    #  to our caller (tcl background error handler) so the called "tkerror"
-    #  can still use  return -code break, to skip remaining messages
-    #  in the error queue for instance)
-
-    set ret [catch {tkerror $err} msg];
+    variable button
+
+    set info $errorInfo
+
+    set ret [catch {::tkerror $err} msg];
     if {$ret != 1} {return -code $ret $msg}
 
     # Ok the application's tkerror either failed or was not found
     # we use the default dialog then :
-    if {$tcl_platform(platform) == "macintosh"} {
-       set ok Ok
+    if {($tcl_platform(platform) eq "macintosh")
+             || ([tk windowingsystem] eq "aqua")} {
+       set ok          [mc Ok]
+       set messageFont system
+       set textRelief  flat
+       set textHilight 0
     } else {
-       set ok OK
+       set ok          [mc OK]
+       set messageFont {Times -18}
+       set textRelief  sunken
+       set textHilight 1
     }
-    set button [tk_dialog .bgerrorDialog "Error in Tcl Script" \
-           "Error: $err" error 0 $ok "Skip Messages" "Stack Trace"]
-    if {$button == 0} {
-       return
-    } elseif {$button == 1} {
-       return -code break
+
+
+    # Truncate the message if it is too wide (longer than 30 characacters) or
+    # too tall (more than 4 newlines).  Truncation occurs at the first point at
+    # which one of those conditions is met.
+    set displayedErr ""
+    set lines 0
+    foreach line [split $err \n] {
+       if { [string length $line] > 30 } {
+           append displayedErr "[string range $line 0 29]..."
+           break
+       }
+       if { $lines > 4 } {
+           append displayedErr "..."
+           break
+       } else {
+           append displayedErr "${line}\n"
+       }
+       incr lines
+    }
+
+    set w .bgerrorDialog
+    set title [mc "Application Error"]
+    set text [mc {Error: %1$s} $err]
+    set buttons [list ok $ok dismiss [mc "Skip Messages"] \
+           function [mc "Details >>"]]
+
+    # 1. Create the top-level window and divide it into top
+    # and bottom parts.
+
+    catch {destroy .bgerrorDialog}
+    toplevel .bgerrorDialog -class ErrorDialog
+    wm title .bgerrorDialog $title
+    wm iconname .bgerrorDialog ErrorDialog
+    wm protocol .bgerrorDialog WM_DELETE_WINDOW { }
+
+    if {($tcl_platform(platform) eq "macintosh") 
+            || ([tk windowingsystem] eq "aqua")} {
+       ::tk::unsupported::MacWindowStyle style .bgerrorDialog dBoxProc
     }
 
-    set w .bgerrorTrace
-    catch {destroy $w}
-    toplevel $w -class ErrorTrace
-    wm minsize $w 1 1
-    wm title $w "Stack Trace for Error"
-    wm iconname $w "Stack Trace"
-    button $w.ok -text OK -command "destroy $w" -default active
-    if {![string compare $tcl_platform(platform) "macintosh"]} {
-      text $w.text -relief flat -bd 2 -highlightthickness 0 -setgrid true \
-           -yscrollcommand "$w.scroll set" -width 60 -height 20
+    frame .bgerrorDialog.bot
+    frame .bgerrorDialog.top
+    if {[tk windowingsystem] eq "x11"} {
+       .bgerrorDialog.bot configure -relief raised -bd 1
+       .bgerrorDialog.top configure -relief raised -bd 1
+    }
+    pack .bgerrorDialog.bot -side bottom -fill both
+    pack .bgerrorDialog.top -side top -fill both -expand 1
+
+    set W [frame $w.top.info]
+    text $W.text                               \
+           -bd 2                               \
+           -yscrollcommand [list $W.scroll set]\
+           -setgrid true                       \
+           -width 40                           \
+           -height 10                          \
+           -state normal                       \
+           -relief $textRelief                 \
+           -highlightthickness $textHilight    \
+           -wrap char
+
+    scrollbar $W.scroll -relief sunken -command [list $W.text yview]
+    pack $W.scroll -side right -fill y
+    pack $W.text -side left -expand yes -fill both
+    $W.text insert 0.0 "$err\n$info"
+    $W.text mark set insert 0.0
+    bind $W.text <ButtonPress-1> { focus %W }
+    $W.text configure -state disabled
+
+    # 2. Fill the top part with bitmap and message
+
+    # Max-width of message is the width of the screen...
+    set wrapwidth [winfo screenwidth .bgerrorDialog]
+    # ...minus the width of the icon, padding and a fudge factor for
+    # the window manager decorations and aesthetics.
+    set wrapwidth [expr {$wrapwidth-60-[winfo pixels .bgerrorDialog 9m]}]
+    label .bgerrorDialog.msg -justify left -text $text -font $messageFont \
+           -wraplength $wrapwidth
+    if {($tcl_platform(platform) eq "macintosh")
+            || ([tk windowingsystem] eq "aqua")} {
+       # On the Macintosh, use the stop bitmap
+       label .bgerrorDialog.bitmap -bitmap stop
     } else {
-      text $w.text -relief sunken -bd 2 -yscrollcommand "$w.scroll set" \
-           -setgrid true -width 60 -height 20
+       # On other platforms, make the error icon
+       canvas .bgerrorDialog.bitmap -width 32 -height 32 -highlightthickness 0
+       .bgerrorDialog.bitmap create oval 0 0 31 31 -fill red -outline black
+       .bgerrorDialog.bitmap create line 9 9 23 23 -fill white -width 4
+       .bgerrorDialog.bitmap create line 9 23 23 9 -fill white -width 4
     }
-    scrollbar $w.scroll -relief sunken -command "$w.text yview"
-    pack $w.ok -side bottom -padx 3m -pady 2m
-    pack $w.scroll -side right -fill y
-    pack $w.text -side left -expand yes -fill both
-    $w.text insert 0.0 $info
-    $w.text mark set insert 0.0
+    grid .bgerrorDialog.bitmap .bgerrorDialog.msg \
+           -in .bgerrorDialog.top      \
+           -row 0                      \
+           -padx 3m                    \
+           -pady 3m
+    grid configure      .bgerrorDialog.msg -sticky nsw -padx {0 3m}
+    grid rowconfigure   .bgerrorDialog.top 1 -weight 1
+    grid columnconfigure .bgerrorDialog.top 1 -weight 1
 
-    bind $w <Return> "destroy $w"
-    bind $w.text <Return> "destroy $w; break"
+    # 3. Create a row of buttons at the bottom of the dialog.
 
-    # Center the window on the screen.
+    set i 0
+    foreach {name caption} $buttons {
+       button .bgerrorDialog.$name     \
+               -text $caption          \
+               -default normal         \
+               -command [namespace code "set button $i"]
+       grid .bgerrorDialog.$name       \
+               -in .bgerrorDialog.bot  \
+               -column $i              \
+               -row 0                  \
+               -sticky ew              \
+               -padx 10
+       grid columnconfigure .bgerrorDialog.bot $i -weight 1
+       # We boost the size of some Mac buttons for l&f
+       if {($tcl_platform(platform) eq "macintosh")
+           || ([tk windowingsystem] eq "aqua")} {
+           if {($name eq "ok") || ($name eq "dismiss")} {
+               grid columnconfigure .bgerrorDialog.bot $i -minsize 79
+           }
+       }
+       incr i
+    }
+    # The "OK" button is the default for this dialog.
+    .bgerrorDialog.ok configure -default active
 
-    wm withdraw $w
+    bind .bgerrorDialog <Return>       [namespace code Return]
+    bind .bgerrorDialog <Destroy>      [namespace code [list Destroy %W]]
+    .bgerrorDialog.function configure -command [namespace code Details]
+
+    # 6. Withdraw the window, then update all the geometry information
+    # so we know how big it wants to be, then center the window in the
+    # display and de-iconify it.
+
+    wm withdraw .bgerrorDialog
     update idletasks
-    set x [expr {[winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \
-           - [winfo vrootx [winfo parent $w]]}]
-    set y [expr {[winfo screenheight $w]/2 - [winfo reqheight $w]/2 \
-           - [winfo vrooty [winfo parent $w]]}]
-    wm geom $w +$x+$y
-    wm deiconify $w
-
-    # Be sure to release any grabs that might be present on the
-    # screen, since they could make it impossible for the user
-    # to interact with the stack trace.
-
-    if {[string compare [grab current .] ""]} {
-       grab release [grab current .]
+    set parent [winfo parent   .bgerrorDialog]
+    set width  [winfo reqwidth .bgerrorDialog]
+    set height [winfo reqheight        .bgerrorDialog]
+    set x [expr {([winfo screenwidth .bgerrorDialog]  - $width )/2 - \
+           [winfo vrootx $parent]}]
+    set y [expr {([winfo screenheight .bgerrorDialog] - $height)/2 - \
+           [winfo vrooty $parent]}]
+    .bgerrorDialog configure -width $width
+    wm geometry .bgerrorDialog +$x+$y
+    wm deiconify .bgerrorDialog
+
+    # 7. Set a grab and claim the focus too.
+
+    set oldFocus [focus]
+    set oldGrab [grab current .bgerrorDialog]
+    if {$oldGrab != ""} {
+       set grabStatus [grab status $oldGrab]
     }
-}
+    grab .bgerrorDialog
+    focus .bgerrorDialog.ok
+
+    # 8. Wait for the user to respond, then restore the focus and
+    # return the index of the selected button.  Restore the focus
+    # before deleting the window, since otherwise the window manager
+    # may take the focus away so we can't redirect it.  Finally,
+    # restore any grab that was in effect.
 
+    vwait [namespace which -variable button]
+    set copy $button; # Save a copy...
+    catch {focus $oldFocus}
+    catch {destroy .bgerrorDialog}
+    if {$oldGrab ne ""} {
+       if {$grabStatus eq "global"} {
+           grab -global $oldGrab
+       } else {
+           grab $oldGrab
+       }
+    }
+
+    if {$copy == 1} {
+       return -code break
+    }
+}
 
+namespace eval :: {
+    # Fool the indexer
+    proc bgerror err {}
+    rename bgerror {}
+    namespace import ::tk::dialog::error::bgerror
+}