diff --git a/src/Mod/Assembly/JointObject.py b/src/Mod/Assembly/JointObject.py index 4cbf7628ba..55ad10d09c 100644 --- a/src/Mod/Assembly/JointObject.py +++ b/src/Mod/Assembly/JointObject.py @@ -32,7 +32,7 @@ from collections.abc import Sequence if App.GuiUp: import FreeCADGui as Gui - from PySide import QtWidgets + from PySide import QtGui, QtWidgets __title__ = "Assembly Joint object" __author__ = "Ondsel" @@ -1386,6 +1386,8 @@ class TaskAssemblyCreateJoint(QtCore.QObject): self.jForm.featureList.installEventFilter(self) + self.createDeleteAction() + self.addition_rejected = False def accept(self): @@ -1784,34 +1786,80 @@ class TaskAssemblyCreateJoint(QtCore.QObject): if info["State"] == "UP" and info["Key"] == "RETURN": self.accept() + def _removeSelectedItems(self, selected_indexes): + for index in selected_indexes: + row = index.row() + if row < len(self.refs): + ref = self.refs[row] + + ref_id = id(ref) + if hasattr(self, "_original_tnp_map") and ref_id in self._original_tnp_map: + # use original TNP string for newly added references + removal_string = self._original_tnp_map[ref_id] + else: + # use processed element name for reloaded references + removal_string = ref[1][0] + + Gui.Selection.removeSelection(ref[0], removal_string) + else: + print(f"Row {row} is out of bounds for refs (length: {len(self.refs)})") + def eventFilter(self, watched, event): if self.jForm is not None and watched == self.jForm.featureList: if event.type() == QtCore.QEvent.ShortcutOverride: - if event.key() == QtCore.Qt.Key_Delete: - event.accept() # Accept the event only if the key is Delete - return True # Indicate that the event has been handled + if ( + hasattr(self, "deleteAction") + and self.deleteAction.shortcut().matches(event.key()) + != QtGui.QKeySequence.NoMatch + ): + event.accept() + return True return False elif event.type() == QtCore.QEvent.KeyPress: - if event.key() == QtCore.Qt.Key_Delete: - selected_indexes = self.jForm.featureList.selectedIndexes() - - for index in selected_indexes: - row = index.row() - if row < len(self.refs): - ref = self.refs[row] - - Gui.Selection.removeSelection(ref[0], ref[1][0]) - + if ( + hasattr(self, "deleteAction") + and self.deleteAction.shortcut().matches(event.key()) + != QtGui.QKeySequence.NoMatch + ): + self.deleteAction.trigger() return True # Consume the event return super().eventFilter(watched, event) + def createDeleteAction(self): + """Create delete action with shortcut""" + try: + delete_sequence = Gui.QtTools.deleteKeySequence() + except AttributeError: + # fallback to standard key if there is no sequence defined + delete_sequence = QtCore.Qt.Key_Delete + + self.deleteAction = QtGui.QAction("Remove", self.jForm) + self.deleteAction.setShortcut(delete_sequence) + + self.deleteAction.setIcon( + QtWidgets.QApplication.style().standardIcon(QtWidgets.QStyle.SP_DialogCancelButton) + ) + + self.deleteAction.setShortcutVisibleInContextMenu(True) + + self.jForm.featureList.addAction(self.deleteAction) + self.jForm.featureList.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) + + self.deleteAction.triggered.connect(self.deleteSelectedItems) + + def deleteSelectedItems(self): + """Delete selected items from the feature list - same logic as Delete key in ev filter""" + selected_indexes = self.jForm.featureList.selectedIndexes() + self._removeSelectedItems(selected_indexes) + def getMovingPart(self, ref): return UtilsAssembly.getMovingPart(self.assembly, ref) # selectionObserver stuff def addSelection(self, doc_name, obj_name, sub_name, mousePos): + original_sub_name = sub_name rootObj = App.getDocument(doc_name).getObject(obj_name) # We do not need the full TNP string like :"Part.Body.Pad.;#a:1;:G0;XTR;:Hc94:8,F.Face6" @@ -1849,6 +1897,12 @@ class TaskAssemblyCreateJoint(QtCore.QObject): # add the vertex name to the reference ref = UtilsAssembly.addVertexToReference(ref, vertex_name) + # store the original TNP string for deletion purposes + if hasattr(self, "_original_tnp_map"): + self._original_tnp_map[id(ref)] = original_sub_name + else: + self._original_tnp_map = {id(ref): original_sub_name} + self.refs.append(ref) self.updateJoint() @@ -1860,15 +1914,24 @@ class TaskAssemblyCreateJoint(QtCore.QObject): self.addition_rejected = False return - ref = [App.getDocument(doc_name).getObject(obj_name), [sub_name]] - moving_part = self.getMovingPart(ref) + rootObj = App.getDocument(doc_name).getObject(obj_name) - # Find and remove the corresponding dictionary from the combined list - for reference in self.refs: - sel_moving_part = self.getMovingPart(reference) - if sel_moving_part == moving_part: + # Apply the same processing as in addSelection to ensure consistent comparison + resolved = rootObj.resolveSubElement(sub_name, True) + sub_name = resolved[2] + + sub_name = UtilsAssembly.fixBodyExtraFeatureInSub(doc_name, sub_name) + + for reference in self.refs[:]: + ref_obj = reference[0] + ref_element_name = reference[1][0] if len(reference[1]) > 0 else "" + + # match both object and processed element name for precise identification + if ref_obj == rootObj and ref_element_name == sub_name: self.refs.remove(reference) break + else: + print("No matching ref found for removal!") self.updateJoint()