]> git.saurik.com Git - wxWidgets.git/commitdiff
Updates for doc/view from Morgan Hua
authorRobin Dunn <robin@alldunn.com>
Mon, 28 Feb 2005 20:16:34 +0000 (20:16 +0000)
committerRobin Dunn <robin@alldunn.com>
Mon, 28 Feb 2005 20:16:34 +0000 (20:16 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@32496 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

wxPython/samples/docview/DocViewDemo.py
wxPython/samples/docview/PyDocViewDemo.py
wxPython/wx/lib/docview.py
wxPython/wx/lib/pydocview.py

index 55eb2a1a281ee0427a073d0fe61c5510feae7ee1..c22b3539ccb93135da91574b56f075c60b559c5a 100644 (file)
@@ -91,6 +91,7 @@ class TextEditView(wx.lib.docview.View):
             sizer.Add(self._textsw, 1, wx.EXPAND, 0)
             self._frame.SetSizer(sizer)
             self._frame.Layout()
+            self._frame.Show(True)
             self.Activate(True)
             return True
         else:  # flags & wx.lib.docview.DOC_SDI
index 92bb8d4d4f1a323293ebaf909b62622deca8580f..9243aea8fd6ff3cec9c029cbff0d958fe3fb8865 100644 (file)
@@ -17,7 +17,8 @@ import wx.lib.docview
 import wx.lib.pydocview
 import activegrid.tool.TextEditor as TextEditor
 import activegrid.tool.FindService as FindService
-import wx.lib.pydocview as WindowMenuService
+_ = wx.GetTranslation
+
 
 #----------------------------------------------------------------------------
 # Classes
@@ -31,19 +32,19 @@ class TextEditorApplication(wx.lib.pydocview.DocApp):
 
         wx.lib.pydocview.DocApp.ShowSplash(self, "activegrid/tool/images/splash.jpg")
 
-        self.SetAppName(wx.GetTranslation("wxPython DocView Demo"))
+        self.SetAppName(_("wxPython PyDocView Demo"))
         config = wx.Config(self.GetAppName(), style = wx.CONFIG_USE_LOCAL_FILE)
 
         docManager = wx.lib.docview.DocManager(flags = self.GetDefaultDocManagerFlags())
         self.SetDocumentManager(docManager)
 
         textTemplate = wx.lib.docview.DocTemplate(docManager,
-                                              wx.GetTranslation("Text"),
+                                              _("Text"),
                                               "*.text;*.txt",
-                                              wx.GetTranslation("Text"),
-                                              wx.GetTranslation(".txt"),
-                                              wx.GetTranslation("Text Document"),
-                                              wx.GetTranslation("Text View"),
+                                              _("Text"),
+                                              _(".txt"),
+                                              _("Text Document"),
+                                              _("Text View"),
                                               TextEditor.TextDocument,
                                               TextEditor.TextView)
         docManager.AssociateTemplate(textTemplate)
@@ -51,11 +52,12 @@ class TextEditorApplication(wx.lib.pydocview.DocApp):
         textService       = self.InstallService(TextEditor.TextService())
         findService       = self.InstallService(FindService.FindService())
         optionsService    = self.InstallService(wx.lib.pydocview.DocOptionsService())
-        windowMenuService = self.InstallService(WindowMenuService.WindowMenuService())
+        windowMenuService = self.InstallService(wx.lib.pydocview.WindowMenuService())
         optionsService.AddOptionsPanel(TextEditor.TextOptionsPanel)
         filePropertiesService = self.InstallService(wx.lib.pydocview.FilePropertiesService())
+        aboutService         = self.InstallService(wx.lib.pydocview.AboutService())
 
-        self.SetDefaultIcon(getDocIcon())
+##        self.SetDefaultIcon(getAppIcon())  # set this for your custom icon
 
         if docManager.GetFlags() & wx.lib.docview.DOC_MDI:
             frame = wx.lib.pydocview.DocMDIParentFrame(docManager, None, -1, wx.GetApp().GetAppName())
@@ -68,96 +70,11 @@ class TextEditorApplication(wx.lib.pydocview.DocApp):
         if not docManager.GetDocuments() and docManager.GetFlags() & wx.lib.docview.DOC_SDI:
             textTemplate.CreateDocument('', wx.lib.docview.DOC_NEW).OnNewDocument()
 
-        wx.CallAfter(self.ShowTip, docManager.FindSuitableParent(), wx.CreateFileTipProvider("activegrid/tool/data/tips.txt", 0))
+        wx.CallAfter(self.ShowTip, wx.GetApp().GetTopWindow(), wx.CreateFileTipProvider("activegrid/tool/data/tips.txt", 0))
 
         return True
 
 
-#----------------------------------------------------------------------------
-# Menu Bitmaps - generated by encode_bitmaps.py
-#----------------------------------------------------------------------------
-from wx import ImageFromStream, BitmapFromImage
-from wx import EmptyIcon
-import cStringIO
-
-
-def getDocData():
-    return \
-'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
-\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x05cID\
-ATX\x85\xed\x97\xcbo\x1b\xd7\x15\xc6\x7fw^\x1c\x92C\x8a\xa4DQ\xa2)\xd9\xb2%?\
-\xe0\xa7\x82\xc0\x85\x83"\xa8\x1b\x17AwYtQtU\xb4\x8b\xa2\x7fH\xfe\x8c\xee\
-\x8b\xac\x124\xab\x02E\n\x17h\x01\x17\x86Q7\xaac7~I\xb2hZ\xe2sH\xce\x83s\xef\
-\xedB\xa6dI~))\x90E\xf2\x01\x17\x98\xb9s\xe7\x9c\xef\x9c\xf9\xce\xb9w\x840L\
-\xbeK\x18\xdf\xa9\xf7\x1f\x08\x00\xa2\xd5ji!\x04\xe3\xf1ma\x9a\x02!\x0c\xe0\
-\xa0-\xa55O\xb6\x06t\xfb\x11\xa0\x98\xca\x99\x880\x0c5\xf0R\xe7B\x08\xb4\xde\
-\xbd6\xc4\xd8\xee\x0bk\xb5\xde3\'\x84f\x10J\x06aB4R\xd8\x96\xc1\x97\x8f{\xfc\
-\xfbq\x97-?\xa2\xe49\x9c\x9d\xf38u\xc4\xa3\x945\xb0\xc6\x8e\r!`\x1f\t!\xd8C\
-\x004\x89\xd4\x04\xb1$\x88%#\xa9(f,\xd6\xdb!\xab\x9b\x01\x9b\xbd\x98 \x96\
-\xb4z\x11\xa6\x80\xea\x94K\x9ch\xfe\xf5\xa0\xcb\xfa\xd6\x90\xea\xa4\xcb\x99Z\
-\x8e\xead\x96\xa2\x97\xc2\x14\t\xd6s\xf3h\x04JC"\xf5\xf3\xa1\x00M.c\xd1\xe9\
-\'\xf4\x82\x11\xc3H\xd2\x0f\x13\xda~L\xcb\x8fI\x12\xc9\x953\x93\\\xff\xaa\
-\xc9\x17\xb7\xb7\xf8j\xdd\xa7\x13J\x82aB\xad\x94\xe2\x83\xe5)\xba\xc3\x84\
-\xde a\xa6\x98\xe2\xc3wf\xb8\xbcX\xa2\xe89(\xa5\x08\x82\xd1\x98\x00\x04qB/\
-\x1c\xd1\xf6Gl\xf6"\x9euc\x84\xd0\xfc\xf4\\\x99Oo\xd4\xf9\xe2\xf6\x16w\x9f\
-\x0chG\t\xbe\x1f\x13\xf9#\xa63\x16\x1f\xff\xee\x027\xefw\xb9\xf5\xb0K\xc7\
-\x8f\x11\xa6`a\xc6\xe5\xdc\xbc\xc7\xfcT\x06/msa~\x82\xa5\xd9\x1c\x8em`\x08\
-\xd0Z\xa1\x94\x02\xc0\xb2,\x8b\x8d\xe6\x90\xcfnl\xf0\xf9\xcd\x06\xf1H\x13E\
-\x92h0\xa2\x906\xe9\x0eF\xf4#I<\x88\xb9w\xa7I\x9cs\xc8\xa5-\xcae\x97\xa3\x93\
-i\xdc\x94\xa0\xe4\xd9\x143\x16\xfd~\xc4\xf4D\x8ak\x17\xa6\xb9z\xae\xcc\xd1r\
-\x06\xc76)dm\xb2)\x03\xa5\xf7jLk\xb0\xc6\x9f~\xbd\x19r}\xa5\xc9\xb0\x9fl?\
-\x1d)&2\x16n\xe9\x19?_.sf>\xcf\xbd\xc7>x6\xaeka\n0S&~\x980\x88\x12l[\xb08\
-\x9b\xe1\xda\xa5\nW\xcfW8;\x9f\'\xefZ;\x02\xd5Z\xa3\xb5~\xae\xa5\xdd\xaa\xb3\
-\x94R\x94<\x87\xc5\xaa\xc7\xe9#9V\xee\xb61\x1d\x13\xc7\xb3I\xa7L\xfe[\x1f\
-\xf0\xd1\xe5\x19\x96O\x97\x08\x84\xa6\xd1\x0c\xe9\r\x136\xfd\x98F7f\xbd\x19Q\
-\xefD\xa4]\x93\xf7O\x95\xf9\xed\xb5\x05\xa6\x0bi\xd0\xa0\xb5\x06\xa5w\x8a\
-\xe6\xc5J\x13B`Y\x16\x96\x94\n\xc76\xf9\xd9\xc5il\x03>\x1e\xc6\x94\x8b.\xc7g\
-2\xcc\x16]\xc2(a\xbd\x19\xa2\xd0,U\xb2\xfc\xf1\xcf\xab\xb4\xba#\xd2\x9eM\xed\
-H\x96 N\xa8\xe4m~\xb4X\xe47W\x8f\x92\xcf\xd8\xe8\xfd\xb9~\x05l\xdb\xde\x16\
-\xa1R\x8a\xa9\xbc\xc3\xd5\xf3\x15\x8a\x9e\xc3\xadG\x1dV\xd6|\xfe\xfa\xe5\x16\
-\x83@"\xa4f\xf9D\x9eKKE\xe6k9\xaa\x15I\xca1\xc9y\x16\xbd0ay\xa1\xc0\xf2B\x91\
-B\xd6\xd9\x8ez\x7f-\xbf\x04\xe3lX\xdb\xcdF\xe3\x98\x06\xd5\x92Kmj\x96l\xc6\
-\xa4\xd1\x89\xf8\xc7\x9d6O\x9e\x05\xa8 \xc1\x16P\x9b\xcd\xf2\xd1{U\xfe\xb3\
-\xda\xe5\xd1\xd3!A?\xa1\x92Oq\xf1X\x81\x93\xd5\xdc[E\xbd\x1f;e8f\xae\xb5\xe0\
-lm\x82\xa7\xa7c\xd67CB\x7fD\xa4!\x1a):\xc3\x84_\xfd\xf8\x08\x1b\xad!\x8f\x1a\
-CD\xa4x\xf7x\x81\xc5\x19\x8fl\xcaDJu\xe8v.\xe28\xd6cu\x8e\xb3\xa1\x81`\xa4y\
-\xd8\x18\xf0\xc9\xdf\xd6ht\x02\x0c\xd3`\xc2\xb3\t\xa5\xa2\xde\x8eX\xdb\n0\
-\x81?\xfc\xfe"\x8b3y,\xcb\xf8F\x04,8\xb8\x0f\x18B\xe0\xa5\x04K\xb3Y~\xf9\xfe\
-\x1c\xc3(\xe1\xc6\xd7m>\xffg\x9d\x87\xf7{,\x1d\xcfsr6K\xde5\x01\x81T\x1a\xeb\
-%v\xde\x9a\xc0\x9e\x94<7\xa2\xb5&e\x19\x9c\x9d\xcbo\xef\th\xee\xac\xf6xp\xb7\
-\x8b\x1f\x8c\xa8\x98i\xe6\xa6\\6\xfd\x98\xf2\xc4\xb6(w\xeb\xfc[\x10x\x81\xca\
-\x9e\xe6qy\xb1Dm2\x83e\x18\xdcZ\xed\xd2\xe8\x84,L\xbb\xdc\xaf\x0f\xa8\x163L\
-\xe6R\x87\x0b}\xec%\x8e\xe3\x9d\xba\xd9\xcf~,\xcc\xf1\xbc\xd2\xb0\xd9\r\xb8\
-\xf9\xa0\xc3\xdf\xef5Yy\xd2\xe7|-\xc7/\xae\xd4\xb8t\xac\x88\x94\xf2\xff\x99\
-\x81\x83\x84L\x01\xd5R\x1a\xcb2\t\x13\xcd\xd7\x8d!\xd7\xef\xb4x\xf7D\x89ss\
-\x13\x98\xc6\xee\xf9\xe1M\xd0Z\x93$\xc9\xe1\x8edZk\x94\x86r>\xc5\x85\xa3\x05\
-\xde;9\x89\xd2\xb0\xb2\xd6\xe3\xee\x86\x8fa\x18\xe3\x85oM\xe0\xb5\x198\x00!P\
-J\x03\x9a\xc5J\x86_\xff\xe4\x18\x00\xb7\x1ev\xf8\xd3\xcd\xa7,\xcd\xe6\xb0\
-\x0e\x11\x92R\xea\xf5\x1ax\x15\xf3\x9dk\xa0\xd9O\xf8\xcb\xed\x06\x1b\xed\x80\
-\x13\x95,\x1f\x9c\x9f\xc6s\xdf\x1c\xd7\xf6\x81$\xc08\xd0\xbb\xdf\x80=;\x1a0\
-\x9dw\xb8rj\x92w\x16\nH\xa9h\xf9\x11\xe1H\x1e \xfb*[\x96\x94r\xe7\xe6\xb0\n\
-\xd6Z\xa3\x94b\xae\x94"\x97\x12<\xde2\x08\xa2\x98 2\xb0\r\xe7\xb5}AJ\xb9]5\
-\xf5z]\x03\xbb\x02\xfa\x06\x10\x80m\x1b\x18\xa6\xc9\xda3\x1f\xd71\xc9\xb9\
-\xf6k\xdf\x91R\x12E\x11\xe2\x87\x7f\xc3\xef=\x81\xff\x01\x1d\xae\x83\xc3q\
-\xb9\xc6\x9f\x00\x00\x00\x00IEND\xaeB`\x82' 
-
-
-
-def getDocBitmap():
-    return BitmapFromImage(getDocImage())
-
-
-def getDocImage():
-    stream = cStringIO.StringIO(getDocData())
-    return ImageFromStream(stream)
-
-
-def getDocIcon():
-    icon = EmptyIcon()
-    icon.CopyFromBitmap(getDocBitmap())
-    return icon
-
-
 #----------------------------------------------------------------------------
 # Main
 #----------------------------------------------------------------------------
