From c3adfb7cb07b159230d585b19fedabe0a6148524 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 12 Sep 2013 08:11:56 +0200 Subject: [PATCH] Prototyped command object infrastructure to be used in regression tests of Octave scripts p4#: 22387 --- .../Application/RiaApplication.cpp | 38 ++++++ ApplicationCode/Application/RiaApplication.h | 6 + .../ProjectDataModel/CMakeLists_files.cmake | 2 + .../ProjectDataModel/RimCommandObject.cpp | 126 ++++++++++++++++++ .../ProjectDataModel/RimCommandObject.h | 62 +++++++++ .../ProjectDataModel/RimProject.cpp | 3 + ApplicationCode/ProjectDataModel/RimProject.h | 3 +- .../ProjectDataModel/RimUiTreeModelPdm.cpp | 18 +++ .../ProjectDataModel/RimUiTreeModelPdm.h | 1 + .../ProjectDataModel/RimUiTreeView.cpp | 31 +---- .../ProjectDataModel/RimUiTreeView.h | 2 - .../RiaPropertyDataCommands.cpp | 7 +- .../UserInterface/RiuMainWindow.cpp | 39 +++++- ApplicationCode/UserInterface/RiuMainWindow.h | 4 + 14 files changed, 312 insertions(+), 30 deletions(-) create mode 100644 ApplicationCode/ProjectDataModel/RimCommandObject.cpp create mode 100644 ApplicationCode/ProjectDataModel/RimCommandObject.h diff --git a/ApplicationCode/Application/RiaApplication.cpp b/ApplicationCode/Application/RiaApplication.cpp index 2490dd08e3..25b7c0ca7f 100644 --- a/ApplicationCode/Application/RiaApplication.cpp +++ b/ApplicationCode/Application/RiaApplication.cpp @@ -350,6 +350,14 @@ bool RiaApplication::loadProject(const QString& projectFileName) caseProgress.incrementProgress(); } + // Loop over command objects and execute them + for (size_t i = 0; i < m_project->commandObjects.size(); i++) + { + m_commandQueue.push_back(m_project->commandObjects[i]); + } + + executeCommandObjects(); + onProjectOpenedOrClosed(); return true; @@ -495,6 +503,8 @@ bool RiaApplication::closeProject(bool askToSaveIfDirty) caf::EffectGenerator::clearEffectCache(); m_project->close(); + m_commandQueue.clear(); + onProjectOpenedOrClosed(); return true; @@ -959,6 +969,10 @@ void RiaApplication::slotWorkerProcessFinished(int exitCode, QProcess::ExitStatu return; } + + executeCommandObjects(); + + // Exit code != 0 means we have an error if (exitCode != 0) { @@ -1678,3 +1692,27 @@ QVariant RiaApplication::cacheDataObject(const QString& key) const return QVariant(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaApplication::addCommandObject(RimCommandObject* commandObject) +{ + m_commandQueue.push_back(commandObject); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaApplication::executeCommandObjects() +{ + if (m_commandQueue.size() > 0) + { + std::list< RimCommandObject* >::iterator it = m_commandQueue.begin(); + + RimCommandObject* first = *it; + first->redo(); + + m_commandQueue.pop_front(); + } +} + diff --git a/ApplicationCode/Application/RiaApplication.h b/ApplicationCode/Application/RiaApplication.h index 30e49914f2..ecc12cc2fb 100644 --- a/ApplicationCode/Application/RiaApplication.h +++ b/ApplicationCode/Application/RiaApplication.h @@ -35,6 +35,7 @@ class RiaSocketServer; class RiaPreferences; class RimReservoirView; class RimProject; +class RimCommandObject; namespace caf { @@ -133,6 +134,9 @@ public: void setCacheDataObject(const QString& key, const QVariant& dataObject); QVariant cacheDataObject(const QString& key) const; + void addCommandObject(RimCommandObject* commandObject); + void executeCommandObjects(); + private: void onProjectOpenedOrClosed(); void setWindowCaptionFromAppState(); @@ -168,4 +172,6 @@ private: cvf::ref m_standardFont; QMap m_sessionCache; // Session cache used to store username/passwords per session + + std::list m_commandQueue; }; diff --git a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake index 5837a805e7..f79c78fd50 100644 --- a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake @@ -42,6 +42,7 @@ ${CEE_CURRENT_LIST_DIR}RimUiTreeView.h ${CEE_CURRENT_LIST_DIR}RimReservoirCellResultsCacher.h ${CEE_CURRENT_LIST_DIR}RimStatisticsCaseEvaluator.h ${CEE_CURRENT_LIST_DIR}RimMimeData.h +${CEE_CURRENT_LIST_DIR}RimCommandObject.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -82,6 +83,7 @@ ${CEE_CURRENT_LIST_DIR}RimUiTreeView.cpp ${CEE_CURRENT_LIST_DIR}RimReservoirCellResultsCacher.cpp ${CEE_CURRENT_LIST_DIR}RimStatisticsCaseEvaluator.cpp ${CEE_CURRENT_LIST_DIR}RimMimeData.cpp +${CEE_CURRENT_LIST_DIR}RimCommandObject.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/ProjectDataModel/RimCommandObject.cpp b/ApplicationCode/ProjectDataModel/RimCommandObject.cpp new file mode 100644 index 0000000000..ba2911bfba --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimCommandObject.cpp @@ -0,0 +1,126 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimCommandObject.h" +#include "RiaApplication.h" +#include "RimCalcScript.h" + +#include "cafPdmUiTextEditor.h" +#include "cafPdmDocument.h" + +#include + +CAF_PDM_SOURCE_INIT(RimCommandObject, "RimCommandObject"); +CAF_PDM_SOURCE_INIT(RimCommandExecuteScript, "RimCommandExecuteScript"); + +//------------------------------------------------------------------------------------------------ +/// +//-------------------------------------------------------------------------------------------------- +RimCommandObject::RimCommandObject() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimCommandObject::~RimCommandObject() +{ +} + + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimCommandExecuteScript::RimCommandExecuteScript() +{ + CAF_PDM_InitField(&scriptText, "ScriptText", QString(), "ScriptText", "", "" ,""); + scriptText.setUiEditorTypeName(caf::PdmUiTextEditor::uiEditorTypeName()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimCommandExecuteScript::~RimCommandExecuteScript() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCommandExecuteScript::redo() +{ + RiaApplication* app = RiaApplication::instance(); + QString octavePath = app->octavePath(); + if (!octavePath.isEmpty()) + { + // http://www.gnu.org/software/octave/doc/interpreter/Command-Line-Options.html#Command-Line-Options + + QStringList arguments; + arguments.append("--path"); + arguments << QApplication::applicationDirPath(); + + arguments.append("-q"); + + arguments.append("--eval"); + arguments << this->scriptText(); + + RiaApplication::instance()->launchProcess(octavePath, arguments); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCommandExecuteScript::undo() +{ + +} + + + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCommandFactory::createCommandObjects(const caf::PdmObjectGroup& selectedObjects, std::vector& commandObjects) +{ + for (size_t i = 0; i < selectedObjects.objects.size(); i++) + { + caf::PdmObject* pdmObject = selectedObjects.objects[i]; + + if (dynamic_cast(pdmObject)) + { + RimCalcScript* calcScript = dynamic_cast(pdmObject); + + QFile file(calcScript->absolutePath); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QTextStream in(&file); + QByteArray byteArray = file.readAll(); + QString scriptText(byteArray); + + RimCommandExecuteScript* command = new RimCommandExecuteScript; + command->scriptText = scriptText; + + commandObjects.push_back(command); + } + } + } +} diff --git a/ApplicationCode/ProjectDataModel/RimCommandObject.h b/ApplicationCode/ProjectDataModel/RimCommandObject.h new file mode 100644 index 0000000000..a5e9b81ea3 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimCommandObject.h @@ -0,0 +1,62 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfBase.h" +#include "cvfObject.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include + +//================================================================================================== +// +// +//================================================================================================== +class RimCommandObject : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; +public: + RimCommandObject(); + virtual ~RimCommandObject(); + + virtual void redo() {}; + virtual void undo() {}; +}; + + +class RimCommandExecuteScript : public RimCommandObject +{ + CAF_PDM_HEADER_INIT; +public: + RimCommandExecuteScript(); + virtual ~RimCommandExecuteScript(); + + caf::PdmField scriptText; + + virtual void redo(); + virtual void undo(); +}; + + +class RimCommandFactory +{ +public: + static void createCommandObjects(const caf::PdmObjectGroup& selectedObjects, std::vector& commandObjects); +}; \ No newline at end of file diff --git a/ApplicationCode/ProjectDataModel/RimProject.cpp b/ApplicationCode/ProjectDataModel/RimProject.cpp index 4af24be49d..c07c6d45fc 100644 --- a/ApplicationCode/ProjectDataModel/RimProject.cpp +++ b/ApplicationCode/ProjectDataModel/RimProject.cpp @@ -75,6 +75,9 @@ RimProject::RimProject(void) wellPathImport = new RimWellPathImport(); wellPathImport.setUiHidden(true); + CAF_PDM_InitFieldNoDefault(&commandObjects, "CommandObjects", "CommandObjects", "", "", ""); + //wellPathImport.setUiHidden(true); + CAF_PDM_InitFieldNoDefault(¤tModelIndexPath, "TreeViewCurrentModelIndexPath", "", "", "", ""); currentModelIndexPath.setUiHidden(true); diff --git a/ApplicationCode/ProjectDataModel/RimProject.h b/ApplicationCode/ProjectDataModel/RimProject.h index e6755cfb18..28c6b5f9fa 100644 --- a/ApplicationCode/ProjectDataModel/RimProject.h +++ b/ApplicationCode/ProjectDataModel/RimProject.h @@ -20,6 +20,7 @@ #include "cafPdmDocument.h" #include "RimWellPathImport.h" +#include "RimCommandObject.h" class RimOilField; class RimCase; @@ -28,7 +29,6 @@ class RimScriptCollection; class RimIdenticalGridCaseGroup; class RigMainGrid; class RigCaseData; -class RimWellPathCollection; //================================================================================================== /// @@ -45,6 +45,7 @@ public: caf::PdmPointersField oilFields; caf::PdmField scriptCollection; caf::PdmField wellPathImport; + caf::PdmPointersField commandObjects; caf::PdmField treeViewState; caf::PdmField currentModelIndexPath; caf::PdmField nextValidCaseId; // Unique case ID within a project, used to identify a case from Octave scripts diff --git a/ApplicationCode/ProjectDataModel/RimUiTreeModelPdm.cpp b/ApplicationCode/ProjectDataModel/RimUiTreeModelPdm.cpp index 4fda91867c..4ffd8b299e 100644 --- a/ApplicationCode/ProjectDataModel/RimUiTreeModelPdm.cpp +++ b/ApplicationCode/ProjectDataModel/RimUiTreeModelPdm.cpp @@ -1084,3 +1084,21 @@ void RimUiTreeModelPdm::deleteAllWellPaths(const QModelIndex& itemIndex) clearClipboard(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimUiTreeModelPdm::populateObjectGroupFromModelIndexList(const QModelIndexList& modelIndexList, caf::PdmObjectGroup* objectGroup) +{ + CVF_ASSERT(objectGroup); + + for (int i = 0; i < modelIndexList.size(); i++) + { + caf::PdmUiTreeItem* uiItem = UiTreeModelPdm::getTreeItemFromIndex(modelIndexList.at(i)); + + if (uiItem && uiItem->dataObject() && uiItem->dataObject().p()) + { + objectGroup->addObject(uiItem->dataObject().p()); + } + } +} + diff --git a/ApplicationCode/ProjectDataModel/RimUiTreeModelPdm.h b/ApplicationCode/ProjectDataModel/RimUiTreeModelPdm.h index 7090bd0905..d3337d18fc 100644 --- a/ApplicationCode/ProjectDataModel/RimUiTreeModelPdm.h +++ b/ApplicationCode/ProjectDataModel/RimUiTreeModelPdm.h @@ -64,6 +64,7 @@ public: void addToParentAndBuildUiItems(caf::PdmUiTreeItem* parentTreeItem, int position, caf::PdmObject* pdmObject); + void populateObjectGroupFromModelIndexList(const QModelIndexList& modelIndexList, caf::PdmObjectGroup* objectGroup); void addObjects(const QModelIndex& itemIndex, caf::PdmObjectGroup& pdmObjects); void moveObjects(const QModelIndex& itemIndex, caf::PdmObjectGroup& pdmObjects); diff --git a/ApplicationCode/ProjectDataModel/RimUiTreeView.cpp b/ApplicationCode/ProjectDataModel/RimUiTreeView.cpp index 5ee8b947cf..b7dd7cac59 100644 --- a/ApplicationCode/ProjectDataModel/RimUiTreeView.cpp +++ b/ApplicationCode/ProjectDataModel/RimUiTreeView.cpp @@ -560,7 +560,6 @@ void RimUiTreeView::slotExecuteScript() } } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -574,6 +573,8 @@ void RimUiTreeView::slotExecuteScriptForSelectedCases() QModelIndex mi = RimUiTreeView::getModelIndexFromString(model(), encodedModelIndex); RimUiTreeModelPdm* myModel = dynamic_cast(model()); + if (!myModel) return; + caf::PdmUiTreeItem* uiItem = myModel->getTreeItemFromIndex(mi); if (uiItem) { @@ -618,7 +619,8 @@ void RimUiTreeView::slotExecuteScriptForSelectedCases() caf::PdmObjectGroup group; QModelIndexList mil = m->selectedRows(); - populateObjectGroupFromModelIndexList(mil, &group); + + myModel->populateObjectGroupFromModelIndexList(mil, &group); std::vector > typedObjects; group.objectsByType(&typedObjects); @@ -909,7 +911,7 @@ void RimUiTreeView::slotCloseCase() caf::PdmObjectGroup group; QModelIndexList mil = m->selectedRows(); - populateObjectGroupFromModelIndexList(mil, &group); + myModel->populateObjectGroupFromModelIndexList(mil, &group); std::vector > typedObjects; group.objectsByType(&typedObjects); @@ -1048,7 +1050,7 @@ void RimUiTreeView::createPdmObjectsFromClipboard(caf::PdmObjectGroup* objectGro if (!mdWithIndexes) return; QModelIndexList indexList = mdWithIndexes->indexes(); - populateObjectGroupFromModelIndexList(indexList, objectGroup); + myModel->populateObjectGroupFromModelIndexList(indexList, objectGroup); } //-------------------------------------------------------------------------------------------------- @@ -1536,27 +1538,6 @@ void RimUiTreeView::slotToggleItemsOff() executeSelectionToggleOperation(TOGGLE_OFF); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimUiTreeView::populateObjectGroupFromModelIndexList(const QModelIndexList& modelIndexList, caf::PdmObjectGroup* objectGroup) -{ - CVF_ASSERT(objectGroup); - - RimUiTreeModelPdm* myModel = dynamic_cast(model()); - if (!myModel) return; - - for (int i = 0; i < modelIndexList.size(); i++) - { - caf::PdmUiTreeItem* uiItem = myModel->getTreeItemFromIndex(modelIndexList.at(i)); - - if (uiItem && uiItem->dataObject() && uiItem->dataObject().p()) - { - objectGroup->addObject(uiItem->dataObject().p()); - } - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimUiTreeView.h b/ApplicationCode/ProjectDataModel/RimUiTreeView.h index 76f4a398c1..204e961d26 100644 --- a/ApplicationCode/ProjectDataModel/RimUiTreeView.h +++ b/ApplicationCode/ProjectDataModel/RimUiTreeView.h @@ -47,8 +47,6 @@ public: void applyTreeViewStateFromString(const QString& treeViewState); void storeTreeViewStateToString(QString& treeViewState); - void populateObjectGroupFromModelIndexList(const QModelIndexList& modelIndexList, caf::PdmObjectGroup* objectGroup); - static QModelIndex getModelIndexFromString(QAbstractItemModel* model, const QString& currentIndexString); static void encodeStringFromModelIndex(const QModelIndex mi, QString& currentIndexString); diff --git a/ApplicationCode/SocketInterface/RiaPropertyDataCommands.cpp b/ApplicationCode/SocketInterface/RiaPropertyDataCommands.cpp index c488f3ac48..9cc21502d6 100644 --- a/ApplicationCode/SocketInterface/RiaPropertyDataCommands.cpp +++ b/ApplicationCode/SocketInterface/RiaPropertyDataCommands.cpp @@ -952,7 +952,12 @@ public: { if (m_currentReservoir->reservoirViews[i]) { - m_currentReservoir->reservoirViews[i]->updateCurrentTimeStepAndRedraw(); + // As new result might have been introduced, update all editors connected + m_currentReservoir->reservoirViews[i]->cellResult->updateConnectedEditors(); + + // It is usually not needed to create new display model, but if any derived geometry based on generated data (from Octave) + // a full display model rebuild is required + m_currentReservoir->reservoirViews[i]->scheduleCreateDisplayModelAndRedraw(); } } } diff --git a/ApplicationCode/UserInterface/RiuMainWindow.cpp b/ApplicationCode/UserInterface/RiuMainWindow.cpp index 1e1a37754c..7223f3bc9f 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.cpp +++ b/ApplicationCode/UserInterface/RiuMainWindow.cpp @@ -59,6 +59,7 @@ #include "RimCellRangeFilterCollection.h" #include "Rim3dOverlayInfoConfig.h" #include "RiuWellImportWizard.h" +#include "RimCalcScript.h" @@ -198,6 +199,8 @@ void RiuMainWindow::createActions() m_snapshotToClipboard = new QAction(QIcon(":/SnapShot.png"), "Copy Snapshot To Clipboard", this); m_snapshotAllViewsToFile = new QAction(QIcon(":/SnapShotSaveViews.png"), "Snapshot All Views To File", this); + m_createCommandObject = new QAction("Create Command Object", this); + m_saveProjectAction = new QAction(QIcon(":/Save.png"), "&Save Project", this); m_saveProjectAsAction = new QAction(QIcon(":/Save.png"), "Save Project &As", this); @@ -220,6 +223,8 @@ void RiuMainWindow::createActions() connect(m_snapshotToFile, SIGNAL(triggered()), SLOT(slotSnapshotToFile())); connect(m_snapshotToClipboard, SIGNAL(triggered()), SLOT(slotSnapshotToClipboard())); connect(m_snapshotAllViewsToFile, SIGNAL(triggered()), SLOT(slotSnapshotAllViewsToFile())); + + connect(m_createCommandObject, SIGNAL(triggered()), SLOT(slotCreateCommandObject())); connect(m_saveProjectAction, SIGNAL(triggered()), SLOT(slotSaveProject())); connect(m_saveProjectAsAction, SIGNAL(triggered()), SLOT(slotSaveProjectAs())); @@ -355,9 +360,13 @@ void RiuMainWindow::createMenus() debugMenu->addAction(m_mockResultsModelAction); debugMenu->addAction(m_mockLargeResultsModelAction); debugMenu->addAction(m_mockInputModelAction); + debugMenu->addSeparator(); + debugMenu->addAction(m_createCommandObject); + connect(debugMenu, SIGNAL(aboutToShow()), SLOT(slotRefreshDebugActions())); + // Windows menu m_windowMenu = menuBar()->addMenu("&Windows"); connect(m_windowMenu, SIGNAL(aboutToShow()), SLOT(slotBuildWindowActions())); @@ -1581,7 +1590,7 @@ void RiuMainWindow::selectedCases(std::vector& cases) QModelIndexList selectedModelIndexes = m_treeView->selectionModel()->selectedIndexes(); caf::PdmObjectGroup group; - m_treeView->populateObjectGroupFromModelIndexList(selectedModelIndexes, &group); + m_treeModelPdm->populateObjectGroupFromModelIndexList(selectedModelIndexes, &group); std::vector > typedObjects; group.objectsByType(&typedObjects); @@ -1661,3 +1670,31 @@ void RiuMainWindow::slotShowCommandLineHelp() QString text = app->commandLineParameterHelp(); app->showFormattedTextInMessageBox(text); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMainWindow::slotCreateCommandObject() +{ + RiaApplication* app = RiaApplication::instance(); + if (!app->project()) return; + + QItemSelectionModel* selectionModel = m_treeView->selectionModel(); + if (selectionModel) + { + QModelIndexList selectedModelIndices = selectionModel->selectedIndexes(); + + caf::PdmObjectGroup selectedObjects; + m_treeModelPdm->populateObjectGroupFromModelIndexList(selectedModelIndices, &selectedObjects); + + std::vector commandObjects; + RimCommandFactory::createCommandObjects(selectedObjects, commandObjects); + + for (size_t i = 0; i < commandObjects.size(); i++) + { + app->project()->commandObjects.push_back(commandObjects[i]); + } + + app->project()->updateConnectedEditors(); + } +} diff --git a/ApplicationCode/UserInterface/RiuMainWindow.h b/ApplicationCode/UserInterface/RiuMainWindow.h index a0f4f91a0d..0317283d15 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.h +++ b/ApplicationCode/UserInterface/RiuMainWindow.h @@ -154,6 +154,8 @@ private: QAction* m_snapshotToClipboard; QAction* m_snapshotAllViewsToFile; + QAction* m_createCommandObject; + // Help actions QAction* m_aboutAction; QAction* m_commandLineHelpAction; @@ -221,6 +223,8 @@ private slots: void slotSnapshotToClipboard(); void slotSnapshotAllViewsToFile(); + void slotCreateCommandObject(); + // Mock models void slotMockModel(); void slotMockResultsModel();