]> git.saurik.com Git - wxWidgets.git/commitdiff
DocView patches from Morgen Hua: bug fixes, and additional SVN
authorRobin Dunn <robin@alldunn.com>
Tue, 31 May 2005 21:41:11 +0000 (21:41 +0000)
committerRobin Dunn <robin@alldunn.com>
Tue, 31 May 2005 21:41:11 +0000 (21:41 +0000)
commands, also added a default template that uses the text editor for
any unknown file type.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@34473 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

22 files changed:
wxPython/samples/ide/activegrid/tool/AboutDialog.py
wxPython/samples/ide/activegrid/tool/AbstractEditor.py
wxPython/samples/ide/activegrid/tool/CodeEditor.py
wxPython/samples/ide/activegrid/tool/DebuggerHarness.py
wxPython/samples/ide/activegrid/tool/DebuggerService.py
wxPython/samples/ide/activegrid/tool/HtmlEditor.py
wxPython/samples/ide/activegrid/tool/IDE.py
wxPython/samples/ide/activegrid/tool/ImageEditor.py
wxPython/samples/ide/activegrid/tool/PHPEditor.py
wxPython/samples/ide/activegrid/tool/PerlEditor.py
wxPython/samples/ide/activegrid/tool/ProjectEditor.py
wxPython/samples/ide/activegrid/tool/PythonEditor.py
wxPython/samples/ide/activegrid/tool/STCTextEditor.py
wxPython/samples/ide/activegrid/tool/SVNService.py
wxPython/samples/ide/activegrid/tool/UICommon.py
wxPython/samples/ide/activegrid/tool/XmlEditor.py
wxPython/samples/ide/activegrid/tool/process.py
wxPython/samples/ide/activegrid/util/__init__.py
wxPython/samples/ide/activegrid/util/objutils.py
wxPython/samples/ide/activegrid/util/xmlmarshaller.py
wxPython/wx/lib/docview.py
wxPython/wx/lib/pydocview.py

index 3a7be9fa741215922721376e74f7f8186d1bbcd9..b43e5244ca2aae5db96a583ac22581cdc4b05ba9 100644 (file)
@@ -59,7 +59,7 @@ class AboutDialog(wx.Dialog):
         splash_bmp = getSplashBitmap()
         image = wx.StaticBitmap(aboutPage, -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(aboutPage, -1, wx.GetApp().GetAppName() + _("\nVersion 0.6 Early Access\n\nCopyright (c) 2003-2005 ActiveGrid Incorporated and Contributors.  All rights reserved.")), 0, wx.ALIGN_LEFT|wx.ALL, 10)
+        sizer.Add(wx.StaticText(aboutPage, -1, wx.GetApp().GetAppName() + _("\nVersion 0.7 Early Access\n\nCopyright (c) 2003-2005 ActiveGrid Incorporated and Contributors.  All rights reserved.")), 0, wx.ALIGN_LEFT|wx.ALL, 10)
         sizer.Add(wx.StaticText(aboutPage, -1, _("http://www.activegrid.com")), 0, wx.ALIGN_LEFT|wx.LEFT|wx.BOTTOM, 10)
         aboutPage.SetSizer(sizer)
         nb.AddPage(aboutPage, _("Copyright"))
index 8369738428b2469d4decdf5227b7e32d6784bbb4..18fbf6d7fc1b84f2801dd23b1e828f479a04355b 100644 (file)
@@ -48,8 +48,17 @@ class CanvasView(wx.lib.docview.View):
         self._pt2 = None
         self._needEraseLasso = False
         self._propShape = None
+        self._maxWidth = 2000
+        self._maxHeight = 16000
 
 
+    def OnDraw(self, dc):
+        """ for Print Preview and Print """
+        dc.BeginDrawing()
+        self._canvas.Redraw(dc)
+        dc.EndDrawing()
+        
+
     def OnCreate(self, doc, flags):
         frame = wx.GetApp().CreateDocumentFrame(self, doc, flags)
         frame.Show()
@@ -130,9 +139,7 @@ class CanvasView(wx.lib.docview.View):
         wx.EVT_KILL_FOCUS(self._canvas, self.OnKillFocus)
         wx.EVT_SET_FOCUS(self._canvas, self.OnFocus)
 
-        maxWidth = 2000
-        maxHeight = 16000
-        self._canvas.SetScrollbars(20, 20, maxWidth / 20, maxHeight / 20)
+        self._canvas.SetScrollbars(20, 20, self._maxWidth / 20, self._maxHeight / 20)
         
         self._canvas.SetBackgroundColour(wx.WHITE)
         self._diagram = ogl.Diagram()
@@ -654,7 +661,16 @@ class EditorCanvasShapeEvtHandler(ogl.ShapeEvtHandler):
         self._view.SetSelection(model, keys == self.SHIFT_KEY or keys == self.CONTROL_KEY)
 
 
+    def OnMovePre(self, dc, x, y, oldX, oldY, display):
+        """ Prevent objects from being dragged outside of viewable area """
+        if (x > self._view._maxWidth) or (y > self._view._maxHeight):
+            return False
+
+        return ogl.ShapeEvtHandler.OnMovePre(self, dc, x, y, oldX, oldY, display)
+
+
     def OnMovePost(self, dc, x, y, oldX, oldY, display):
+        """ Update the model's record of where the shape should be.  Also enable redo/undo.  """
         if x == oldX and y == oldY:
             return
         if not self._view.GetDocument():
index d8a158a0ee9bf5ec31e4869cd48def8230bd7e14..de0fbaf86e1669f1bb1280b28cc45120ba8650db 100644 (file)
@@ -633,10 +633,8 @@ class CodeCtrl(STCTextEditor.TextCtrl):
     BREAKPOINT_MARKER_MASK = 0x2
     
             
-    def __init__(self, parent, ID = -1, style = wx.NO_FULL_REPAINT_ON_RESIZE):
-        if ID == -1:
-            ID = wx.NewId()
-        STCTextEditor.TextCtrl.__init__(self, parent, ID, style)
+    def __init__(self, parent, id=-1, style = wx.NO_FULL_REPAINT_ON_RESIZE):
+        STCTextEditor.TextCtrl.__init__(self, parent, id, style)
         
         self.UsePopUp(False)
         self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
@@ -672,10 +670,10 @@ class CodeCtrl(STCTextEditor.TextCtrl):
         if _WINDOWS:  # should test to see if menu item exists, if it does, add this workaround
             self.CmdKeyClear(wx.stc.STC_KEY_TAB, 0)  # menu item "Indent Lines" from CodeService.InstallControls() generates another INDENT_LINES_ID event, so we'll explicitly disable the tab processing in the editor
 
-        wx.stc.EVT_STC_MARGINCLICK(self, ID, self.OnMarginClick)
+        wx.stc.EVT_STC_MARGINCLICK(self, self.GetId(), self.OnMarginClick)
         wx.EVT_KEY_DOWN(self, self.OnKeyPressed)
         if self.GetMatchingBraces(): 
-            wx.stc.EVT_STC_UPDATEUI(self, ID, self.OnUpdateUI)
+            wx.stc.EVT_STC_UPDATEUI(self, self.GetId(), self.OnUpdateUI)
 
         self.StyleClearAll()
         self.UpdateStyles()
@@ -720,7 +718,8 @@ class CodeCtrl(STCTextEditor.TextCtrl):
                 item = menuBar.FindItemById(itemID)
                 if item:
                     menu.Append(itemID, item.GetLabel())
-
+                    wx.EVT_MENU(self, itemID, self.DSProcessEvent)  # wxHack: for customized right mouse menu doesn't work with new DynamicSashWindow
+                    wx.EVT_UPDATE_UI(self, itemID, self.DSProcessUpdateUIEvent)  # wxHack: for customized right mouse menu doesn't work with new DynamicSashWindow
         return menu
                 
 
@@ -834,6 +833,7 @@ class CodeCtrl(STCTextEditor.TextCtrl):
 
     def DoIndent(self):
         self.AddText('\n')
+        self.EnsureCaretVisible()
         # Need to do a default one for all languges
 
 
index e321865a09302381dcbfc6b107d8cb5103e59ff6..433c118dce95e29ad07367d0650c89c595a24856 100644 (file)
@@ -22,6 +22,8 @@ import inspect
 from xml.dom.minidom import getDOMImplementation
 import atexit
 import pickle
+import cStringIO
+import bz2
 
 if sys.platform.startswith("win"):
     import win32api
@@ -107,7 +109,7 @@ class Adb(bdb.Bdb):
             exc_type_name = exc_type
         else: 
             exc_type_name = exc_type.__name__
-        message = "Exception occurred: " + repr(exc_type_name) + " See locals.__exception__ for details."
+        message = "Exception occured: " + repr(exc_type_name) + " See locals.__exception__ for details."
         traceback.print_exception(exc_type, exc_value, exc_traceback)
         self._harness.interaction(message, frame, message)
 
@@ -189,8 +191,7 @@ class Adb(bdb.Bdb):
         return ""
                 
     def stop_here(self, frame):
-        if( self._userBreak ):
-            self._userBreak = False
+        if self._userBreak:
             return True
         
 
@@ -270,6 +271,7 @@ class BreakListenerThread(threading.Thread):
             if _VERBOSE: print "Before calling server close on breakpoint server"
             self._server.server_close()
             if _VERBOSE: print "Calling server close on breakpoint server"
+            self._server = None
                            
         
 class DebuggerHarness(object):
@@ -312,8 +314,11 @@ class DebuggerHarness(object):
         self._server.register_function(self.clear_breakpoint)
         self._server.register_function(self.set_all_breakpoints)
         self._server.register_function(self.attempt_introspection)
+        self._server.register_function(self.execute_in_frame)
         self._server.register_function(self.add_watch)
+        self._server.register_function(self.request_frame_document)
         
+        self.frame_stack = []
         self.message_frame_dict = {}
         self.introspection_list = []
         atexit.register(self.do_exit)
@@ -364,7 +369,28 @@ class DebuggerHarness(object):
                 tp, val, tb = sys.exc_info()
                 return self.get_exception_document(tp, val, tb) 
         return ""
-                
+        
+    def execute_in_frame(self, frame_message, command):
+        frame = self.message_frame_dict[frame_message]
+        output = cStringIO.StringIO()
+        out = sys.stdout
+        err = sys.stderr
+        sys.stdout = output
+        sys.stderr = output
+        try:
+            exec command in frame.f_globals, frame.f_locals
+            return output.getvalue()
+            sys.stdout = out
+            sys.stderr = err        
+        except:
+            sys.stdout = out
+            sys.stderr = err        
+
+            tp, val, tb = sys.exc_info()           
+            output = cStringIO.StringIO()
+            traceback.print_exception(tp, val, tb, file=output)
+            return output.getvalue()   
+               
     def attempt_introspection(self, frame_message, chain):
         try:
             frame = self.message_frame_dict[frame_message]
@@ -608,22 +634,27 @@ class DebuggerHarness(object):
             
         
     def getFrameXML(self, base_frame):
-        doc = getDOMImplementation().createDocument(None, "stack", None)
-        top_element = doc.documentElement
 
-        stack = []
+        self.frame_stack = []
         frame = base_frame
         while frame is not None:
             if((frame.f_code.co_filename.count('DebuggerHarness.py') == 0) or _DEBUG_DEBUGGER):
-                stack.append(frame)
+                self.frame_stack.append(frame)
             frame = frame.f_back
-        stack.reverse()
+        self.frame_stack.reverse()
         self.message_frame_dict = {}
-        for f in stack:
-            self.addFrame(f,top_element, doc)
+        doc = getDOMImplementation().createDocument(None, "stack", None)
+        top_element = doc.documentElement
+        numberFrames = len(self.frame_stack)
+        for index in range(numberFrames):
+            frame = self.frame_stack[index]
+            message = self._adb.frame2message(frame)
+            # We include globals and locals only for the last frame as an optimization for cases
+            # where there are a lot of frames.
+            self.addFrame(frame, top_element, doc, includeContent=(index == numberFrames - 1))
         return doc.toxml()
         
-    def addFrame(self, frame, root_element, document):
+    def addFrame(self, frame, root_element, document, includeContent=False):
         frameNode = document.createElement('frame')
         root_element.appendChild(frameNode)
         
@@ -633,11 +664,19 @@ class DebuggerHarness(object):
         frameNode.setAttribute('line', str(frame.f_lineno))
         message = self._adb.frame2message(frame)
         frameNode.setAttribute('message', message)
-        #print "Frame: %s %s %s" %(message, frame.f_lineno, filename)
         self.message_frame_dict[message] = frame
-        self.addDict(frameNode, "locals", frame.f_locals, document, 2)        
-        self.addNode(frameNode, "globals", frame.f_globals,  document)
-                    
+        if includeContent:
+            self.addDict(frameNode, "locals", frame.f_locals, document, 2)        
+            self.addNode(frameNode, "globals", frame.f_globals,  document)
+            
+    def request_frame_document(self, message):
+        frame = self.message_frame_dict[message]  
+        doc = getDOMImplementation().createDocument(None, "stack", None)
+        top_element = doc.documentElement
+        if frame:
+            self.addFrame(frame, top_element, doc, includeContent=True)
+        return xmlrpclib.Binary(bz2.compress(doc.toxml()))
+            
     def getRepr(self, varName, globals, locals):
         try:
             return repr(eval(varName, globals, locals))
@@ -647,23 +686,25 @@ class DebuggerHarness(object):
    
     def saferepr(self, thing):
         try:
-            return repr(thing)
+            try:
+                return repr(thing)
+            except:
+                return str(type(thing))
         except:
             tp, val, tb = sys.exc_info()
-            traceback.print_exception(tp, val, tb)
+            #traceback.print_exception(tp, val, tb)
             return repr(val)
                     
     # The debugger calls this method when it reaches a breakpoint.
     def interaction(self, message, frame, info):
         if _VERBOSE:
             print 'hit debug side interaction'
-        self._userBreak = False
+        self._adb._userBreak = False
 
         self._currentFrame = frame
         done = False
         while not done:
             try:
-                import bz2
                 xml = self.getFrameXML(frame)
                 arg = xmlrpclib.Binary(bz2.compress(xml))
                 if _VERBOSE:
index 79e78e04663926cdbb79b9863ae05e104557221c..8da8bc2492fd177619f34f5115ee62f7c05faffe 100644 (file)
@@ -41,6 +41,7 @@ import pickle
 import DebuggerHarness
 import traceback
 import StringIO
+
 if wx.Platform == '__WXMSW__':
     try:
         import win32api
@@ -72,7 +73,12 @@ class OutputReaderThread(threading.Thread):
         self._lineCount = 0
         self._accumulate = accumulate
         self._callbackOnExit = callbackOnExit
-         
+        self.setDaemon(True)
+    
+    def __del__(self):
+        # See comment on DebugCommandUI.StopExecution
+        self._keepGoing = False
+             
     def run(self):
         file = self._file
         start = time.time()
@@ -83,7 +89,7 @@ class OutputReaderThread(threading.Thread):
                 text = file.readline()
                 if text == '' or text == None:
                     self._keepGoing = False
-                elif not self._accumulate:
+                elif not self._accumulate and self._keepGoing:
                     self._callback_function(text)
                 else:
                     # Should use a buffer? StringIO?
@@ -91,11 +97,11 @@ class OutputReaderThread(threading.Thread):
                 # Seems as though the read blocks if we got an error, so, to be
                 # sure that at least some of the exception gets printed, always 
                 # send the first hundred lines back as they come in.
-                if self._lineCount < 100:    
+                if self._lineCount < 100 and self._keepGoing:    
                     self._callback_function(output)
                     self._lineCount += 1
                     output = "" 
