From f3d5b204d21b711996c918b1a465b280fd61a4e0 Mon Sep 17 00:00:00 2001 From: Paddle Date: Wed, 10 May 2023 10:46:48 +0200 Subject: [PATCH 1/3] Core: WorkbenchComboBox and WorkbenchGroup simplification. --- src/Gui/Action.cpp | 274 ++++++++++---------------------------- src/Gui/Action.h | 20 +-- src/Gui/Application.h | 6 +- src/Gui/ApplicationPy.cpp | 4 +- 4 files changed, 84 insertions(+), 220 deletions(-) diff --git a/src/Gui/Action.cpp b/src/Gui/Action.cpp index 32f5ecb0aa..fa85f145d6 100644 --- a/src/Gui/Action.cpp +++ b/src/Gui/Action.cpp @@ -59,6 +59,7 @@ #include "WhatsThis.h" #include "Widgets.h" #include "Workbench.h" +#include "WorkbenchManager.h" #include "ShortcutManager.h" #include "Tools.h" @@ -602,34 +603,8 @@ void ActionGroup::onHovered (QAction *act) // -------------------------------------------------------------------- -namespace Gui { - -/** - * The WorkbenchActionEvent class is used to send an event of which workbench must be activated. - * We cannot activate the workbench directly as we will destroy the widget that emits the signal. - * @author Werner Mayer - */ -class WorkbenchActionEvent : public QEvent -{ -public: - explicit WorkbenchActionEvent(QAction* act) - : QEvent(QEvent::User), act(act) - { } - QAction* action() const - { return act; } -private: - QAction* act; - - Q_DISABLE_COPY(WorkbenchActionEvent) -}; -} - WorkbenchComboBox::WorkbenchComboBox(WorkbenchGroup* wb, QWidget* parent) : QComboBox(parent), group(wb) { - connect(this, qOverload(&WorkbenchComboBox::activated), - this, qOverload(&WorkbenchComboBox::onActivated)); - connect(getMainWindow(), &MainWindow::workbenchActivated, - this, &WorkbenchComboBox::onWorkbenchActivated); } void WorkbenchComboBox::showPopup() @@ -644,89 +619,21 @@ void WorkbenchComboBox::showPopup() QComboBox::showPopup(); } -void WorkbenchComboBox::actionEvent ( QActionEvent* qae ) +void WorkbenchComboBox::refreshList(QList actionList) { - QAction *action = qae->action(); - switch (qae->type()) { - case QEvent::ActionAdded: - { - if (action->isVisible()) { - QIcon icon = action->icon(); - if (icon.isNull()) { - this->addItem(action->text(), action->data()); - } - else { - this->addItem(icon, action->text(), action->data()); - } - if (action->isChecked()) { - this->setCurrentIndex(action->data().toInt()); - } - } - break; - } - case QEvent::ActionChanged: - { - QVariant data = action->data(); - int index = this->findData(data); - // added a workbench - if (index < 0 && action->isVisible()) { - QIcon icon = action->icon(); - if (icon.isNull()) - this->addItem(action->text(), data); - else - this->addItem(icon, action->text(), data); - } - // removed a workbench - else if (index >=0 && !action->isVisible()) { - this->removeItem(index); - } - break; - } - case QEvent::ActionRemoved: - { - //Nothing needs to be done - break; - } - default: - break; - } -} + clear(); -void WorkbenchComboBox::onActivated(int item) -{ - // Send the event to the workbench group to delay the destruction of the emitting widget. - int index = itemData(item).toInt(); - auto ev = new WorkbenchActionEvent(this->actions().at(index)); - QApplication::postEvent(this->group, ev); -} + for (QAction* action : actionList) { + QIcon icon = action->icon(); + if (icon.isNull()) { + this->addItem(action->text()); + } + else { + this->addItem(icon, action->text()); + } -void WorkbenchComboBox::onActivated(QAction* action) -{ - // set the according item to the action - QVariant data = action->data(); - int index = this->findData(data); - setCurrentIndex(index); -} - -void WorkbenchComboBox::onWorkbenchActivated(const QString& name) -{ - // There might be more than only one instance of WorkbenchComboBox there. - // However, all of them share the same QAction objects. Thus, if the user - // has selected one it also gets checked. Then Application::activateWorkbench - // also invokes this slot method by calling the signal workbenchActivated in - // MainWindow. If calling activateWorkbench() from within the Python console - // the matching action must be set by calling this function. - // To avoid to recursively (but only one recursion level) call Application:: - // activateWorkbench the method refreshWorkbenchList() shouldn't set the - // checked item. - //QVariant item = itemData(currentIndex()); - QList act = actions(); - for (QList::Iterator it = act.begin(); it != act.end(); ++it) { - if ((*it)->objectName() == name) { - if (/*(*it)->data() != item*/!(*it)->isChecked()) { - (*it)->trigger(); - } - break; + if (action->isChecked()) { + this->setCurrentIndex(this->count() - 1); } } } @@ -735,30 +642,29 @@ void WorkbenchComboBox::onWorkbenchActivated(const QString& name) WorkbenchGroup::WorkbenchGroup ( Command* pcCmd, QObject * parent ) : ActionGroup( pcCmd, parent ) { - // Start a list with 50 elements but extend it when requested - for (int i=0; i<50; i++) { - QAction* action = groupAction()->addAction(QLatin1String("")); - action->setVisible(false); - action->setCheckable(true); - action->setData(QVariant(i)); // set the index - } + refreshWorkbenchList(); - Application::Instance->signalActivateWorkbench.connect(boost::bind(&WorkbenchGroup::slotActivateWorkbench, this, bp::_1)); - Application::Instance->signalAddWorkbench.connect(boost::bind(&WorkbenchGroup::slotAddWorkbench, this, bp::_1)); - Application::Instance->signalRemoveWorkbench.connect(boost::bind(&WorkbenchGroup::slotRemoveWorkbench, this, bp::_1)); + Application::Instance->signalRefreshWorkbenches.connect(boost::bind(&WorkbenchGroup::refreshWorkbenchList, this)); + + connect(getMainWindow(), &MainWindow::workbenchActivated, + this, &WorkbenchGroup::onWorkbenchActivated); } void WorkbenchGroup::addTo(QWidget *widget) { - refreshWorkbenchList(); - auto setupBox = [&](WorkbenchComboBox* box) { box->setIconSize(QSize(16, 16)); box->setToolTip(toolTip()); box->setStatusTip(action()->statusTip()); box->setWhatsThis(action()->whatsThis()); - box->addActions(groupAction()->actions()); - connect(groupAction(), &QActionGroup::triggered, box, qOverload(&WorkbenchComboBox::onActivated)); + box->refreshList(actions()); + connect(this, &WorkbenchGroup::workbenchListRefreshed, box, &WorkbenchComboBox::refreshList); + connect(groupAction(), &QActionGroup::triggered, box, [this, box](QAction* action) { + box->setCurrentIndex(actions().indexOf(action)); + }); + connect(box, qOverload(&WorkbenchComboBox::activated), this, [this](int index) { + actions()[index]->trigger(); + }); }; if (widget->inherits("QToolBar")) { auto* box = new WorkbenchComboBox(this, widget); @@ -776,25 +682,12 @@ void WorkbenchGroup::addTo(QWidget *widget) else if (widget->inherits("QMenu")) { auto menu = qobject_cast(widget); menu = menu->addMenu(action()->text()); - menu->addActions(groupAction()->actions()); - } -} + menu->addActions(actions()); -void WorkbenchGroup::setWorkbenchData(int index, const QString& wb) -{ - QList workbenches = groupAction()->actions(); - QString name = Application::Instance->workbenchMenuText(wb); - QPixmap px = Application::Instance->workbenchIcon(wb); - QString tip = Application::Instance->workbenchToolTip(wb); - - workbenches[index]->setObjectName(wb); - workbenches[index]->setIcon(px); - workbenches[index]->setText(name); - workbenches[index]->setToolTip(tip); - workbenches[index]->setStatusTip(tr("Select the '%1' workbench").arg(name)); - workbenches[index]->setVisible(true); - if (index < 9) { - workbenches[index]->setShortcut(QKeySequence(QString::fromUtf8("W,%1").arg(index+1))); + connect(this, &WorkbenchGroup::workbenchListRefreshed, this, [this, menu](QList actions) { + menu->clear(); + menu->addActions(actions); + }); } } @@ -802,79 +695,60 @@ void WorkbenchGroup::refreshWorkbenchList() { QStringList enabled_wbs_list = DlgSettingsWorkbenchesImp::getEnabledWorkbenches(); - // Resize the action group. - QList workbenches = groupAction()->actions(); - int numActions = workbenches.size(); - int extend = enabled_wbs_list.size() - numActions; - if (extend > 0) { - for (int i=0; iaddAction(QLatin1String("")); - action->setCheckable(true); - action->setData(QVariant(numActions++)); // set the index - } + // Clear the actions. + for (QAction* action : actions()) { + groupAction()->removeAction(action); + delete action; } - // Show all enabled wb + Workbench* activeWB = WorkbenchManager::instance()->active(); + + // Create action list of enabled wb int index = 0; - for (const auto& it : enabled_wbs_list) { - setWorkbenchData(index++, it); - } -} + for (const auto& wbName : enabled_wbs_list) { + QString name = Application::Instance->workbenchMenuText(wbName); + QPixmap px = Application::Instance->workbenchIcon(wbName); + QString tip = Application::Instance->workbenchToolTip(wbName); -void WorkbenchGroup::customEvent( QEvent* event ) -{ - if (event->type() == QEvent::User) { - auto ce = static_cast(event); - ce->action()->trigger(); - } -} - -void WorkbenchGroup::slotActivateWorkbench(const char* /*name*/) -{ -} - -void WorkbenchGroup::slotAddWorkbench(const char* name) -{ - QList workbenches = groupAction()->actions(); - QAction* action = nullptr; - for (auto it : workbenches) { - if (!it->isVisible()) { - action = it; - break; - } - } - - if (!action) { - int index = workbenches.size(); - action = groupAction()->addAction(QLatin1String("")); + QAction* action = groupAction()->addAction(name); action->setCheckable(true); action->setData(QVariant(index)); // set the index + action->setObjectName(wbName); + action->setIcon(px); + action->setToolTip(tip); + action->setStatusTip(tr("Select the '%1' workbench").arg(name)); + if (index < 9) { + action->setShortcut(QKeySequence(QString::fromUtf8("W,%1").arg(index + 1))); + } + if (wbName.toStdString() == activeWB->name()) { + action->setChecked(true); + } + + index++; } - QString wb = QString::fromLatin1(name); - QPixmap px = Application::Instance->workbenchIcon(wb); - QString text = Application::Instance->workbenchMenuText(wb); - QString tip = Application::Instance->workbenchToolTip(wb); - action->setIcon(px); - action->setObjectName(wb); - action->setText(text); - action->setToolTip(tip); - action->setStatusTip(tr("Select the '%1' workbench").arg(wb)); - action->setVisible(true); // do this at last + // Signal to the widgets (WorkbenchComboBox & menu) to update the wb list + workbenchListRefreshed(actions()); } -void WorkbenchGroup::slotRemoveWorkbench(const char* name) +void WorkbenchGroup::onWorkbenchActivated(const QString& name) { - QString workbench = QString::fromLatin1(name); - QList workbenches = groupAction()->actions(); - for (auto it : workbenches) { - if (it->objectName() == workbench) { - it->setObjectName(QString()); - it->setIcon(QIcon()); - it->setText(QString()); - it->setToolTip(QString()); - it->setStatusTip(QString()); - it->setVisible(false); // do this at last + // There might be more than only one instance of WorkbenchComboBox there. + // However, all of them share the same QAction objects. Thus, if the user + // has selected one it also gets checked. Then Application::activateWorkbench + // also invokes this slot method by calling the signal workbenchActivated in + // MainWindow. If calling activateWorkbench() from within the Python console + // the matching action must be set by calling this function. + // To avoid to recursively (but only one recursion level) call Application:: + // activateWorkbench the method refreshWorkbenchList() shouldn't set the + // checked item. + //QVariant item = itemData(currentIndex()); + + for (QAction* action : actions()) { + if (action->objectName() == name) { + if (!action->isChecked()) { + action->trigger(); + } break; } } diff --git a/src/Gui/Action.h b/src/Gui/Action.h index 684a653cfc..06c00ac610 100644 --- a/src/Gui/Action.h +++ b/src/Gui/Action.h @@ -188,14 +188,7 @@ public: void showPopup() override; public Q_SLOTS: - void onActivated(int); - void onActivated(QAction*); - -protected Q_SLOTS: - void onWorkbenchActivated(const QString&); - -protected: - void actionEvent (QActionEvent*) override; + void refreshList(QList); private: WorkbenchGroup* group; @@ -222,15 +215,14 @@ public: void refreshWorkbenchList(); void slotActivateWorkbench(const char*); - void slotAddWorkbench(const char*); - void slotRemoveWorkbench(const char*); -protected: - void customEvent(QEvent* event) override; +Q_SIGNALS: + void workbenchListRefreshed(QList); + +protected Q_SLOTS: + void onWorkbenchActivated(const QString&); private: - void setWorkbenchData(int index, const QString& wb); - Q_DISABLE_COPY(WorkbenchGroup) }; diff --git a/src/Gui/Application.h b/src/Gui/Application.h index ba2b46601b..4ce5701f97 100644 --- a/src/Gui/Application.h +++ b/src/Gui/Application.h @@ -126,10 +126,8 @@ public: boost::signals2::signal signalActivatedObject; /// signal on activated workbench boost::signals2::signal signalActivateWorkbench; - /// signal on added workbench - boost::signals2::signal signalAddWorkbench; - /// signal on removed workbench - boost::signals2::signal signalRemoveWorkbench; + /// signal on added/removed workbench + boost::signals2::signal signalRefreshWorkbenches; /// signal on show hidden items boost::signals2::signal signalShowHidden; /// signal on activating view diff --git a/src/Gui/ApplicationPy.cpp b/src/Gui/ApplicationPy.cpp index 82154fc7f3..d9a43af0bf 100644 --- a/src/Gui/ApplicationPy.cpp +++ b/src/Gui/ApplicationPy.cpp @@ -976,7 +976,7 @@ PyObject* Application::sAddWorkbenchHandler(PyObject * /*self*/, PyObject *args) } PyDict_SetItemString(Instance->_pcWorkbenchDictionary,item.c_str(),object.ptr()); - Instance->signalAddWorkbench(item.c_str()); + Instance->signalRefreshWorkbenches(); } catch (const Py::Exception&) { return nullptr; @@ -997,9 +997,9 @@ PyObject* Application::sRemoveWorkbenchHandler(PyObject * /*self*/, PyObject *ar return nullptr; } - Instance->signalRemoveWorkbench(psKey); WorkbenchManager::instance()->removeWorkbench(psKey); PyDict_DelItemString(Instance->_pcWorkbenchDictionary,psKey); + Instance->signalRefreshWorkbenches(); Py_Return; } From d238eb313d79f6742a996c5618c6abef38a5cf05 Mon Sep 17 00:00:00 2001 From: Paddle Date: Wed, 10 May 2023 10:47:13 +0200 Subject: [PATCH 2/3] Pref: Wb: remove the need to restart on wb activation and order change. --- src/Gui/DlgSettingsWorkbenchesImp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Gui/DlgSettingsWorkbenchesImp.cpp b/src/Gui/DlgSettingsWorkbenchesImp.cpp index 84269b6a18..aea9e7b60c 100644 --- a/src/Gui/DlgSettingsWorkbenchesImp.cpp +++ b/src/Gui/DlgSettingsWorkbenchesImp.cpp @@ -293,6 +293,9 @@ void DlgSettingsWorkbenchesImp::saveSettings() hGrp->SetASCII("Ordered", orderedStr.str().c_str()); hGrp->SetASCII("Disabled", disabledStr.str().c_str()); + //Update the list of workbenches in the WorkbenchGroup and in the WorkbenchComboBox & workbench QMenu + Application::Instance->signalRefreshWorkbenches(); + App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General")-> SetASCII("BackgroundAutoloadModules", autoloadStr.str().c_str()); @@ -477,8 +480,6 @@ void DlgSettingsWorkbenchesImp::loadWorkbenchSelector() void DlgSettingsWorkbenchesImp::wbToggled(const QString& wbName, bool enabled) { - requireRestart(); - setStartWorkbenchComboItems(); //reorder the list of items. @@ -551,7 +552,6 @@ void DlgSettingsWorkbenchesImp::setStartWorkbenchComboItems() void DlgSettingsWorkbenchesImp::wbItemMoved() { - requireRestart(); for (int i = 0; i < ui->wbList->count(); i++) { wbListItem* wbItem = dynamic_cast(ui->wbList->itemWidget(ui->wbList->item(i))); if (wbItem) { From c3c5f491ef62fad70169bfc59f7f717ce9dac959 Mon Sep 17 00:00:00 2001 From: Paddle Date: Mon, 22 May 2023 15:21:40 +0200 Subject: [PATCH 3/3] Wb group fixes --- src/Gui/Action.cpp | 13 ++++++++----- src/Gui/Action.h | 6 +----- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/Gui/Action.cpp b/src/Gui/Action.cpp index fa85f145d6..3105ad1ca7 100644 --- a/src/Gui/Action.cpp +++ b/src/Gui/Action.cpp @@ -603,7 +603,7 @@ void ActionGroup::onHovered (QAction *act) // -------------------------------------------------------------------- -WorkbenchComboBox::WorkbenchComboBox(WorkbenchGroup* wb, QWidget* parent) : QComboBox(parent), group(wb) +WorkbenchComboBox::WorkbenchComboBox(QWidget* parent) : QComboBox(parent) { } @@ -667,13 +667,13 @@ void WorkbenchGroup::addTo(QWidget *widget) }); }; if (widget->inherits("QToolBar")) { - auto* box = new WorkbenchComboBox(this, widget); + auto* box = new WorkbenchComboBox(widget); setupBox(box); qobject_cast(widget)->addWidget(box); } else if (widget->inherits("QMenuBar")) { - auto* box = new WorkbenchComboBox(this, widget); + auto* box = new WorkbenchComboBox(widget); setupBox(box); bool left = WorkbenchSwitcher::isLeftCorner(WorkbenchSwitcher::getValue()); @@ -684,7 +684,7 @@ void WorkbenchGroup::addTo(QWidget *widget) menu = menu->addMenu(action()->text()); menu->addActions(actions()); - connect(this, &WorkbenchGroup::workbenchListRefreshed, this, [this, menu](QList actions) { + connect(this, &WorkbenchGroup::workbenchListRefreshed, this, [menu](QList actions) { menu->clear(); menu->addActions(actions); }); @@ -701,7 +701,10 @@ void WorkbenchGroup::refreshWorkbenchList() delete action; } + std::string activeWbName = ""; Workbench* activeWB = WorkbenchManager::instance()->active(); + if (activeWB) + activeWbName = activeWB->name(); // Create action list of enabled wb int index = 0; @@ -720,7 +723,7 @@ void WorkbenchGroup::refreshWorkbenchList() if (index < 9) { action->setShortcut(QKeySequence(QString::fromUtf8("W,%1").arg(index + 1))); } - if (wbName.toStdString() == activeWB->name()) { + if (wbName.toStdString() == activeWbName) { action->setChecked(true); } diff --git a/src/Gui/Action.h b/src/Gui/Action.h index 06c00ac610..4be36fa8e7 100644 --- a/src/Gui/Action.h +++ b/src/Gui/Action.h @@ -177,22 +177,18 @@ private: }; // -------------------------------------------------------------------- - -class WorkbenchGroup; class GuiExport WorkbenchComboBox : public QComboBox { Q_OBJECT public: - explicit WorkbenchComboBox(WorkbenchGroup* wb, QWidget* parent=nullptr); + explicit WorkbenchComboBox(QWidget* parent=nullptr); void showPopup() override; public Q_SLOTS: void refreshList(QList); private: - WorkbenchGroup* group; - Q_DISABLE_COPY(WorkbenchComboBox) };