From ec2e5fe2ac634870ed116ade2d9134b075519546 Mon Sep 17 00:00:00 2001 From: Paddle Date: Wed, 29 Mar 2023 11:34:32 +0200 Subject: [PATCH 01/15] Pref: Wb: remove args first element on restart. - isRebootRequired is not public but in accept&reject. - PreferencePage::isRebootRequired changed to const - Change 2 warnings to log - remove useless c_str() - Change DlgPreferencesImp::isRebootRequired name + reboot by restart everywhere. - Sort workbenches so that disabled wb are sorted. --- src/Gui/ApplicationPy.cpp | 2 -- src/Gui/CommandStd.cpp | 1 - src/Gui/DlgPreferencesImp.cpp | 17 +++++++++++++---- src/Gui/DlgPreferencesImp.h | 5 +++-- src/Gui/DlgSettingsWorkbenchesImp.cpp | 16 +++++++++------- src/Gui/PropertyPage.cpp | 10 +++++----- src/Gui/PropertyPage.h | 6 +++--- 7 files changed, 33 insertions(+), 24 deletions(-) diff --git a/src/Gui/ApplicationPy.cpp b/src/Gui/ApplicationPy.cpp index d0d5678179..6b04456f78 100644 --- a/src/Gui/ApplicationPy.cpp +++ b/src/Gui/ApplicationPy.cpp @@ -1377,8 +1377,6 @@ PyObject* Application::sShowPreferences(PyObject * /*self*/, PyObject *args) wc.restoreCursor(); cDlg.exec(); wc.setWaitCursor(); - cDlg.isRebootRequired(); //The user may have applied first, then clicked the cancel button so it's not in the if(cDlg.exec()) - wc.setWaitCursor(); Py_Return; } diff --git a/src/Gui/CommandStd.cpp b/src/Gui/CommandStd.cpp index 9d58e84e72..92bb6b846e 100644 --- a/src/Gui/CommandStd.cpp +++ b/src/Gui/CommandStd.cpp @@ -385,7 +385,6 @@ void StdCmdDlgPreferences::activated(int iMsg) if (cDlg.exec()) { cDlg.activeGroupPage(groupName, index); } - cDlg.isRebootRequired(); //The user may have applied first, then clicked the cancel button so it's not in the if(cDlg.exec()) } //=========================================================================== diff --git a/src/Gui/DlgPreferencesImp.cpp b/src/Gui/DlgPreferencesImp.cpp index 4133b00636..7eceaad27f 100644 --- a/src/Gui/DlgPreferencesImp.cpp +++ b/src/Gui/DlgPreferencesImp.cpp @@ -71,7 +71,7 @@ DlgPreferencesImp* DlgPreferencesImp::_activeDialog = nullptr; */ DlgPreferencesImp::DlgPreferencesImp(QWidget* parent, Qt::WindowFlags fl) : QDialog(parent, fl), ui(new Ui_DlgPreferences), - invalidParameter(false), canEmbedScrollArea(true), rebootRequired(false) + invalidParameter(false), canEmbedScrollArea(true), restartRequired(false) { ui->setupUi(this); QFontMetrics fm(font()); @@ -339,6 +339,14 @@ void DlgPreferencesImp::accept() applyChanges(); if (!this->invalidParameter) QDialog::accept(); + + restartIfRequired(); +} + +void DlgPreferencesImp::reject() +{ + QDialog::reject(); + restartIfRequired(); } void DlgPreferencesImp::onButtonBoxClicked(QAbstractButton* btn) @@ -464,7 +472,7 @@ void DlgPreferencesImp::applyChanges() auto page = qobject_cast(tabWidget->widget(j)); if (page) { page->saveSettings(); - rebootRequired = rebootRequired || page->isRebootRequired(); + restartRequired = restartRequired || page->isRestartRequired(); } } } @@ -477,9 +485,9 @@ void DlgPreferencesImp::applyChanges() } } -void DlgPreferencesImp::isRebootRequired() +void DlgPreferencesImp::restartIfRequired() { - if (rebootRequired) { + if (restartRequired) { QMessageBox* restartBox = new QMessageBox(); restartBox->setIcon(QMessageBox::Warning); restartBox->setWindowTitle(tr("Restart required")); @@ -498,6 +506,7 @@ void DlgPreferencesImp::isRebootRequired() QTimer::singleShot(1000, []() { QStringList args = QApplication::arguments(); + args.pop_front(); if (getMainWindow()->close()) QProcess::startDetached(QApplication::applicationFilePath(), args); }); diff --git a/src/Gui/DlgPreferencesImp.h b/src/Gui/DlgPreferencesImp.h index ec3fccfc00..aac9521b0f 100644 --- a/src/Gui/DlgPreferencesImp.h +++ b/src/Gui/DlgPreferencesImp.h @@ -124,10 +124,11 @@ public: ~DlgPreferencesImp() override; void accept() override; + void reject() override; void reload(); void activateGroupPage(const QString& group, int index); void activeGroupPage(QString& group, int& index) const; - void isRebootRequired(); + void restartIfRequired(); protected: void changeEvent(QEvent *e) override; @@ -163,7 +164,7 @@ private: std::unique_ptr ui; bool invalidParameter; bool canEmbedScrollArea; - bool rebootRequired; + bool restartRequired; static const int GroupNameRole; /**< A name for our Qt::UserRole, used when storing user data in a list item */ diff --git a/src/Gui/DlgSettingsWorkbenchesImp.cpp b/src/Gui/DlgSettingsWorkbenchesImp.cpp index d0581c3a04..334e0e821c 100644 --- a/src/Gui/DlgSettingsWorkbenchesImp.cpp +++ b/src/Gui/DlgSettingsWorkbenchesImp.cpp @@ -343,6 +343,8 @@ void DlgSettingsWorkbenchesImp::buildWorkbenchList() QSignalBlocker sigblk(ui->wbList); QStringList workbenches = Application::Instance->workbenches(); + workbenches.sort(); //This will sort alphabetically the disabled wb. + QStringList enabledWbs = getEnabledWorkbenches(); QStringList disabledWbs = getDisabledWorkbenches(); @@ -352,7 +354,7 @@ void DlgSettingsWorkbenchesImp::buildWorkbenchList() addWorkbench(wbName, true); } else { - Base::Console().Warning("Ignoring unknown %s workbench found in user preferences.", wbName.toStdString().c_str()); + Base::Console().Log("Ignoring unknown %s workbench found in user preferences.\n", wbName.toStdString().c_str()); } } //Second we add workbench in alphabetical order that are either Disabled, or !enabled && !disabled, ie newly added wb. @@ -361,7 +363,7 @@ void DlgSettingsWorkbenchesImp::buildWorkbenchList() addWorkbench(wbName, false); } else if (!enabledWbs.contains(wbName)) { - Base::Console().Warning("Adding unknown %s workbench.", wbName.toStdString().c_str()); + Base::Console().Log("Adding unknown %s workbench.\n", wbName.toStdString().c_str()); addWorkbench(wbName, false); } } @@ -392,7 +394,7 @@ QStringList DlgSettingsWorkbenchesImp::getEnabledWorkbenches() QString allWorkbenches = QString::fromLatin1("ALL"); hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Workbenches"); - enabled_wbs = QString::fromStdString(hGrp->GetASCII("Enabled", allWorkbenches.toStdString().c_str()).c_str()); + enabled_wbs = QString::fromStdString(hGrp->GetASCII("Enabled", allWorkbenches.toStdString().c_str())); #if QT_VERSION >= QT_VERSION_CHECK(5,15,0) enabled_wbs_list = enabled_wbs.split(QLatin1String(","), Qt::SkipEmptyParts); #else @@ -461,7 +463,7 @@ void DlgSettingsWorkbenchesImp::loadWorkbenchSelector() void DlgSettingsWorkbenchesImp::wbToggled(const QString& wbName, bool enabled) { - requireReboot(); + requireRestart(); setStartWorkbenchComboItems(); @@ -535,7 +537,7 @@ void DlgSettingsWorkbenchesImp::setStartWorkbenchComboItems() void DlgSettingsWorkbenchesImp::wbItemMoved() { - requireReboot(); + requireRestart(); for (int i = 0; i < ui->wbList->count(); i++) { wbListItem* wbItem = dynamic_cast(ui->wbList->itemWidget(ui->wbList->item(i))); if (wbItem) { @@ -563,13 +565,13 @@ void DlgSettingsWorkbenchesImp::onStartWbChanged(int index) void DlgSettingsWorkbenchesImp::onWbSelectorChanged(int index) { Q_UNUSED(index); - requireReboot(); + requireRestart(); } void DlgSettingsWorkbenchesImp::onWbByTabToggled(bool val) { Q_UNUSED(val); - requireReboot(); + requireRestart(); } #include "moc_DlgSettingsWorkbenchesImp.cpp" diff --git a/src/Gui/PropertyPage.cpp b/src/Gui/PropertyPage.cpp index 19b7e0916f..704c08cc4a 100644 --- a/src/Gui/PropertyPage.cpp +++ b/src/Gui/PropertyPage.cpp @@ -98,7 +98,7 @@ void PropertyPage::onReset() // ---------------------------------------------------------------- /** Construction */ -PreferencePage::PreferencePage(QWidget* parent) : QWidget(parent), rebootRequired(false) +PreferencePage::PreferencePage(QWidget* parent) : QWidget(parent), restartRequired(false) { } @@ -107,14 +107,14 @@ void PreferencePage::changeEvent(QEvent* event) QWidget::changeEvent(event); } -bool PreferencePage::isRebootRequired() +bool PreferencePage::isRestartRequired() const { - return rebootRequired; + return restartRequired; } -void PreferencePage::requireReboot() +void PreferencePage::requireRestart() { - rebootRequired = true; + restartRequired = true; } diff --git a/src/Gui/PropertyPage.h b/src/Gui/PropertyPage.h index 702aba60bc..5d17f3bf8f 100644 --- a/src/Gui/PropertyPage.h +++ b/src/Gui/PropertyPage.h @@ -73,8 +73,8 @@ public: explicit PreferencePage(QWidget* parent = nullptr); ~PreferencePage() override = default; - bool isRebootRequired(); - void requireReboot(); + bool isRestartRequired() const; + void requireRestart(); public Q_SLOTS: virtual void loadSettings()=0; @@ -84,7 +84,7 @@ protected: void changeEvent(QEvent* event) override = 0; private: - bool rebootRequired; + bool restartRequired; }; /** Subclass that embeds a form from a UI file. From e19e02ce5ca19ba18efb7fd326ee3aff0b212a9f Mon Sep 17 00:00:00 2001 From: Paddle Date: Wed, 29 Mar 2023 11:50:46 +0200 Subject: [PATCH 02/15] Pref: wb: disable none workbench by default. --- src/Gui/DlgSettingsWorkbenchesImp.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Gui/DlgSettingsWorkbenchesImp.cpp b/src/Gui/DlgSettingsWorkbenchesImp.cpp index 334e0e821c..da9a5249e3 100644 --- a/src/Gui/DlgSettingsWorkbenchesImp.cpp +++ b/src/Gui/DlgSettingsWorkbenchesImp.cpp @@ -404,8 +404,9 @@ QStringList DlgSettingsWorkbenchesImp::getEnabledWorkbenches() if (enabled_wbs_list.at(0) == allWorkbenches) { enabled_wbs_list.removeFirst(); QStringList workbenches = Application::Instance->workbenches(); - for (QStringList::Iterator it = workbenches.begin(); it != workbenches.end(); ++it) { - enabled_wbs_list.append(*it); + for(auto& wbName : workbenches) { + if (wbName.toStdString() != "NoneWorkbench") + enabled_wbs_list.append(wbName); } enabled_wbs_list.sort(); } @@ -426,6 +427,9 @@ QStringList DlgSettingsWorkbenchesImp::getDisabledWorkbenches() disabled_wbs_list = disabled_wbs.split(QLatin1String(","), QString::SkipEmptyParts); #endif + if (disabled_wbs_list.isEmpty()) { + disabled_wbs_list.append(QString::fromLatin1("NoneWorkbench")); + } return disabled_wbs_list; } From 9c02b2bc05f1e6a6f265be375bafae87ae2e2598 Mon Sep 17 00:00:00 2001 From: Paddle Date: Wed, 29 Mar 2023 12:03:08 +0200 Subject: [PATCH 03/15] Pref: wb: disable test workbench by default. It still appears and can be activated in the pref page. --- src/Gui/DlgSettingsWorkbenchesImp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Gui/DlgSettingsWorkbenchesImp.cpp b/src/Gui/DlgSettingsWorkbenchesImp.cpp index da9a5249e3..3ae66f577e 100644 --- a/src/Gui/DlgSettingsWorkbenchesImp.cpp +++ b/src/Gui/DlgSettingsWorkbenchesImp.cpp @@ -405,7 +405,7 @@ QStringList DlgSettingsWorkbenchesImp::getEnabledWorkbenches() enabled_wbs_list.removeFirst(); QStringList workbenches = Application::Instance->workbenches(); for(auto& wbName : workbenches) { - if (wbName.toStdString() != "NoneWorkbench") + if (wbName.toStdString() != "NoneWorkbench" && wbName.toStdString() != "TestWorkbench") enabled_wbs_list.append(wbName); } enabled_wbs_list.sort(); @@ -429,6 +429,7 @@ QStringList DlgSettingsWorkbenchesImp::getDisabledWorkbenches() if (disabled_wbs_list.isEmpty()) { disabled_wbs_list.append(QString::fromLatin1("NoneWorkbench")); + disabled_wbs_list.append(QString::fromLatin1("TestWorkbench")); } return disabled_wbs_list; } From 996f4da12323f70bafbefaab874e8314f5ca0626 Mon Sep 17 00:00:00 2001 From: Paddle Date: Wed, 29 Mar 2023 15:54:17 +0200 Subject: [PATCH 04/15] Pref: wb: remove the list of disabled wb. TODO: Addon Manager should add workbenches to the list of enabled wb on installation. And remove them from the list on uninstall. TODO: Addon Manager 'disable mode' should be removed. --- src/Gui/Action.cpp | 27 +++-------- src/Gui/DlgSettingsWorkbenchesImp.cpp | 65 +++++++++++++-------------- src/Gui/DlgSettingsWorkbenchesImp.h | 3 +- 3 files changed, 40 insertions(+), 55 deletions(-) diff --git a/src/Gui/Action.cpp b/src/Gui/Action.cpp index bd0e4113c3..f2289df944 100644 --- a/src/Gui/Action.cpp +++ b/src/Gui/Action.cpp @@ -802,34 +802,21 @@ void WorkbenchGroup::refreshWorkbenchList() { QStringList items = Application::Instance->workbenches(); QStringList enabled_wbs_list = DlgSettingsWorkbenchesImp::getEnabledWorkbenches(); - QStringList disabled_wbs_list = DlgSettingsWorkbenchesImp::getDisabledWorkbenches(); - QStringList enable_wbs; // Go through the list of enabled workbenches and verify that they really exist because // it might be possible that a workbench has been removed after setting up the list of // enabled workbenches. - for (const auto& it : enabled_wbs_list) { - int index = items.indexOf(it); - if (index >= 0) { - enable_wbs << it; - items.removeAt(index); + for (int i = 0; i < enabled_wbs_list.size(); i++) { + if (items.indexOf(enabled_wbs_list[i]) < 0) { + enabled_wbs_list.removeAt(i); + i--; } } - // Filter out the actively disabled workbenches - for (const auto& it : disabled_wbs_list) { - int index = items.indexOf(it); - if (index >= 0) { - items.removeAt(index); - } - } - - // Now add the remaining workbenches of 'items'. They have been added to the application - // after setting up the list of enabled workbenches. - enable_wbs.append(items); + // Resize the action group. QList workbenches = groupAction()->actions(); int numActions = workbenches.size(); - int extend = enable_wbs.size() - numActions; + int extend = enabled_wbs_list.size() - numActions; if (extend > 0) { for (int i=0; iaddAction(QLatin1String("")); @@ -840,7 +827,7 @@ void WorkbenchGroup::refreshWorkbenchList() // Show all enabled wb int index = 0; - for (const auto& it : enable_wbs) { + for (const auto& it : enabled_wbs_list) { setWorkbenchData(index++, it); } } diff --git a/src/Gui/DlgSettingsWorkbenchesImp.cpp b/src/Gui/DlgSettingsWorkbenchesImp.cpp index 3ae66f577e..77fe379957 100644 --- a/src/Gui/DlgSettingsWorkbenchesImp.cpp +++ b/src/Gui/DlgSettingsWorkbenchesImp.cpp @@ -253,7 +253,7 @@ DlgSettingsWorkbenchesImp::~DlgSettingsWorkbenchesImp() void DlgSettingsWorkbenchesImp::saveSettings() { - std::ostringstream enabledStr, disabledStr, autoloadStr; + std::ostringstream enabledStr, autoloadStr; auto addStrToOss = [](std::string wbName, std::ostringstream& oss) { if (!oss.str().empty()) @@ -270,9 +270,6 @@ void DlgSettingsWorkbenchesImp::saveSettings() if (wbItem->isEnabled()) { addStrToOss(wbName, enabledStr); } - else { - addStrToOss(wbName, disabledStr); - } if (wbItem->isAutoLoading()) { addStrToOss(wbName, autoloadStr); @@ -281,13 +278,9 @@ void DlgSettingsWorkbenchesImp::saveSettings() if (enabledStr.str().empty()) //make sure that we have at least one enabled workbench. enabledStr << "NoneWorkbench"; - else { - addStrToOss("NoneWorkbench", disabledStr); //Note, NoneWorkbench is not in the table so it's not added before. - } ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Workbenches"); hGrp->SetASCII("Enabled", enabledStr.str().c_str()); - hGrp->SetASCII("Disabled", disabledStr.str().c_str()); App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General")-> SetASCII("BackgroundAutoloadModules", autoloadStr.str().c_str()); @@ -346,7 +339,6 @@ void DlgSettingsWorkbenchesImp::buildWorkbenchList() workbenches.sort(); //This will sort alphabetically the disabled wb. QStringList enabledWbs = getEnabledWorkbenches(); - QStringList disabledWbs = getDisabledWorkbenches(); //First we add the enabled wbs in their saved order. for (const auto& wbName : enabledWbs) { @@ -357,13 +349,9 @@ void DlgSettingsWorkbenchesImp::buildWorkbenchList() Base::Console().Log("Ignoring unknown %s workbench found in user preferences.\n", wbName.toStdString().c_str()); } } - //Second we add workbench in alphabetical order that are either Disabled, or !enabled && !disabled, ie newly added wb. + //Second we add workbenches that are disabled in alphabetical order. for (const auto& wbName : workbenches) { - if (disabledWbs.contains(wbName)) { - addWorkbench(wbName, false); - } - else if (!enabledWbs.contains(wbName)) { - Base::Console().Log("Adding unknown %s workbench.\n", wbName.toStdString().c_str()); + if (!enabledWbs.contains(wbName) && wbName.toStdString() != "NoneWorkbench") { addWorkbench(wbName, false); } } @@ -371,9 +359,6 @@ void DlgSettingsWorkbenchesImp::buildWorkbenchList() void DlgSettingsWorkbenchesImp::addWorkbench(const QString& wbName, bool enabled) { - if (wbName.toStdString() == "NoneWorkbench") - return; // Do not list the default empty Workbench - bool isStartupWb = wbName.toStdString() == _startupModule; bool autoLoad = std::find(_backgroundAutoloadedModules.begin(), _backgroundAutoloadedModules.end(), wbName.toStdString()) != _backgroundAutoloadedModules.end(); @@ -385,7 +370,6 @@ void DlgSettingsWorkbenchesImp::addWorkbench(const QString& wbName, bool enabled ui->wbList->setItemWidget(wItem, widget); } - QStringList DlgSettingsWorkbenchesImp::getEnabledWorkbenches() { QString enabled_wbs; @@ -413,25 +397,38 @@ QStringList DlgSettingsWorkbenchesImp::getEnabledWorkbenches() return enabled_wbs_list; } -QStringList DlgSettingsWorkbenchesImp::getDisabledWorkbenches() +void DlgSettingsWorkbenchesImp::addToEnabledWorkenches(const QString wbToAddName) { - QString disabled_wbs; - QStringList disabled_wbs_list; - ParameterGrp::handle hGrp; + QStringList enabled_wbs_list = getEnabledWorkbenches(); - hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Workbenches"); - disabled_wbs = QString::fromStdString(hGrp->GetASCII("Disabled", "")); -#if QT_VERSION >= QT_VERSION_CHECK(5,15,0) - disabled_wbs_list = disabled_wbs.split(QLatin1String(","), Qt::SkipEmptyParts); -#else - disabled_wbs_list = disabled_wbs.split(QLatin1String(","), QString::SkipEmptyParts); -#endif + enabled_wbs_list.push_back(wbToAddName); - if (disabled_wbs_list.isEmpty()) { - disabled_wbs_list.append(QString::fromLatin1("NoneWorkbench")); - disabled_wbs_list.append(QString::fromLatin1("TestWorkbench")); + std::ostringstream enabledStr; + for (auto& wbName : enabled_wbs_list) { + if (!enabledStr.str().empty()) + enabledStr << ","; + enabledStr << wbName.toStdString(); } - return disabled_wbs_list; + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Workbenches"); + hGrp->SetASCII("Enabled", enabledStr.str().c_str()); +} + +void DlgSettingsWorkbenchesImp::removeFromEnabledWorkenches(const QString wbToRemoveName) +{ + QStringList enabled_wbs_list = getEnabledWorkbenches(); + + std::ostringstream enabledStr; + for (const auto& wbName : enabled_wbs_list) { + if (wbName != wbToRemoveName) { + if (!enabledStr.str().empty()) + enabledStr << ","; + enabledStr << wbName.toStdString(); + } + } + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Workbenches"); + hGrp->SetASCII("Enabled", enabledStr.str().c_str()); } /** diff --git a/src/Gui/DlgSettingsWorkbenchesImp.h b/src/Gui/DlgSettingsWorkbenchesImp.h index ce91a31034..a0ed157d20 100644 --- a/src/Gui/DlgSettingsWorkbenchesImp.h +++ b/src/Gui/DlgSettingsWorkbenchesImp.h @@ -49,7 +49,8 @@ public: void loadSettings() override; static QStringList getEnabledWorkbenches(); - static QStringList getDisabledWorkbenches(); + static void addToEnabledWorkenches(const QString wbName); + static void removeFromEnabledWorkenches(const QString wbName); protected Q_SLOTS: void wbToggled(const QString& wbName, bool enabled); From 835b96b724cf1d6efe8011feaff3012d3171920d Mon Sep 17 00:00:00 2001 From: Paddle Date: Wed, 29 Mar 2023 16:13:47 +0200 Subject: [PATCH 05/15] Pref: make restartIfRequired() private --- src/Gui/DlgPreferencesImp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Gui/DlgPreferencesImp.h b/src/Gui/DlgPreferencesImp.h index aac9521b0f..f734128d50 100644 --- a/src/Gui/DlgPreferencesImp.h +++ b/src/Gui/DlgPreferencesImp.h @@ -128,7 +128,6 @@ public: void reload(); void activateGroupPage(const QString& group, int index); void activeGroupPage(QString& group, int& index) const; - void restartIfRequired(); protected: void changeEvent(QEvent *e) override; @@ -151,6 +150,7 @@ private: void applyChanges(); void restoreDefaults(); QString longestGroupName() const; + void restartIfRequired(); //@} private: From a2030126668cff9db355a74fd394f5bbef6dae1d Mon Sep 17 00:00:00 2001 From: Paddle Date: Thu, 30 Mar 2023 11:44:14 +0200 Subject: [PATCH 06/15] Addon manager: Subscribe to core the enabled status of addon workbenches. --- src/Mod/AddonManager/Addon.py | 120 ++++++++++++++++++ .../AddonManager/addonmanager_installer.py | 5 + .../AddonManager/addonmanager_uninstaller.py | 5 + 3 files changed, 130 insertions(+) diff --git a/src/Mod/AddonManager/Addon.py b/src/Mod/AddonManager/Addon.py index 8ec366018e..50f0b3dbfe 100644 --- a/src/Mod/AddonManager/Addon.py +++ b/src/Mod/AddonManager/Addon.py @@ -24,6 +24,7 @@ """ Defines the Addon class to encapsulate information about FreeCAD Addons """ import os +import re from urllib.parse import urlparse from typing import Dict, Set, List, Optional from threading import Lock @@ -592,6 +593,9 @@ class Addon: "The existence of this file prevents FreeCAD from loading this Addon. To re-enable, delete the file." ) + if (self.contains_workbench()): + self.disable_workbench() + def enable(self): """Re-enable loading this addon by deleting the stopfile""" @@ -601,6 +605,122 @@ class Addon: except FileNotFoundError: pass + if (self.contains_workbench()): + self.enable_workbench() + + def enable_workbench(self): + pref = fci.ParamGet("User parameter:BaseApp/Workbenches") + enabled_wbs = pref.GetString("Enabled", "All") + #print(f"start enabling : {enabled_wbs}") + + if (enabled_wbs == "All"): + enabled_wbs = ""; + + if fci.FreeCADGui: + wbs = [wb for wb in fci.FreeCADGui.listWorkbenches()] + wbs.sort() + for wbName in wbs: + if (wbName != "NoneWorkbench" and wbName != "TestWorkbench"): + if (enabled_wbs != ""): + enabled_wbs += "," + enabled_wbs += wbName + else: + enabled_wbs += "NoneWorkbench" + + enabled_wbs += "," + enabled_wbs += self.get_workbench_name() + pref.SetString("Enabled", enabled_wbs) + #print(f"Done enabling {enabled_wbs} \n") + + def disable_workbench(self): + pref = fci.ParamGet("User parameter:BaseApp/Workbenches") + enabled_wbs = pref.GetString("Enabled", "All") + #print(f"start disabling {enabled_wbs}") + + if (enabled_wbs == "All"): + enabled_wbs = ""; + + if fci.FreeCADGui: + wbs = [wb for wb in fci.FreeCADGui.listWorkbenches()] + wbs.sort() + for wbName in workbenches: + if (wbName != "NoneWorkbench" and wbName != "TestWorkbench" and wbName != self.get_workbench_name()): + if (enabled_wbs != ""): + enabled_wbs += "," + enabled_wbs += wbName + else: + enabled_wbs += "NoneWorkbench" + else: + enabled_wbs_list = enabled_wbs.split(',') + enabled_wbs = ""; + for wbName in enabled_wbs_list: + if (wbName != self.get_workbench_name()): + if (enabled_wbs != ""): + enabled_wbs += "," + enabled_wbs += wbName + + pref.SetString("Enabled", enabled_wbs) + #print(f"done disabling : {enabled_wbs} \n") + + def get_workbench_name(self) -> str: + """Find the name of the workbench class (ie the name under which it's registered in freecad core)')""" + wb_name = "" + + if self.repo_type == Addon.Kind.PACKAGE: + for wb in self.metadata.content["workbench"]: # we may have more than one wb. + if wb_name != "": + wb_name += "," + wb_name += wb.classname + + if self.repo_type == Addon.Kind.WORKBENCH or wb_name == "": + wb_name = self.try_find_wbname_in_files() + + if wb_name == "": + wb_name = self.name + + return wb_name + + def try_find_wbname_in_files(self) -> str: + wb_name = ""; + filesInDir = [] + + mod_dir = os.path.join(self.mod_directory, self.name) + + for root, subdirs, files in os.walk(mod_dir): + for f in files: + if not os.path.isdir(os.path.join(root, f).replace("\\", "/")): + filesInDir.append(os.path.join(root, f).replace("\\", "/")) + if filesInDir: + for currentfile in filesInDir: + filename, extension = os.path.splitext(currentfile) + if extension == ".py": + #print(f"Current file: {currentfile} ") + try: + with open(os.path.join(root, currentfile), 'r') as f: + content = f.read() + m = re.search('Gui.addWorkbench\((\w+)\(\)\)', content) + if m: + wb_name = m.group(1) + break + except Exception as e: + continue + #print(f"Found name {wb_name} \n") + return wb_name + + + + + + + + + + + + + + + # @dataclass(frozen) class MissingDependencies: diff --git a/src/Mod/AddonManager/addonmanager_installer.py b/src/Mod/AddonManager/addonmanager_installer.py index 18c493344b..90b652b375 100644 --- a/src/Mod/AddonManager/addonmanager_installer.py +++ b/src/Mod/AddonManager/addonmanager_installer.py @@ -153,6 +153,11 @@ class AddonInstaller(QtCore.QObject): success = self._install_by_git() elif method_to_use == InstallationMethod.COPY: success = self._install_by_copy() + if ( + hasattr(self.addon_to_install, "contains_workbench") + and self.addon_to_install.contains_workbench() + ): + self.addon_to_install.enable_workbench() except utils.ProcessInterrupted: pass if success: diff --git a/src/Mod/AddonManager/addonmanager_uninstaller.py b/src/Mod/AddonManager/addonmanager_uninstaller.py index 87e9ac0812..36d0cbd831 100644 --- a/src/Mod/AddonManager/addonmanager_uninstaller.py +++ b/src/Mod/AddonManager/addonmanager_uninstaller.py @@ -113,6 +113,11 @@ class AddonUninstaller(QObject): self.run_uninstall_script(path_to_remove) self.remove_extra_files(path_to_remove) success = utils.rmdir(path_to_remove) + if ( + hasattr(self.addon_to_remove, "contains_workbench") + and self.addon_to_remove.contains_workbench() + ): + self.addon_to_remove.disable_workbench() except OSError as e: error_message = str(e) else: From 4487154c57c544c8bd8e32cc0f574c2318036b72 Mon Sep 17 00:00:00 2001 From: Paddle Date: Thu, 30 Mar 2023 11:46:54 +0200 Subject: [PATCH 07/15] Pref: wb: change parameter group to prevent issues between 0.21 and older versions. --- src/Gui/DlgSettingsWorkbenchesImp.cpp | 8 ++++---- src/Mod/AddonManager/Addon.py | 19 ++----------------- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/src/Gui/DlgSettingsWorkbenchesImp.cpp b/src/Gui/DlgSettingsWorkbenchesImp.cpp index 77fe379957..ffc0064732 100644 --- a/src/Gui/DlgSettingsWorkbenchesImp.cpp +++ b/src/Gui/DlgSettingsWorkbenchesImp.cpp @@ -279,7 +279,7 @@ void DlgSettingsWorkbenchesImp::saveSettings() if (enabledStr.str().empty()) //make sure that we have at least one enabled workbench. enabledStr << "NoneWorkbench"; - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Workbenches"); + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches"); hGrp->SetASCII("Enabled", enabledStr.str().c_str()); App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General")-> @@ -377,7 +377,7 @@ QStringList DlgSettingsWorkbenchesImp::getEnabledWorkbenches() ParameterGrp::handle hGrp; QString allWorkbenches = QString::fromLatin1("ALL"); - hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Workbenches"); + hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches"); enabled_wbs = QString::fromStdString(hGrp->GetASCII("Enabled", allWorkbenches.toStdString().c_str())); #if QT_VERSION >= QT_VERSION_CHECK(5,15,0) enabled_wbs_list = enabled_wbs.split(QLatin1String(","), Qt::SkipEmptyParts); @@ -410,7 +410,7 @@ void DlgSettingsWorkbenchesImp::addToEnabledWorkenches(const QString wbToAddName enabledStr << wbName.toStdString(); } - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Workbenches"); + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches"); hGrp->SetASCII("Enabled", enabledStr.str().c_str()); } @@ -427,7 +427,7 @@ void DlgSettingsWorkbenchesImp::removeFromEnabledWorkenches(const QString wbToRe } } - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Workbenches"); + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches"); hGrp->SetASCII("Enabled", enabledStr.str().c_str()); } diff --git a/src/Mod/AddonManager/Addon.py b/src/Mod/AddonManager/Addon.py index 50f0b3dbfe..6a654ad941 100644 --- a/src/Mod/AddonManager/Addon.py +++ b/src/Mod/AddonManager/Addon.py @@ -609,7 +609,7 @@ class Addon: self.enable_workbench() def enable_workbench(self): - pref = fci.ParamGet("User parameter:BaseApp/Workbenches") + pref = fci.ParamGet("User parameter:BaseApp/Preferences/Workbenches") enabled_wbs = pref.GetString("Enabled", "All") #print(f"start enabling : {enabled_wbs}") @@ -633,7 +633,7 @@ class Addon: #print(f"Done enabling {enabled_wbs} \n") def disable_workbench(self): - pref = fci.ParamGet("User parameter:BaseApp/Workbenches") + pref = fci.ParamGet("User parameter:BaseApp/Preferences/Workbenches") enabled_wbs = pref.GetString("Enabled", "All") #print(f"start disabling {enabled_wbs}") @@ -707,21 +707,6 @@ class Addon: #print(f"Found name {wb_name} \n") return wb_name - - - - - - - - - - - - - - - # @dataclass(frozen) class MissingDependencies: """Encapsulates a group of four types of dependencies: From 4407387ab43f31dab4957fc9b64d588f859ed0dc Mon Sep 17 00:00:00 2001 From: Paddle Date: Fri, 31 Mar 2023 14:12:01 +0200 Subject: [PATCH 08/15] Pref: wb: change to disabled + ordered lists. --- src/Gui/Action.cpp | 11 --- src/Gui/DlgSettingsWorkbenchesImp.cpp | 117 ++++++++++++++------------ src/Gui/DlgSettingsWorkbenchesImp.h | 3 +- 3 files changed, 65 insertions(+), 66 deletions(-) diff --git a/src/Gui/Action.cpp b/src/Gui/Action.cpp index f2289df944..32f5ecb0aa 100644 --- a/src/Gui/Action.cpp +++ b/src/Gui/Action.cpp @@ -800,19 +800,8 @@ void WorkbenchGroup::setWorkbenchData(int index, const QString& wb) void WorkbenchGroup::refreshWorkbenchList() { - QStringList items = Application::Instance->workbenches(); QStringList enabled_wbs_list = DlgSettingsWorkbenchesImp::getEnabledWorkbenches(); - // Go through the list of enabled workbenches and verify that they really exist because - // it might be possible that a workbench has been removed after setting up the list of - // enabled workbenches. - for (int i = 0; i < enabled_wbs_list.size(); i++) { - if (items.indexOf(enabled_wbs_list[i]) < 0) { - enabled_wbs_list.removeAt(i); - i--; - } - } - // Resize the action group. QList workbenches = groupAction()->actions(); int numActions = workbenches.size(); diff --git a/src/Gui/DlgSettingsWorkbenchesImp.cpp b/src/Gui/DlgSettingsWorkbenchesImp.cpp index ffc0064732..c6e5807f33 100644 --- a/src/Gui/DlgSettingsWorkbenchesImp.cpp +++ b/src/Gui/DlgSettingsWorkbenchesImp.cpp @@ -253,7 +253,7 @@ DlgSettingsWorkbenchesImp::~DlgSettingsWorkbenchesImp() void DlgSettingsWorkbenchesImp::saveSettings() { - std::ostringstream enabledStr, autoloadStr; + std::ostringstream orderedStr, disabledStr, autoloadStr; auto addStrToOss = [](std::string wbName, std::ostringstream& oss) { if (!oss.str().empty()) @@ -268,7 +268,10 @@ void DlgSettingsWorkbenchesImp::saveSettings() std::string wbName = wbItem->objectName().toStdString(); if (wbItem->isEnabled()) { - addStrToOss(wbName, enabledStr); + addStrToOss(wbName, orderedStr); + } + else { + addStrToOss(wbName, disabledStr); } if (wbItem->isAutoLoading()) { @@ -276,11 +279,18 @@ void DlgSettingsWorkbenchesImp::saveSettings() } } - if (enabledStr.str().empty()) //make sure that we have at least one enabled workbench. - enabledStr << "NoneWorkbench"; + if (orderedStr.str().empty()) //make sure that we have at least one enabled workbench. This should not be necessary because startup wb cannot be disabled. + orderedStr << "NoneWorkbench"; + else { + if (!disabledStr.str().empty()) + disabledStr << ","; + disabledStr << "NoneWorkbench"; + } + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches"); - hGrp->SetASCII("Enabled", enabledStr.str().c_str()); + hGrp->SetASCII("Ordered", orderedStr.str().c_str()); + hGrp->SetASCII("Disabled", disabledStr.str().c_str()); App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General")-> SetASCII("BackgroundAutoloadModules", autoloadStr.str().c_str()); @@ -335,23 +345,16 @@ void DlgSettingsWorkbenchesImp::buildWorkbenchList() { QSignalBlocker sigblk(ui->wbList); - QStringList workbenches = Application::Instance->workbenches(); - workbenches.sort(); //This will sort alphabetically the disabled wb. - QStringList enabledWbs = getEnabledWorkbenches(); + QStringList disabledWbs = getDisabledWorkbenches(); //First we add the enabled wbs in their saved order. for (const auto& wbName : enabledWbs) { - if (workbenches.contains(wbName)) { - addWorkbench(wbName, true); - } - else { - Base::Console().Log("Ignoring unknown %s workbench found in user preferences.\n", wbName.toStdString().c_str()); - } + addWorkbench(wbName, true); } //Second we add workbenches that are disabled in alphabetical order. - for (const auto& wbName : workbenches) { - if (!enabledWbs.contains(wbName) && wbName.toStdString() != "NoneWorkbench") { + for (const auto& wbName : disabledWbs) { + if (wbName.toStdString() != "NoneWorkbench") { addWorkbench(wbName, false); } } @@ -372,63 +375,71 @@ void DlgSettingsWorkbenchesImp::addWorkbench(const QString& wbName, bool enabled QStringList DlgSettingsWorkbenchesImp::getEnabledWorkbenches() { - QString enabled_wbs; + QStringList disabled_wbs_list = getDisabledWorkbenches(); QStringList enabled_wbs_list; + QStringList wbs_ordered_list; + QString wbs_ordered; ParameterGrp::handle hGrp; - QString allWorkbenches = QString::fromLatin1("ALL"); hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches"); - enabled_wbs = QString::fromStdString(hGrp->GetASCII("Enabled", allWorkbenches.toStdString().c_str())); + wbs_ordered = QString::fromStdString(hGrp->GetASCII("Ordered", "")); #if QT_VERSION >= QT_VERSION_CHECK(5,15,0) - enabled_wbs_list = enabled_wbs.split(QLatin1String(","), Qt::SkipEmptyParts); + wbs_ordered_list = wbs_ordered.split(QLatin1String(","), Qt::SkipEmptyParts); #else - enabled_wbs_list = enabled_wbs.split(QLatin1String(","), QString::SkipEmptyParts); + wbs_ordered_list = wbs_ordered.split(QLatin1String(","), QString::SkipEmptyParts); #endif - if (enabled_wbs_list.at(0) == allWorkbenches) { - enabled_wbs_list.removeFirst(); - QStringList workbenches = Application::Instance->workbenches(); - for(auto& wbName : workbenches) { - if (wbName.toStdString() != "NoneWorkbench" && wbName.toStdString() != "TestWorkbench") - enabled_wbs_list.append(wbName); + QStringList workbenches = Application::Instance->workbenches(); + workbenches.sort(); + + //First we add the wb that are ordered. + for(auto& wbName : wbs_ordered_list) { + if (workbenches.contains(wbName) && !disabled_wbs_list.contains(wbName)) { //Some wb may have been removed + enabled_wbs_list.append(wbName); + } + else { + Base::Console().Log("Ignoring unknown %s workbench found in user preferences.\n", wbName.toStdString().c_str()); } - enabled_wbs_list.sort(); } + + //Then we add the wbs that are not ordered and not disabled in alphabetical order + for(auto& wbName : workbenches) { + if (!enabled_wbs_list.contains(wbName) && !disabled_wbs_list.contains(wbName)) + enabled_wbs_list.append(wbName); + } + return enabled_wbs_list; } -void DlgSettingsWorkbenchesImp::addToEnabledWorkenches(const QString wbToAddName) +QStringList DlgSettingsWorkbenchesImp::getDisabledWorkbenches() { - QStringList enabled_wbs_list = getEnabledWorkbenches(); + QString disabled_wbs; + QStringList unfiltered_disabled_wbs_list; + QStringList disabled_wbs_list; + ParameterGrp::handle hGrp; - enabled_wbs_list.push_back(wbToAddName); + hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches"); + disabled_wbs = QString::fromStdString(hGrp->GetASCII("Disabled", "NoneWorkbench,TestWorkbench")); +#if QT_VERSION >= QT_VERSION_CHECK(5,15,0) + unfiltered_disabled_wbs_list = disabled_wbs.split(QLatin1String(","), Qt::SkipEmptyParts); +#else + unfiltered_disabled_wbs_list = disabled_wbs.split(QLatin1String(","), QString::SkipEmptyParts); +#endif - std::ostringstream enabledStr; - for (auto& wbName : enabled_wbs_list) { - if (!enabledStr.str().empty()) - enabledStr << ","; - enabledStr << wbName.toStdString(); - } + QStringList workbenches = Application::Instance->workbenches(); - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches"); - hGrp->SetASCII("Enabled", enabledStr.str().c_str()); -} - -void DlgSettingsWorkbenchesImp::removeFromEnabledWorkenches(const QString wbToRemoveName) -{ - QStringList enabled_wbs_list = getEnabledWorkbenches(); - - std::ostringstream enabledStr; - for (const auto& wbName : enabled_wbs_list) { - if (wbName != wbToRemoveName) { - if (!enabledStr.str().empty()) - enabledStr << ","; - enabledStr << wbName.toStdString(); + for (auto& wbName : unfiltered_disabled_wbs_list) { + if (workbenches.contains(wbName)) { //Some wb may have been removed + disabled_wbs_list.append(wbName); + } + else { + Base::Console().Log("Ignoring unknown %s workbench found in user preferences.\n", wbName.toStdString().c_str()); } } - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches"); - hGrp->SetASCII("Enabled", enabledStr.str().c_str()); + disabled_wbs_list.sort(); + + return disabled_wbs_list; } /** diff --git a/src/Gui/DlgSettingsWorkbenchesImp.h b/src/Gui/DlgSettingsWorkbenchesImp.h index a0ed157d20..ce91a31034 100644 --- a/src/Gui/DlgSettingsWorkbenchesImp.h +++ b/src/Gui/DlgSettingsWorkbenchesImp.h @@ -49,8 +49,7 @@ public: void loadSettings() override; static QStringList getEnabledWorkbenches(); - static void addToEnabledWorkenches(const QString wbName); - static void removeFromEnabledWorkenches(const QString wbName); + static QStringList getDisabledWorkbenches(); protected Q_SLOTS: void wbToggled(const QString& wbName, bool enabled); From 31c483587aadff5351125ea8bd3bef95d7975d8a Mon Sep 17 00:00:00 2001 From: Paddle Date: Fri, 31 Mar 2023 14:12:19 +0200 Subject: [PATCH 09/15] Addon manager: wb change to ordered + disabled lists. --- src/Mod/AddonManager/Addon.py | 92 +++++++++---------- .../AddonManager/addonmanager_uninstaller.py | 2 +- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/Mod/AddonManager/Addon.py b/src/Mod/AddonManager/Addon.py index 6a654ad941..19562f1661 100644 --- a/src/Mod/AddonManager/Addon.py +++ b/src/Mod/AddonManager/Addon.py @@ -609,58 +609,58 @@ class Addon: self.enable_workbench() def enable_workbench(self): - pref = fci.ParamGet("User parameter:BaseApp/Preferences/Workbenches") - enabled_wbs = pref.GetString("Enabled", "All") - #print(f"start enabling : {enabled_wbs}") - - if (enabled_wbs == "All"): - enabled_wbs = ""; - - if fci.FreeCADGui: - wbs = [wb for wb in fci.FreeCADGui.listWorkbenches()] - wbs.sort() - for wbName in wbs: - if (wbName != "NoneWorkbench" and wbName != "TestWorkbench"): - if (enabled_wbs != ""): - enabled_wbs += "," - enabled_wbs += wbName - else: - enabled_wbs += "NoneWorkbench" - - enabled_wbs += "," - enabled_wbs += self.get_workbench_name() - pref.SetString("Enabled", enabled_wbs) - #print(f"Done enabling {enabled_wbs} \n") + wbName = self.get_workbench_name() + + # Remove from the list of disabled. + self.remove_from_disabled_wbs(wbName) def disable_workbench(self): pref = fci.ParamGet("User parameter:BaseApp/Preferences/Workbenches") - enabled_wbs = pref.GetString("Enabled", "All") - #print(f"start disabling {enabled_wbs}") + wbName = self.get_workbench_name() - if (enabled_wbs == "All"): - enabled_wbs = ""; + # Add the wb to the list of disabled if it was not already + disabled_wbs = pref.GetString("Disabled", "NoneWorkbench,TestWorkbench") + #print(f"start disabling {disabled_wbs}") + disabled_wbs_list = disabled_wbs.split(',') + if not (wbName in disabled_wbs_list): + disabled_wbs += "," + wbName + pref.SetString("Disabled", disabled_wbs) + #print(f"done disabling : {disabled_wbs} \n") - if fci.FreeCADGui: - wbs = [wb for wb in fci.FreeCADGui.listWorkbenches()] - wbs.sort() - for wbName in workbenches: - if (wbName != "NoneWorkbench" and wbName != "TestWorkbench" and wbName != self.get_workbench_name()): - if (enabled_wbs != ""): - enabled_wbs += "," - enabled_wbs += wbName - else: - enabled_wbs += "NoneWorkbench" - else: - enabled_wbs_list = enabled_wbs.split(',') - enabled_wbs = ""; - for wbName in enabled_wbs_list: - if (wbName != self.get_workbench_name()): - if (enabled_wbs != ""): - enabled_wbs += "," - enabled_wbs += wbName + def desinstall_workbench(self): + pref = fci.ParamGet("User parameter:BaseApp/Preferences/Workbenches") + wbName = self.get_workbench_name() - pref.SetString("Enabled", enabled_wbs) - #print(f"done disabling : {enabled_wbs} \n") + # Remove from the list of ordered. + ordered_wbs = pref.GetString("Ordered", "") + #print(f"start remove from ordering {ordered_wbs}") + ordered_wbs_list = ordered_wbs.split(',') + ordered_wbs = "" + for wb in ordered_wbs_list: + if (wb != wbName): + if (ordered_wbs != ""): + ordered_wbs += "," + ordered_wbs += wb + pref.SetString("Ordered", ordered_wbs) + #print(f"end remove from ordering {ordered_wbs}") + + # Remove from the list of disabled. + self.remove_from_disabled_wbs(wbName) + + def remove_from_disabled_wbs(self, wbName: str): + pref = fci.ParamGet("User parameter:BaseApp/Preferences/Workbenches") + + disabled_wbs = pref.GetString("Disabled", "NoneWorkbench,TestWorkbench") + #print(f"start enabling : {disabled_wbs}") + disabled_wbs_list = disabled_wbs.split(',') + disabled_wbs = "" + for wb in disabled_wbs_list: + if (wb != wbName): + if (disabled_wbs != ""): + disabled_wbs += "," + disabled_wbs += wb + pref.SetString("Disabled", disabled_wbs) + #print(f"Done enabling {disabled_wbs} \n") def get_workbench_name(self) -> str: """Find the name of the workbench class (ie the name under which it's registered in freecad core)')""" diff --git a/src/Mod/AddonManager/addonmanager_uninstaller.py b/src/Mod/AddonManager/addonmanager_uninstaller.py index 36d0cbd831..94082753a5 100644 --- a/src/Mod/AddonManager/addonmanager_uninstaller.py +++ b/src/Mod/AddonManager/addonmanager_uninstaller.py @@ -117,7 +117,7 @@ class AddonUninstaller(QObject): hasattr(self.addon_to_remove, "contains_workbench") and self.addon_to_remove.contains_workbench() ): - self.addon_to_remove.disable_workbench() + self.addon_to_remove.desinstall_workbench() except OSError as e: error_message = str(e) else: From 1603720d7a594d7ceee345ec43b8938c220d7c86 Mon Sep 17 00:00:00 2001 From: Paddle Date: Fri, 31 Mar 2023 14:31:55 +0200 Subject: [PATCH 10/15] Addon manager: lint and black. --- src/Mod/AddonManager/Addon.py | 54 ++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/Mod/AddonManager/Addon.py b/src/Mod/AddonManager/Addon.py index 19562f1661..24cba65223 100644 --- a/src/Mod/AddonManager/Addon.py +++ b/src/Mod/AddonManager/Addon.py @@ -610,22 +610,24 @@ class Addon: def enable_workbench(self): wbName = self.get_workbench_name() - + # Remove from the list of disabled. self.remove_from_disabled_wbs(wbName) + def disable_workbench(self): pref = fci.ParamGet("User parameter:BaseApp/Preferences/Workbenches") wbName = self.get_workbench_name() # Add the wb to the list of disabled if it was not already disabled_wbs = pref.GetString("Disabled", "NoneWorkbench,TestWorkbench") - #print(f"start disabling {disabled_wbs}") - disabled_wbs_list = disabled_wbs.split(',') + # print(f"start disabling {disabled_wbs}") + disabled_wbs_list = disabled_wbs.split(",") if not (wbName in disabled_wbs_list): disabled_wbs += "," + wbName pref.SetString("Disabled", disabled_wbs) - #print(f"done disabling : {disabled_wbs} \n") + # print(f"done disabling : {disabled_wbs} \n") + def desinstall_workbench(self): pref = fci.ParamGet("User parameter:BaseApp/Preferences/Workbenches") @@ -633,57 +635,57 @@ class Addon: # Remove from the list of ordered. ordered_wbs = pref.GetString("Ordered", "") - #print(f"start remove from ordering {ordered_wbs}") - ordered_wbs_list = ordered_wbs.split(',') + # print(f"start remove from ordering {ordered_wbs}") + ordered_wbs_list = ordered_wbs.split(",") ordered_wbs = "" for wb in ordered_wbs_list: - if (wb != wbName): - if (ordered_wbs != ""): + if wb != wbName: + if ordered_wbs != "": ordered_wbs += "," ordered_wbs += wb pref.SetString("Ordered", ordered_wbs) - #print(f"end remove from ordering {ordered_wbs}") - + # print(f"end remove from ordering {ordered_wbs}") + # Remove from the list of disabled. self.remove_from_disabled_wbs(wbName) + def remove_from_disabled_wbs(self, wbName: str): pref = fci.ParamGet("User parameter:BaseApp/Preferences/Workbenches") disabled_wbs = pref.GetString("Disabled", "NoneWorkbench,TestWorkbench") - #print(f"start enabling : {disabled_wbs}") - disabled_wbs_list = disabled_wbs.split(',') + # print(f"start enabling : {disabled_wbs}") + disabled_wbs_list = disabled_wbs.split(",") disabled_wbs = "" for wb in disabled_wbs_list: - if (wb != wbName): - if (disabled_wbs != ""): + if wb != wbName: + if disabled_wbs != "": disabled_wbs += "," disabled_wbs += wb pref.SetString("Disabled", disabled_wbs) - #print(f"Done enabling {disabled_wbs} \n") + # print(f"Done enabling {disabled_wbs} \n") + def get_workbench_name(self) -> str: """Find the name of the workbench class (ie the name under which it's registered in freecad core)')""" wb_name = "" - + if self.repo_type == Addon.Kind.PACKAGE: - for wb in self.metadata.content["workbench"]: # we may have more than one wb. + for wb in self.metadata.content["workbench"]: # we may have more than one wb. if wb_name != "": wb_name += "," wb_name += wb.classname - if self.repo_type == Addon.Kind.WORKBENCH or wb_name == "": wb_name = self.try_find_wbname_in_files() - if wb_name == "": wb_name = self.name - return wb_name + def try_find_wbname_in_files(self) -> str: - wb_name = ""; + wb_name = "" filesInDir = [] - + mod_dir = os.path.join(self.mod_directory, self.name) for root, subdirs, files in os.walk(mod_dir): @@ -694,17 +696,17 @@ class Addon: for currentfile in filesInDir: filename, extension = os.path.splitext(currentfile) if extension == ".py": - #print(f"Current file: {currentfile} ") + # print(f"Current file: {currentfile} ") try: - with open(os.path.join(root, currentfile), 'r') as f: + with open(os.path.join(root, currentfile), "r") as f: content = f.read() - m = re.search('Gui.addWorkbench\((\w+)\(\)\)', content) + m = re.search("Gui.addWorkbench\((\w+)\(\)\)", content) if m: wb_name = m.group(1) break except Exception as e: continue - #print(f"Found name {wb_name} \n") + # print(f"Found name {wb_name} \n") return wb_name # @dataclass(frozen) From 184147d5135c0af5dab2ed26612359287f8b1bbc Mon Sep 17 00:00:00 2001 From: Paddle Date: Fri, 31 Mar 2023 14:34:40 +0200 Subject: [PATCH 11/15] DlgPreferencesImp::accept : move restartIfRequired in the if. --- src/Gui/DlgPreferencesImp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Gui/DlgPreferencesImp.cpp b/src/Gui/DlgPreferencesImp.cpp index 7eceaad27f..78030622c5 100644 --- a/src/Gui/DlgPreferencesImp.cpp +++ b/src/Gui/DlgPreferencesImp.cpp @@ -337,10 +337,10 @@ void DlgPreferencesImp::accept() { this->invalidParameter = false; applyChanges(); - if (!this->invalidParameter) + if (!this->invalidParameter) { QDialog::accept(); - - restartIfRequired(); + restartIfRequired(); + } } void DlgPreferencesImp::reject() From d769b9c9f2bac2a3049b956895e77c97f575b663 Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Fri, 31 Mar 2023 09:40:12 -0500 Subject: [PATCH 12/15] Addon Manager: Black and pylint cleanup --- src/Mod/AddonManager/Addon.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/Mod/AddonManager/Addon.py b/src/Mod/AddonManager/Addon.py index 24cba65223..e631f717d9 100644 --- a/src/Mod/AddonManager/Addon.py +++ b/src/Mod/AddonManager/Addon.py @@ -593,7 +593,7 @@ class Addon: "The existence of this file prevents FreeCAD from loading this Addon. To re-enable, delete the file." ) - if (self.contains_workbench()): + if self.contains_workbench(): self.disable_workbench() def enable(self): @@ -605,7 +605,7 @@ class Addon: except FileNotFoundError: pass - if (self.contains_workbench()): + if self.contains_workbench(): self.enable_workbench() def enable_workbench(self): @@ -614,7 +614,6 @@ class Addon: # Remove from the list of disabled. self.remove_from_disabled_wbs(wbName) - def disable_workbench(self): pref = fci.ParamGet("User parameter:BaseApp/Preferences/Workbenches") wbName = self.get_workbench_name() @@ -628,7 +627,6 @@ class Addon: pref.SetString("Disabled", disabled_wbs) # print(f"done disabling : {disabled_wbs} \n") - def desinstall_workbench(self): pref = fci.ParamGet("User parameter:BaseApp/Preferences/Workbenches") wbName = self.get_workbench_name() @@ -649,7 +647,6 @@ class Addon: # Remove from the list of disabled. self.remove_from_disabled_wbs(wbName) - def remove_from_disabled_wbs(self, wbName: str): pref = fci.ParamGet("User parameter:BaseApp/Preferences/Workbenches") @@ -665,13 +662,15 @@ class Addon: pref.SetString("Disabled", disabled_wbs) # print(f"Done enabling {disabled_wbs} \n") - def get_workbench_name(self) -> str: - """Find the name of the workbench class (ie the name under which it's registered in freecad core)')""" + """Find the name of the workbench class (ie the name under which it's + registered in freecad core)'""" wb_name = "" if self.repo_type == Addon.Kind.PACKAGE: - for wb in self.metadata.content["workbench"]: # we may have more than one wb. + for wb in self.metadata.content[ + "workbench" + ]: # we may have more than one wb. if wb_name != "": wb_name += "," wb_name += wb.classname @@ -681,7 +680,6 @@ class Addon: wb_name = self.name return wb_name - def try_find_wbname_in_files(self) -> str: wb_name = "" filesInDir = [] @@ -704,11 +702,12 @@ class Addon: if m: wb_name = m.group(1) break - except Exception as e: + except OSError as e: continue # print(f"Found name {wb_name} \n") return wb_name + # @dataclass(frozen) class MissingDependencies: """Encapsulates a group of four types of dependencies: @@ -771,7 +770,9 @@ class MissingDependencies: translate( "AddonsInstaller", "Got an error when trying to import {}", - ).format(py_dep) + ":\n" + str(e) + ).format(py_dep) + + ":\n" + + str(e) ) self.python_optional = [] @@ -785,7 +786,9 @@ class MissingDependencies: translate( "AddonsInstaller", "Got an error when trying to import {}", - ).format(py_dep) + ":\n" + str(e) + ).format(py_dep) + + ":\n" + + str(e) ) self.wbs.sort() From 6a0decd44a40547a5b310923f129d664c14bfafe Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Fri, 31 Mar 2023 09:40:39 -0500 Subject: [PATCH 13/15] Addon Manager: Tests for classname finder --- .../AddonManagerTest/app/test_addon.py | 98 ++++++++++++++++++- 1 file changed, 93 insertions(+), 5 deletions(-) diff --git a/src/Mod/AddonManager/AddonManagerTest/app/test_addon.py b/src/Mod/AddonManager/AddonManagerTest/app/test_addon.py index 8ba6e8e447..dd5956bcf0 100644 --- a/src/Mod/AddonManager/AddonManagerTest/app/test_addon.py +++ b/src/Mod/AddonManager/AddonManagerTest/app/test_addon.py @@ -20,7 +20,7 @@ # * . * # * * # *************************************************************************** - +import tempfile import unittest import os import sys @@ -32,7 +32,6 @@ from addonmanager_macro import Macro class TestAddon(unittest.TestCase): - MODULE = "test_addon" # file name without extension def setUp(self): @@ -41,7 +40,6 @@ class TestAddon(unittest.TestCase): ) def test_display_name(self): - # Case 1: No display name set elsewhere: name == display_name addon = Addon( "FreeCAD", @@ -84,7 +82,6 @@ class TestAddon(unittest.TestCase): self.assertEqual(expected_tags, tags) def test_contains_functions(self): - # Test package.xml combinations: # Workbenches @@ -201,7 +198,6 @@ class TestAddon(unittest.TestCase): self.assertTrue(addon.__dict__, second_addon.__dict__) def test_dependency_resolution(self): - addonA = Addon( "AddonA", "https://github.com/FreeCAD/FakeAddonA", @@ -303,3 +299,95 @@ class TestAddon(unittest.TestCase): "TagC" in addon.tags, "Found 'TagA' in tags, it should have been excluded by version requirement", ) + + def test_try_find_wbname_in_files_empty_dir(self): + with tempfile.TemporaryDirectory() as mod_dir: + # Arrange + test_addon = Addon("test") + test_addon.mod_directory = mod_dir + os.mkdir(os.path.join(mod_dir, test_addon.name)) + + # Act + wb_name = test_addon.try_find_wbname_in_files() + + # Assert + self.assertEqual(wb_name, "") + + def test_try_find_wbname_in_files_non_python_ignored(self): + with tempfile.TemporaryDirectory() as mod_dir: + # Arrange + test_addon = Addon("test") + test_addon.mod_directory = mod_dir + base_path = os.path.join(mod_dir, test_addon.name) + os.mkdir(base_path) + file_path = os.path.join(base_path, "test.txt") + with open(file_path, "w", encoding="utf-8") as f: + f.write("Gui.addWorkbench(TestWorkbench())") + + # Act + wb_name = test_addon.try_find_wbname_in_files() + + # Assert + self.assertEqual(wb_name, "") + + def test_try_find_wbname_in_files_simple(self): + with tempfile.TemporaryDirectory() as mod_dir: + # Arrange + test_addon = Addon("test") + test_addon.mod_directory = mod_dir + base_path = os.path.join(mod_dir, test_addon.name) + os.mkdir(base_path) + file_path = os.path.join(base_path, "test.py") + with open(file_path, "w", encoding="utf-8") as f: + f.write("Gui.addWorkbench(TestWorkbench())") + + # Act + wb_name = test_addon.try_find_wbname_in_files() + + # Assert + self.assertEqual(wb_name, "TestWorkbench") + + def test_try_find_wbname_in_files_variable_used(self): + with tempfile.TemporaryDirectory() as mod_dir: + # Arrange + test_addon = Addon("test") + test_addon.mod_directory = mod_dir + base_path = os.path.join(mod_dir, test_addon.name) + os.mkdir(base_path) + file_path = os.path.join(base_path, "test.py") + with open(file_path, "w", encoding="utf-8") as f: + f.write("Gui.addWorkbench(wb)") + + # Act + wb_name = test_addon.try_find_wbname_in_files() + + # Assert + self.assertEqual(wb_name, "") + + def test_try_find_wbname_in_files_variants(self): + variants = [ + "Gui.addWorkbench(TestWorkbench())", + "Gui.addWorkbench (TestWorkbench())", + "Gui.addWorkbench( TestWorkbench() )", + "Gui.addWorkbench(TestWorkbench( ))", + "Gui.addWorkbench( TestWorkbench( ) )", + "Gui.addWorkbench( TestWorkbench ( ) )", + "Gui.addWorkbench ( TestWorkbench ( ) )", + ] + for variant in variants: + with self.subTest(variant=variant): + with tempfile.TemporaryDirectory() as mod_dir: + # Arrange + test_addon = Addon("test") + test_addon.mod_directory = mod_dir + base_path = os.path.join(mod_dir, test_addon.name) + os.mkdir(base_path) + file_path = os.path.join(base_path, "test.py") + with open(file_path, "w", encoding="utf-8") as f: + f.write(variant) + + # Act + wb_name = test_addon.try_find_wbname_in_files() + + # Assert + self.assertEqual(wb_name, "TestWorkbench") From e70a360ebe5bce12b1c388cf3b2d036024e306f1 Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Fri, 31 Mar 2023 10:13:47 -0500 Subject: [PATCH 14/15] Addon Manager: Modify regex for whitespace --- src/Mod/AddonManager/Addon.py | 49 +++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/Mod/AddonManager/Addon.py b/src/Mod/AddonManager/Addon.py index e631f717d9..adb896cd27 100644 --- a/src/Mod/AddonManager/Addon.py +++ b/src/Mod/AddonManager/Addon.py @@ -681,31 +681,36 @@ class Addon: return wb_name def try_find_wbname_in_files(self) -> str: - wb_name = "" - filesInDir = [] - + """Attempt to locate a line with an addWorkbench command in the workbench's + Python files. If it is directly instantiating a workbench, then we can use + the line to determine classname for this workbench. If it uses a variable, + or if the line doesn't exist at all, an empty string is returned.""" mod_dir = os.path.join(self.mod_directory, self.name) - for root, subdirs, files in os.walk(mod_dir): + for root, _, files in os.walk(mod_dir): for f in files: - if not os.path.isdir(os.path.join(root, f).replace("\\", "/")): - filesInDir.append(os.path.join(root, f).replace("\\", "/")) - if filesInDir: - for currentfile in filesInDir: - filename, extension = os.path.splitext(currentfile) - if extension == ".py": - # print(f"Current file: {currentfile} ") - try: - with open(os.path.join(root, currentfile), "r") as f: - content = f.read() - m = re.search("Gui.addWorkbench\((\w+)\(\)\)", content) - if m: - wb_name = m.group(1) - break - except OSError as e: - continue - # print(f"Found name {wb_name} \n") - return wb_name + current_file = os.path.join(root, f) + if not os.path.isdir(current_file): + filename, extension = os.path.splitext(current_file) + if extension == ".py": + wb_classname = self._find_classname_in_file(current_file) + print(f"Current file: {current_file} ") + if wb_classname: + print(f"Found name {wb_classname} \n") + return wb_classname + return "" + + @staticmethod + def _find_classname_in_file(current_file) -> str: + try: + with open(current_file, "r", encoding="utf-8") as python_file: + content = python_file.read() + search_result = re.search(r"Gui.addWorkbench\s*\(\s*(\w+)\s*\(\s*\)\s*\)", content) + if search_result: + return search_result.group(1) + except OSError: + pass + return "" # @dataclass(frozen) From fcfcebea0ba8260044bc9670e6603e70a8df5748 Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Fri, 31 Mar 2023 10:21:12 -0500 Subject: [PATCH 15/15] Addon Manager: Add test for subdirectory --- .../AddonManagerTest/app/test_addon.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/Mod/AddonManager/AddonManagerTest/app/test_addon.py b/src/Mod/AddonManager/AddonManagerTest/app/test_addon.py index dd5956bcf0..b7e0ff4149 100644 --- a/src/Mod/AddonManager/AddonManagerTest/app/test_addon.py +++ b/src/Mod/AddonManager/AddonManagerTest/app/test_addon.py @@ -347,6 +347,25 @@ class TestAddon(unittest.TestCase): # Assert self.assertEqual(wb_name, "TestWorkbench") + def test_try_find_wbname_in_files_subdir(self): + with tempfile.TemporaryDirectory() as mod_dir: + # Arrange + test_addon = Addon("test") + test_addon.mod_directory = mod_dir + base_path = os.path.join(mod_dir, test_addon.name) + os.mkdir(base_path) + subdir = os.path.join(base_path, "subdirectory") + os.mkdir(subdir) + file_path = os.path.join(subdir, "test.py") + with open(file_path, "w", encoding="utf-8") as f: + f.write("Gui.addWorkbench(TestWorkbench())") + + # Act + wb_name = test_addon.try_find_wbname_in_files() + + # Assert + self.assertEqual(wb_name, "TestWorkbench") + def test_try_find_wbname_in_files_variable_used(self): with tempfile.TemporaryDirectory() as mod_dir: # Arrange