-                elif time.time() - start > 0.25:
+                elif time.time() - start > 0.25 and self._keepGoing:
                     try:
                         self._callback_function(output) 
                     except wx._core.PyDeadObjectError:
@@ -103,8 +109,8 @@ class OutputReaderThread(threading.Thread):
                         self._keepGoing = False
                     start = time.time()
                     output = "" 
-            except TypeError:
-                pass
+            #except TypeError:
+            #    pass
             except:
                 tp, val, tb = sys.exc_info()
                 print "Exception in OutputReaderThread.run():", tp, val
@@ -118,7 +124,7 @@ class OutputReaderThread(threading.Thread):
         
     def AskToStop(self):
         self._keepGoing = False
-        
+                
 import  wx.lib.newevent
 (UpdateTextEvent, EVT_UPDATE_STDTEXT) = wx.lib.newevent.NewEvent()
 (UpdateErrorEvent, EVT_UPDATE_ERRTEXT) = wx.lib.newevent.NewEvent()
@@ -165,7 +171,6 @@ class Executor:
         self._stdOutReader = None
         self._stdErrReader = None
         self._process = None
-        DebuggerService.executors.append(self)
         
     def OutCall(self, text):
         evt = UpdateTextEvent(value = text)
@@ -180,8 +185,6 @@ class Executor:
             startIn = str(os.getcwd())
         startIn = os.path.abspath(startIn)
         command = self._cmd + ' ' + arguments
-        #stdinput = process.IOBuffer()
-        #self._process = process.ProcessProxy(command, mode='b', cwd=startIn, stdin=stdinput)
         self._process = process.ProcessOpen(command, mode='b', cwd=startIn, env=environment)
         # Kick off threads to read stdout and stderr and write them
         # to our text control. 
@@ -189,35 +192,46 @@ class Executor:
         self._stdOutReader.start()
         self._stdErrReader = OutputReaderThread(self._process.stderr, self._stdErrCallback, accumulate=False)
         self._stdErrReader.start()
-                
-    
+                        
     def DoStopExecution(self):
+        # See comment on DebugCommandUI.StopExecution
         if(self._process != None):
-            self._process.kill()
-            self._process.close()
-            self._process = None
-        if(self._stdOutReader != None):
             self._stdOutReader.AskToStop()
-        if(self._stdErrReader != None):
             self._stdErrReader.AskToStop()
-        DebuggerService.executors.remove(self)
+            try:
+                self._process.kill(gracePeriod=2.0)
+            except:
+                pass
+            self._process = None
         
 class RunCommandUI(wx.Panel):
+    runners = []
+    
+    def ShutdownAllRunners():
+        # See comment on DebugCommandUI.StopExecution
+        for runner in RunCommandUI.runners:
+            try:
+                runner.StopExecution(None)
+            except wx._core.PyDeadObjectError:
+                pass
+        RunCommandUI.runners = []    
+    ShutdownAllRunners = staticmethod(ShutdownAllRunners)
     
     def __init__(self, parent, id, fileName):
         wx.Panel.__init__(self, parent, id)
         self._noteBook = parent
         
+        threading._VERBOSE = _VERBOSE
+        
         self.KILL_PROCESS_ID = wx.NewId()
         self.CLOSE_TAB_ID = wx.NewId()
         
-        self.Bind(wx.EVT_END_PROCESS, self.OnProcessEnded)
         
         # GUI Initialization follows
         sizer = wx.BoxSizer(wx.HORIZONTAL)
         self._tb = tb = wx.ToolBar(self,  -1, wx.DefaultPosition, (30,1000), wx.TB_VERTICAL| wx.TB_FLAT, "Runner" )
         tb.SetToolBitmapSize((16,16))
-        sizer.Add(tb, 0, wx.EXPAND |wx.ALIGN_LEFT|wx.ALL, 1)
+        sizer.Add(tb, 0, wx.EXPAND|wx.ALIGN_LEFT|wx.ALL, 1)
 
         close_bmp = getCloseBitmap()
         tb.AddSimpleTool( self.CLOSE_TAB_ID, close_bmp, _('Close Window'))
@@ -245,12 +259,16 @@ class RunCommandUI(wx.Panel):
         self.SetSizer(sizer)
         sizer.Fit(self)
         
+        self._stopped = False
         # Executor initialization
         self._executor = Executor(fileName, self, callbackOnExit=self.ExecutorFinished)
         self.Bind(EVT_UPDATE_STDTEXT, self.AppendText)
         self.Bind(EVT_UPDATE_ERRTEXT, self.AppendErrorText)
         
+        RunCommandUI.runners.append(self)
+        
     def __del__(self):
+        # See comment on DebugCommandUI.StopExecution
         self._executor.DoStopExecution()
                  
     def Execute(self, initialArgs, startIn, environment):
@@ -267,9 +285,11 @@ class RunCommandUI(wx.Panel):
                 break
            
     def StopExecution(self):
-        self.Unbind(EVT_UPDATE_STDTEXT)
-        self.Unbind(EVT_UPDATE_ERRTEXT)
-        self._executor.DoStopExecution()
+        if not self._stopped:
+            self._stopped = True
+            self.Unbind(EVT_UPDATE_STDTEXT)
+            self.Unbind(EVT_UPDATE_ERRTEXT)
+            self._executor.DoStopExecution()
         
     def AppendText(self, event):
         self._textCtrl.SetReadOnly(False)
@@ -295,10 +315,10 @@ class RunCommandUI(wx.Panel):
         id = event.GetId()
         
         if id == self.KILL_PROCESS_ID:
-            self._executor.DoStopExecution()
+            self.StopExecution()
             
         elif id == self.CLOSE_TAB_ID:
-            self._executor.DoStopExecution()
+            self.StopExecution()
             index = self._noteBook.GetSelection()
             self._noteBook.GetPage(index).Show(False)
             self._noteBook.RemovePage(index)
@@ -349,8 +369,6 @@ class RunCommandUI(wx.Panel):
                 
         foundView.GetCtrl().MarkerAdd(lineNum -1, CodeEditor.CodeCtrl.CURRENT_LINE_MARKER_NUM)
 
-    def OnProcessEnded(self, evt):
-        self._executor.DoStopExecution()
 
 DEFAULT_PORT = 32032
 DEFAULT_HOST = 'localhost' 
@@ -374,9 +392,13 @@ class DebugCommandUI(wx.Panel):
     DebuggerRunning = staticmethod(DebuggerRunning)
     
     def ShutdownAllDebuggers():
+        # See comment on DebugCommandUI.StopExecution
         for debugger in DebugCommandUI.debuggers:
-            debugger.StopExecution(None)
-            
+            try:
+                debugger.StopExecution(None)
+            except wx._core.PyDeadObjectError:
+                pass
+        DebugCommandUI.debuggers = []    
     ShutdownAllDebuggers = staticmethod(ShutdownAllDebuggers)
     
     def GetAvailablePort():
@@ -549,9 +571,8 @@ class DebugCommandUI(wx.Panel):
         self.framesTab.PopulateBPList()
         
     def __del__(self):
-        if self in DebugCommandUI.debuggers:
-            DebugCommandUI.debuggers.remove(self)
-        
+        # See comment on DebugCommandUI.StopExecution
+        self.StopExecution(None)        
         
     def DisableWhileDebuggerRunning(self):
         self._tb.EnableTool(self.STEP_ID, False)
@@ -655,23 +676,42 @@ class DebugCommandUI(wx.Panel):
         
                        
     def StopExecution(self, event):
-        self._stopped = True
-        self.DisableAfterStop()
-        try:
-            self._callback.ServerClose()
-        except:
-            pass 
-        try:
-            if self._executor:
-                self._executor.DoStopExecution()
-                self._executor = None
-        except:
-            pass
-        self.DeleteCurrentLineMarkers()
-        DebugCommandUI.ReturnPortToPool(self._debuggerPort)
-        DebugCommandUI.ReturnPortToPool(self._guiPort)
-        DebugCommandUI.ReturnPortToPool(self._debuggerBreakPort)
+        # This is a general comment on shutdown for the running and debugged processes. Basically, the
+        # current state of this is the result of trial and error coding. The common problems were memory
+        # access violations and threads that would not exit. Making the OutputReaderThreads daemons seems
+        # to have side-stepped the hung thread issue. Being very careful not to touch things after calling
+        # process.py:ProcessOpen.kill() also seems to have fixed the memory access violations, but if there
+        # were more ugliness discovered I would not be surprised. If anyone has any help/advice, please send
+        # it on to mfryer@activegrid.com.
+        if not self._stopped:
+            self._stopped = True
+            try:
+                self.DisableAfterStop()
+            except wx._core.PyDeadObjectError:
+                pass
+            try:
+                self._callback.ShutdownServer()
+            except:
+                tp,val,tb = sys.exc_info()
+                traceback.print_exception(tp, val, tb)
 
+            try:
+                self.DeleteCurrentLineMarkers()
+            except:
+                pass
+            try:
+                DebugCommandUI.ReturnPortToPool(self._debuggerPort)
+                DebugCommandUI.ReturnPortToPool(self._guiPort)
+                DebugCommandUI.ReturnPortToPool(self._debuggerBreakPort)
+            except:
+                pass
+            try:
+                if self._executor:
+                    self._executor.DoStopExecution()
+                    self._executor = None
+            except:
+                tp,val,tb = sys.exc_info()
+                traceback.print_exception(tp, val, tb)                
     def StopAndRemoveUI(self, event):
         self.StopExecution(None)
         if self in DebugCommandUI.debuggers:
@@ -695,7 +735,7 @@ class DebugCommandUI(wx.Panel):
         self.framesTab.AppendErrorText(event.value)
         
     def OnClearOutput(self, event):
-        self.framesTab.ClearOutput()
+        self.framesTab.ClearOutput(None)
 
     def SwitchToOutputTab(self):
         self.framesTab.SwitchToOutputTab()
@@ -899,10 +939,10 @@ class FramesUI(wx.SplitterWindow):
         self._notebook.Hide()
         sizer3.Add(self._notebook, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 1)
         self.consoleTab = self.MakeConsoleTab(self._notebook, wx.NewId())
-        #self.inspectConsoleTab = self.MakeInspectConsoleTab(self._notebook, wx.NewId())
+        self.inspectConsoleTab = self.MakeInspectConsoleTab(self._notebook, wx.NewId())
         self.breakPointsTab = self.MakeBreakPointsTab(self._notebook, wx.NewId())
         self._notebook.AddPage(self.consoleTab, "Output")
-        #self._notebook.AddPage(self.inspectConsoleTab, "Interact")
+        self._notebook.AddPage(self.inspectConsoleTab, "Interact")
         self._notebook.AddPage(self.breakPointsTab, "Break Points")
 
         self.SetMinimumPaneSize(20)
@@ -936,23 +976,74 @@ class FramesUI(wx.SplitterWindow):
         return panel
         
     def MakeInspectConsoleTab(self, parent, id):
-        def OnEnterPressed(event):
-            print "Enter text was %s" % event.GetString()
-        def OnText(event):
-            print "Command was %s" % event.GetString()
+        self.command_list = []
+        self.command_index = 0
+        def ExecuteCommand(command):
+            if not len(self.command_list) or not command == self.command_list[len(self.command_list) -1]:
+                self.command_list.append(command)
+                self.command_index = len(self.command_list) - 1
+            retval = self._ui._callback._debuggerServer.execute_in_frame(self._framesChoiceCtrl.GetStringSelection(), command)
+            self._interCtrl.AddText("\n" + str(retval))
+            self._interCtrl.ScrollToLine(self._interCtrl.GetLineCount())
+            # Refresh the tree view in case this command resulted in changes there. TODO: Need to reopen tree items.
+            self.PopulateTreeFromFrameMessage(self._framesChoiceCtrl.GetStringSelection())
+
+        def ReplaceLastLine(command):
+            line = self._interCtrl.GetLineCount() - 1
+            self._interCtrl.GotoLine(line)
+            start = self._interCtrl.GetCurrentPos()
+            self._interCtrl.SetTargetStart(start)
+            end = self._interCtrl.GetLineEndPosition(line)
+            self._interCtrl.SetTargetEnd(end)
+            self._interCtrl.ReplaceTarget(">>> " + command)
+            self._interCtrl.GotoLine(line)
+            self._interCtrl.SetSelectionStart(self._interCtrl.GetLineEndPosition(line))
             
-        panel = wx.Panel(parent, id)
-        try:
+        def OnKeyPressed(event):
+            key = event.KeyCode()
+            if key == wx.WXK_DELETE or key == wx.WXK_BACK:
+                if self._interCtrl.GetLine(self._interCtrl.GetCurrentLine()) == ">>> ":
+                    return
+            elif key == wx.WXK_RETURN:
+                command = self._interCtrl.GetLine(self._interCtrl.GetCurrentLine())[4:]
+                ExecuteCommand(command)             
+                self._interCtrl.AddText("\n>>> ")
+                return
+            elif key == wx.WXK_UP:
+                if not len(self.command_list):
+                    return
+                ReplaceLastLine(self.command_list[self.command_index])
+                if self.command_index  == 0:
+                    self.command_index  = len(self.command_list) - 1
+                else:
+                    self.command_index = self.command_index - 1
+                return
+            elif key == wx.WXK_DOWN:
+                if not len(self.command_list):
+                    return
+                if self.command_index  < len(self.command_list) - 1:
+                    self.command_index = self.command_index + 1
+                else:
+                    self.command_index = 0
+                ReplaceLastLine(self.command_list[self.command_index])                        
+                return
+            event.Skip()
+
+        try:    
+            panel = wx.Panel(parent, id)
             sizer = wx.BoxSizer(wx.HORIZONTAL)
-            self._ictextCtrl = wx.TextCtrl(panel, wx.NewId(), style=wx.TE_MULTILINE|wx.TE_RICH|wx.HSCROLL)
-            sizer.Add(self._ictextCtrl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 2)
-            self._ictextCtrl.Bind(wx.EVT_TEXT_ENTER, OnEnterPressed)
-            self._ictextCtrl.Bind(wx.EVT_TEXT, OnText)
+            self._interCtrl = STCTextEditor.TextCtrl(panel, wx.NewId())
+            sizer.Add(self._interCtrl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 2)
+            self._interCtrl.SetViewLineNumbers(False)
             if wx.Platform == '__WXMSW__':
                 font = "Courier New"
             else:
                 font = "Courier"
-            self._ictextCtrl.SetDefaultStyle(wx.TextAttr(font=wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.NORMAL, faceName = font)))
+            self._interCtrl.SetFont(wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.NORMAL, faceName = font))
+            self._interCtrl.SetFontColor(wx.BLACK)
+            self._interCtrl.StyleClearAll()
+            wx.EVT_KEY_DOWN(self._interCtrl, OnKeyPressed)
+            self._interCtrl.AddText(">>> ")
             panel.SetSizer(sizer)
         except:
             tp, val, tb = sys.exc_info()
@@ -1066,6 +1157,7 @@ class FramesUI(wx.SplitterWindow):
         tree = self._treeCtrl  
         root = self._root   
         tree.DeleteChildren(root)
+        self._interCtrl.Enable(False)
    
         #tree.Hide()
         
@@ -1088,6 +1180,8 @@ class FramesUI(wx.SplitterWindow):
         
     def LoadFramesListXML(self, framesXML):
         wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
+        self._interCtrl.Enable(True)
+
         try:
             domDoc = parseString(framesXML)
             list = self._framesChoiceCtrl
@@ -1103,6 +1197,7 @@ class FramesUI(wx.SplitterWindow):
                 frame_count += 1
             index = len(self._stack) - 1
             list.SetSelection(index) 
+
             node = self._stack[index]
             self.currentItem = index
             self.PopulateTreeFromFrameNode(node)
@@ -1121,13 +1216,20 @@ class FramesUI(wx.SplitterWindow):
 
         
     def ListItemSelected(self, event):