index 8f5f038ba7f4577673d74dae3bddadd79b310e41..aad8359e1478cc61b2c57e9cd017ef855919b0b5 100644 (file)
@@ -1318,7 +1318,7 @@ class DocManager(wx.EvtHandler):
         """
         Creates a new document and reads in the selected file.
         """
-        if not self.CreateDocument('', 0):
+        if not self.CreateDocument('', DEFAULT_DOCMAN_FLAGS):
             self.OnOpenFileFailure()
 
 
@@ -1709,6 +1709,11 @@ class DocManager(wx.EvtHandler):
             else:
                 return None
 
+        if path and flags & DOC_SILENT:
+            temp = self.FindTemplateForPath(path)
+        else:
+            temp, path = self.SelectDocumentPath(templates, path, flags)
+
         # Existing document
         if self.GetFlags() & DOC_OPEN_ONCE:
             for document in self._docs:
@@ -1720,11 +1725,6 @@ class DocManager(wx.EvtHandler):
                             firstView.GetFrame().Iconize(False)
                     return None
 
-        if flags & DOC_SILENT:
-            temp = self.FindTemplateForPath(path)
-        else:
-            temp, path = self.SelectDocumentPath(templates, path, flags)
-
         if temp:
             newDoc = temp.CreateDocument(path, flags)
             if newDoc:
index 97ad542f870b0a0b1448f8968777f7211eec2483..94e41b48ba3503435260f892628729ac356ecfb5 100644 (file)
@@ -20,8 +20,13 @@ import os
 import os.path
 import time
 import string
+import pickle
+import getpass
+import tempfile
+import mmap
 _ = wx.GetTranslation
 
+
 #----------------------------------------------------------------------------
 # Constants
 #----------------------------------------------------------------------------
@@ -236,7 +241,7 @@ class OptionsDialog(wx.Dialog):
         Initializes the options dialog with a notebook page that contains new
         instances of the passed optionsPanelClasses.
         """
-        wx.Dialog.__init__(self, parent, -1, _("Options"), size = (310, 375))
+        wx.Dialog.__init__(self, parent, -1, _("Options"), size = (310, 400))
 
         self._optionsPanels = []
         self._docManager = docManager
@@ -307,14 +312,11 @@ class GeneralOptionsPanel(wx.Panel):
                                       choices = [_("Show each document in its own window (SDI)"),
                                                  _("Show All documents in a single window (MDI)")],
                                       majorDimension=1,
-                                      #style = wx.RA_SPECIFY_ROWS
                                       )
-        #self._documentRadioBox.SetBackgroundColour(backgroundColor) # wxBug: uses wrong background color
         if config.ReadInt("UseMDI", True):
             self._documentRadioBox.SetSelection(1)
         else:
             self._documentRadioBox.SetSelection(0)
-            
         def OnDocumentInterfaceSelect(event):
             if not self._documentInterfaceMessageShown:
                 msgTitle = wx.GetApp().GetAppName()
@@ -324,8 +326,7 @@ class GeneralOptionsPanel(wx.Panel):
                               msgTitle,
                               wx.OK | wx.ICON_INFORMATION,
                               self.GetParent())
-                self._documentInterfaceMessageShown = True
-                
+                self._documentInterfaceMessageShown = True            
         wx.EVT_RADIOBOX(self, self._documentRadioBox.GetId(), OnDocumentInterfaceSelect)
         optionsBorderSizer = wx.BoxSizer(wx.VERTICAL)
         optionsSizer = wx.BoxSizer(wx.VERTICAL)
@@ -361,8 +362,88 @@ class DocApp(wx.PySimpleApp):
         self._services = []
         self._defaultIcon = None
         self._registeredCloseEvent = False
-        self._debug = False
+        if not hasattr(self, "_debug"):  # only set if not already initialized
+            self._debug = False
+        if not hasattr(self, "_singleInstance"):  # only set if not already initialized
+            self._singleInstance = True
+            
+        # if _singleInstance is TRUE only allow one single instance of app to run.
+        # When user tries to run a second instance of the app, abort startup,
+        # But if user also specifies files to open in command line, send message to running app to open those files
+        if self._singleInstance:
+            # create shared memory temporary file
+            if wx.Platform == '__WXMSW__':
+                tfile = tempfile.TemporaryFile(prefix="ag", suffix="tmp")
+                fno = tfile.fileno()
+                self._sharedMemory = mmap.mmap(fno, 1024, "shared_memory")
+            else:
+                tfile = file(os.path.join(tempfile.gettempdir(), tempfile.gettempprefix() + getpass.getuser() + "AGSharedMemory"), 'w+b')
+                tfile.write("*")
+                tfile.seek(1024)
+                tfile.write(" ")
+                tfile.flush()
+                fno = tfile.fileno()
+                self._sharedMemory = mmap.mmap(fno, 1024)
+
+            self._singleInstanceChecker = wx.SingleInstanceChecker(self.GetAppName() + '-' + wx.GetUserId())
+            if self._singleInstanceChecker.IsAnotherRunning():
+                # have running single instance open file arguments
+                foundArgs = False
+                args = sys.argv[1:]
+                for arg in args:
+                    if arg[0] != '/' and arg[0] != '-':
+                        foundArgs = True
+                        break
+                          
+                if foundArgs:                      
+                    data = pickle.dumps(args)
+                    while 1:
+                        self._sharedMemory.seek(0)
+                        marker = self._sharedMemory.read_byte()
+                        if marker == '\0' or marker == '*':        # available buffer
+                            self._sharedMemory.seek(0)
+                            self._sharedMemory.write_byte('-')     # set writing marker
+                            self._sharedMemory.write(data)  # write files we tried to open to shared memory
+                            self._sharedMemory.seek(0)
+                            self._sharedMemory.write_byte('+')     # set finished writing marker
+                            self._sharedMemory.flush()
+                            break
+                        else:
+                            time.sleep(1)  # give enough time for buffer to be available
+                        
+                return False
+            else:
+                self._timer = wx.PyTimer(self.DoBackgroundListenAndLoad)
+                self._timer.Start(250)
+
         return True
+        
+
+    def DoBackgroundListenAndLoad(self):
+        """
+        Open any files specified in the given command line argument passed in via shared memory
+        """
+
+        self._sharedMemory.seek(0)
+        if self._sharedMemory.read_byte() == '+':  # available data
+            data = self._sharedMemory.read(1024-1)
+            self._sharedMemory.seek(0)
+            self._sharedMemory.write_byte("*")     # finished reading, set buffer free marker
+            self._sharedMemory.flush()
+            args = pickle.loads(data)
+            for arg in args:
+                if arg[0] != '/' and arg[0] != '-':
+                    self.GetDocumentManager().CreateDocument(arg, wx.lib.docview.DOC_SILENT)
+            
+            # force display of running app
+            topWindow = wx.GetApp().GetTopWindow()
+            if topWindow.IsIconized():
+                topWindow.Iconize(False)
+            else:
+                topWindow.Raise()
+            
+        
+        self._timer.Start(1000) # 1 second interval
 
 
     def OpenCommandLineArgs(self):
@@ -654,11 +735,26 @@ class DocApp(wx.PySimpleApp):
 
     def SetDebug(self, debug):
         """
