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:
parent
749a8fa1d6
commit
924392346b
|
@ -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")
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
<qresource>
|
||||
<file>icons/Spreadsheet.svg</file>
|
||||
<file>icons/SpreadsheetController.svg</file>
|
||||
<file>icons/SpreadsheetPropertyController.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -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 |
|
@ -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
Loading…
Reference in New Issue
Block a user