-        message = event.GetString()
+        self.PopulateTreeFromFrameMessage(event.GetString())
+        self.OnSyncFrame(None)
+        
+    def PopulateTreeFromFrameMessage(self, message):    
         index = 0
         for node in self._stack:
             if node.getAttribute("message") == message:
+                binType = self._ui._callback._debuggerServer.request_frame_document(message)
+                xmldoc = bz2.decompress(binType.data)
+                domDoc = parseString(xmldoc)
+                nodeList = domDoc.getElementsByTagName('frame')
                 self.currentItem = index
-                self.PopulateTreeFromFrameNode(node)
-                self.OnSyncFrame(None)
+                if len(nodeList):
+                    self.PopulateTreeFromFrameNode(nodeList[0])
                 return
             index = index + 1
                         
@@ -1146,7 +1248,8 @@ class FramesUI(wx.SplitterWindow):
             if not firstChild:
                 firstChild = treeNode
         tree.Expand(root)
-        tree.Expand(firstChild)
+        if firstChild:
+            tree.Expand(firstChild)
         self._p2.FitInside()
         
     def IntrospectCallback(self, event):
@@ -1252,7 +1355,13 @@ class DebuggerView(Service.ServiceView):
     
     def OnToolClicked(self, event):
         self.GetFrame().ProcessEvent(event)
-    
+        
+    def ProcessUpdateUIEvent(self, event):
+        return False
+        
+    def ProcessEvent(self, event):
+        return False
+
     #------------------------------------------------------------------------------
     # Class methods
     #-----------------------------------------------------------------------------
@@ -1396,9 +1505,9 @@ class DebuggerCallback:
     def start(self):
         self._serverHandlerThread.start()
     
-    def ServerClose(self):
-        rbt = RequestBreakThread(self._breakServer, kill=True)
-        rbt.start()
+    def ShutdownServer(self):
+        #rbt = RequestBreakThread(self._breakServer, kill=True)
+        #rbt.start()
         self.setWaiting(False)
         if self._serverHandlerThread:
             self._serverHandlerThread.AskToStop()
@@ -1410,29 +1519,21 @@ class DebuggerCallback:
                 
     def SingleStep(self):
         self._debuggerUI.DisableWhileDebuggerRunning()
-        #dot = DebuggerOperationThread(self._debuggerServer.set_step)
-        #dot.start()
         self._debuggerServer.set_step() # Figure out where to set allowNone
         self.waitForRPC()
 
     def Next(self):
         self._debuggerUI.DisableWhileDebuggerRunning()
-        #dot = DebuggerOperationThread(self._debuggerServer.set_next)
-        #dot.start()
         self._debuggerServer.set_next()
         self.waitForRPC()
         
     def Continue(self):
         self._debuggerUI.DisableWhileDebuggerRunning()
-        #dot = DebuggerOperationThread(self._debuggerServer.set_continue)
-        #dot.start()
         self._debuggerServer.set_continue()
         self.waitForRPC()
         
     def Return(self):
         self._debuggerUI.DisableWhileDebuggerRunning()
-        #dot = DebuggerOperationThread(self._debuggerServer.set_return)
-        #dot.start()
         self._debuggerServer.set_return()
         self.waitForRPC()
         
@@ -1498,7 +1599,6 @@ class DebuggerCallback:
         if _VERBOSE: print "+"*40
         
 class DebuggerService(Service.Service):
-    executors = []
 
     #----------------------------------------------------------------------------
     # Constants
@@ -1509,11 +1609,6 @@ class DebuggerService(Service.Service):
     DEBUG_ID = wx.NewId()
     DEBUG_WEBSERVER_ID = wx.NewId()
 
-    def KillAllRunningProcesses():
-        execs = DebuggerService.executors
-        for executor in execs:
-            executor.DoStopExecution()
-    KillAllRunningProcesses = staticmethod(KillAllRunningProcesses)
             
     def ComparePaths(first, second):
         one = DebuggerService.ExpandPath(first)
@@ -1530,7 +1625,8 @@ class DebuggerService(Service.Service):
             try:
                 return win32api.GetLongPathName(path)
             except:
-                print "Cannot get long path for %s" % path
+                if _VERBOSE:
+                    print "Cannot get long path for %s" % path
                 
         return path
         
@@ -1755,6 +1851,7 @@ class DebuggerService(Service.Service):
 
     def OnExit(self):
         DebugCommandUI.ShutdownAllDebuggers()
+        RunCommandUI.ShutdownAllRunners()
         
     def OnRunProject(self, event):
         if _WINDOWS and not _PYWIN32_INSTALLED:
@@ -2010,9 +2107,6 @@ class CommandPropertiesDialog(wx.Dialog):
             self._lastStartIn = str(os.getcwd())
         self._startEntry = wx.TextCtrl(self, -1, self._lastStartIn)
         self._startEntry.SetToolTipString(self._lastStartIn)
-        def TextChanged2(event):
-            self._startEntry.SetToolTipString(event.GetString())
-        self.Bind(wx.EVT_TEXT, TextChanged2, self._startEntry)
 
         flexGridSizer.Add(self._startEntry, 1, wx.EXPAND)
         self._findDir = wx.Button(self, -1, _("Browse..."))
@@ -2240,19 +2334,20 @@ def getBreakIcon():
     return wx.IconFromBitmap(getBreakBitmap())
 
 #----------------------------------------------------------------------
+
 def getClearOutputData():
     return \
 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
-\x00\x00\xb4IDAT8\x8d\xa5\x92\xdd\r\x03!\x0c\x83\xbf\xa0n\xd4\x9d\xda5\xb81\
-\xbaS\xbb\x12\xee\x03?\xe5\x08\xe5N\xba\xbc Db\xec\xd8p\xb1l\xb8\xa7\x83\xfe\
-\xb0\x02H\x92F\xc0_\xa3\x99$\x99\x99\xedznc\xe36\x81\x88\x98"\xb2\x02\xa2\
-\x1e\xc4Q\x9aUD\x161\xcd\xde\x1c\x83\x15\x084)\x8d\xc5)\x06\xab\xaaZ\x92\xee\
-\xce\x11W\xdbGD\x0cIT\x06\xe7\x00\xdeY\xfe\xcc\x89\x06\xf0\xf2\x99\x00\xe0\
-\x91\x7f\xab\x83\xed\xa4\xc8\xafK\x0c\xcf\x92\x83\x99\x8d\xe3p\xef\xe4\xa1\
-\x0b\xe57j\xc8:\x06\t\x08\x87.H\xb2n\xa8\xc9\xa9\x12vQ\xfeG"\xe3\xacw\x00\
-\x10$M\xd3\x86_\xf0\xe5\xfc\xb4\xfa\x02\xcb\x13j\x10\xc5\xd7\x92D\x00\x00\
-\x00\x00IEND\xaeB`\x82' 
+\x00\x00\xb7IDAT8\x8d\xa5\x93\xdd\x11\xc3 \x0c\x83%`\xa3\xee\xd4\xaeA\xc6\
+\xe8N\xedF%\xea\x03\t\x81\xf0\x97\xbb\xf8%G\xce\xfe\x90eC\x1a\x8b;\xe1\xf2\
+\x83\xd6\xa0Q2\x8de\xf5oW\xa05H\xea\xd7\x93\x84$\x18\xeb\n\x88;\'.\xd5\x1d\
+\x80\x07\xe1\xa1\x1d\xa2\x1cbF\x92\x0f\x80\xe0\xd1 \xb7\x14\x8c \x00*\x15\
+\x97\x14\x8c\x8246\x1a\xf8\x98\'/\xdf\xd8Jn\xe65\xc0\xa7\x90_L"\x01\xde\x9d\
+\xda\xa7\x92\xfb\xc5w\xdf\t\x07\xc4\x05ym{\xd0\x1a\xe3\xb9xS\x81\x04\x18\x05\
+\xc9\x04\xc9a\x00Dc9\x9d\x82\xa4\xbc\xe8P\xb2\xb5P\xac\xf2\x0c\xd4\xf5\x00\
+\x88>\xac\xe17\x84\xe4\xb9G\x8b7\x9f\xf3\x1fsUl^\x7f\xe7y\x0f\x00\x00\x00\
+\x00IEND\xaeB`\x82' 
 
 def getClearOutputBitmap():
     return BitmapFromImage(getClearOutputImage())
@@ -2295,13 +2390,15 @@ def getContinueData():
     return \
 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
-\x00\x00\x9eIDAT8\x8d\xbd\x92\xd1\r\x83@\x0cC\xed\x8a\x11X\xac\x1b\xddF,\xd6\
-\x11\x90\xdc\x0f\x9a\x93s)\x14Z\xa9\x91\x10\n\x97\xbc\xd89\x80?\x84\x1a\xa4\
-\x83\xfc\x1c$\x1e)7\xdf<Y0\xaf\x0b\xe6\xf5\x1d\xa1\xb5\x13C\x03 !\xaa\xfd\
-\xed\n:mr\xc0\x1d\x8f\xc9\x9a!\t$\xe5\xd3I\xe2\xe5B$\x99\x00[\x01\xe8\xc5\
-\xd9G\xfaN`\xd8\x81I\xed\x8c\xb19\x94\x8d\xcbL\x00;t\xcf\x9fwPh\xdb\x0e\xe8\
-\xd3,\x17\x8b\xc7\x9d\xbb>\x8a \xec5\x94\tc\xc4\x12\xab\x94\xeb\x7fkWr\xc9B%\
-\xfc\xd2\xfcM<\x01\xf6tn\x12O3c\xe6\x00\x00\x00\x00IEND\xaeB`\x82' 
+\x00\x00\xcdIDAT8\x8d\xa5\x93\xd1\r\xc20\x0cD\xef\xec,\xc0b\x88\x8d`$\x06Cb\
+\x81\xc6\xc7GI\xeb\x94RZq?U"\xdby\xe7SIs\xfc#\xfbU\xa0\xa8\xba\xc6\xa0og\xee\
+!P\xd4y\x80\x04\xf3\xc2U\x82{\x9ct\x8f\x93\xb0\xa2\xdbm\xf5\xba\'h\xcdg=`\
+\xeeTT\xd1\xc6o& \t\x9a\x13\x00J\x9ev\xb1\'\xa3~\x14+\xbfN\x12\x92\x00@\xe6\
+\x85\xdd\x00\x000w\xe6\xe2\xde\xc7|\xdf\x08\xba\x1d(\xaa2n+\xca\xcd\x8d,\xea\
+\x98\xc4\x07\x01\x00D\x1dd^\xa8\xa8j\x9ew\xed`\xa9\x16\x99\xde\xa6G\x8b\xd3Y\
+\xe6\x85]\n\r\x7f\x99\xf5\x96Jnlz#\xab\xdb\xc1\x17\x19\xb0XV\xc2\xdf\xa3)\
+\x85<\xe4\x88\x85.F\x9a\xf3H3\xb0\xf3g\xda\xd2\x0b\xc5_|\x17\xe8\xf5R\xd6\
+\x00\x00\x00\x00IEND\xaeB`\x82' 
 
 def getContinueBitmap():
     return BitmapFromImage(getContinueImage())
@@ -2361,12 +2458,12 @@ def getStepInIcon():
 #----------------------------------------------------------------------
 def getStopData():
     return \
-"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
+'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
-\x00\x00FIDAT8\x8d\xed\x91\xc1\t\xc00\x0c\x03O!\x0b\xa9\xfb\xef\xa6\xfcB\xa1\
-N\t\xf4Wr\xa0\x8f\xb1\x0f\x81\xe1\x97\xe4-\xb6}_V%\xc8\xc2, \t\x92\xe6]\xfbZ\
-\xf7\x08\xa0W\xc3\xea5\xdb\rl_IX\xe5\xf0d\x00\xfa\x8d#\x7f\xc4\xf7'\xab\x00\
-\x00\x00\x00IEND\xaeB`\x82" 
+\x00\x00QIDAT8\x8d\xdd\x93A\n\xc00\x08\x04g\xb5\xff\x7fq\x13sn\xda&\x01\x0b\
+\xa5]\xf0"\xec(.J\xe6dd)\xf7\x13\x80\xadoD-12\xc8\\\xd3\r\xe2\xa6\x00j\xd9\
+\x0f\x03\xde\xbf\xc1\x0f\x00\xa7\x18\x01t\xd5\\\x05\xc8\\}T#\xe9\xfb\xbf\x90\
+\x064\xd8\\\x12\x1fQM\xf5\xd9\x00\x00\x00\x00IEND\xaeB`\x82' 
 
 def getStopBitmap():
     return BitmapFromImage(getStopImage())
index fa5d09de986f7679b584c52a0fc8a5504852463a..21001efc6b977229f5da4e9af54cea630439b10e 100644 (file)
@@ -105,14 +105,16 @@ class HtmlService(CodeEditor.CodeService):
 class HtmlCtrl(CodeEditor.CodeCtrl):
 
 
-    def __init__(self, parent, ID = -1, style = wx.NO_FULL_REPAINT_ON_RESIZE):
-        CodeEditor.CodeCtrl.__init__(self, parent, ID, style)
+    def __init__(self, parent, id=-1, style=wx.NO_FULL_REPAINT_ON_RESIZE):
+        CodeEditor.CodeCtrl.__init__(self, parent, id, style)
         self.SetLexer(wx.stc.STC_LEX_HTML)
         self.SetProperty("fold.html", "1")
 
+
     def GetMatchingBraces(self):
         return "<>[]{}()"
 
+
     def CanWordWrap(self):
         return True
 
index 7767890fcca56647db4dcf2c7080c98f855e1c81..1d68e31f87e7523fdc7fbffcce93793a1ed9ab98 100644 (file)
@@ -79,8 +79,6 @@ class IDEApplication(wx.lib.pydocview.DocApp):
         import PHPEditor
         import wx.lib.ogl as ogl
         import DebuggerService
-        import atexit
-        atexit.register(DebuggerService.DebuggerService.KillAllRunningProcesses)
         import AboutDialog
         import SVNService
                     
@@ -109,6 +107,19 @@ class IDEApplication(wx.lib.pydocview.DocApp):
         docManager = wx.lib.docview.DocManager(flags = self.GetDefaultDocManagerFlags())
         self.SetDocumentManager(docManager)
 
