dabo Commit
Revision 4061
Date: 2008-05-04 08:53:57 -0700 (Sun, 04 May 2008)
Author: Ed
Trac: http://svn.dabodev.com/trac/dabo/changeset/4061
Changed:
D branches/ed-ide/ClassDesigner.py
D branches/ed-ide/ClassDesignerComponents.py
D branches/ed-ide/ClassDesignerControlMixin.py
D branches/ed-ide/ClassDesignerCustomPropertyDialog.py
D branches/ed-ide/ClassDesignerEditor.py
D branches/ed-ide/ClassDesignerExceptions.py
D branches/ed-ide/ClassDesignerFormMixin.py
D branches/ed-ide/ClassDesignerMenu.py
D branches/ed-ide/ClassDesignerMethodSheet.py
D branches/ed-ide/ClassDesignerObjectPropertySheet.py
D branches/ed-ide/ClassDesignerPemForm.py
D branches/ed-ide/ClassDesignerPropSheet.py
D branches/ed-ide/ClassDesignerSizerPalette.py
D branches/ed-ide/ClassDesignerTreeSheet.py
D branches/ed-ide/CxnEditor.py
D branches/ed-ide/DragHandle.py
D branches/ed-ide/Editor.py
D branches/ed-ide/MenuBarPanel.py
D branches/ed-ide/MenuDesigner.py
D branches/ed-ide/MenuDesignerComponents.py
D branches/ed-ide/MenuDesignerForm.py
D branches/ed-ide/MenuDesignerPropForm.py
D branches/ed-ide/MenuPanel.py
D branches/ed-ide/PrefEditor.cdxml
D branches/ed-ide/PrefEditor.py
D branches/ed-ide/ReportDesigner.py
A branches/ed-ide/components/
A branches/ed-ide/components/ClassDesigner/
A branches/ed-ide/components/ClassDesigner/ClassDesigner.py
A branches/ed-ide/components/ClassDesigner/ClassDesignerComponents.py
A branches/ed-ide/components/ClassDesigner/ClassDesignerControlMixin.py
A
branches/ed-ide/components/ClassDesigner/ClassDesignerCustomPropertyDialog.py
A branches/ed-ide/components/ClassDesigner/ClassDesignerEditor.py
A branches/ed-ide/components/ClassDesigner/ClassDesignerExceptions.py
A branches/ed-ide/components/ClassDesigner/ClassDesignerFormMixin.py
A branches/ed-ide/components/ClassDesigner/ClassDesignerMenu.py
A branches/ed-ide/components/ClassDesigner/ClassDesignerMethodSheet.py
A branches/ed-ide/components/ClassDesigner/ClassDesignerObjectPropertySheet.py
A branches/ed-ide/components/ClassDesigner/ClassDesignerPemForm.py
A branches/ed-ide/components/ClassDesigner/ClassDesignerPropSheet.py
A branches/ed-ide/components/ClassDesigner/ClassDesignerSizerPalette.py
A branches/ed-ide/components/ClassDesigner/ClassDesignerTreeSheet.py
A branches/ed-ide/components/ClassDesigner/DragHandle.py
A branches/ed-ide/components/ClassDesigner/QLWImageData.py
A branches/ed-ide/components/ClassDesigner/QuickLayoutWizard.py
A branches/ed-ide/components/CxnEditor/
A branches/ed-ide/components/CxnEditor/CxnEditor.py
A branches/ed-ide/components/CxnEditor/conn.xsd
A branches/ed-ide/components/MenuDesigner/
A branches/ed-ide/components/MenuDesigner/MenuBarPanel.py
A branches/ed-ide/components/MenuDesigner/MenuDesigner.py
A branches/ed-ide/components/MenuDesigner/MenuDesignerComponents.py
A branches/ed-ide/components/MenuDesigner/MenuDesignerForm.py
A branches/ed-ide/components/MenuDesigner/MenuDesignerPropForm.py
A branches/ed-ide/components/MenuDesigner/MenuPanel.py
A branches/ed-ide/components/ReportDesigner/
A branches/ed-ide/components/ReportDesigner/ReportDesigner.py
A branches/ed-ide/components/ReportDesigner/sample.cnxml
A branches/ed-ide/components/ReportDesigner/sampleDaboIcon.png
A branches/ed-ide/components/ReportDesigner/sampleReport.rfxml
A branches/ed-ide/components/TextEditor/
A branches/ed-ide/components/TextEditor/TextEditor.py
D branches/ed-ide/conn.xsd
D branches/ed-ide/mover.cdxml
D branches/ed-ide/sample.cnxml
D branches/ed-ide/sampleDaboIcon.png
D branches/ed-ide/sampleReport.rfxml
A branches/ed-ide/samples/
A branches/ed-ide/samples/classes/
A branches/ed-ide/samples/classes/mover.cdxml
A branches/ed-ide/tools/
A branches/ed-ide/tools/AppWizard/
A branches/ed-ide/tools/PrefEditor/
A branches/ed-ide/tools/PrefEditor/PrefEditor.cdxml
A branches/ed-ide/tools/PrefEditor/PrefEditor.py
D branches/ed-ide/wizards/
Log:
First pass at reorganizing the IDE stuff
Diff:
Deleted: branches/ed-ide/ClassDesigner.py
Deleted: branches/ed-ide/ClassDesignerComponents.py
Deleted: branches/ed-ide/ClassDesignerControlMixin.py
Deleted: branches/ed-ide/ClassDesignerCustomPropertyDialog.py
Deleted: branches/ed-ide/ClassDesignerEditor.py
Deleted: branches/ed-ide/ClassDesignerExceptions.py
Deleted: branches/ed-ide/ClassDesignerFormMixin.py
Deleted: branches/ed-ide/ClassDesignerMenu.py
Deleted: branches/ed-ide/ClassDesignerMethodSheet.py
Deleted: branches/ed-ide/ClassDesignerObjectPropertySheet.py
Deleted: branches/ed-ide/ClassDesignerPemForm.py
Deleted: branches/ed-ide/ClassDesignerPropSheet.py
Deleted: branches/ed-ide/ClassDesignerSizerPalette.py
Deleted: branches/ed-ide/ClassDesignerTreeSheet.py
Deleted: branches/ed-ide/CxnEditor.py
Deleted: branches/ed-ide/DragHandle.py
Deleted: branches/ed-ide/Editor.py
Deleted: branches/ed-ide/MenuBarPanel.py
Deleted: branches/ed-ide/MenuDesigner.py
Deleted: branches/ed-ide/MenuDesignerComponents.py
Deleted: branches/ed-ide/MenuDesignerForm.py
Deleted: branches/ed-ide/MenuDesignerPropForm.py
Deleted: branches/ed-ide/MenuPanel.py
Deleted: branches/ed-ide/PrefEditor.cdxml
Deleted: branches/ed-ide/PrefEditor.py
Deleted: branches/ed-ide/ReportDesigner.py
Copied: branches/ed-ide/components/ClassDesigner/ClassDesigner.py (from rev
4060, branches/ed-ide/ClassDesigner.py)
===================================================================
--- branches/ed-ide/components/ClassDesigner/ClassDesigner.py
(rev 0)
+++ branches/ed-ide/components/ClassDesigner/ClassDesigner.py 2008-05-04
15:53:57 UTC (rev 4061)
@@ -0,0 +1,4089 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import sys
+import os
+import copy
+import inspect
+import dabo
+from dabo.dLocalize import _
+import dabo.dEvents as dEvents
+if __name__ == "__main__":
+ dabo.ui.loadUI("wx")
+# This is because I'm a lazy typist
+dui = dabo.ui
+from ClassDesignerFormMixin import ClassDesignerFormMixin as dfm
+from ClassDesignerPemForm import PemForm
+from ClassDesignerEditor import EditorForm
+from ClassDesignerComponents import LayoutPanel
+from ClassDesignerComponents import LayoutBasePanel
+from ClassDesignerComponents import LayoutSpacerPanel
+from ClassDesignerComponents import LayoutSizer
+from ClassDesignerComponents import LayoutBorderSizer
+from ClassDesignerComponents import LayoutGridSizer
+from ClassDesignerComponents import LayoutSaverMixin
+from ClassDesignerComponents import NoSizerBasePanel
+from ClassDesignerComponents import szItemDefaults
+from ClassDesignerComponents import classFlagProp
+from ClassDesignerControlMixin import ClassDesignerControlMixin as cmix
+from ClassDesignerCustomPropertyDialog import ClassDesignerCustomPropertyDialog
+from ClassDesignerSizerPalette import SizerPaletteForm
+from dabo.lib.DesignerXmlConverter import DesignerXmlConverter
+import ClassDesignerMenu
+import dabo.lib.xmltodict as xtd
+import dabo.ui.dialogs as dlgs
+from dabo.lib.utils import dictStringify
+from ClassDesignerExceptions import PropertyUpdateException
+# Temporary fix for wxPython 2.6 users
+try:
+ dabo.ui.dDockForm
+ _USE_DOCKFORM = True
+except:
+ dabo.ui.dDockForm = None
+ _USE_DOCKFORM = False
+
+
+
+class ClassDesigner(dabo.dApp):
+ # Behaviors which are normal in the framework may need to
+ # be modified when run as the ClassDesigner. This flag will
+ # distinguish between the two states.
+ isDesigner = True
+
+ def __init__(self, clsFile=""):
+ super(ClassDesigner, self).__init__(showSplashScreen=False,
+ splashTimeout=10)
+
+ self._basePrefKey = "dabo.ide.ClassDesigner"
+ self._desFormClass = None
+ self._selectedClass = dui.dForm
+ self._currentForm = None
+ self._editorForm = None
+ self._pemForm = None
+ self._tree = None
+ self._palette = None
+ self._sizerPalette = None
+ self._selection = []
+ self._editors = []
+ self._srcObj = None
+ self._srcPos = None
+ self._codeDict = {}
+ self._classCodeDict = {}
+ self._classPropDict = {}
+ self._classImportDict = {}
+ self._classDefaultVals = {}
+ self._mixedControlClasses = {}
+ self._superClassInfo = {}
+ self._addingClass = False
+ # Tuple of all paged-control classes
+ self.pagedControls = (dui.dPageFrame, dui.dPageList,
dui.dPageSelect,
+ dui.dPageFrameNoTabs)
+ self.MainFormClass = None
+ self.setAppInfo("appName", "Class Designer")
+ # Some processes need to behave differently when we are
+ # importing a class from a cdxml file; this flag lets them
+ # determine what process is being run.
+ self.openingClassXML = False
+ # Create the clipboard
+ self._clipboard = None
+ # This holds a reference to the target object when
+ # there is a context menu event.
+ self._contextObj = None
+ # When saving classes, we need to note when we are inside
+ # a class definition. The list is used as the class stack.
+ self._classStack = []
+ # We also need to save child class definitions on a stack, when
+ # saving/recreating class components with nested objects.
+ self._classChildDefStack = []
+ # Flag for indicating that all props, not just non-default ones,
+ # are saved in the .cdxml file
+ self.saveAllProps = False
+ # When we set the DefaultBorder for a sizer, should we
+ # resize all its children?
+ self._propagateDefaultBorder = True
+ # Store the name of the custom class menu here instead of
+ # hard-coding it in several places.
+ self._customClassCaption = _("Custom Classes")
+ # Add this to the persistent MRUs
+ self._persistentMRUs[self._customClassCaption] =
self.addCustomClass
+ # Save the default atts for sizers. This way we can distinguish
+ # from default sizers that can be replaced from customized
+ # sizers which should remain.
+ self._defBoxSizerAtts = bsa = {}
+ atts =
LayoutSizer().getDesignerDict(allProps=True)["attributes"]
+ bsa["DefaultBorder"] = atts["DefaultBorder"]
+ bsa["DefaultBorderTop"] = atts["DefaultBorderTop"]
+ bsa["DefaultBorderBottom"] = atts["DefaultBorderBottom"]
+ bsa["DefaultBorderLeft"] = atts["DefaultBorderLeft"]
+ bsa["DefaultBorderRight"] = atts["DefaultBorderRight"]
+ self._defGridSizerAtts = gsa = {}
+ atts =
LayoutGridSizer().getDesignerDict(allProps=True)["attributes"]
+ gsa["HGap"] = atts["HGap"]
+ gsa["VGap"] = atts["VGap"]
+ gsa["MaxDimension"] = atts["MaxDimension"]
+ # Get rid of the update/refresh delays
+ dabo.useUpdateDelays = False
+
+
+ # Define the controls that can be added to the ClassDesigner.
The
+ # 'order' value will determine their order in the menu. One plan
+ # is to keep track of the user's choices, and weight the orders
+ # so that their most frequent choices are at the top.
+ self.designerControls = ({"name" : "Box", "class" : dui.dBox,
"order" : 0},
+ {"name" : "Bitmap", "class" : dui.dBitmap,
"order" : 10},
+ {"name" : "BitmapButton", "class" :
dui.dBitmapButton, "order" : 20},
+ {"name" : "Button", "class" : dui.dButton,
"order" : 30},
+ {"name" : "CheckBox", "class" : dui.dCheckBox,
"order" : 40},
+ {"name" : "CodeEditor", "class" : dui.dEditor,
"order" : 45},
+ {"name" : "ComboBox", "class" : dui.dComboBox,
"order" : 50},
+ {"name" : "DateTextBox", "class" :
dui.dDateTextBox, "order" : 60},
+ {"name" : "DropdownList", "class" :
dui.dDropdownList, "order" : 70},
+ {"name" : "EditBox", "class" : dui.dEditBox,
"order" : 80},
+ {"name" : "Gauge", "class" : dui.dGauge,
"order" : 90},
+ {"name" : "Grid", "class" : dui.dGrid, "order"
: 100},
+ {"name" : "Image", "class" : dui.dImage,
"order" : 110},
+ {"name" : "Label", "class" : dui.dLabel,
"order" : 120},
+ {"name" : "Line", "class" : dui.dLine, "order"
: 130},
+ {"name" : "ListBox", "class" : dui.dListBox,
"order" : 140},
+ {"name" : "ListControl", "class" :
dui.dListControl, "order" : 150},
+ {"name" : "RadioList", "class" :
dui.dRadioList, "order" : 160},
+ {"name" : "Page", "class" : dui.dPage, "order"
: 170},
+ {"name" : "Panel", "class" : dui.dPanel,
"order" : 180},
+ {"name" : "ScrollPanel", "class" :
dui.dScrollPanel, "order" : 190},
+ {"name" : "PageFrame", "class" :
dui.dPageFrame, "order" : 200},
+ {"name" : "PageList", "class" : dui.dPageList,
"order" : 210},
+ {"name" : "PageSelect", "class" :
dui.dPageSelect, "order" : 220},
+ {"name" : "PageFrameNoTabs", "class" :
dui.dPageFrameNoTabs, "order" : 230},
+ {"name" : "Slider", "class" : dui.dSlider,
"order" : 240},
+ {"name" : "Spinner", "class" : dui.dSpinner,
"order" : 250},
+ {"name" : "Splitter", "class" : dui.dSplitter,
"order" : 260},
+ {"name" : "TextBox", "class" : dui.dTextBox,
"order" : 270},
+ {"name" : "ToggleButton", "class" :
dui.dToggleButton, "order" : 280},
+ {"name" : "TreeView", "class" : dui.dTreeView,
"order" : 290}
+ )
+ self._initSizerDefaults()
+ self._initClassEvents()
+
+ self.setup()
+
+ clsOK = False
+ if clsFile:
+ try:
+ frm = self.openClass(clsFile)
+ clsOK = True
+ except IOError, e:
+ dui.stop(str(e))
+
+ if not clsOK:
+ # Define the form class, and instantiate it.
+ frmClass = self.getFormClass()
+
+ # Temp! for development
+# useSz = not os.path.exists("/Users/ed/dls")
+# frm = frmClass(UseSizers=useSz)
+ frm = frmClass(UseSizers=True)
+
+ frm._setupPanels()
+ # Use this to determine if an empty class should be
released
+ frm._initialStateDict = frm.getDesignerDict()
+ else:
+ frm._initialStateDict = {}
+ frm.Controller = self
+ self.MainForm = frm
+ # When more than one ClassDesigner is open, this will
+ # hold the active reference.
+ self.CurrentForm = frm
+ # Create the form the holds the PropSheet, Method listing
+ # and object tree if it hasn't already been created.
+ pf = self._pemForm
+ if pf is None:
+ pf = self._pemForm = PemForm(None)
+ pf.Controller = self
+ pf.Visible = True
+
+ # Create the control palette
+ palette = self.ControlPalette
+ palette.Controller = self
+ palette.Visible = False
+
+ # Create the sizer palette, but make it hidden to start
+ palette = self.SizerPalette
+ palette.Controller = self
+ palette.Visible = False
+
+ # Create the Code Editor
+ ed = self.EditorForm
+ ed.Controller = self
+ ed.Visible = True
+
+ # Set the initial selection to the form
+ self.select(self.CurrentForm)
+
+ frm.Visible = True
+ dui.callAfter(frm.layout)
+ dui.callAfterInterval(100, self.updateLayout)
+ dui.callAfter(frm.bringToFront)
+ dui.callAfter(frm.saveState)
+ self.start()
+
+
+ def _initSizerDefaults(self):
+ """Create a dict containing the sizer default settings
+ for each designer class.
+ """
+ self._sizerDefaults = {}
+ defVals = {"BorderSides": ["All"], "Proportion": 1, "HAlign":
"Left",
+ "VAlign": "Top", "Border": 0, "Expand": True}
+ # Use the defaults for each class, except where specified
+ dct = defVals.copy()
+ self._sizerDefaults[dui.dBox] = dct
+ dct = defVals.copy()
+ dct.update({"HAlign" : "center", "VAlign" : "middle"})
+ self._sizerDefaults[dui.dBitmap] = dct
+ dct = defVals.copy()
+ dct.update({"Proportion" : 0, "Expand" : False})
+ dct.update({"HAlign" : "center", "VAlign" : "middle"})
+ self._sizerDefaults[dui.dBitmapButton] = dct
+ dct = defVals.copy()
+ dct.update({"Proportion" : 0, "Expand" : False})
+ dct.update({"HAlign" : "center", "VAlign" : "middle"})
+ self._sizerDefaults[dui.dButton] = dct
+ dct = defVals.copy()
+ dct.update({"Proportion" : 0})
+ self._sizerDefaults[dui.dCheckBox] = dct
+ dct = defVals.copy()
+ dct.update({"Proportion" : 0})
+ self._sizerDefaults[dui.dComboBox] = dct
+ dct = defVals.copy()
+ dct.update({"Proportion" : 0})
+ self._sizerDefaults[dui.dDateTextBox] = dct
+ dct = defVals.copy()
+ self._sizerDefaults[dui.dDialog] = dct
+ dct = defVals.copy()
+ dct.update({"Proportion" : 0})
+ self._sizerDefaults[dui.dDropdownList] = dct
+ dct = defVals.copy()
+ self._sizerDefaults[dui.dEditBox] = dct
+ dct = defVals.copy()
+ self._sizerDefaults[dui.dEditor] = dct
+ dct = defVals.copy()
+ dct.update({"Proportion" : 0})
+ self._sizerDefaults[dui.dGauge] = dct
+ dct = defVals.copy()
+ self._sizerDefaults[dui.dGrid] = dct
+ dct = defVals.copy()
+ self._sizerDefaults[dui.dGridSizer] = dct
+ dct = defVals.copy()
+ self._sizerDefaults[dui.dHtmlBox] = dct
+ dct = defVals.copy()
+ dct.update({"HAlign" : "center", "VAlign" : "middle"})
+ self._sizerDefaults[dui.dImage] = dct
+ dct = defVals.copy()
+ dct.update({"Proportion" : 0, "Expand" : False})
+ self._sizerDefaults[dui.dLabel] = dct
+ dct = defVals.copy()
+ dct.update({"Proportion" : 0})
+ dct.update({"HAlign" : "center", "VAlign" : "middle"})
+ self._sizerDefaults[dui.dLine] = dct
+ dct = defVals.copy()
+ self._sizerDefaults[dui.dListBox] = dct
+ dct = defVals.copy()
+ self._sizerDefaults[dui.dListControl] = dct
+ dct = defVals.copy()
+ self._sizerDefaults[dui.dOkCancelDialog] = dct
+ dct = defVals.copy()
+ self._sizerDefaults[dui.dRadioList] = dct
+ dct = defVals.copy()
+ self._sizerDefaults[dui.dPage] = dct
+ dct.update({"HAlign" : "center", "VAlign" : "middle"})
+ self._sizerDefaults[dui.dPanel] = dct
+ dct = defVals.copy()
+ dct.update({"HAlign" : "center", "VAlign" : "middle"})
+ self._sizerDefaults[dui.dScrollPanel] = dct
+ dct = defVals.copy()
+ dct.update({"HAlign" : "center", "VAlign" : "middle"})
+ self._sizerDefaults[dui.dPageFrame] = dct
+ dct = defVals.copy()
+ dct.update({"HAlign" : "center", "VAlign" : "middle"})
+ self._sizerDefaults[dui.dPageList] = dct
+ dct = defVals.copy()
+ dct.update({"HAlign" : "center", "VAlign" : "middle"})
+ self._sizerDefaults[dui.dPageSelect] = dct
+ dct = defVals.copy()
+ dct.update({"HAlign" : "center", "VAlign" : "middle"})
+ self._sizerDefaults[dui.dPageFrameNoTabs] = dct
+ dct = defVals.copy()
+ self._sizerDefaults[dui.dSizer] = dct
+ dct = defVals.copy()
+ dct.update({"Proportion" : 0})
+ dct.update({"HAlign" : "center", "VAlign" : "middle"})
+ self._sizerDefaults[dui.dSlider] = dct
+ dct = defVals.copy()
+ dct.update({"Proportion" : 0})
+ self._sizerDefaults[dui.dSpinner] = dct
+ dct = defVals.copy()
+ dct.update({"HAlign" : "center", "VAlign" : "middle"})
+ self._sizerDefaults[dui.dSplitter] = dct
+ dct = defVals.copy()
+ dct.update({"Proportion" : 0})
+ self._sizerDefaults[dui.dTextBox] = dct
+ dct = defVals.copy()
+ dct.update({"Proportion" : 0, "Expand" : False})
+ dct.update({"HAlign" : "center", "VAlign" : "middle"})
+ self._sizerDefaults[dui.dToggleButton] = dct
+ dct = defVals.copy()
+ dct.update({"HAlign" : "center", "VAlign" : "middle"})
+ self._sizerDefaults[dui.dTreeView] = dct
+ return
+
+
+ def _initClassEvents(self):
+ """Create a dict by baseclass of all applicable events."""
+ self._classEvents = {}
+ self._classMethods = {}
+ baseEvents = ("DataEvent", "EditorEvent", "GridEvent",
"KeyEvent",
+ "ListEvent", "MenuEvent", "MouseEvent",
"SashEvent",
+ "CalendarEvent", "TreeEvent")
+ classes = (dui.dBox, dui.dBitmap, dui.dBitmapButton,
dui.dButton, dui.dCheckBox,
+ dui.dComboBox, dui.dDateTextBox, dui.dDialog,
dui.dDropdownList,
+ dui.dEditBox, dui.dEditor, dui.dForm,
dui.dDockForm, dui.dGauge, dui.dGrid, dui.dImage,
+ dui.dLabel, dui.dLine, dui.dListBox,
dui.dListControl, dui.dOkCancelDialog,
+ dui.dPanel, dui.dPage, dui.dScrollPanel,
dui.dPage, dui.dPageFrame,
+ dui.dPageList, dui.dPageSelect,
dui.dPageFrameNoTabs, dui.dRadioList,
+ dui.dSlider, dui.dSpinner, dui.dSplitter,
dui.dTextBox, dui.dToggleButton,
+ dui.dTreeView, dlgs.Wizard, dlgs.WizardPage)
+
+ def evtsForClass(cls):
+ ret = []
+ for kk, vv in dEvents.__dict__.items():
+ if kk in baseEvents:
+ # These are superclasses of individual
events.
+ continue
+ try:
+ if vv.appliesToClass(cls):
+ ret.append("on%s" % kk)
+ except:
+ pass
+ ret.sort()
+ return ret
+
+ def mthdsForClass(cls):
+ ret = []
+ mthds = inspect.getmembers(cls, inspect.ismethod)
+ ret = [mthd[0] for mthd in mthds
+ if mthd[0][0] in
"abcdefghijklmnopqrstuvwxyz"]
+ return ret
+
+ for cls in classes:
+ self._classEvents[cls] = evtsForClass(cls)
+ self._classMethods[cls] = mthdsForClass(cls)
+
+ def getFormClass(self, filepath=None):
+ """If the selected class is a form/dialog, return a mixed-in
+ subclass of it. Otherwise, return the base ClassDesignerForm.
+ """
+ formIsMain = issubclass(self._selectedClass, (dui.dForm,
dui.dDialog))
+ isDialog = issubclass(self._selectedClass, (dui.dDialog, ))
+ isWizard = issubclass(self._selectedClass, (dlgs.Wizard, ))
+ isDockForm = _USE_DOCKFORM and issubclass(self._selectedClass,
(dui.dDockForm, ))
+ if formIsMain:
+ if isDockForm:
+ base = self._selectedClass
##dui.dForm
+ elif not isDialog and self._desFormClass is not None:
+ return self._desFormClass
+ else:
+ base = self._selectedClass
+ else:
+ base = dui.dForm
+ class DesForm(dfm, base):
+ _superBase = base
+ _superMixin = dfm
+ _classFile = filepath
+ def __init__(self, parent=None, *args, **kwargs):
+ self._isMain = formIsMain
+ if isDialog:
+ kwargs["BorderResizable"] = True
+ kwargs["ShowCloseButton"] = True
+ if isWizard:
+ kwargs["Caption"] = "Dabo Wizard
Designer"
+ base.__init__(self, parent=parent, *args,
**kwargs)
+ dfm.__init__(self, parent=parent, *args,
**kwargs)
+ self._basePrefKey =
"dabo.ide.ClassDesigner.ClassDesignerForm"
+
+ def _afterInit(self):
+ self._designerMode = True
+ self._formMode = True
+ if isDockForm:
+ self._configureForDockForm()
+ super(DesForm, self)._afterInit()
+
+ def addControls(self):
+ if not isinstance(self, dui.dOkCancelDialog):
+ # Could be a wizard, or some other
object with an 'addControls' method
+ self._superBase.addControls(self)
+ return
+ if self.UseSizers:
+ self.mainPanel = LayoutBasePanel(self)
+ self.Sizer.append1x(self.mainPanel)
+ self.mainPanel.Sizer = LayoutSizer("v")
+ # Use a Layout Sizer instead of the
default sizer.
+ self.initLayoutPanel =
LayoutPanel(self.mainPanel)
+ else:
+ self.mainPanel = self.initLayoutPanel =
NoSizerBasePanel(self, BackColor=(222,222,255))
+ self.Sizer.append1x(self.mainPanel)
+ self.layout()
+ # We need to 'deactivate' the built-in buttons
+ self.btnOK.unbindEvent(dEvents.Hit)
+ self.btnCancel.unbindEvent(dEvents.Hit)
+ self.btnOK.Enabled = self.btnCancel.Enabled =
False
+
+
+ def _setupPanels(self, fromNew=True):
+ if isinstance(self, dlgs.Wizard):
+ self.mainPanel = self.pagePanel
+ if self.UseSizers:
+ self.mainPanel.Sizer =
LayoutSizer("v")
+ if fromNew:
+ # Need to ask for number of
pages.
+ numPages =
dabo.ui.getInt(_("How many pages?"), caption=_("Wizard Pages"),
+ defaultValue=3)
+ pgCls =
self.getControlClass(dlgs.WizardPage)
+ pgs = [pgCls] * max(1, numPages)
+ self.append(pgs)
+ for num, p in
enumerate(self._pages):
+ # Remove the title and
line from the current sizer
+ p.Caption = _("Page %s
Title") % num
+ if self.UseSizers:
+ # This will
automatically add itself to the sizer
+ LayoutPanel(p)
+ else:
+
p.Sizer.append1x(NoSizerBasePanel(p))
+ self.initLayoutPanel =
self._pages[0].Children[0]
+ else:
+ self.initLayoutPanel =
self.mainPanel
+ self.CurrentPage = 0
+ self.btnCancel.Enabled = False
+ # Prevent the Finish button from
closing the design surface.
+ self.finish = lambda: False
+ return
+
+ if self.UseSizers:
+ if isinstance(self,
dui.dOkCancelDialog):
+ # already done
+ return
+ if _USE_DOCKFORM and isinstance(self,
dui.dDockForm):
+ self.mainPanel =
self.CenterPanel
+ else:
+ self.Sizer = dui.dSizer("v")
+ self.mainPanel =
LayoutBasePanel(self)
+
self.Sizer.append1x(self.mainPanel)
+
+ self.mainPanel.Sizer = LayoutSizer("v")
+ # Use a Layout Sizer instead of the
default sizer.
+ self.initLayoutPanel =
LayoutPanel(self.mainPanel)
+ else:
+ self.Sizer.release()
+ self.Sizer = None
+ self.mainPanel = self.initLayoutPanel =
NoSizerBasePanel(self, BackColor=(222,222,255))
+ self.layout()
+ ret = DesForm
+ if formIsMain and not isDialog and not isDockForm:
+ self._desFormClass = ret
+ return ret
+
+
+ def _reuseMainForm(self, useSizers=False):
+ """Determines if the MainForm for the Class Designer is a
blank, unedited
+ form, which can be re-used when the user opens an existing
class or
+ creates a new class.
+ """
+ mf = self.MainForm
+ if mf:
+ if mf.UseSizers != useSizers:
+ return False
+ mfCurrDict = mf.getDesignerDict()
+ # Position and size of the form may have changed;
delete those
+ # since they are irrelevant. Also, it seems that on
Windows these
+ # atts are set while the object is being created, so we
have to
+ # clear them in the _initialStateDict, too.
+ for att in ("Left", "Top", "Width", "Height"):
+ try:
+ del mfCurrDict["attributes"][att]
+ except: pass
+ try:
+ del
mf._initialStateDict["attributes"][att]
+ except: pass
+ ret = mf and (mf._initialStateDict == mfCurrDict)
+ return ret
+
+
+ def onEditUndo(self, evt):
+ dabo.infoLog.write(_("Not implemented yet"))
+ def onEditRedo(self, evt):
+ dabo.infoLog.write(_("Not implemented yet"))
+
+
+ def _importClassXML(self, pth):
+ """Read in the XML and associated code file (if any), and
+ return a dict that can be used to re-create the object.
+ """
+ try:
+ if not os.path.exists(pth):
+ if os.path.exists(os.path.abspath(pth)):
+ pth = os.path.abspath(pth)
+ dct = xtd.xmltodict(pth, addCodeFile=True)
+ except StandardError, e:
+ if pth.strip().startswith("<?xml") or
os.path.exists(pth):
+ raise IOError, _("This does not appear to be a
valid class file.")
+ else:
+ raise IOError, _("The class file '%s' was not
found.") % pth
+
+
+ # Traverse the dct, looking for superclass information
+ super = xtd.flattenClassDict(dct)
+ if super:
+ # We need to modify the info to incorporate the
superclass info
+ xtd.addInheritedInfo(dct, super)
+ # Store the base code so that we can determine if
instances have
+ # modified it.
+ self._updateClassCodeRepository(super)
+ return dct
+
+
+ def _updateClassCodeRepository(self, dct):
+ """Take a flattened dict of class IDs and store any code
+ associated with those IDs, so that we can later compare it to
+ an object's code in order to determine if it has been changed.
+ """
+ cds = [(kk, vv["code"]) for kk, vv in dct.items()
+ if vv["code"]]
+ for cd in cds:
+ self._classCodeDict.update({cd[0]: cd[1]})
+
+
+ def _getClassMethod(self, clsID, mthd):
+ """Given a class ID and a method name, returns the code for that
+ classID/method combination (if any) from self._classCodeDict.
+ """
+ cd = self._classCodeDict.get(clsID, {})
+ return cd.get(mthd, "")
+
+
+ def _findSizerInClassDict(self, clsd):
+ """Recursively search until a child is found with sizer
information.
+ If no such child is found, return False.
+ """
+ ret = False
+ atts = clsd.get("attributes", {})
+ szinf = atts.get("sizerInfo", "{}")
+ if szinf != "{}":
+ ret = True
+ else:
+ kids = clsd.get("children", [])
+ for kid in kids:
+ ret = self._findSizerInClassDict(kid)
+ if ret:
+ break
+ return ret
+
+
+ def openClass(self, pth):
+ """Called when the user selects the 'Open' menu and selects
+ a saved XML file. We need to open the file, and confirm that it
is
+ indeed a valid class file. If so, we then re-construct the
class in
+ a new ClassDesigner window.
+ """
+ # Set the flag so that components know what process we're in.
+ self.openingClassXML = True
+ # Clear any existing superclass info
+ self._superClassInfo = {}
+ # Translate the file path into a class dictionary.
+ clsd = self._importClassXML(pth)
+ # See if the class name requires a separate import
+ nm = clsd["name"]
+ try:
+ imp, clsname = nm.rsplit(".", 1)
+ imptSt = "from %(imp)s import %(clsname)s" % locals()
+ exec imptSt in locals()
+ clsd["fullname"] = nm
+ clsd["name"] = clsname
+ except ValueError:
+ clsd["fullname"] = nm
+
+ # See if it is a full form-based class, or an individual
component.
+ isFormClass = (clsd["name"] in ("dForm", "dDockForm",
"dDialog", "dOkCancelDialog", "Wizard"))
+ if isFormClass:
+ atts = clsd["attributes"]
+ del atts["designerClass"]
+ nm = clsd["name"]
+ else:
+ atts = {"UseSizers": self._findSizerInClassDict(clsd)}
+ nm = "ClassDesignerForm"
+
+ isDlg = (clsd["name"] in ("dDialog", "dOkCancelDialog",
"Wizard"))
+ isWiz = (clsd["name"] in ("Wizard",))
+ if isDlg:
+ self._selectedClass = {"dDialog": dui.dDialog,
+ "dOkCancelDialog": dui.dOkCancelDialog,
+ "Wizard": dlgs.Wizard}[clsd["name"]]
+
+ # Convert any paths in the atts
+ self._basePath = pth
+ dabo.lib.utils.resolveAttributePathing(atts, pth)
+ # Read in any .cnxml connection defs.
+ currdir = os.path.dirname(pth)
+ self._initDB(currdir)
+ if os.path.split(currdir)[-1].lower() == "ui":
+ # Standard directory structure; process the parent
directory
+ self._initDB(os.path.dirname(currdir))
+ if self._reuseMainForm(useSizers=atts.get("UseSizers", False)):
+ # Original form hasn't changed, so just use it.
+ frm = self.MainForm
+ frm.setPropertiesFromAtts(atts)
+ else:
+ # For now, just create a standard dForm mixed-in
ClassDesigner
+ # form as the base.
+ frmClass = self.getFormClass(filepath=pth)
+ if isWiz:
+ self._extractKey(atts, "PageCount")
+ frm = frmClass(None, Name=nm, SaveRestorePosition=False,
+ attProperties=atts)
+ if isWiz:
+ self._recreateWizardPages(frm, clsd["children"])
+ # Clear the children dict
+ clsd["children"] = []
+ frm._setupPanels(fromNew=False)
+ lp = frm.initLayoutPanel
+ if isFormClass and frm.UseSizers and not isWiz:
+ # Remove the LayoutPanel that was added
+ lp.ControllingSizer.remove(lp, True)
+ self._srcObj = frm.mainPanel
+ else:
+ self._srcObj = lp
+ if not isFormClass:
+ # Set the Caption of the form to the class name
+ fname = os.path.split(pth)[1]
+ frm.Caption = os.path.splitext(fname)[0]
+ frm.Controller = self
+ self.CurrentForm = frm
+ frm._classFile = pth
+ frm._formMode = frm.SaveRestorePosition = isFormClass
+ if isFormClass:
+ # See if there is any code associated with the form
+ code = clsd.get("code", "")
+ if code:
+ self._codeDict[frm] = {}
+ # Each method will be a separate dict
+ for mthd, cd in code.items():
+ cd = cd.replace("\n]", "]")
+ if mthd == "importStatements":
+ self._classImportDict[frm] = cd
+ else:
+ self._codeDict[frm][mthd] = cd
+ # Do the same for the properties
+ propDefs = clsd.get("properties", {})
+ # Restore any prop definitions.
+ if propDefs:
+ self._classPropDict[frm] = propDefs
+ # Set the child objects
+ kids = clsd["children"]
+ else:
+ # Add the class to the form
+ kids = clsd
+ if frm.UseSizers:
+ self._extractKey(clsd["attributes"], "Top")
+ self._extractKey(clsd["attributes"], "Left")
+ self._extractKey(clsd["attributes"], "Height")
+ self._extractKey(clsd["attributes"], "Width")
+ # Add the child objects recursively
+ obj = self.recreateChildren(frm.mainPanel, kids, None, False)
+ # Clear the superclass info
+ self._superClassInfo = {}
+ self._basePath = None
+ if isFormClass and obj:
+ self.select(obj)
+ else:
+ self.select(frm)
+ # Clear the process flag
+ self.openingClassXML = False
+ # Show it!
+ frm.Centered = True
+ frm.Visible = True
+ # Save the initial state
+ dabo.ui.callAfter(frm.saveState)
+
+ return frm
+
+
+ def extractSuperClassInfo(self, pth):
+ try:
+ superdct = xtd.xmltodict(pth, addCodeFile=True)
+ except:
+ raise IOError, _("This does not appear to be a valid
class file.")
+ # Traverse the dct, looking for superclass information
+ sup = xtd.flattenClassDict(superdct)
+ # Store the base code so that we can determine if instances have
+ # modified it.
+ self._updateClassCodeRepository(sup)
+ # Add it to the current class definitions
+ self._superClassInfo.update(sup)
+
+
+ def inherit(self, dct):
+ super = self._superClassInfo
+ if super:
+ # We need to modify the info to incorporate the
superclass info
+ xtd.addInheritedInfo(dct, super)
+ return dct
+
+
+ def recreateChildren(self, parent, chld, szr, fromSzr, debug=0):
+ """Recursive routine to re-create the sizer/object structure of
+ the class.
+ """
+ ret = None
+ if isinstance(chld, dict):
+ # Single child passed
+ chld = [chld]
+ for dct in chld:
+ atts = dct["attributes"]
+ # Convert any paths in the atts
+ dabo.lib.utils.resolveAttributePathing(atts,
self._basePath)
+ clsname = self._extractKey(atts, "designerClass", "")
+ # See if this is a saved class inserted into another
design
+ isCustomClass = False
+ customClassPath = None
+ if os.path.exists(clsname) and atts.has_key("classID"):
+ isCustomClass = True
+ customClassPath = clsname
+ # Start with the custom class, and then update
it with the current stuff
+ self.extractSuperClassInfo(clsname)
+ self.inherit(dct)
+ cls = dct["name"]
+ classID = self._extractKey(atts, "classID", "")
+ kids = dct.get("children", None)
+ if self._addingClass:
+ code = {}
+ else:
+ code = dct.get("code", {})
+ propDefs = dct.get("properties", {})
+ sizerInfo = self._extractKey(atts, "sizerInfo", "{}")
+ if isinstance(sizerInfo, basestring):
+ sizerInfoDict = eval(sizerInfo)
+ else:
+ sizerInfoDict = sizerInfo
+
+ rowColAtts = self._extractKey(atts, "rowColPos",
"(None,None)")
+ if clsname == "LayoutPanel":
+ # Panel has already been created by the sizer's
slots;
+ # just set any sizer item props.
+ pnl = self._srcObj
+ sz = pnl.ControllingSizer
+ itm = pnl.ControllingSizerItem
+ sz.setItemProps(itm, sizerInfoDict)
+ if classID:
+ pnl.classID = classID
+ if kids:
+ self.recreateChildren(pnl, kids, None,
False)
+
+ elif clsname == "LayoutSpacerPanel":
+ spc = int(atts.get("Spacing", "20"))
+ pnl = self._srcObj
+ prnt = pnl.Parent
+ pos = pnl.getPositionInSizer()
+ sz = pnl.ControllingSizer
+ sz.remove(pnl)
+ dui.callAfter(pnl.release)
+ obj = LayoutSpacerPanel(prnt, Spacing=spc)
+ if isinstance(sz, dui.dGridSizer):
+ itm = sz.append(obj, row=pos[0],
col=pos[1])
+ else:
+ itm = sz.insert(pos, obj)
+ sz.setItemProps(itm, sizerInfoDict)
+ if classID:
+ obj.classID = classID
+ ret = obj
+
+ elif clsname in ("LayoutSizer", "LayoutBorderSizer"):
+ ornt = self._extractKey(atts, "Orientation",
"h")
+ slots = int(self._extractKey(atts, "SlotCount",
"1"))
+ useBox, boxCaption = None, None
+ if clsname == "LayoutBorderSizer":
+ useBox = True
+ boxCaption = self._extractKey(atts,
"Caption", None)
+ sz, pnl = self.addSizer("box", orient=ornt,
slots=slots,
+ useBox=useBox,
boxCaption=boxCaption)
+ szCont = sz.ControllingSizer
+ itm = sz.ControllingSizerItem
+
+ is2D = isinstance(szCont, dabo.ui.dGridSizer)
+ defaults = {True: szItemDefaults[2],
+ False: szItemDefaults[1]}[is2D]
+ defAtts = {}
+ for key, val in defaults.items():
+ defAtts["Sizer_%s" % key] = val
+ defAtts.update(dictStringify(atts))
+ atts = defAtts
+ sz.setPropertiesFromAtts(atts)
+ if classID:
+ sz.classID = classID
+ if not fromSzr:
+ parent.Sizer = sz
+ if szCont is not None and itm is not None:
+ szCont.setItemProps(itm, sizerInfoDict)
+ if kids:
+ # We need to set the value of _srcObj
to the individual
+ # LayoutPanel in the sizer. The number
of kids should
+ # match the number of slots created
when the sizer
+ # was created.
+ childWindowList = sz.ChildWindows[:]
+ for pos, kid in enumerate(kids):
+ # Set the LayoutPanel to the
'source' object
+ pnl = self._srcObj =
childWindowList[pos]
+ # Pass the 'kid' as a list,
since that's what
+ # recreateChildren() expects.
+ self.recreateChildren(parent,
[kid], sz, True)
+ ret = sz
+
+ elif clsname == "LayoutGridSizer":
+ rows = int(self._extractKey(atts, "Rows", "1"))
+ cols = int(self._extractKey(atts, "Columns",
"1"))
+ sz, pnl = self.addSizer("grid", rows=rows,
cols=cols)
+ szCont = sz.ControllingSizer
+ is2D = isinstance(szCont, dabo.ui.dGridSizer)
+ defaults = {True: szItemDefaults[2],
+ False: szItemDefaults[1]}[is2D]
+ defAtts = {}
+ for key, val in defaults.items():
+ defAtts["Sizer_%s" % key] = val
+ defAtts.update(dictStringify(atts))
+ atts = defAtts
+ sz.setPropertiesFromAtts(atts)
+ if not fromSzr:
+ parent.Sizer = sz
+ itm = sz.ControllingSizerItem
+ if szCont is not None and itm is not None:
+ szCont.setItemProps(itm, sizerInfoDict)
+ if classID:
+ sz.classID = classID
+ if kids:
+ for kid in kids:
+ kidatts = kid["attributes"]
+ rowCol =
kidatts.get("rowColPos")
+ if isinstance(rowCol, tuple):
+ row, col = rowCol
+ else:
+ row, col =
eval(kidatts.get("rowColPos"))
+ # Set the LayoutPanel to the
'source' object
+ pnl = self._srcObj =
sz.getItemByRowCol(row, col)
+ # Pass the 'kid' as a list,
since that's what
+ # recreateChildren() expects.
+ obj =
self.recreateChildren(parent, [kid], sz, True)
+ ret = sz
+
+ else:
+ # An actual control!
+ if szr:
+ if isinstance(szr, LayoutGridSizer):
+ if isinstance(rowColAtts,
tuple):
+ row, col = rowColAtts
+ else:
+ row, col =
eval(rowColAtts)
+ if row is not None and col is
not None:
+ # It has a given
position, so use that. Otherwise,
+ # they may be pasting
into a grid sizer.
+ self._srcObj =
szr.getItemByRowCol(row, col)
+ props = {}
+
+ try:
+ imp, clsname = cls.rsplit(".", 1)
+ imptSt = "from %(imp)s import
%(clsname)s" % locals()
+ exec imptSt in locals()
+ dct["fullname"] = cls
+ dct["name"] = clsname
+ newClass = eval(clsname)
+ except ValueError:
+ dct["fullname"] = cls
+ newClass = dui.__dict__[cls]
+
+ isGrid = issubclass(newClass, dui.dGrid)
+ isTree = issubclass(newClass, dui.dTreeView)
+ isSplitter = issubclass(newClass, dui.dSplitter)
+ isPageControl = issubclass(newClass,
self.pagedControls)
+ noTabs = issubclass(newClass,
dui.dPageFrameNoTabs)
+ if isGrid:
+ try:
+ # The column entries will
create themselves, so
+ # we don't want to create them
now.
+ del atts["ColumnCount"]
+ except:
+ pass
+ props["ColumnCount"] = 0
+ elif isPageControl:
+ props["PageCount"] =
int(atts.get("PageCount", "0"))
+ props["TabPosition"] =
atts.get("TabPosition", "")
+ try:
+ del atts["PageCount"]
+ except: pass
+ try:
+ del atts["TabPosition"]
+ except: pass
+ if noTabs:
+ del props["TabPosition"]
+ elif isSplitter:
+ ornt = self._extractKey(atts,
"Orientation", "Vertical")
+ splt = self._extractKey(atts, "Split",
"False")
+ props["createPanes"] = False
+ atts["Split"] = False
+ # If we are pasting, we can get two objects
with the same
+ # Name value, so change it to NameBase.
+ nm = self._extractKey(atts, "Name", clsname)
+ props["NameBase"] = nm
+ obj = self.addNewControl(None, newClass,
props=props,
+ skipUpdate=True,
attProperties=atts)
+ ret = obj
+ if isSplitter:
+
obj.setPropertiesFromAtts({"Orientation": ornt})
+ if splt:
+ dabo.ui.setAfter(obj, "Split",
True)
+ sz = obj.ControllingSizer
+ itm = obj.ControllingSizerItem
+ if sz is not None and itm is not None:
+ sz.setItemProps(itm, sizerInfoDict)
+ if classID:
+ obj.classID = classID
+
+ for mthd, cd in code.items():
+ if not self._codeDict.g
(721584 bytes were truncated as it was too long for the email (max 40000
bytes.)
_______________________________________________
Post Messages to: [email protected]
Subscription Maintenance: http://leafe.com/mailman/listinfo/dabo-dev
Searchable Archives: http://leafe.com/archives/search/dabo-dev
This message: http://leafe.com/archives/byMID/[EMAIL PROTECTED]