From 2eeaec1909452c66566cd99b35bad8abae9ed54f Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Sat, 11 Jun 2005 23:18:57 +0000 Subject: [PATCH] Docview and IDE patch from Morag Hua with fix for bug #1217890 "Closing view crashes Python" plus some new features: New feature added to the IDE is 'Extensions'. Under Tools|Options|Extensions, you can add calls to external programs. For example you can add a "Notepad" extension (under windows) that will exec Notepad on the currently open file. A new "Notepad" menu item will appear under the Tools menu. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@34638 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- wxPython/docs/CHANGES.txt | 12 + wxPython/samples/docview/DocViewDemo.py | 1 + .../ide/activegrid/tool/AbstractEditor.py | 43 +- .../ide/activegrid/tool/DebuggerHarness.py | 3 +- .../ide/activegrid/tool/DebuggerService.py | 41 +- .../ide/activegrid/tool/ExtensionService.py | 387 ++++++++++ wxPython/samples/ide/activegrid/tool/IDE.py | 5 +- .../ide/activegrid/tool/ProjectEditor.py | 19 +- .../samples/ide/activegrid/tool/UICommon.py | 10 +- .../samples/ide/activegrid/util/__init__.py | 25 +- .../samples/ide/activegrid/util/aglogging.py | 103 +++ wxPython/samples/ide/activegrid/util/lang.py | 67 ++ .../samples/ide/activegrid/util/objutils.py | 225 ++---- .../ide/activegrid/util/xmlmarshaller.py | 695 ++++++++++-------- .../ide/activegrid/util/xmlprettyprinter.py | 17 +- .../samples/ide/activegrid/util/xmlutils.py | 128 ++++ wxPython/samples/pydocview/PyDocViewDemo.py | 2 + wxPython/wx/lib/docview.py | 23 +- wxPython/wx/lib/pydocview.py | 12 +- 19 files changed, 1285 insertions(+), 533 deletions(-) create mode 100644 wxPython/samples/ide/activegrid/tool/ExtensionService.py create mode 100644 wxPython/samples/ide/activegrid/util/aglogging.py create mode 100644 wxPython/samples/ide/activegrid/util/lang.py create mode 100644 wxPython/samples/ide/activegrid/util/xmlutils.py diff --git a/wxPython/docs/CHANGES.txt b/wxPython/docs/CHANGES.txt index 3a9e0789ce..b187da09c6 100644 --- a/wxPython/docs/CHANGES.txt +++ b/wxPython/docs/CHANGES.txt @@ -20,11 +20,23 @@ Fixes for bug #1217872, pydocview.DocService not correctly initialized Fix for bug #1217874, Error in parameter name in DocManager.CreateView +Added wrappers for the wx.RendererNative class. + Added the wx.lib.splitter module, which contains the MultiSplitterWindow class. This class is much like the standard wx.SplitterWindow class, except it allows more than one split, so it can manage more than two child windows. +Docview and IDE patch from Morag Hua with fix for bug #1217890 +"Closing view crashes Python" plus some new features:: + + New feature added to the IDE is 'Extensions'. Under + Tools|Options|Extensions, you can add calls to external programs. + For example you can add a "Notepad" extension (under windows) that + will exec Notepad on the currently open file. A new "Notepad" + menu item will appear under the Tools menu. + + diff --git a/wxPython/samples/docview/DocViewDemo.py b/wxPython/samples/docview/DocViewDemo.py index 7fa1f5fc9b..ba7bb6623a 100644 --- a/wxPython/samples/docview/DocViewDemo.py +++ b/wxPython/samples/docview/DocViewDemo.py @@ -122,6 +122,7 @@ class TextEditView(wx.lib.docview.View): def OnDraw(self, dc): + """ For Print and Print Preview """ pass diff --git a/wxPython/samples/ide/activegrid/tool/AbstractEditor.py b/wxPython/samples/ide/activegrid/tool/AbstractEditor.py index 18fbf6d7fc..f8e9d16e4e 100644 --- a/wxPython/samples/ide/activegrid/tool/AbstractEditor.py +++ b/wxPython/samples/ide/activegrid/tool/AbstractEditor.py @@ -86,11 +86,15 @@ class CanvasView(wx.lib.docview.View): def OnFocus(self, event): - self.SetFocus() self.FocusColorPropertyShape(True) event.Skip() + def FocusOnClick(self, event): + self.SetFocus() + event.Skip() + + def OnKillFocus(self, event): self.FocusColorPropertyShape(False) event.Skip() @@ -129,12 +133,12 @@ class CanvasView(wx.lib.docview.View): wx.EVT_KEY_DOWN(self._canvas, self.OnKeyPressed) # need this otherwise mouse clicks don't set focus to this view - wx.EVT_LEFT_DOWN(self._canvas, self.OnFocus) - wx.EVT_LEFT_DCLICK(self._canvas, self.OnFocus) - wx.EVT_RIGHT_DOWN(self._canvas, self.OnFocus) - wx.EVT_RIGHT_DCLICK(self._canvas, self.OnFocus) - wx.EVT_MIDDLE_DOWN(self._canvas, self.OnFocus) - wx.EVT_MIDDLE_DCLICK(self._canvas, self.OnFocus) + wx.EVT_LEFT_DOWN(self._canvas, self.FocusOnClick) + wx.EVT_LEFT_DCLICK(self._canvas, self.FocusOnClick) + wx.EVT_RIGHT_DOWN(self._canvas, self.FocusOnClick) + wx.EVT_RIGHT_DCLICK(self._canvas, self.FocusOnClick) + wx.EVT_MIDDLE_DOWN(self._canvas, self.FocusOnClick) + wx.EVT_MIDDLE_DCLICK(self._canvas, self.FocusOnClick) wx.EVT_KILL_FOCUS(self._canvas, self.OnKillFocus) wx.EVT_SET_FOCUS(self._canvas, self.OnFocus) @@ -397,7 +401,7 @@ class CanvasView(wx.lib.docview.View): shape.SetBrush(brush) if text: shape.AddText(text) - shape.SetShadowMode(ogl.SHADOW_RIGHT) + shape.SetShadowMode(ogl.SHADOW_NONE) self._diagram.AddShape(shape) shape.Show(True) if not eventHandler: @@ -417,9 +421,28 @@ class CanvasView(wx.lib.docview.View): if shape: shape.Select(False) + for line in shape.GetLines(): + shape.RemoveLine(line) + self._diagram.RemoveShape(line) + for obj in self._diagram.GetShapeList(): + for line in obj.GetLines(): + if self.IsShapeContained(shape, line.GetTo()) or self.IsShapeContained(shape, line.GetFrom()): + obj.RemoveLine(line) + self._diagram.RemoveShape(line) + if line == shape: + obj.RemoveLine(line) + + shape.RemoveFromCanvas(self._canvas) self._diagram.RemoveShape(shape) - if isinstance(shape, ogl.CompositeShape): - shape.RemoveFromCanvas(self._canvas) + + + def IsShapeContained(self, parent, shape): + if parent == shape: + return True + elif shape.GetParent(): + return self.IsShapeContained(parent, shape.GetParent()) + + return False def UpdateShape(self, model): diff --git a/wxPython/samples/ide/activegrid/tool/DebuggerHarness.py b/wxPython/samples/ide/activegrid/tool/DebuggerHarness.py index 433c118dce..63452dcb9d 100644 --- a/wxPython/samples/ide/activegrid/tool/DebuggerHarness.py +++ b/wxPython/samples/ide/activegrid/tool/DebuggerHarness.py @@ -378,7 +378,8 @@ class DebuggerHarness(object): sys.stdout = output sys.stderr = output try: - exec command in frame.f_globals, frame.f_locals + code = compile(command, '', 'single') + exec code in frame.f_globals, frame.f_locals return output.getvalue() sys.stdout = out sys.stderr = err diff --git a/wxPython/samples/ide/activegrid/tool/DebuggerService.py b/wxPython/samples/ide/activegrid/tool/DebuggerService.py index 8da8bc2492..547d8c9912 100644 --- a/wxPython/samples/ide/activegrid/tool/DebuggerService.py +++ b/wxPython/samples/ide/activegrid/tool/DebuggerService.py @@ -41,7 +41,7 @@ import pickle import DebuggerHarness import traceback import StringIO - +import UICommon if wx.Platform == '__WXMSW__': try: import win32api @@ -132,8 +132,7 @@ import wx.lib.newevent class Executor: def GetPythonExecutablePath(): - config = wx.ConfigBase_Get() - path = config.Read("ActiveGridPythonLocation") + path = UICommon.GetPythonExecPath() if path: return path wx.MessageBox(_("To proceed I need to know the location of the python.exe you would like to use.\nTo set this, go to Tools-->Options and use the 'Python' tab to enter a value.\n"), _("Python Executable Location Unknown")) @@ -149,24 +148,29 @@ class Executor: path = Executor.GetPythonExecutablePath() self._cmd = '"' + path + '" -u \"' + fileName + '\"' #Better way to do this? Quotes needed for windows file paths. + def spaceAndQuote(text): + if text.startswith("\"") and text.endswith("\""): + return ' ' + text + else: + return ' \"' + text + '\"' if(arg1 != None): - self._cmd += ' \"' + arg1 + '\"' + self._cmd += spaceAndQuote(arg1) if(arg2 != None): - self._cmd += ' \"' + arg2 + '\"' + self._cmd += spaceAndQuote(arg2) if(arg3 != None): - self._cmd += ' \"' + arg3 + '\"' + self._cmd += spaceAndQuote(arg3) if(arg4 != None): - self._cmd += ' \"' + arg4 + '\"' + self._cmd += spaceAndQuote(arg4) if(arg5 != None): - self._cmd += ' \"' + arg5 + '\"' + self._cmd += spaceAndQuote(arg5) if(arg6 != None): - self._cmd += ' \"' + arg6 + '\"' + self._cmd += spaceAndQuote(arg6) if(arg7 != None): - self._cmd += ' \"' + arg7 + '\"' + self._cmd += spaceAndQuote(arg7) if(arg8 != None): - self._cmd += ' \"' + arg8 + '\"' + self._cmd += spaceAndQuote(arg8) if(arg9 != None): - self._cmd += ' \"' + arg9 + '\"' + self._cmd += spaceAndQuote(arg9) self._stdOutReader = None self._stdErrReader = None @@ -621,7 +625,7 @@ class DebugCommandUI(wx.Panel): self._tb.EnableTool(self.BREAK_INTO_DEBUGGER_ID, False) self._tb.EnableTool(self.KILL_PROCESS_ID, False) - def SynchCurrentLine(self, filename, lineNum): + def SynchCurrentLine(self, filename, lineNum, noArrow=False): # FACTOR THIS INTO DocManager self.DeleteCurrentLineMarkers() @@ -651,8 +655,9 @@ class DebugCommandUI(wx.Panel): foundView.Activate() foundView.GotoLine(lineNum) startPos = foundView.PositionFromLine(lineNum) - - foundView.GetCtrl().MarkerAdd(lineNum -1, CodeEditor.CodeCtrl.CURRENT_LINE_MARKER_NUM) + + if not noArrow: + foundView.GetCtrl().MarkerAdd(lineNum -1, CodeEditor.CodeCtrl.CURRENT_LINE_MARKER_NUM) def DeleteCurrentLineMarkers(self): openDocs = wx.GetApp().GetDocumentManager().GetDocuments() @@ -803,7 +808,7 @@ class BreakpointsUI(wx.Panel): list = self._bpListCtrl fileName = list.GetItem(self.currentItem, 2).GetText() lineNumber = list.GetItem(self.currentItem, 1).GetText() - self._ui.SynchCurrentLine( fileName, int(lineNumber) ) + self._ui.SynchCurrentLine( fileName, int(lineNumber) , noArrow=True) def ClearBreakPoint(self, event): if self.currentItem >= 0: @@ -1810,7 +1815,7 @@ class DebuggerService(Service.Service): wsService = wx.GetApp().GetService(WebServerService.WebServerService) fileName, args = wsService.StopAndPrepareToDebug() try: - page = DebugCommandUI(Service.ServiceView.bottomTab, -1, str(fileName), self) + page = DebugCommandUI(Service.ServiceView.bottomTab, -1, fileName, self) count = Service.ServiceView.bottomTab.GetPageCount() Service.ServiceView.bottomTab.AddPage(page, _("Debugging: Internal WebServer")) Service.ServiceView.bottomTab.SetSelection(count) @@ -2124,7 +2129,7 @@ class CommandPropertiesDialog(wx.Dialog): flexGridSizer.Add(self._pythonPathEntry, 1, wx.EXPAND) flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0) flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0) - if debugging: + if debugging and _WINDOWS: self._postpendCheckBox = wx.CheckBox(self, -1, postpendStaticText) checked = bool(config.ReadInt("PythonPathPostpend", 1)) self._postpendCheckBox.SetValue(checked) diff --git a/wxPython/samples/ide/activegrid/tool/ExtensionService.py b/wxPython/samples/ide/activegrid/tool/ExtensionService.py new file mode 100644 index 0000000000..b75e544585 --- /dev/null +++ b/wxPython/samples/ide/activegrid/tool/ExtensionService.py @@ -0,0 +1,387 @@ +#---------------------------------------------------------------------------- +# Name: ExtensionService.py +# Purpose: Extension Service for IDE +# +# Author: Peter Yared +# +# Created: 5/23/05 +# CVS-ID: $ID:$ +# Copyright: (c) 2005 ActiveGrid, Inc. +# License: wxWindows License +#---------------------------------------------------------------------------- + +import wx +import wx.lib.pydocview +import MessageService +import os +import os.path +import pickle + +_ = wx.GetTranslation + + +SPACE = 10 +HALF_SPACE = 5 + + +EXTENSIONS_CONFIG_STRING = "Extensions" + + + +# TODO: Redo extensions menu on OK, or provide alert that it won't happen until restart + + +#---------------------------------------------------------------------------- +# Classes +#---------------------------------------------------------------------------- + +class Extension: + + + def __init__(self, menuItemName): + self.menuItemName = menuItemName + self.id = 0 + self.menuItemDesc = '' + self.command = '' + self.commandPreArgs = '' + self.commandPostArgs = '' + self.fileExt = None + + +class ExtensionService(wx.lib.pydocview.DocService): + + + def __init__(self): + self.LoadExtensions() + + + def LoadExtensions(self): + config = wx.ConfigBase_Get() + pickledExtensions = config.Read(EXTENSIONS_CONFIG_STRING) + if pickledExtensions: + try: + self._extensions = pickle.loads(pickledExtensions.encode('ascii')) + except: + tp, val, tb = sys.exc_info() + traceback.print_exception(tp,val,tb) + self._extensions = [] + else: + self._extensions = [] + + + def SaveExtensions(self): + config = wx.ConfigBase_Get() + config.Write(EXTENSIONS_CONFIG_STRING, pickle.dumps(self._extensions)) + + + def GetExtensions(self): + return self._extensions + + + def SetExtensions(self, extensions): + self._extensions = extensions + + + def InstallControls(self, frame, menuBar = None, toolBar = None, statusBar = None, document = None): + toolsMenuIndex = menuBar.FindMenu(_("&Tools")) + if toolsMenuIndex > -1: + toolsMenu = menuBar.GetMenu(toolsMenuIndex) + else: + toolsMenu = wx.Menu() + + if self._extensions: + if toolsMenu.GetMenuItems(): + toolsMenu.AppendSeparator() + for ext in self._extensions: + # Append a tool menu item for each extension + ext.id = wx.NewId() + toolsMenu.Append(ext.id, ext.menuItemName) + wx.EVT_MENU(frame, ext.id, frame.ProcessEvent) + wx.EVT_UPDATE_UI(frame, ext.id, frame.ProcessUpdateUIEvent) + + if toolsMenuIndex == -1: + formatMenuIndex = menuBar.FindMenu(_("&Format")) + menuBar.Insert(formatMenuIndex + 1, toolsMenu, _("&Tools")) + + def ProcessEvent(self, event): + id = event.GetId() + for extension in self._extensions: + if id == extension.id: + self.OnExecuteExtension(extension) + return True + return False + + + def ProcessUpdateUIEvent(self, event): + id = event.GetId() + for extension in self._extensions: + if id == extension.id: + if extension.fileExt: + doc = wx.GetApp().GetDocumentManager().GetCurrentDocument() + if doc and '*' in extension.fileExt: + event.Enable(True) + return True + if doc: + for fileExt in extension.fileExt: + if fileExt in doc.GetDocumentTemplate().GetFileFilter(): + event.Enable(True) + return True + event.Enable(False) + return False + return False + + + def OnExecuteExtension(self, extension): + if extension.fileExt: + doc = wx.GetApp().GetDocumentManager().GetCurrentDocument() + if not doc: + return + filename = doc.GetFilename() + ext = os.path.splitext(filename)[1] + if not '*' in extension.fileExt: + if not ext or ext[1:] not in extension.fileExt: + return + cmds = [extension.command] + if extension.commandPreArgs: + cmds.append(extension.commandPreArgs) + cmds.append(filename) + if extension.commandPostArgs: + cmds.append(extension.commandPostArgs) + os.spawnv(os.P_NOWAIT, extension.command, cmds) + + else: + cmd = extension.command + if extension.commandPreArgs: + cmd = cmd + ' ' + extension.commandPreArgs + if extension.commandPostArgs: + cmd = cmd + ' ' + extension.commandPostArgs + f = os.popen(cmd) + messageService = wx.GetApp().GetService(MessageService.MessageService) + messageService.ShowWindow() + view = messageService.GetView() + for line in f.readlines(): + view.AddLines(line) + view.GetControl().EnsureCaretVisible() + f.close() + + +class ExtensionOptionsPanel(wx.Panel): + + + def __init__(self, parent, id): + wx.Panel.__init__(self, parent, id) + + extOptionsPanelBorderSizer = wx.BoxSizer(wx.HORIZONTAL) + + extOptionsPanelSizer = wx.FlexGridSizer(cols=2, hgap=SPACE, vgap=HALF_SPACE) + + extCtrlSizer = wx.BoxSizer(wx.VERTICAL) + extCtrlSizer.Add(wx.StaticText(self, -1, _("Extensions:")), 0) + self._extListBox = wx.ListBox(self, -1, size=(-1,185), style=wx.LB_SINGLE) + self.Bind(wx.EVT_LISTBOX, self.OnListBoxSelect, self._extListBox) + extCtrlSizer.Add(self._extListBox, 1, wx.TOP | wx.BOTTOM | wx.EXPAND, SPACE) + buttonSizer = wx.GridSizer(rows=1, hgap=10, vgap=5) + self._moveUpButton = wx.Button(self, -1, _("Move Up")) + self.Bind(wx.EVT_BUTTON, self.OnMoveUp, self._moveUpButton) + buttonSizer.Add(self._moveUpButton, 0) + self._moveDownButton = wx.Button(self, -1, _("Move Down")) + self.Bind(wx.EVT_BUTTON, self.OnMoveDown, self._moveDownButton) + buttonSizer.Add(self._moveDownButton, 0) + extCtrlSizer.Add(buttonSizer, 0, wx.ALIGN_CENTER | wx.BOTTOM, HALF_SPACE) + buttonSizer = wx.GridSizer(rows=1, hgap=10, vgap=5) + self._addButton = wx.Button(self, -1, _("Add")) + self.Bind(wx.EVT_BUTTON, self.OnAdd, self._addButton) + buttonSizer.Add(self._addButton, 0) + self._deleteButton = wx.Button(self, wx.ID_DELETE) + self.Bind(wx.EVT_BUTTON, self.OnDelete, self._deleteButton) + buttonSizer.Add(self._deleteButton, 0) + extCtrlSizer.Add(buttonSizer, 0, wx.ALIGN_CENTER) + extOptionsPanelSizer.Add(extCtrlSizer, 0) + + self._extDetailPanel = wx.Panel(self) + staticBox = wx.StaticBox(self._extDetailPanel, label=_("Selected Extension")) + staticBoxSizer = wx.StaticBoxSizer(staticBox) + self._extDetailPanel.SetSizer(staticBoxSizer) + extDetailSizer = wx.FlexGridSizer(cols=1, hgap=5, vgap=3) + staticBoxSizer.AddSizer(extDetailSizer, 0, wx.ALL, 5) + + extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Menu Item Name:"))) + self._menuItemNameTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1)) + extDetailSizer.Add(self._menuItemNameTextCtrl, 1, wx.EXPAND) + self.Bind(wx.EVT_TEXT, self.SaveCurrentItem, self._menuItemNameTextCtrl) + + extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Menu Item Description:"))) + self._menuItemDescTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1)) + extDetailSizer.Add(self._menuItemDescTextCtrl, 1, wx.EXPAND) + + extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Path:"))) + self._commandTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1)) + findFileButton = wx.Button(self._extDetailPanel, -1, _("Browse...")) + def OnBrowseButton(event): + fileDlg = wx.FileDialog(self, _("Choose an Executable:"), style=wx.OPEN | wx.HIDE_READONLY) + path = self._commandTextCtrl.GetValue() + if path: + fileDlg.SetPath(path) + if fileDlg.ShowModal() == wx.ID_OK: + self._commandTextCtrl.SetValue(fileDlg.GetPath()) + self._commandTextCtrl.SetInsertionPointEnd() + fileDlg.Destroy() + wx.EVT_BUTTON(findFileButton, -1, OnBrowseButton) + hsizer = wx.BoxSizer(wx.HORIZONTAL) + hsizer.Add(self._commandTextCtrl, 1, wx.EXPAND) + hsizer.Add(findFileButton, 0, wx.LEFT, HALF_SPACE) + extDetailSizer.Add(hsizer, 0) + + extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Pre Arguments:"))) + self._commandPreArgsTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1)) + extDetailSizer.Add(self._commandPreArgsTextCtrl, 1, wx.EXPAND) + + extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Post Arguments:"))) + self._commandPostArgsTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1)) + extDetailSizer.Add(self._commandPostArgsTextCtrl, 1, wx.EXPAND) + + extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("File Extensions (Comma Separated):"))) + self._fileExtTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1)) + self._fileExtTextCtrl.SetToolTipString(_("""For example: "txt, text" or "*" for all files""")) + extDetailSizer.Add(self._fileExtTextCtrl, 1, wx.EXPAND) + + extOptionsPanelSizer.Add(self._extDetailPanel, 0) + + extOptionsPanelBorderSizer.Add(extOptionsPanelSizer, 0, wx.ALL | wx.EXPAND, SPACE) + self.SetSizer(extOptionsPanelBorderSizer) + self.Layout() + parent.AddPage(self, _("Extensions")) + + if self.PopulateItems(): + self._extListBox.SetSelection(0) + self.OnListBoxSelect(None) + + + def OnOK(self, optionsDialog): + self.SaveCurrentItem() + extensionsService = wx.GetApp().GetService(ExtensionService) + oldExtensions = extensionsService.GetExtensions() + extensionsService.SetExtensions(self._extensions) + extensionsService.SaveExtensions() + if oldExtensions.__repr__() != self._extensions.__repr__(): + msgTitle = wx.GetApp().GetAppName() + if not msgTitle: + msgTitle = _("Document Options") + wx.MessageBox(_("Extension changes will not appear until the application is restarted."), + msgTitle, + wx.OK | wx.ICON_INFORMATION, + self.GetParent()) + + + def PopulateItems(self): + extensionsService = wx.GetApp().GetService(ExtensionService) + import copy + self._extensions = copy.deepcopy(extensionsService.GetExtensions()) + for extension in self._extensions: + self._extListBox.Append(extension.menuItemName, extension) + self._currentItem = None + self._currentItemIndex = -1 + return len(self._extensions) + + + def OnListBoxSelect(self, event): + self.SaveCurrentItem() + if not self._extListBox.GetSelections(): + self._currentItemIndex = -1 + self._currentItem = None + self._deleteButton.Enable(False) + self._moveUpButton.Enable(False) + self._moveDownButton.Enable(False) + else: + self._currentItemIndex = self._extListBox.GetSelection() + self._currentItem = self._extListBox.GetClientData(self._currentItemIndex) + self._deleteButton.Enable() + self._moveUpButton.Enable(self._extListBox.GetCount() > 1 and self._currentItemIndex > 0) + self._moveDownButton.Enable(self._extListBox.GetCount() > 1 and self._currentItemIndex < self._extListBox.GetCount() - 1) + self.LoadItem(self._currentItem) + + + def SaveCurrentItem(self, event=None): + extension = self._currentItem + if extension: + if extension.menuItemName != self._menuItemNameTextCtrl.GetValue(): + extension.menuItemName = self._menuItemNameTextCtrl.GetValue() + self._extListBox.SetString(self._currentItemIndex, extension.menuItemName) + extension.menuItemDesc = self._menuItemDescTextCtrl.GetValue() + extension.command = self._commandTextCtrl.GetValue() + extension.commandPreArgs = self._commandPreArgsTextCtrl.GetValue() + extension.commandPostArgs = self._commandPostArgsTextCtrl.GetValue() + fileExt = self._fileExtTextCtrl.GetValue().replace(' ','') + if not fileExt: + extension.fileExt = None + else: + extension.fileExt = fileExt.split(',') + + + def LoadItem(self, extension): + if extension: + self._menuItemDescTextCtrl.SetValue(extension.menuItemDesc or '') + self._commandTextCtrl.SetValue(extension.command or '') + self._commandPreArgsTextCtrl.SetValue(extension.commandPreArgs or '') + self._commandPostArgsTextCtrl.SetValue(extension.commandPostArgs or '') + if extension.fileExt: + self._fileExtTextCtrl.SetValue(extension.fileExt.__repr__()[1:-1].replace("'","")) # Make the list a string, strip the brakcet on either side + else: + self._fileExtTextCtrl.SetValue('') + self._menuItemNameTextCtrl.SetValue(extension.menuItemName or '') # Do the name last since it triggers the write event that updates the entire item + self._extDetailPanel.Enable() + else: + self._menuItemNameTextCtrl.SetValue('') + self._menuItemDescTextCtrl.SetValue('') + self._commandTextCtrl.SetValue('') + self._commandPreArgsTextCtrl.SetValue('') + self._commandPostArgsTextCtrl.SetValue('') + self._fileExtTextCtrl.SetValue('') + self._extDetailPanel.Enable(False) + + + def OnAdd(self, event): + self.SaveCurrentItem() + extensionNames = map(lambda extension: extension.menuItemName, self._extensions) + name = _("Untitled") + count = 1 + while name in extensionNames: + count = count + 1 + name = _("Untitled %s") % count + extension = Extension(name) + self._extensions.append(extension) + self._extListBox.Append(extension.menuItemName, extension) + self._extListBox.SetSelection(self._extListBox.GetCount() - 1) + self.OnListBoxSelect(None) + self._menuItemNameTextCtrl.SetFocus() + self._menuItemNameTextCtrl.SetSelection(-1, -1) + + + def OnDelete(self, event): + self._extListBox.Delete(self._currentItemIndex) + self._extensions.remove(self._currentItem) + self._currentItemIndex = min(self._currentItemIndex, self._extListBox.GetCount() - 1) + if self._currentItemIndex > -1: + self._extListBox.SetSelection(self._currentItemIndex) + self._currentItem = None # Don't update it since it no longer exists + self.OnListBoxSelect(None) + + + def OnMoveUp(self, event): + itemAboveString = self._extListBox.GetString(self._currentItemIndex - 1) + itemAboveData = self._extListBox.GetClientData(self._currentItemIndex - 1) + self._extListBox.Delete(self._currentItemIndex - 1) + self._extListBox.Insert(itemAboveString, self._currentItemIndex) + self._extListBox.SetClientData(self._currentItemIndex, itemAboveData) + self._currentItemIndex = self._currentItemIndex - 1 + self.OnListBoxSelect(None) # Reset buttons + + + def OnMoveDown(self, event): + itemBelowString = self._extListBox.GetString(self._currentItemIndex + 1) + itemBelowData = self._extListBox.GetClientData(self._currentItemIndex + 1) + self._extListBox.Delete(self._currentItemIndex + 1) + self._extListBox.Insert(itemBelowString, self._currentItemIndex) + self._extListBox.SetClientData(self._currentItemIndex, itemBelowData) + self._currentItemIndex = self._currentItemIndex + 1 + self.OnListBoxSelect(None) # Reset buttons diff --git a/wxPython/samples/ide/activegrid/tool/IDE.py b/wxPython/samples/ide/activegrid/tool/IDE.py index 1d68e31f87..4a9a5a45c8 100644 --- a/wxPython/samples/ide/activegrid/tool/IDE.py +++ b/wxPython/samples/ide/activegrid/tool/IDE.py @@ -81,6 +81,7 @@ class IDEApplication(wx.lib.pydocview.DocApp): import DebuggerService import AboutDialog import SVNService + import ExtensionService if not ACTIVEGRID_BASE_IDE: import DataModelEditor @@ -304,6 +305,7 @@ class IDEApplication(wx.lib.pydocview.DocApp): deploymentService = self.InstallService(DeploymentService.DeploymentService()) dataModelService = self.InstallService(DataModelEditor.DataModelService()) welcomeService = self.InstallService(WelcomeService.WelcomeService()) + extensionService = self.InstallService(ExtensionService.ExtensionService()) optionsService = self.InstallService(wx.lib.pydocview.DocOptionsService(supportedModes=wx.lib.docview.DOC_MDI)) aboutService = self.InstallService(wx.lib.pydocview.AboutService(AboutDialog.AboutDialog)) svnService = self.InstallService(SVNService.SVNService()) @@ -326,6 +328,7 @@ class IDEApplication(wx.lib.pydocview.DocApp): optionsService.AddOptionsPanel(STCTextEditor.TextOptionsPanel) optionsService.AddOptionsPanel(HtmlEditor.HtmlOptionsPanel) optionsService.AddOptionsPanel(SVNService.SVNOptionsPanel) + optionsService.AddOptionsPanel(ExtensionService.ExtensionOptionsPanel) filePropertiesService.AddCustomEventHandler(projectService) @@ -374,7 +377,7 @@ class IDEApplication(wx.lib.pydocview.DocApp): if os.path.exists(tips_path): wx.CallAfter(self.ShowTip, docManager.FindSuitableParent(), wx.CreateFileTipProvider(tips_path, 0)) - wx.UpdateUIEvent.SetUpdateInterval(200) # Overhead of updating menus was too much. Change to update every 200 milliseconds. + wx.UpdateUIEvent.SetUpdateInterval(400) # Overhead of updating menus was too much. Change to update every 400 milliseconds. return True diff --git a/wxPython/samples/ide/activegrid/tool/ProjectEditor.py b/wxPython/samples/ide/activegrid/tool/ProjectEditor.py index 4d88f9defc..9934eaade7 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.objutils +import activegrid.util.xmlutils import UICommon import Wizard import SVNService @@ -49,10 +49,10 @@ HALF_SPACE = 5 #---------------------------------------------------------------------------- def load(fileObject): - return activegrid.util.objutils.defaultLoad(fileObject) + return activegrid.util.xmlutils.defaultLoad(fileObject, knownTypes={"projectmodel" : ProjectModel}) def save(fileObject, projectModel): - activegrid.util.objutils.defaultSave(fileObject, projectModel, prettyPrint=True) + activegrid.util.xmlutils.defaultSave(fileObject, projectModel, prettyPrint=True, knownTypes={"projectmodel" : ProjectModel}) #---------------------------------------------------------------------------- @@ -1055,7 +1055,8 @@ class ProjectView(wx.lib.docview.View): descr = template.GetDescription() + _(" (") + template.GetFileFilter() + _(")") choices.append(descr) allfilter = allfilter + template.GetFileFilter() - choices.insert(0, _("All (%s)") % allfilter) + choices.insert(0, _("All (%s)") % allfilter) # first item + choices.append(_("Any (*.*)")) # last item filterChoice = wx.Choice(frame, -1, size=(250, -1), choices=choices) filterChoice.SetSelection(0) filterChoice.SetToolTipString(_("Select file type filter.")) @@ -1112,7 +1113,8 @@ class ProjectView(wx.lib.docview.View): paths = [] index = filterChoice.GetSelection() - if index: + lastIndex = filterChoice.GetCount()-1 + if index and index != lastIndex: # if not All or Any template = visibleTemplates[index-1] # do search in files on disk @@ -1121,7 +1123,7 @@ class ProjectView(wx.lib.docview.View): break for name in files: - if index == 0: # all + if index == 0: # All for template in visibleTemplates: if template.FileMatchesTemplate(name): filename = os.path.join(root, name) @@ -1132,6 +1134,11 @@ class ProjectView(wx.lib.docview.View): paths.append(filename) break + elif index == lastIndex: # Any + filename = os.path.join(root, name) + # if already in project, don't add it, otherwise undo will remove it from project even though it was already in it. + if not doc.IsFileInProject(filename): + paths.append(filename) else: # use selected filter if template.FileMatchesTemplate(name): filename = os.path.join(root, name) diff --git a/wxPython/samples/ide/activegrid/tool/UICommon.py b/wxPython/samples/ide/activegrid/tool/UICommon.py index 6b81a9b8cf..98f863a9da 100644 --- a/wxPython/samples/ide/activegrid/tool/UICommon.py +++ b/wxPython/samples/ide/activegrid/tool/UICommon.py @@ -14,6 +14,7 @@ import os import os.path import wx import ProjectEditor +import activegrid.util as utillib _ = wx.GetTranslation def CreateDirectoryControl( parent, fileLabel, dirLabel, fileExtension, startingName="", startingDirectory=""): @@ -117,4 +118,11 @@ def PluralName(name): return name[0:-1] + 'ies' else: return name + 's' - \ No newline at end of file + +def GetPythonExecPath(): + pythonExecPath = wx.ConfigBase_Get().Read("ActiveGridPythonLocation") + if not pythonExecPath: + pythonExecPath = utillib.pythonExecPath + return pythonExecPath + + diff --git a/wxPython/samples/ide/activegrid/util/__init__.py b/wxPython/samples/ide/activegrid/util/__init__.py index 4cda367b3c..943607976f 100644 --- a/wxPython/samples/ide/activegrid/util/__init__.py +++ b/wxPython/samples/ide/activegrid/util/__init__.py @@ -14,8 +14,10 @@ import traceback import sys import os -def _registerMainModuleDir(): - global mainModuleDir +def isWindows(): + return os.name == 'nt' + +def _generateMainModuleDir(): if sys.executable.find('python') != -1: utilModuleDir = os.path.dirname(__file__) if not os.path.isabs(utilModuleDir): @@ -25,5 +27,22 @@ def _registerMainModuleDir(): mainModuleDir = os.path.dirname(mainModuleDir) # Get rid of library.zip else: mainModuleDir = os.path.dirname(sys.executable) + return mainModuleDir + +mainModuleDir = _generateMainModuleDir() + + +def _generatePythonExecPath(): + if sys.executable.find('python') != -1: + pythonExecPath = sys.executable + else: + pythonExecPath = os.path.join(os.path.dirname(sys.executable), '3rdparty\python2.3\python') + return pythonExecPath + +pythonExecPath = _generatePythonExecPath() + +def getCommandNameForExecPath(execPath): + if isWindows(): + return '"%s"' % execPath + return execPath -_registerMainModuleDir() diff --git a/wxPython/samples/ide/activegrid/util/aglogging.py b/wxPython/samples/ide/activegrid/util/aglogging.py new file mode 100644 index 0000000000..e4b5e7fd47 --- /dev/null +++ b/wxPython/samples/ide/activegrid/util/aglogging.py @@ -0,0 +1,103 @@ +#---------------------------------------------------------------------------- +# Name: aglogging.py +# Purpose: Utilities to help with logging +# +# Author: Jeff Norton +# +# Created: 01/04/05 +# CVS-ID: $Id$ +# Copyright: (c) 2005 ActiveGrid, Inc. +# License: wxWindows License +#---------------------------------------------------------------------------- + +import sys +import os +import re +import traceback +import logging +from activegrid.util.lang import * + +LEVEL_FATAL = logging.FATAL +LEVEL_ERROR = logging.ERROR +LEVEL_WARN = logging.WARN +LEVEL_INFO = logging.INFO +LEVEL_DEBUG = logging.DEBUG + +TEST_MODE_NONE = 0 +TEST_MODE_DETERMINISTIC = 1 +TEST_MODE_NON_DETERMINISTIC = 2 + +global agTestMode +agTestMode = TEST_MODE_NONE + +def setTestMode(mode): + global agTestMode + agTestMode = mode + +def getTestMode(): + global agTestMode + return agTestMode + +def testMode(normalObj, testObj=None): + if getTestMode() > TEST_MODE_NONE: + return testObj + return normalObj + +pythonFileRefPattern = asString(r'(?<=File ")[^"]*(#[^#]*")(, line )[0-9]*') +phpFileRefPattern = asString(r'( in ).*#([^#]*#[^ ]*)(?= on line )') +pathSepPattern = os.sep +if (pathSepPattern == "\\"): + pathSepPattern = "\\\\" +pythonFileRefPattern = pythonFileRefPattern.replace("#", pathSepPattern) +pythonFileRefPattern = re.compile(pythonFileRefPattern) +phpFileRefPattern = phpFileRefPattern.replace("#", pathSepPattern) +phpFileRefPattern = re.compile(phpFileRefPattern) + +def removeFileRefs(str): + str = pythonFileRefPattern.sub(_fileNameReplacement, str) + str = phpFileRefPattern.sub(_fileNameReplacementPHP, str) + return str + +def removePHPFileRefs(str): + str = phpFileRefPattern.sub(_fileNameReplacementPHP, str) + return str + +def _fileNameReplacement(match): + return "...%s" % match.group(1).replace(os.sep, "/") + +def _fileNameReplacementPHP(match): + return "%s...%s" % (match.group(1), match.group(2).replace(os.sep, "/")) + +def getTraceback(): + extype, val, tb = sys.exc_info() + tbs = "\n" + for s in traceback.format_tb(tb): + tbs += s + return tbs + +def reportException(out=None, stacktrace=False, diffable=False, exception=None): + if (True): # exception == None): + extype, val, t = sys.exc_info() + else: + extype = type(exception) + val = exception + if (stacktrace): + e,v,t = sys.exc_info() + if (diffable): + exstr = removeFileRefs(str(val)) + else: + exstr = str(val) + if (out == None): + print "Got Exception = %s: %s" % (extype, exstr) + else: + print >> out, "Got Exception = %s: %s" % (extype, exstr) + if (stacktrace): + fmt = traceback.format_exception(extype, val, t) + for s in fmt: + if (diffable): + s = removeFileRefs(s) + if (out == None): + print s + else: + print >> out, s + diff --git a/wxPython/samples/ide/activegrid/util/lang.py b/wxPython/samples/ide/activegrid/util/lang.py new file mode 100644 index 0000000000..56777fa370 --- /dev/null +++ b/wxPython/samples/ide/activegrid/util/lang.py @@ -0,0 +1,67 @@ +#---------------------------------------------------------------------------- +# Name: lang.py +# Purpose: Active grid language specific utilities -- provides portability +# for common idiom's that have language specific implementations +# +# Author: Jeff Norton +# +# Created: 04/27/05 +# CVS-ID: $Id$ +# Copyright: (c) 2004-2005 ActiveGrid, Inc. +# License: wxWindows License +#---------------------------------------------------------------------------- + +def isMain(caller): + return caller == '__main__' + +def ag_className(obj): + return obj.__class__.__name__ + +def asDict(src): + return src + +def asList(src): + return src + +def asTuple(src): + return src + +def asString(src): + return src + +def asInt(src): + return src + +def asBool(src): + return src + +def asObject(src): + return src + +def cast(src, type): + return src + +def asRef(src): + return src + +def asClass(src): + return src + +def localize(text): + return text + +# Pass in Python code as a string. The cross-compiler will convert to PHP +# and in-line the result. +def pyToPHP(expr): + pass + +# Pass in PHP code as a string. The cross-compiler will drop it in-line verbatim. +def PHP(expr): + pass + +# Bracket Python only code. The Cross-compiler will ignore the bracketed code. +def ifDefPy(comment=False): + pass + +def endIfDef(): + pass diff --git a/wxPython/samples/ide/activegrid/util/objutils.py b/wxPython/samples/ide/activegrid/util/objutils.py index 97bd2f79e0..9658aa2a2a 100644 --- a/wxPython/samples/ide/activegrid/util/objutils.py +++ b/wxPython/samples/ide/activegrid/util/objutils.py @@ -14,98 +14,7 @@ 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 = defaultUnmarshal(xml, knownTypes=knownTypes) - if hasattr(fileObject, 'name'): - loadedObject.fileName = os.path.abspath(fileObject.name) - loadedObject.initialize() - return loadedObject - -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'): - clonedObject.fileName = objectToClone.fileName - try: - clonedObject.initialize() - except AttributeError: - pass - return clonedObject +from types import * def classForName(className): pathList = className.split('.') @@ -115,31 +24,6 @@ def classForName(className): code = code.__dict__[name] return code -def hasattrignorecase(object, name): - namelow = name.lower() - for attr in dir(object): - if attr.lower() == namelow: - return True - for attr in dir(object): - if attr.lower() == '_' + namelow: - return True - return False - -def setattrignorecase(object, name, value): - namelow = name.lower() - for attr in object.__dict__: - if attr.lower() == namelow: - object.__dict__[attr] = value - return - object.__dict__[name] = value - -def getattrignorecase(object, name): - namelow = name.lower() - for attr in object.__dict__: - if attr.lower() == namelow: - return object.__dict__[attr] - return object.__dict__[name] - def hasPropertyValue(obj, attr): hasProp = False try: @@ -159,7 +43,7 @@ def hasPropertyValue(obj, attr): return hasProp def toDiffableString(value): - s = repr(value) + s = str(value) ds = "" i = s.find(" at 0x") start = 0 @@ -171,19 +55,51 @@ def toDiffableString(value): start = j i = s.find(" at 0x", start) return ds + s[start:] - + +def toString(value, options=0): + if ((options & PRINT_OBJ_DIFFABLE) > 0): + return toDiffableString(value) + return value + +def toTypeString(obj): + if (isinstance(obj, BooleanType)): + return "bool" + elif (isinstance(obj, UnicodeType)): + return "unicode" + elif (isinstance(obj, basestring)): + return "string" + elif (isinstance(obj, IntType)): + return "int" + elif (isinstance(obj, FloatType)): + return "float" + elif (type(obj) == ListType): + return "list" + elif (isinstance(obj, DictType)): + return "dict" + elif (isinstance(obj, TupleType)): + return "tuple" + elif (isinstance(obj, InstanceType)): + return type(obj) + else: + return type(obj) + PRINT_OBJ_GETATTR = 1 PRINT_OBJ_HIDE_INTERNAL = 2 PRINT_OBJ_COMPACT = 4 PRINT_OBJ_NONONE = 8 +PRINT_OBJ_DIFFABLE = 16 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) + print >> out, " "*indent, "%s: %s" % (name, toString(str(object), flags)), + if ((flags & PRINT_OBJ_INTERNAL) == 0): + print >> out return True finalNewLine = False printed = True +## if (exclude == None): +## exclude = [] if ((flags & PRINT_OBJ_COMPACT) > 0): if (exclude and object in exclude): return @@ -191,7 +107,7 @@ def printObject(out, object, name="", indent=0, flags=0, exclude=None, maxIndent if ((flags & PRINT_OBJ_INTERNAL) == 0): finalNewLine = True flags |= PRINT_OBJ_INTERNAL - if (object == None): + if (object is None): if (flags & PRINT_OBJ_NONONE) == 0: print >> out, " "*indent, name, " = None", else: @@ -201,21 +117,21 @@ def printObject(out, object, name="", indent=0, flags=0, exclude=None, maxIndent 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)", + if ((exclude != None) and object in exclude): + print >> out, " "*indent, name, " : ", toTypeString(object), " of length = ", len(object), " (already printed)", + elif ((exclude != None) and name in exclude): + print >> out, " "*indent, name, " : ", toTypeString(object), " of length = ", len(object), " (excluded)", else: - if (exclude != None): exclude.append(object) - print >> out, " "*indent, name, " : ", type(object), " of length = %i" % len(object), + if ((exclude != None) and (len(object) > 0)): exclude.append(object) + print >> out, " "*indent, name, " : ", toTypeString(object), " of length = %d" % 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) + printObject(out, o, name="[%d]" % 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)", + if ((exclude != None) and object in exclude): + print >> out, " "*indent, name, " : ", toTypeString(object), " (already printed)", else: - if (exclude != None): exclude.append(object) + if ((exclude != None) and (len(object) > 0)): exclude.append(object) if (len(name) > 0): print >> out, " "*indent, name, if ((flags & PRINT_OBJ_COMPACT) == 0): @@ -226,25 +142,29 @@ def printObject(out, object, name="", indent=0, flags=0, exclude=None, maxIndent 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, ",", + for key in keys: + if (key != None): + n = key + if (not (isinstance(n, basestring))): + n = str(n) + if ((not n.startswith("_") or ((flags & PRINT_OBJ_HIDE_INTERNAL) == 0))): + if printObject(out, object[key], name=n, indent=indent+2, flags=(flags | PRINT_OBJ_INTERNAL), 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), + if ((exclude != None) and object in exclude): + print >> out, " "*indent, name, " : ", toTypeString(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)", + if (name.startswith("_")): ## and ((flags & PRINT_OBJ_HIDE_INTERNAL) > 0)): + print >> out, " "*indent, name, " : ", toTypeString(object), + elif ((exclude != None) and object.__dict__ in exclude): + print >> out, " "*indent, name, " : ", toTypeString(object), " (already printed)", else: - print >> out, " "*indent, name, " : ", type(object), + print >> out, " "*indent, name, " : ", toTypeString(object), if ((flags & PRINT_OBJ_GETATTR) == 0): if ((flags & PRINT_OBJ_COMPACT) == 0): print >> out @@ -259,14 +179,19 @@ def printObject(out, object, name="", indent=0, flags=0, exclude=None, 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)", + if ((exclude != None) and name in exclude): + print >> out, " "*indent, name, " : ", toTypeString(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:]), + print >> out, " "*indent, name, ":", toTypeString(object), "[%d] = %s...%s" % (len(object), object[:50], object[-50:]), else: - print >> out, " "*indent, name, ":", type(object), "=", str(object), + print >> out, " "*indent, name, ":", toTypeString(object), "=", str(object), +## elif (isinstance(object, float)): +## val = str(object) +## if (len(val) > 17): +## val = val[:17] +## print >> out, " "*indent, name, ":", type(object), "=", val, else: - print >> out, " "*indent, name, ":", type(object), "=", str(object), + print >> out, " "*indent, name, ":", toTypeString(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 1b9cd67d45..266418a1eb 100644 --- a/wxPython/samples/ide/activegrid/util/xmlmarshaller.py +++ b/wxPython/samples/ide/activegrid/util/xmlmarshaller.py @@ -12,20 +12,19 @@ import __builtin__ import sys from types import * +import logging import xml.sax import xml.sax.handler -from xml.sax import saxutils - -import objutils +import xml.sax.saxutils as saxutils +from activegrid.util.lang import * +import activegrid.util.aglogging as aglogging MODULE_PATH = "__main__" -### ToDO remove maxOccurs "unbounded" resolves to -1 hacks after bug 177 is fixed +## ToDO remove maxOccurs "unbounded" resolves to -1 hacks after bug 177 is fixed """ - -More documentation later, but here are some special Python attributes -that McLane recognizes: +Special attributes that we recognize: name: __xmlname__ type: string @@ -33,26 +32,26 @@ description: the name of the xml element for the marshalled object name: __xmlattributes__ type: tuple or list -description: the name(s) of the Python string attribute(s) to be +description: the name(s) of the Lang string attribute(s) to be marshalled as xml attributes instead of nested xml elements. currently -these can only be strings since there's not a way to get the type +these can only be strings since there"s not a way to get the type information back when unmarshalling. name: __xmlexclude__ type: tuple or list -description: the name(s) of the python attribute(s) to skip when +description: the name(s) of the lang attribute(s) to skip when marshalling. name: __xmlrename__ type: dict -description: describes an alternate Python <-> XML name mapping. +description: describes an alternate Lang <-> XML name mapping. Normally the name mapping is the identity function. __xmlrename__ -overrides that. The keys are the Python names, the values are their +overrides that. The keys are the Lang names, the values are their associated XML names. name: __xmlflattensequence__ type: dict, tuple, or list -description: the name(s) of the Python sequence attribute(s) whose +description: the name(s) of the Lang sequence attribute(s) whose items are to be marshalled as a series of xml elements (with an optional keyword argument that specifies the element name to use) as opposed to containing them in a separate sequence element, e.g.: @@ -60,12 +59,12 @@ opposed to containing them in a separate sequence element, e.g.: myseq = (1, 2) - 1 - 2 + 1 + 2 - -1 -2 + +1 +2 name: __xmlnamespaces__ type: dict @@ -82,10 +81,10 @@ should be used as the default namespace for the object. name: __xmlattrnamespaces__ type: dict -description: a dict assigning the Python object's attributes to the namespaces +description: a dict assigning the Lang object"s attributes to the namespaces defined in __xmlnamespaces__. Each item in the dict should consist of a prefix,attributeList combination where the key is the prefix and the value is -a list of the Python attribute names. e.g.: +a list of the Lang attribute names. e.g.: __xmlattrnamespaces__ = { "ag":["firstName", "lastName", "addressLine1", "city"] } @@ -99,6 +98,14 @@ __xmlattrgroups__ = {"name": ["firstName", "lastName"], "address": ["addressLine """ +global xmlMarshallerLogger +xmlMarshallerLogger = logging.getLogger("activegrid.util.xmlmarshaller.marshal") +xmlMarshallerLogger.setLevel(aglogging.LEVEL_WARN) +# INFO : low-level info +# DEBUG : debugging info + +global knownGlobalTypes + ################################################################################ # # module exceptions @@ -119,7 +126,7 @@ class UnhandledTypeException(Error): return "%s is not supported for marshalling." % str(self.typename) class XMLAttributeIsNotStringType(Error): - """Exception raised when an object's attribute is specified to be + """Exception raised when an object"s attribute is specified to be marshalled as an XML attribute of the enclosing object instead of a nested element. """ @@ -128,27 +135,33 @@ class XMLAttributeIsNotStringType(Error): self.typename = typename def __str__(self): return """%s was set to be marshalled as an XML attribute - instead of a nested element, but the object's type is %s, not + instead of a nested element, but the object"s type is %s, not string.""" % (self.attrname, self.typename) +class MarshallerException(Exception): + pass + ################################################################################ # # constants and such # ################################################################################ -XMLNS = 'xmlns' -XMLNS_PREFIX = XMLNS + ':' +XMLNS = "xmlns" +XMLNS_PREFIX = XMLNS + ":" XMLNS_PREFIX_LENGTH = len(XMLNS_PREFIX) -BASETYPE_ELEMENT_NAME = 'item' +BASETYPE_ELEMENT_NAME = "item" +DICT_ITEM_NAME = "qqDictItem" +DICT_ITEM_KEY_NAME = "key" +DICT_ITEM_VALUE_NAME = "value" -# This list doesn't seem to be used. +# This list doesn"t seem to be used. # Internal documentation or useless? You make the call! -MEMBERS_TO_SKIP = ('__module__', '__doc__', '__xmlname__', '__xmlattributes__', - '__xmlexclude__', '__xmlflattensequence__', '__xmlnamespaces__', - '__xmldefaultnamespace__', '__xmlattrnamespaces__', - '__xmlattrgroups__') +##MEMBERS_TO_SKIP = ("__module__", "__doc__", "__xmlname__", "__xmlattributes__", +## "__xmlexclude__", "__xmlflattensequence__", "__xmlnamespaces__", +## "__xmldefaultnamespace__", "__xmlattrnamespaces__", +## "__xmlattrgroups__") ################################################################################ # @@ -156,73 +169,94 @@ MEMBERS_TO_SKIP = ('__module__', '__doc__', '__xmlname__', '__xmlattributes__', # ################################################################################ +def setattrignorecase(object, name, value): + if (name not in object.__dict__): + namelow = name.lower() + for attr in object.__dict__: + if attr.lower() == namelow: + object.__dict__[attr] = value + return + object.__dict__[name] = value + +def getComplexType(obj): + if (hasattr(obj, "__xsdcomplextype__")): + return obj.__xsdcomplextype__ + return None + def _objectfactory(objname, objargs=None, xsname=None): - '''dynamically create an object based on the objname and return - it. look it up in the BASETYPE_ELEMENT_MAP first. - ''' - # split the objname into the typename and module path, - # importing the module if need be. + "dynamically create an object based on the objname and return it." + if not isinstance(objargs, list): objargs = [objargs] - - if (xsname): - try: - objname = knownGlobalTypes[xsname] - except KeyError: - pass - -## print "[objectfactory] creating an object of type %s and value %s, xsname=%s" % (objname, objargs, xsname) - objtype = objname.split('.')[-1] - pathlist = objname.split('.') - modulename = '.'.join(pathlist[0:-1]) +## print "[objectfactory] xsname [%s]; objname [%s]" % (xsname, objname) + + # (a) deal with tagName:knownTypes mappings + if (xsname != None): + objclass = knownGlobalTypes.get(xsname) + if (objclass != None): + if (objargs != None): + return objclass(*objargs) + else: + return objclass() + + # (b) next with intrinisic types + if objname == "str" or objname == "unicode": # don"t strip: blanks are significant + if len(objargs) > 0: + return saxutils.unescape(objargs[0]).encode() + else: + return "" + elif objname == "bool": + return not objargs[0].lower() == "false" + elif objname in ("float", "int", "long"): +## objargs = [x.strip() for x in objargs] + return __builtin__.__dict__[objname](*objargs) + elif objname == "None": + return None + + # (c) objtype=path...module.class + # split the objname into the typename and module path, + # importing the module if need be. +## print "[objectfactory] creating an object of type %s and value %s, xsname=%s" % (objname, objargs, xsname) + objtype = objname.split(".")[-1] + pathlist = objname.split(".") + modulename = ".".join(pathlist[0:-1]) ## print "[objectfactory] object [%s] %s(%r)" % (objname, objtype, objargs) - if objname == 'bool': - return not objargs[0].lower() == 'false' - elif objname == 'str': # don't strip strings - blanks are significant !!! - if len(objargs) > 0: - return saxutils.unescape(objargs[0]).encode() - else: - return '' - elif objname == 'unicode': # don't strip strings - blanks are significant !!! - if len(objargs) > 0: - return saxutils.unescape(objargs[0]).encode() - else: - return '' - elif objtype in ('float', 'int', 'str', 'long'): - objargs = [x.strip() for x in objargs] try: - if __builtin__.__dict__.has_key(objname): - module = __builtin__ - elif knownGlobalModule: - module = knownGlobalModule - else: - if modulename: - module = __import__(modulename) + if modulename: + module = __import__(modulename) for name in pathlist[1:-1]: module = module.__dict__[name] + elif __builtin__.__dict__.has_key(objname): + module = __builtin__ + else: + raise MarshallerException("Could not find class %s" % objname) if objargs: return module.__dict__[objtype](*objargs) else: - if objtype == 'None': - return None return module.__dict__[objtype]() except KeyError: - raise KeyError("Could not find class %s" % objname) + raise MarshallerException("Could not find class %s" % objname) class Element: + def __init__(self, name, attrs=None): self.name = name self.attrs = attrs - self.content = '' + self.content = "" self.children = [] + def getobjtype(self): - if self.attrs.has_key('objtype'): - return self.attrs.getValue('objtype') - else: - return 'str' - def toString(self): + objtype = self.attrs.get("objtype") + if (objtype == None): + if (len(self.children) > 0): + objtype = "dict" + else: + objtype = "str" + return objtype + + def __str__(self): print " name = ", self.name, "; attrs = ", self.attrs, "number of children = ", len(self.children) i = -1 for child in self.children: @@ -237,7 +271,7 @@ class XMLObjectFactory(xml.sax.ContentHandler): self.elementstack = [] xml.sax.handler.ContentHandler.__init__(self) - def toString(self): + def __str__(self): print "-----XMLObjectFactory Dump-------------------------------" if (self.rootelement == None): print "rootelement is None" @@ -248,14 +282,14 @@ class XMLObjectFactory(xml.sax.ContentHandler): for e in self.elementstack: i = i + 1 print "elementstack[", i, "]: " - e.toString() + str(e) print "-----end XMLObjectFactory--------------------------------" ## ContentHandler methods def startElement(self, name, attrs): ## print "startElement for name: ", name - if name.find(':') > -1: # Strip namespace prefixes for now until actually looking them up in xsd - name = name[name.index(':') + 1:] + if name.find(":") > -1: # Strip namespace prefixes for now until actually looking them up in xsd + name = name[name.find(":") + 1:] ## for attrname in attrs.getNames(): ## print "%s: %s" % (attrname, attrs.getValue(attrname)) element = Element(name, attrs.copy()) @@ -263,15 +297,15 @@ class XMLObjectFactory(xml.sax.ContentHandler): ## print self.elementstack def characters(self, content): -## print "got content: %s" % content - if content: +## print "got content: %s (%s)" % (content, type(content)) + if (content != None): self.elementstack[-1].content += content def endElement(self, name): -## print "[endElement] name of element we're at the end of: %s" % name +## print "[endElement] name of element we"re at the end of: %s" % name xsname = name - if name.find(':') > -1: # Strip namespace prefixes for now until actually looking them up in xsd - name = name[name.index(':') + 1:] + if name.find(":") > -1: # Strip namespace prefixes for now until actually looking them up in xsd + name = name[name.find(":") + 1:] oldChildren = self.elementstack[-1].children element = self.elementstack.pop() if ((len(self.elementstack) > 1) and (self.elementstack[-1].getobjtype() == "None")): @@ -285,29 +319,18 @@ class XMLObjectFactory(xml.sax.ContentHandler): ## print "[endElement] %s: skipping a (objtype==None) end tag" % name return constructorarglist = [] - if element.content: + if (len(element.content) > 0): strippedElementContent = element.content.strip() - if strippedElementContent: + if (len(strippedElementContent) > 0): constructorarglist.append(element.content) ## print "[endElement] calling objectfactory" obj = _objectfactory(objtype, constructorarglist, xsname) - complexType = None - if hasattr(obj, '__xsdcomplextype__'): - complexType = getattr(obj, '__xsdcomplextype__') - if (hasattr(obj, '__xmlname__') and getattr(obj, '__xmlname__') == "sequence"): -## print "[endElement] sequence found" -## self.toString() + complexType = getComplexType(obj) + if (obj != None): + if (hasattr(obj, "__xmlname__") and getattr(obj, "__xmlname__") == "sequence"): self.elementstack[-1].children = oldChildren -## self.toString() -## print "done moving sequence stuff; returning" return - if len(self.elementstack) > 0: -## print "[endElement] appending child with name: ", name, "; objtype: ", objtype - parentElement.children.append((name, obj)) -## print "parentElement now has ", len(parentElement.children), " children" - else: - self.rootelement = obj - if element.attrs and not isinstance(obj, list): + if (len(element.attrs) > 0) and not isinstance(obj, list): ## print "[endElement] %s: element has attrs and the obj is not a list" % name for attrname, attr in element.attrs.items(): if attrname == XMLNS or attrname.startswith(XMLNS_PREFIX): @@ -315,77 +338,101 @@ class XMLObjectFactory(xml.sax.ContentHandler): ns = attrname[XMLNS_PREFIX_LENGTH:] else: ns = "" - if not hasattr(obj, '__xmlnamespaces__'): + if not hasattr(obj, "__xmlnamespaces__"): obj.__xmlnamespaces__ = {ns:attr} elif ns not in obj.__xmlnamespaces__: - if (hasattr(obj.__class__, '__xmlnamespaces__') - and obj.__xmlnamespaces__ is obj.__class__.__xmlnamespaces__): - obj.__xmlnamespaces__ = dict(obj.__xmlnamespaces__) + if (hasattr(obj.__class__, "__xmlnamespaces__") + and (obj.__xmlnamespaces__ is obj.__class__.__xmlnamespaces__)): + obj.__xmlnamespaces__ = dict(obj.__xmlnamespaces__) obj.__xmlnamespaces__[ns] = attr - elif not attrname == 'objtype': - if attrname.find(':') > -1: # Strip namespace prefixes for now until actually looking them up in xsd - attrname = attrname[attrname.index(':') + 1:] - if complexType: + elif not attrname == "objtype": + if attrname.find(":") > -1: # Strip namespace prefixes for now until actually looking them up in xsd + attrname = attrname[attrname.find(":") + 1:] + if (complexType != None): xsdElement = complexType.findElement(attrname) - if xsdElement: + if (xsdElement != None): type = xsdElement.type - if type: - type = xsdToPythonType(type) + if (type != None): + type = xsdToLangType(type) ### ToDO remove maxOccurs hack after bug 177 is fixed if attrname == "maxOccurs" and attr == "unbounded": attr = "-1" attr = _objectfactory(type, attr) - objutils.setattrignorecase(obj, _toAttrName(obj, attrname), attr) + try: + setattrignorecase(obj, _toAttrName(obj, attrname), attr) + except AttributeError: + raise MarshallerException("Error unmarshalling attribute \"%s\" of XML element \"%s\": object type not specified or known" % (attrname, name)) ## obj.__dict__[_toAttrName(obj, attrname)] = attr # stuff any child attributes meant to be in a sequence via the __xmlflattensequence__ flattenDict = {} - if hasattr(obj, '__xmlflattensequence__'): + if hasattr(obj, "__xmlflattensequence__"): + flatten = obj.__xmlflattensequence__ ## print "[endElement] %s: obj has __xmlflattensequence__" % name - if (isinstance(obj.__xmlflattensequence__,dict)): -## print "[endElement] dict with obj.__xmlflattensequence__.items: ", obj.__xmlflattensequence__.items() - for sequencename, xmlnametuple in obj.__xmlflattensequence__.items(): - for xmlname in xmlnametuple: -## print "[endElement]: adding flattenDict[%s] = %s" % (xmlname, sequencename) - flattenDict[xmlname] = sequencename - # handle __xmlflattensequence__ list/tuple (i.e. no element rename) - elif (isinstance(obj.__xmlflattensequence__,list) or isinstance(obj.__xmlflattensequence__,tuple)): - for sequencename in obj.__xmlflattensequence__: - flattenDict[sequencename] = sequencename + if (isinstance(flatten, dict)): +## print "[endElement] dict with flatten.items: ", flatten.items() + for sequencename, xmlnametuple in flatten.items(): + if (xmlnametuple == None): + flattenDict[sequencename] = sequencename + elif (not isinstance(xmlnametuple, (tuple, list))): + flattenDict[str(xmlnametuple)] = sequencename + else: + for xmlname in xmlnametuple: + ## print "[endElement]: adding flattenDict[%s] = %s" % (xmlname, sequencename) + flattenDict[xmlname] = sequencename else: - raise "Invalid type for __xmlflattensequence___ : it must be a dict, list, or tuple" + raise "Invalid type for __xmlflattensequence___ : it must be a dict" - # reattach an object's attributes to it + # reattach an object"s attributes to it for childname, child in element.children: ## print "[endElement] childname is: ", childname, "; child is: ", child - if flattenDict.has_key(childname): + if (childname in flattenDict): sequencename = _toAttrName(obj, flattenDict[childname]) ## print "[endElement] sequencename is: ", sequencename - try: + if (not hasattr(obj, sequencename)): ## print "[endElement] obj.__dict__ is: ", obj.__dict__ - sequencevalue = obj.__dict__[sequencename] - except (AttributeError, KeyError): - sequencevalue = None - if sequencevalue == None: - sequencevalue = [] - obj.__dict__[sequencename] = sequencevalue + obj.__dict__[sequencename] = [] + sequencevalue = getattr(obj, sequencename) + if (sequencevalue == None): + obj.__dict__[sequencename] = [] + sequencevalue = getattr(obj, sequencename) sequencevalue.append(child) - elif isinstance(obj, list): -## print "appended childname = ", childname + elif (objtype == "list"): obj.append(child) + elif isinstance(obj, dict): + if (childname == DICT_ITEM_NAME): + obj[child[DICT_ITEM_KEY_NAME]] = child[DICT_ITEM_VALUE_NAME] + else: + obj[childname] = child else: ## print "childname = %s, obj = %s, child = %s" % (childname, repr(obj), repr(child)) - objutils.setattrignorecase(obj, _toAttrName(obj, childname), child) - obj.__dict__[_toAttrName(obj, childname)] = child + try: + setattrignorecase(obj, _toAttrName(obj, childname), child) + except AttributeError: + raise MarshallerException("Error unmarshalling child element \"%s\" of XML element \"%s\": object type not specified or known" % (childname, name)) +## obj.__dict__[_toAttrName(obj, childname)] = child - if complexType: + if (complexType != None): for element in complexType.elements: if element.default: elementName = _toAttrName(obj, element.name) if ((elementName not in obj.__dict__) or (obj.__dict__[elementName] == None)): - pythonType = xsdToPythonType(element.type) - defaultValue = _objectfactory(pythonType, element.default) + langType = xsdToLangType(element.type) + defaultValue = _objectfactory(langType, element.default) obj.__dict__[elementName] = defaultValue + ifDefPy() + if (isinstance(obj, list)): + if ((element.attrs.has_key("mutable")) and (element.attrs.getValue("mutable") == "false")): + obj = tuple(obj) + endIfDef() + + if (len(self.elementstack) > 0): +## print "[endElement] appending child with name: ", name, "; objtype: ", objtype + parentElement.children.append((name, obj)) +## print "parentElement now has ", len(parentElement.children), " children" + else: + self.rootelement = obj + def getRootObject(self): return self.rootelement @@ -399,11 +446,11 @@ def _toAttrName(obj, name): ## name = "_%s%s" % (obj.__class__.__name__, name) return name -__typeMappingXsdToPython = { +__typeMappingXsdToLang = { "string": "str", "char": "str", "varchar": "str", - "date": "str", # ToDO Need to work out how to create python date types + "date": "str", # ToDO Need to work out how to create lang date types "boolean": "bool", "decimal": "float", # ToDO Does python have a better fixed point type? "int": "int", @@ -419,86 +466,86 @@ __typeMappingXsdToPython = { "double": "float", } -def xsdToPythonType(xsdType): - try: - return __typeMappingXsdToPython[xsdType] - except KeyError: +def xsdToLangType(xsdType): + langType = __typeMappingXsdToLang.get(xsdType) + if (langType == None): raise Exception("Unknown xsd type %s" % xsdType) + return langType -def _getXmlValue(pythonValue): - if (isinstance(pythonValue, bool)): - return str(pythonValue).lower() - elif (isinstance(pythonValue, unicode)): - return pythonValue.encode() +def _getXmlValue(langValue): + if (isinstance(langValue, bool)): + return str(langValue).lower() + elif (isinstance(langValue, unicode)): + return langValue.encode() else: - return str(pythonValue) + return str(langValue) -def unmarshal(xmlstr, knownTypes=None, knownModule=None): - global knownGlobalTypes, knownGlobalModule +def unmarshal(xmlstr, knownTypes=None): + global knownGlobalTypes if (knownTypes == None): knownGlobalTypes = {} else: knownGlobalTypes = knownTypes - knownGlobalModule = knownModule objectfactory = XMLObjectFactory() xml.sax.parseString(xmlstr, objectfactory) return objectfactory.getRootObject() -def marshal(obj, elementName=None, prettyPrint=False, indent=0, knownTypes=None, withEncoding=True, encoding=None): - xmlstr = ''.join(_marshal(obj, elementName, prettyPrint=prettyPrint, indent=indent, knownTypes=knownTypes)) - if withEncoding: - if encoding is None: - return '\n%s' % (sys.getdefaultencoding(), xmlstr) - else: - return '\n%s' % (encoding, xmlstr.encode(encoding)) - else: +def marshal(obj, elementName=None, prettyPrint=False, indent=0, knownTypes=None, encoding=-1): + xmlstr = "".join(_marshal(obj, elementName, prettyPrint=prettyPrint, indent=indent, knownTypes=knownTypes)) + if (isinstance(encoding, basestring)): + return '\n%s' % (encoding, xmlstr.encode(encoding)) + elif (encoding == None): return xmlstr + else: + return '\n%s' % (sys.getdefaultencoding(), xmlstr) -def _marshal(obj, elementName=None, nameSpacePrefix='', nameSpaces=None, prettyPrint=False, indent=0, knownTypes=None): +def _marshal(obj, elementName=None, nameSpacePrefix="", nameSpaces=None, prettyPrint=False, indent=0, knownTypes=None): + xmlMarshallerLogger.debug("--> _marshal: elementName=%s, type=%s, obj=%s" % (elementName, type(obj), str(obj))) + xmlString = None if prettyPrint or indent: - prefix = ' '*indent - newline = '\n' + prefix = " "*indent + newline = "\n" increment = 4 else: - prefix = '' - newline = '' + prefix = "" + newline = "" increment = 0 - ## Determine the XML element name. If it isn't specified in the - ## parameter list, look for it in the __xmlname__ Python + ## Determine the XML element name. If it isn"t specified in the + ## parameter list, look for it in the __xmlname__ Lang ## attribute, else use the default generic BASETYPE_ELEMENT_NAME. if not nameSpaces: nameSpaces = {} # Need to do this since if the {} is a default parameter it gets shared by all calls into the function - nameSpaceAttrs = '' + nameSpaceAttrs = "" if knownTypes == None: knownTypes = {} - if hasattr(obj, '__xmlnamespaces__'): - for nameSpaceKey, nameSpaceUrl in getattr(obj, '__xmlnamespaces__').items(): - if nameSpaceUrl in nameSpaces: + if hasattr(obj, "__xmlnamespaces__"): + for nameSpaceKey, nameSpaceUrl in getattr(obj, "__xmlnamespaces__").items(): + if nameSpaceUrl in asDict(nameSpaces): nameSpaceKey = nameSpaces[nameSpaceUrl] else: -## # TODO: Wait to do this until there is shared state for use when going through the object graph -## origNameSpaceKey = nameSpaceKey # Make sure there is no key collision, ie: same key referencing two different URL's +## # TODO: Wait to do this until there is shared for use when going through the object graph +## origNameSpaceKey = nameSpaceKey # Make sure there is no key collision, ie: same key referencing two different URL"s ## i = 1 ## while nameSpaceKey in nameSpaces.values(): ## nameSpaceKey = origNameSpaceKey + str(i) ## i += 1 nameSpaces[nameSpaceUrl] = nameSpaceKey - if nameSpaceKey == '': + if nameSpaceKey == "": nameSpaceAttrs += ' xmlns="%s" ' % (nameSpaceUrl) else: nameSpaceAttrs += ' xmlns:%s="%s" ' % (nameSpaceKey, nameSpaceUrl) nameSpaceAttrs = nameSpaceAttrs.rstrip() - if hasattr(obj, '__xmldefaultnamespace__'): - nameSpacePrefix = getattr(obj, '__xmldefaultnamespace__') + ':' + if hasattr(obj, "__xmldefaultnamespace__"): + nameSpacePrefix = getattr(obj, "__xmldefaultnamespace__") + ":" if not elementName: - if hasattr(obj, '__xmlname__'): + if hasattr(obj, "__xmlname__"): elementName = nameSpacePrefix + obj.__xmlname__ else: elementName = nameSpacePrefix + BASETYPE_ELEMENT_NAME else: elementName = nameSpacePrefix + elementName - if hasattr(obj, '__xmlsequencer__'): + if hasattr(obj, "__xmlsequencer__"): elementAdd = obj.__xmlsequencer__ else: elementAdd = None @@ -507,42 +554,41 @@ def _marshal(obj, elementName=None, nameSpacePrefix='', nameSpaces=None, prettyP members_to_skip = [] ## Add more members_to_skip based on ones the user has selected ## via the __xmlexclude__ attribute. - if hasattr(obj, '__xmlexclude__'): + if hasattr(obj, "__xmlexclude__"): ## print "marshal: found __xmlexclude__" - members_to_skip += list(obj.__xmlexclude__) + members_to_skip.extend(obj.__xmlexclude__) # Marshal the attributes that are selected to be XML attributes. - objattrs = '' - className = obj.__class__.__name__ + objattrs = "" + className = ag_className(obj) classNamePrefix = "_" + className - if hasattr(obj, '__xmlattributes__'): + if hasattr(obj, "__xmlattributes__"): ## print "marshal: found __xmlattributes__" xmlattributes = obj.__xmlattributes__ - members_to_skip += xmlattributes + members_to_skip.extend(xmlattributes) for attr in xmlattributes: internalAttrName = attr + ifDefPy() if (attr.startswith("__") and not attr.endswith("__")): internalAttrName = classNamePrefix + attr + endIfDef() # Fail silently if a python attribute is specified to be # an XML attribute but is missing. ## print "marshal: processing attribute ", internalAttrName - try: - value = obj.__dict__[internalAttrName] - except KeyError: - continue -## # But, check and see if it is a property first: -## if (objutils.hasPropertyValue(obj, attr)): -## value = getattr(obj, attr) -## else: -## continue + attrs = obj.__dict__ + value = attrs.get(internalAttrName) xsdElement = None - if hasattr(obj, '__xsdcomplextype__'): + complexType = getComplexType(obj) + if (complexType != None): ## print "marshal: found __xsdcomplextype__" - complexType = getattr(obj, '__xsdcomplextype__') xsdElement = complexType.findElement(attr) - if xsdElement: + if (xsdElement != None): default = xsdElement.default - if default == value or default == _getXmlValue(value): - continue + if (default != None): + if ((default == value) or (default == _getXmlValue(value))): + continue + else: + if (value == None): + continue elif value == None: continue @@ -556,184 +602,205 @@ def _marshal(obj, elementName=None, nameSpacePrefix='', nameSpaces=None, prettyP else: value = "false" - attrNameSpacePrefix = '' - if hasattr(obj, '__xmlattrnamespaces__'): + attrNameSpacePrefix = "" + if hasattr(obj, "__xmlattrnamespaces__"): ## print "marshal: found __xmlattrnamespaces__" - for nameSpaceKey, nameSpaceAttributes in getattr(obj, '__xmlattrnamespaces__').items(): - if nameSpaceKey == nameSpacePrefix[:-1]: # Don't need to specify attribute namespace if it is the same as it's element + for nameSpaceKey, nameSpaceAttributes in getattr(obj, "__xmlattrnamespaces__").iteritems(): + if nameSpaceKey == nameSpacePrefix[:-1]: # Don't need to specify attribute namespace if it is the same as its element continue if attr in nameSpaceAttributes: - attrNameSpacePrefix = nameSpaceKey + ':' + attrNameSpacePrefix = nameSpaceKey + ":" break -## if attr.startswith('_'): +## if attr.startswith("_"): ## attr = attr[1:] - if (hasattr(obj, "__xmlrename__") and attr in obj.__xmlrename__): + if (hasattr(obj, "__xmlrename__") and attr in asDict(obj.__xmlrename__)): ## print "marshal: found __xmlrename__ (and its attribute)" attr = obj.__xmlrename__[attr] - objattrs += ' %s%s="%s"' % (attrNameSpacePrefix, attr, value) + objattrs += ' %s%s="%s"' % (attrNameSpacePrefix, attr, str(value)) ## print "marshal: new objattrs is: ", objattrs - if isinstance(obj, NoneType): - return '' + if (obj == None): + xmlString = [""] elif isinstance(obj, bool): - return ['%s<%s objtype="bool">%s%s' % (prefix, elementName, obj, elementName, newline)] + xmlString = ['%s<%s objtype="bool">%s%s' % (prefix, elementName, obj, elementName, newline)] elif isinstance(obj, int): - return ['''%s<%s objtype="int">%s%s''' % (prefix, elementName, str(obj), elementName, newline)] + xmlString = ['%s<%s objtype="int">%s%s' % (prefix, elementName, str(obj), elementName, newline)] elif isinstance(obj, long): - return ['%s<%s objtype="long">%s%s' % (prefix, elementName, str(obj), elementName, newline)] + xmlString = ['%s<%s objtype="long">%s%s' % (prefix, elementName, str(obj), elementName, newline)] elif isinstance(obj, float): - return ['%s<%s objtype="float">%s%s' % (prefix, elementName, str(obj), elementName, newline)] + xmlString = ['%s<%s objtype="float">%s%s' % (prefix, elementName, str(obj), elementName, newline)] elif isinstance(obj, unicode): # have to check before basestring - unicode is instance of base string - return ['''%s<%s>%s%s''' % (prefix, elementName, saxutils.escape(obj.encode()), elementName, newline)] + xmlString = ['%s<%s>%s%s' % (prefix, elementName, saxutils.escape(obj.encode()), elementName, newline)] elif isinstance(obj, basestring): - return ['''%s<%s>%s%s''' % (prefix, elementName, saxutils.escape(obj), elementName, newline)] + xmlString = ['%s<%s>%s%s' % (prefix, elementName, saxutils.escape(obj), elementName, newline)] elif isinstance(obj, list): if len(obj) < 1: - return '' - xmlString = ['%s<%s objtype="list">%s' % (prefix, elementName, newline)] - for item in obj: - xmlString.extend(_marshal(item, nameSpaces=nameSpaces, indent=indent+increment, knownTypes=knownTypes)) - xmlString.append('%s%s' % (prefix, elementName, newline)) - return xmlString + xmlString = "" + else: + xmlString = ['%s<%s objtype="list">%s' % (prefix, elementName, newline)] + for item in obj: + xmlString.extend(_marshal(item, nameSpaces=nameSpaces, indent=indent+increment, knownTypes=knownTypes)) + xmlString.append("%s%s" % (prefix, elementName, newline)) elif isinstance(obj, tuple): if len(obj) < 1: - return '' - xmlString = ['%s<%s objtype="list" mutable="false">%s' % (prefix, elementName, newline)] - for item in obj: - xmlString.extend(_marshal(item, nameSpaces=nameSpaces, indent=indent+increment, knownTypes=knownTypes)) - xmlString.append('%s%s' % (prefix, elementName, newline)) - return xmlString + xmlString = "" + else: + xmlString = ['%s<%s objtype="list" mutable="false">%s' % (prefix, elementName, newline)] + for item in obj: + xmlString.extend(_marshal(item, nameSpaces=nameSpaces, indent=indent+increment, knownTypes=knownTypes)) + xmlString.append("%s%s" % (prefix, elementName, newline)) elif isinstance(obj, dict): xmlString = ['%s<%s objtype="dict">%s' % (prefix, elementName, newline)] - subprefix = prefix + ' '*increment + subprefix = prefix + " "*increment subindent = indent + 2*increment for key, val in obj.iteritems(): - xmlString.append("%s%s" % (subprefix, newline)) - xmlString.extend(_marshal(key, indent=subindent, knownTypes=knownTypes)) - xmlString.append("%s%s%s%s" % (subprefix, newline, subprefix, newline)) - xmlString.extend(_marshal(val, nameSpaces=nameSpaces, indent=subindent, knownTypes=knownTypes)) - xmlString.append("%s%s" % (subprefix, newline)) - xmlString.append('%s%s' % (prefix, elementName, newline)) - return xmlString +## if (isinstance(key, basestring) and key is legal identifier): +## xmlString.extend(_marshal(val, elementName=key, nameSpaces=nameSpaces, indent=subindent, knownTypes=knownTypes)) +## else: + xmlString.append("%s<%s>%s" % (subprefix, DICT_ITEM_NAME, newline)) + xmlString.extend(_marshal(key, elementName=DICT_ITEM_KEY_NAME, indent=subindent, knownTypes=knownTypes)) + xmlString.extend(_marshal(val, elementName=DICT_ITEM_VALUE_NAME, nameSpaces=nameSpaces, indent=subindent, knownTypes=knownTypes)) + xmlString.append("%s%s" % (subprefix, DICT_ITEM_NAME, newline)) + xmlString.append("%s%s" % (prefix, elementName, newline)) else: - moduleName = obj.__class__.__module__ - if (moduleName == "activegrid.model.schema"): - xmlString = ['%s<%s%s%s' % (prefix, elementName, nameSpaceAttrs, objattrs)] + # Only add the objtype if the element tag is unknown to us. + objname = knownTypes.get(elementName) + if (objname != None): + xmlString = ["%s<%s%s%s" % (prefix, elementName, nameSpaceAttrs, objattrs)] else: - # Only add the objtype if the element tag is unknown to us. - try: - objname = knownTypes[elementName] - xmlString = ['%s<%s%s%s' % (prefix, elementName, nameSpaceAttrs, objattrs)] - except KeyError: - xmlString = ['%s<%s%s%s objtype="%s.%s"' % (prefix, elementName, nameSpaceAttrs, objattrs, moduleName, className)] -## print "UnknownTypeException: Unknown type (%s.%s) passed to marshaller" % (moduleName, className) - # get the member, value pairs for the object, filtering out the types we don't support + xmlString = ['%s<%s%s%s objtype="%s.%s"' % (prefix, elementName, nameSpaceAttrs, objattrs, obj.__class__.__module__, className)] + # get the member, value pairs for the object, filtering out the types we don"t support if (elementAdd != None): - prefix += increment*' ' + prefix += increment*" " indent += increment xmlMemberString = [] - if hasattr(obj, '__xmlbody__'): + if hasattr(obj, "__xmlbody__"): xmlbody = getattr(obj, obj.__xmlbody__) if xmlbody != None: xmlMemberString.append(xmlbody) else: - entryList = obj.__dict__.items() -## # Add in properties -## for key in obj.__class__.__dict__.iterkeys(): -## if (key not in members_to_skip and key not in obj.__dict__ -## and objutils.hasPropertyValue(obj, key)): -## value = getattr(obj, key) -## entryList.append((key, value)) - entryList.sort() - if hasattr(obj, '__xmlattrgroups__'): - attrGroups = obj.__xmlattrgroups__ - if (not isinstance(attrGroups,dict)): + if hasattr(obj, "__xmlattrgroups__"): + attrGroups = obj.__xmlattrgroups__.copy() + if (not isinstance(attrGroups, dict)): raise "__xmlattrgroups__ is not a dict, but must be" - for n in attrGroups: - v = attrGroups[n] - members_to_skip += v + for n in attrGroups.iterkeys(): + members_to_skip.extend(attrGroups[n]) else: attrGroups = {} # add the list of all attributes to attrGroups - eList = [] - for x, z in entryList: - eList.append(x) - attrGroups['__nogroup__'] = eList + eList = obj.__dict__.keys() + eList.sort() + attrGroups["__nogroup__"] = eList - for eName in attrGroups: - eList = attrGroups[eName] - if (eName != '__nogroup__'): - prefix += increment*' ' + for eName, eList in attrGroups.iteritems(): + if (eName != "__nogroup__"): + prefix += increment*" " indent += increment xmlMemberString.append('%s<%s objtype="None">%s' % (prefix, eName, newline)) for name in eList: value = obj.__dict__[name] -## print " ", name, " = ", value -## # special name handling for private "__*" attributes: -## # remove the _ added by Python -## if name.startswith(classNamePrefix): name = name[len(classNamePrefix):] - if eName == '__nogroup__' and name in members_to_skip: continue - if name.startswith('__') and name.endswith('__'): continue -## idx = name.find('__') -## if idx > 0: -## newName = name[idx+2:] -## if newName: -## name = newName -## print "marshal: processing subElement ", name + if eName == "__nogroup__" and name in members_to_skip: continue + if name.startswith("__") and name.endswith("__"): continue subElementNameSpacePrefix = nameSpacePrefix - if hasattr(obj, '__xmlattrnamespaces__'): - for nameSpaceKey, nameSpaceValues in getattr(obj, '__xmlattrnamespaces__').items(): + if hasattr(obj, "__xmlattrnamespaces__"): + for nameSpaceKey, nameSpaceValues in getattr(obj, "__xmlattrnamespaces__").iteritems(): if name in nameSpaceValues: - subElementNameSpacePrefix = nameSpaceKey + ':' + subElementNameSpacePrefix = nameSpaceKey + ":" break # handle sequences listed in __xmlflattensequence__ # specially: instead of listing the contained items inside - # of a separate list, as god intended, list them inside + # of a separate list, as God intended, list them inside # the object containing the sequence. - if hasattr(obj, '__xmlflattensequence__') and name in obj.__xmlflattensequence__ and value: - try: - xmlnametuple = obj.__xmlflattensequence__[name] - xmlname = None - if len(xmlnametuple) == 1: - xmlname = xmlnametuple[0] - except: - xmlname = name -## xmlname = name.lower() + if (hasattr(obj, "__xmlflattensequence__") and (value != None) and (name in asDict(obj.__xmlflattensequence__))): + xmlnametuple = obj.__xmlflattensequence__[name] + if (xmlnametuple == None): + xmlnametuple = [name] + elif (not isinstance(xmlnametuple, (tuple,list))): + xmlnametuple = [str(xmlnametuple)] + xmlname = None + if (len(xmlnametuple) == 1): + xmlname = xmlnametuple[0] +## ix = 0 for seqitem in value: +## xmlname = xmlnametuple[ix] +## ix += 1 +## if (ix >= len(xmlnametuple)): +## ix = 0 xmlMemberString.extend(_marshal(seqitem, xmlname, subElementNameSpacePrefix, nameSpaces=nameSpaces, indent=indent+increment, knownTypes=knownTypes)) else: - if (hasattr(obj, "__xmlrename__") and name in obj.__xmlrename__): + if (hasattr(obj, "__xmlrename__") and name in asDict(obj.__xmlrename__)): xmlname = obj.__xmlrename__[name] else: xmlname = name -## if (indent > 30): -## print "getting pretty deep, xmlname = ", xmlname xmlMemberString.extend(_marshal(value, xmlname, subElementNameSpacePrefix, nameSpaces=nameSpaces, indent=indent+increment, knownTypes=knownTypes)) - if (eName != '__nogroup__'): -## print "marshal: Completing attrGroup ", eName - xmlMemberString.append('%s%s' % (prefix, eName, newline)) + if (eName != "__nogroup__"): + xmlMemberString.append("%s%s" % (prefix, eName, newline)) prefix = prefix[:-increment] indent -= increment # if we have nested elements, add them here, otherwise close the element tag immediately. - xmlMemberString = filter(lambda x: len(x)>0, xmlMemberString) + newList = [] + for s in xmlMemberString: + if (len(s) > 0): newList.append(s) + xmlMemberString = newList if len(xmlMemberString) > 0: - xmlString.append('>') - if hasattr(obj, '__xmlbody__'): + xmlString.append(">") + if hasattr(obj, "__xmlbody__"): xmlString.extend(xmlMemberString) - xmlString.append('%s' % (elementName, newline)) + xmlString.append("%s" % (elementName, newline)) else: xmlString.append(newline) if (elementAdd != None): - xmlString.append('%s<%s>%s' % (prefix, elementAdd, newline)) + xmlString.append("%s<%s>%s" % (prefix, elementAdd, newline)) xmlString.extend(xmlMemberString) if (elementAdd != None): - xmlString.append('%s%s' % (prefix, elementAdd, newline)) + xmlString.append("%s%s" % (prefix, elementAdd, newline)) prefix = prefix[:-increment] indent -= increment - xmlString.append('%s%s' % (prefix, elementName, newline)) + xmlString.append("%s%s" % (prefix, elementName, newline)) else: - xmlString.append('/>%s' % newline) - return xmlString + xmlString.append("/>%s" % newline) +## return xmlString + xmlMarshallerLogger.debug("<-- _marshal: %s" % str(xmlString)) + return xmlString + +# A simple test, to be executed when the xmlmarshaller is run standalone +class MarshallerPerson: + __xmlname__ = "person" + __xmlexclude__ = ["fabulousness",] + __xmlattributes__ = ("nonSmoker",) + __xmlrename__ = {"_phoneNumber": "telephone"} + __xmlflattensequence__ = {"favoriteWords": ("vocabulary",)} + __xmlattrgroups__ = {"name": ["firstName", "lastName"], "address": ["addressLine1", "city", "state", "zip"]} + + def setPerson(self): + self.firstName = "Albert" + self.lastName = "Camus" + self.addressLine1 = "23 Absurd St." + self.city = "Ennui" + self.state = "MO" + self.zip = "54321" + self._phoneNumber = "808-303-2323" + self.favoriteWords = ["angst", "ennui", "existence"] + self.phobias = ["war", "tuberculosis", "cars"] + self.weight = 150 + self.fabulousness = "tres tres" + self.nonSmoker = False + +if isMain(__name__): + p1 = MarshallerPerson() + p1.setPerson() + xmlP1 = marshal(p1, prettyPrint=True, encoding="utf-8") + print "\n########################" + print "# testPerson test case #" + print "########################" + print xmlP1 + p2 = unmarshal(xmlP1) + xmlP2 = marshal(p2, prettyPrint=True, encoding="utf-8") + if xmlP1 == xmlP2: + print "Success: repeated marshalling yields identical results" + else: + print "Failure: repeated marshalling yields different results" + print xmlP2 diff --git a/wxPython/samples/ide/activegrid/util/xmlprettyprinter.py b/wxPython/samples/ide/activegrid/util/xmlprettyprinter.py index 29dbf16be3..97d74130cd 100644 --- a/wxPython/samples/ide/activegrid/util/xmlprettyprinter.py +++ b/wxPython/samples/ide/activegrid/util/xmlprettyprinter.py @@ -10,8 +10,7 @@ # License: wxWindows License #---------------------------------------------------------------------------- import xml.sax -import xml.sax.handler - +from activegrid.util.lang import * class XMLPrettyPrinter(xml.sax.ContentHandler): def __init__(self, indentationChar=' ', newlineChar='\n'): @@ -24,7 +23,7 @@ class XMLPrettyPrinter(xml.sax.ContentHandler): ## ContentHandler methods def startElement(self, name, attrs): - indentation = self.newlineChar + (self.indentationLevel * self.indentationChar) + indentation = self.newlineChar + (self.indentationChar * self.indentationLevel) # build attribute string attrstring = '' for attr in attrs.getNames(): @@ -36,6 +35,7 @@ class XMLPrettyPrinter(xml.sax.ContentHandler): self.hitCharData = False def characters(self, content): +## print "--> characters(%s)" % content self.xmlOutput += content self.hitCharData = True @@ -43,11 +43,12 @@ class XMLPrettyPrinter(xml.sax.ContentHandler): self.indentationLevel -= 1 indentation = '' if not self.hitCharData: -## indentation += self.newlineChar + (self.indentationLevel * self.indentationChar) - indentation += self.indentationLevel * self.indentationChar + indentation += self.newlineChar + (self.indentationChar * self.indentationLevel) +## indentation += self.indentationChar * self.indentationLevel else: self.hitCharData = False - self.xmlOutput += '%s%s' % (indentation, self.elementStack.pop(), self.newlineChar) +## self.xmlOutput += '%s%s' % (indentation, self.elementStack.pop(), self.newlineChar) + self.xmlOutput += '%s' % (indentation, self.elementStack.pop()) def getXMLString(self): return self.xmlOutput[1:] @@ -57,7 +58,7 @@ def xmlprettyprint(xmlstr, spaces=4): xml.sax.parseString(xmlstr, xpp) return xpp.getXMLString() -if __name__ == '__main__': +if isMain(__name__): simpleTestString = """some texttwo's data""" - print prettyprint(simpleTestString) + print xmlprettyprint(simpleTestString) diff --git a/wxPython/samples/ide/activegrid/util/xmlutils.py b/wxPython/samples/ide/activegrid/util/xmlutils.py new file mode 100644 index 0000000000..ac0ed7c6cf --- /dev/null +++ b/wxPython/samples/ide/activegrid/util/xmlutils.py @@ -0,0 +1,128 @@ +#---------------------------------------------------------------------------- +# Name: xmlutils.py +# Purpose: XML and Marshaller Utilities +# +# Author: Jeff Norton +# +# Created: 6/2/05 +# CVS-ID: $Id$ +# Copyright: (c) 2004-2005 ActiveGrid, Inc. +# License: wxWindows License +#---------------------------------------------------------------------------- + +import os +import activegrid.util.objutils as objutils +import activegrid.util.xmlmarshaller as xmlmarshaller + +agKnownTypes = None + +def defaultLoad(fileObject, knownTypes=None): + xml = fileObject.read() + loadedObject = unmarshal(xml, knownTypes=knownTypes) + if hasattr(fileObject, 'name'): + loadedObject.fileName = os.path.abspath(fileObject.name) + loadedObject.initialize() + return loadedObject + +def unmarshal(xml, knownTypes=None): + if not knownTypes: knownTypes = getAgKnownTypes() + return xmlmarshaller.unmarshal(xml, knownTypes=knownTypes) + +def defaultSave(fileObject, objectToSave, prettyPrint=True, knownTypes=None, encoding='utf-8'): + xml = marshal(objectToSave, prettyPrint=prettyPrint, knownTypes=knownTypes, encoding=encoding) + fileObject.write(xml) + fileObject.flush() + +def marshal(objectToSave, prettyPrint=True, knownTypes=None, encoding='utf-8'): + if not knownTypes: knownTypes = getAgKnownTypes() + return xmlmarshaller.marshal(objectToSave, prettyPrint=prettyPrint, knownTypes=knownTypes, encoding=encoding) + +def cloneObject(objectToClone, knownTypes=None, encoding='utf-8'): + if not knownTypes: knownTypes = getAgKnownTypes() + xml = xmlmarshaller.marshal(objectToClone, prettyPrint=True, knownTypes=knownTypes, encoding=encoding) + clonedObject = xmlmarshaller.unmarshal(xml, knownTypes=knownTypes) + if hasattr(objectToClone, 'fileName'): + clonedObject.fileName = objectToClone.fileName + try: + clonedObject.initialize() + except AttributeError: + pass + return clonedObject + +def getAgKnownTypes(): + import activegrid.model.processmodel + import activegrid.model.schema + import activegrid.data.dataservice + import activegrid.server.deployment + global agKnownTypes + if agKnownTypes == None: + tmpAgKnownTypes = {} + AG_TYPE_MAPPING = { + "ag:append" : "activegrid.model.processmodel.AppendOperation", + "ag:body" : "activegrid.model.processmodel.Body", + "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:restParameter" : "activegrid.server.deployment.RestParameter", + "ag:restService" : "activegrid.server.deployment.RestService", + "ag:schemaOptions" : "activegrid.model.schema.SchemaOptions", + "ag:schemaref" : "activegrid.server.deployment.SchemaRef", + "ag:serviceref" : "activegrid.server.deployment.ServiceRef", + "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", + } + + for keyName, className in AG_TYPE_MAPPING.iteritems(): + try: + tmpAgKnownTypes[keyName] = objutils.classForName(className) + except KeyError: + print "Error mapping knownType", className + pass + if len(tmpAgKnownTypes) > 0: + agKnownTypes = tmpAgKnownTypes + return agKnownTypes diff --git a/wxPython/samples/pydocview/PyDocViewDemo.py b/wxPython/samples/pydocview/PyDocViewDemo.py index 82ee66e596..aa0d2f02b6 100644 --- a/wxPython/samples/pydocview/PyDocViewDemo.py +++ b/wxPython/samples/pydocview/PyDocViewDemo.py @@ -90,6 +90,8 @@ class TextEditorApplication(pydocview.DocApp): if os.path.exists("tips.txt"): wx.CallAfter(self.ShowTip, wx.GetApp().GetTopWindow(), wx.CreateFileTipProvider("tips.txt", 0)) + wx.UpdateUIEvent.SetUpdateInterval(400) # Overhead of updating menus was too much. Change to update every 400 milliseconds. + # Tell the framework that everything is great return True diff --git a/wxPython/wx/lib/docview.py b/wxPython/wx/lib/docview.py index e99799ff3d..2ef9db4441 100644 --- a/wxPython/wx/lib/docview.py +++ b/wxPython/wx/lib/docview.py @@ -13,6 +13,7 @@ import os import os.path +import shutil import wx import sys _ = wx.GetTranslation @@ -436,6 +437,7 @@ class Document(wx.EvtHandler): backupFilename = None fileObject = None + copied = False try: # if current file exists, move it to a safe place temporarily if os.path.exists(filename): @@ -453,7 +455,8 @@ class Document(wx.EvtHandler): while os.path.exists(backupFilename): i += 1 backupFilename = "%s.bak%s" % (filename, i) - os.rename(filename, backupFilename) + shutil.copy(filename, backupFilename) + copied = True fileObject = file(filename, 'w') self.SaveObject(fileObject) @@ -470,11 +473,9 @@ class Document(wx.EvtHandler): 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) - os.rename(backupFilename, filename) - self.SetDocumentModificationDate() + # save failed, remove copied file + if backupFilename and copied: + os.remove(backupFilename) wx.MessageBox("Could not save '%s'. %s" % (FileNameFromPath(filename), sys.exc_value), msgTitle, @@ -1247,10 +1248,6 @@ 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() @@ -2793,8 +2790,10 @@ class DocMDIChildFrame(wx.MDIChildFrame): self._childView.Activate(False) self._childView.Destroy() self._childView = None - if self._childDocument: - self._childDocument.Destroy() # This isn't in the wxWindows codebase but the document needs to be disposed of somehow + if self._childDocument: # This isn't in the wxWindows codebase but the document needs to be disposed of somehow + self._childDocument.DeleteContents() + if self._childDocument.GetDocumentManager(): + self._childDocument.GetDocumentManager().RemoveDocument(self._childDocument) self._childDocument = None self.Destroy() else: diff --git a/wxPython/wx/lib/pydocview.py b/wxPython/wx/lib/pydocview.py index 57327ea806..7c9f8e00c0 100644 --- a/wxPython/wx/lib/pydocview.py +++ b/wxPython/wx/lib/pydocview.py @@ -1185,7 +1185,7 @@ class DocService(wx.EvtHandler): def __init__(self): """Initializes the DocService.""" - wx.EvtHandler.__init__(self) + pass def GetDocumentManager(self): @@ -1478,7 +1478,7 @@ class GeneralOptionsPanel(wx.Panel): msgTitle = wx.GetApp().GetAppName() if not msgTitle: msgTitle = _("Document Options") - wx.MessageBox("Document interface changes will not appear until the application is restarted.", + wx.MessageBox(_("Document interface changes will not appear until the application is restarted."), msgTitle, wx.OK | wx.ICON_INFORMATION, self.GetParent()) @@ -1995,10 +1995,7 @@ class DocApp(wx.PySimpleApp): if isinstance(document, ChildDocument) and document.GetParentDocument() == parentDocument: if document.GetFirstView().GetFrame(): document.GetFirstView().GetFrame().SetFocus() - if document.GetFirstView().OnClose(deleteWindow = False): - if document.GetFirstView().GetFrame(): - document.GetFirstView().GetFrame().Close() # wxBug: Need to do this for some random reason - else: + if not document.GetFirstView().OnClose(): return False return True @@ -2338,7 +2335,6 @@ class AboutService(DocService): """ Initializes the AboutService. """ - DocService.__init__(self) if aboutDialog: self._dlg = aboutDialog self._image = None @@ -2406,7 +2402,6 @@ class FilePropertiesService(DocService): """ Initializes the PropertyService. """ - DocService.__init__(self) self._customEventHandlers = [] @@ -2710,7 +2705,6 @@ class WindowMenuService(DocService): """ Initializes the WindowMenu and its globals. """ - DocService.__init__(self) self.ARRANGE_WINDOWS_ID = wx.NewId() self.SELECT_WINDOW_1_ID = wx.NewId() self.SELECT_WINDOW_2_ID = wx.NewId()