+        defaultTemplate = wx.lib.docview.DocTemplate(docManager,
+                _("Any"),
+                "*.*",
+                _("Any"),
+                _(".txt"),
+                _("Text Document"),
+                _("Text View"),
+                STCTextEditor.TextDocument,
+                STCTextEditor.TextView,
+                wx.lib.docview.TEMPLATE_INVISIBLE,
+                icon = STCTextEditor.getTextIcon())
+        docManager.AssociateTemplate(defaultTemplate)
+
         if not ACTIVEGRID_BASE_IDE:
             dplTemplate = DeploymentService.DeploymentTemplate(docManager,
                 _("Deployment"),
index 669123616983788be4be4112724df46cb7a7ae80..a2215723d726898ba32b29e0b290587570972a92 100644 (file)
@@ -39,15 +39,15 @@ class ImageView(wx.lib.docview.View):
 
         frame = wx.GetApp().CreateDocumentFrame(self, doc, flags)
         panel = wx.Panel(frame, -1)            
-        bitmap = wx.Image(doc.GetFilename()).ConvertToBitmap()
-        self._ctrl = wx.StaticBitmap(panel, -1, bitmap, (0,0), (bitmap.GetWidth(), bitmap.GetHeight()))
+        self._bitmap = wx.Image(doc.GetFilename()).ConvertToBitmap()
+        self._ctrl = wx.StaticBitmap(panel, -1, self._bitmap, (0,0), (self._bitmap.GetWidth(), self._bitmap.GetHeight()))
         wx.EVT_LEFT_DOWN(self._ctrl, self.OnFocus)
         wx.EVT_LEFT_DCLICK(self._ctrl, self.OnFocus)
         wx.EVT_RIGHT_DOWN(self._ctrl, self.OnFocus)
         wx.EVT_RIGHT_DCLICK(self._ctrl, self.OnFocus)
         wx.EVT_MIDDLE_DOWN(self._ctrl, self.OnFocus)
         wx.EVT_MIDDLE_DCLICK(self._ctrl, self.OnFocus)
-        panel.SetClientSize(bitmap.GetSize())
+        panel.SetClientSize(self._bitmap.GetSize())
         frame.SetClientSize(panel.GetSize())
         self.Activate()
         return True
@@ -69,6 +69,13 @@ class ImageView(wx.lib.docview.View):
         return True
 
 
+    def OnDraw(self, dc):
+        """ for Print Preview and Print """
+        dc.BeginDrawing()
+        dc.DrawBitmap(self._bitmap, 10, 10, True)
+        dc.EndDrawing()
+        
+
 #----------------------------------------------------------------------------
 # Icon Bitmaps - generated by encode_bitmaps.py
 #----------------------------------------------------------------------------
index fba7b6c02938944c31ce23b9e22c04e9c9ed7e93..bd8fa0602980fe5dada2ab46532c422ebc3f290b 100644 (file)
@@ -151,8 +151,8 @@ class PHPService(CodeEditor.CodeService):
 class PHPCtrl(CodeEditor.CodeCtrl):
 
 
-    def __init__(self, parent, ID = -1, style = wx.NO_FULL_REPAINT_ON_RESIZE):
-        CodeEditor.CodeCtrl.__init__(self, parent, ID, style)
+    def __init__(self, parent, id=-1, style=wx.NO_FULL_REPAINT_ON_RESIZE):
+        CodeEditor.CodeCtrl.__init__(self, parent, id, style)
         self.SetLexer(wx.stc.STC_LEX_PHP)
         self.SetStyleBits(7)
         self.SetKeyWords(4, string.join(PHPKEYWORDS))
index 8c31a322dd440f1f9cc71ed568fe4276c6003268..aaab62a206e470263eefce05fe0aa29c9df2869b 100644 (file)
@@ -62,8 +62,8 @@ class PerlService(CodeEditor.CodeService):
 class PerlCtrl(CodeEditor.CodeCtrl):
 
 
-    def __init__(self, parent, ID = -1, style = wx.NO_FULL_REPAINT_ON_RESIZE):
-        CodeEditor.CodeCtrl.__init__(self, parent, ID, style)
+    def __init__(self, parent, id=-1, style=wx.NO_FULL_REPAINT_ON_RESIZE):
+        CodeEditor.CodeCtrl.__init__(self, parent, id, style)
         self.SetLexer(wx.stc.STC_LEX_PERL)
         self.SetKeyWords(0, string.join(PERLKEYWORDS))
 
index 56331050ec72ea0d4e9bb4db22bff32edb57a2f7..4d88f9defc31c0e065989f4db4064693bb0bb564 100644 (file)
@@ -20,7 +20,7 @@ from wxPython.lib.rcsizer import RowColSizer
 import time
 import Service
 import sys
-import activegrid.util.xmlmarshaller
+import activegrid.util.objutils
 import UICommon
 import Wizard
 import SVNService
@@ -47,18 +47,12 @@ HALF_SPACE = 5
 #----------------------------------------------------------------------------
 # XML Marshalling Methods
 #----------------------------------------------------------------------------
-LOCAL_TYPE_MAPPING = { "projectmodel"   : "activegrid.tool.ProjectEditor.ProjectModel", }
-
 
 def load(fileObject):
-    xml = fileObject.read()
-    projectModel = activegrid.util.xmlmarshaller.unmarshal(xml, knownTypes=LOCAL_TYPE_MAPPING)
-    return projectModel
-
+    return activegrid.util.objutils.defaultLoad(fileObject)
 
 def save(fileObject, projectModel):
-    xml = activegrid.util.xmlmarshaller.marshal(projectModel, prettyPrint=True, knownTypes=LOCAL_TYPE_MAPPING)
-    fileObject.write(xml)
+    activegrid.util.objutils.defaultSave(fileObject, projectModel, prettyPrint=True)
 
 
 #----------------------------------------------------------------------------
@@ -72,6 +66,9 @@ class ProjectModel:
 
     def __init__(self):
         self._files = []
+        
+    def initialize(self):
+        pass
      
    
 class ProjectDocument(wx.lib.docview.Document):
@@ -143,8 +140,6 @@ class ProjectDocument(wx.lib.docview.Document):
             if path.startswith("."):  # relative to project file
                 curPath = os.path.dirname(self.GetFilename())
                 path = os.path.normpath(os.path.join(curPath, path))
-            elif not ACTIVEGRID_BASE_IDE:
-                print "Warning: absolute path '%s' found in project file, this may affect deployment" % path
             newFilePaths.append(path)
         return newFilePaths
 
@@ -229,7 +224,7 @@ class ProjectDocument(wx.lib.docview.Document):
             if isProject:
                 documents = self.GetDocumentManager().GetDocuments()
                 for document in documents:
-                    if document.GetFilename() == oldFile:  # If the renamed document is open, update it
+                    if os.path.normcase(document.GetFilename()) == os.path.normcase(oldFile):  # If the renamed document is open, update it
                         document.SetFilename(newFile)
                         document.SetTitle(wx.lib.docview.FileNameFromPath(newFile))
                         document.UpdateAllViews(hint = ("rename", document, newFile))
@@ -238,7 +233,7 @@ class ProjectDocument(wx.lib.docview.Document):
                 self.AddFile(newFile)
                 documents = self.GetDocumentManager().GetDocuments()
                 for document in documents:
-                    if document.GetFilename() == oldFile:  # If the renamed document is open, update it
+                    if os.path.normcase(document.GetFilename()) == os.path.normcase(oldFile):  # If the renamed document is open, update it
                         document.SetFilename(newFile, notifyViews = True)
                         document.UpdateAllViews(hint = ("rename", document, newFile))
             return True
@@ -293,7 +288,7 @@ class NewProjectWizard(Wizard.BaseWizard):
                 # What if the document is already open and we're overwriting it?
                 documents = docManager.GetDocuments()
                 for document in documents:
-                    if document.GetFilename() == self._fullProjectPath:  # If the renamed document is open, update it
+                    if os.path.normcase(document.GetFilename()) == os.path.normcase(self._fullProjectPath):  # If the renamed document is open, update it
                         document.DeleteAllViews()
                         break
                 os.remove(self._fullProjectPath)
@@ -848,10 +843,12 @@ class ProjectView(wx.lib.docview.View):
         or id == ProjectService.RENAME_ID
         or id == ProjectService.ADD_FILES_TO_PROJECT_ID
         or id == ProjectService.ADD_ALL_FILES_TO_PROJECT_ID
-        or id == wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID
-        or id == ProjectService.DELETE_FILE_ID):
+        or id == wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID):
             event.Enable(self._HasSelection())
             return True
+        elif id == ProjectService.DELETE_FILE_ID:
+            event.Enable(len(self.GetSelectedFiles()) > 0)
+            return True
         elif id == ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID:
             event.Enable(False)
             return True
@@ -866,6 +863,10 @@ class ProjectView(wx.lib.docview.View):
         or id == ProjectService.OPEN_SELECTION_ID):
             event.Enable(self._HasFilesSelected())
             return True
+        elif (id == wx.ID_PREVIEW
+        or id == wx.ID_PRINT):
+            event.Enable(False)
+            return True            
         else:
             return False
 
@@ -924,6 +925,16 @@ class ProjectView(wx.lib.docview.View):
         return filenames
 
 
+    def GetSelectedProjects(self):
+        filenames = []
+        for item in self._treeCtrl.GetSelections():
+            if self._IsItemProject(item):
+                filename = self._treeCtrl.GetLongFilename(item)
+                if filename and filename not in filenames:
+                    filenames.append(filename)
+        return filenames
+
+
     def AddProjectToView(self, document):
         rootItem = self._treeCtrl.GetRootItem()
         projectItem = self._treeCtrl.AppendItem(rootItem, self._MakeProjectName(document))
@@ -981,8 +992,7 @@ class ProjectView(wx.lib.docview.View):
                         allfilter = allfilter + _(';')
                     descr = descr + temp.GetDescription() + _(" (") + temp.GetFileFilter() + _(") |") + temp.GetFileFilter()  # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
                     allfilter = allfilter + temp.GetFileFilter()
-            descr = _("All") + _(" (") + allfilter + _(") |") + allfilter + _('|') + descr  # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
-            descr = descr + _("|") + _("Any (*.*) | *.*")
+            descr = _("All (%s)|%s|%s|Any (*.*) | *.*") %  (allfilter, allfilter, descr)  # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
         else:
             descr = _("*.*")
             
@@ -1203,8 +1213,10 @@ class ProjectView(wx.lib.docview.View):
             itemIDs = [wx.ID_CLOSE, wx.ID_SAVE, wx.ID_SAVEAS, None]
         menuBar = self._GetParentFrame().GetMenuBar()
         itemIDs = itemIDs + [ProjectService.ADD_FILES_TO_PROJECT_ID, ProjectService.ADD_ALL_FILES_TO_PROJECT_ID, ProjectService.REMOVE_FROM_PROJECT]
+        svnIDs = [SVNService.SVNService.SVN_UPDATE_ID, SVNService.SVNService.SVN_CHECKIN_ID, SVNService.SVNService.SVN_REVERT_ID]
         if SVN_INSTALLED:
             itemIDs = itemIDs + [None, SVNService.SVNService.SVN_UPDATE_ID, SVNService.SVNService.SVN_CHECKIN_ID, SVNService.SVNService.SVN_REVERT_ID]
+        globalIDs = [wx.ID_UNDO, wx.ID_REDO, wx.ID_CLOSE, wx.ID_SAVE, wx.ID_SAVEAS]
         itemIDs = itemIDs + [None, wx.ID_UNDO, wx.ID_REDO, None, wx.ID_CUT, wx.ID_COPY, wx.ID_PASTE, wx.ID_CLEAR, None, wx.ID_SELECTALL, ProjectService.RENAME_ID, ProjectService.DELETE_FILE_ID, None, wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID]
         for itemID in itemIDs:
             if not itemID:
@@ -1218,8 +1230,16 @@ class ProjectView(wx.lib.docview.View):
                     wx.EVT_MENU(self._GetParentFrame(), ProjectService.REMOVE_FROM_PROJECT, self.OnClear)
                     wx.EVT_UPDATE_UI(self._GetParentFrame(), ProjectService.REMOVE_FROM_PROJECT, self._GetParentFrame().ProcessUpdateUIEvent)
                 else:
+                    svnService = wx.GetApp().GetService(SVNService.SVNService)
                     item = menuBar.FindItemById(itemID)
                     if item:
+                        if itemID in svnIDs:
+                            if SVN_INSTALLED and svnService:
+                                wx.EVT_MENU(self._GetParentFrame(), itemID, svnService.ProcessEvent)
+                        elif itemID in globalIDs:
+                            pass
+                        else:
+                            wx.EVT_MENU(self._treeCtrl, itemID, self.ProcessEvent)
                         menu.Append(itemID, item.GetLabel())
         self._treeCtrl.PopupMenu(menu, wx.Point(event.GetX(), event.GetY()))
         menu.Destroy()
@@ -1824,9 +1844,43 @@ class ProjectService(Service.Service):
 
     def ProcessEventBeforeWindows(self, event):
         id = event.GetId()
+        
         if id == wx.ID_CLOSE_ALL:
             self.OnFileCloseAll(event)
             return True
+            
+        elif id == wx.ID_CLOSE:
+            document = self.GetDocumentManager().GetCurrentDocument()
+            if document and document.GetDocumentTemplate().GetDocumentType() == ProjectDocument:
+                self.OnProjectClose(event)
+                return True
+            else:
+                return False
+        return False
+
+
+    def ProcessUpdateUIEventBeforeWindows(self, event):
+        id = event.GetId()
+        
+        if id == wx.ID_CLOSE_ALL:
+            for document in self.GetDocumentManager().GetDocuments():
+                if document.GetDocumentTemplate().GetDocumentType() != ProjectDocument:
+                    event.Enable(True)
+                    return True
+                    
+            event.Enable(False)
+            return True
+            
+        elif id == wx.ID_CLOSE:
+            document = self.GetDocumentManager().GetCurrentDocument()
+            if document and document.GetDocumentTemplate().GetDocumentType() == ProjectDocument:
+                projectFilenames = self.GetView().GetSelectedProjects()
+                if projectFilenames and len(projectFilenames):
+                    event.Enable(True)
+                else:
+                    event.Enable(False)
+                return True
+                
         return False
 
 
@@ -2055,6 +2109,14 @@ class ProjectService(Service.Service):
         self.GetView().Activate(True)  # after add, should put focus on project editor
 
 
+    def OnProjectClose(self, event):
+        projectFilenames = self.GetView().GetSelectedProjects()
+        for filename in projectFilenames:
+            doc = self.FindProjectByFile(filename)
+            if doc:
+                self.GetDocumentManager().CloseDocument(doc, False)
+
+
     def OnFileCloseAll(self, event):
         for document in self.GetDocumentManager().GetDocuments()[:]:  # Cloning list to make sure we go through all docs even as they are deleted
             if document.GetDocumentTemplate().GetDocumentType() != ProjectDocument:
index 876f42b6bf1fad05fdfb1629f0ab1a47c0e0196a..6496f7f58a66499b9e7a78d1bcd02a76244beeba 100644 (file)
@@ -49,6 +49,11 @@ class PythonDocument(CodeEditor.CodeDocument):
 class PythonView(CodeEditor.CodeView):
 
 
+    def GetCtrlClass(self):
+        """ Used in split window to instantiate new instances """
+        return PythonCtrl
+
+
     def ProcessUpdateUIEvent(self, event):
         if not self.GetCtrl():
             return False
@@ -62,11 +67,6 @@ class PythonView(CodeEditor.CodeView):
         return CodeEditor.CodeView.ProcessUpdateUIEvent(self, event)
 
 
-    def GetCtrlClass(self):
-        """ Used in split window to instantiate new instances """
-        return PythonCtrl
-
-
     def OnActivateView(self, activate, activeView, deactiveView):
         STCTextEditor.TextView.OnActivateView(self, activate, activeView, deactiveView)
         if activate:
@@ -345,8 +345,8 @@ class PythonService(CodeEditor.CodeService):
 class PythonCtrl(CodeEditor.CodeCtrl):
 
 
-    def __init__(self, parent, ID = -1, style = wx.NO_FULL_REPAINT_ON_RESIZE):
-        CodeEditor.CodeCtrl.__init__(self, parent, ID, style)
+    def __init__(self, parent, id=-1, style=wx.NO_FULL_REPAINT_ON_RESIZE):
+        CodeEditor.CodeCtrl.__init__(self, parent, id, style)
         self.SetProperty("tab.timmy.whinge.level", "1")
         self.SetProperty("fold.comment.python", "1")
         self.SetProperty("fold.quotes.python", "1")
@@ -516,6 +516,7 @@ class PythonCtrl(CodeEditor.CodeCtrl):
                 if doExtraIndent or len(textNoTrailingSpaces) and textNoTrailingSpaces[-1] == ':':
                     spaces = spaces + ' ' * self.GetIndent()
             self.AddText('\n' + spaces)
+        self.EnsureCaretVisible()
 
 
     # Callback for tokenizer in self.DoIndent
