| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | from __future__ import absolute_import
|
| |
|
| | import FreeCAD as App
|
| | import Part
|
| |
|
| | mm = App.Units.MilliMetre
|
| | deg = App.Units.Degree
|
| | Q = App.Units.Quantity
|
| |
|
| | from AttachmentEditor.FrozenClass import FrozenClass
|
| |
|
| | try:
|
| | from Show import TempoVis
|
| | from Show.DepGraphTools import getAllDependent
|
| | except ImportError as err:
|
| |
|
| | def TempoVis(doc, tag):
|
| | return None
|
| |
|
| | def getAllDependent(feature):
|
| | return []
|
| |
|
| | App.Console.PrintWarning(
|
| | "AttachmentEditor: Failed to import some code from Show module. Functionality will be limited.\n"
|
| | )
|
| | App.Console.PrintWarning(str(err))
|
| |
|
| | if App.GuiUp:
|
| | import FreeCADGui as Gui
|
| | from PySide import QtCore, QtGui
|
| | from FreeCADGui import PySideUic as uic
|
| |
|
| |
|
| |
|
| |
|
| | try:
|
| | _fromUtf8 = QtCore.QString.fromUtf8
|
| | except AttributeError:
|
| |
|
| | def _fromUtf8(s):
|
| | return s
|
| |
|
| |
|
| | translate = App.Qt.translate
|
| |
|
| |
|
| |
|
| | def linkSubList_convertToOldStyle(references):
|
| | (
|
| | "input: [(obj1, (sub1, sub2)), (obj2, (sub1, sub2))]\n"
|
| | "output: [(obj1, sub1), (obj1, sub2), (obj2, sub1), (obj2, sub2)]"
|
| | )
|
| | result = []
|
| | for tup in references:
|
| | if type(tup[1]) is tuple or type(tup[1]) is list:
|
| | for subname in tup[1]:
|
| | result.append((tup[0], subname))
|
| | if len(tup[1]) == 0:
|
| | result.append((tup[0], ""))
|
| | elif isinstance(tup[1], str):
|
| |
|
| | result.append(tup)
|
| | return result
|
| |
|
| |
|
| | def StrFromLink(feature, subname):
|
| | return feature.Name + ((":" + subname) if subname else "")
|
| |
|
| |
|
| | def LinkFromStr(strlink, document):
|
| | if len(strlink) == 0:
|
| | return None
|
| | pieces = strlink.split(":")
|
| |
|
| | feature = document.getObject(pieces[0])
|
| |
|
| | subname = ""
|
| | if feature is None:
|
| | raise ValueError(
|
| | translate("AttachmentEditor", "No object named {}", None).format(pieces[0])
|
| | )
|
| | if len(pieces) == 2:
|
| | subname = pieces[1]
|
| | elif len(pieces) > 2:
|
| | raise ValueError(
|
| | translate(
|
| | "AttachmentEditor", "Failed to parse link (more than one colon encountered)", None
|
| | )
|
| | )
|
| |
|
| | return (
|
| | feature,
|
| | str(subname),
|
| | )
|
| |
|
| |
|
| | def StrListFromRefs(references):
|
| | """input: PropertyLinkSubList. Output: list of strings for UI."""
|
| | references_oldstyle = linkSubList_convertToOldStyle(references)
|
| | return [StrFromLink(feature, subelement) for (feature, subelement) in references_oldstyle]
|
| |
|
| |
|
| | def RefsFromStrList(strings, document):
|
| | """input: strings as from UI. Output: list of tuples that can be assigned to PropertyLinkSubList."""
|
| | refs = []
|
| | for st in strings:
|
| | lnk = LinkFromStr(st, document)
|
| | if lnk is not None:
|
| | refs.append(lnk)
|
| | return refs
|
| |
|
| |
|
| | def GetSelectionAsLinkSubList():
|
| | sel = Gui.Selection.getSelectionEx("", 0)
|
| | result = []
|
| | for selobj in sel:
|
| | for subname in selobj.SubElementNames:
|
| | result.append((selobj.Object, subname))
|
| | if len(selobj.SubElementNames) == 0:
|
| | result.append((selobj.Object, ""))
|
| | return result
|
| |
|
| |
|
| | def PlacementsFuzzyCompare(plm1, plm2):
|
| | pos_eq = (plm1.Base - plm2.Base).Length < 1e-7
|
| |
|
| | q1 = plm1.Rotation.Q
|
| | q2 = plm2.Rotation.Q
|
| |
|
| |
|
| | if q1[0] * q2[0] + q1[1] * q2[1] + q1[2] * q2[2] + q1[3] * q2[3] < 0:
|
| | q2 = [-v for v in q2]
|
| | rot_eq = (
|
| | abs(q1[0] - q2[0]) + abs(q1[1] - q2[1]) + abs(q1[2] - q2[2]) + abs(q1[3] - q2[3])
|
| | ) < 1e-12
|
| | return pos_eq and rot_eq
|
| |
|
| |
|
| | class CancelError(Exception):
|
| | def __init__(self):
|
| | self.message = "Canceled by user"
|
| | self.isCancelError = True
|
| |
|
| |
|
| | class AttachmentEditorTaskPanel(FrozenClass):
|
| | """The editmode TaskPanel for attachment editing"""
|
| |
|
| | KEYmode = (
|
| | QtCore.Qt.ItemDataRole.UserRole
|
| | )
|
| | KEYon = (
|
| | QtCore.Qt.ItemDataRole.UserRole + 1
|
| | )
|
| |
|
| | def __define_attributes(self):
|
| | self.obj = None
|
| | self.attacher = None
|
| | self.obj_is_attachable = (
|
| | True
|
| | )
|
| |
|
| | self.last_sugr = None
|
| |
|
| | self.form = None
|
| | self.block = False
|
| | self.refLines = []
|
| | self.refButtons = []
|
| | self.attachmentOffsetEdits = []
|
| | self.i_active_ref = (
|
| | -1
|
| | )
|
| | self.auto_next = False
|
| |
|
| | self.tv = None
|
| |
|
| | self.create_transaction = True
|
| | self.callback_OK = None
|
| | self.callback_Cancel = None
|
| | self.callback_Apply = None
|
| |
|
| | self._freeze()
|
| |
|
| | def __init__(
|
| | self,
|
| | obj_to_attach,
|
| | take_selection=False,
|
| | create_transaction=True,
|
| | callback_OK=None,
|
| | callback_Cancel=None,
|
| | callback_Apply=None,
|
| | ):
|
| |
|
| | self.__define_attributes()
|
| |
|
| | self.create_transaction = create_transaction
|
| | self.callback_OK = callback_OK
|
| | self.callback_Cancel = callback_Cancel
|
| | self.callback_Apply = callback_Apply
|
| |
|
| | self.obj = obj_to_attach
|
| | try:
|
| | if not self.obj.hasExtension("Part::AttachExtension"):
|
| | self.obj.addExtension("Part::AttachExtensionPython")
|
| | except Exception:
|
| | pass
|
| |
|
| | if hasattr(obj_to_attach, "Attacher"):
|
| | self.attacher = obj_to_attach.Attacher
|
| | elif hasattr(obj_to_attach, "AttacherType"):
|
| | self.attacher = Part.AttachEngine(obj_to_attach.AttacherType)
|
| | else:
|
| | movable = True
|
| | if not hasattr(self.obj, "Placement"):
|
| | movable = False
|
| | if "Hidden" in self.obj.getEditorMode(
|
| | "Placement"
|
| | ) or "ReadOnly" in self.obj.getEditorMode("Placement"):
|
| | movable = False
|
| | if not movable:
|
| | if self.callback_Cancel:
|
| | self.callback_Cancel()
|
| | raise ValueError(
|
| | translate(
|
| | "AttachmentEditor",
|
| | "Object {} is neither movable nor attachable, can't edit attachment",
|
| | None,
|
| | ).format(self.obj.Label)
|
| | )
|
| |
|
| | self.obj_is_attachable = False
|
| | self.attacher = Part.AttachEngine()
|
| |
|
| | mb = QtGui.QMessageBox()
|
| | mb.setIcon(mb.Icon.Warning)
|
| | mb.setText(
|
| | translate(
|
| | "AttachmentEditor",
|
| | "{} is not attachable. The attachment editor can still be used to align the object, but the attachment will not be parametric.",
|
| | None,
|
| | ).format(obj_to_attach.Label)
|
| | )
|
| | mb.setWindowTitle(translate("AttachmentEditor", "Attachment", None))
|
| | btnAbort = mb.addButton(QtGui.QMessageBox.StandardButton.Abort)
|
| | btnOK = mb.addButton(
|
| | translate("AttachmentEditor", "Continue", None),
|
| | QtGui.QMessageBox.ButtonRole.ActionRole,
|
| | )
|
| | mb.setDefaultButton(btnOK)
|
| | mb.exec_()
|
| | if mb.clickedButton() is btnAbort:
|
| | if self.callback_Cancel:
|
| | self.callback_Cancel()
|
| | raise CancelError()
|
| |
|
| | import os
|
| |
|
| | self.form = uic.loadUi(os.path.dirname(__file__) + os.path.sep + "TaskAttachmentEditor.ui")
|
| | self.form.setWindowIcon(QtGui.QIcon(":/icons/tools/Part_Attachment.svg"))
|
| | self.form.setWindowTitle(translate("AttachmentEditor", "Attachment", None))
|
| |
|
| | self.form.attachmentOffsetX.setProperty("unit", "mm")
|
| | self.form.attachmentOffsetY.setProperty("unit", "mm")
|
| | self.form.attachmentOffsetZ.setProperty("unit", "mm")
|
| | Gui.ExpressionBinding(self.form.attachmentOffsetX).bind(self.obj, "AttachmentOffset.Base.x")
|
| | Gui.ExpressionBinding(self.form.attachmentOffsetY).bind(self.obj, "AttachmentOffset.Base.y")
|
| | Gui.ExpressionBinding(self.form.attachmentOffsetZ).bind(self.obj, "AttachmentOffset.Base.z")
|
| |
|
| | Gui.ExpressionBinding(self.form.attachmentOffsetYaw).bind(
|
| | self.obj, "AttachmentOffset.Rotation.Yaw"
|
| | )
|
| | Gui.ExpressionBinding(self.form.attachmentOffsetPitch).bind(
|
| | self.obj, "AttachmentOffset.Rotation.Pitch"
|
| | )
|
| | Gui.ExpressionBinding(self.form.attachmentOffsetRoll).bind(
|
| | self.obj, "AttachmentOffset.Rotation.Roll"
|
| | )
|
| |
|
| | self.refLines = [
|
| | self.form.lineRef1,
|
| | self.form.lineRef2,
|
| | self.form.lineRef3,
|
| | self.form.lineRef4,
|
| | ]
|
| | self.refButtons = [
|
| | self.form.buttonRef1,
|
| | self.form.buttonRef2,
|
| | self.form.buttonRef3,
|
| | self.form.buttonRef4,
|
| | ]
|
| | self.attachmentOffsetEdits = [
|
| | self.form.attachmentOffsetX,
|
| | self.form.attachmentOffsetY,
|
| | self.form.attachmentOffsetZ,
|
| | self.form.attachmentOffsetYaw,
|
| | self.form.attachmentOffsetPitch,
|
| | self.form.attachmentOffsetRoll,
|
| | ]
|
| |
|
| | self.block = False
|
| |
|
| | for i in range(len(self.refLines)):
|
| | QtCore.QObject.connect(
|
| | self.refLines[i],
|
| | QtCore.SIGNAL("textEdited(QString)"),
|
| | lambda txt, i=i: self.lineRefChanged(i, txt),
|
| | )
|
| |
|
| | for i in range(len(self.refLines)):
|
| | QtCore.QObject.connect(
|
| | self.refButtons[i], QtCore.SIGNAL("clicked()"), lambda i=i: self.refButtonClicked(i)
|
| | )
|
| |
|
| | for i in range(len(self.attachmentOffsetEdits)):
|
| | QtCore.QObject.connect(
|
| | self.attachmentOffsetEdits[i],
|
| | QtCore.SIGNAL("valueChanged(double)"),
|
| | lambda val, i=i: self.attachmentOffsetChanged(i, val),
|
| | )
|
| |
|
| | QtCore.QObject.connect(
|
| | self.form.checkBoxFlip, QtCore.SIGNAL("clicked()"), self.checkBoxFlipClicked
|
| | )
|
| |
|
| | QtCore.QObject.connect(
|
| | self.form.listOfModes, QtCore.SIGNAL("itemSelectionChanged()"), self.modeSelected
|
| | )
|
| |
|
| | if self.create_transaction:
|
| | self.obj.Document.openTransaction(
|
| | translate("AttachmentEditor", "Edit attachment of {}", None).format(self.obj.Name)
|
| | )
|
| |
|
| | self.readParameters()
|
| |
|
| | if len(self.attacher.References) == 0 and take_selection:
|
| | sel = GetSelectionAsLinkSubList()
|
| | for i in range(len(sel))[::-1]:
|
| | if sel[i][0] is obj_to_attach:
|
| | sel.pop(i)
|
| | self.attacher.References = sel
|
| |
|
| | self.fillAllRefLines()
|
| |
|
| | if len(self.attacher.References) == 0:
|
| | self.i_active_ref = 0
|
| | self.auto_next = True
|
| | else:
|
| | self.i_active_ref = -1
|
| | self.auto_next = False
|
| |
|
| | Gui.Selection.addObserver(self, 0)
|
| |
|
| | self.updatePreview()
|
| | self.updateRefButtons()
|
| |
|
| | self.tv = TempoVis(self.obj.Document, tag="PartGui.TaskAttachmentEditor")
|
| | if self.tv:
|
| | self.tv.hide_all_dependent(self.obj)
|
| | self.tv.show(self.obj)
|
| | self.tv.setUnpickable(self.obj)
|
| | self.tv.modifyVPProperty(self.obj, "Transparency", 70)
|
| | self.tv.show([obj for (obj, subname) in self.attacher.References])
|
| |
|
| |
|
| | def getStandardButtons(self):
|
| | return (
|
| | QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Apply
|
| | )
|
| |
|
| | def clicked(self, button):
|
| | if button == QtGui.QDialogButtonBox.Apply:
|
| | if self.obj_is_attachable:
|
| | self.writeParameters()
|
| | if self.create_transaction:
|
| | self.obj.Document.commitTransaction()
|
| | self.obj.Document.openTransaction(
|
| | translate("AttachmentEditor", "Edit attachment of {}", None).format(
|
| | self.obj.Name
|
| | )
|
| | )
|
| | self.updatePreview()
|
| | if self.callback_Apply:
|
| | self.callback_Apply()
|
| |
|
| | def accept(self):
|
| | if self.obj_is_attachable:
|
| | self.writeParameters()
|
| | if self.create_transaction:
|
| | self.obj.Document.commitTransaction()
|
| | self.cleanUp()
|
| | Gui.Control.closeDialog()
|
| | if self.callback_OK:
|
| | self.callback_OK()
|
| |
|
| | def reject(self):
|
| | if self.create_transaction:
|
| | self.obj.Document.abortTransaction()
|
| | self.cleanUp()
|
| | Gui.Control.closeDialog()
|
| | if self.callback_Cancel:
|
| | self.callback_Cancel()
|
| |
|
| |
|
| | def addSelection(self, docname, objname, subname, pnt):
|
| | i = self.i_active_ref
|
| | if i < 0:
|
| |
|
| | return
|
| | if i > 0 and self.auto_next:
|
| | prevref = LinkFromStr(self.refLines[i - 1].text(), self.obj.Document)
|
| | if prevref[0].Name == objname and subname == "":
|
| |
|
| |
|
| | i -= 1
|
| | if i > len(self.refLines) - 1:
|
| |
|
| | assert self.auto_next
|
| | self.i_active_ref = -1
|
| | self.updateRefButtons()
|
| | return
|
| | if i > -1:
|
| | if ";" in subname:
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | tmp = subname.split(";")
|
| | subname = tmp[0] + tmp[-1].split(".")[-1]
|
| | parent = self.obj.getParentGeoFeatureGroup()
|
| | if parent is not None:
|
| | path = [objname] + subname.split(".")
|
| | if parent.Name in path:
|
| | path = path[path.index(parent.Name) + 1 :]
|
| | if len(path) > 1:
|
| | objname = path[0]
|
| | subname = ".".join(path[1:])
|
| |
|
| |
|
| | if objname == self.obj.Name:
|
| | self.form.message.setText(
|
| | translate("AttachmentEditor", "Ignored. Can't attach object to itself!", None)
|
| | )
|
| | return
|
| | if App.getDocument(docname).getObject(objname) in getAllDependent(self.obj):
|
| | self.form.message.setText(
|
| | translate(
|
| | "AttachmentEditor",
|
| | "{} depends on object being attached, can't use it for attachment",
|
| | None,
|
| | ).format(objname)
|
| | )
|
| | return
|
| |
|
| | self.refLines[i].setText(
|
| | StrFromLink(App.getDocument(docname).getObject(objname), subname)
|
| | )
|
| | self.lineRefChanged(i, "")
|
| | if self.auto_next:
|
| | i += 1
|
| | self.i_active_ref = i
|
| | self.updateRefButtons()
|
| |
|
| |
|
| |
|
| | def attachmentOffsetChanged(self, index, value):
|
| | if self.block:
|
| | return
|
| | plm = self.attacher.AttachmentOffset
|
| | pos = plm.Base
|
| | if index == 0:
|
| | pos.x = Q(self.form.attachmentOffsetX.text()).Value
|
| | if index == 1:
|
| | pos.y = Q(self.form.attachmentOffsetY.text()).Value
|
| | if index == 2:
|
| | pos.z = Q(self.form.attachmentOffsetZ.text()).Value
|
| | if index >= 0 and index <= 2:
|
| | plm.Base = pos
|
| | if index >= 3 and index <= 5:
|
| | yaw = Q(self.form.attachmentOffsetYaw.text()).Value
|
| | pitch = Q(self.form.attachmentOffsetPitch.text()).Value
|
| | roll = Q(self.form.attachmentOffsetRoll.text()).Value
|
| | rot = App.Rotation(yaw, pitch, roll)
|
| | plm.Rotation = rot
|
| |
|
| | self.attacher.AttachmentOffset = plm
|
| |
|
| | self.updatePreview()
|
| |
|
| | def checkBoxFlipClicked(self):
|
| | if self.block:
|
| | return
|
| | self.attacher.Reverse = self.form.checkBoxFlip.isChecked()
|
| | self.updatePreview()
|
| |
|
| | def lineRefChanged(self, index, value):
|
| | if self.block:
|
| | return
|
| |
|
| | self.updatePreview()
|
| |
|
| | def refButtonClicked(self, index):
|
| | if self.block:
|
| | return
|
| | if self.i_active_ref == index:
|
| |
|
| | self.i_active_ref = -1
|
| | else:
|
| |
|
| | self.i_active_ref = index
|
| | self.auto_next = False
|
| | self.updateRefButtons()
|
| |
|
| | def modeSelected(self):
|
| | if self.block:
|
| | return
|
| | self.attacher.Mode = self.getCurrentMode()
|
| | self.updatePreview()
|
| |
|
| |
|
| | def writeParameters(self):
|
| | "Transfer from the dialog to the object"
|
| | self.attacher.writeParametersToFeature(self.obj)
|
| |
|
| | def readParameters(self):
|
| | "Transfer from the object to the dialog"
|
| | if self.obj_is_attachable:
|
| | self.attacher.readParametersFromFeature(self.obj)
|
| |
|
| | plm = self.attacher.AttachmentOffset
|
| | try:
|
| | old_selfblock = self.block
|
| | self.block = True
|
| | self.form.attachmentOffsetX.lineEdit().setText((plm.Base.x * mm).UserString)
|
| | self.form.attachmentOffsetY.lineEdit().setText((plm.Base.y * mm).UserString)
|
| | self.form.attachmentOffsetZ.lineEdit().setText((plm.Base.z * mm).UserString)
|
| | self.form.attachmentOffsetYaw.lineEdit().setText(
|
| | (plm.Rotation.toEuler()[0] * deg).UserString
|
| | )
|
| | self.form.attachmentOffsetPitch.lineEdit().setText(
|
| | (plm.Rotation.toEuler()[1] * deg).UserString
|
| | )
|
| | self.form.attachmentOffsetRoll.lineEdit().setText(
|
| | (plm.Rotation.toEuler()[2] * deg).UserString
|
| | )
|
| |
|
| | self.form.checkBoxFlip.setChecked(self.attacher.Reverse)
|
| |
|
| | self.fillAllRefLines()
|
| | finally:
|
| | self.block = old_selfblock
|
| |
|
| | def fillAllRefLines(self):
|
| | old_block = self.block
|
| | try:
|
| | self.block = True
|
| | strings = StrListFromRefs(self.attacher.References)
|
| | if len(strings) < len(self.refLines):
|
| | strings.extend([""] * (len(self.refLines) - len(strings)))
|
| | for i in range(len(self.refLines)):
|
| | self.refLines[i].setText(strings[i])
|
| | finally:
|
| | self.block = old_block
|
| |
|
| | def parseAllRefLines(self):
|
| | self.attacher.References = RefsFromStrList(
|
| | [le.text() for le in self.refLines], self.obj.Document
|
| | )
|
| |
|
| | def updateListOfModes(self):
|
| | """needs suggestor to have been called, and assigned to self.last_sugr"""
|
| | try:
|
| | old_selfblock = self.block
|
| | self.block = True
|
| | list_widget = self.form.listOfModes
|
| | list_widget.clear()
|
| | sugr = self.last_sugr
|
| |
|
| | valid_modes = ["Deactivated"] + sugr["allApplicableModes"]
|
| |
|
| |
|
| | for m in valid_modes:
|
| | item = QtGui.QListWidgetItem()
|
| | txt = self.attacher.getModeInfo(m)["UserFriendlyName"]
|
| | item.setText(txt)
|
| | item.setData(self.KEYmode, m)
|
| | item.setData(self.KEYon, True)
|
| | if m == sugr["bestFitMode"]:
|
| | f = item.font()
|
| | f.setBold(True)
|
| | item.setFont(f)
|
| | list_widget.addItem(item)
|
| | item.setSelected(self.attacher.Mode == m)
|
| |
|
| | for m in sugr["reachableModes"].keys():
|
| | item = QtGui.QListWidgetItem()
|
| | txt = self.attacher.getModeInfo(m)["UserFriendlyName"]
|
| | listlistrefs = sugr["reachableModes"][m]
|
| | if len(listlistrefs) == 1:
|
| | listrefs_userfriendly = [
|
| | self.attacher.getRefTypeInfo(t)["UserFriendlyName"] for t in listlistrefs[0]
|
| | ]
|
| | txt = translate("AttachmentEditor", "{} (add {})", None).format(
|
| | txt, "+".join(listrefs_userfriendly)
|
| | )
|
| | else:
|
| | txt = translate("AttachmentEditor", "{} (add more references)", None).format(
|
| | txt
|
| | )
|
| | item.setText(txt)
|
| | item.setData(self.KEYmode, m)
|
| | item.setData(self.KEYon, True)
|
| | if m == sugr["bestFitMode"]:
|
| | f = item.font()
|
| | f.setBold(True)
|
| | item.setFont(f)
|
| |
|
| |
|
| | f = item.flags()
|
| | f = f & ~(QtCore.Qt.ItemFlag.ItemIsEnabled | QtCore.Qt.ItemFlag.ItemIsSelectable)
|
| | item.setFlags(f)
|
| |
|
| | list_widget.addItem(item)
|
| |
|
| |
|
| | for item in list_widget.findItems("", QtCore.Qt.MatchContains):
|
| | m = item.data(self.KEYmode)
|
| | on = item.data(self.KEYon)
|
| |
|
| | mi = self.attacher.getModeInfo(m)
|
| | cmb = []
|
| | for refstr in mi["ReferenceCombinations"]:
|
| | refstr_userfriendly = [
|
| | self.attacher.getRefTypeInfo(t)["UserFriendlyName"] for t in refstr
|
| | ]
|
| | cmb.append(", ".join(refstr_userfriendly))
|
| |
|
| | tip = mi["BriefDocu"]
|
| | if m != "Deactivated":
|
| | tip += "\n\n"
|
| | tip += translate(
|
| | "AttachmentEditor", "Reference combinations:", None
|
| | ) + " \n\n".join(cmb)
|
| |
|
| | item.setToolTip(tip)
|
| |
|
| | finally:
|
| | self.block = old_selfblock
|
| |
|
| | def updateRefButtons(self):
|
| | try:
|
| | old_selfblock = self.block
|
| | self.block = True
|
| | for i in range(len(self.refButtons)):
|
| | btn = self.refButtons[i]
|
| | btn.setCheckable(True)
|
| | btn.setChecked(self.i_active_ref == i)
|
| | typ = translate("AttachmentEditor", "Reference{}", None).format(str(i + 1))
|
| | if self.last_sugr is not None:
|
| | typestr = self.last_sugr["references_Types"]
|
| | if i < len(typestr):
|
| | typ = self.attacher.getRefTypeInfo(typestr[i])["UserFriendlyName"]
|
| | btn.setText(
|
| | translate("AttachmentEditor", "Selecting…", None)
|
| | if self.i_active_ref == i
|
| | else typ
|
| | )
|
| | finally:
|
| | self.block = old_selfblock
|
| |
|
| | def getCurrentMode(self):
|
| | list_widget = self.form.listOfModes
|
| | sel = list_widget.selectedItems()
|
| | if len(sel) == 1:
|
| | if sel[0].data(self.KEYon):
|
| | return str(
|
| | sel[0].data(self.KEYmode)
|
| | )
|
| |
|
| | if self.last_sugr is not None:
|
| | if self.last_sugr["message"] == "OK":
|
| | return self.last_sugr["bestFitMode"]
|
| |
|
| | return self.attacher.Mode
|
| |
|
| | def updatePreview(self):
|
| | new_plm = None
|
| |
|
| | try:
|
| | self.parseAllRefLines()
|
| | self.last_sugr = self.attacher.suggestModes()
|
| | if self.last_sugr["message"] == "LinkBroken":
|
| | raise ValueError(
|
| | translate("AttachmentEditor", "Failed to resolve links. {}", None).format(
|
| | self.last_sugr["error"]
|
| | )
|
| | )
|
| |
|
| | self.updateListOfModes()
|
| |
|
| | self.attacher.Mode = self.getCurrentMode()
|
| |
|
| | new_plm = self.attacher.calculateAttachedPlacement(self.obj.Placement)
|
| | if new_plm is None:
|
| | self.form.message.setText(translate("AttachmentEditor", "Not attached", None))
|
| | else:
|
| | self.form.message.setText(
|
| | translate("AttachmentEditor", "Attached with mode {}", None).format(
|
| | self.attacher.getModeInfo(self.getCurrentMode())["UserFriendlyName"]
|
| | )
|
| | )
|
| | if PlacementsFuzzyCompare(self.obj.Placement, new_plm) == False:
|
| |
|
| |
|
| | self.obj.Placement = new_plm
|
| | except Exception as err:
|
| | self.form.message.setText(
|
| | translate("AttachmentEditor", "Error: {}", None).format(str(err))
|
| | )
|
| |
|
| | if new_plm is not None:
|
| | self.form.groupBox_AttachmentOffset.setTitle(
|
| | translate("AttachmentEditor", "Attachment Offset (in local coordinates):", None)
|
| | )
|
| | self.form.groupBox_AttachmentOffset.setEnabled(True)
|
| | else:
|
| | self.form.groupBox_AttachmentOffset.setTitle(
|
| | translate("AttachmentEditor", "Attachment Offset (inactive - not attached):", None)
|
| | )
|
| | self.form.groupBox_AttachmentOffset.setEnabled(False)
|
| |
|
| | def cleanUp(self):
|
| | """stuff that needs to be done when dialog is closed."""
|
| | Gui.Selection.removeObserver(self)
|
| | if self.tv:
|
| | self.tv.restore()
|
| |
|