]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wx/lib/ErrorDialogs.py
Fix or add some DoGetBestSize's
[wxWidgets.git] / wxPython / wx / lib / ErrorDialogs.py
index eb20380b307f317bb84b6d767125201480f0a448..0fb94350a251d8f3d9504624ab1daa6b198ea3b1 100644 (file)
+#----------------------------------------------------------------------------
+# Name:         ErrorDialogs.py
+# Version:      1.0
+# Created:      September--October 2001
+# Author:       Chris Fama of Wholly Snakes Software,
+#               Chris.Fama@whollysnakes.com
+#----------------------------------------------------------------------------
+"""
+ErrorDialogs.py: by Christopher J. Fama (trading under the name
+Wholly Snakes Software {Australian Business Number: 28379514278}).
 
-"""Renamer stub: provides a way to drop the wx prefix from wxPython objects."""
+This code is released under the auspices of the modified version of
+the GNU Library Public License (LGPL) that constitutes the license
+under which the GUI package wxPython is released [see the file
+LICENSE.TXT accompanying that distribution).  I must also thank Graham
+Boyd, of Boyd Mining, and CEO of the Minserve group of companies
+(www.minserve.com.au), for kindly allowing the release of this
+module under a "free" license, despite a certain part of it's
+development having taken place while working for him...
 
-__cvsid__ = "$Id$"
-__revision__ = "$Revision$"[11:-2]
+Please note that this code, written for Python 2.1, is derives from
+code written when Python 1.5.2 was current.  Although since Python 2.0
+the sys.excepthook variable has been available, for ease and potential
+backwards compatibility (or to be more realistic
+backwards-PARTIAL-compatibility!), the code catches errors by
+assigning a custom object to sys.stderr and monitoring calls to it's
+writ) method.  Such calls which take place with a new value of
+sys.last_traceback stand as evidence that at interpreter error has
+just occurred; please note that this means that NO OTHER OUTPUT TO
+sys.stderr WILL BE DISPLAYED.  THIS INCLUDES "warnings" generated by
+the interpreter.  As far as I am aware, unless your code itself writes
+to sys.stderr itself, these will be the only things you miss out
+on--and many, if not most or all, of these will occur before your code
+even gets the opportunity to set one of these file-like objects in
+place.  If this is a problem for you and you can't work around it,
+please contact means or the wxPython-users mailing list.
+
+
+DOCUMENTATION:
+
+This is a module to display errors--either explicitly requested by a
+script or arbitrary interpreter errors--these needs arose in the
+course of a commercial (contract) project, but were not developed in
+the course of work on such [well, very little, albeit concurrently]...
+[NBNB.Does not currently support display of other than interpreter errors.]
+
+Usage, after 'from wxPython.lib.ErrorDialogs import *' (all
+identifiers defined in this module begin with "wxPy", and many of them
+with "wxPyError_", so there should be no namespace conflicts...):
+
+    wxPyNewErrorDialog (<win> (['frame='] <frame (can be None)>,
+                                         <OPTIONS>))
+                   ...
+    wxPyDestroyErrorDialogIfPresent () # e.g. when top frame destroyed)
+
+for unhandled errors, or
+
+    returnval = wxpyNonFatalError (<frame (can be None)>,
+                          <HTML message>
+                          [,<OPTIONS>])
+or
+    returnval = wxPyFatalError (<HTML message>,
+                       [,<OPTIONS, an extra one of which may be
+                          'frame=' <frame (defaults to None)>>])
+or
+
+    wxPybNonWindowingError (message)
+
+for explicit errors.
+
+<win> is one of
+    wxPyNonFatalErrorDialog
+    wxPyFatalErrorDialog
+    wxPyFatalErrorDialogWithTraceback
+    wxPyNonFatalErrorDialogWithTraceback
+    wxPyNonWindowingErrorHandler
+
+and the OPTIONS (with defaults) are: (please note that the options for
+wxPyNonWindowingErrorHandler / wxPyNonWindowingError are 'almost' a (small))
+subset of these):
+
+    'modal' [default 1]: block until dismissed.
+
+    'programname' [default "Python program"]: appears inThe
+    caption of the dialog, amidst it's text and (by default) in mailings.
+
+    'whendismissed' option, if given, this should be a string, to be
+    executed in a restricted environment (see rexec module) after
+    dialog dismissal.  Typically, this should be Python code to "clean
+    up" after what was presumably the partial execution of some
+    operation started by the user, after the unexpected interruption
+    by some error [which--at least the way I work, means an unexpected
+    error in the code, since exceptions that may be raised by some
+    foreseen (in a programmatic sense) should normally be handled by
+    try...except clauses].
+    NOTE THAT CURRENTLY THE rexec CODE IS NOT WORKING, SO THIS IS JUST DONE
+    BY exec...
+
+    'mailto': if None, give no "e-mail support" option, otherwise this
+    is meant to be an address for 'bug reports'; a command button will
+    be created for this, which pops up another dialog  [Linux], or a window of
+    another program [Windows].
+
+    On Windows, this will launch your mailer (assuming your mailer
+    would start when a file with the '.eml'extension is double-clicked
+    in Windows Explorer--this will be the case for Microsoft Outlook
+    Express [tm and all those legal necessities] if installed, and the
+    association has not been taken over by some other program.  On
+    Linux, it will open a file dialog to save the message, by default
+    as a '.html' file...{Please note that, on Windows and with current
+    (when I got the machine I'm writing this on--early 2000) versions
+    of Outlook Express, you may need to enter your e-mail address in
+    the box beside the "mail support" button.)
+
+    The template for the mail message is in the 'MessageTemplate'
+    attribute of the dialog-derived class in question (e.g.,
+    wxPyNonFatalErrorDialog).  Search for this in the code below to
+    see the default (note that this template is in HTML format).  This
+    attributes uses the '%{name}s' string conversion feature of Python
+    [see sec.2 of the Python Library Reference]; allowed Lance are:
+    programname version exceptionname exceptionvalue
+    extraexceptioninformation traceback
+
+    'version': str(this) will appear after 'Version' below "Error in
+    <programname>" at the top of the dialog.
+
+EXAMPLES:
+
+    sys.stderr = wxPyNonFatalErrorWindowWithTraceback (
+        parentframe,
+        programname='sumthing',
+        mailto='me@sumwear',
+        whendismissed="from wxPython.wx import * ; wxBell()")
+
+FOR INTERNATIONAL [NON-ENGLISH-SPEAKING] USE:
+    wxPyNonFatalErrorDialog and relatives have the method
+        SetText(Number NUMBER, STRING)
+
+    where STRING is to displayed in the wxStaticText control with ID
+    wxPyError_ID_TEXT<NUMBER>--see the automatically-generated code
+    for information about the meaning of these...
+
+"""
+
+
+#----------------------------------------------------------------------
+import warnings
+
+warningmsg = r"""\
+
+##############################################################\
+# THIS MODULE IS DEPRECATED and NOT MAINTAINED                |
+##############################################################/
+
+"""
+
+warnings.warn(warningmsg, DeprecationWarning, stacklevel=2)
+
+#----------------------------------------------------------------------
+
+
+_debug = 0
+#_debug = 1 # uncomment to display some information (to stdout)
+Version = 1.3
+
+from wxPython.wx import *
+import string, sys, traceback, time, rexec, operator, types, cStringIO, os
+#from wxPython.lib.createandsendHTMLmail import *# now inline
+#import MimeWriter, mimetools, tempfile, smtplib
+import urllib, webbrowser
+
+from ErrorDialogs_wdr import *
+
+# You may see from the above line that I used the excellent RAD tool
+# wxDesigner, by Robert Roebling, to accelerate development of this
+# module...  The above is left for the convenience of making future
+# changes with wxDesigner; also so the wxDesigner-generated codedoes
+# not need to precede the "hand-generated" code in this file; finally,
+# as a personal endorsement: it is truly a brilliant time-saver!
+# Please note that, at the time of writing, the wxDesigner-generated
+# output requires manual removal of the PythonBitmaps function--an
+# appropriate version of this function will be imported from a
+# similarly- named module.  Another manual change will have to be made
+# to the automatically-generated source: "parent.sizerAroundText = "
+# should be added [immediately] before the text similar to "item13 =
+# wxStaticBoxSizer( item14, wxVERTICAL )", this sizer being the one
+# containing the wxTextCtrl...  [IMPORTANT NOTE: THIS LINE SHOULD BE
+# THE ONE INSTANTIATING A wxStat2icBoxSizer, *NOT* THE wxStaticBox
+# ITSELF...]  As of version 1.2 [November 2001], this also needs to be
+# done for the {sizers around the}   wxPyClickableHtmlWindow's generated in
+# populate_wxPyNonFatalError and populate_wxPyFatalError--note that
+# for ease this sizer is still called "sizerAroundText"...
+
+def wxPyDestroyErrorDialogIfPresent():
+    if isinstance(sys.stderr,wxPyNonFatalErrorDialog):
+        sys.stderr.Destroy()
+    sys.stderr = None
+
+def wxPyNewErrorDialog(dlg):
+    wxPyDestroyErrorDialogIfPresent()
+    sys.stderr = dlg
+
+class wxPyNonWindowingErrorHandler:
+    this_exception = 0
+    softspace = 0
+    def __init__(self,fatal=0,file=sys.__stderr__):
+        self.fatal = fatal
+        self.file = file
+    def write(self,s):
+        import sys
+        if s.find("Warning") <> 0\
+           and  self.this_exception is not sys.last_traceback:
+            wxPyNonWindowingError("The Python interpreter encountered an error "
+                              "not handled by any\nexception handler--this "
+                              "may represent some programming error.",
+                              fatal=self.fatal,
+                               stderr=self.file,
+                              last=1)
+        self.this_exception = sys.last_traceback
+
+def wxPyNonWindowingError(msg,#output=None,errors=None,
+                          stderr=sys.__stderr__,
+                          fatal=1,
+                          last=None):
+    if os.path.exists("wxPyNonWindowingErrors.txt"):
+        mode = 'a+'
+    else:
+        mode = 'w'
+    fl = open("wxPyNonWindowingErrors.txt",mode)
+    if stderr is not None:
+        l = [fl,stderr] # so that the error will be written to the file
+            # before any potential error in stderr.write()... (this is largely
+            # for my own sake in developing...)
+    else:
+        l = [fl]
+    for f in l:
+        f.write(time.ctime (time.time ()) + ": ")
+        f.write(msg)
+        #f.flush()
+        if sys.exc_info () [0] is not None:
+            if last:
+                f.write('Currently handled exception:\n')
+                f.flush()
+            traceback.print_exc(file=f)
+            if last:
+                f.write('\nPrevious (?) error:\n')
+        elif last or sys.last_traceback:
+            f.write("\n\n(For wizards only) ")
+        if last:
+            if type(last) <> types.ListType or len(last) < 3:
+                if (hasattr(sys,"last_traceback") and sys.last_traceback):
+                    last = [sys.last_type ,sys.last_value,sys.last_traceback]
+            if type(last) == types.ListType:
+                traceback.print_exception(last[0],last[1],last[2],
+                                          None,f)
+         #f.flush()
+        if f is sys.__stderr__:
+            s = ' (see the file "wxPyNonWindowingErrors.txt")'
+        else:
+            s = ""
+        f.write("Please contact the author with a copy of this\n"
+                "message%s.\n" % s)
+        #f.flush()
+    fl.close()
+    if fatal and stderr is sys.__stderr__:
+        if sys.__stderr__ and sys.platform in ["windows",'nt',"win32"]:
+            sys.__stderr__.write(
+                "\nYou may have to manually close this window to exit.")
+        sys.exit()
+
+class wxPythonRExec (rexec.RExec):
+    def __init__(self,securityhole=0,*args,**kwargs):
+        apply(rexec.RExec.__init__, (self,) + args, kwargs)
+        if securityhole:
+            self.ok_builtin_modules = self.ok_builtin_modules + \
+            ('wxPython', 'wxPython.wxc','wxPython.wx','wxPython.misc',
+             'wxPython.misc2', 'wxPython.windows', 'wxPython.gdi',
+             'wxPython.clip_dnd', 'wxPython.events', 'wxPython.mdi',
+             'wxPython.frames', 'wxPython.stattool', 'wxPython.controls',
+             'wxPython.controls2', 'wxPython.windows2', 'wxPython.cmndlgs',
+             'wxPython.windows3', 'wxPython.image', 'wxPython.printfw',
+             'wxc','misc', 'misc2', 'windows', 'gdi', 'clip_dnd', 'events',
+             'mdi', 'frames', 'stattool', 'controls', 'controls2', 'windows2',
+             'cmndlgs', 'windows3', 'image', 'printfw', 'wx')
+            # possible security hole!
+
+##def wxPyFatalError(msg,frame=None,**kwargs):
+##    kwargs.update({'fatal' : 1})
+##    apply(wxPyNonFatalError,
+##          (frame,msg),
+##          kwargs)
+
+class wxPyNonFatalErrorDialogWithTraceback(wxDialog):
+    this_exception = 0
+    populate_function = populate_wxPyNonFatalErrorDialogWithTraceback
+    no_continue_button = False
+    fatal = False
+    modal = True
+    exitjustreturns = False # really only for testing!
+
+    def __init__(self, parent, id,
+                 pos=wxDefaultPosition,
+                 size=wxDefaultSize,
+                 style=wxDEFAULT_DIALOG_STYLE,
+                 programname="Python program",
+                 version="?",
+                 mailto=None,
+                 whendismissed="",
+                 extraversioninformation="",
+                 caption="Python error!",
+                 versionname=None,
+                 errorname=None,
+                 disable_exit_button=False):
+
+        if self.fatal:
+            whetherNF = ""
+        else:
+            whetherNF = "non-"
+        title = "A (%sfatal) error has occurred in %s!"\
+                % (whetherNF,programname)
+        self.programname = programname # save for later use
+        self.mailto = mailto # save for later use
+        self.parent = parent # save for later use
+        self.whendismissed = whendismissed # save for later use
+        self.dialogtitle = title # save for later use
+
+        wxDialog.__init__(self, parent, id, title, pos, size, style)
+
+        self.topsizer = self.populate_function( False,True )
+
+        self.SetProgramName(programname)
+        self.SetVersion(version)
+        if errorname:
+            self.FindWindowById(wxPyError_ID_TEXT1).SetLabel(str(errorname))
+        if versionname:
+            self.FindWindowById(wxPyError_ID_TEXT2).SetLabel(str(versionname))
+        self.FindWindowById(wxPyError_ID_VERSIONNUMBER).SetLabel(str(version))
+        self.FindWindowById(wxPyError_ID_EXTRA_VERSION_INFORMATION).SetLabel(str(
+            extraversioninformation))
+        if caption:
+            self.SetTitle(caption)
+
+        if not self.no_continue_button:
+            EVT_BUTTON(self, wxPyError_ID_CONTINUE, self.OnContinue)
+        if mailto:
+            disable_mail_button = 0
+        else:
+            disable_mail_button = 1
+        if not disable_mail_button:
+            EVT_BUTTON(self, wxPyError_ID_MAIL, self.OnMail)
+        else:
+            self.GetMailButton().Enable(False)
+        # disable the entry box for an e-mail address by default (NOT PROPERLY DOCUMENTED)
+        if not hasattr(self,"enable_mail_address_box"):
+            self.FindWindowById(wxPyError_ID_ADDRESS).Enable(False)
+        if not disable_exit_button:
+            EVT_BUTTON(self, wxPyError_ID_EXIT, self.OnExit)
+
+    def GetExtraInformation(self):
+        return self.extraexceptioninformation
+
+    def SetExtraInformation(self,value):
+        self.extraexceptioninformation = value
+        c = self.GetExtraInformationCtrl()
+        if c is not None:
+            c.SetLabel(str(value))
+            self.topsizer.Layout()
+
+    def GetExtraInformationCtrl(self):
+        return self.FindWindowById(wxPyError_ID_EXTRAINFORMATION)
+
+    def GetExceptionName(self):
+        return str(self.exceptiontype)
+
+    def SetExceptionName(self,value):
+        self.exceptiontype = str(value)
+        c = self.GetExceptionNameCtrl()
+        if c is not None:
+            c.SetLabel(str(value))
+            self.topsizer.Layout()
+
+    def GetExceptionNameCtrl(self):
+        return self.FindWindowById(wxPyError_ID_EXCEPTIONNAME)
+
+    def GetTraceback(self):
+        try:
+            return self.traceback
+        except AttributeError:
+            return None
+
+    def SetTraceback(self,value):
+        self.traceback = value
+        c = self.GetTracebackCtrl()
+        if c is not None:
+            s,cs = c.GetSize(), c.GetClientSize()
+            if value[-1] == '\n':
+                value = value[:-1]
+            if _debug:
+                print "%s.SetTraceback(): ...SetValue('%s' (^M=\\r; ^J=\\n))"\
+                      % (self,value.replace('\n',"^J"))
+            c.SetValue(value)
+
+            # Despite using the wxADJUST_MINSIZE flag in the
+            # appropriate AddWindow method of the sizer, this doesn't
+            # size the control appropriately... evidently the control's
+            # GetBestSize method is not returning the "correct"
+            # value...  So we perform a rather ugly "fix"... note that
+            # this also requires that we remove the wxADJUST_MINSIZE
+            # flag from the AddWindow method of the sizer containing
+            # the wxTextCtrl, which adds the wxTextCtrl...  (this
+            # amounts, as of wxDesigner 2.6, to only a few mouse
+            # clicks...)
+
+            if _debug:
+                size = c.GetBestSize()
+                print "%s.SetTraceback(): %s.GetBestSize() = (%s,%s)"\
+                      % (self,c,size.width,size.height)
+            w,h = 0,0
+            for v in value.split("\n"):
+                pw,ph,d,e = t = c.GetFullTextExtent(v)
+                if _debug:
+                    print v, t
+                h = h + ph + e# + d
+                pw = pw + wxSystemSettings_GetSystemMetric(wxSYS_VSCROLL_X)
+                if pw > w:
+                    w = pw
+            w = w + s.width - cs.width
+            h = h + s.height - cs.height
+            if _debug:
+                print "%s.SetTraceback(): calculated w,h =" % c,\
+                      w,h,"and sys.platform = '%s'" % sys.platform
+            self.sizerAroundText.SetItemMinSize (c,w,h)
+            c.SetSize ((w,h))
+            c.SetSizeHints (w,h,w,h)
+            c.Refresh()#.SetAutoLayout(False)
+
+            #^ the reason we need the above seems to be to replace the
+            #faulty GetBestSize of wxTextCtrl...
+            #self.sizerAroundText.Layout()
+            self.topsizer.Layout()
+
+    def GetTracebackCtrl(self):
+        return self.FindWindowById(wxPyError_ID_TEXTCTRL)
+
+    def GetVersion(self):
+        return self.version
+
+    def SetVersion(self,value):
+        self.version = value
+        c = self.GetVersionNumberCtrl()
+        if c is not None:
+            c.SetLabel(value)
+            self.topsizer.Layout()
+
+    def GetVersionNumberCtrl(self):
+        return self.FindWindowById(wxPyError_ID_VERSIONNUMBER)
+
+    def GetProgramName(self):
+        return self.programname
+
+    def SetProgramName(self,value):
+        self.programname = value
+        c = self.GetProgramNameCtrl()
+        if c is not None:
+            c.SetLabel(value)
+            self.topsizer.Layout()
+
+    def GetProgramNameCtrl(self):
+        return self.FindWindowById(wxPyError_ID_PROGRAMNAME)
+
+    def GetContinueButton(self):
+        return self.FindWindowById(wxPyError_ID_CONTINUE)
+
+    def GetMailButton(self):
+        return self.FindWindowById(wxPyError_ID_MAIL)
+
+    def GetExitButton(self):
+        return self.FindWindowById(wxPyError_ID_EXIT)
+
+    # write handler (which is really the guts of the thing...
+    # [Note that this doesn't use sys.excepthook because I already had a
+    # working body of code...
+
+    def write(self,s):
+        if self.this_exception is not sys.last_traceback:
+          if not wxThread_IsMain():
+             # Aquire the GUI mutex before making GUI calls.  Mutex is released
+             # when locker is deleted at the end of this function.
+             locker = wxMutexGuiLocker()
+
+          self.this_exception = sys.last_traceback
+            # this is meant to be done once per traceback's sys.stderr.write's
+            # - on the first in fact.....
+          try:
+            #from wxPython.wx import wxBell
+            wxBell()
+
+            if _debug:
+                if sys.stdout: sys.stdout.write(
+                    'in  %s.write(): ' % self)
+
+            self.exceptiontype = sys.last_type
+            self.extraexceptioninformation = sys.last_value
+            c = cStringIO.StringIO()
+            traceback.print_last(None,c)
+            self.traceback = c.getvalue()
+
+            if _debug:
+                #import traceback
+                traceback.print_last(None,sys.stdout)
+
+            self.SetExceptionName(str(self.exceptiontype))
+            self.SetExtraInformation(str(self.extraexceptioninformation))
+            self.SetTraceback(str(self.traceback))
+
+            self.topsizer.Fit(self)
+            self.topsizer.SetSizeHints(self)
+            self.CentreOnScreen()
+
+            if self.modal:
+                self.ShowModal()
+            else:
+                self.Show(True)
+
+          except:
+              if not locals().has_key("c"):
+                  c = cStringIO.StringIO()
+                  c.write("[Exception occurred before data from "
+                          "sys.last_traceback available]")
+              wxPyNonWindowingError("Warning: "
+                                "a %s error was encountered trying to "
+                                "handle the exception\n%s\nThis was:"#%s\n"
+                                % (sys.exc_type, c.getvalue()),#, c2.getvalue()),
+                                stderr=sys.stdout,
+                                last=0)
+
+
+    # button handlers:
+
+    def OnContinue(self, event):
+     try:
+        if self.whendismissed:
+            parent = self.parent # so whendismissed can refer to "parent"
+            if 1:
+                if _debug:
+                    if sys.stdout: sys.stdout.write("exec '''%s''': "
+                                         % (self.whendismissed))
+                exec self.whendismissed
+                if _debug: print "\n",
+            else:
+                if _debug:
+                    if sys.stdout: sys.stdout.write("wxPythonRExec(%s).r_exec('''%s'''): "
+                                         % (self.securityhole,
+                                            self.whendismissed))
+                wxPythonRExec(self.securityhole).r_exec(self.whendismissed)
+                if _debug: print "\n",
+        if self.modal:
+            self.EndModal(wxID_OK)
+        else:
+            self.Close ()
+        if _debug: print "reimporting ",
+        for  m in sys.modules.values():
+            if m and m.__dict__["__name__"][0] in string.uppercase:#hack!
+                if _debug:
+                    print m.__dict__["__name__"],
+                reload (m)
+                if _debug:
+                    print ' ',
+        if _debug:
+            print '\nENDING %s.OnContinue()..\n\n' % (self,),
+     except:
+      wxPyNonWindowingError("Warning: the following exception information"
+                        " may not be the full story.. (because "
+                        "a %s(%s) error was encountered trying to "
+                        "handle the exception)\n\n"
+                        % tuple(sys.exc_info()[:2]),
+                        stderr=sys.stdout,
+                        last=0)
+
+    PlainMessageTemplate = \
+                 "Hello,\n\n"\
+                 '%(programname)s'\
+                 " error.\n\n"\
+                 "I encountered the following error when running your "\
+                 'program %(programname)s,'\
+                 "at %(date)s.\n\n"\
+                 "(The following has been automatically generated...)\n"\
+                 '%(traceback)s\n\n'\
+                 "More information follows:\n\n"\
+                 '[Insert more '\
+                 "information about the error here, such as what you were "\
+                 "trying to do at the time of the error.  Please "\
+                 "understand that failure to fill in this field will be "\
+                 "interpreted as an invitation to consign this e-mail "\
+                 "straight to the trash can!]\n\n"\
+                 'Yours sincerely,\n'\
+                 "[insert your name here]\n"
+
+    HTMLMessageTemplate = \
+                 '<html>\n'\
+                 '<body>'\
+                 "<p>\n"\
+                 "<i><b>Hello,</b></i>\n<p>\n"\
+                 '<p><h2><font color="#CC6C00">%(programname)s</font>'\
+                 " error.</h2>\n"\
+                 "I encountered the following error when running your "\
+                 'program <font color="#CC6C00">%(programname)s</font>,'\
+                 "at %(date)s.\n<p>\n"\
+                 "<p>"\
+                 "<h2>Traceback (automatically generated):</h2>\n"\
+                 '<p><font size="-1">\n<pre>%(traceback)s</pre>\n<p></font><p>'\
+                 "\n<p>\n<h2>More information follows:</h2>\n<p>\n"\
+                 '<font color="#CC6C00">'\
+                 '<i>[Insert more '\
+                 "information about the error here, such as what you were "\
+                 "trying to do at the time of the error.  Please "\
+                 "understand that failure to fill in this field will be "\
+                 "interpreted as an invitation to consign this e-mail "\
+                 "straight to the trash can!]\n</i><p>\n"\
+                 "</font><p>\n"\
+                 '<i><b>Yours sincerely,</b></i>\n<p>'\
+                 '<font color="#CC6C00">'\
+                 "[insert your name here]\n"\
+                 "</font>\n"\
+                 "</body>\n"\
+                 "</html>\n"
+    # text="#000000" bgcolor="#FFFFFF">\n'\
+
+    def OnMail(self,event):
+      try:
+        if _debug:
+            print 'Attempting to write mail message.\n',
+        gmtdate = time.asctime(time.gmtime(time.time())) + ' GMT'
+        tm = time.localtime(time.time())
+        date = time.asctime(tm) + ' ' +\
+               time.strftime("%Z",tm)
+        programname = self.programname
+        traceback = self.traceback
+        mailto = self.mailto
+
+        subject = "Un-caught exception when running %s." % programname
+        mailfrom = None#self.FindWindowById (wxPyError_ID_ADDRESS)
+        if mailfrom:
+            mailfrom = mailfrom.GetValue()
+        if _startmailerwithhtml(mailto,subject,
+                                self.HTMLMessageTemplate % vars(),
+                                text=self.PlainMessageTemplate % vars(),
+                                mailfrom=mailfrom):
+          if not (hasattr(self,"fatal") and self.fatal):
+            self.OnContinue(event) # if ok, then act as if "Continue" selected
+      except:
+          wxPyNonWindowingError("Warning: the following exception information"
+                                " may not be the full story... (because "
+                                "a %s error was encountered trying to "
+                                "handle the original exception)\n\n"#%s"
+                                % (sys.exc_type,),#self.msg),
+                                stderr=sys.stdout,
+                                last=0)
+
+    def OnExit(self, event):
+        if self.IsModal():
+            self.EndModal(wxID_CANCEL)
+        if self.exitjustreturns:
+            return
+        wxGetApp().ExitMainLoop()
+
+    def SetText(self,number,string):
+        self.FindWindowById(eval("wxPyError_ID_TEXT%d"
+                                 % number)).SetLabel(string)
+        self.topsizer.Layout()
+
+class wxPyFatalErrorDialogWithTraceback(wxPyNonFatalErrorDialogWithTraceback):
+    populate_function = populate_wxPyFatalErrorDialogWithTraceback
+    no_continue_button = True
+    fatal = True
+
+class wxPyNonFatalErrorDialog(wxPyNonFatalErrorDialogWithTraceback):
+    populate_function = populate_wxPyNonFatalErrorDialog
+
+class wxPyFatalErrorDialog(wxPyFatalErrorDialogWithTraceback):
+    populate_function = populate_wxPyFatalErrorDialog
+
+def _startmailerwithhtml(mailto,subject,html,text=None,mailfrom=None):
+    if sys.hexversion >= 0x02000000:#\
+        # and sys.platform in ["windows",'nt',"w is in32"]:
+        s = 'mailto:%s?subject=%s&body=%s' % (mailto,
+                                               urllib.quote(subject),
+                                               urllib.quote(
+            text.replace('\n','\r\n'),
+            ""))
+
+        # Note that RFC 2368 requires that line breaks in the body of
+        # a message contained in a mailto URL MUST be encoded with
+        # "%0D%0A"--even on Unix/Linux.  Also note that there appears
+        # to be no way to specify that the body of a mailto tag be
+        # interpreted as HTML (mailto tags shouldn't stuff around with
+        # the MIME-Version/Content-Type headers, the RFC says, so I
+        # can't even be bothered trying, as the Python
+        # webbrowser/urllib modules quite likely won't allow
+        # this... anyway, a plain text message is [at least!] fine...).
+
+        if _debug:
+            t = urllib.quote(text)
+            if len(t) > 20 * 80:
+                t = t[0:20 * 80] + "..."
+                print "\nSummarizing (only shortened version of argument "\
+                      "printed here), ",
+            print 'webbrowser.open("' \
+                  'mailto:%s?subject=%s&body=%s"' % (mailto,
+                                                     urllib.quote(subject),
+                                                     t)
+        webbrowser.open(s)
+        return 1
+    else:
+        return _writehtmlmessage(mailto,subject,html,text,mailfrom=mailfrom)
+
+def _writehtmlmessage(mailto,subject,html,text=None,parent=None,mailfrom=None):
+    dlg = wxFileDialog (parent,
+                        "Please choose a a file to save the message to...",
+                        ".",
+                        "bug-report",
+                        "HTML files (*.htm,*.html)|*.htm,*.html|"
+                        "All files (*)|*",
+                        wxSAVE | wxHIDE_READONLY)
+    if dlg.ShowModal() <> wxID_CANCEL:
+        f = open(dlg.GetPath(),"w")
+        dlg.Destroy()
+        f.write(_createhtmlmail(html,text,subject,to=mailto,mailfrom=mailfrom))
+        f.close()
+        return 1
+    else:
+        return 0
+
+# PLEASE NOTE THAT THE CODE BELOW FOR WRITING A GIVEN
+#(HTML) MESSAGE IS BY ART GILLESPIE [with slight modifications by yours truly].
+
+def _createhtmlmail (html, text, subject, to=None, mailfrom=None):
+    """Create a mime-message that will render HTML in popular
+       MUAs, text in better ones (if indeed text is not unTrue (e.g. None)
+       """
+    import MimeWriter, mimetools, cStringIO
+
+    out = cStringIO.StringIO() # output buffer for our message
+    htmlin = cStringIO.StringIO(html)
+    if text:
+            txtin = cStringIO.StringIO(text)
+
+    writer = MimeWriter.MimeWriter(out)
+    #
+    # set up some basic headers... we put subject here
+    # because smtplib.sendmail expects it to be in the
+    # message body
+    #
+    if mailfrom:
+            writer.addheader("From", mailfrom)
+            #writer.addheader("Reply-to", mailfrom)
+    writer.addheader("Subject", subject)
+    if to:
+            writer.addheader("To", to)
+    writer.addheader("MIME-Version", "1.0")
+    #
+    # start the multipart section of the message
+    # multipart/alternative seems to work better
+    # on some MUAs than multipart/mixed
+    #
+    writer.startmultipartbody("alternative")
+    writer.flushheaders()
+    #
+    # the plain text section
+    #
+    if text:
+        subpart = writer.nextpart()
+        subpart.addheader("Content-Transfer-Encoding", "quoted-printable")
+        pout = subpart.startbody("text/plain", [("charset", 'us-ascii')])
+        mimetools.encode(txtin, pout, 'quoted-printable')
+        txtin.close()
+    #
+    # start the html subpart of the message
+    #
+    subpart = writer.nextpart()
+    subpart.addheader("Content-Transfer-Encoding", "quoted-printable")
+    pout = subpart.startbody("text/html", [("charset", 'us-ascii')])
+    mimetools.encode(htmlin, pout, 'quoted-printable')
+    htmlin.close()
+    #
+    # Now that we're done, close our writer and
+    # return the message body
+    #
+    writer.lastpart()
+    msg = out.getvalue()
+    out.close()
+    return msg
+
+def _sendmail(mailto,subject,html,text):# currently unused
+    """For illustration only--this function is not actually used."""
+    import smtplib
+    message = _createhtmlmail(html, text, subject)
+    server = smtplib.SMTP("localhost")
+    server.sendmail(mailto, subject, message)
+    server.quit()
+
+def wxPyFatalError(parent,msg,**kw):
+    return wxPyFatalOrNonFatalError(parent,msg,fatal=1,**kw)
+
+def wxPyNonFatalError(parent,msg,**kw):
+    return wxPyFatalOrNonFatalError(parent,msg,fatal=0,**kw)
+
+def wxPyResizeHTMLWindowToDispelScrollbar(window,
+                                         fraction,
+                                         sizer=None,
+                                         defaultfraction=0.7):
+    # Try to `grow' parent window (typically a dialog), only so far as
+    # no scrollbar is necessary, mantaining aspect ratio of display.
+    # Will go no further than specified fraction of display size.
+    w = 200
+    if type(fraction) == type(''):
+        fraction = int(fraction[:-1]) / 100.
+    ds = wxDisplaySize ()
+    c = window.GetInternalRepresentation ()
+    while w < ds[0] * fraction:
+        c.Layout(w)
+        if _debug:
+            print '(c.GetHeight() + 20, w * ds[1]/ds[0]):',\
+                  (c.GetHeight() + 20, w * ds[1]/ds[0])
+        if c.GetHeight() + 20 < w * ds[1]/ds[0]:
+            size = (w,min(int ((w) * ds[1]/ds[0]),
+                          c.GetHeight()))
+            break
+        w = w + 20
+    else:
+        if type(defaultfraction) == type(''):
+            defaultfraction = int(defaultfraction[:-1]) / 100.
+        defaultsize = (defaultfraction * ds[0], defaultfraction * ds[1])
+        if _debug:
+            print 'defaultsize =',defaultsize
+        size = defaultsize
+    window.SetSize(size)
+    if sizer is not None:
+        sizer.SetMinSize(size)
+        sizer.Fit(window)
+        #sizer.SetSizeHints(window)
+
+def wxPyFatalOrNonFatalError(parent,
+                             msg,
+                             fatal=0,
+                             extraversioninformation="",
+                             caption=None,
+                             versionname=None,
+                             errorname=None,
+                             version="?",
+                             programname="Python program",
+                             tback=None,# backwards compatibility, and for
+                             #possible future inclusion of ability to display
+                             #a traceback along with the given message
+                             #"msg"... currently ignored though...
+                             modal=0):
+    if not wxThread_IsMain():
+        # Aquire the GUI mutex before making GUI calls.  Mutex is released
+        # when locker is deleted at the end of this function.
+        locker = wxMutexGuiLocker()
+
+    dlg = wxDialog(parent,-1,"Error!")
+
+    if fatal:
+        populate_function = populate_wxPyFatalError
+    else:
+        populate_function = populate_wxPyNonFatalError
+
+    sizer = populate_function(dlg,False,True)
+
+    window = dlg.FindWindowById(wxPyError_ID_HTML)
+    window.SetPage(msg)
+    wxPyResizeHTMLWindowToDispelScrollbar(window,
+                                          "85%",
+                                          sizer=dlg.sizerAroundText)
+    dlg.FindWindowById(wxPyError_ID_PROGRAMNAME).SetLabel(str(programname))
+    if errorname:
+        dlg.FindWindowById(wxPyError_ID_TEXT1).SetLabel(str(errorname))
+    if versionname:
+        dlg.FindWindowById(wxPyError_ID_TEXT2).SetLabel(str(versionname))
+    dlg.FindWindowById(wxPyError_ID_VERSIONNUMBER).SetLabel(str(version))
+    dlg.FindWindowById(wxPyError_ID_EXTRA_VERSION_INFORMATION).SetLabel(str(
+        extraversioninformation))
+    if caption:
+        dlg.SetTitle(caption)
+    sizer.Fit(dlg)
+    sizer.SetSizeHints(dlg)
+    dlg.CentreOnScreen()
+
+    if modal:
+        v = dlg.ShowModal()
+        dlg.Destroy()
+        return v
+    else:
+        dlg.Show(True)
 
-from wx import _rename
-from wxPython.lib import ErrorDialogs
-_rename(globals(), ErrorDialogs.__dict__, modulename='lib.ErrorDialogs')
-del ErrorDialogs
-del _rename