Merge pull request #9534 from Ondsel-Development/fix_wb_index_issue

Core: rework WorkbenchGroup & WorkbenchComboBox
This commit is contained in:
sliptonic
2023-06-19 10:27:40 -05:00
committed by GitHub
5 changed files with 124 additions and 261 deletions

View File

@@ -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
WorkbenchComboBox::WorkbenchComboBox(QWidget* parent) : QComboBox(parent)
{
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<int>(&WorkbenchComboBox::activated),
this, qOverload<int>(&WorkbenchComboBox::onActivated));
connect(getMainWindow(), &MainWindow::workbenchActivated,
this, &WorkbenchComboBox::onWorkbenchActivated);
}
void WorkbenchComboBox::showPopup()
@@ -644,71 +619,122 @@ void WorkbenchComboBox::showPopup()
QComboBox::showPopup();
}
void WorkbenchComboBox::actionEvent ( QActionEvent* qae )
void WorkbenchComboBox::refreshList(QList<QAction*> 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;
clear();
for (QAction* action : actionList) {
QIcon icon = action->icon();
if (icon.isNull()) {
this->addItem(action->text());
}
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;
else {
this->addItem(icon, action->text());
}
case QEvent::ActionRemoved:
{
//Nothing needs to be done
break;
if (action->isChecked()) {
this->setCurrentIndex(this->count() - 1);
}
default:
break;
}
}
void WorkbenchComboBox::onActivated(int item)
/* TRANSLATOR Gui::WorkbenchGroup */
WorkbenchGroup::WorkbenchGroup ( Command* pcCmd, QObject * parent )
: ActionGroup( pcCmd, parent )
{
// 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);
refreshWorkbenchList();
Application::Instance->signalRefreshWorkbenches.connect(boost::bind(&WorkbenchGroup::refreshWorkbenchList, this));
connect(getMainWindow(), &MainWindow::workbenchActivated,
this, &WorkbenchGroup::onWorkbenchActivated);
}
void WorkbenchComboBox::onActivated(QAction* action)
void WorkbenchGroup::addTo(QWidget *widget)
{
// set the according item to the action
QVariant data = action->data();
int index = this->findData(data);
setCurrentIndex(index);
auto setupBox = [&](WorkbenchComboBox* box) {
box->setIconSize(QSize(16, 16));
box->setToolTip(toolTip());
box->setStatusTip(action()->statusTip());
box->setWhatsThis(action()->whatsThis());
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<int>(&WorkbenchComboBox::activated), this, [this](int index) {
actions()[index]->trigger();
});
};
if (widget->inherits("QToolBar")) {
auto* box = new WorkbenchComboBox(widget);
setupBox(box);
qobject_cast<QToolBar*>(widget)->addWidget(box);
}
else if (widget->inherits("QMenuBar")) {
auto* box = new WorkbenchComboBox(widget);
setupBox(box);
bool left = WorkbenchSwitcher::isLeftCorner(WorkbenchSwitcher::getValue());
qobject_cast<QMenuBar*>(widget)->setCornerWidget(box, left ? Qt::TopLeftCorner : Qt::TopRightCorner);
}
else if (widget->inherits("QMenu")) {
auto menu = qobject_cast<QMenu*>(widget);
menu = menu->addMenu(action()->text());
menu->addActions(actions());
connect(this, &WorkbenchGroup::workbenchListRefreshed, this, [menu](QList<QAction*> actions) {
menu->clear();
menu->addActions(actions);
});
}
}
void WorkbenchComboBox::onWorkbenchActivated(const QString& name)
void WorkbenchGroup::refreshWorkbenchList()
{
QStringList enabled_wbs_list = DlgSettingsWorkbenchesImp::getEnabledWorkbenches();
// Clear the actions.
for (QAction* action : actions()) {
groupAction()->removeAction(action);
delete action;
}
std::string activeWbName = "";
Workbench* activeWB = WorkbenchManager::instance()->active();
if (activeWB)
activeWbName = activeWB->name();
// Create action list of enabled wb
int index = 0;
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);
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() == activeWbName) {
action->setChecked(true);
}
index++;
}
// Signal to the widgets (WorkbenchComboBox & menu) to update the wb list
workbenchListRefreshed(actions());
}
void WorkbenchGroup::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
@@ -720,166 +746,17 @@ void WorkbenchComboBox::onWorkbenchActivated(const QString& name)
// activateWorkbench the method refreshWorkbenchList() shouldn't set the
// checked item.
//QVariant item = itemData(currentIndex());
QList<QAction*> act = actions();
for (QList<QAction*>::Iterator it = act.begin(); it != act.end(); ++it) {
if ((*it)->objectName() == name) {
if (/*(*it)->data() != item*/!(*it)->isChecked()) {
(*it)->trigger();
for (QAction* action : actions()) {
if (action->objectName() == name) {
if (!action->isChecked()) {
action->trigger();
}
break;
}
}
}
/* TRANSLATOR Gui::WorkbenchGroup */
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
}
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));
}
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<QAction*>(&WorkbenchComboBox::onActivated));
};
if (widget->inherits("QToolBar")) {
auto* box = new WorkbenchComboBox(this, widget);
setupBox(box);
qobject_cast<QToolBar*>(widget)->addWidget(box);
}
else if (widget->inherits("QMenuBar")) {
auto* box = new WorkbenchComboBox(this, widget);
setupBox(box);
bool left = WorkbenchSwitcher::isLeftCorner(WorkbenchSwitcher::getValue());
qobject_cast<QMenuBar*>(widget)->setCornerWidget(box, left ? Qt::TopLeftCorner : Qt::TopRightCorner);
}
else if (widget->inherits("QMenu")) {
auto menu = qobject_cast<QMenu*>(widget);
menu = menu->addMenu(action()->text());
menu->addActions(groupAction()->actions());
}
}
void WorkbenchGroup::setWorkbenchData(int index, const QString& wb)
{
QList<QAction*> 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)));
}
}
void WorkbenchGroup::refreshWorkbenchList()
{
QStringList enabled_wbs_list = DlgSettingsWorkbenchesImp::getEnabledWorkbenches();
// Resize the action group.
QList<QAction*> workbenches = groupAction()->actions();
int numActions = workbenches.size();
int extend = enabled_wbs_list.size() - numActions;
if (extend > 0) {
for (int i=0; i<extend; i++) {
QAction* action = groupAction()->addAction(QLatin1String(""));
action->setCheckable(true);
action->setData(QVariant(numActions++)); // set the index
}
}
// Show all enabled wb
int index = 0;
for (const auto& it : enabled_wbs_list) {
setWorkbenchData(index++, it);
}
}
void WorkbenchGroup::customEvent( QEvent* event )
{
if (event->type() == QEvent::User) {
auto ce = static_cast<Gui::WorkbenchActionEvent*>(event);
ce->action()->trigger();
}
}
void WorkbenchGroup::slotActivateWorkbench(const char* /*name*/)
{
}
void WorkbenchGroup::slotAddWorkbench(const char* name)
{
QList<QAction*> 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(""));
action->setCheckable(true);
action->setData(QVariant(index)); // set the 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
}
void WorkbenchGroup::slotRemoveWorkbench(const char* name)
{
QString workbench = QString::fromLatin1(name);
QList<QAction*> 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
break;
}
}
}
// --------------------------------------------------------------------
class RecentFilesAction::Private: public ParameterGrp::ObserverType

