dabodemo Commit Revision 438 Date: 2006-10-31 08:28:17 -0800 (Tue, 31 Oct 2006) Author: ed
Changed: U trunk/DaboDemo/DaboDemo-code.py U trunk/DaboDemo/DaboDemo.cdxml U trunk/DaboDemo/Modules.py
Log: OK, I've got the whole 'modified code' thing working now. You can edit the code in any sample, and save that code. When you go to the demo page, the result of your modifications will be visible. You can switch between the original and modified at any time. It is written to disk, so the modifications persist between sessions.
I also implemented the DemoErrorPanel, which will display if the modified code contains any errors. It will display the traceback information, and let you jump back to the 'offending' line. This was pretty much lifted straight from the wxPython demo, but re-written to 100% Dabo code.
Diff: Modified: trunk/DaboDemo/DaboDemo-code.py =================================================================== --- trunk/DaboDemo/DaboDemo-code.py 2006-10-30 22:18:27 UTC (rev 437) +++ trunk/DaboDemo/DaboDemo-code.py 2006-10-31 16:28:17 UTC (rev 438) @@ -3,12 +3,11 @@ ### 'Dabo Code ID: XXXX', ### as these are needed to link the code to the objects. -## *!* ## Dabo Code ID: dPageFrame-dPage -def showDemoPage(self): - self.SelectedPageNumber = 2 +## *!* ## Dabo Code ID: dHtmlBox-dPage +def afterInit(self): + self.HTML = """<h1 align="center">Dabo Demonstration</h1>""" - ## *!* ## Dabo Code ID: dEditBox-dPanel def clear(self, evt=None): self.Value = "" @@ -21,22 +20,32 @@ -## *!* ## Dabo Code ID: dHtmlBox-dPage -def afterInit(self): - self.HTML = """<h1 align="center">Dabo Demonstration</h1>""" -# self.Value = _("Dabo Demonstration") -# self.Alignment = "Center" -# self.FontSize = 32 -# self.FontBold = True - - - ## *!* ## Dabo Code ID: dEditor-dPage def onContentChanged(self, evt): self.Form.editorChanged() +## *!* ## Dabo Code ID: dButton-dPage-409 +def onHit(self, evt): + # Delete modified code + self.Form.deleteModCode() + + + +## *!* ## Dabo Code ID: dButton-dPage +def onHit(self, evt): + # Save modified code + self.Form.saveModCode() + + + +## *!* ## Dabo Code ID: dPageFrame-dPage +def showDemoPage(self): + self.SelectedPageNumber = 2 + + + ## *!* ## Dabo Code ID: dRadioList-dPage def afterInit(self): self.reset(False) @@ -63,8 +72,23 @@ import os import sys from Modules import DemoModules +from Modules import DemoError +from Modules import DemoErrorPanel from dabo.dLocalize import _ +def _getActiveCode(self): + try: + ret = self.demoModules.getActive() + except StandardError, e: + ret = 0 + return ret + +def _setActiveCode(self, val): + self.demoModules.setActive(val) + self.loadDemo() + self.loadDemoSource() + self.radMod.Value = val + def afterInitAll(self): pth = os.path.abspath(os.path.join(os.getcwd(), "samples")) if pth not in sys.path: @@ -95,21 +119,32 @@ sn._obj = demos[mc][sc] tree.expandAll() +def deleteModCode(self): + self.demoModules.deleteModified() + self.ActiveCode = 0 + def editorChanged(self): self.saveModButton.Enabled = self.codeEditor.Modified def loadDemo(self): - pnlClass = self.demoModules.getActive().TestPanel dpnl = self.demoPanel sz = dpnl.Sizer for kid in dpnl.Children: sz.remove(kid, True) - pnl = pnlClass(dpnl) + try: + pnl = self.demoModules.getActive().TestPanel(dpnl) + except: + pnl = DemoErrorPanel(dpnl) + err = DemoError(sys.exc_info()) + pnl.setErrorInfo(self.codePage, err) + sz.append1x(pnl) if self.displayFrame.SelectedPageNumber == 0: # Switch to the demo self.demoPageFrame.showDemoPage() + self.demoPanel.layout() + def loadDemoSource(self): dm = self.demoModules self.codeEditor.Value = dm.getSource() @@ -123,12 +158,17 @@ self.log.scrollToEnd() self.log.ShowPosition(self.log.GetLastPosition()) +def saveModCode(self): + self.demoModules.saveMod(self.codeEditor.Value) + self.ActiveCode = 1 + self.demoModules.updateFile() + self.radMod.reset(self.codeEditor.Modified) + def setOverview(self): module = self.demoModules.getActive() ov = module.overview self.moduleOverview.HTML = ov - def treeSelection(self): try: sel = self.tree.Selection._obj @@ -142,3 +182,9 @@ ok = False self.displayFrame.showContents(ok) + +def showCode(self, line=-1): + self.codeEditor.showContainingPage() + if line is not None: + self.codeEditor.LineNumber = line + \ No newline at end of file
Modified: trunk/DaboDemo/DaboDemo.cdxml =================================================================== --- trunk/DaboDemo/DaboDemo.cdxml 2006-10-30 22:18:27 UTC (rev 437) +++ trunk/DaboDemo/DaboDemo.cdxml 2006-10-31 16:28:17 UTC (rev 438) @@ -1,5 +1,17 @@ <?xml version="1.0" encoding="utf-8" standalone="no"?> -<dForm code-ID="dForm-top" Name="DaboDemoForm" Caption="Dabo: A Demonstration" Top="179" Height="668" Width="841" designerClass="DesForm" UseSizers="True" Left="392"> +<dForm code-ID="dForm-top" Name="DaboDemoForm" Caption="Dabo: A Demonstration" Top="79" Height="666" Width="906" designerClass="DesForm" UseSizers="True" Left="68"> + <properties> + <ActiveCode> + <comment>Zero for Original; 1 for modified</comment> + <defaultValue>0</defaultValue> + <deller>None</deller> + <getter>_getActiveCode</getter> + <propName>ActiveCode</propName> + <defaultType>integer</defaultType> + <setter>_setActiveCode</setter> + </ActiveCode> + </properties> + <dSizer SlotCount="1" designerClass="LayoutSizer" Orientation="Vertical"> <dSplitter SashPosition="201" sizerInfo="{'BorderSides': ['All'], 'Proportion': 1, 'HAlign': 'Center', 'VAlign': 'Middle', 'Border': 0, 'Expand': True}" designerClass="controlMix" Split="True" Orientation="Vertical"> <dPanel designerClass="MixedSplitterPanel" Name="dPanel2"> @@ -15,7 +27,7 @@ <dPageFrameNoTabs RegID="displayFrame" code-ID="dPageFrameNoTabs-dPanel" sizerInfo="{'BorderSides': ['All'], 'Proportion': 1, 'HAlign': 'Center', 'VAlign': 'Middle', 'Border': 0, 'Expand': True}" designerClass="controlMix" PageCount="2"> <dPage Caption="" designerClass="controlMix" Name="dPage"> <dSizer SlotCount="1" designerClass="LayoutSizer" Orientation="Vertical"> - <dHtmlBox RegID="mainOverview" code-ID="dHtmlBox-dPage" designerClass="controlMix" sizerInfo="{'BorderSides': ['All'], 'Proportion': 1, 'HAlign': 'Left', 'VAlign': 'Top', 'Border': 0, 'Expand': True}"></dHtmlBox> + <dHtmlBox RegID="mainOverview" code-ID="dHtmlBox-dPage" sizerInfo="{'BorderSides': ['All'], 'Proportion': 1, 'HAlign': 'Left', 'VAlign': 'Top', 'Border': 0, 'Expand': True}" designerClass="controlMix"></dHtmlBox> </dSizer> </dPage> <dPage Caption="" designerClass="controlMix" Name="dPage1"> @@ -23,17 +35,17 @@ <dPageFrame RegID="demoPageFrame" code-ID="dPageFrame-dPage" sizerInfo="{'BorderSides': ['All'], 'Proportion': 1, 'HAlign': 'Center', 'VAlign': 'Middle', 'Border': 0, 'Expand': True}" designerClass="controlMix" PageCount="3"> <dPage Caption="Overview" designerClass="controlMix" Name="dPage"> <dSizer SlotCount="1" designerClass="LayoutSizer" Orientation="Vertical"> - <dHtmlBox RegID="moduleOverview" designerClass="controlMix" sizerInfo="{'BorderSides': ['All'], 'Proportion': 1, 'HAlign': 'Left', 'VAlign': 'Top', 'Border': 0, 'Expand': True}"></dHtmlBox> + <dHtmlBox RegID="moduleOverview" sizerInfo="{'BorderSides': ['All'], 'Proportion': 1, 'HAlign': 'Left', 'VAlign': 'Top', 'Border': 0, 'Expand': True}" designerClass="controlMix"></dHtmlBox> </dSizer> </dPage> - <dPage Caption="Demo Code" designerClass="controlMix" Name="dPage1"> + <dPage Caption="Demo Code" designerClass="controlMix" Name="dPage1" RegID="codePage"> <dSizer SlotCount="2" designerClass="LayoutSizer" Orientation="Vertical"> <dSizer SlotCount="5" sizerInfo="{'BorderSides': ['All'], 'Proportion': 0, 'HAlign': 'Left', 'VAlign': 'Top', 'Border': 0, 'Expand': True}" designerClass="LayoutSizer" Orientation="Horizontal"> <dLabel Caption="Active Version:" sizerInfo="{'BorderSides': ['All'], 'Proportion': 0, 'HAlign': 'Left', 'VAlign': 'Middle', 'Border': 5, 'Expand': False}" designerClass="controlMix"></dLabel> - <dRadioList code-ID="dRadioList-dPage" sizerInfo="{'BorderSides': ['All'], 'Proportion': 0, 'HAlign': 'Left', 'VAlign': 'Middle', 'Border': 0, 'Expand': False}" Orientation="Horizontal" Value="Original" Choices="[u'Original', u'Modified']" Caption="" designerClass="controlMix" ShowBox="False" RegID="radMod"></dRadioList> + <dRadioList code-ID="dRadioList-dPage" sizerInfo="{'BorderSides': ['All'], 'Proportion': 0, 'HAlign': 'Left', 'VAlign': 'Middle', 'Border': 0, 'Expand': False}" ValueMode="position" Orientation="Horizontal" Value="0" Choices="[u'Original', u'Modified']" Caption="" DataSource="self.Form" designerClass="controlMix" ShowBox="False" RegID="radMod" DataField="ActiveCode"></dRadioList> <dPanel Spacing="12" sizerInfo="{'BorderSides': ['All'], 'Proportion': 0, 'HAlign': 'Left', 'VAlign': 'Top', 'Border': 0, 'Expand': True}" designerClass="LayoutSpacerPanel"></dPanel> - <dButton RegID="saveModButton" Caption="Save Changes" sizerInfo="{'BorderSides': ['All'], 'Proportion': 0, 'HAlign': 'Center', 'VAlign': 'Middle', 'Border': 5, 'Expand': False}" designerClass="controlMix"></dButton> - <dButton RegID="delModButton" Caption="Delete Modified" sizerInfo="{'BorderSides': ['All'], 'Proportion': 0, 'HAlign': 'Center', 'VAlign': 'Middle', 'Border': 5, 'Expand': False}" designerClass="controlMix" Name="dButton1"></dButton> + <dButton RegID="saveModButton" Caption="Save Changes" sizerInfo="{'BorderSides': ['All'], 'Proportion': 0, 'HAlign': 'Center', 'VAlign': 'Middle', 'Border': 5, 'Expand': False}" code-ID="dButton-dPage" designerClass="controlMix"></dButton> + <dButton code-ID="dButton-dPage-409" Caption="Delete Modified" sizerInfo="{'BorderSides': ['All'], 'Proportion': 0, 'HAlign': 'Center', 'VAlign': 'Middle', 'Border': 5, 'Expand': False}" designerClass="controlMix" Name="dButton1" RegID="delModButton"></dButton> </dSizer> <dEditor RegID="codeEditor" code-ID="dEditor-dPage" sizerInfo="{'BorderSides': ['All'], 'Proportion': 1, 'HAlign': 'Left', 'VAlign': 'Top', 'Border': 0, 'Expand': True}" designerClass="controlMix"></dEditor> </dSizer>
Modified: trunk/DaboDemo/Modules.py =================================================================== --- trunk/DaboDemo/Modules.py 2006-10-30 22:18:27 UTC (rev 437) +++ trunk/DaboDemo/Modules.py 2006-10-31 16:28:17 UTC (rev 438) @@ -16,6 +16,13 @@ #---------------------------------------------------------------------------- """ import os +import sys +import traceback +import types +import dabo +dabo.ui.loadUI("wx") +import dabo.dEvents as dEvents +from dabo.dLocalize import _ class ModuleDictWrapper: @@ -35,26 +42,30 @@ """Dynamically manages the original/modified versions of a demo module. """ + modOrig = 0 + modMod = 1 + origDir = "samples" + modDir = "modified" + + def __init__(self, name): self.modActive = -1 # Index used in self.modules for orig and modified versions - self.modOrig = 0 - self.modMod = 1 self.name = name # (dict , source , filename , description , error information ) # ( 0 , 1 , 2 , 3 , 4 ) self.modules = [[None, "" , "" , "<original>" , None], [None, "" , "" , "<modified>" , None]] - fname = "samples/%s.py" % name + fname = "%s/%s.py" % (self.origDir, name) # load original module self.loadFromFile(fname, self.modOrig) self.setActive(self.modOrig) # load modified module (if one exists) - modName = "modified/%s.py" % name + modName = "%s/%s.py" % (self.modDir, name) if os.path.exists(modName): - self.loadFromFile(modName, modMod) + self.loadFromFile(modName, self.modMod) def loadFromFile(self, filename, modID): @@ -77,7 +88,7 @@ code = compile(source, description, "exec") exec code in self.modules[modID][0] except: - #self.modules[modID][4] = DemoError(sys.exc_info()) + self.modules[modID][4] = DemoError(sys.exc_info()) self.modules[modID][0] = None else: self.modules[modID][4] = None @@ -125,6 +136,35 @@ return self.modules[self.modMod][1] != "" + def saveMod(self, code): + fname = self.modules[self.modMod][2] + if not fname: + base = os.path.split(self.modules[self.modOrig][2])[-1] + fname = self.modules[self.modMod][2] = os.path.join(self.modDir, base) + self.modules[self.modMod][1] = code + self.updateFile(self.modMod) + self.loadDict(self.modMod) + + + def getOrigDir(cls): + return cls.origDir + getOrigDir = classmethod(getOrigDir) + + + def getModDir(cls): + return cls.modDir + getModDir = classmethod(getModDir) + + + def deleteModified(self): + fname = self.modules[self.modMod][2] + if not fname: + #nothing to delete! + return + self.modules[self.modMod][1] = "" + os.remove(fname) + + def updateFile(self, modID=None): """Updates the file from which a module was loaded with (possibly updated) source @@ -133,7 +173,6 @@ modID = self.modActive source = self.modules[modID][1] filename = self.modules[modID][2] - try: file = open(filename, "wt") file.write(source) @@ -147,3 +186,114 @@ self.modules[modID][0] = None self.modules[modID][1] = "" self.modules[modID][2] = "" + +#--------------------------------------------------------------------------- + +class DemoError: + """Wraps and stores information about the current exception""" + def __init__(self, exc_info): + import copy + + excType, excValue = exc_info[:2] + # traceback list entries: (filename, line number, function name, text) + self.traceback = traceback.extract_tb(exc_info[2]) + + # --Based on traceback.py::format_exception_only()-- + if type(excType) == types.ClassType: + self.exception_type = excType.__name__ + else: + self.exception_type = excType + + # If it's a syntax error, extra information needs + # to be added to the traceback + if excType is SyntaxError: + try: + msg, (filename, lineno, self.offset, line) = excValue + except: + pass + else: + if not filename: + filename = "<string>" + line = line.strip() + self.traceback.append( (filename, lineno, "", line) ) + excValue = msg + try: + self.exception_details = str(excValue) + except: + self.exception_details = "<unprintable %s object>" & type(excValue).__name__ + + del exc_info + + def __str__(self): + ret = "Type %s \n \ + Traceback: %s \n \ + Details : %s" % ( str(self.exception_type), str(self.traceback), self.exception_details ) + return ret + +#--------------------------------------------------------------------------- + +class DemoErrorPanel(dabo.ui.dPanel): + """Panel put into the demo tab when the demo fails to run due to errors""" + + def setErrorInfo(self, codePanel, demoError): + self.codePanel = codePanel + sz = self.Sizer = dabo.ui.dSizer("v") + lbl = dabo.ui.dLabel(self, Caption=_("An error has occurred while trying to run the demo"), + ForeColor="red") + lbl.FontSize += 2 + sz.append(lbl, halign="center", border=10) + + bs = dabo.ui.dBorderSizer(self, "v", Caption=_("Exception Info")) + gs = dabo.ui.dGridSizer(MaxCols=2, HGap=5, VGap=2) + gs.append(dabo.ui.dLabel(self, Caption=_("Type:"), FontBold=True), halign="right") + gs.append(dabo.ui.dLabel(self, Caption=demoError.exception_type), halign="left") + gs.append(dabo.ui.dLabel(self, Caption=_("Details:"), FontBold=True), halign="right") + gs.append(dabo.ui.dLabel(self, Caption=demoError.exception_details), halign="left") + bs.append(gs, border=8) + sz.append(bs, halign="center", border=5) + + + lst = self.tbList = dabo.ui.dListControl(self, BorderStyle="sunken", + MultipleSelect=False) + lst.bindEvent(dEvents.MouseLeftDoubleClick, self.onListDoubleClick) + lst.addColumn(_("Filename")) + lst.addColumn(_("Line")) + lst.addColumn(_("Function")) + lst.addColumn(_("Code")) + self.insertTraceback(lst, demoError.traceback) + lst.autoSizeColumns((0,1,2)) + + sz.appendSpacer(10) + sz.append(dabo.ui.dLabel(self, Caption=_("Traceback"))) + sz.appendSpacer(5) + sz.append1x(lst, border=5) + lbl = dabo.ui.dLabel(self, Caption=_("""Entries from the demo module are shown in blue +Double-click on them to go to the offending line""")) + sz.append(lbl, halign="center") + sz.appendSpacer(5) + self.layout() + + + def insertTraceback(self, lst, traceback): + #Add the traceback data + for tbNum in range(len(traceback)): + data = traceback[tbNum] + lst.append( (os.path.basename(data[0]), str(data[1]), str(data[2]), str(data[3])) ) + + # Check whether this entry is from the demo module + pth = os.path.split(data[0])[0] + codeDirs = (DemoModules.getOrigDir(), DemoModules.getModDir()) + if pth in codeDirs: + lst.setItemData(tbNum, int(data[1])) # Store line number for easy access + # Give it a blue colour + lst.setItemForeColor(tbNum, "blue") + else: + lst.setItemData(tbNum, -1) # Editor can't jump into this one's code + + + def onListDoubleClick(self, evt): + # If double-clicking on a demo's entry, jump to the line number + num = self.tbList.getItemData(self.tbList.PositionValue) + dabo.ui.callAfter(self.Form.showCode, num) + +
©2006 Ed Leafe |
|