From 5b1db512317b6cfe420238e0d7c85b5d5291ae27 Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Wed, 19 Jun 2024 15:02:34 +0200 Subject: [PATCH 1/3] Spreadsheet: ViewProviderSpreadsheet: define some variables. --- src/Mod/Spreadsheet/Gui/ViewProviderSpreadsheet.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Mod/Spreadsheet/Gui/ViewProviderSpreadsheet.cpp b/src/Mod/Spreadsheet/Gui/ViewProviderSpreadsheet.cpp index ff91acff48..3f4fa32224 100644 --- a/src/Mod/Spreadsheet/Gui/ViewProviderSpreadsheet.cpp +++ b/src/Mod/Spreadsheet/Gui/ViewProviderSpreadsheet.cpp @@ -145,7 +145,9 @@ void ViewProviderSheet::exportAsFile() &selectedFilter); if (!fileName.isEmpty()) { if (sheet) { - char delim, quote, escape; + char delim = '\0'; + char quote = '\0'; + char escape = '\0'; std::string errMsg = "Export"; bool isValid = sheet->getCharsFromPrefs(delim, quote, escape, errMsg); @@ -154,7 +156,6 @@ void ViewProviderSheet::exportAsFile() } else { Base::Console().Error(errMsg.c_str()); - return; } } } From 4ca08fd684304e4ed02f9a936a65d3841f278cf2 Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Wed, 19 Jun 2024 15:09:05 +0200 Subject: [PATCH 2/3] Assembly: ViewProviderBom: Use runCommand instead of C API --- src/Mod/Assembly/Gui/ViewProviderBom.cpp | 34 +++++++----------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/src/Mod/Assembly/Gui/ViewProviderBom.cpp b/src/Mod/Assembly/Gui/ViewProviderBom.cpp index 1ce7cbd18e..ee2146ad8f 100644 --- a/src/Mod/Assembly/Gui/ViewProviderBom.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderBom.cpp @@ -32,6 +32,7 @@ #include #include +#include #include @@ -53,33 +54,16 @@ QIcon ViewProviderBom::getIcon() const bool ViewProviderBom::doubleClicked() { - try { - // Ensure the Python interpreter is initialized - if (!Py_IsInitialized()) { - Py_Initialize(); - } + std::string obj_name = getObject()->getNameInDocument(); + std::string doc_name = getObject()->getDocument()->getName(); - // Acquire the GIL (Global Interpreter Lock) - PyGILState_STATE gstate; - gstate = PyGILState_Ensure(); - std::string obj_name = getObject()->getNameInDocument(); - std::string doc_name = getObject()->getDocument()->getName(); + std::string pythonCommand = "import CommandCreateBom\n" + "obj = App.getDocument('" + + doc_name + "').getObject('" + obj_name + + "')\n" + "Gui.Control.showDialog(CommandCreateBom.TaskAssemblyCreateBom(obj))"; - // Call the Python function - std::string pythonCommand = "import CommandCreateBom\n" - "obj = App.getDocument('" - + doc_name + "').getObject('" + obj_name - + "')\n" - "Gui.Control.showDialog(CommandCreateBom.TaskAssemblyCreateBom(obj))"; - - PyRun_SimpleString(pythonCommand.c_str()); - - // Release the GIL - PyGILState_Release(gstate); - } - catch (...) { - PyErr_Print(); - } + Gui::Command::runCommand(Gui::Command::App, pythonCommand.c_str()); return true; } From d8d2cbcc62f97d46813e8c8e5fffee97a49716da Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Wed, 19 Jun 2024 15:10:00 +0200 Subject: [PATCH 3/3] Assembly: BOM: Add help button. Make auto-generated columns bold. --- src/Mod/Assembly/CommandCreateBom.py | 183 +++++++++++++++--- .../Resources/panels/TaskAssemblyCreateBom.ui | 41 ++-- 2 files changed, 186 insertions(+), 38 deletions(-) diff --git a/src/Mod/Assembly/CommandCreateBom.py b/src/Mod/Assembly/CommandCreateBom.py index 523342c1d3..c90425bf6c 100644 --- a/src/Mod/Assembly/CommandCreateBom.py +++ b/src/Mod/Assembly/CommandCreateBom.py @@ -34,8 +34,7 @@ if App.GuiUp: import UtilsAssembly import Preferences - -# translate = App.Qt.translate +from functools import partial __title__ = "Assembly Command Create Bill of Materials" __author__ = "Ondsel" @@ -44,11 +43,11 @@ __url__ = "https://www.freecad.org" translate = App.Qt.translate TranslatedColumnNames = [ - translate("Assembly", "Index"), - translate("Assembly", "Name"), + translate("Assembly", "Index (auto)"), + translate("Assembly", "Name (auto)"), translate("Assembly", "Description"), - translate("Assembly", "File Name"), - translate("Assembly", "Quantity"), + translate("Assembly", "File Name (auto)"), + translate("Assembly", "Quantity (auto)"), ] ColumnNames = [ @@ -67,22 +66,22 @@ class CommandCreateBom: def GetResources(self): return { "Pixmap": "Assembly_BillOfMaterials", - "MenuText": QT_TRANSLATE_NOOP("Assembly_BillOfMaterials", "Create Bill of Materials"), + "MenuText": QT_TRANSLATE_NOOP("Assembly_CreateBom", "Create Bill of Materials"), "Accel": "O", "ToolTip": "