View File

@@ -177,29 +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 onActivated(int);
void onActivated(QAction*);
protected Q_SLOTS:
void onWorkbenchActivated(const QString&);
protected:
void actionEvent (QActionEvent*) override;
void refreshList(QList<QAction*>);
private:
WorkbenchGroup* group;
Q_DISABLE_COPY(WorkbenchComboBox)
};
@@ -222,15 +211,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<QAction*>);
protected Q_SLOTS:
void onWorkbenchActivated(const QString&);
private:
void setWorkbenchData(int index, const QString& wb);
Q_DISABLE_COPY(WorkbenchGroup)
};

View File

@@ -126,10 +126,8 @@ public:
boost::signals2::signal<void (const Gui::ViewProvider&)> signalActivatedObject;
/// signal on activated workbench
boost::signals2::signal<void (const char*)> signalActivateWorkbench;
/// signal on added workbench
boost::signals2::signal<void (const char*)> signalAddWorkbench;
/// signal on removed workbench
boost::signals2::signal<void (const char*)> signalRemoveWorkbench;
/// signal on added/removed workbench
boost::signals2::signal<void ()> signalRefreshWorkbenches;
/// signal on show hidden items
boost::signals2::signal<void (const Gui::Document&)> signalShowHidden;
/// signal on activating view

View File

@@ -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;
}

View File

@@ -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<wbListItem*>(ui->wbList->itemWidget(ui->wbList->item(i)));
if (wbItem) {