Related #6097 Qt ignores shortcut of actions in invisible toolbar, but not for actions in a hidden menu action of menu bar, which is likely a Qt bug. The desired behavior should be that of toolbar actions, so that actions belong to different workbenches can have the same shortcut without conflict. This commit works around this inconsistency by ensuring only the active actions are added in menu bar. In addition, all active actions will be added to a zero sized child widget of the main window, which ensures the shortcuts of these actions being active regardless whether the action is in toolbar or menu bar, visible or not.
424 lines
14 KiB
C++
424 lines
14 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2005 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
|
* *
|
|
* This file is part of the FreeCAD CAx development system. *
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Library General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2 of the License, or (at your option) any later version. *
|
|
* *
|
|
* This library is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU Library General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Library General Public *
|
|
* License along with this library; see the file COPYING.LIB. If not, *
|
|
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
|
* Suite 330, Boston, MA 02111-1307, USA *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "PreCompiled.h"
|
|
#ifndef _PreComp_
|
|
# include <QAction>
|
|
# include <QApplication>
|
|
# include <QToolBar>
|
|
# include <QToolButton>
|
|
# include <QPointer>
|
|
#endif
|
|
|
|
#include "ToolBarManager.h"
|
|
#include "Application.h"
|
|
#include "Command.h"
|
|
#include "MainWindow.h"
|
|
|
|
|
|
using namespace Gui;
|
|
|
|
ToolBarItem::ToolBarItem() : forceHide(HideStyle::VISIBLE)
|
|
{
|
|
}
|
|
|
|
ToolBarItem::ToolBarItem(ToolBarItem* item, HideStyle forcehide) : forceHide(forcehide)
|
|
{
|
|
if ( item )
|
|
item->appendItem(this);
|
|
}
|
|
|
|
ToolBarItem::~ToolBarItem()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
void ToolBarItem::setCommand(const std::string& name)
|
|
{
|
|
_name = name;
|
|
}
|
|
|
|
const std::string & ToolBarItem::command() const
|
|
{
|
|
return _name;
|
|
}
|
|
|
|
bool ToolBarItem::hasItems() const
|
|
{
|
|
return _items.count() > 0;
|
|
}
|
|
|
|
ToolBarItem* ToolBarItem::findItem(const std::string& name)
|
|
{
|
|
if ( _name == name ) {
|
|
return this;
|
|
} else {
|
|
for ( QList<ToolBarItem*>::Iterator it = _items.begin(); it != _items.end(); ++it ) {
|
|
if ( (*it)->_name == name ) {
|
|
return *it;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
ToolBarItem* ToolBarItem::copy() const
|
|
{
|
|
auto root = new ToolBarItem;
|
|
root->setCommand( command() );
|
|
|
|
QList<ToolBarItem*> items = getItems();
|
|
for ( QList<ToolBarItem*>::Iterator it = items.begin(); it != items.end(); ++it ) {
|
|
root->appendItem( (*it)->copy() );
|
|
}
|
|
|
|
return root;
|
|
}
|
|
|
|
uint ToolBarItem::count() const
|
|
{
|
|
return _items.count();
|
|
}
|
|
|
|
void ToolBarItem::appendItem(ToolBarItem* item)
|
|
{
|
|
_items.push_back( item );
|
|
}
|
|
|
|
bool ToolBarItem::insertItem( ToolBarItem* before, ToolBarItem* item)
|
|
{
|
|
int pos = _items.indexOf(before);
|
|
if (pos != -1) {
|
|
_items.insert(pos, item);
|
|
return true;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
void ToolBarItem::removeItem(ToolBarItem* item)
|
|
{
|
|
int pos = _items.indexOf(item);
|
|
if (pos != -1)
|
|
_items.removeAt(pos);
|
|
}
|
|
|
|
void ToolBarItem::clear()
|
|
{
|
|
for ( QList<ToolBarItem*>::Iterator it = _items.begin(); it != _items.end(); ++it ) {
|
|
delete *it;
|
|
}
|
|
|
|
_items.clear();
|
|
}
|
|
|
|
ToolBarItem& ToolBarItem::operator << (ToolBarItem* item)
|
|
{
|
|
appendItem(item);
|
|
return *this;
|
|
}
|
|
|
|
ToolBarItem& ToolBarItem::operator << (const std::string& command)
|
|
{
|
|
auto item = new ToolBarItem(this);
|
|
item->setCommand(command);
|
|
return *this;
|
|
}
|
|
|
|
QList<ToolBarItem*> ToolBarItem::getItems() const
|
|
{
|
|
return _items;
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
|
|
ToolBarManager* ToolBarManager::_instance=nullptr;
|
|
|
|
ToolBarManager* ToolBarManager::getInstance()
|
|
{
|
|
if ( !_instance )
|
|
_instance = new ToolBarManager;
|
|
return _instance;
|
|
}
|
|
|
|
void ToolBarManager::destruct()
|
|
{
|
|
delete _instance;
|
|
_instance = nullptr;
|
|
}
|
|
|
|
ToolBarManager::ToolBarManager()
|
|
{
|
|
}
|
|
|
|
ToolBarManager::~ToolBarManager()
|
|
{
|
|
}
|
|
|
|
void ToolBarManager::setup(ToolBarItem* toolBarItems)
|
|
{
|
|
if (!toolBarItems)
|
|
return; // empty menu bar
|
|
|
|
static QPointer<QWidget> _ActionWidget;
|
|
if (!_ActionWidget)
|
|
_ActionWidget = new QWidget(getMainWindow());
|
|
else {
|
|
for (auto action : _ActionWidget->actions())
|
|
_ActionWidget->removeAction(action);
|
|
}
|
|
|
|
saveState();
|
|
this->toolbarNames.clear();
|
|
|
|
int max_width = getMainWindow()->width();
|
|
int top_width = 0;
|
|
|
|
ParameterGrp::handle hPref = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
|
|
->GetGroup("MainWindow")->GetGroup("Toolbars");
|
|
bool nameAsToolTip = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
|
|
->GetGroup("Preferences")->GetGroup("MainWindow")->GetBool("ToolBarNameAsToolTip",true);
|
|
QList<ToolBarItem*> items = toolBarItems->getItems();
|
|
QList<QToolBar*> toolbars = toolBars();
|
|
for (QList<ToolBarItem*>::Iterator it = items.begin(); it != items.end(); ++it) {
|
|
// search for the toolbar
|
|
QString name = QString::fromUtf8((*it)->command().c_str());
|
|
this->toolbarNames << name;
|
|
QToolBar* toolbar = findToolBar(toolbars, name);
|
|
std::string toolbarName = (*it)->command();
|
|
bool toolbar_added = false;
|
|
|
|
if (!toolbar) {
|
|
toolbar = getMainWindow()->addToolBar(
|
|
QApplication::translate("Workbench",
|
|
toolbarName.c_str())); // i18n
|
|
toolbar->setObjectName(name);
|
|
if (nameAsToolTip){
|
|
auto tooltip = QChar::fromLatin1('[')
|
|
+ QApplication::translate("Workbench", toolbarName.c_str())
|
|
+ QChar::fromLatin1(']');
|
|
toolbar->setToolTip(tooltip);
|
|
}
|
|
toolbar_added = true;
|
|
}
|
|
else {
|
|
int index = toolbars.indexOf(toolbar);
|
|
toolbars.removeAt(index);
|
|
}
|
|
|
|
bool visible = hPref->GetBool(toolbarName.c_str(), true) && (*it)->forceHide == ToolBarItem::HideStyle::VISIBLE;
|
|
toolbar->setVisible(visible);
|
|
toolbar->toggleViewAction()->setVisible((*it)->forceHide == ToolBarItem::HideStyle::VISIBLE);
|
|
|
|
// setup the toolbar
|
|
setup(*it, toolbar);
|
|
for (auto action : toolbar->actions())
|
|
_ActionWidget->addAction(action);
|
|
|
|
// try to add some breaks to avoid to have all toolbars in one line
|
|
if (toolbar_added) {
|
|
if (top_width > 0 && getMainWindow()->toolBarBreak(toolbar))
|
|
top_width = 0;
|
|
// the width() of a toolbar doesn't return useful results so we estimate
|
|
// its size by the number of buttons and the icon size
|
|
QList<QToolButton*> btns = toolbar->findChildren<QToolButton*>();
|
|
top_width += (btns.size() * toolbar->iconSize().width());
|
|
if (top_width > max_width) {
|
|
top_width = 0;
|
|
getMainWindow()->insertToolBarBreak(toolbar);
|
|
}
|
|
}
|
|
}
|
|
|
|
// hide all unneeded toolbars
|
|
for (QList<QToolBar*>::Iterator it = toolbars.begin(); it != toolbars.end(); ++it) {
|
|
// make sure that the main window has the focus when hiding the toolbar with
|
|
// the combo box inside
|
|
QWidget *fw = QApplication::focusWidget();
|
|
while (fw && !fw->isWindow()) {
|
|
if (fw == *it) {
|
|
getMainWindow()->setFocus();
|
|
break;
|
|
}
|
|
fw = fw->parentWidget();
|
|
}
|
|
// ignore toolbars which do not belong to the previously active workbench
|
|
QByteArray toolbarName = (*it)->objectName().toUtf8();
|
|
if (!(*it)->toggleViewAction()->isVisible())
|
|
continue;
|
|
//hPref->SetBool(toolbarName.constData(), (*it)->isVisible());
|
|
(*it)->hide();
|
|
(*it)->toggleViewAction()->setVisible(false);
|
|
}
|
|
|
|
hPref = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
|
|
->GetGroup("Preferences")->GetGroup("General");
|
|
bool lockToolBars = hPref->GetBool("LockToolBars", false);
|
|
setMovable(!lockToolBars);
|
|
}
|
|
|
|
void ToolBarManager::setup(ToolBarItem* item, QToolBar* toolbar) const
|
|
{
|
|
CommandManager& mgr = Application::Instance->commandManager();
|
|
QList<ToolBarItem*> items = item->getItems();
|
|
QList<QAction*> actions = toolbar->actions();
|
|
for (QList<ToolBarItem*>::Iterator it = items.begin(); it != items.end(); ++it) {
|
|
// search for the action item
|
|
QAction* action = findAction(actions, QString::fromLatin1((*it)->command().c_str()));
|
|
if (!action) {
|
|
if ((*it)->command() == "Separator") {
|
|
action = toolbar->addSeparator();
|
|
} else {
|
|
// Check if action was added successfully
|
|
if (mgr.addTo((*it)->command().c_str(), toolbar))
|
|
action = toolbar->actions().constLast();
|
|
}
|
|
|
|
// set the tool button user data
|
|
if (action) action->setData(QString::fromLatin1((*it)->command().c_str()));
|
|
} else {
|
|
// Note: For toolbars we do not remove and re-add the actions
|
|
// because this causes flicker effects. So, it could happen that the order of
|
|
// buttons doesn't match with the order of commands in the workbench.
|
|
int index = actions.indexOf(action);
|
|
actions.removeAt(index);
|
|
}
|
|
}
|
|
|
|
// remove all tool buttons which we don't need for the moment
|
|
for (QList<QAction*>::Iterator it = actions.begin(); it != actions.end(); ++it) {
|
|
toolbar->removeAction(*it);
|
|
}
|
|
}
|
|
|
|
void ToolBarManager::saveState() const
|
|
{
|
|
ParameterGrp::handle hPref = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
|
|
->GetGroup("MainWindow")->GetGroup("Toolbars");
|
|
|
|
QList<QToolBar*> toolbars = toolBars();
|
|
for (QStringList::ConstIterator it = this->toolbarNames.begin(); it != this->toolbarNames.end(); ++it) {
|
|
QToolBar* toolbar = findToolBar(toolbars, *it);
|
|
if (toolbar) {
|
|
if (!toolbar->toggleViewAction()->isVisible())
|
|
continue; //if toggleViewAction is not visible it means that the toolbar is forceHide. In which case we do not save settings.
|
|
QByteArray toolbarName = toolbar->objectName().toUtf8();
|
|
hPref->SetBool(toolbarName.constData(), toolbar->isVisible());
|
|
}
|
|
}
|
|
}
|
|
|
|
void ToolBarManager::restoreState() const
|
|
{
|
|
ParameterGrp::handle hPref = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
|
|
->GetGroup("MainWindow")->GetGroup("Toolbars");
|
|
|
|
QList<QToolBar*> toolbars = toolBars();
|
|
for (QStringList::ConstIterator it = this->toolbarNames.begin(); it != this->toolbarNames.end(); ++it) {
|
|
QToolBar* toolbar = findToolBar(toolbars, *it);
|
|
if (toolbar) {
|
|
QByteArray toolbarName = toolbar->objectName().toUtf8();
|
|
toolbar->setVisible(hPref->GetBool(toolbarName.constData(), toolbar->isVisible()));
|
|
}
|
|
}
|
|
|
|
|
|
hPref = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
|
|
->GetGroup("Preferences")->GetGroup("General");
|
|
bool lockToolBars = hPref->GetBool("LockToolBars", false);
|
|
setMovable(!lockToolBars);
|
|
}
|
|
|
|
void ToolBarManager::retranslate() const
|
|
{
|
|
QList<QToolBar*> toolbars = toolBars();
|
|
for (QList<QToolBar*>::Iterator it = toolbars.begin(); it != toolbars.end(); ++it) {
|
|
QByteArray toolbarName = (*it)->objectName().toUtf8();
|
|
(*it)->setWindowTitle(
|
|
QApplication::translate("Workbench",
|
|
(const char*)toolbarName));
|
|
}
|
|
}
|
|
|
|
void Gui::ToolBarManager::setMovable(bool moveable) const
|
|
{
|
|
for (auto& tb : toolBars()) {
|
|
tb->setMovable(moveable);
|
|
}
|
|
}
|
|
|
|
QToolBar* ToolBarManager::findToolBar(const QList<QToolBar*>& toolbars, const QString& item) const
|
|
{
|
|
for (QList<QToolBar*>::ConstIterator it = toolbars.begin(); it != toolbars.end(); ++it) {
|
|
if ((*it)->objectName() == item)
|
|
return *it;
|
|
}
|
|
|
|
return nullptr; // no item with the user data found
|
|
}
|
|
|
|
QAction* ToolBarManager::findAction(const QList<QAction*>& acts, const QString& item) const
|
|
{
|
|
for (QList<QAction*>::ConstIterator it = acts.begin(); it != acts.end(); ++it) {
|
|
if ((*it)->data().toString() == item)
|
|
return *it;
|
|
}
|
|
|
|
return nullptr; // no item with the user data found
|
|
}
|
|
|
|
QList<QToolBar*> ToolBarManager::toolBars() const
|
|
{
|
|
QWidget* mw = getMainWindow();
|
|
QList<QToolBar*> tb;
|
|
QList<QToolBar*> bars = getMainWindow()->findChildren<QToolBar*>();
|
|
for (QList<QToolBar*>::Iterator it = bars.begin(); it != bars.end(); ++it) {
|
|
if ((*it)->parentWidget() == mw)
|
|
tb.push_back(*it);
|
|
}
|
|
|
|
return tb;
|
|
}
|
|
|
|
void ToolBarManager::setToolbarVisibility(bool show, const QList<QString>& names) {
|
|
for (auto& name : names) {
|
|
setToolbarVisibility(show, name);
|
|
}
|
|
}
|
|
|
|
void ToolBarManager::setToolbarVisibility(bool show, const QString& name) {
|
|
|
|
ParameterGrp::handle hPref = App::GetApplication().GetUserParameter().GetGroup("BaseApp")->GetGroup("MainWindow")->GetGroup("Toolbars");
|
|
|
|
QToolBar* tb = findToolBar(toolBars(), name);
|
|
if (tb) {
|
|
if (show) {
|
|
if(hPref->GetBool(name.toStdString().c_str(), true))
|
|
tb->show();
|
|
tb->toggleViewAction()->setVisible(true);
|
|
}
|
|
else {
|
|
tb->hide();
|
|
tb->toggleViewAction()->setVisible(false);
|
|
}
|
|
}
|
|
} |