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)
+
+
_______________________________________________
Post Messages to: [email protected]
Subscription Maintenance: http://leafe.com/mailman/listinfo/dabo-dev