]> git.saurik.com Git - wxWidgets.git/commitdiff
Docview and IDE patch from Morag Hua with fix for bug #1217890
authorRobin Dunn <robin@alldunn.com>
Sat, 11 Jun 2005 23:18:57 +0000 (23:18 +0000)
committerRobin Dunn <robin@alldunn.com>
Sat, 11 Jun 2005 23:18:57 +0000 (23:18 +0000)
"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

19 files changed:
wxPython/docs/CHANGES.txt
wxPython/samples/docview/DocViewDemo.py
wxPython/samples/ide/activegrid/tool/AbstractEditor.py
wxPython/samples/ide/activegrid/tool/DebuggerHarness.py
wxPython/samples/ide/activegrid/tool/DebuggerService.py
wxPython/samples/ide/activegrid/tool/ExtensionService.py [new file with mode: 0644]
wxPython/samples/ide/activegrid/tool/IDE.py
wxPython/samples/ide/activegrid/tool/ProjectEditor.py
wxPython/samples/ide/activegrid/tool/UICommon.py
wxPython/samples/ide/activegrid/util/__init__.py
wxPython/samples/ide/activegrid/util/aglogging.py [new file with mode: 0644]
wxPython/samples/ide/activegrid/util/lang.py [new file with mode: 0644]
wxPython/samples/ide/activegrid/util/objutils.py
wxPython/samples/ide/activegrid/util/xmlmarshaller.py
wxPython/samples/ide/activegrid/util/xmlprettyprinter.py
wxPython/samples/ide/activegrid/util/xmlutils.py [new file with mode: 0644]
wxPython/samples/pydocview/PyDocViewDemo.py
wxPython/wx/lib/docview.py
wxPython/wx/lib/pydocview.py

index 3a9e0789ceb1e8d91f0061701e945b5a62786432..b187da09c6c93272ad47f42a07502c13e0748f2f 100644 (file)
@@ -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.
+
+
 
 
 
index 7fa1f5fc9bc8755662e13b8c79b66885e32bcb5e..ba7bb6623a388087e52f41b5ad3fc237c0107c18 100644 (file)
@@ -122,6 +122,7 @@ class TextEditView(wx.lib.docview.View):
 
 
     def OnDraw(self, dc):
+        """ For Print and Print Preview """
         pass
 
 
index 18fbf6d7fc1b84f2801dd23b1e828f479a04355b..f8e9d16e4ef03904130838b2d121ee8306700b3c 100644 (file)
@@ -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):
index 433c118dce95e29ad07367d0650c89c595a24856..63452dcb9d8ebd7864b68c6ac45e06f6885098cd 100644 (file)
@@ -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, '<string>', 'single')
+            exec code in frame.f_globals, frame.f_locals
             return output.getvalue()
             sys.stdout = out
             sys.stderr = err        
index 8da8bc2492fd177619f34f5115ee62f7c05faffe..547d8c9912d204ff61d9236757e5c63d433cc4c6 100644 (file)
@@ -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 (file)
index 0000000..b75e544
--- /dev/null
@@ -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
index 1d68e31f87e7523fdc7fbffcce93793a1ed9ab98..4a9a5a45c8ef510a8d7dba953d78d82d3f6b1e86 100644 (file)
@@ -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
 
index 4d88f9defc31c0e065989f4db4064693bb0bb564..9934eaade7cc2cb9578ac8eec1fb7bff2624479c 100644 (file)
@@ -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)
index 6b81a9b8cfc618bb13f95e9764522ccee3939670..98f863a9da49319c2a5a652808403189f03cb8aa 100644 (file)
@@ -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
+    
+
index 4cda367b3ce77bd07f312bafd5ffeca2d58010c0..943607976fb1a401a2da1d7d0c737edc4c0e6436 100644 (file)
@@ -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 (file)
index 0000000..e4b5e7f
--- /dev/null
@@ -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 (file)
index 0000000..56777fa
--- /dev/null
@@ -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
index 97bd2f79e013228174c415afcf27dc15fc709303..9658aa2a2aa5a52816c46ed3a241323739a1f17e 100644 (file)
@@ -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
index 1b9cd67d4585b2ae2a2037166322616d1162ca1e..266418a1ebd73dfb9594f31fc9bf527091a923a2 100644 (file)
 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)
 <!-- normal way of marshalling -->
 <myseq>
-  <item objtype='int'>1</item>
-  <item objtype='int'>2</item>
+  <item objtype="int">1</item>
+  <item objtype="int">2</item>
 </myseq>
