diff --git a/InitGui.py b/InitGui.py index b8849f6..1b1be38 100644 --- a/InitGui.py +++ b/InitGui.py @@ -79,6 +79,7 @@ class Lattice2Workbench (Workbench): cmdsGuiTools = ([] + Lattice2.GuiTools.Inspect.exportedCommands + Lattice2.GuiTools.SubstituteObject.exportedCommands + + Lattice2.GuiTools.ExposeLinkSub.exportedCommands ) self.appendToolbar('Lattice2GuiTools', cmdsGuiTools) self.appendMenu('Lattice2', cmdsGuiTools) diff --git a/Lattice2GuiTools.py b/Lattice2GuiTools.py index 8bf1e94..c986c05 100644 --- a/Lattice2GuiTools.py +++ b/Lattice2GuiTools.py @@ -1,3 +1,4 @@ import lattice2Inspect as Inspect import lattice2RecomputeLocker as RecomputeLocker import lattice2SubstituteObject as SubstituteObject +import lattice2ExposeLinkSub as ExposeLinkSub \ No newline at end of file diff --git a/lattice2Executer.py b/lattice2Executer.py index 6319c5e..c8ce060 100644 --- a/lattice2Executer.py +++ b/lattice2Executer.py @@ -49,26 +49,28 @@ def executeFeature(obj): globalIsCreatingLatticeFeature = False -def warning(obj,message): +def warning(obj,message,forceMessage = None): ''' - warning(obj,message): smart warning message function. If feature is being + warning(obj,message, forceMessage = None): smart warning message function. If feature is being created, a warning message pops up. If otherwise, the warning is printed to the console/report view. + If forceMessage is True, the message is shown regardless; if False, the message is suppressed). ''' - _showMsg(obj, message, _type= u'Warning') + _showMsg(obj, message, forceMessage, _type= u'Warning') -def error(obj,message): +def error(obj,message, forceMessage = None): ''' - error(obj, message): smart error message function. If feature is being + error(obj, message, forceMessage = None): smart error message function. If feature is being created, an error message pops up. If otherwise, the error is printed to the console/report view. + If forceMessage is True, the message is shown regardless; if False, the message is suppressed). ''' - _showMsg(obj, message, _type= u'Error') + _showMsg(obj, message, forceMessage, _type= u'Error') -def _showMsg(obj, message, _type): +def _showMsg(obj, message, forceMessage, _type): '''showMsg(obj, message, _type): convenience function, contains the shared code of error() and warning()''' global globalIsCreatingLatticeFeature - if globalIsCreatingLatticeFeature: + if (globalIsCreatingLatticeFeature or forceMessage == True) and not forceMessage == False: mb = QtGui.QMessageBox() mb.setIcon(mb.Icon.Warning) mb.setText(_type + u": \n" + message) @@ -87,9 +89,9 @@ def _showMsg(obj, message, _type): printfunc = FreeCAD.Console.PrintError if obj is not None: - printfunc(obj.Name + ": " + message) + printfunc(obj.Name + ": " + message+"\n") else: - printfunc(message) + printfunc(message+"\n") class CancelError(Exception): diff --git a/lattice2ExposeLinkSub.py b/lattice2ExposeLinkSub.py new file mode 100644 index 0000000..eaadf0f --- /dev/null +++ b/lattice2ExposeLinkSub.py @@ -0,0 +1,151 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2016 - Victor Titov (DeepSOIC) * +#* * +#* * +#* This program is free software; you can redistribute it and/or modify * +#* it under the terms of the GNU Lesser General Public License (LGPL) * +#* as published by the Free Software Foundation; either version 2 of * +#* the License, or (at your option) any later version. * +#* for detail see the LICENCE text file. * +#* * +#* This program is distributed in the hope that it will be useful, * +#* but WITHOUT ANY WARRANTY; without even the implied warranty of * +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +#* GNU Library General Public License for more details. * +#* * +#* You should have received a copy of the GNU Library General Public * +#* License along with this program; if not, write to the Free Software * +#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +#* USA * +#* * +#*************************************************************************** + +__title__= "Lattice ExposeLinkSub tool for FreeCAD" +__author__ = "DeepSOIC" +__doc__ = "Tool to expose LinkSub properties of objects, by spawning a SubLink object for each sublinked element, and redirecting the links" + +from lattice2Common import * +import lattice2SubLink as LSL +import lattice2Executer as Executer +import FreeCAD as App + +def ExposeLinkSub(feature, propname): + # read links out into reflist variable + if feature.getTypeIdOfProperty(propname) == 'App::PropertyLinkSubList': + reflist = getattr(feature,propname) + elif feature.getTypeIdOfProperty(propname) == 'App::PropertyLinkSub': + (obj, subnames) = getattr(feature,propname) + reflist = [(obj,subname) for subname in subnames] + if len(reflist)>1: + raise ValueError("Link of type 'App::PropertyLinkSub' points to more than one subelement. Not supported yet.") + del (obj) + else: + raise ValueError("Link type not supported: "+feature.getTypeIdOfProperty(propname)) + if reflist is None: + raise ValueError("Nothing is linked, nothing to do") + #return + + # make SubLinks objects, and redirect the links in reflist + for i in range(len(reflist)): + (obj, subname) = reflist[i] + if "Face" in subname: + newsubname = "Face1" + elif "Edge" in subname: + newsubname = "Edge1" + elif "Vertex" in subname: + newsubname = "Vertex1" + else: + App.Console.PrintLog("Link %prop of feature %feat links either to whole object, or to something unknown. Subname is %sub. Skipped.\n" + .replace("%prop",propname) + .replace("%feat",feature.Name) + .replace("%sub",repr(subname)) ) + continue + sublink = LSL.CreateSubLink(obj, [subname]) + reflist[i] = (sublink,newsubname) + del obj + + # write back + if feature.getTypeIdOfProperty(propname) == 'App::PropertyLinkSubList': + setattr(feature,propname,reflist) + elif feature.getTypeIdOfProperty(propname) == 'App::PropertyLinkSub': + setattr(feature,propname,reflist[0]) + +def cmdExposeLinkSubs(): + sel = FreeCADGui.Selection.getSelectionEx() + if len(sel) != 1: + raise SelectionError( "Bad selection", "Select one object, first! You have selected %i objects".replace("%i",str(len(sel))) ) + App.ActiveDocument.openTransaction("Expose LinkSub of "+sel[0].Object.Name) + obj = sel[0].Object + cnt = 0 + try: + for propname in obj.PropertiesList: + if 'App::PropertyLinkSub' in obj.getTypeIdOfProperty(propname): + if getattr(obj,propname) is None: continue + try: + if obj.isDerivedFrom("Part::Part2DObject") and propname == "Support": + if False == askYesNo("Support", "ExposeLinkSub is about to expose Support link of %feat. This will cause PartDesign additive operations to start new objects instead of adding to support solid, and subtractive PartDesign operations to fail. Expose the support link?" + .replace("%feat",obj.Label)): + continue + ExposeLinkSub(obj, propname) + cnt += 1 + except Exception as err: + Executer.warning(None,"Attempting to expose sublink property %prop of %feat caused an error:\n%err" + .replace("%prop",propname) + .replace("%feat",obj.Name) + .replace("%err",err.message) ) + if cnt == 0: + raise ValueError("No links to expose were found.") + except Exception: + App.ActiveDocument.abortTransaction() + raise + + +# candidate for transferring +def askYesNo(title, message): + '''Displays messagebox with three buttons: yes, no, abort. yes -> returns True. no -> returns False. abort -> raises CancelError''' + from PySide import QtGui + mb = QtGui.QMessageBox() + mb.setIcon(mb.Icon.Question) + mb.setText(message) + mb.setWindowTitle(title) + btnAbort = mb.addButton(QtGui.QMessageBox.StandardButton.Abort) + btnYes = mb.addButton(QtGui.QMessageBox.StandardButton.Yes) + btnNo = mb.addButton(QtGui.QMessageBox.StandardButton.No) + mb.setDefaultButton(btnYes) + mb.exec_() + if mb.clickedButton() is btnAbort: + raise CancelError() + return mb.clickedButton() is btnYes + + + +class _CommandExposeLinkSub: + "Command to expose ..LinkSub.. properties of other features" + def GetResources(self): + return {'Pixmap' : getIconPath("Lattice2_ExposeLinkSub.svg"), + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Lattice2_ExposeLinkSub","Expose links to subelements"), + 'Accel': "", + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Lattice2_ExposeLinkSub","Expose links to subelements: create SubLink features as proxies for subelement dependencies of selected object")} + + def Activated(self): + try: + if len(FreeCADGui.Selection.getSelection())==0: + infoMessage("ExposeLinkSub", + "'Expose links to subelements' command. Exposes subelement links of an object by creating SubLink features as proxies for subelement dependencies.\n\n"+ + "Please select one object, then invoke the command.") + return + cmdExposeLinkSubs() + except Exception as err: + msgError(err) + + def IsActive(self): + if App.ActiveDocument: + return True + else: + return False + +FreeCADGui.addCommand('Lattice2_ExposeLinkSub', _CommandExposeLinkSub()) + +exportedCommands = ['Lattice2_ExposeLinkSub'] + diff --git a/lattice2SubLink.py b/lattice2SubLink.py index 52ce258..7d24e11 100644 --- a/lattice2SubLink.py +++ b/lattice2SubLink.py @@ -288,6 +288,7 @@ def CreateSubLink(object, subnames): FreeCADGui.doCommand("f.Object.ViewObject.hide()") FreeCADGui.doCommand("Gui.Selection.addSelection(f)") FreeCADGui.doCommand("f = None") + return App.ActiveDocument.ActiveObject def cmdSubLink(): sel = FreeCADGui.Selection.getSelectionEx()