index 113721029a12283b9d11ddb549ef67ee8ccf0db5..549c708c23c250636920f5e51ebadd408336f2dd 100644 (file)
@@ -47,27 +47,16 @@ TEXT_STATUS_BAR_ID = wx.NewId()
 class TextDocument(wx.lib.docview.Document):
 
 
-    def OnSaveDocument(self, filename):
+    def SaveObject(self, fileObject):
         view = self.GetFirstView()
-        docFile = file(self._documentFile, "w")
-        docFile.write(view.GetValue())
-        docFile.close()
-        self.Modify(False)
-        self.SetDocumentModificationDate()
-        self.SetDocumentSaved(True)
+        fileObject.write(view.GetValue())
         return True
+        
 
-
-    def OnOpenDocument(self, filename):
+    def LoadObject(self, fileObject):
         view = self.GetFirstView()
-        docFile = file(self._documentFile, 'r')
-        data = docFile.read()
+        data = fileObject.read()
         view.SetValue(data)
-        self.SetFilename(filename, True)
-        self.Modify(False)
-        self.SetDocumentModificationDate()
-        self.UpdateAllViews()
-        self._savedYet = True
         return True
 
 
@@ -90,12 +79,6 @@ class TextDocument(wx.lib.docview.Document):
         # Don't create a command processor, it has its own
         pass
 
-# Use this to override MultiClient.Select to prevent yellow background.
-def MultiClientSelectBGNotYellow(a):
-        a.GetParent().multiView.UnSelect()
-        a.selected = True
-        #a.SetBackgroundColour(wx.Colour(255,255,0)) # Yellow
-        a.Refresh()
 
 class TextView(wx.lib.docview.View):
     MARKER_NUM = 0
@@ -110,39 +93,32 @@ class TextView(wx.lib.docview.View):
         self._textEditor = None
         self._markerCount = 0
         self._commandProcessor = None
-        self._multiSash = None
+        self._dynSash = None
 
 
     def GetCtrlClass(self):
+        """ Used in split window to instantiate new instances """
         return TextCtrl
-
+        
 
     def GetCtrl(self):
-        # look for active one first
-        self._textEditor = self._GetActiveCtrl(self._multiSash)
-        if self._textEditor == None:  # it is possible none are active
-            # look for any existing one
-            self._textEditor = self._FindCtrl(self._multiSash)
         return self._textEditor
-        
 