-        Returns False if the application is in debug mode.
+        Sets the application's debug mode.
         """
         self._debug = debug
 
 
+    def GetSingleInstance(self):
+        """
+        Returns True if the application is in single instance mode.  Used to determine if multiple instances of the application is allowed to launch.
+        """
+        return self._singleInstance
+
+
+    def SetSingleInstance(self, singleInstance):
+        """
+        Sets application's single instance mode.
+        """
+        self._singleInstance = singleInstance
+
+
+
     def CreateChildDocument(self, parentDocument, documentType, objectToEdit, path = ''):
         """
         Creates a child window of a document that edits an object.  The child window
@@ -720,9 +816,12 @@ class DocApp(wx.PySimpleApp):
 
     def ShowSplash(self, image):
         """
-        Shows a splash window with the given image.
+        Shows a splash window with the given image.  Input parameter 'image' can either be a wx.Bitmap or a filename.
         """
-        splash_bmp = wx.Image(image).ConvertToBitmap()
+        if isinstance(image, wx.Bitmap):
+            splash_bmp = image
+        else:
+            splash_bmp = wx.Image(image).ConvertToBitmap()
         self._splash = wx.SplashScreen(splash_bmp,wx.SPLASH_CENTRE_ON_SCREEN | wx.SPLASH_NO_TIMEOUT,0, None, -1) 
         self._splash.Show()
 
