diff --git a/src/Gui/Action.cpp b/src/Gui/Action.cpp index 38bae0cf59..f388e9ee91 100644 --- a/src/Gui/Action.cpp +++ b/src/Gui/Action.cpp @@ -44,11 +44,16 @@ #include #include "Action.h" #include "Application.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" @@ -818,6 +823,195 @@ void RecentFilesAction::save() // -------------------------------------------------------------------- +/* 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 = tr(QString::fromLatin1(shortcut_modifiers.c_str())\ + .append(QString::number(index+1,10)).toStdString().c_str()); + 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=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 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) { diff --git a/src/Gui/Action.h b/src/Gui/Action.h index bf72a7f44e..5429db732a 100644 --- a/src/Gui/Action.h +++ b/src/Gui/Action.h @@ -210,6 +210,38 @@ private: int maximumItems; /**< Number of maximum items */ }; +// -------------------------------------------------------------------- + +/** + * The RecentMacrosAction class holds a menu listed with the recent macros + * that were executed, edited, or created + */ +class GuiExport RecentMacrosAction : public ActionGroup +{ + Q_OBJECT + +public: + RecentMacrosAction (Command* pcCmd, QObject * parent = 0); + virtual ~RecentMacrosAction(); + + void appendFile(const QString&); + void activateFile(int); + void resizeList(int); + +private: + void setFiles(const QStringList&); + QStringList files() const; + void restore(); + void save(); + +private: + int visibleItems; /**< Number of visible items */ + int maximumItems; /**< Number of maximum items */ + std::string shortcut_modifiers; /**< default = "Ctrl+Shift+" */ + int shortcut_count; /**< Number of dynamic shortcuts to create -- default = 3*/ +}; + + // -------------------------------------------------------------------- /** diff --git a/src/Gui/CommandStd.cpp b/src/Gui/CommandStd.cpp index 3e77ddfe6d..ce1bee3d27 100644 --- a/src/Gui/CommandStd.cpp +++ b/src/Gui/CommandStd.cpp @@ -172,6 +172,46 @@ Action * StdCmdRecentFiles::createAction(void) return pcAction; } +//=========================================================================== +// Std_RecentMacros +//=========================================================================== + +DEF_STD_CMD_C(StdCmdRecentMacros) + +StdCmdRecentMacros::StdCmdRecentMacros() + :Command("Std_RecentMacros") +{ + sGroup = QT_TR_NOOP("Macro"); + sMenuText = QT_TR_NOOP("Recent macros"); + sToolTipText = QT_TR_NOOP("Recent macro list"); + sWhatsThis = "Std_RecentMacros"; + sStatusTip = QT_TR_NOOP("Recent macro list"); + eType = NoTransaction; +} + +/** + * Opens the recent macro at position \a iMsg in the menu. + * If the macro does not exist or cannot be loaded this item is removed + * from the list. + */ +void StdCmdRecentMacros::activated(int iMsg) +{ + RecentMacrosAction* act = qobject_cast(_pcAction); + if (act) act->activateFile( iMsg ); +} + +/** + * Creates the QAction object containing the recent macros. + */ +Action * StdCmdRecentMacros::createAction(void) +{ + RecentMacrosAction* pcAction = new RecentMacrosAction(this, getMainWindow()); + pcAction->setObjectName(QLatin1String("recentMacros")); + pcAction->setDropDownMenu(true); + applyCommandData(this->className(), pcAction); + return pcAction; +} + //=========================================================================== // Std_About //=========================================================================== @@ -766,6 +806,7 @@ void CreateStdCommands(void) rcCmdMgr.addCommand(new StdCmdCommandLine()); rcCmdMgr.addCommand(new StdCmdWorkbench()); rcCmdMgr.addCommand(new StdCmdRecentFiles()); + rcCmdMgr.addCommand(new StdCmdRecentMacros()); rcCmdMgr.addCommand(new StdCmdWhatsThis()); rcCmdMgr.addCommand(new StdCmdPythonHelp()); rcCmdMgr.addCommand(new StdCmdOnlineHelp()); diff --git a/src/Gui/DlgMacroExecuteImp.cpp b/src/Gui/DlgMacroExecuteImp.cpp index 95870d03b6..7e7607768c 100644 --- a/src/Gui/DlgMacroExecuteImp.cpp +++ b/src/Gui/DlgMacroExecuteImp.cpp @@ -274,6 +274,7 @@ void DlgMacroExecuteImp::accept() QFileInfo fi(dir, item->text(0)); 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()) @@ -334,6 +335,7 @@ void DlgMacroExecuteImp::on_editButton_clicked() edit->open(file); edit->resize(400, 300); getMainWindow()->addWindow(edit); + getMainWindow()->appendRecentMacro(file); if (mitem->systemWide) { editor->setReadOnly(true); @@ -341,7 +343,6 @@ void DlgMacroExecuteImp::on_editButton_clicked() shownName = QString::fromLatin1("%1[*] - [%2]").arg(item->text(0), tr("Read-only")); edit->setWindowTitle(shownName); } - close(); } @@ -380,6 +381,7 @@ void DlgMacroExecuteImp::on_createButton_clicked() editor->setWindowIcon(Gui::BitmapFactory().iconFromTheme("applications-python")); PythonEditorView* edit = new PythonEditorView(editor, getMainWindow()); edit->open(fi.absoluteFilePath()); + getMainWindow()->appendRecentMacro(fi.absoluteFilePath()); edit->setWindowTitle(QString::fromLatin1("%1[*]").arg(fn)); edit->resize(400, 300); getMainWindow()->addWindow(edit); diff --git a/src/Gui/DlgSettingsMacro.ui b/src/Gui/DlgSettingsMacro.ui index b840c608ad..6c03a55f40 100644 --- a/src/Gui/DlgSettingsMacro.ui +++ b/src/Gui/DlgSettingsMacro.ui @@ -48,25 +48,21 @@ Macro recording settings - + + 9 + + + 9 + + + 9 + + 9 6 - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -76,7 +72,16 @@ 6 - + + 11 + + + 11 + + + 11 + + 11 @@ -112,8 +117,8 @@ - - + + FullScript.FCScript @@ -133,7 +138,16 @@ Gui commands - + + 11 + + + 11 + + + 11 + + 11 @@ -186,20 +200,26 @@ Macro path - + + 11 + + + 11 + + + 11 + + 11 6 - + The directory in which the application will search for macros - - Gui::FileChooser::Directory - MacroPath @@ -214,10 +234,152 @@ + + + + Recent macros menu + + + + + + Size of recent macro list + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + How many macros should be listed in recent macros list + + + 12 + + + RecentMacros + + + RecentMacros + + + + + + + Shortcut count + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + How many recent macros should have shortcuts + + + 3 + + + ShortcutCount + + + RecentMacros + + + + + + + Keyboard Modifiers + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Keyboard modifiers, default = Ctrl+Shift+ + + + ShortcutModifiers + + + RecentMacros + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + Gui::PrefLineEdit + QLineEdit +
Gui/PrefWidgets.h
+
+ + Gui::PrefSpinBox + QSpinBox +
Gui/PrefWidgets.h
+
+ + Gui::PrefCheckBox + QCheckBox +
Gui/PrefWidgets.h
+
Gui::FileChooser QWidget @@ -228,11 +390,6 @@ Gui::FileChooser
Gui/PrefWidgets.h
- - Gui::PrefCheckBox - QCheckBox -
Gui/PrefWidgets.h
-
diff --git a/src/Gui/DlgSettingsMacroImp.cpp b/src/Gui/DlgSettingsMacroImp.cpp index 1ee3b887fb..5f2548cf8e 100644 --- a/src/Gui/DlgSettingsMacroImp.cpp +++ b/src/Gui/DlgSettingsMacroImp.cpp @@ -22,10 +22,11 @@ #include "PreCompiled.h" - #include "DlgSettingsMacroImp.h" #include "ui_DlgSettingsMacro.h" +#include "Action.h" #include "Application.h" +#include "MainWindow.h" using namespace Gui::Dialog; @@ -58,6 +59,18 @@ DlgSettingsMacroImp::~DlgSettingsMacroImp() { // no need to delete child widgets, Qt does it all for us } +/** Sets the size of the recent macros list from the user parameters. + * @see RecentMacrosAction + * @see StdCmdRecentMacros + */ +void DlgSettingsMacroImp::setRecentMacroSize() +{ + RecentMacrosAction *recent = getMainWindow()->findChild(QLatin1String("recentMacros")); + if (recent) { + ParameterGrp::handle hGrp = WindowParameter::getDefaultParameter()->GetGroup("RecentMacros"); + recent->resizeList(hGrp->GetInt("RecentMacros", 4)); + } +} void DlgSettingsMacroImp::saveSettings() { @@ -68,6 +81,10 @@ void DlgSettingsMacroImp::saveSettings() ui->PConsoleCheckBox->onSave(); ui->FileLogCheckBox->onSave(); ui->MacroPath_2->onSave(); + ui->RecentMacros->onSave(); + ui->ShortcutModifiers->onSave(); + ui->ShortcutCount->onSave(); + setRecentMacroSize(); } void DlgSettingsMacroImp::loadSettings() @@ -79,6 +96,9 @@ void DlgSettingsMacroImp::loadSettings() ui->PConsoleCheckBox->onRestore(); ui->FileLogCheckBox->onRestore(); ui->MacroPath_2->onRestore(); + ui->RecentMacros->onRestore(); + ui->ShortcutModifiers->onRestore(); + ui->ShortcutCount->onRestore(); } /** diff --git a/src/Gui/DlgSettingsMacroImp.h b/src/Gui/DlgSettingsMacroImp.h index 325154ec5b..646fad6092 100644 --- a/src/Gui/DlgSettingsMacroImp.h +++ b/src/Gui/DlgSettingsMacroImp.h @@ -52,6 +52,7 @@ protected: private: std::unique_ptr ui; + void setRecentMacroSize(); }; } // namespace Dialog diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index 3b71b43e3d..ba3e169fed 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -1320,6 +1320,15 @@ void MainWindow::appendRecentFile(const QString& filename) } } +void MainWindow::appendRecentMacro(const QString& filename) +{ + RecentMacrosAction *recent = this->findChild + (QString::fromLatin1("recentMacros")); + if (recent) { + recent->appendFile(filename); + } +} + void MainWindow::updateActions(bool delay) { //make it safe to call before the main window is actually created diff --git a/src/Gui/MainWindow.h b/src/Gui/MainWindow.h index c27bc406b5..d704956547 100644 --- a/src/Gui/MainWindow.h +++ b/src/Gui/MainWindow.h @@ -118,6 +118,10 @@ public: * MRU: Appends \a file to the list of recent files. */ void appendRecentFile(const QString& filename); + /** + * MRU: Appends \a macro to the list of recent macros. + */ + void appendRecentMacro(const QString& filename); /** * Returns true that the context menu contains the 'Customize...' menu item. */ diff --git a/src/Gui/Workbench.cpp b/src/Gui/Workbench.cpp index 1dd2348aa4..5c0eee3f45 100644 --- a/src/Gui/Workbench.cpp +++ b/src/Gui/Workbench.cpp @@ -671,6 +671,7 @@ MenuItem* StdWorkbench::setupMenuBar() const *macro << "Std_DlgMacroRecord" << "Std_MacroStopRecord" << "Std_DlgMacroExecute" + << "Std_RecentMacros" << "Separator" << "Std_DlgMacroExecuteDirect" << "Std_MacroAttachDebugger"