-##    def GetCtrls(self, parent = None):
-##        """ Walk through the MultiSash windows and find all Ctrls """
-##        controls = []
-##        if isinstance(parent, self.GetCtrlClass()):
-##            return [parent]
-##        if hasattr(parent, "GetChildren"):
-##            for child in parent.GetChildren():
-##                controls = controls + self.GetCtrls(child)
-##        return controls
+
+    def SetCtrl(self, ctrl):
+        self._textEditor = ctrl
+                
+
+    def OnCreatePrintout(self):
+        """ for Print Preview and Print """
+        return TextPrintout(self, self.GetDocument().GetPrintableName())
 
             
     def OnCreate(self, doc, flags):
         frame = wx.GetApp().CreateDocumentFrame(self, doc, flags, style = wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
-        wx.lib.multisash.MultiClient.Select = MultiClientSelectBGNotYellow
-        self._multiSash = wx.lib.multisash.MultiSash(frame, -1)
-        self._multiSash.SetDefaultChildClass(self.GetCtrlClass()) # wxBug:  MultiSash instantiates the first TextCtrl with this call
-        self._textEditor = self.GetCtrl()  # wxBug: grab the TextCtrl from the MultiSash datastructure
+        self._dynSash = wx.gizmos.DynamicSashWindow(frame, -1, style=wx.CLIP_CHILDREN)
+        self._dynSash._view = self
+        self._textEditor = self.GetCtrlClass()(self._dynSash, -1, style=wx.NO_BORDER)
         self._CreateSizer(frame)
         self.Activate()
         frame.Show(True)
@@ -150,33 +126,9 @@ class TextView(wx.lib.docview.View):
         return True
 
 
-    def _GetActiveCtrl(self, parent):
-        """ Walk through the MultiSash windows and find the active Control """
-        if isinstance(parent, wx.lib.multisash.MultiClient) and parent.selected:
-            return parent.child
-        if hasattr(parent, "GetChildren"):
-            for child in parent.GetChildren():
-                found = self._GetActiveCtrl(child)
-                if found:
-                    return found
-        return None
-
-
-    def _FindCtrl(self, parent):
-        """ Walk through the MultiSash windows and find the first TextCtrl """
-        if isinstance(parent, self.GetCtrlClass()):
-            return parent
-        if hasattr(parent, "GetChildren"):
-            for child in parent.GetChildren():
-                found = self._FindCtrl(child)
-                if found:
-                    return found
-        return None
-
-
     def _CreateSizer(self, frame):
         sizer = wx.BoxSizer(wx.HORIZONTAL)
-        sizer.Add(self._multiSash, 1, wx.EXPAND)
+        sizer.Add(self._dynSash, 1, wx.EXPAND)
         frame.SetSizer(sizer)
         frame.SetAutoLayout(True)
 
@@ -300,12 +252,12 @@ class TextView(wx.lib.docview.View):
 
         id = event.GetId()
         if id == wx.ID_UNDO:
-             event.Enable(self.GetCtrl().CanUndo())
-             event.SetText(_("Undo") + '\t' + _('Ctrl+Z'))
-             return True
+            event.Enable(self.GetCtrl().CanUndo())
+            event.SetText(_("&Undo\tCtrl+Z"))  # replace menu string
+            return True
         elif id == wx.ID_REDO:
             event.Enable(self.GetCtrl().CanRedo())
-            event.SetText(_("Redo") + '\t' + _('Ctrl+Y'))
+            event.SetText(_("&Redo\tCtrl+Y"))  # replace menu string
             return True
         elif (id == wx.ID_CUT
         or id == wx.ID_COPY
@@ -586,6 +538,7 @@ class TextView(wx.lib.docview.View):
     def GetLine(self, lineNum):
         return self.GetCtrl().GetLine(lineNum-1)  # line numbering for editor is 0 based, we are 1 based.
 
+
     def MarkerDefine(self):
         """ This must be called after the texteditor is instantiated """
         self.GetCtrl().MarkerDefine(TextView.MARKER_NUM, wx.stc.STC_MARK_CIRCLE, wx.BLACK, wx.BLUE)
@@ -601,6 +554,7 @@ class TextView(wx.lib.docview.View):
             self.GetCtrl().MarkerAdd(lineNum, marker_index)
             self._markerCount += 1
 
+
     def MarkerAdd(self, lineNum = -1, marker_index=MARKER_NUM, mask=MARKER_MASK):
         if lineNum == -1:
             lineNum = self.GetCtrl().GetCurrentLine()
@@ -959,10 +913,14 @@ class TextOptionsPanel(wx.Panel):
 
 class TextCtrl(wx.stc.StyledTextCtrl):
 
-    def __init__(self, parent, ID = -1, style = wx.NO_FULL_REPAINT_ON_RESIZE):
-        if ID == -1:
-            ID = wx.NewId()
-        wx.stc.StyledTextCtrl.__init__(self, parent, ID, style = style)
+    def __init__(self, parent, id=-1, style=wx.NO_FULL_REPAINT_ON_RESIZE):
+        wx.stc.StyledTextCtrl.__init__(self, parent, id, style=style)
+
+        if isinstance(parent, wx.gizmos.DynamicSashWindow):
+            self._dynSash = parent
+            self.SetupDSScrollBars()
+            self.Bind(wx.gizmos.EVT_DYNAMIC_SASH_SPLIT, self.OnDSSplit)
+            self.Bind(wx.gizmos.EVT_DYNAMIC_SASH_UNIFY, self.OnDSUnify)
 
         self._font = None
         self._fontColor = None
@@ -975,6 +933,8 @@ class TextCtrl(wx.stc.StyledTextCtrl):
         self.CmdKeyAssign(wx.stc.STC_KEY_NEXT, wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMOUT)
         self.Bind(wx.stc.EVT_STC_ZOOM, self.OnUpdateLineNumberMarginWidth)  # auto update line num width on zoom
         wx.EVT_KEY_DOWN(self, self.OnKeyPressed)
+        wx.EVT_KILL_FOCUS(self, self.OnKillFocus)
+        wx.EVT_SET_FOCUS(self, self.OnFocus)
         self.SetMargins(0,0)
 
         self.SetUseTabs(0)
@@ -998,21 +958,23 @@ class TextCtrl(wx.stc.StyledTextCtrl):
         self.SetFontColor(color)
         self.MarkerDefineDefault()
 
-        # for multisash initialization
-        if isinstance(parent, wx.lib.multisash.MultiClient):
-            while parent.GetParent():
-                parent = parent.GetParent()
-                if hasattr(parent, "GetView"):
-                    break
-            if hasattr(parent, "GetView"):
-                textEditor = parent.GetView()._textEditor
-                if textEditor:
-                    doc = textEditor.GetDocPointer()
-                    if doc:
-                        self.SetDocPointer(doc)
+
+    def OnFocus(self, event):
+        self.SetSelBackground(1, "BLUE")
+        self.SetSelForeground(1, "WHITE")
+        if hasattr(self, "_dynSash"):
+            self._dynSash._view.SetCtrl(self)
+        event.Skip()
 
 
+    def OnKillFocus(self, event):
+        self.SetSelBackground(0, "BLUE")
+        self.SetSelForeground(0, "WHITE")
+        self.SetSelBackground(1, "#C0C0C0")
+        # Don't set foreground color, use syntax highlighted default colors.
+        event.Skip()
         
+
     def SetViewDefaults(self, configPrefix = "Text", hasWordWrap = True, hasTabs = False):
         config = wx.ConfigBase_Get()
         self.SetViewWhiteSpace(config.ReadInt(configPrefix + "EditorViewWhitespace", False))
@@ -1031,7 +993,6 @@ class TextCtrl(wx.stc.StyledTextCtrl):
             self.SetIndent(4)
             self.SetTabWidth(4)
 
-
         
     def GetDefaultFont(self):
         """ Subclasses should override this """
@@ -1064,6 +1025,7 @@ class TextCtrl(wx.stc.StyledTextCtrl):
     def GetFont(self):
         return self._font
         
+
     def SetFont(self, font):
         self._font = font
         self.StyleSetFont(wx.stc.STC_STYLE_DEFAULT, self._font)
@@ -1202,6 +1164,160 @@ class TextCtrl(wx.stc.StyledTextCtrl):
         else:
             self.SetWrapMode(wx.stc.STC_WRAP_NONE)
 
+
+    #----------------------------------------------------------------------------
+    # DynamicSashWindow methods
+    #----------------------------------------------------------------------------
+
+    def SetupDSScrollBars(self):
+        # hook the scrollbars provided by the wxDynamicSashWindow
+        # to this view
+        v_bar = self._dynSash.GetVScrollBar(self)
+        h_bar = self._dynSash.GetHScrollBar(self)
+        v_bar.Bind(wx.EVT_SCROLL, self.OnDSSBScroll)
+        h_bar.Bind(wx.EVT_SCROLL, self.OnDSSBScroll)
+        v_bar.Bind(wx.EVT_SET_FOCUS, self.OnDSSBFocus)
+        h_bar.Bind(wx.EVT_SET_FOCUS, self.OnDSSBFocus)
+
+        # And set the wxStyledText to use these scrollbars instead
+        # of its built-in ones.
+        self.SetVScrollBar(v_bar)
+        self.SetHScrollBar(h_bar)
+
+
+    def OnDSSplit(self, evt):
+        newCtrl = self._dynSash._view.GetCtrlClass()(self._dynSash, -1, style=wx.NO_BORDER)
+        newCtrl.SetDocPointer(self.GetDocPointer())     # use the same document
+        self.SetupDSScrollBars()
+        if self == self._dynSash._view.GetCtrl():  # originally had focus
+            wx.CallAfter(self.SetFocus)  # do this to set colors correctly.  wxBug:  for some reason, if we don't do a CallAfter, it immediately calls OnKillFocus right after our SetFocus.
+
+
+    def OnDSUnify(self, evt):
+        self.SetupDSScrollBars()
+        self.SetFocus()  # do this to set colors correctly
+
+
+    def OnDSSBScroll(self, evt):
+        # redirect the scroll events from the _dynSash's scrollbars to the STC
+        self.GetEventHandler().ProcessEvent(evt)
+
+
+    def OnDSSBFocus(self, evt):
+        # when the scrollbar gets the focus move it back to the STC
+        self.SetFocus()
+
+
+    def DSProcessEvent(self, event):
+        # wxHack: Needed for customized right mouse click menu items.        
+        if hasattr(self, "_dynSash"):
+            if event.GetId() == wx.ID_SELECTALL:
+                # force focus so that select all occurs in the window user right clicked on.
+                self.SetFocus()
+
+            return self._dynSash._view.ProcessEvent(event)
+        return False
+
+
+    def DSProcessUpdateUIEvent(self, event):
+        # wxHack: Needed for customized right mouse click menu items.        
+        if hasattr(self, "_dynSash"):
+            id = event.GetId()
+            if (id == wx.ID_SELECTALL  # allow select all even in non-active window, then force focus to it, see above ProcessEvent
+            or id == wx.ID_UNDO
+            or id == wx.ID_REDO):
+                pass  # allow these actions even in non-active window
+            else:  # disallow events in non-active windows.  Cut/Copy/Paste/Delete is too confusing user experience.
+                if self._dynSash._view.GetCtrl() != self:
+                     event.Enable(False)
+                     return True
+
+            return self._dynSash._view.ProcessUpdateUIEvent(event)
+        return False
+
+
+class TextPrintout(wx.lib.docview.DocPrintout):
+    """ for Print Preview and Print """
+    
+
+    def OnPreparePrinting(self):
+        """ initialization """
+        dc = self.GetDC()
+
+        ppiScreenX, ppiScreenY = self.GetPPIScreen()
+        ppiPrinterX, ppiPrinterY = self.GetPPIPrinter()
+        scaleX = float(ppiPrinterX)/ppiScreenX
+        scaleY = float(ppiPrinterY)/ppiScreenY
+
+        pageWidth, pageHeight = self.GetPageSizePixels()
+        self._scaleFactorX = scaleX/pageWidth
+        self._scaleFactorY = scaleY/pageHeight
+
+        w, h = dc.GetSize()
+        overallScaleX = self._scaleFactorX * w
+        overallScaleY = self._scaleFactorY * h
+        
+        txtCtrl = self._printoutView.GetCtrl()
+        font, color = txtCtrl.GetFontAndColorFromConfig()
+
+        self._margin = 40
+        self._fontHeight = font.GetPointSize() + 1
+        self._pageLines = int((h/overallScaleY - (2 * self._margin))/self._fontHeight)
+        self._maxLines = txtCtrl.GetLineCount()
+        self._numPages, remainder = divmod(self._maxLines, self._pageLines)
+        if remainder != 0:
+            self._numPages += 1
+
+        spaces = 1
+        lineNum = self._maxLines
+        while lineNum >= 10:
+            lineNum = lineNum/10
+            spaces += 1
+        self._printFormat = "%%0%sd: %%s" % spaces
+
+
+    def OnPrintPage(self, page):
+        """ Prints the given page of the view """
+        dc = self.GetDC()
+        
+        txtCtrl = self._printoutView.GetCtrl()
+        font, color = txtCtrl.GetFontAndColorFromConfig()
+        dc.SetFont(font)
+        
+        w, h = dc.GetSize()
+        dc.SetUserScale(self._scaleFactorX * w, self._scaleFactorY * h)
+        
+        dc.BeginDrawing()
+        
+        dc.DrawText("%s - page %s" % (self.GetTitle(), page), self._margin, self._margin/2)
+
+        startY = self._margin
+        startLine = (page - 1) * self._pageLines
+        endLine = min((startLine + self._pageLines), self._maxLines)
+        for i in range(startLine, endLine):
+            text = txtCtrl.GetLine(i).rstrip()
+            startY += self._fontHeight
+            if txtCtrl.GetViewLineNumbers():
+                dc.DrawText(self._printFormat % (i+1, text), self._margin, startY)
+            else:
+                dc.DrawText(text, self._margin, startY)
+                
+        dc.EndDrawing()
+
+        return True
+
+
+    def HasPage(self, pageNum):
+        return pageNum <= self._numPages
+
+
+    def GetPageInfo(self):
+        minPage = 1
+        maxPage = self._numPages
+        selPageFrom = 1
+        selPageTo = self._numPages
+        return (minPage, maxPage, selPageFrom, selPageTo)
+
         
 #----------------------------------------------------------------------------
 # Icon Bitmaps - generated by encode_bitmaps.py
index 97206c5d9f4735fb138b540486bb110f9e669dc8..9d35ad0ce9218765c7274b87863ec3d0550f9e25 100644 (file)
@@ -11,6 +11,7 @@
 #----------------------------------------------------------------------------
 
 import wx
+import os
 import os.path
 import ProjectEditor
 import MessageService
@@ -31,7 +32,7 @@ _ = wx.GetTranslation
 # Constants
 #----------------------------------------------------------------------------
 SVN_CONFIG_DIR = "SVNConfigDir"
-SVN_REPOSITORY_URL = "SVNRepositoryURL"
+SVN_REPOSITORY_URL = "SVNRepositoryURLs"
 
 SPACE = 10
 HALF_SPACE = 5
@@ -42,13 +43,15 @@ HALF_SPACE = 5
 #----------------------------------------------------------------------------
 
 class SVNService(wx.lib.pydocview.DocService):
+    SVN_UPDATE_ALL_ID = wx.NewId()
     SVN_UPDATE_ID = wx.NewId()
     SVN_CHECKIN_ID = wx.NewId()
+    SVN_CHECKIN_ALL_ID = wx.NewId()
     SVN_CHECKOUT_ID = wx.NewId()
     SVN_REVERT_ID = wx.NewId()
     SVN_ADD_ID = wx.NewId()
     SVN_DELETE_ID = wx.NewId()
-    SVN_COMMAND_LIST = [SVN_UPDATE_ID, SVN_CHECKIN_ID, SVN_CHECKOUT_ID, SVN_REVERT_ID, SVN_ADD_ID, SVN_DELETE_ID]
+    SVN_COMMAND_LIST = [SVN_UPDATE_ALL_ID, SVN_CHECKIN_ALL_ID, SVN_UPDATE_ID, SVN_CHECKIN_ID, SVN_CHECKOUT_ID, SVN_REVERT_ID, SVN_ADD_ID, SVN_DELETE_ID]
 
 
     def __init__(self):
@@ -57,13 +60,14 @@ class SVNService(wx.lib.pydocview.DocService):
         global SVN_INSTALLED
         if SVN_INSTALLED:
             config = wx.ConfigBase_Get()
+            
             configDir = config.Read(SVN_CONFIG_DIR, "")
-
             self._client = pysvn.Client(configDir)
             try:
                 self._defaultURL = self._client.info('.').url
             except:
                 pass
+                
             self._client.callback_cancel = self.IfCancel
             self._client.callback_notify = self.UpdateStatus
             self._client.callback_get_log_message = self.GetLogMessage
@@ -274,6 +278,12 @@ class SVNService(wx.lib.pydocview.DocService):
 
         menu.AppendSeparator()
 
+        wx.EVT_MENU(frame, SVNService.SVN_UPDATE_ALL_ID, self.ProcessEvent)
+        wx.EVT_UPDATE_UI(frame, SVNService.SVN_UPDATE_ALL_ID, self.ProcessUpdateUIEvent)
+        menu.Append(SVNService.SVN_UPDATE_ALL_ID, _("SVN Update All in Project"), _("Update all files in a project from Subversion"))
+        wx.EVT_MENU(frame, SVNService.SVN_CHECKIN_ALL_ID, self.ProcessEvent)
+        wx.EVT_UPDATE_UI(frame, SVNService.SVN_CHECKIN_ALL_ID, self.ProcessUpdateUIEvent)
+        menu.Append(SVNService.SVN_CHECKIN_ALL_ID, _("SVN Commit All in Project..."), _("Commit all files changes in a project to Subversion"))
         wx.EVT_MENU(frame, SVNService.SVN_UPDATE_ID, self.ProcessEvent)
         wx.EVT_UPDATE_UI(frame, SVNService.SVN_UPDATE_ID, self.ProcessUpdateUIEvent)
         menu.Append(SVNService.SVN_UPDATE_ID, _("SVN Update"), _("Update file from Subversion"))
@@ -309,9 +319,10 @@ class SVNService(wx.lib.pydocview.DocService):
 
 
         if id == SVNService.SVN_UPDATE_ID:
-            filenames = self.GetCurrentDocuments()
-
             wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
+            
+            filenames = self.GetCurrentDocuments()[:]
+            filenames.sort(self.BasenameCaseInsensitiveCompare)
 
             messageService = wx.GetApp().GetService(MessageService.MessageService)
             messageService.ShowWindow()
@@ -355,9 +366,174 @@ class SVNService(wx.lib.pydocview.DocService):
             wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
 
             return True
+            
+        elif id == SVNService.SVN_UPDATE_ALL_ID:
+            wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
+
+            messageService = wx.GetApp().GetService(MessageService.MessageService)
+            messageService.ShowWindow()
+
+            view = messageService.GetView()
+            view.ClearLines()
+            view.AddLines(_("SVN Update:\n"))
+            
+            projects = self.GetCurrentProjects()
+            for project in projects:
+                openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
+                for doc in openDocs:
+                    if doc.GetFilename() == project:
+                        filenames = doc.GetFiles()[:]  # make a copy and sort it.
+                        filenames.sort(self.BasenameCaseInsensitiveCompare)
+
+                        for filename in filenames:
+                            view.AddLines("%s\n" % filename)
+                            try:
+                                status = self._client.update(filename)
+                
+                                if status.number > 0:
+                                    view.AddLines(_("Updated to revision %s\n") % status.number)
+            
+                                    openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
+                                    for doc in openDocs:
+                                        if doc.GetFilename() == filename:
+                                            yesNoMsg = wx.MessageDialog(wx.GetApp().GetTopWindow(),
+                                                                     _("Updated file '%s' is currently open.  Close it?") % os.path.basename(filename),
+                                                                     _("Close File"),
+                                                                     wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION)
+                                            status = yesNoMsg.ShowModal()
+                                            if status == wx.ID_YES:
+                                                doc.DeleteAllViews()
+                                            elif status == wx.ID_NO:
+                                                pass
+                                            else: # elif status == wx.CANCEL:
+                                                wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
+                                                return True
+                                            break
+                                else:
+                                    view.AddLines(_("Update failed.\n"))
+                
+                            except pysvn.ClientError, e:
+                                view.AddLines("%s\n" % str(e))
+                                wx.MessageBox(str(e), _("SVN Update"), wx.OK | wx.ICON_EXCLAMATION)
+                            except:
+                                extype, ex, tb = sys.exc_info()
+                                view.AddLines("Update failed: (%s) %s\n" % (extype, str(ex)))
+                                for line in traceback.format_tb(tb):
+                                    view.AddLines(line)
+                
+                                wx.MessageBox(_("Update failed."), _("SVN Update"), wx.OK | wx.ICON_EXCLAMATION)
+
+            wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
+            return True
+
+        elif id == SVNService.SVN_CHECKIN_ALL_ID:
+            filenames = []
+            projects = self.GetCurrentProjects()
+            for project in projects:
+                openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
+                for doc in openDocs:
+                    if doc.GetFilename() == project:
+                        for filename in doc.GetFiles():
+                            if filename not in filenames:
+                                filenames.append(filename)
+            filenames.sort(self.BasenameCaseInsensitiveCompare)
+
+            # ask user if dirty files should be saved first
+            openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
+            for filename in filenames:
+                for doc in openDocs:
+                    if doc.GetFilename() == filename and doc.IsModified():
+                        yesNoMsg = wx.MessageDialog(wx.GetApp().GetTopWindow(),
+                                                 _("'%s' has unsaved modifications.  Save it before commit?") % os.path.basename(filename),
+                                                 _("SVN Commit"),
+                                                 wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION)
+                        status = yesNoMsg.ShowModal()
+                        if status == wx.ID_YES:
+                            doc.Save()
+                        elif status == wx.ID_NO:
+                            pass
+                        else: # elif status == wx.CANCEL:
+                            return True
+                        break
+
+            shortFilenames = []
+            for i, filename in enumerate(filenames):
+                shortFilename = os.path.basename(filename)
+                shortFilenames.append(shortFilename)
+
+            dlg = wx.Dialog(wx.GetApp().GetTopWindow(), -1, _("SVN Commit"))
+
+            sizer = wx.BoxSizer(wx.VERTICAL)
+            sizer.Add(wx.StaticText(dlg, -1, _("Comment:")), 0, wx.ALIGN_CENTER_VERTICAL)
+            commentText = wx.TextCtrl(dlg, -1, size=(250,-1), style=wx.TE_MULTILINE)
+            sizer.Add(commentText, 1, wx.EXPAND|wx.TOP, HALF_SPACE)
+
+            sizer.Add(wx.StaticText(dlg, -1, _("Files:")), 0, wx.ALIGN_CENTER_VERTICAL|wx.TOP, SPACE)
+            fileList = wx.CheckListBox(dlg, -1, choices = shortFilenames)
+            for i in range(fileList.GetCount()):
+                fileList.Check(i, True)
+            sizer.Add(fileList, 0, wx.EXPAND|wx.TOP, HALF_SPACE)
+
+            buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
+            okBtn = wx.Button(dlg, wx.ID_OK)
+            okBtn.SetDefault()
+            buttonSizer.Add(okBtn, 0, wx.RIGHT, HALF_SPACE)
+            buttonSizer.Add(wx.Button(dlg, wx.ID_CANCEL), 0)
+
+            contentSizer = wx.BoxSizer(wx.VERTICAL)
+            contentSizer.Add(sizer, 0, wx.ALL, SPACE)
+            contentSizer.Add(buttonSizer, 0, wx.ALL|wx.ALIGN_RIGHT, SPACE)
+
+            dlg.SetSizer(contentSizer)
+            dlg.Fit()
+            dlg.Layout()
+
+            if dlg.ShowModal() == wx.ID_OK:
+                wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
+
+                messageService = wx.GetApp().GetService(MessageService.MessageService)
+                messageService.ShowWindow()
+
+                view = messageService.GetView()
+                view.ClearLines()
+                view.AddLines(_("SVN Commit:\n"))
+
+                try:
+                    selFilenames = []
+                    for i in range(fileList.GetCount()):
+                        if fileList.IsChecked(i):
+                            selFilenames.append(filenames[i])
+                            view.AddLines("%s\n" % filenames[i])
+                        
+                    if len(selFilenames):
+                        comment = commentText.GetValue()
+                        status = self._client.checkin(selFilenames, comment)
+
+                        if status is None:
+                            view.AddLines(_("Nothing to commit.\n"))
+                        elif status.number > 0:
+                            view.AddLines(_("Committed as revision %s.\n") % status.number)
+                        else:
+                            view.AddLines(_("Commit failed.\n"))
+
+                except pysvn.ClientError, e:
+                    view.AddLines("%s\n" % str(e))
+                    wx.MessageBox(str(e), _("SVN Commit"), wx.OK | wx.ICON_EXCLAMATION)
+                except:
+                    extype, ex, tb = sys.exc_info()
+                    view.AddLines("Commit failed: (%s) %s\n" % (extype, str(ex)))
+                    for line in traceback.format_tb(tb):
+                        view.AddLines(line)
+                    wx.MessageBox(_("Commit failed."), _("SVN Commit"), wx.OK | wx.ICON_EXCLAMATION)
+
+                wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
+            dlg.Destroy()
+            return True
+
 
         elif id == SVNService.SVN_CHECKIN_ID:
-            filenames = self.GetCurrentDocuments()
+            filenames = self.GetCurrentDocuments()[:]
+            filenames.sort(self.BasenameCaseInsensitiveCompare)            
 
             # ask user if dirty files should be saved first
             openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
@@ -459,9 +635,14 @@ class SVNService(wx.lib.pydocview.DocService):
 
             gridSizer = wx.FlexGridSizer(cols = 2, hgap = 5, vgap = 5)
             gridSizer.Add(wx.StaticText(dlg, -1, _("Repository URL:")), 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, HALF_SPACE)
-            svnURLText = wx.TextCtrl(dlg, -1, svnUrl, size = (200, -1))
-            svnURLText.SetToolTipString(svnUrl)
-            gridSizer.Add(svnURLText, 0)
+            svnUrlList = ReadSvnUrlList()
+            svnURLCombobox = wx.ComboBox(dlg, -1, size=(200, -1), choices=svnUrlList, style=wx.CB_DROPDOWN)
+            if len(svnUrlList):
+                svnURLCombobox.SetToolTipString(svnUrlList[0])
+                svnURLCombobox.SetStringSelection(svnUrlList[0])
+            else:
+                svnURLCombobox.SetToolTipString(_("Set Repository URL"))
+            gridSizer.Add(svnURLCombobox, 0)
 
             gridSizer.Add(wx.StaticText(dlg, -1, _("Checkout to dir:")), 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, HALF_SPACE)
             localPath = wx.TextCtrl(dlg, -1, size = (200, -1))
@@ -502,6 +683,8 @@ class SVNService(wx.lib.pydocview.DocService):
 
             if dlg.ShowModal() == wx.ID_OK:
                 wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
+                
+                WriteSvnUrlList(svnURLCombobox)
 
                 messageService = wx.GetApp().GetService(MessageService.MessageService)
                 messageService.ShowWindow()
@@ -510,7 +693,7 @@ class SVNService(wx.lib.pydocview.DocService):
                 view.ClearLines()
                 view.AddLines(_("SVN Checkout:\n"))
 
-                svnUrl = svnURLText.GetValue()
+                svnUrl = svnURLCombobox.GetValue()
                 toLocation = localPath.GetValue()
                 try:
                     self._client.checkout(svnUrl, toLocation)
@@ -651,9 +834,31 @@ class SVNService(wx.lib.pydocview.DocService):
             event.Enable(True)
             return True
 
+        elif (id == SVNService.SVN_UPDATE_ALL_ID
+        or id == SVNService.SVN_CHECKIN_ALL_ID):
+            if self.GetCurrentProjects():
+                event.Enable(True)
+            else:
+                event.Enable(False)
+            return True
+
         return False
 
 
+    def GetCurrentProjects(self):
+        projectService = wx.GetApp().GetService(ProjectEditor.ProjectService)
+        if projectService:
+            projView = projectService.GetView()
+
+            if projView.HasFocus():
+                filenames = projView.GetSelectedProjects()
+                if len(filenames):
+                    return filenames
+                else:
+                    return None
+        return None
+
+
     def GetCurrentDocuments(self):
 
         projectService = wx.GetApp().GetService(ProjectEditor.ProjectService)
@@ -676,6 +881,17 @@ class SVNService(wx.lib.pydocview.DocService):
         return filenames
 
 
+    def BasenameCaseInsensitiveCompare(self, s1, s2):
+        s1L = os.path.basename(s1).lower()
+        s2L = os.path.basename(s2).lower()
+        if s1L == s2L:
+            return 0
+        elif s1L < s2L:
+            return -1
+        else:
+            return 1
+
+
 class SVNOptionsPanel(wx.Panel):
 
 
@@ -683,8 +899,6 @@ class SVNOptionsPanel(wx.Panel):
         wx.Panel.__init__(self, parent, id)
 
         config = wx.ConfigBase_Get()
-        svnService = wx.GetApp().GetService(SVNService)
-        svnUrl = config.Read(SVN_REPOSITORY_URL, svnService._defaultURL)
         configDir = config.Read(SVN_CONFIG_DIR, "")
 
         borderSizer = wx.BoxSizer(wx.VERTICAL)
@@ -718,10 +932,42 @@ class SVNOptionsPanel(wx.Panel):
         hsizer.Add(findDirButton, 0, wx.LEFT, HALF_SPACE)
         sizer.Add(hsizer, 0)
 
+
+        svnUrlList = ReadSvnUrlList()
         sizer.Add(wx.StaticText(self, -1, _("SVN URL:")), 0, wx.ALIGN_CENTER_VERTICAL)
-        self._svnURLText = wx.TextCtrl(self, -1, svnUrl, size = (200, -1))
-        self._svnURLText.SetToolTipString(svnUrl)
-        sizer.Add(self._svnURLText, 0)
+        self._svnURLCombobox = wx.ComboBox(self, -1, size=(200, -1), choices=svnUrlList, style=wx.CB_DROPDOWN)
+        if len(svnUrlList):
+            self._svnURLCombobox.SetToolTipString(svnUrlList[0])
+            self._svnURLCombobox.SetStringSelection(svnUrlList[0])
+        else:
+            self._svnURLCombobox.SetToolTipString(_("Set Repository URL"))
+        sizer.Add(self._svnURLCombobox, 0)
+
+
+        sizer.Add(wx.StaticText(self, -1, _("SVN_SSH:")), 0, wx.ALIGN_CENTER_VERTICAL)
+        svnSSH = os.getenv("SVN_SSH")
+        if not svnSSH or svnSSH == "":
+            self._svnSSH = wx.TextCtrl(self, -1, size = (200, -1))
+        else:
+            self._svnSSH = wx.TextCtrl(self, -1, svnSSH, size = (200, -1))
+        self._svnSSH.SetToolTipString(_("Override SVN_SSH environment variable temporarily."))
+        
+        findSSHButton = wx.Button(self, -1, _("Browse..."))
+
+        def OnBrowseFileButton(event):
+            dirDlg = wx.FileDialog(self, _("Choose a file:"), style=wx.OPEN|wx.CHANGE_DIR)
+            if dirDlg.ShowModal() == wx.ID_OK:
+                self._svnSSH.SetValue(dirDlg.GetPath())
+                self._svnSSH.SetToolTipString(self._svnSSH.GetValue())
+                self._svnSSH.SetInsertionPointEnd()
+            dirDlg.Destroy()
+        wx.EVT_BUTTON(findSSHButton, -1, OnBrowseFileButton)
+
+        hsizer = wx.BoxSizer(wx.HORIZONTAL)
+        hsizer.Add(self._svnSSH, 1, wx.EXPAND)
+        hsizer.Add(findSSHButton, 0, wx.LEFT, HALF_SPACE)
+        sizer.Add(hsizer, 0)
+
 
         borderSizer.Add(sizer, 0, wx.ALL, SPACE)
         self.SetSizer(borderSizer)
@@ -731,6 +977,43 @@ class SVNOptionsPanel(wx.Panel):
 
     def OnOK(self, optionsDialog):
         config = wx.ConfigBase_Get()
+        
         config.Write(SVN_CONFIG_DIR, self._svnConfigDir.GetValue())
-        config.Write(SVN_REPOSITORY_URL, self._svnURLText.GetValue())
+        
+        WriteSvnUrlList(self._svnURLCombobox)
+        
+        os.environ["SVN_SSH"] = self._svnSSH.GetValue()
+        
+
+def ReadSvnUrlList():
+    """ Read in list of SNV repository URLs.  First in list is the last one path used. """
+    config = wx.ConfigBase_Get()
+    urlStringList = config.Read(SVN_REPOSITORY_URL)
+    if len(urlStringList):
+        urlList = eval(urlStringList)
+    else:
+        urlList = []
+    if len(urlList) == 0:
+        svnService = wx.GetApp().GetService(SVNService)
+        if svnService and hasattr(svnService, "_defaultURL"):
+            urlList.append(svnService._defaultURL)
+    return urlList
+
+
+def WriteSvnUrlList(comboBox):
+    """ Save out list of SVN repository URLs from combobox.  Put on top the current selection.  Only save out first 10 from the list """
+    urlList = []
+    
+    url = comboBox.GetValue()
+    if len(url):
+        urlList.append(url)
+        
+    for i in range(min(comboBox.GetCount(), 10)):
+        url = comboBox.GetString(i)
+        if url not in urlList:
+            urlList.append(url)
+
+    config = wx.ConfigBase_Get()
+    config.Write(SVN_REPOSITORY_URL, urlList.__repr__())
+
 
index 52c6a152dcd1c47c3a177f66fcac73fc02ef10f6..6b81a9b8cfc618bb13f95e9764522ccee3939670 100644 (file)
@@ -56,6 +56,10 @@ def CreateDirectoryControl( parent, fileLabel, dirLabel, fileExtension, starting
         if nameControl.GetValue().find(' ') != -1:
             wx.MessageBox(_("Please provide a filename that does not contains spaces."), _("Spaces in Filename"))            
             return False
+        if not os.path.exists(dirControl.GetValue()):
+            wx.MessageBox(_("That directory does not exist. Please choose an existing directory."), _("Provide a Valid Directory"))            
+            return False
+        
         filePath = os.path.join(dirControl.GetValue(), MakeNameEndInExtension(nameControl.GetValue(), "." + fileExtension))
         if os.path.exists(filePath):
             if allowOverwriteOnPrompt:
index d2e2080814b0c70c423a350a0d6b7ec0a5ce3fc1..0c27e51f1563ee2f5d4bf1c799084cb52a5c4233 100644 (file)
@@ -63,8 +63,8 @@ class XmlService(CodeEditor.CodeService):
 class XmlCtrl(CodeEditor.CodeCtrl):
 
 
-    def __init__(self, parent, ID = -1, style = wx.NO_FULL_REPAINT_ON_RESIZE):
-        CodeEditor.CodeCtrl.__init__(self, parent, ID, style)
+    def __init__(self, parent, id=-1, style=wx.NO_FULL_REPAINT_ON_RESIZE):
+        CodeEditor.CodeCtrl.__init__(self, parent, id, style)
         self.SetLexer(wx.stc.STC_LEX_XML)
         self.SetProperty("fold.html", "1")
 
index 691c1396991e3bff88f4ebdbe5f936f8e39c1721..a521f0cf509d27cc5dbc2663c0cf9d12341867be 100644 (file)
@@ -1924,7 +1924,7 @@ class IOBuffer:
 
         self.__buf = ''
         # A state change is defined as the buffer being closed or a
-        # write occurring.
+        # write occuring.
         if mutex is not None:
             self._mutex = mutex
         else:
index edcfb1ca9511aaf499d04f4a203dc6ddafde0196..4cda367b3ce77bd07f312bafd5ffeca2d58010c0 100644 (file)
@@ -21,8 +21,9 @@ def _registerMainModuleDir():
         if not os.path.isabs(utilModuleDir):
             utilModuleDir = os.path.join(os.getcwd(), utilModuleDir)
         mainModuleDir = os.path.normpath(os.path.join(utilModuleDir, os.path.join(os.path.pardir, os.path.pardir)))
+        if mainModuleDir.endswith('.zip'):
+            mainModuleDir = os.path.dirname(mainModuleDir) # Get rid of library.zip
     else:
         mainModuleDir = os.path.dirname(sys.executable)
 
 _registerMainModuleDir()
-
index 3b2935f1e56dc91b7abe54a6c9d7dc3100910d1d..97bd2f79e013228174c415afcf27dc15fc709303 100644 (file)
@@ -14,23 +14,89 @@ import logging
 import traceback
 import sys
 import os
-
 import xmlmarshaller
 
+AG_TYPE_MAPPING =    { "ag:append"      : "activegrid.model.processmodel.AppendOperation",
+                       "ag:body"        : "activegrid.model.processmodel.Body",
+                       "ag:copy"        : "activegrid.model.processmodel.CopyOperation",
+                       "ag:cssRule"     : "activegrid.model.processmodel.CssRule",
+                       "ag:datasource"  : "activegrid.data.dataservice.DataSource",
+                       "ag:debug"       : "activegrid.model.processmodel.DebugOperation",
+                       "ag:deployment"  : "activegrid.server.deployment.Deployment",
+                       "ag:glue"        : "activegrid.model.processmodel.Glue",
+                       "ag:hr"          : "activegrid.model.processmodel.HorizontalRow",
+                       "ag:image"       : "activegrid.model.processmodel.Image",
+                       "ag:inputs"      : "activegrid.model.processmodel.Inputs",
+                       "ag:label"       : "activegrid.model.processmodel.Label",
+                       "ag:processmodel": "activegrid.model.processmodel.ProcessModel",
+                       "ag:processmodelref" : "activegrid.server.deployment.ProcessModelRef",
+                       "ag:query"       : "activegrid.model.processmodel.Query",
+                       "ag:schemaOptions" : "activegrid.model.schema.SchemaOptions",
+                       "ag:schemaref"   : "activegrid.server.deployment.SchemaRef",
+                       "ag:set"         : "activegrid.model.processmodel.SetOperation",
+                       "ag:text"        : "activegrid.model.processmodel.Text",
+                       "ag:title"       : "activegrid.model.processmodel.Title",
+                       "ag:view"        : "activegrid.model.processmodel.View",
+                       "bpws:case"      : "activegrid.model.processmodel.BPELCase",
+                       "bpws:catch"     : "activegrid.model.processmodel.BPELCatch",
+                       "bpws:faultHandlers" : "activegrid.model.processmodel.BPELFaultHandlers",
+                       "bpws:invoke"    : "activegrid.model.processmodel.BPELInvoke",
+                       "bpws:onMessage" : "activegrid.model.processmodel.BPELOnMessage",
+                       "bpws:otherwise" : "activegrid.model.processmodel.BPELOtherwise",
+                       "bpws:pick"      : "activegrid.model.processmodel.BPELPick",
+                       "bpws:process"   : "activegrid.model.processmodel.BPELProcess",
+                       "bpws:receive"   : "activegrid.model.processmodel.BPELReceive",
+                       "bpws:reply"     : "activegrid.model.processmodel.BPELReply",
+                       "bpws:scope"     : "activegrid.model.processmodel.BPELScope",
+                       "bpws:sequence"  : "activegrid.model.processmodel.BPELSequence",
+                       "bpws:switch"    : "activegrid.model.processmodel.BPELSwitch",
+                       "bpws:terminate" : "activegrid.model.processmodel.BPELTerminate",
+                       "bpws:variable"  : "activegrid.model.processmodel.BPELVariable",
+                       "bpws:variables" : "activegrid.model.processmodel.BPELVariables",
+                       "bpws:while"     : "activegrid.model.processmodel.BPELWhile",
+                       "wsdl:message"   : "activegrid.model.processmodel.WSDLMessage",
+                       "wsdl:part"      : "activegrid.model.processmodel.WSDLPart",
+                       "xforms:group"   : "activegrid.model.processmodel.XFormsGroup",
+                       "xforms:input"   : "activegrid.model.processmodel.XFormsInput",
+                       "xforms:label"   : "activegrid.model.processmodel.XFormsLabel",
+                       "xforms:output"  : "activegrid.model.processmodel.XFormsOutput",
+                       "xforms:secret"  : "activegrid.model.processmodel.XFormsSecret",
+                       "xforms:submit"  : "activegrid.model.processmodel.XFormsSubmit",
+                       "xs:all"         : "activegrid.model.schema.XsdSequence",
+                       "xs:complexType" : "activegrid.model.schema.XsdComplexType",
+                       "xs:element"     : "activegrid.model.schema.XsdElement",
+                       "xs:field"       : "activegrid.model.schema.XsdKeyField",
+                       "xs:key"         : "activegrid.model.schema.XsdKey",
+                       "xs:keyref"      : "activegrid.model.schema.XsdKeyRef",
+                       "xs:schema"      : "activegrid.model.schema.Schema",
+                       "xs:selector"    : "activegrid.model.schema.XsdKeySelector",              
+                       "xs:sequence"    : "activegrid.model.schema.XsdSequence",
+                       "projectmodel"   : "activegrid.tool.ProjectEditor.ProjectModel",
+                     }
+
 def defaultLoad(fileObject, knownTypes=None):
     xml = fileObject.read()
-    loadedObject = xmlmarshaller.unmarshal(xml, knownTypes=knownTypes)
+    loadedObject = defaultUnmarshal(xml, knownTypes=knownTypes)
     if hasattr(fileObject, 'name'):
         loadedObject.fileName = os.path.abspath(fileObject.name)
     loadedObject.initialize()
     return loadedObject
 
-def defaultSave(fileObject, objectToSave, knownTypes=None, withEncoding=1, encoding='utf-8'):
-    xml = xmlmarshaller.marshal(objectToSave, prettyPrint=True, knownTypes=knownTypes, withEncoding=withEncoding, encoding=encoding)
+def defaultUnmarshal(xml, knownTypes=None):
+    if not knownTypes: knownTypes = AG_TYPE_MAPPING
+    return xmlmarshaller.unmarshal(xml, knownTypes=knownTypes)    
+
+def defaultSave(fileObject, objectToSave, prettyPrint=True, knownTypes=None, withEncoding=1, encoding='utf-8'):
+    xml = defaultMarshal(objectToSave, prettyPrint=prettyPrint, knownTypes=knownTypes, withEncoding=withEncoding, encoding=encoding)
     fileObject.write(xml)
     fileObject.flush()
+
+def defaultMarshal(objectToSave, prettyPrint=True, knownTypes=None, withEncoding=1, encoding='utf-8'):
+    if not knownTypes: knownTypes = AG_TYPE_MAPPING
+    return xmlmarshaller.marshal(objectToSave, prettyPrint=prettyPrint, knownTypes=knownTypes, withEncoding=withEncoding, encoding=encoding)
+    
 def clone(objectToClone, knownTypes=None, encoding='utf-8'):
+    if not knownTypes: knownTypes = AG_TYPE_MAPPING
     xml = xmlmarshaller.marshal(objectToClone, prettyPrint=True, knownTypes=knownTypes, encoding=encoding)
     clonedObject = xmlmarshaller.unmarshal(xml, knownTypes=knownTypes)
     if hasattr(objectToClone, 'fileName'):
@@ -91,3 +157,116 @@ def hasPropertyValue(obj, attr):
     except KeyError:
         pass
     return hasProp
+
+def toDiffableString(value):
+    s = repr(value)
+    ds = ""
+    i = s.find(" at 0x") 
+    start = 0
+    while (i >= 0):
+        j = s.find(">", i)
+        if (j < i):
+            break
+        ds += s[start:i]
+        start = j
+        i = s.find(" at 0x", start) 
+    return ds + s[start:]
+    
+PRINT_OBJ_GETATTR = 1
+PRINT_OBJ_HIDE_INTERNAL = 2
+PRINT_OBJ_COMPACT = 4
+PRINT_OBJ_NONONE = 8
+PRINT_OBJ_INTERNAL = 512
+
+def printObject(out, object, name="", indent=0, flags=0, exclude=None, maxIndent=30):
+    if ((maxIndent != None) and (indent > maxIndent)):
+        print >> out, " "*indent, name, str(object)
+        return True
+    finalNewLine = False
+    printed = True
+    if ((flags & PRINT_OBJ_COMPACT) > 0):
+        if (exclude and object in exclude):
+            return
+        indent = 0
+    if ((flags & PRINT_OBJ_INTERNAL) == 0):
+        finalNewLine = True
+    flags |= PRINT_OBJ_INTERNAL
+    if (object == None):
+        if (flags & PRINT_OBJ_NONONE) == 0:
+            print >> out, " "*indent, name, " = None",
+        else:
+            finalNewLine = False
+            printed = False
+    elif (name.startswith("_") and ((flags & PRINT_OBJ_HIDE_INTERNAL) > 0)):
+        finalNewLine = False
+        printed = False
+    elif (isinstance(object, (list, tuple))):
+        if (exclude and object in exclude):
+            print >> out, " "*indent, name, " : ", type(object), " of length = ", len(object), " (already printed)",
+        elif (exclude and name in exclude):
+            print >> out, " "*indent, name, " : ", type(object), " of length = ", len(object), " (excluded)",
+        else:
+            if (exclude != None): exclude.append(object)
+            print >> out, " "*indent, name, " : ", type(object), " of length = %i" % len(object),
+            for i, o in enumerate(object):
+                print >> out
+                printObject(out, o, name="[%i]" % i, indent=indent+2, flags=flags, exclude=exclude, maxIndent=maxIndent)
+    elif (isinstance(object, dict)):
+        if (exclude and object in exclude):
+            print >> out, " "*indent, name, " : ", type(object), " (already printed)",
+        else:
+            if (exclude != None): exclude.append(object)
+            if (len(name) > 0):
+                print >> out, " "*indent, name,
+                if ((flags & PRINT_OBJ_COMPACT) == 0):
+                    print >> out
+                    indent += 2
+            print >> out, " "*indent, "{",
+            if ((flags & PRINT_OBJ_COMPACT) == 0):
+                print >> out
+            keys = object.keys()
+            keys.sort()
+            for n in keys:
+                if ((n != None) and (not n.startswith("_") or ((flags & PRINT_OBJ_HIDE_INTERNAL) == 0))):
+                    if printObject(out, object[n], name=n, indent=indent+2, flags=flags, exclude=exclude, maxIndent=maxIndent):
+                        if ((flags & PRINT_OBJ_COMPACT) == 0):
+                            print >> out
+                        else:
+                            print >> out, ",",
+            print >> out, " "*indent, "}",
+    elif (hasattr(object, "__dict__")):
+        if (exclude and object in exclude):
+            print >> out, " "*indent, name, " : ", type(object), " (already printed) = ", toDiffableString(object),
+        else:
+            if (exclude != None): exclude.append(object)
+            if (name.startswith("_")):
+                print >> out, " "*indent, name, " : ", type(object),
+            elif (exclude and object.__dict__ in exclude):
+                print >> out, " "*indent, name, " : ", type(object), " (already printed)",
+            else:
+                print >> out, " "*indent, name, " : ", type(object),
+                if ((flags & PRINT_OBJ_GETATTR) == 0):
+                    if ((flags & PRINT_OBJ_COMPACT) == 0):
+                        print >> out
+                    printObject(out, object.__dict__, indent=indent, flags=flags, exclude=exclude, maxIndent=maxIndent)
+                else:
+                    keys = object.__dict__.keys()
+                    keys.sort()
+                    for n in keys:
+                        if ((flags & PRINT_OBJ_COMPACT) == 0):
+                            print >> out
+                        printObject(out, getattr(object, n), name=n, indent=indent+2, flags=flags, exclude=exclude, maxIndent=maxIndent)
+    elif (indent < 0):
+        print >> out, object,
+    elif isinstance(object, basestring):
+        if (exclude and name in exclude):
+            print >> out, " "*indent, name, " : ", type(object), " of length = ", len(object), " (excluded)",
+        elif (len(object) > 100):
+            print >> out, " "*indent, name, ":", type(object), "[%i] = %s...%s" % (len(object), object[:50], object[-50:]),
+        else:
+            print >> out, " "*indent, name, ":", type(object), "=", str(object),
+    else:
+        print >> out, " "*indent, name, ":", type(object), "=", str(object),
+    if (finalNewLine):
+        print >> out
+    return printed
index 1dcf3699e1d2838c55cf32431512a14d243214e0..1b9cd67d4585b2ae2a2037166322616d1162ca1e 100644 (file)
@@ -195,6 +195,8 @@ def _objectfactory(objname, objargs=None, xsname=None):
     try:
         if __builtin__.__dict__.has_key(objname):
             module = __builtin__
+        elif knownGlobalModule:
+            module = knownGlobalModule
         else:
             if modulename:
                 module = __import__(modulename)
@@ -431,12 +433,13 @@ def _getXmlValue(pythonValue):
     else:
         return str(pythonValue)
 
-def unmarshal(xmlstr, knownTypes=None):
-    global knownGlobalTypes
+def unmarshal(xmlstr, knownTypes=None, knownModule=None):
+    global knownGlobalTypes, knownGlobalModule
     if (knownTypes == None):
         knownGlobalTypes = {}
     else:
         knownGlobalTypes = knownTypes
+    knownGlobalModule = knownModule
     objectfactory = XMLObjectFactory()
     xml.sax.parseString(xmlstr, objectfactory)
     return objectfactory.getRootObject()
index 2dd76d012a9a981db92428dfb90465c270530aca..7d41d3dfe12109be1590d1b9924520921a2bd2fb 100644 (file)
@@ -435,6 +435,7 @@ class Document(wx.EvtHandler):
             msgTitle = _("File Error")
 
         backupFilename = None
+        fileObject = None
         try:
             # if current file exists, move it to a safe place temporarily
             if os.path.exists(filename):
@@ -457,10 +458,18 @@ class Document(wx.EvtHandler):
             fileObject = file(filename, 'w')
             self.SaveObject(fileObject)
             fileObject.close()
-
+            fileObject = None
+            
             if backupFilename:
                 os.remove(backupFilename)
         except:
+            # for debugging purposes
+            import traceback
+            traceback.print_exc()
+
+            if fileObject:
+                fileObject.close()  # file is still open, close it, need to do this before removal 
+
             # save failed, restore old file
             if backupFilename:
                 os.remove(filename)
@@ -501,7 +510,16 @@ class Document(wx.EvtHandler):
         fileObject = file(filename, 'r')
         try:
             self.LoadObject(fileObject)
+            fileObject.close()
+            fileObject = None
         except:
+            # for debugging purposes
+            import traceback
+            traceback.print_exc()
+
+            if fileObject:
+                fileObject.close()  # file is still open, close it 
+
             wx.MessageBox("Could not open '%s'.  %s" % (FileNameFromPath(filename), sys.exc_value),
                           msgTitle,
                           wx.OK | wx.ICON_EXCLAMATION,
@@ -945,7 +963,7 @@ class View(wx.EvtHandler):
 
         Override to return an instance of a class other than wxDocPrintout.
         """
-        return DocPrintout(self)
+        return DocPrintout(self, self.GetDocument().GetPrintableName())
 
 
     def GetFrame(self):
@@ -1229,6 +1247,10 @@ class DocTemplate(wx.Object):
         Returns True if the path's extension matches one of this template's
         file filter extensions.
         """
+##        print "*** path", path
+##        if "*.*" in self.GetFileFilter():
+##            return True
+##            
         ext = FindExtension(path)
         if not ext: return False
         return ext in self.GetFileFilter()
@@ -1450,9 +1472,14 @@ class DocManager(wx.EvtHandler):
 
         printout = view.OnCreatePrintout()
         if printout:
-            pdd = wx.PrintDialogData()
+            if not hasattr(self, "printData"):
+                self.printData = wx.PrintData()
+                self.printData.SetPaperId(wx.PAPER_LETTER)
+            self.printData.SetPrintMode(wx.PRINT_MODE_PRINTER)
+                
+            pdd = wx.PrintDialogData(self.printData)
             printer = wx.Printer(pdd)
-            printer.Print(view.GetFrame(), printout) # , True)
+            printer.Print(view.GetFrame(), printout)
 
 
     def OnPrintSetup(self, event):
@@ -1465,11 +1492,21 @@ class DocManager(wx.EvtHandler):
         else:
             parentWin = wx.GetApp().GetTopWindow()
 
-        data = wx.PrintDialogData()
+        if not hasattr(self, "printData"):
+            self.printData = wx.PrintData()
+            self.printData.SetPaperId(wx.PAPER_LETTER)
+            
+        data = wx.PrintDialogData(self.printData)
         printDialog = wx.PrintDialog(parentWin, data)
         printDialog.GetPrintDialogData().SetSetupDialog(True)
         printDialog.ShowModal()
-        # TODO: Confirm that we don't have to remember PrintDialogData
+        
+        # this makes a copy of the wx.PrintData instead of just saving
+        # a reference to the one inside the PrintDialogData that will
+        # be destroyed when the dialog is destroyed
+        self.printData = wx.PrintData(printDialog.GetPrintDialogData().GetPrintData())
+        
+        printDialog.Destroy()
 
 
     def OnPreview(self, event):
@@ -1483,13 +1520,22 @@ class DocManager(wx.EvtHandler):
 
         printout = view.OnCreatePrintout()
         if printout:
+            if not hasattr(self, "printData"):
+                self.printData = wx.PrintData()
+                self.printData.SetPaperId(wx.PAPER_LETTER)
+            self.printData.SetPrintMode(wx.PRINT_MODE_PREVIEW)
+                
+            data = wx.PrintDialogData(self.printData)
             # Pass two printout objects: for preview, and possible printing.
-            preview = wx.PrintPreview(printout, view.OnCreatePrintout())
+            preview = wx.PrintPreview(printout, view.OnCreatePrintout(), data)
+            if not preview.Ok():
+                wx.MessageBox(_("Unable to display print preview."))
+                return
             # wxWindows source doesn't use base frame's pos, size, and icon, but did it this way so it would work like MS Office etc.
             mimicFrame =  wx.GetApp().GetTopWindow()
             frame = wx.PreviewFrame(preview, mimicFrame, _("Print Preview"), mimicFrame.GetPosition(), mimicFrame.GetSize())
             frame.SetIcon(mimicFrame.GetIcon())
-            frame.SetTitle(mimicFrame.GetTitle() + _(" - Preview"))
+            frame.SetTitle(_("%s - %s - Preview") % (mimicFrame.GetTitle(), view.GetDocument().GetPrintableName()))
             frame.Initialize()
             frame.Show(True)
 
@@ -1575,7 +1621,7 @@ class DocManager(wx.EvtHandler):
         if doc and doc.GetCommandProcessor():
             doc.GetCommandProcessor().SetMenuStrings()
         else:
-            event.SetText(_("Undo") + '\t' + _('Ctrl+Z'))
+            event.SetText(_("&Undo\tCtrl+Z"))
 
 
     def OnUpdateRedo(self, event):
@@ -1587,7 +1633,7 @@ class DocManager(wx.EvtHandler):
         if doc and doc.GetCommandProcessor():
             doc.GetCommandProcessor().SetMenuStrings()
         else:
-            event.SetText(_("Redo") + '\t' + _('Ctrl+Y'))
+            event.SetText(_("&Redo\tCtrl+Y"))
 
 
     def OnUpdatePrint(self, event):
@@ -1800,9 +1846,9 @@ class DocManager(wx.EvtHandler):
             temp, path = self.SelectDocumentPath(templates, path, flags)
 
         # Existing document
-        if self.GetFlags() & DOC_OPEN_ONCE:
+        if path and self.GetFlags() & DOC_OPEN_ONCE:
             for document in self._docs:
-                if document.GetFilename() == path:
+                if document.GetFilename() and os.path.normcase(document.GetFilename()) == os.path.normcase(path):
                     """ check for file modification outside of application """
                     if os.path.exists(path) and os.path.getmtime(path) != document.GetDocumentModificationDate():
                         msgTitle = wx.GetApp().GetAppName()
@@ -2034,11 +2080,17 @@ class DocManager(wx.EvtHandler):
         Given a path, try to find template that matches the extension. This is
         only an approximate method of finding a template for creating a
         document.
+        
+        Note this wxPython verson looks for and returns a default template if no specific template is found.
         """
+        default = None
         for temp in self._templates:
             if temp.FileMatchesTemplate(path):
                 return temp
-        return None
+                
+            if "*.*" in temp.GetFileFilter():
+                default = temp
+        return default
 
 
     def FindSuitableParent(self):
@@ -2077,7 +2129,7 @@ class DocManager(wx.EvtHandler):
                         allfilter = allfilter + _(';')
                     descr = descr + temp.GetDescription() + _(" (") + temp.GetFileFilter() + _(") |") + temp.GetFileFilter()  # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
                     allfilter = allfilter + temp.GetFileFilter()
-            descr = _("All") + _(" (") + allfilter + _(") |") + allfilter + _('|') + descr  # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
+            descr = _("All (%s)|%s|%s|Any (*.*) | *.*") %  (allfilter, allfilter, descr)  # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
         else:
             descr = _("*.*")
 
@@ -2790,7 +2842,7 @@ class DocPrintout(wx.Printout):
         """
         Constructor.
         """
-        wx.Printout.__init__(self)
+        wx.Printout.__init__(self, title)
         self._printoutView = view
 
 
@@ -3058,15 +3110,15 @@ class CommandProcessor(wx.Object):
             else:
                 redoAccel = ''
             if undoCommand and undoItem and undoCommand.CanUndo():
-                undoItem.SetText(_("Undo ") + undoCommand.GetName() + undoAccel)
+                undoItem.SetText(_("&Undo ") + undoCommand.GetName() + undoAccel)
             #elif undoCommand and not undoCommand.CanUndo():
             #    undoItem.SetText(_("Can't Undo") + undoAccel)
             else:
-                undoItem.SetText(_("Undo" + undoAccel))
+                undoItem.SetText(_("&Undo" + undoAccel))
             if redoCommand and redoItem:
-                redoItem.SetText(_("Redo ") + redoCommand.GetName() + redoAccel)
+                redoItem.SetText(_("&Redo ") + redoCommand.GetName() + redoAccel)
             else:
-                redoItem.SetText(_("Redo") + redoAccel)
+                redoItem.SetText(_("&Redo") + redoAccel)
 
 
     def CanUndo(self):
index 3292f8aa91483d7600586796cff17326aabc42e4..0314e5141b4770c1d3da75e09a1d045f4f849c8d 100644 (file)
@@ -295,7 +295,7 @@ class DocMDIParentFrameMixIn:
 
         config = wx.ConfigBase_Get()
         if config.ReadInt("MDIFrameMaximized", False):
-            # wxBug: On maximize, statusbar leaves a residual that needs to be refreshed, happens even when user does it
+            # wxBug: On maximize, statusbar leaves a residual that needs to be refereshed, happens even when user does it
             self.Maximize()
 
         self.CreateEmbeddedWindows(embeddedWindows)
@@ -1603,7 +1603,7 @@ class DocApp(wx.PySimpleApp):
             args = pickle.loads(data)
             for arg in args:
                 if arg[0] != '/' and arg[0] != '-' and os.path.exists(arg):
-                    self.GetDocumentManager().CreateDocument(arg, wx.lib.docview.DOC_SILENT)
+                    self.GetDocumentManager().CreateDocument(os.path.normpath(arg), wx.lib.docview.DOC_SILENT)
             
             # force display of running app
             topWindow = wx.GetApp().GetTopWindow()
@@ -1624,7 +1624,7 @@ class DocApp(wx.PySimpleApp):
         args = sys.argv[1:]
         for arg in args:
             if arg[0] != '/' and arg[0] != '-' and os.path.exists(arg):
-                self.GetDocumentManager().CreateDocument(arg, wx.lib.docview.DOC_SILENT)
+                self.GetDocumentManager().CreateDocument(os.path.normpath(arg), wx.lib.docview.DOC_SILENT)
 
 
     def GetDocumentManager(self):