" + QT_TRANSLATE_NOOP( - "Assembly_CreateView", + "Assembly_CreateBom", "Create a bill of materials of the current assembly. If an assembly is active, it will be a BOM of this assembly. Else it will be a BOM of the whole document.", ) + "

" + QT_TRANSLATE_NOOP( - "Assembly_CreateView", + "Assembly_CreateBom", "The BOM object is a document object that stores the settings of your BOM. It is also a spreadsheet object so you can easily visualize the bom. If you don't need the BOM object to be saved as a document object, you can simply export and cancel the task.", ) + "

" + QT_TRANSLATE_NOOP( - "Assembly_CreateView", - "The columns 'Index', 'Name', 'File Name' and 'Quantity' are automatically generated on recompute. The 'Description' and custom columns are not overwriten.", + "Assembly_CreateBom", + "The columns 'Index', 'Name', 'File Name' and 'Quantity' are automatically generated on recompute. The 'Description' and custom columns are not overwritten.", ) + "

", "CmdType": "ForEdit", @@ -115,22 +114,22 @@ class TaskAssemblyCreateBom(QtCore.QObject): self.form.columnList.installEventFilter(self) - self.form.btnAddColumn.clicked.connect(self.addColumn) + self.form.btnAddColumn.clicked.connect(self.showAddColumnMenu) self.form.btnExport.clicked.connect(self.export) + self.form.helpButton.clicked.connect(self.showHelpDialog) + pref = Preferences.preferences() if bomObj: App.setActiveTransaction("Edit Bill Of Materials") - names = [] - for i in range(len(bomObj.columnsNames)): - text = bomObj.columnsNames[i] - if text in ColumnNames: - index = ColumnNames.index(text) - text = TranslatedColumnNames[index] - names.append(text) - self.form.columnList.addItems(names) + for name in bomObj.columnsNames: + if name in ColumnNames: + index = ColumnNames.index(name) + name = TranslatedColumnNames[index] + + self.addColItem(name) self.bomObj = bomObj self.form.CheckBox_onlyParts.setChecked(bomObj.onlyParts) @@ -139,7 +138,10 @@ class TaskAssemblyCreateBom(QtCore.QObject): else: App.setActiveTransaction("Create Bill Of Materials") - self.form.columnList.addItems(TranslatedColumnNames) + + # Add the columns + for name in TranslatedColumnNames: + self.addColItem(name) self.createBomObject() self.form.CheckBox_onlyParts.setChecked(pref.GetBool("BOMOnlyParts", False)) @@ -199,15 +201,67 @@ class TaskAssemblyCreateBom(QtCore.QObject): counter += 1 new_name = f"{new_name}_{counter}" - new_item = QtWidgets.QListWidgetItem(new_name) - new_item.setFlags(new_item.flags() | QtCore.Qt.ItemIsEditable) - self.form.columnList.addItem(new_item) + item = self.addColItem(new_name) # Ensure the new item is selected and starts editing - self.form.columnList.setCurrentItem(new_item) - self.form.columnList.editItem(new_item) + self.form.columnList.setCurrentItem(item) + self.form.columnList.editItem(item) self.updateColumnList() + def addColItem(self, name): + item = QtWidgets.QListWidgetItem(name) + + isCustomCol = self.isCustomColumn(name) + + if isCustomCol: + item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable) + else: + font = item.font() + font.setBold(True) + item.setFont(font) + + self.form.columnList.addItem(item) + return item + + def showAddColumnMenu(self): + menu = QtWidgets.QMenu() + # Get the current columns in the list + current_columns = [ + self.form.columnList.item(i).text() for i in range(self.form.columnList.count()) + ] + + # Add actions for columns that are not currently in the list + noneAdded = True + for name in TranslatedColumnNames: + if name not in current_columns: + action = QtWidgets.QAction(f"Add '{name}' column", self) + action.triggered.connect(partial(self.addColItem, name)) + menu.addAction(action) + noneAdded = False + + if noneAdded: + self.addColumn() + return + + # Add the action for adding a custom column + action = QtWidgets.QAction("Add custom column", self) + action.triggered.connect(self.addColumn) + menu.addAction(action) + + # Show the menu below the button + menu.exec_( + self.form.btnAddColumn.mapToGlobal(QtCore.QPoint(0, self.form.btnAddColumn.height())) + ) + + def isCustomColumn(self, name): + isCustomCol = True + if name in TranslatedColumnNames: + # Description column is currently not auto generated so it's a custom column + index = TranslatedColumnNames.index(name) + if ColumnNames[index] != "Description": + isCustomCol = False + return isCustomCol + def onItemsReordered(self, parent, start, end, destination, row): self.updateColumnList() @@ -248,8 +302,20 @@ class TaskAssemblyCreateBom(QtCore.QObject): ) item.setText(old_text) else: + isCustomCol = self.isCustomColumn(new_text) + + if not isCustomCol: + font = item.font() + font.setBold(True) + item.setFont(font) + # Use a single-shot timer to defer changing the flags (else FC crashes) + QtCore.QTimer.singleShot(0, lambda: self.makeItemNonEditable(item)) + self.updateColumnList() + def makeItemNonEditable(self, item): + item.setFlags(item.flags() & ~QtCore.Qt.ItemIsEditable) + def isNameDuplicate(self, name): for i in range(self.form.columnList.count()): if self.form.columnList.item(i).text() == name: @@ -289,6 +355,71 @@ class TaskAssemblyCreateBom(QtCore.QObject): return super().eventFilter(watched, event) + def showHelpDialog(self): + help_dialog = QtWidgets.QDialog(self.form) + help_dialog.setWindowFlags(QtCore.Qt.Popup) + help_dialog.setWindowModality(QtCore.Qt.NonModal) + help_dialog.setAttribute(QtCore.Qt.WA_DeleteOnClose) + + layout = QtWidgets.QVBoxLayout() + layout.setContentsMargins(10, 10, 10, 10) + + options_title = QtWidgets.QLabel("" + translate("Assembly", "Options:") + "") + options_text = QtWidgets.QLabel( + " - " + + translate( + "Assembly", + "Sub-assemblies children : If checked, Sub assemblies children will be added to the bill of materials.", + ) + + "\n" + " - " + + translate( + "Assembly", + "Parts children : If checked, Parts children will be added to the bill of materials.", + ) + + "\n" + " - " + + translate( + "Assembly", + "Only parts : If checked, only Part containers and sub-assemblies will be added to the bill of materials. Solids like PartDesign Bodies, fasteners or Part workbench primitives will be ignored.", + ) + + "\n" + ) + columns_title = QtWidgets.QLabel("" + translate("Assembly", "Columns:") + "") + columns_text = QtWidgets.QLabel( + " - " + + translate( + "Assembly", + "Auto columns : (Index, Quantity, Name...) are populated automatically. Any modification you make will be overridden. These columns cannot be renamed.", + ) + + "\n" + " - " + + translate( + "Assembly", + "Custom columns : 'Description' and other custom columns you add by clicking on 'Add column' will not have their data overwritten. These columns can be renamed by double-clicking or pressing F2 (Renaming a column will currently lose its data).", + ) + + "\n" + "\n" + + translate( + "Assembly", + "Any column (custom or not) can be deleted by pressing Del.", + ) + + "\n" + ) + + options_text.setWordWrap(True) + columns_text.setWordWrap(True) + + layout.addWidget(options_title) + layout.addWidget(options_text) + layout.addWidget(columns_title) + layout.addWidget(columns_text) + + help_dialog.setLayout(layout) + help_dialog.setFixedWidth(500) + + help_dialog.show() + if App.GuiUp: Gui.addCommand("Assembly_CreateBom", CommandCreateBom()) diff --git a/src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateBom.ui b/src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateBom.ui index 8726839896..6e58c74302 100644 --- a/src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateBom.ui +++ b/src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateBom.ui @@ -14,13 +14,13 @@ Create Bill Of Materials - + - If checked, Sub assemblies sub-components will be added to the bill of materials. + If checked, Sub assemblies children will be added to the bill of materials. - Detail sub-assemblies + Sub-assemblies children true @@ -33,13 +33,13 @@ - + - If checked, Parts sub-components will be added to the bill of materials. + If checked, Parts children will be added to the bill of materials. - Detail parts + Parts children true @@ -52,10 +52,10 @@ - + - If checked, only Part containers will be added to the bill of materials. Solids like PartDesign Bodies will be ignored. + If checked, only Part containers and sub-assemblies will be added to the bill of materials. Solids like PartDesign Bodies, fasteners or Part workbench primitives will be ignored. Only parts @@ -71,11 +71,8 @@ - + - - Columns of the bill of materials - Columns @@ -100,6 +97,26 @@ + + + + + 0 + 0 + + + + Help + + + + + + + :/icons/help-browser.svg:/icons/help-browser.svg + + +