@@ -767,33 +866,6 @@ class _DocFrameFileDropTarget(wx.FileDropTarget):
                           self._docManager.FindSuitableParent())
 
 
-def _AboutDialog(frame):
-    """
-    Opens an AboutDialog.  Shared by DocMDIParentFrame and DocSDIFrame.
-    """
-    dlg = wx.Dialog(frame, -1, _("About ") + wx.GetApp().GetAppName(), style = wx.DEFAULT_DIALOG_STYLE)
-    dlg.SetBackgroundColour(wx.WHITE)
-    sizer = wx.BoxSizer(wx.VERTICAL)
-    splash_bmp = wx.Image("activegrid/tool/images/splash.jpg").ConvertToBitmap()
-    image = wx.StaticBitmap(dlg, -1, splash_bmp, (0,0), (splash_bmp.GetWidth(), splash_bmp.GetHeight()))
-    sizer.Add(image, 0, wx.ALIGN_CENTER|wx.ALL, 0)
-    sizer.Add(wx.StaticText(dlg, -1, _("ActiveGrid Application Builder\nVersion 1.0\n\nCopyright (c) 2003-2005 ActiveGrid Incorporated and Contributors.  All rights reserved.")), 0, wx.ALIGN_LEFT|wx.ALL, 5)
-    sizer.Add(wx.StaticText(dlg, -1, _("ActiveGrid Development Team:\nLawrence Bruhmuller\nMatt Fryer\nJoel Hare\nMorgan Hua\nJeff Norton\nPeter Yared")), 0, wx.ALIGN_LEFT|wx.ALL, 5)
-    sizer.Add(wx.StaticText(dlg, -1, _("http://www.activegrid.com")), 0, wx.ALIGN_LEFT|wx.ALL, 5)
-
-
-    btn = wx.Button(dlg, wx.ID_OK)
-    sizer.Add(btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
-
-    dlg.SetSizer(sizer)
-    dlg.SetAutoLayout(True)
-    sizer.Fit(dlg)
-    
-    dlg.CenterOnScreen()
-    dlg.ShowModal()
-    dlg.Destroy()
-
-
 class DocMDIParentFrame(wx.lib.docview.DocMDIParentFrame):
     """
     The DocMDIParentFrame is the primary frame which the DocApp uses to host MDI child windows.  It offers
@@ -1273,7 +1345,7 @@ class DocMDIParentFrame(wx.lib.docview.DocMDIParentFrame):
 
     def UpdateWindowMenu(self):
         """
-        Updates the WindowMenu Windows platforms.
+        Updates the WindowMenu on Windows platforms.
         """
         if wx.Platform == '__WXMSW__':
             children = filter(lambda child: isinstance(child, wx.MDIChildFrame), self.GetChildren())
@@ -1332,7 +1404,9 @@ class DocMDIParentFrame(wx.lib.docview.DocMDIParentFrame):
         """
         Invokes the about dialog.
         """
-        _AboutDialog(self)
+        aboutService = wx.GetApp().GetService(AboutService)
+        if aboutService:
+            aboutService.ShowAbout()
 
 
     def OnViewToolBar(self, event):
@@ -1671,7 +1745,9 @@ class DocSDIFrame(wx.lib.docview.DocChildFrame):
         """
         Invokes the about dialog.
         """
-        _AboutDialog(self)
+        aboutService = wx.GetApp().GetService(AboutService)
+        if aboutService:
+            aboutService.ShowAbout()
 
 
     def OnViewToolBar(self, event):
@@ -1724,9 +1800,68 @@ class DocSDIFrame(wx.lib.docview.DocChildFrame):
             self._docManager.FileHistoryRemoveMenu(self._fileMenu)
 
 
+class AboutService(DocService):
+    """
+    About Dialog Service that installs under the Help menu to show the properties of the current application.
+    """
+
+    def __init__(self, aboutDialog = None):
+        """
+        Initializes the AboutService.
+        """
+        if aboutDialog:
+            self._dlg = aboutDialog
+        else:
+            self._dlg = AboutDialog  # use default AboutDialog
+        
+
+    def ShowAbout(self):
+        """
+        Show the AboutDialog
+        """
+        dlg = self._dlg(wx.GetApp().GetTopWindow())
+        dlg.CenterOnScreen()
+        dlg.ShowModal()
+        dlg.Destroy()
+
+
+    def SetAboutDialog(self, dlg):
+        """
+        Customize the AboutDialog
+        """
+        self._dlg = dlg
+
+
+class AboutDialog(wx.Dialog):
+    """
+    Opens an AboutDialog.  Shared by DocMDIParentFrame and DocSDIFrame.
+    """
+    
+    def __init__(self, parent):
+        """
+        Initializes the about dialog.
+        """
+        wx.Dialog.__init__(self, parent, -1, _("About ") + wx.GetApp().GetAppName(), style = wx.DEFAULT_DIALOG_STYLE)
+
+        self.SetBackgroundColour(wx.WHITE)
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        splash_bmp = wx.Image("activegrid/tool/images/splash.jpg").ConvertToBitmap()
+        image = wx.StaticBitmap(self, -1, splash_bmp, (0,0), (splash_bmp.GetWidth(), splash_bmp.GetHeight()))
+        sizer.Add(image, 0, wx.ALIGN_CENTER|wx.ALL, 0)
+        sizer.Add(wx.StaticText(self, -1, wx.GetApp().GetAppName()), 0, wx.ALIGN_LEFT|wx.ALL, 5)
+    
+        btn = wx.Button(self, wx.ID_OK)
+        sizer.Add(btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
+    
+        self.SetSizer(sizer)
+        self.SetAutoLayout(True)
+        sizer.Fit(self)
+    
+
+
 class FilePropertiesService(DocService):
     """
-    Service that installas under the File menu to show the properties of the file associated
+    Service that installs under the File menu to show the properties of the file associated
     with the current document.
     """
 
@@ -1825,7 +1960,7 @@ class FilePropertiesService(DocService):
         and creates odd word boundaries.  Instead, we will chop the path without regard to
         spaces, but pay attention to path delimiters.
         """
-        chopped = None
+        chopped = ""
         textLen = len(text)
         start = 0
 
@@ -1840,7 +1975,7 @@ class FilePropertiesService(DocService):
                 if lastSep != -1 and lastSep != start:
                     end = lastSep
 
-            if chopped:
+            if len(chopped):
                 chopped = chopped + '\n' + text[start:end]
             else:
                 chopped = text[start:end]
@@ -1867,6 +2002,8 @@ class FilePropertiesDialog(wx.Dialog):
 
         filePropertiesService = wx.GetApp().GetService(FilePropertiesService)
 
+        fileExists = os.path.exists(filename)
+
         notebook = wx.Notebook(self, -1)
         tab = wx.Panel(notebook, -1)
 
@@ -1879,20 +2016,24 @@ class FilePropertiesDialog(wx.Dialog):
         gridSizer.Add(wx.StaticText(tab, -1, filePropertiesService.chopPath(os.path.dirname(filename))), flag=wx.BOTTOM, border=SPACE, row=1, col=1)
 
         gridSizer.Add(wx.StaticText(tab, -1, _("Size:")), flag=wx.RIGHT, border=HALF_SPACE, row=2, col=0)
-        gridSizer.Add(wx.StaticText(tab, -1, str(os.path.getsize(filename)) + ' ' + _("bytes")), row=2, col=1)
+        if fileExists:
+            gridSizer.Add(wx.StaticText(tab, -1, str(os.path.getsize(filename)) + ' ' + _("bytes")), row=2, col=1)
 
         lineSizer = wx.BoxSizer(wx.VERTICAL)    # let the line expand horizontally without vertical expansion
         lineSizer.Add(wx.StaticLine(tab, -1, size = (10,-1)), 0, wx.EXPAND)
         gridSizer.Add(lineSizer, flag=wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.TOP, border=HALF_SPACE, row=3, col=0, colspan=2)
 
         gridSizer.Add(wx.StaticText(tab, -1, _("Created:")), flag=wx.RIGHT, border=HALF_SPACE, row=4, col=0)
-        gridSizer.Add(wx.StaticText(tab, -1, time.ctime(os.path.getctime(filename))), row=4, col=1)
+        if fileExists:
+            gridSizer.Add(wx.StaticText(tab, -1, time.ctime(os.path.getctime(filename))), row=4, col=1)
 
         gridSizer.Add(wx.StaticText(tab, -1, _("Modified:")), flag=wx.RIGHT, border=HALF_SPACE, row=5, col=0)
-        gridSizer.Add(wx.StaticText(tab, -1, time.ctime(os.path.getmtime(filename))), row=5, col=1)
+        if fileExists:
+            gridSizer.Add(wx.StaticText(tab, -1, time.ctime(os.path.getmtime(filename))), row=5, col=1)
 
         gridSizer.Add(wx.StaticText(tab, -1, _("Accessed:")), flag=wx.RIGHT, border=HALF_SPACE, row=6, col=0)
-        gridSizer.Add(wx.StaticText(tab, -1, time.ctime(os.path.getatime(filename))), row=6, col=1)
+        if fileExists:
+            gridSizer.Add(wx.StaticText(tab, -1, time.ctime(os.path.getatime(filename))), row=6, col=1)
 
         # add a border around the inside of the tab
         spacerGrid = wx.BoxSizer(wx.VERTICAL)