/*************************************************************************** * Copyright (c) 2004 Werner Mayer * * * * 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 # include # include # include # include # include # include # include # include #endif #include #include #include #include "Action.h" #include "BitmapFactory.h" #include "Command.h" #include "DlgUndoRedo.h" #include "DlgWorkbenchesImp.h" #include "Document.h" #include "EditorView.h" #include "FileDialog.h" #include "Macro.h" #include "MainWindow.h" #include "PythonEditor.h" #include "WhatsThis.h" #include "Widgets.h" #include "Workbench.h" using namespace Gui; using namespace Gui::Dialog; namespace bp = boost::placeholders; /** * Constructs an action called \a name with parent \a parent. It also stores a pointer * to the command object. */ Action::Action (Command* pcCmd, QObject * parent) : QObject(parent), _action(new QAction( this )), _pcCmd(pcCmd) { _action->setObjectName(QString::fromLatin1(_pcCmd->getName())); connect(_action, SIGNAL(triggered(bool)), this, SLOT(onActivated())); } Action::Action (Command* pcCmd, QAction* action, QObject * parent) : QObject(parent), _action(action), _pcCmd(pcCmd) { _action->setParent(this); _action->setObjectName(QString::fromLatin1(_pcCmd->getName())); connect(_action, SIGNAL(triggered(bool)), this, SLOT(onActivated())); } Action::~Action() { delete _action; } /** * Adds this action to widget \a w. */ void Action::addTo(QWidget *w) { w->addAction(_action); } /** * Activates the command. */ void Action::onActivated () { _pcCmd->invoke(0,Command::TriggerAction); } /** * Sets whether the command is toggled. */ void Action::onToggled(bool b) { _pcCmd->invoke( b ? 1 : 0 , Command::TriggerAction); } void Action::setCheckable(bool b) { if(b == _action->isCheckable()) return; _action->setCheckable(b); if (b) { disconnect(_action, SIGNAL(triggered(bool)), this, SLOT(onActivated())); connect(_action, SIGNAL(toggled(bool)), this, SLOT(onToggled(bool))); } else { connect(_action, SIGNAL(triggered(bool)), this, SLOT(onActivated())); disconnect(_action, SIGNAL(toggled(bool)), this, SLOT(onToggled(bool))); } } void Action::setChecked(bool b, bool no_signal) { bool blocked; if(no_signal) blocked = _action->blockSignals(true); _action->setChecked(b); if(no_signal) _action->blockSignals(blocked); } bool Action::isChecked() const { return _action->isChecked(); } /** * Sets whether the action is enabled. */ void Action::setEnabled(bool b) { _action->setEnabled(b); } void Action::setVisible(bool b) { _action->setVisible(b); } void Action::setShortcut(const QString & key) { _action->setShortcut(key); } QKeySequence Action::shortcut() const { return _action->shortcut(); } void Action::setIcon (const QIcon & icon) { _action->setIcon(icon); } QIcon Action::icon () const { return _action->icon(); } void Action::setStatusTip(const QString & s) { _action->setStatusTip(s); } QString Action::statusTip() const { return _action->statusTip(); } void Action::setText(const QString & s) { _action->setText(s); } QString Action::text() const { return _action->text(); } void Action::setToolTip(const QString & s) { _action->setToolTip(s); } QString Action::toolTip() const { return _action->toolTip(); } void Action::setWhatsThis(const QString & s) { _action->setWhatsThis(s); } QString Action::whatsThis() const { return _action->whatsThis(); } void Action::setMenuRole(QAction::MenuRole menuRole) { _action->setMenuRole(menuRole); } // -------------------------------------------------------------------- /** * Constructs an action called \a name with parent \a parent. It also stores a pointer * to the command object. */ ActionGroup::ActionGroup ( Command* pcCmd,QObject * parent) : Action(pcCmd, parent), _group(0), _dropDown(false),_external(false),_toggle(false),_isMode(false) { _group = new QActionGroup(this); connect(_group, SIGNAL(triggered(QAction*)), this, SLOT(onActivated (QAction*))); connect(_group, SIGNAL(hovered(QAction*)), this, SLOT(onHovered(QAction*))); } ActionGroup::~ActionGroup() { delete _group; } /** * Adds this action to widget \a w. */ void ActionGroup::addTo(QWidget *w) { // When adding an action that has defined a menu then shortcuts // of the menu actions don't work. To make this working we must // set the menu explicitly. This means calling QAction::setMenu() // and adding this action to the widget doesn't work. if (_dropDown) { if (w->inherits("QMenu")) { QMenu *menu = new QMenu(w); QAction* action = qobject_cast(w)->addMenu(menu); action->setMenuRole(_action->menuRole()); menu->setTitle(_action->text()); menu->addActions(_group->actions()); } else if (w->inherits("QToolBar")) { w->addAction(_action); QToolButton* tb = w->findChildren().last(); tb->setPopupMode(QToolButton::MenuButtonPopup); tb->setObjectName(QString::fromLatin1("qt_toolbutton_menubutton")); QList acts = _group->actions(); QMenu* menu = new QMenu(tb); menu->addActions(acts); tb->setMenu(menu); //tb->addActions(_group->actions()); } else { w->addActions(_group->actions()); // no drop-down } } else { w->addActions(_group->actions()); } } void ActionGroup::setEnabled( bool b ) { Action::setEnabled(b); _group->setEnabled(b); } void ActionGroup::setDisabled (bool b) { Action::setEnabled(!b); _group->setDisabled(b); } void ActionGroup::setExclusive (bool b) { _group->setExclusive(b); } bool ActionGroup::isExclusive() const { return _group->isExclusive(); } void ActionGroup::setVisible( bool b ) { Action::setVisible(b); _group->setVisible(b); } QAction* ActionGroup::addAction(QAction* action) { int index = _group->actions().size(); action = _group->addAction(action); action->setData(QVariant(index)); return action; } QAction* ActionGroup::addAction(const QString& text) { int index = _group->actions().size(); QAction* action = _group->addAction(text); action->setData(QVariant(index)); return action; } QList ActionGroup::actions() const { return _group->actions(); } int ActionGroup::checkedAction() const { QAction* checked = _group->checkedAction(); return checked ? checked->data().toInt() : -1; } void ActionGroup::setCheckedAction(int i) { QAction* a = _group->actions()[i]; a->setChecked(true); this->setIcon(a->icon()); if (!this->_isMode) this->setToolTip(a->toolTip()); this->setProperty("defaultAction", QVariant(i)); } /** * Activates the command. */ void ActionGroup::onActivated () { _pcCmd->invoke(this->property("defaultAction").toInt(), Command::TriggerAction); } void ActionGroup::onToggled(bool) { onActivated(); } /** * Activates the command. */ void ActionGroup::onActivated (QAction* a) { int index = _group->actions().indexOf(a); // Calling QToolButton::setIcon() etc. has no effect if it has QAction set. // We have to change the QAction icon instead #if 0 QList widgets = a->associatedWidgets(); for (QList::iterator it = widgets.begin(); it != widgets.end(); ++it) { QMenu* menu = qobject_cast(*it); if (menu) { QToolButton* button = qobject_cast(menu->parent()); if (button) { button->setIcon(a->icon()); button->setText(a->text()); button->setToolTip(a->toolTip()); this->setProperty("defaultAction", QVariant(index)); } } } #endif this->setIcon(a->icon()); if (!this->_isMode) this->setToolTip(a->toolTip()); this->setProperty("defaultAction", QVariant(index)); _pcCmd->invoke(index, Command::TriggerChildAction); } void ActionGroup::onHovered (QAction *a) { Gui::ToolTip::showText(QCursor::pos(), a->toolTip()); } // -------------------------------------------------------------------- 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: WorkbenchActionEvent(QAction* a) : QEvent(QEvent::User), act(a) { } ~WorkbenchActionEvent() { } QAction* action() const { return act; } private: QAction* act; }; } WorkbenchComboBox::WorkbenchComboBox(WorkbenchGroup* wb, QWidget* parent) : QComboBox(parent), group(wb) { connect(this, SIGNAL(activated(int)), this, SLOT(onActivated(int))); connect(getMainWindow(), SIGNAL(workbenchActivated(const QString&)), this, SLOT(onWorkbenchActivated(const QString&))); } WorkbenchComboBox::~WorkbenchComboBox() { } void WorkbenchComboBox::showPopup() { int rows = count(); if (rows > 0) { int height = view()->sizeHintForRow(0); int maxHeight = QApplication::primaryScreen()->size().height(); view()->setMinimumHeight(qMin(height * rows, maxHeight/2)); } QComboBox::showPopup(); } void WorkbenchComboBox::actionEvent ( QActionEvent* e ) { QAction *action = e->action(); switch (e->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; } } void WorkbenchComboBox::onActivated(int i) { // Send the event to the workbench group to delay the destruction of the emitting widget. int index = itemData(i).toInt(); WorkbenchActionEvent* ev = new WorkbenchActionEvent(this->actions()[index]); QApplication::postEvent(this->group, ev); // TODO: Test if we can use this instead //QTimer::singleShot(20, this->actions()[i], SLOT(trigger())); } 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 a = actions(); for (QList::Iterator it = a.begin(); it != a.end(); ++it) { if ((*it)->objectName() == name) { if (/*(*it)->data() != item*/!(*it)->isChecked()) (*it)->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 = _group->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)); } WorkbenchGroup::~WorkbenchGroup() { } void WorkbenchGroup::addTo(QWidget *w) { refreshWorkbenchList(); if (w->inherits("QToolBar")) { QToolBar* bar = qobject_cast(w); QComboBox* box = new WorkbenchComboBox(this, w); box->setIconSize(QSize(16, 16)); box->setToolTip(_action->toolTip()); box->setStatusTip(_action->statusTip()); box->setWhatsThis(_action->whatsThis()); box->addActions(_group->actions()); connect(_group, SIGNAL(triggered(QAction*)), box, SLOT(onActivated (QAction*))); bar->addWidget(box); } else if (w->inherits("QMenu")) { QMenu* menu = qobject_cast(w); menu = menu->addMenu(_action->text()); menu->addActions(_group->actions()); } } void WorkbenchGroup::setWorkbenchData(int i, const QString& wb) { QList workbenches = _group->actions(); QString name = Application::Instance->workbenchMenuText(wb); QPixmap px = Application::Instance->workbenchIcon(wb); QString tip = Application::Instance->workbenchToolTip(wb); workbenches[i]->setObjectName(wb); workbenches[i]->setIcon(px); workbenches[i]->setText(name); workbenches[i]->setToolTip(tip); workbenches[i]->setStatusTip(tr("Select the '%1' workbench").arg(name)); workbenches[i]->setVisible(true); if (i < 9) workbenches[i]->setShortcut(QKeySequence(QString::fromUtf8("W,%1").arg(i+1))); } void WorkbenchGroup::refreshWorkbenchList() { QStringList items = Application::Instance->workbenches(); QStringList enabled_wbs_list = DlgWorkbenchesImp::load_enabled_workbenches(); QStringList disabled_wbs_list = DlgWorkbenchesImp::load_disabled_workbenches(); 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 (QStringList::Iterator it = enabled_wbs_list.begin(); it != enabled_wbs_list.end(); ++it) { int index = items.indexOf(*it); if (index >= 0) { enable_wbs << *it; items.removeAt(index); } } // Filter out the actively disabled workbenches for (QStringList::Iterator it = disabled_wbs_list.begin(); it != disabled_wbs_list.end(); ++it) { 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); QList workbenches = _group->actions(); int numActions = workbenches.size(); int extend = enable_wbs.size() - numActions; if (extend > 0) { for (int i=0; iaddAction(QLatin1String("")); action->setCheckable(true); action->setData(QVariant(numActions++)); // set the index } } // Show all enabled wb int index = 0; for (QStringList::Iterator it = enable_wbs.begin(); it != enable_wbs.end(); ++it) { setWorkbenchData(index++, *it); } } void WorkbenchGroup::customEvent( QEvent* e ) { if (e->type() == QEvent::User) { Gui::WorkbenchActionEvent* ce = (Gui::WorkbenchActionEvent*)e; ce->action()->trigger(); } } void WorkbenchGroup::slotActivateWorkbench(const char* /*name*/) { } void WorkbenchGroup::slotAddWorkbench(const char* name) { QList workbenches = _group->actions(); QAction* action = nullptr; for (QList::Iterator it = workbenches.begin(); it != workbenches.end(); ++it) { if (!(*it)->isVisible()) { action = *it; break; } } if (!action) { int index = workbenches.size(); action = _group->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 workbenches = _group->actions(); for (QList::Iterator it = workbenches.begin(); it != workbenches.end(); ++it) { 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 { public: Private(RecentFilesAction *master, const char *path):master(master) { handle = App::GetApplication().GetParameterGroupByPath(path); handle->Attach(this); } virtual ~Private() { handle->Detach(this); } void OnChange(Base::Subject &, const char *reason) { if (!updating && reason && strcmp(reason, "RecentFiles")==0) { Base::StateLocker guard(updating); master->restore(); } } public: RecentFilesAction *master; ParameterGrp::handle handle; bool updating = false; }; // -------------------------------------------------------------------- /* TRANSLATOR Gui::RecentFilesAction */ RecentFilesAction::RecentFilesAction ( Command* pcCmd, QObject * parent ) : ActionGroup( pcCmd, parent ), visibleItems(4), maximumItems(20) { _pimpl.reset(new Private(this, "User parameter:BaseApp/Preferences/RecentFiles")); restore(); } RecentFilesAction::~RecentFilesAction() { } /** Adds the new item to the recent files. */ void RecentFilesAction::appendFile(const QString& filename) { // restore the list of recent files QStringList files = this->files(); // if already inside remove and prepend it files.removeAll(filename); files.prepend(filename); setFiles(files); save(); // update the XML structure and save the user parameter to disk (#0001989) bool saveParameter = App::GetApplication().GetParameterGroupByPath ("User parameter:BaseApp/Preferences/General")->GetBool("SaveUserParameter", true); if (saveParameter) { ParameterManager* parmgr = App::GetApplication().GetParameterSet("User parameter"); parmgr->SaveDocument(App::Application::Config()["UserParameter"].c_str()); } } /** * Set the list of recent files. For each item an action object is * created and added to this action group. */ void RecentFilesAction::setFiles(const QStringList& files) { QList recentFiles = _group->actions(); int numRecentFiles = std::min(recentFiles.count(), files.count()); for (int index = 0; index < numRecentFiles; index++) { QFileInfo fi(files[index]); recentFiles[index]->setText(QString::fromLatin1("%1 %2").arg(index+1).arg(fi.fileName())); recentFiles[index]->setStatusTip(tr("Open file %1").arg(files[index])); recentFiles[index]->setToolTip(files[index]); // set the full name that we need later for saving recentFiles[index]->setData(QVariant(index)); recentFiles[index]->setVisible(true); } // if less file names than actions numRecentFiles = std::min(numRecentFiles, this->visibleItems); for (int index = numRecentFiles; index < recentFiles.count(); index++) { recentFiles[index]->setVisible(false); recentFiles[index]->setText(QString()); recentFiles[index]->setToolTip(QString()); } } /** * Returns the list of defined recent files. */ QStringList RecentFilesAction::files() const { QStringList files; QList recentFiles = _group->actions(); for (int index = 0; index < recentFiles.count(); index++) { QString file = recentFiles[index]->toolTip(); if (file.isEmpty()) break; files.append(file); } return files; } void RecentFilesAction::activateFile(int id) { // restore the list of recent files QStringList files = this->files(); if (id < 0 || id >= files.count()) return; // no valid item QString filename = files[id]; QFileInfo fi(filename); if (!fi.exists() || !fi.isFile()) { QMessageBox::critical(getMainWindow(), tr("File not found"), tr("The file '%1' cannot be opened.").arg(filename)); files.removeAll(filename); setFiles(files); } else { // invokes appendFile() SelectModule::Dict dict = SelectModule::importHandler(filename); for (SelectModule::Dict::iterator it = dict.begin(); it != dict.end(); ++it) { Application::Instance->open(it.key().toUtf8(), it.value().toLatin1()); break; } } } void RecentFilesAction::resizeList(int size) { this->visibleItems = size; int diff = this->visibleItems - this->maximumItems; // create new items if needed for (int i=0; iaddAction(QLatin1String(""))->setVisible(false); setFiles(files()); } /** Loads all recent files from the preferences. */ void RecentFilesAction::restore() { ParameterGrp::handle hGrp = _pimpl->handle; // we want at least 20 items but we do only show the number of files // that is defined in user parameters this->visibleItems = hGrp->GetInt("RecentFiles", this->visibleItems); int count = std::max(this->maximumItems, this->visibleItems); for (int i=0; iaddAction(QLatin1String(""))->setVisible(false); std::vector MRU = hGrp->GetASCIIs("MRU"); QStringList files; for (std::vector::iterator it = MRU.begin(); it!=MRU.end();++it) files.append(QString::fromUtf8(it->c_str())); setFiles(files); } /** Saves all recent files to the preferences. */ void RecentFilesAction::save() { ParameterGrp::handle hGrp = _pimpl->handle; int count = hGrp->GetInt("RecentFiles", this->visibleItems); // save number of files hGrp->Clear(); // count all set items QList recentFiles = _group->actions(); int num = std::min(count, recentFiles.count()); for (int index = 0; index < num; index++) { QString key = QString::fromLatin1("MRU%1").arg(index); QString value = recentFiles[index]->toolTip(); if (value.isEmpty()) break; hGrp->SetASCII(key.toLatin1(), value.toUtf8()); } Base::StateLocker guard(_pimpl->updating); hGrp->SetInt("RecentFiles", count); // restore } // -------------------------------------------------------------------- /* TRANSLATOR Gui::RecentMacrosAction */ RecentMacrosAction::RecentMacrosAction ( Command* pcCmd, QObject * parent ) : ActionGroup( pcCmd, parent ), visibleItems(4), maximumItems(20) { restore(); } RecentMacrosAction::~RecentMacrosAction() { } /** Adds the new item to the recent files. */ void RecentMacrosAction::appendFile(const QString& filename) { // restore the list of recent files QStringList files = this->files(); // if already inside remove and prepend it files.removeAll(filename); files.prepend(filename); setFiles(files); save(); // update the XML structure and save the user parameter to disk (#0001989) bool saveParameter = App::GetApplication().GetParameterGroupByPath ("User parameter:BaseApp/Preferences/General")->GetBool("SaveUserParameter", true); if (saveParameter) { ParameterManager* parmgr = App::GetApplication().GetParameterSet("User parameter"); parmgr->SaveDocument(App::Application::Config()["UserParameter"].c_str()); } } /** * Set the list of recent macro files. For each item an action object is * created and added to this action group. */ void RecentMacrosAction::setFiles(const QStringList& files) { ParameterGrp::handle hGrp = App::GetApplication().GetUserParameter().GetGroup("BaseApp") ->GetGroup("Preferences")->GetGroup("RecentMacros"); this->shortcut_modifiers = hGrp->GetASCII("ShortcutModifiers","Ctrl+Shift+"); this->shortcut_count = std::min(hGrp->GetInt("ShortcutCount",3),9);//max = 9, e.g. Ctrl+Shift+9 this->visibleItems = hGrp->GetInt("RecentMacros",12); QList recentFiles = _group->actions(); int numRecentFiles = std::min(recentFiles.count(), files.count()); for (int index = 0; index < numRecentFiles; index++) { QFileInfo fi(files[index]); QString accel = QString::fromStdString(shortcut_modifiers); accel.append(QString::number(index+1,10)).toStdString(); recentFiles[index]->setText(QString::fromLatin1("%1 %2").arg(index+1).arg(fi.baseName())); recentFiles[index]->setStatusTip(tr("Run macro %1 (Shift+click to edit) shortcut: %2").arg(files[index]).arg(accel)); recentFiles[index]->setToolTip(files[index]); // set the full name that we need later for saving recentFiles[index]->setData(QVariant(index)); if (index < shortcut_count){ recentFiles[index]->setShortcut(accel); } recentFiles[index]->setVisible(true); } // if less file names than actions numRecentFiles = std::min(numRecentFiles, this->visibleItems); for (int index = numRecentFiles; index < recentFiles.count(); index++) { recentFiles[index]->setVisible(false); recentFiles[index]->setText(QString()); recentFiles[index]->setToolTip(QString()); } } /** * Returns the list of defined recent files. */ QStringList RecentMacrosAction::files() const { QStringList files; QList recentFiles = _group->actions(); for (int index = 0; index < recentFiles.count(); index++) { QString file = recentFiles[index]->toolTip(); if (file.isEmpty()) break; files.append(file); } return files; } void RecentMacrosAction::activateFile(int id) { // restore the list of recent files QStringList files = this->files(); if (id < 0 || id >= files.count()) return; // no valid item QString filename = files[id]; QFileInfo fi(filename); if (!fi.exists() || !fi.isFile()) { QMessageBox::critical(getMainWindow(), tr("File not found"), tr("The file '%1' cannot be opened.").arg(filename)); files.removeAll(filename); setFiles(files); } else { if (QApplication::keyboardModifiers() == Qt::ShiftModifier){ //open for editing on Shift+click PythonEditor* editor = new PythonEditor(); editor->setWindowIcon(Gui::BitmapFactory().iconFromTheme("applications-python")); PythonEditorView* edit = new PythonEditorView(editor, getMainWindow()); edit->setDisplayName(PythonEditorView::FileName); edit->open(filename); edit->resize(400, 300); getMainWindow()->addWindow(edit); getMainWindow()->appendRecentMacro(filename); edit->setWindowTitle(fi.fileName()); } else { //execute macro on normal (non-shifted) click try { getMainWindow()->appendRecentMacro(fi.filePath()); Application::Instance->macroManager()->run(Gui::MacroManager::File, fi.filePath().toUtf8()); // after macro run recalculate the document if (Application::Instance->activeDocument()) Application::Instance->activeDocument()->getDocument()->recompute(); } catch (const Base::SystemExitException&) { // handle SystemExit exceptions Base::PyGILStateLocker locker; Base::PyException e; e.ReportException(); } } } } void RecentMacrosAction::resizeList(int size) { this->visibleItems = size; int diff = this->visibleItems - this->maximumItems; // create new items if needed for (int i=0; iaddAction(QLatin1String(""))->setVisible(false); setFiles(files()); } /** Loads all recent files from the preferences. */ void RecentMacrosAction::restore() { ParameterGrp::handle hGrp = App::GetApplication().GetUserParameter().GetGroup("BaseApp")->GetGroup("Preferences"); if (hGrp->HasGroup("RecentMacros")) { hGrp = hGrp->GetGroup("RecentMacros"); // we want at least 20 items but we do only show the number of files // that is defined in user parameters this->visibleItems = hGrp->GetInt("RecentMacros", this->visibleItems); this->shortcut_count = hGrp->GetInt("ShortcutCount", 3); // number of shortcuts this->shortcut_modifiers = hGrp->GetASCII("ShortcutModifiers","Ctrl+Shift+"); } int count = std::max(this->maximumItems, this->visibleItems); for (int i=_group->actions().size(); iaddAction(QLatin1String(""))->setVisible(false); std::vector MRU = hGrp->GetASCIIs("MRU"); QStringList files; for (std::vector::iterator it = MRU.begin(); it!=MRU.end();++it) files.append(QString::fromUtf8(it->c_str())); setFiles(files); } /** Saves all recent files to the preferences. */ void RecentMacrosAction::save() { ParameterGrp::handle hGrp = App::GetApplication().GetUserParameter().GetGroup("BaseApp") ->GetGroup("Preferences")->GetGroup("RecentMacros"); int count = hGrp->GetInt("RecentMacros", this->visibleItems); // save number of files hGrp->Clear(); // count all set items QList recentFiles = _group->actions(); int num = std::min(count, recentFiles.count()); for (int index = 0; index < num; index++) { QString key = QString::fromLatin1("MRU%1").arg(index); QString value = recentFiles[index]->toolTip(); if (value.isEmpty()) break; hGrp->SetASCII(key.toLatin1(), value.toUtf8()); } hGrp->SetInt("RecentMacros", count); // restore hGrp->SetInt("ShortcutCount", this->shortcut_count); hGrp->SetASCII("ShortcutModifiers",this->shortcut_modifiers.c_str()); } // -------------------------------------------------------------------- UndoAction::UndoAction (Command* pcCmd,QObject * parent) : Action(pcCmd, parent) { _toolAction = new QAction(this); _toolAction->setMenu(new UndoDialog()); connect(_toolAction, SIGNAL(triggered(bool)), this, SLOT(onActivated())); } UndoAction::~UndoAction() { QMenu* menu = _toolAction->menu(); delete menu; delete _toolAction; } void UndoAction::addTo (QWidget * w) { if (w->inherits("QToolBar")) { actionChanged(); connect(_action, SIGNAL(changed()), this, SLOT(actionChanged())); w->addAction(_toolAction); } else { w->addAction(_action); } } void UndoAction::actionChanged() { // Do NOT set the shortcut again for _toolAction since this is already // reserved for _action. Otherwise we get an ambiguity of it with the // result that it doesn't work anymore. _toolAction->setText(_action->text()); _toolAction->setToolTip(_action->toolTip()); _toolAction->setStatusTip(_action->statusTip()); _toolAction->setWhatsThis(_action->whatsThis()); _toolAction->setIcon(_action->icon()); } void UndoAction::setEnabled(bool b) { Action::setEnabled(b); _toolAction->setEnabled(b); } void UndoAction::setVisible(bool b) { Action::setVisible(b); _toolAction->setVisible(b); } // -------------------------------------------------------------------- RedoAction::RedoAction ( Command* pcCmd,QObject * parent ) : Action(pcCmd, parent) { _toolAction = new QAction(this); _toolAction->setMenu(new RedoDialog()); connect(_toolAction, SIGNAL(triggered(bool)), this, SLOT(onActivated())); } RedoAction::~RedoAction() { QMenu* menu = _toolAction->menu(); delete menu; delete _toolAction; } void RedoAction::addTo ( QWidget * w ) { if (w->inherits("QToolBar")) { actionChanged(); connect(_action, SIGNAL(changed()), this, SLOT(actionChanged())); w->addAction(_toolAction); } else { w->addAction(_action); } } void RedoAction::actionChanged() { // Do NOT set the shortcut again for _toolAction since this is already // reserved for _action. Otherwise we get an ambiguity of it with the // result that it doesn't work anymore. _toolAction->setText(_action->text()); _toolAction->setToolTip(_action->toolTip()); _toolAction->setStatusTip(_action->statusTip()); _toolAction->setWhatsThis(_action->whatsThis()); _toolAction->setIcon(_action->icon()); } void RedoAction::setEnabled ( bool b ) { Action::setEnabled(b); _toolAction->setEnabled(b); } void RedoAction::setVisible ( bool b ) { Action::setVisible(b); _toolAction->setVisible(b); } // -------------------------------------------------------------------- DockWidgetAction::DockWidgetAction ( Command* pcCmd, QObject * parent ) : Action(pcCmd, parent), _menu(0) { } DockWidgetAction::~DockWidgetAction() { delete _menu; } void DockWidgetAction::addTo ( QWidget * w ) { if (!_menu) { _menu = new QMenu(); _action->setMenu(_menu); connect(_menu, SIGNAL(aboutToShow()), getMainWindow(), SLOT(onDockWindowMenuAboutToShow())); } w->addAction(_action); } // -------------------------------------------------------------------- ToolBarAction::ToolBarAction ( Command* pcCmd, QObject * parent ) : Action(pcCmd, parent), _menu(0) { } ToolBarAction::~ToolBarAction() { delete _menu; } void ToolBarAction::addTo ( QWidget * w ) { if (!_menu) { _menu = new QMenu(); _action->setMenu(_menu); connect(_menu, SIGNAL(aboutToShow()), getMainWindow(), SLOT(onToolBarMenuAboutToShow())); } w->addAction(_action); } // -------------------------------------------------------------------- WindowAction::WindowAction ( Command* pcCmd, QObject * parent ) : ActionGroup(pcCmd, parent), _menu(0) { } WindowAction::~WindowAction() { } void WindowAction::addTo ( QWidget * w ) { QMenu* menu = qobject_cast(w); if (!menu) { if (!_menu) { _menu = new QMenu(); _action->setMenu(_menu); _menu->addActions(_group->actions()); connect(_menu, SIGNAL(aboutToShow()), getMainWindow(), SLOT(onWindowsMenuAboutToShow())); } w->addAction(_action); } else { menu->addActions(_group->actions()); connect(menu, SIGNAL(aboutToShow()), getMainWindow(), SLOT(onWindowsMenuAboutToShow())); } } #include "moc_Action.cpp"