daboide Commit
Revision 323
Date: 2006-01-11 16:44:53 -0800 (Wed, 11 Jan 2006)
Author: paul
Changed:
U trunk/ReportDesigner.py
Log:
Mapped Ctrl+F6 and Ctrl+F7 to toggle the showing and hiding of the object tree
and propsheet, respectively.
Revamped the selected objects to not refer to the dPanels but to the
ReportObjects
as defined over in the report writer. Added a DesignerObject attribute to these
so that each ReportObject knows what its visual object (if any) is.
To see this in action:
python ReportDesigner.py sampleReport.rfxml
...and then open the propsheet and object tree. Navigate the objects in the
tree and notice the propsheet and designer stay in sync. Move or size an
object with the mouse and the props update. Change a prop value in the
propsheet and the object changes.
We are getting there. Still to do (quick brainstorm):
+ Undo/Redo (# of steps as a user pref)
+ Cut/Clear (currently no way to remove an object)
+ Groups/Variables in TreeView
+ Report Controls selector, to add a control to the report
+ Visual column dividers, in case report.columnCount > 1
+ Column header/footer bands
+ Visual rotation of objects (you can already set rotation in propsheet)
+ Some way to preserve XML comments, in case people hand-edited the xml
(it seems rude for the designer to wipe away the comments)
+ Rulers, grid, and snap-to-grid functionality
+ An editor/wizard for creating the sample data set
+ Visual design of pageBackground and pageForeground "bands"
Can't make new reports yet, but it is kind of cool how I can load my
handcrafted reports into the designer and make simple visual tweaks. I'm
psyched!!
Diff:
Modified: trunk/ReportDesigner.py
===================================================================
--- trunk/ReportDesigner.py 2006-01-11 18:51:06 UTC (rev 322)
+++ trunk/ReportDesigner.py 2006-01-12 00:44:53 UTC (rev 323)
@@ -9,47 +9,6 @@
dc = None # singleton DesignerController
-class DesignerReportControlMixin(object):
- def getProp(self, propName, evaluate):
- """Override in subclasses."""
- return "'??'"
-
- def setProp(self, propName, propVal):
- """Override in subclasses."""
- print "override setProp()"
-
- def getPropVal(self, propName):
- return self.getProp(propName, evaluate=False)
-
- def updatePropVal(self, propName, propVal):
- self.setProp(str(propName), str(propVal))
-
- def _getDesProps(self):
- strType = {"type" : str, "readonly" : False}
- props = self.Props.PropDefaults.keys()
- desProps = {}
- for prop in props:
- desProps[prop] = strType
- return desProps
-
-
- def _getProps(self):
- return self._props
-
- def _setProps(self, val):
- self._props = val
-
-
- Props = property(_getProps, _setProps)
-
- DesignerProps = property(_getDesProps, None, None,
- _("""Returns a dict of editable properties for the control,
with the
- prop names as the keys, and the value for each another dict,
- containing the following keys: 'type', which controls how to
display
- and edit the property, and 'readonly', which will prevent
editing
- when True. (dict)""") )
-
-
def DesignerController():
# Wrapper function to enforce singleton class instance
class DesignerController(object):
@@ -59,7 +18,7 @@
self._selection = []
self._inSelection = False
- def showObjectTree(self, bringToTop=True, refresh=False):
+ def showObjectTree(self, bringToTop=False, refresh=False):
ps = self.ObjectTree
if ps is None:
refresh = True
@@ -79,10 +38,14 @@
ps = self.ObjectTree = ObjectTreeForm()
ps.bindEvent(dEvents.Close, self._onObjectTreeFormClose)
ps.Editor.app = self
+ # Allow the activate to fire so that position is set:
+ ps.Visible = True
+ ps.Raise()
+ self.SelectedForm.Raise()
return ps
- def showPropSheet(self, bringToTop=True, refresh=False):
+ def showPropSheet(self, bringToTop=False, refresh=False):
ps = self.PropSheet
if ps is None:
refresh = True
@@ -102,6 +65,9 @@
ps = self.PropSheet = PropSheetForm()
ps.bindEvent(dEvents.Close, self._onPropSheetFormClose)
ps.Editor.app = self
+ ps.Visible = True
+ ps.Raise()
+ self.SelectedForm.Raise()
return ps
@@ -244,7 +210,7 @@
"""Constructs the tree of report objects."""
sel = self.Selection
if sel:
- selObjs = [nn._obj for nn in sel]
+ selObjs = [nn.ReportObject for nn in sel]
self.clear()
self.recurseLayout()
@@ -260,7 +226,7 @@
if frm is None:
frm = rf
parentNode = self.setRootNode("report")
- parentNode._obj = None
+ parentNode.ReportObject = frm
elements = frm.keys()
elements.sort(rw._elementSort)
@@ -269,13 +235,13 @@
item = frm[name]
if isinstance(item, dict):
node = parentNode.appendChild(name)
- node._obj = rd.findBandByName(name)
+ node.ReportObject = item
if item.has_key("objects"):
for child in item["objects"]:
self.recurseLayout(frm=child,
parentNode=node)
elif name == "name":
node = parentNode.appendChild(item)
- node._obj = rd.findObjectByName(item)
+ node.ReportObject = frm
def select(self, objList):
"""Iterate through the nodes, and set their Selected status
@@ -284,11 +250,20 @@
if self._inAppSelection:
return
self._inAppSelection = True
+
+ # First make sure all objs in objList have nodes:
+ for obj in objList:
+ if obj not in [o.ReportObject for o in self.nodes]:
+ self.updateDisplay()
+ break
+
selNodes = [nn for nn in self.nodes
- if nn._obj in objList]
+ if nn.ReportObject in objList]
+
self.Selection = selNodes
self._inAppSelection = False
+
def onTreeSelection(self, evt):
if self._inAppSelection:
# Otherwise, this would be infinite recursion, because
unlike most other
@@ -297,9 +272,8 @@
return
selectedObjs = []
for sel in self.Selection:
- selObj = sel._obj
- if selObj:
- selectedObjs.append(selObj)
+ selObj = sel.ReportObject
+ selectedObjs.append(selObj)
dc.select(selectedObjs)
@@ -314,6 +288,16 @@
def getObjPropVal(self, obj, prop):
return obj.getPropVal(prop)
+ def updateVal(self, prop, val, typ):
+ """Called from the grid to notify that the current cell's
+ value has been changed. Update the corresponding
+ property value.
+ """
+ for obj in self._selected:
+ obj.setProp(prop, val)
+ dc.SelectedForm.getCurrentEditor().propsChanged()
+
+
class PropSheetForm(DesignerControllerForm):
def initProperties(self):
PropSheetForm.doDefault()
@@ -324,7 +308,7 @@
#------------------------------------------------------------------------------
# ObjectPanel Class
#
-class ObjectPanel(dabo.ui.dPanel, DesignerReportControlMixin):
+class ObjectPanel(dabo.ui.dPanel):
"""Base class for all report objects
All of the various types of report objects like strings, images,
rectangles,
@@ -353,7 +337,7 @@
self.Bands = self._rw.Bands
def getPositionText(self):
- return ("x:%(x)s y:%(y)s width:%(width)s height:%(height)s" %
self.Props)
+ return ("x:%(x)s y:%(y)s width:%(width)s height:%(height)s" %
self.ReportObject)
def initEvents(self):
self.bindEvent(dEvents.Paint, self.onPaint)
@@ -379,13 +363,13 @@
def getProp(self, prop, evaluate=True, fillDefault=True):
if evaluate and fillDefault:
# The report object can do it all:
- return self.Props.getProp(prop)
+ return self.ReportObject.getProp(prop)
try:
- val = self.Props[prop]
+ val = self.ReportObject[prop]
except KeyError:
if fillDefault:
- val = self.Props.PropDefaults[prop]
+ val = self.ReportObject.PropDefaults[prop]
if val is not None and evaluate and prop not in ("type",):
try:
@@ -474,12 +458,12 @@
x = objWidth / 2
val = x
- self.Props[prop] = str(val)
+ self.ReportObject.setProp(prop, str(val))
if prop == "name":
# change the ui object name to reflect.
oldName = self.Name
- self.Name = self.Props[prop]
+ self.Name = self.ReportObject.getProp(prop)
self.Parent._objects[self.Name] =
self.Parent._objects[oldName]
del(self.Parent._objects[oldName])
@@ -499,7 +483,7 @@
def draw(self):
- self.Parent.drawObject(self.Props)
+ self.Parent.drawObject(self.ReportObject)
def onDoubleClick(self, evt):
@@ -508,7 +492,7 @@
# selected us, but perhaps they had the shift key down
resulting
# in the second mousedown unselecting us. Nonetheless,
we should
# be selected:
- self._rd.SelectedObjects.append(self)
+ self._rd.SelectedObjects.append(self.ReportObject)
self.Refresh()
self.Parent._rd.propertyDialog(self)
@@ -624,23 +608,25 @@
_so = self._rd.SelectedObjects
if not self.Selected:
if evt.EventData["shiftDown"] or
evt.EventData["controlDown"]:
- _so.append(self)
+ _so.append(self.ReportObject)
else:
oldSelectedObjects = copy.copy(_so)
- _so = [self,]
+ _so = [self.ReportObject,]
for obj in oldSelectedObjects:
- obj.Refresh()
+ do = getattr(obj, "DesignerObject",
None)
+ if do:
+ do.Refresh()
else:
if evt.EventData["shiftDown"] or
evt.EventData["controlDown"]:
for idx in range(len(_so)):
- if _so[idx] == self:
+ if _so[idx] == self.ReportObject:
del _so[idx]
break
else:
oldSelectedObjects = copy.copy(_so)
- _so = [self,]
+ _so = [self.ReportObject,]
for obj in oldSelectedObjects:
- obj.Refresh()
+ obj.DesignerObject.Refresh()
self._rd.SelectedObjects = _so
self._rd.showPosition()
self.Refresh()
@@ -778,14 +764,14 @@
dc.DrawRectangle(rect[0],rect[1],rect[2],rect[3])
def _getSelected(self):
- return self in self._rd.SelectedObjects
+ return self.ReportObject in self._rd.SelectedObjects
def _setSelected(self, val):
if val:
- self._rd.SelectedObjects.append(self)
+ self._rd.SelectedObjects.append(self.ReportObject)
else:
for idx in range(len(self._rd.SelectedObjects)):
- if self._rd.SelectedObjects[idx] == self:
+ if self._rd.SelectedObjects[idx] ==
self.ReportObject:
del self._rd.SelectedObjects[idx]
break
self.Refresh()
@@ -797,20 +783,7 @@
#------------------------------------------------------------------------------
-class StringObject(ObjectPanel): pass
-class RectObject(ObjectPanel):
- def afterInit(self):
- self.doDefault()
-
-class LineObject(ObjectPanel):
- def afterInit(self):
- self.doDefault()
-
-class ImageObject(ObjectPanel):
- def afterInit(self):
- self.doDefault()
-
#------------------------------------------------------------------------------
# BandLabel Class
#
@@ -898,7 +871,7 @@
if newHeight < 0: newHeight = 0
self.Parent.setProp("height", newHeight)
self.Form.Refresh()
- self.Parent._rd.SelectedObjects = [self.Parent]
+ self.Parent._rd.SelectedObjects =
[self.Parent.ReportObject]
def onLeftDown(self, evt):
if self.Application.Platform == "Mac":
@@ -958,7 +931,7 @@
#
# Band Class
#
-class Band(dabo.ui.dPanel, DesignerReportControlMixin):
+class Band(dabo.ui.dPanel):
"""Base class for report bands.
Bands contain any number of objects, which can receive the focus and be
@@ -1009,19 +982,17 @@
oldSelectedObjects = copy.copy(self._rd.SelectedObjects)
self._rd.SelectedObjects = []
for obj in oldSelectedObjects:
- obj.Refresh()
+ o = getattr(obj, "DesignerObject")
+ if o:
+ o.Refresh()
def drawObjects(self):
- if self.Props.has_key("objects"):
- for obj in self.Props["objects"]:
+ if self.ReportObject.has_key("objects"):
+ for obj in self.ReportObject["objects"]:
self.drawObject(obj)
def drawObject(self, obj):
- self.getObject(obj)
-
-
- def getObject(self, obj):
if not obj.has_key("name"):
# The report designer needs to identify objects
uniquely, and saves the
# 'name' property to the object in the rfxml file.
However, perhaps a
@@ -1035,19 +1006,10 @@
dabo.infoLog.write("Report object didn't have a name...
assigned '%s'." % name)
if obj["name"] not in self._objects.keys():
- if obj["type"] == "string":
- cls = StringObject
- elif obj["type"] == "rect":
- cls = RectObject
- elif obj["type"] == "line":
- cls = LineObject
- elif obj["type"] == "image":
- cls = ImageObject
- else:
- cls = ObjectPanel
- o = cls(self, Name=obj["name"])
+ o = ObjectPanel(self, Name=obj["name"])
self._objects[obj["name"]] = o
- o.Props = obj
+ o.ReportObject = obj
+ o.ReportObject.DesignerObject = o
else:
o = self._objects[obj["name"]]
@@ -1085,13 +1047,13 @@
def getProp(self, prop, evaluate=True, fillDefault=True):
if evaluate and fillDefault:
# The report object can do it all:
- return self.Props.getProp(prop)
+ return self.ReportObject.getProp(prop)
try:
- val = self.Props[prop]
+ val = self.ReportObject[prop]
except KeyError:
if fillDefault:
- val = self.Props.PropDefaults.get(prop)
+ val = self.ReportObject.PropDefaults.get(prop)
if val is not None and evaluate and prop not in ("type",):
try:
@@ -1108,7 +1070,7 @@
If setting more than one property, self.setProps() is faster.
"""
- self.Props[prop] = str(val)
+ self.ReportObject.setProp(prop, str(val))
if sendPropsChanged:
self.Parent.propsChanged()
@@ -1188,7 +1150,7 @@
def copy(self):
so = self.SelectedObjects
if len(so) > 0:
- self._clipboard = copy.copy(self.SelectedObjects)
+ self._clipboard = copy.copy(so)
def cut(self):
print "cut not implemented yet."
@@ -1196,17 +1158,18 @@
def paste(self):
_newSelected = []
for obj in self._clipboard:
- newobjprops = copy.copy(obj.Props)
- newobjprops["x"] = str(self._rw.getPt(obj.getProp("x"))
+ 3)
- newobjprops["y"] = str(self._rw.getPt(obj.getProp("y"))
+ 3)
- newobjprops["name"] =
self._getUniqueName(newobjprops["name"], obj.Parent)
- obj.Parent.Props["objects"].append(newobjprops)
- _newSelected.append((obj.Parent, newobjprops["name"]))
+ newobj = copy.copy(obj)
+ newobj["x"] = str(self._rw.getPt(obj.getProp("x")) + 3)
+ newobj["y"] = str(self._rw.getPt(obj.getProp("y")) + 3)
+ newobj["name"] = self._getUniqueName(newobj["name"],
+ obj.DesignerObject.Parent)
+
obj.DesignerObject.Parent.ReportObject["objects"].append(newobjprops)
+ _newSelected.append(newobj)
self.drawReportForm()
- self.SelectedObjects = []
- for ns in _newSelected:
- o = eval("ns[0].%s" % ns[1])
- self.SelectedObjects.append(o)
+ selectedObjects = []
+ for obj in _newSelected:
+ selectedObjects.append(obj)
+ self.SelectedObjects = selectedObjects
self.Refresh()
@@ -1281,10 +1244,13 @@
def showPosition(self):
"""If one object is selected, show its position and size."""
- if len(self.SelectedObjects) == 1:
- o = self.SelectedObjects[0]
+ # selected objects could include non-visible. Filter these out.
+ so = [o for o in self.SelectedObjects
+ if getattr(o, "DesignerObject", None) is not
None]
+ if len(so) == 1:
+ o = getattr(so[0], "DesignerObject")
st = o.getPositionText()
- elif len(self.SelectedObjects) > 1:
+ elif len(so) > 1:
st = " -multiple objects selected- "
else:
st = ""
@@ -1471,7 +1437,8 @@
self._rulers["%s-left" % band] =
self.getRuler("v")
self._rulers["%s-right" % band] =
self.getRuler("v")
b = Band(self, Caption=band)
- b.Props = self.ReportForm[band]
+ b.ReportObject = self.ReportForm[band]
+ b.ReportObject.DesignerObject = b
b._rw = self._rw
self._bands.append(b)
@@ -1491,7 +1458,7 @@
self.drawReportForm()
def drawReportForm(self):
- """Resize and position the bands accordingly."""
+ """Resize and position the bands accordingly, and draw the
objects."""
rw = self._rw
rf = self._rw.ReportForm
z = self.ZoomFactor
@@ -1515,7 +1482,7 @@
b = band.bandLabel
b.Width = band.Width
- bandHeight = band.Props.getProp("height")
+ bandHeight = band.ReportObject.getProp("height")
if bandHeight is None:
# dynamic band height: size of band determined
at runtime. For now, fake it.
bandHeight = 75
@@ -1605,12 +1572,12 @@
def _arrange(self, mode):
_newSelected = []
- for o in self.SelectedObjects:
+ for obj in self.SelectedObjects:
curidx = None
- objects = o.Parent.Props["objects"]
- _newSelected.append((o.Parent.Props.get("name"),
o.Props["name"]))
+ objects =
obj.DesignerObject.Parent.ReportObject["objects"]
+ _newSelected.append(obj)
for idx, props in enumerate(objects):
- if props["name"] == o.Name:
+ if props["name"] == obj.DesignerObject.Name:
curidx = idx
if curidx is None:
print "!!!"
@@ -1624,7 +1591,7 @@
self.reInitReportForm()
self.SelectedObjects = []
for ns in _newSelected:
-
self.SelectedObjects.append(self.findObjectByName(ns[1]))
+ self.SelectedObjects.append(ns)
self.Refresh()
@@ -1824,10 +1791,18 @@
ed._onFormResize(None)
def onViewShowObjectTree(self, evt):
- self.DesignerController.showObjectTree()
+ o = self.DesignerController.ObjectTree
+ if o and o.Visible:
+ self.DesignerController.hideObjectTree()
+ else:
+ self.DesignerController.showObjectTree()
def onViewShowPropertySheet(self, evt):
- self.DesignerController.showPropSheet()
+ o = self.DesignerController.PropSheet
+ if o and o.Visible:
+ self.DesignerController.hidePropSheet()
+ else:
+ self.DesignerController.showPropSheet()
def fillMenu(self):
mb = self.MenuBar
@@ -1881,11 +1856,11 @@
viewMenu.appendSeparator()
- viewMenu.append("Show Object Tree",
+ viewMenu.append("Show/Hide Object Tree\tCtrl+F6",
bindfunc=self.onViewShowObjectTree,
help="Show the object hierarchy.")
- viewMenu.append("Show Property Sheet",
+ viewMenu.append("Show/Hide Property Sheet\tCtrl+F7",
bindfunc=self.onViewShowPropertySheet,
help="Show the properties for the selected
report objects.")
_______________________________________________
Post Messages to: [email protected]
Subscription Maintenance: http://leafe.com/mailman/listinfo/dabo-dev