From 2e9e496b57d91be89a49b81e3920912dcb18a11d Mon Sep 17 00:00:00 2001 From: Daniel Wood Date: Mon, 3 Feb 2025 16:58:24 +0000 Subject: [PATCH] CAM: Tool Bit Library Fixes (#18973) * remove unused else * Enable reloading / re-selection of libraries * Reload the libraries when exiting the editor * Clear the model to prevent duplicate entries * add missing docstring to reduce linting warnings * Maintain any previous library selection when editing --- src/Mod/CAM/Path/Tool/Gui/BitLibrary.py | 85 +++++++++++++++++++------ 1 file changed, 64 insertions(+), 21 deletions(-) diff --git a/src/Mod/CAM/Path/Tool/Gui/BitLibrary.py b/src/Mod/CAM/Path/Tool/Gui/BitLibrary.py index 9ea2d355dc..8604a1575c 100644 --- a/src/Mod/CAM/Path/Tool/Gui/BitLibrary.py +++ b/src/Mod/CAM/Path/Tool/Gui/BitLibrary.py @@ -59,6 +59,7 @@ translate = FreeCAD.Qt.translate def checkWorkingDir(): + """Check the tool library directory writable and configure a new library if required""" # users shouldn't use the example toolbits and libraries. # working directory should be writable Path.Log.track() @@ -97,7 +98,8 @@ def checkWorkingDir(): Path.Preferences.setLastPathToolBit("{}{}Bit".format(workingdir, os.path.sep)) Path.Log.debug("setting workingdir to: {}".format(workingdir)) - # Copy only files of default Path/Tool folder to working directory (targeting the README.md help file) + # Copy only files of default Path/Tool folder to working directory + # (targeting the README.md help file) src_toolfiles = os.listdir(defaultdir) for file_name in src_toolfiles: if file_name in ["README.md"]: @@ -216,6 +218,7 @@ class _TableView(PySide.QtGui.QTableView): self._copyTool(uuid, dst + i) def dropEvent(self, event): + """Handle drop events on the tool table""" Path.Log.track() mime = event.mimeData() data = mime.data("application/x-qstandarditemmodeldatalist") @@ -247,6 +250,7 @@ class ModelFactory: """ Path.Log.track() path = Path.Preferences.lastPathToolLibrary() + model.clear() if os.path.isdir(path): # opening all tables in a directory libFiles = [f for f in glob.glob(path + os.path.sep + "*.fctl")] @@ -394,15 +398,16 @@ class ToolBitSelector(object): self.factory = ModelFactory() self.toolModel = PySide.QtGui.QStandardItemModel(0, len(self.columnNames())) self.libraryModel = PySide.QtGui.QStandardItemModel(0, len(self.columnNames())) - self.factory.find_libraries(self.libraryModel) self.setupUI() self.title = self.form.windowTitle() def columnNames(self): + """Define the column names to display""" return ["#", "Tool"] def currentLibrary(self, shortNameOnly): + """Get the file path for the current tool library""" libfile = Path.Preferences.lastFileToolLibrary() if libfile is None or libfile == "": return "" @@ -411,6 +416,7 @@ class ToolBitSelector(object): return libfile def loadData(self): + """Load the toolbits for the selected tool library""" Path.Log.track() self.toolModel.clear() self.toolModel.setHorizontalHeaderLabels(self.columnNames()) @@ -422,40 +428,58 @@ class ToolBitSelector(object): # Get the data for the selected index libPath = self.libraryModel.item(currentIndex).data(_PathRole) self.factory.library_open(self.toolModel, libPath) - else: - pass self.toolModel.takeColumn(3) self.toolModel.takeColumn(2) - def setupUI(self): + def loadToolLibraries(self): + """ + Load the tool libraries in to self.libraryModel + and populate the tooldock form combobox with the + libraries names + """ Path.Log.track() - self.loadData() # Load the initial data for the tool model - self.form.tools.setModel(self.toolModel) - self.form.tools.selectionModel().selectionChanged.connect(self.enableButtons) - self.form.tools.doubleClicked.connect(partial(self.selectedOrAllToolControllers)) + # Get the current library so we can try and maintain any previous selection + current_lib = self.currentLibrary(True) # True to get short name only + + # load the tool libraries + self.factory.find_libraries(self.libraryModel) # Set the library model to the combobox self.form.cboLibraries.setModel(self.libraryModel) + # Set the current library as the selected item in the combobox + currentIndex = self.form.cboLibraries.findText(current_lib) + + # Set the selected library as the currentIndex in the combobox + if currentIndex == -1 and self.libraryModel.rowCount() > 0: + # If current library is not found, default to the first item + currentIndex = 0 + + self.form.cboLibraries.setCurrentIndex(currentIndex) + + def setupUI(self): + """Setup the form and load the tooltable data""" + Path.Log.track() + # Connect the library change to reload data and update tooltip self.form.cboLibraries.currentIndexChanged.connect(self.loadData) self.form.cboLibraries.currentIndexChanged.connect(self.updateLibraryTooltip) - # Set the current library as the selected item in the combobox - current_lib = self.currentLibrary(True) # True to get short name only - currentIndex = self.form.cboLibraries.findText(current_lib) - if currentIndex == -1 and self.libraryModel.rowCount() > 0: - # If current library is not found, default to the first item - currentIndex = 0 - self.form.cboLibraries.setCurrentIndex(currentIndex) - self.updateLibraryTooltip(currentIndex) # Initialize the tooltip + # Load the tool libraries. + # This will trigger a change in current index of the cboLibraries combobox + self.loadToolLibraries() + + self.form.tools.setModel(self.toolModel) + self.form.tools.selectionModel().selectionChanged.connect(self.enableButtons) + self.form.tools.doubleClicked.connect(partial(self.selectedOrAllToolControllers)) self.form.libraryEditorOpen.clicked.connect(self.libraryEditorOpen) self.form.addToolController.clicked.connect(self.selectedOrAllToolControllers) def updateLibraryTooltip(self, index): + """Add a tooltip to the combobox""" if index != -1: item = self.libraryModel.item(index) if item: @@ -467,15 +491,18 @@ class ToolBitSelector(object): self.form.cboLibraries.setToolTip(translate("CAM_Toolbit", "No library selected")) def enableButtons(self): + """Enable button to add tool controller when a tool is selected""" + # Set buttons inactive + self.form.addToolController.setEnabled(False) selected = len(self.form.tools.selectedIndexes()) >= 1 if selected: jobs = len([1 for j in FreeCAD.ActiveDocument.Objects if j.Name[:3] == "Job"]) >= 1 - self.form.addToolController.setEnabled(selected and jobs) + self.form.addToolController.setEnabled(selected and jobs) def libraryEditorOpen(self): library = ToolBitLibrary() library.open() - self.loadData() + self.loadToolLibraries() def selectedOrAllTools(self): """ @@ -565,6 +592,7 @@ class ToolBitLibrary(object): self.title = self.form.windowTitle() def toolBitNew(self): + """Create a new toolbit""" Path.Log.track() # select the shape file @@ -596,6 +624,7 @@ class ToolBitLibrary(object): self.librarySave() def toolBitExisting(self): + """Add an existing toolbit to the library""" filenames = PathToolBitGui.GetToolFiles() @@ -612,6 +641,7 @@ class ToolBitLibrary(object): self.librarySave() def toolDelete(self): + """Delete a tool""" Path.Log.track() selectedRows = set([index.row() for index in self.toolTableView.selectedIndexes()]) for row in sorted(list(selectedRows), key=lambda r: -r): @@ -635,6 +665,7 @@ class ToolBitLibrary(object): return self.form.exec_() def libraryPath(self): + """Select and load a tool library""" Path.Log.track() path = PySide.QtGui.QFileDialog.getExistingDirectory( self.form, "Tool Library Path", Path.Preferences.lastPathToolLibrary() @@ -646,6 +677,7 @@ class ToolBitLibrary(object): self.loadData() def cleanupDocument(self): + """Clean up the document""" # This feels like a hack. Remove the toolbit object # remove the editor from the dialog # re-enable all the controls @@ -658,6 +690,7 @@ class ToolBitLibrary(object): self.lockoff() def accept(self): + """Handle accept signal""" self.editor.accept() self.temptool.Proxy.saveToFile(self.temptool, self.temptool.File) self.librarySave() @@ -665,9 +698,11 @@ class ToolBitLibrary(object): self.cleanupDocument() def reject(self): + """Handle reject signal""" self.cleanupDocument() def lockon(self): + """Set the state of the form widgets: inactive""" self.toolTableView.setEnabled(False) self.form.toolCreate.setEnabled(False) self.form.toolDelete.setEnabled(False) @@ -679,6 +714,7 @@ class ToolBitLibrary(object): self.form.librarySave.setEnabled(False) def lockoff(self): + """Set the state of the form widgets: active""" self.toolTableView.setEnabled(True) self.form.toolCreate.setEnabled(True) self.form.toolDelete.setEnabled(True) @@ -691,6 +727,7 @@ class ToolBitLibrary(object): self.form.librarySave.setEnabled(True) def toolEdit(self, selected): + """Edit the selected tool bit""" Path.Log.track() item = self.toolModel.item(selected.row(), 0) @@ -721,6 +758,7 @@ class ToolBitLibrary(object): print("all done") def libraryNew(self): + """Create a new tool library""" TooltableTypeJSON = translate("CAM_ToolBit", "Tooltable JSON (*.fctl)") filename = PySide.QtGui.QFileDialog.getSaveFileName( @@ -744,6 +782,7 @@ class ToolBitLibrary(object): self.loadData() def librarySave(self): + """Save the tool library""" library = {} tools = [] library["version"] = 1 @@ -771,6 +810,7 @@ class ToolBitLibrary(object): self.form.close() def libPaths(self): + """Get the file path for the last used tool library""" lib = Path.Preferences.lastFileToolLibrary() loc = Path.Preferences.lastPathToolLibrary() @@ -785,6 +825,7 @@ class ToolBitLibrary(object): ] def loadData(self, path=None): + """Load tooltable data""" Path.Log.track(path) self.toolTableView.setUpdatesEnabled(False) self.form.TableList.setUpdatesEnabled(False) @@ -821,6 +862,7 @@ class ToolBitLibrary(object): self.form.TableList.setUpdatesEnabled(True) def setupUI(self): + """Setup the form and load the tool library data""" Path.Log.track() self.form.TableList.setModel(self.listModel) self.toolTableView.setModel(self.toolModel) @@ -846,7 +888,7 @@ class ToolBitLibrary(object): self.toolSelect([], []) def librarySaveAs(self, path): - + """Save the tooltable to a format to use with an external system""" TooltableTypeJSON = translate("CAM_ToolBit", "Tooltable JSON (*.fctl)") TooltableTypeLinuxCNC = translate("CAM_ToolBit", "LinuxCNC tooltable (*.tbl)") TooltableTypeCamotics = translate("CAM_ToolBit", "CAMotics tooltable (*.json)") @@ -874,7 +916,7 @@ class ToolBitLibrary(object): self.librarySave() def libararySaveLinuxCNC(self, path): - # linuxcnc line template + """Export the tool table to a file for use with linuxcnc""" LIN = "T{} P{} X{} Y{} Z{} A{} B{} C{} U{} V{} W{} D{} I{} J{} Q{}; {}" with open(path, "w") as fp: fp.write(";\n") @@ -938,6 +980,7 @@ class ToolBitLibrary(object): Path.Log.error("Could not find tool #{} ".format(toolNr)) def libararySaveCamotics(self, path): + """Export the tool table to a file for use with camotics""" SHAPEMAP = { "ballend": "Ballnose",