From 26ee3a06e28e16b71367183581a4f3b10ee4e832 Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Tue, 31 May 2005 21:41:11 +0000 Subject: [PATCH] DocView patches from Morgen Hua: bug fixes, and additional SVN 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 --- .../ide/activegrid/tool/AboutDialog.py | 2 +- .../ide/activegrid/tool/AbstractEditor.py | 22 +- .../samples/ide/activegrid/tool/CodeEditor.py | 14 +- .../ide/activegrid/tool/DebuggerHarness.py | 81 +++-- .../ide/activegrid/tool/DebuggerService.py | 315 ++++++++++++------ .../samples/ide/activegrid/tool/HtmlEditor.py | 6 +- wxPython/samples/ide/activegrid/tool/IDE.py | 15 +- .../ide/activegrid/tool/ImageEditor.py | 13 +- .../samples/ide/activegrid/tool/PHPEditor.py | 4 +- .../samples/ide/activegrid/tool/PerlEditor.py | 4 +- .../ide/activegrid/tool/ProjectEditor.py | 98 +++++- .../ide/activegrid/tool/PythonEditor.py | 15 +- .../ide/activegrid/tool/STCTextEditor.py | 294 +++++++++++----- .../samples/ide/activegrid/tool/SVNService.py | 315 +++++++++++++++++- .../samples/ide/activegrid/tool/UICommon.py | 4 + .../samples/ide/activegrid/tool/XmlEditor.py | 4 +- .../samples/ide/activegrid/tool/process.py | 2 +- .../samples/ide/activegrid/util/__init__.py | 3 +- .../samples/ide/activegrid/util/objutils.py | 189 ++++++++++- .../ide/activegrid/util/xmlmarshaller.py | 7 +- wxPython/wx/lib/docview.py | 90 +++-- wxPython/wx/lib/pydocview.py | 6 +- 22 files changed, 1189 insertions(+), 314 deletions(-) diff --git a/wxPython/samples/ide/activegrid/tool/AboutDialog.py b/wxPython/samples/ide/activegrid/tool/AboutDialog.py index 3a7be9fa74..b43e5244ca 100644 --- a/wxPython/samples/ide/activegrid/tool/AboutDialog.py +++ b/wxPython/samples/ide/activegrid/tool/AboutDialog.py @@ -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")) diff --git a/wxPython/samples/ide/activegrid/tool/AbstractEditor.py b/wxPython/samples/ide/activegrid/tool/AbstractEditor.py index 8369738428..18fbf6d7fc 100644 --- a/wxPython/samples/ide/activegrid/tool/AbstractEditor.py +++ b/wxPython/samples/ide/activegrid/tool/AbstractEditor.py @@ -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(): diff --git a/wxPython/samples/ide/activegrid/tool/CodeEditor.py b/wxPython/samples/ide/activegrid/tool/CodeEditor.py index d8a158a0ee..de0fbaf86e 100644 --- a/wxPython/samples/ide/activegrid/tool/CodeEditor.py +++ b/wxPython/samples/ide/activegrid/tool/CodeEditor.py @@ -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 diff --git a/wxPython/samples/ide/activegrid/tool/DebuggerHarness.py b/wxPython/samples/ide/activegrid/tool/DebuggerHarness.py index e321865a09..433c118dce 100644 --- a/wxPython/samples/ide/activegrid/tool/DebuggerHarness.py +++ b/wxPython/samples/ide/activegrid/tool/DebuggerHarness.py @@ -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: diff --git a/wxPython/samples/ide/activegrid/tool/DebuggerService.py b/wxPython/samples/ide/activegrid/tool/DebuggerService.py index 79e78e0466..8da8bc2492 100644 --- a/wxPython/samples/ide/activegrid/tool/DebuggerService.py +++ b/wxPython/samples/ide/activegrid/tool/DebuggerService.py @@ -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\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()) diff --git a/wxPython/samples/ide/activegrid/tool/HtmlEditor.py b/wxPython/samples/ide/activegrid/tool/HtmlEditor.py index fa5d09de98..21001efc6b 100644 --- a/wxPython/samples/ide/activegrid/tool/HtmlEditor.py +++ b/wxPython/samples/ide/activegrid/tool/HtmlEditor.py @@ -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 diff --git a/wxPython/samples/ide/activegrid/tool/IDE.py b/wxPython/samples/ide/activegrid/tool/IDE.py index 7767890fcc..1d68e31f87 100644 --- a/wxPython/samples/ide/activegrid/tool/IDE.py +++ b/wxPython/samples/ide/activegrid/tool/IDE.py @@ -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"), diff --git a/wxPython/samples/ide/activegrid/tool/ImageEditor.py b/wxPython/samples/ide/activegrid/tool/ImageEditor.py index 6691236169..a2215723d7 100644 --- a/wxPython/samples/ide/activegrid/tool/ImageEditor.py +++ b/wxPython/samples/ide/activegrid/tool/ImageEditor.py @@ -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 #---------------------------------------------------------------------------- diff --git a/wxPython/samples/ide/activegrid/tool/PHPEditor.py b/wxPython/samples/ide/activegrid/tool/PHPEditor.py index fba7b6c029..bd8fa06029 100644 --- a/wxPython/samples/ide/activegrid/tool/PHPEditor.py +++ b/wxPython/samples/ide/activegrid/tool/PHPEditor.py @@ -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)) diff --git a/wxPython/samples/ide/activegrid/tool/PerlEditor.py b/wxPython/samples/ide/activegrid/tool/PerlEditor.py index 8c31a322dd..aaab62a206 100644 --- a/wxPython/samples/ide/activegrid/tool/PerlEditor.py +++ b/wxPython/samples/ide/activegrid/tool/PerlEditor.py @@ -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)) diff --git a/wxPython/samples/ide/activegrid/tool/ProjectEditor.py b/wxPython/samples/ide/activegrid/tool/ProjectEditor.py index 56331050ec..4d88f9defc 100644 --- a/wxPython/samples/ide/activegrid/tool/ProjectEditor.py +++ b/wxPython/samples/ide/activegrid/tool/ProjectEditor.py @@ -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: diff --git a/wxPython/samples/ide/activegrid/tool/PythonEditor.py b/wxPython/samples/ide/activegrid/tool/PythonEditor.py index 876f42b6bf..6496f7f58a 100644 --- a/wxPython/samples/ide/activegrid/tool/PythonEditor.py +++ b/wxPython/samples/ide/activegrid/tool/PythonEditor.py @@ -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 diff --git a/wxPython/samples/ide/activegrid/tool/STCTextEditor.py b/wxPython/samples/ide/activegrid/tool/STCTextEditor.py index 113721029a..549c708c23 100644 --- a/wxPython/samples/ide/activegrid/tool/STCTextEditor.py +++ b/wxPython/samples/ide/activegrid/tool/STCTextEditor.py @@ -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 diff --git a/wxPython/samples/ide/activegrid/tool/SVNService.py b/wxPython/samples/ide/activegrid/tool/SVNService.py index 97206c5d9f..9d35ad0ce9 100644 --- a/wxPython/samples/ide/activegrid/tool/SVNService.py +++ b/wxPython/samples/ide/activegrid/tool/SVNService.py @@ -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__()) + diff --git a/wxPython/samples/ide/activegrid/tool/UICommon.py b/wxPython/samples/ide/activegrid/tool/UICommon.py index 52c6a152dc..6b81a9b8cf 100644 --- a/wxPython/samples/ide/activegrid/tool/UICommon.py +++ b/wxPython/samples/ide/activegrid/tool/UICommon.py @@ -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: diff --git a/wxPython/samples/ide/activegrid/tool/XmlEditor.py b/wxPython/samples/ide/activegrid/tool/XmlEditor.py index d2e2080814..0c27e51f15 100644 --- a/wxPython/samples/ide/activegrid/tool/XmlEditor.py +++ b/wxPython/samples/ide/activegrid/tool/XmlEditor.py @@ -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") diff --git a/wxPython/samples/ide/activegrid/tool/process.py b/wxPython/samples/ide/activegrid/tool/process.py index 691c139699..a521f0cf50 100644 --- a/wxPython/samples/ide/activegrid/tool/process.py +++ b/wxPython/samples/ide/activegrid/tool/process.py @@ -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: diff --git a/wxPython/samples/ide/activegrid/util/__init__.py b/wxPython/samples/ide/activegrid/util/__init__.py index edcfb1ca95..4cda367b3c 100644 --- a/wxPython/samples/ide/activegrid/util/__init__.py +++ b/wxPython/samples/ide/activegrid/util/__init__.py @@ -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() - diff --git a/wxPython/samples/ide/activegrid/util/objutils.py b/wxPython/samples/ide/activegrid/util/objutils.py index 3b2935f1e5..97bd2f79e0 100644 --- a/wxPython/samples/ide/activegrid/util/objutils.py +++ b/wxPython/samples/ide/activegrid/util/objutils.py @@ -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 diff --git a/wxPython/samples/ide/activegrid/util/xmlmarshaller.py b/wxPython/samples/ide/activegrid/util/xmlmarshaller.py index 1dcf3699e1..1b9cd67d45 100644 --- a/wxPython/samples/ide/activegrid/util/xmlmarshaller.py +++ b/wxPython/samples/ide/activegrid/util/xmlmarshaller.py @@ -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() diff --git a/wxPython/wx/lib/docview.py b/wxPython/wx/lib/docview.py index 2dd76d012a..7d41d3dfe1 100644 --- a/wxPython/wx/lib/docview.py +++ b/wxPython/wx/lib/docview.py @@ -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): diff --git a/wxPython/wx/lib/pydocview.py b/wxPython/wx/lib/pydocview.py index 3292f8aa91..0314e5141b 100644 --- a/wxPython/wx/lib/pydocview.py +++ b/wxPython/wx/lib/pydocview.py @@ -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): -- 2.45.2