Spreadsheet: property controller - fixes #926

Added a new object and tool called property controller, which
must be added to a spreadsheet and gives the value of a cell to
a property of an object.
This commit is contained in:
Yorik van Havre 2014-03-29 16:16:04 -03:00
parent 749a8fa1d6
commit 924392346b
5 changed files with 355 additions and 8 deletions

View File

@ -54,7 +54,7 @@ class SpreadsheetWorkbench(Workbench):
def Initialize(self):
import Spreadsheet,Spreadsheet_rc
from DraftTools import translate
commands = ["Spreadsheet_Create","Spreadsheet_Controller"]
commands = ["Spreadsheet_Create","Spreadsheet_Controller","Spreadsheet_PropertyController"]
self.appendToolbar(str(translate("Spreadsheet","Spreadsheet tools")),commands)
self.appendMenu(str(translate("Spreadsheet","&Spreadsheet")),commands)
FreeCADGui.addIconPath(":/icons")

View File

@ -2,5 +2,6 @@
<qresource>
<file>icons/Spreadsheet.svg</file>
<file>icons/SpreadsheetController.svg</file>
<file>icons/SpreadsheetPropertyController.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,198 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2860"
sodipodi:version="0.32"
inkscape:version="0.48.4 r9939"
sodipodi:docname="Spreadsheet.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs2862">
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3377"
id="radialGradient3692"
cx="45.883327"
cy="28.869568"
fx="45.883327"
fy="28.869568"
r="19.467436"
gradientUnits="userSpaceOnUse" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3377"
id="radialGradient3703"
gradientUnits="userSpaceOnUse"
cx="135.38333"
cy="97.369568"
fx="135.38333"
fy="97.369568"
r="19.467436"
gradientTransform="matrix(0.97435,0.2250379,-0.4623105,2.0016728,48.487554,-127.99883)" />
<linearGradient
id="linearGradient3377">
<stop
id="stop3379"
offset="0"
style="stop-color:#faff2b;stop-opacity:1;" />
<stop
id="stop3381"
offset="1"
style="stop-color:#ffaa00;stop-opacity:1;" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3377"
id="radialGradient3705"
gradientUnits="userSpaceOnUse"
cx="148.88333"
cy="81.869568"
fx="148.88333"
fy="81.869568"
r="19.467436"
gradientTransform="matrix(1.3852588,-0.05136783,0.03705629,0.9993132,-60.392403,7.7040438)" />
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective2868" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3864"
id="radialGradient3850"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.6028459,1.0471639,-1.9794021,1.1395295,127.9588,-74.456907)"
cx="51.328892"
cy="31.074146"
fx="51.328892"
fy="31.074146"
r="19.571428" />
<linearGradient
id="linearGradient3864">
<stop
id="stop3866"
offset="0"
style="stop-color:#71b2f8;stop-opacity:1;" />
<stop
id="stop3868"
offset="1"
style="stop-color:#002795;stop-opacity:1;" />
</linearGradient>
<radialGradient
r="19.571428"
fy="31.074146"
fx="51.328892"
cy="31.074146"
cx="51.328892"
gradientTransform="matrix(0.6028459,1.0471639,-1.9794021,1.1395295,127.9588,-74.456907)"
gradientUnits="userSpaceOnUse"
id="radialGradient5020"
xlink:href="#linearGradient3864"
inkscape:collect="always" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.24306796"
inkscape:cx="310.19837"
inkscape:cy="-495.41626"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="1053"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata2865">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3002"
width="56.18182"
height="46.545456"
x="4"
y="9.272728" />
<rect
style="color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3002-9"
width="56.18182"
height="46.545456"
x="4"
y="9.272728" />
<path
style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="m 4,20.545455 55.636364,0"
id="path3790"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="M 20.909091,9.6363636 20.909091,56"
id="path3792"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 4,32.429811 55.090909,0"
id="path3794"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 4,44.483064 55.636364,0"
id="path3796"
inkscape:connector-curvature="0" />
<g
id="g3845"
transform="matrix(0.77804702,0,0,0.77804702,-45.60341,-94.446731)">
<path
inkscape:connector-curvature="0"
style="fill:#0034ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 96.18444,141.44968 -19.81441,7.17921 29.4349,3.97209 -0.72357,36.12665 17.25881,-10.94388 0.57587,-34.38485 -26.7316,-1.94922 z"
id="path3823"
sodipodi:nodetypes="ccccccc" />
<path
inkscape:connector-curvature="0"
style="fill:#0034ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 75.57941,148.6589 30.70884,3.36562 0,36.47719 -31.12383,-5.06479 0.41499,-34.77802 z"
id="path3825"
sodipodi:nodetypes="ccccc" />
<path
inkscape:connector-curvature="0"
style="fill:url(#radialGradient5020);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 106.05435,152.06948 16.72598,-8.4088"
id="path3827" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@ -215,6 +215,7 @@ class Spreadsheet:
if obj:
obj.Proxy = self
obj.addProperty("App::PropertyLinkList","Controllers","Base","Cell controllers of this object")
self.Object = obj.Name
self._cells = {} # this stores cell contents
self._relations = {} # this stores relations - currently not used
self.cols = [] # this stores filled columns
@ -245,6 +246,7 @@ class Spreadsheet:
if not r in self.rows:
self.rows.append(r)
self.rows.sort()
self.updateControlledProperties(key)
else:
self.__dict__.__setitem__(key,value)
@ -266,6 +268,8 @@ class Spreadsheet:
def __getstate__(self):
self._cells["Type"] = self.Type
if hasattr(self,"Object"):
self._cells["Object"] = self.Object
return self._cells
def __setstate__(self,state):
@ -275,6 +279,9 @@ class Spreadsheet:
if "Type" in self._cells.keys():
self.Type = self._cells["Type"]
del self._cells["Type"]
if "Object" in self._cells.keys():
self.Object = self._cells["Object"]
del self._cells["Object"]
# updating relation tables
self.rows = []
self.cols = []
@ -423,16 +430,57 @@ class Spreadsheet:
if obj:
if hasattr(obj,"Controllers"):
for co in obj.Controllers:
co.Proxy.setCells(co,obj)
import Draft
if Draft.getType(co) == "SpreadsheetController":
co.Proxy.setCells(co,obj)
def getControlledCells(self,obj):
"returns a list of cells managed by controllers"
cells = []
if hasattr(obj,"Controllers"):
for c in obj.Controllers:
cells.extend(c.Proxy.getCells(c,obj))
for co in obj.Controllers:
import Draft
if Draft.getType(co) == "SpreadsheetController":
cells.extend(co.Proxy.getCells(co,obj))
return cells
def getControllingCells(self,obj):
"returns a list of controlling cells managed by controllers"
cells = []
if hasattr(obj,"Controllers"):
for co in obj.Controllers:
import Draft
if Draft.getType(co) == "SpreadsheetPropertyController":
if co.Cell:
cells.append(co.Cell.lower())
return cells
def updateControlledProperties(self,key):
"updates the properties of controlled objects"
if hasattr(self,"Object"):
obj = FreeCAD.ActiveDocument.getObject(self.Object)
if obj:
import Draft
if Draft.getType(obj) == "Spreadsheet":
if hasattr(obj,"Controllers"):
for co in obj.Controllers:
if Draft.getType(co) == "SpreadsheetPropertyController":
if co.Cell.upper() == key.upper():
if co.TargetObject and co.TargetProperty:
b = co.TargetObject
props = co.TargetProperty.split(".")
for p in props:
if hasattr(b,p):
if p != props[-1]:
b = getattr(b,p)
else:
return
try:
setattr(b,p,self._cells[key])
if DEBUG: print "setting property ",co.TargetProperty, " of object ",co.TargetObject.Name, " to ",self._cells[key]
except:
if DEBUG: print "unable to set property ",co.TargetProperty, " of object ",co.TargetObject.Name, " to ",self._cells[key]
class ViewProviderSpreadsheet(object):
def __init__(self, vobj):
@ -454,6 +502,7 @@ class ViewProviderSpreadsheet(object):
return True
def unsetEdit(self,vobj,mode):
del self.editor
return False
def claimChildren(self):
@ -590,6 +639,39 @@ class ViewProviderSpreadsheetController:
return ":/icons/SpreadsheetController.svg"
class SpreadsheetPropertyController:
"A spreadsheet property controller object"
def __init__(self,obj):
obj.Proxy = self
self.Type = "SpreadsheetPropertyController"
obj.addProperty("App::PropertyLink","TargetObject","Base","The object that must be controlled")
obj.addProperty("App::PropertyString","TargetProperty","Base","The property of the target object to control")
obj.addProperty("App::PropertyString","Cell","Base","The cell that contains the value to apply to the property")
def execute(self,obj):
pass
def __getstate__(self):
return self.Type
def __setstate__(self,state):
if state:
self.Type = state
def onChanged(self,obj,prop):
pass
class ViewProviderSpreadsheetPropertyController:
"A view provider for the spreadsheet property controller"
def __init__(self,vobj):
vobj.Proxy = self
def getIcon(self):
import Spreadsheet_rc
return ":/icons/SpreadsheetPropertyController.svg"
class SpreadsheetView(QtGui.QWidget):
"A spreadsheet viewer for FreeCAD"
@ -643,6 +725,7 @@ class SpreadsheetView(QtGui.QWidget):
"updates the cells with the contents of the spreadsheet"
if self.spreadsheet:
controlled = self.spreadsheet.Proxy.getControlledCells(self.spreadsheet)
controlling = self.spreadsheet.Proxy.getControllingCells(self.spreadsheet)
for cell in self.spreadsheet.Proxy._cells.keys():
if cell != "Type":
c,r = self.spreadsheet.Proxy.splitKey(cell)
@ -663,6 +746,11 @@ class SpreadsheetView(QtGui.QWidget):
brush.setStyle(QtCore.Qt.Dense6Pattern)
if self.table.item(r,c):
self.table.item(r,c).setBackground(brush)
elif cell in controlling:
brush = QtGui.QBrush(QtGui.QColor(0, 0, 255))
brush.setStyle(QtCore.Qt.Dense6Pattern)
if self.table.item(r,c):
self.table.item(r,c).setBackground(brush)
def changeCell(self,r,c,value=None):
"changes the contens of a cell"
@ -755,6 +843,46 @@ class _Command_Spreadsheet_Controller:
FreeCAD.ActiveDocument.recompute()
class _Command_Spreadsheet_PropertyController:
"the Spreadsheet_Controller FreeCAD command"
def GetResources(self):
return {'Pixmap' : 'SpreadsheetPropertyController',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Spreadsheet_PropertyController","Add property controller"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Spreadsheet_PropertyController","Adds a property controller to a selected spreadsheet")}
def IsActive(self):
if FreeCADGui.Selection.getSelection():
return True
else:
return False
def Activated(self):
import Draft
from DraftTools import translate
sel = FreeCADGui.Selection.getSelection()
if (len(sel) == 1) and Draft.getType(sel[0]) == "Spreadsheet":
n = FreeCADGui.Selection.getSelection()[0].Name
FreeCAD.ActiveDocument.openTransaction(str(translate("Spreadsheet","Add property controller")))
FreeCADGui.doCommand("import Spreadsheet")
FreeCADGui.doCommand("Spreadsheet.makeSpreadsheetPropertyController(FreeCAD.ActiveDocument."+n+")")
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
elif (len(sel) == 2):
if (Draft.getType(sel[0]) == "Spreadsheet") and (Draft.getType(sel[1]) == "SpreadsheetPropertyController"):
s = sel[0].Name
o = sel[1].Name
elif (Draft.getType(sel[1]) == "Spreadsheet") and (Draft.getType(sel[0]) == "SpreadsheetPropertyController"):
s = sel[1].Name
o = sel[0].Name
else:
return
FreeCAD.ActiveDocument.openTransaction(str(translate("Spreadsheet","Add property controller")))
FreeCADGui.doCommand("import Spreadsheet")
FreeCADGui.doCommand("Spreadsheet.makeSpreadsheetPropertyController(FreeCAD.ActiveDocument."+s+",FreeCAD.ActiveDocument."+o+")")
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
def makeSpreadsheet():
"makeSpreadsheet(): adds a spreadsheet object to the active document"
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython","Spreadsheet")
@ -782,6 +910,25 @@ def makeSpreadsheetController(spreadsheet,cell=None,direction=None):
return obj
def makeSpreadsheetPropertyController(spreadsheet,object=None,prop=None,cell=None):
"""makeSpreadsheetPropertyController(spreadsheet,[object,prop,cell]): adds a
property controller, targetting the given object if any, to the given spreadsheet.
You can give a property (such as "Length" or "Proxy.Length") and a cell address
(such as "B6")."""
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython","PropertyController")
SpreadsheetPropertyController(obj)
if FreeCAD.GuiUp:
ViewProviderSpreadsheetPropertyController(obj.ViewObject)
conts = spreadsheet.Controllers
conts.append(obj)
spreadsheet.Controllers = conts
if cell:
obj.Cell = cell
if prop:
obj.Property = prop
return obj
def addSpreadsheetView(view):
"addSpreadsheetView(view): adds the given spreadsheet view to the FreeCAD MDI area"
if FreeCAD.GuiUp:
@ -873,3 +1020,4 @@ def export(exportList,filename):
FreeCADGui.addCommand('Spreadsheet_Create',_Command_Spreadsheet_Create())
FreeCADGui.addCommand('Spreadsheet_Controller',_Command_Spreadsheet_Controller())
FreeCADGui.addCommand('Spreadsheet_PropertyController',_Command_Spreadsheet_PropertyController())

File diff suppressed because one or more lines are too long