-<!-- with __xmlflattensequence__ set to {'myseq': 'squish'} -->
-<squish objtype='int'>1</squish>
-<squish objtype='int'>2</squish>
+<!-- with __xmlflattensequence__ set to {"myseq": "squish"} -->
+<squish objtype="int">1</squish>
+<squish objtype="int">2</squish>
 
 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] 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 !!!
+##    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 objtype in ('float', 'int', 'str', 'long'):
-            objargs = [x.strip() for x in objargs]
+            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)
 
     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 '<?xml version="1.0" encoding="%s"?>\n%s' % (sys.getdefaultencoding(), xmlstr)
-        else:
-            return '<?xml version="1.0" encoding="%s"?>\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 '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, xmlstr.encode(encoding))
+    elif (encoding == None):
         return xmlstr
+    else:
+        return '<?xml version="1.0" encoding="%s"?>\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>%s' % (prefix, elementName, obj, elementName, newline)]
+        xmlString = ['%s<%s objtype="bool">%s</%s>%s' % (prefix, elementName, obj, elementName, newline)]
     elif isinstance(obj, int):
-        return ['''%s<%s objtype="int">%s</%s>%s''' % (prefix, elementName, str(obj), elementName, newline)]
+        xmlString = ['%s<%s objtype="int">%s</%s>%s' % (prefix, elementName, str(obj), elementName, newline)]
     elif isinstance(obj, long):
-        return ['%s<%s objtype="long">%s</%s>%s' % (prefix, elementName, str(obj), elementName, newline)]
+        xmlString = ['%s<%s objtype="long">%s</%s>%s' % (prefix, elementName, str(obj), elementName, newline)]
     elif isinstance(obj, float):
-        return ['%s<%s objtype="float">%s</%s>%s' % (prefix, elementName, str(obj), elementName, newline)]
+        xmlString = ['%s<%s objtype="float">%s</%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>%s''' % (prefix, elementName, saxutils.escape(obj.encode()), elementName, newline)]
+        xmlString = ['%s<%s>%s</%s>%s' % (prefix, elementName, saxutils.escape(obj.encode()), elementName, newline)]
     elif isinstance(obj, basestring):
-        return ['''%s<%s>%s</%s>%s''' % (prefix, elementName, saxutils.escape(obj), elementName, newline)]
+        xmlString = ['%s<%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>%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>%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>%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>%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<key>%s" % (subprefix, newline))
-            xmlString.extend(_marshal(key, indent=subindent, knownTypes=knownTypes))
-            xmlString.append("%s</key>%s%s<value>%s" % (subprefix, newline, subprefix, newline))
-            xmlString.extend(_marshal(val, nameSpaces=nameSpaces, indent=subindent, knownTypes=knownTypes))
-            xmlString.append("%s</value>%s" % (subprefix, newline))
-        xmlString.append('%s</%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>%s" % (subprefix, DICT_ITEM_NAME, newline))
+        xmlString.append("%s</%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 _<class-name> 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>%s' % (prefix, eName, newline))
+                if (eName != "__nogroup__"):
+                    xmlMemberString.append("%s</%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>%s' % (elementName, newline))
+                xmlString.append("</%s>%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>%s' % (prefix, elementAdd, newline))
+                    xmlString.append("%s</%s>%s" % (prefix, elementAdd, newline))
                     prefix = prefix[:-increment]
                     indent -= increment
-                xmlString.append('%s</%s>%s' % (prefix, elementName, newline))
+                xmlString.append("%s</%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
index 29dbf16be3efe743029cdec717acb7592e5ad98c..97d74130cd837ef10293559fb929d31065b6c6a1 100644 (file)
@@ -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>%s' % (indentation, self.elementStack.pop(), self.newlineChar)
+##        self.xmlOutput += '%s</%s>%s' % (indentation, self.elementStack.pop(), self.newlineChar)
+        self.xmlOutput += '%s</%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 = """<one>some text<two anattr="booga">two's data</two></one>"""
-    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 (file)
index 0000000..ac0ed7c
--- /dev/null
@@ -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
index 82ee66e596312bd0a13896d6bc0531b35f39e32a..aa0d2f02b697422f7109fa6babd89c8b788d5e1b 100644 (file)
@@ -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
 
index e99799ff3d87c7315fd84e0f11d6a6b5790c6dbc..2ef9db4441bdb39903a97f83cf098b2936b05724 100644 (file)
@@ -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:
index 57327ea806614bb3c17b0b727ecd55f1cce35aad..7c9f8e00c07eb14dbe52c9e38029d973fb67a773 100644 (file)
@@ -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()