#############################################################################
# Background error handler with email support
#############################################################################
# $Id: BrowseError.tcl,v 1.1 2006-01-17 14:27:55+01 rolf Exp rolf $
#############################################################################


#############################################################################
# Global variables & Setup
###########################################################
namespace eval myerror {
    variable MyError
    
    set MyError(Win)            .myErrorDialog
    set MyError(WinTitle)       "Browse application error"
    
    set MyError(Button)         -1      ;# The button number pressed

    set MyError(MsgFont)        {Times -18}
    set MyError(EmailTo)        Rolf.Schroedter@dlr.de
    
    namespace export bgerror error_ret 
}

###########################################################
# Destroy the error dialog window
###########################################################
proc myerror::Destroy {w} {
    variable MyError

    if {$w eq $MyError(Win)} {
        set MyError(Button) -1
    }
}

###########################################################
# Show error details (stack) in a text widget
###########################################################
proc myerror::Details {} {
    variable MyError

    set w $MyError(Win)
    set caption [option get $w.details text {}]
    set command [option get $w.details command {}]
    if { ($caption eq "") || ($command eq "") } {
        grid forget $w.details
    }
    $w.details configure -text $caption -command \
        "$command [list [.myErrorDialog.top.info.text get 1.0 end]]"
    grid $w.top.info - -sticky nsew -padx 3m -pady 3m
}

###########################################################
# Error dialog window
# Code 'stolen' from Tk's bgerror.tcl 
###########################################################
proc myerror::ErrorDialog {err} {
    global errorInfo tcl_platform
    variable MyError

    set info $errorInfo

    # 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 $MyError(Win)
    set title $MyError(WinTitle)
    set text "Error: $displayedErr"
    set buttons [list ok "Ok"   dismiss "Ignore"  details "Details >>"]

    # 1. Create the top-level window and divide it into top
    # and bottom parts.

    catch {destroy $w}
    toplevel $w -class ErrorDialog
    wm title $w $title
    wm iconname $w ErrorDialog

    frame $w.bot
    frame $w.top
    if {$tcl_platform(platform) eq "unix"} {
        $w.bot configure -relief raised -bd 1
        $w.top configure -relief raised -bd 1
    }
    pack $w.bot -side bottom -fill both
    pack $w.top -side top -fill both -expand 1

    set W [frame $w.top.info]
    text $W.text -setgrid true -width 40 -height 10 -state normal -wrap char \
            -bd 2 -relief sunken -highlightthickness 1 \
            -yscrollcommand [list $W.scroll set]

    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

    label $w.msg -justify left -text $text -font $MyError(MsgFont)
    canvas $w.bitmap -width 32 -height 32 -highlightthickness 0
    $w.bitmap create oval 0 0 31 31 -fill red -outline black
    $w.bitmap create line 9 9 23 23 -fill white -width 4
    $w.bitmap create line 9 23 23 9 -fill white -width 4
    grid $w.bitmap $w.msg -row 0 -padx 3m -pady 3m -in $w.top
            
    grid configure              $w.msg -sticky nsw
    grid rowconfigure           $w.top 1 -weight 1
    grid columnconfigure        $w.top 1 -weight 1

    # 3. Create a row of buttons at the bottom of the dialog.

    set i 0
    foreach {name caption} $buttons {
        button $w.$name -text $caption -default normal \
            -command [list set myerror::MyError(Button) $i]
        grid $w.$name -column $i -row 0 -sticky ew -padx 10 -in $w.bot
        grid columnconfigure $w.bot $i -weight 1
        incr i
    }
    # The "OK" button is the default for this dialog.
    $w.ok configure -default active

    bind $w <Return>                ::myerror::Return]
    bind $w <Destroy>               {::myerror::Destroy %W}
    $w.details configure -command   ::myerror::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 $w
    update idletasks
    set parent [winfo parent    $w]
    set width  [winfo reqwidth  $w]
    set height [winfo reqheight $w]
    set x [expr {([winfo screenwidth $w]  - $width )/2 - [winfo vrootx $parent]}]
    set y [expr {([winfo screenheight $w] - $height)/2 - [winfo vrooty $parent]}]
    $w configure -width $width
    wm geometry $w +$x+$y
    wm deiconify $w

    # 7. Set a grab and claim the focus too.

    set oldFocus [focus]
    set oldGrab [grab current $w]
    if {$oldGrab != ""} {
        set grabStatus [grab status $oldGrab]
    }
    grab $w
    focus $w.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 ::myerror::MyError(Button)
    set button $MyError(Button)
    catch {focus $oldFocus}
    catch {destroy $w}
    if {$oldGrab ne ""} {
        if {$grabStatus eq "global"} {
            grab -global $oldGrab
        } else {
            grab $oldGrab
        }
    }

    if {$button == 1} {
        return -code break
    }
}

###########################################################
# My bgerror proc
# And a version returning from the caller
###########################################################
proc myerror::bgerror {err} {
    variable MyError
    
    ErrorDialog $err
}
proc myerror::error_ret {err} {
#    tk_messageBox -type ok -icon error -message $err
#    MessageDlg .error -type ok -icon error -message $err
    bgerror $err
    return -code return
}

namespace import ::myerror::bgerror ::myerror::error_ret 
