Salome HOME
History for undo and redo commands
authorsbh <sergey.belash@opencascade.com>
Tue, 3 Feb 2015 17:50:01 +0000 (20:50 +0300)
committersbh <sergey.belash@opencascade.com>
Tue, 3 Feb 2015 17:50:01 +0000 (20:50 +0300)
src/Model/Model_Session.cpp
src/Model/Model_Session.h
src/ModelAPI/ModelAPI_Session.h
src/ModuleBase/ModuleBase_Operation.cpp
src/PartSet/PartSet_Module.cpp
src/XGUI/CMakeLists.txt
src/XGUI/XGUI_HistoryMenu.cpp [new file with mode: 0644]
src/XGUI/XGUI_HistoryMenu.h [new file with mode: 0644]
src/XGUI/XGUI_ObjectsBrowser.cpp
src/XGUI/XGUI_Workshop.cpp
src/XGUI/XGUI_Workshop.h

index 816b87f750d1e391f44a92ef939a0981d5214289..e9edb8856c2c0d1c9ba490caa0c8400951cbc07e 100644 (file)
@@ -50,7 +50,7 @@ void Model_Session::closeAll()
   Model_Application::getApplication()->deleteAllDocuments();
 }
 
-void Model_Session::startOperation()
+void Model_Session::startOperation(const std::string& theId)
 {
   ROOT_DOC->startOperation();
   static std::shared_ptr<Events_Message> aStartedMsg
@@ -118,6 +118,22 @@ void Model_Session::redo()
   setCheckTransactions(true);
 }
 
+//! Returns stack of performed operations
+std::list<std::string> Model_Session::undoList()
+{
+  std::list<std::string> temp;
+  temp.push_front("Part");
+  temp.push_front("Sketch");
+  temp.push_front("Extrusion");
+  return temp;
+}
+//! Returns stack of rolled back operations
+std::list<std::string> Model_Session::redoList()
+{
+  std::list<std::string> temp;
+  return temp;
+}
+
 FeaturePtr Model_Session::createFeature(string theFeatureID)
 {
   if (this != myImpl) {
index fa94b8aae8588b8153a7086aff2d0a4c3c5879e3..0ae8bc46aa44fe763f82023531cb27bc3be7aed7 100644 (file)
@@ -48,7 +48,7 @@ class Model_Session : public ModelAPI_Session, public Events_Listener
   MODEL_EXPORT virtual void closeAll();
 
   //! Starts a new operation (opens a tansaction)
-  MODEL_EXPORT virtual void startOperation();
+  MODEL_EXPORT virtual void startOperation(const std::string& theId);
   //! Finishes the previously started operation (closes the transaction)
   MODEL_EXPORT virtual void finishOperation();
   //! Aborts the operation 
@@ -66,6 +66,10 @@ class Model_Session : public ModelAPI_Session, public Events_Listener
   MODEL_EXPORT virtual bool canRedo();
   //! Redoes last operation
   MODEL_EXPORT virtual void redo();
+  //! Returns stack of performed operations
+  MODEL_EXPORT virtual std::list<std::string> undoList();
+  //! Returns stack of rolled back operations
+  MODEL_EXPORT virtual std::list<std::string> redoList();
 
   /// Returns the root document of the application (that may contains sub-documents)
   MODEL_EXPORT virtual std::shared_ptr<ModelAPI_Document> moduleDocument();
index 619509dd2cfdeb97f5d75ec53db32c7556aed5c5..933dfc58689bb237d1fee40fa04dcf19a3e88a9b 100644 (file)
@@ -45,7 +45,8 @@ class MODELAPI_EXPORT ModelAPI_Session
   virtual void closeAll() = 0;
 
   //! Starts a new operation (opens a tansaction)
-  virtual void startOperation() = 0;
+  //! \param theId of operation for history (optional)
+  virtual void startOperation(const std::string& theId) = 0;
   //! Finishes the previously started operation (closes the transaction)
   virtual void finishOperation() = 0;
   //! Aborts the operation 
@@ -63,6 +64,10 @@ class MODELAPI_EXPORT ModelAPI_Session
   virtual bool canRedo() = 0;
   //! Redoes last operation
   virtual void redo() = 0;
+  //! Returns stack of performed operations (from last to first)
+  virtual std::list<std::string> undoList() = 0;
+  //! Returns stack of rolled back operations (from last rolled back to first)
+  virtual std::list<std::string> redoList() = 0;
 
   /// Registers the plugin that creates features.
   /// It is obligatory for each plugin to call this function on loading to be found by 
index de9a9e857adb4ab11e69a832dd9a2c57299b13df..bfe58446d370168a50092075ea228460c6ca7c25 100644 (file)
@@ -146,7 +146,8 @@ std::shared_ptr<ModelAPI_Document> ModuleBase_Operation::document() const
 
 void ModuleBase_Operation::start()
 {
-  ModelAPI_Session::get()->startOperation();
+  QString anId = getDescription()->operationId();
+  ModelAPI_Session::get()->startOperation(anId.toStdString());
 
   if (!myIsEditing)
     createFeature();
index 49323976a568ca433a2a268280d81d1d98c6a945..7fe2956f1a9d516ff55781c83c23dde2b344fd96 100644 (file)
@@ -534,7 +534,7 @@ void PartSet_Module::deleteObjects()
   }
 
   SessionPtr aMgr = ModelAPI_Session::get();
-  aMgr->startOperation();
+  aMgr->startOperation("DeletePartSet");
   std::set<FeaturePtr>::const_iterator anIt = aRefFeatures.begin(),
                                        aLast = aRefFeatures.end();
   for (; anIt != aLast; anIt++) {
index 26879a5e3e478af7648742a0ed7cc1e13734b073..c7a27c7161cfdc275dc1f0be70c5ca5f2282d253 100644 (file)
@@ -23,6 +23,7 @@ SET(PROJECT_HEADERS
        XGUI_Tools.h
        XGUI_ViewerProxy.h
        XGUI_Workshop.h
+       XGUI_HistoryMenu.h
 )
 
 SET(PROJECT_AUTOMOC 
@@ -46,6 +47,7 @@ SET(PROJECT_SOURCES
        XGUI_Tools.cpp
        XGUI_ViewerProxy.cpp
        XGUI_Workshop.cpp
+       XGUI_HistoryMenu.cpp
 )
 
 SET(PROJECT_RESOURCES 
diff --git a/src/XGUI/XGUI_HistoryMenu.cpp b/src/XGUI/XGUI_HistoryMenu.cpp
new file mode 100644 (file)
index 0000000..3e36f42
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * XGUI_HistoryMenu.cpp
+ *
+ *  Created on: Feb 2, 2015
+ *      Author: sbh
+ */
+
+#include <XGUI_HistoryMenu.h>
+
+#include <ModelAPI_Session.h>
+
+#include <QListWidget>
+#include <QWidgetAction>
+#include <QToolButton>
+
+//! Extends given feature with previously created context menu.
+//! \param theId - Id of the feature to add \a theMenu
+//! \param theMenu - Enables or disables menu feature
+XGUI_HistoryMenu::XGUI_HistoryMenu(QToolButton* theParent)
+ : QMenu(theParent),
+   myHistoryList(new QListWidget(this))
+{
+  theParent->setMenu(this);
+  theParent->setPopupMode(QToolButton::MenuButtonPopup);
+
+  QWidgetAction* aListAction = new QWidgetAction(this);
+  aListAction->setDefaultWidget(myHistoryList);
+  this->addAction(aListAction);
+
+  myHistoryList->setMouseTracking(true); // track mouse hover
+  myHistoryList->setSelectionMode(QAbstractItemView::ExtendedSelection);
+  connect(myHistoryList, SIGNAL(itemEntered(QListWidgetItem *)),
+          this,          SLOT(setStackSelectedTo(QListWidgetItem *)));
+  connect(myHistoryList, SIGNAL(itemClicked(QListWidgetItem *)),
+          this,          SLOT(onItemPressed(QListWidgetItem *)));
+}
+
+XGUI_HistoryMenu::~XGUI_HistoryMenu()
+{
+}
+
+void XGUI_HistoryMenu::setHistory(const QList<QAction*>& theActions)
+{
+  myHistoryList->clear();
+  foreach(QAction* anAct, theActions) {
+    QListWidgetItem* anItem = new QListWidgetItem(anAct->icon(),
+                                                  anAct->text(),
+                                                  myHistoryList);
+    anAct->deleteLater();
+  }
+}
+
+
+void XGUI_HistoryMenu::setStackSelectedTo(QListWidgetItem * theItem)
+{
+  if (!theItem)
+    return;
+
+  QListWidgetItem* eachItem = NULL;
+  bool isSelect = true;
+  for(int aRow = 0; aRow < myHistoryList->count(); ++aRow) {
+    eachItem = myHistoryList->item(aRow);
+    myHistoryList->setItemSelected(eachItem, isSelect);
+    // Deselect items below hovered
+    if (eachItem == theItem) {
+      isSelect = false;
+    }
+  }
+}
+
+void XGUI_HistoryMenu::onItemPressed(QListWidgetItem * theItem)
+{
+  int selectedSize = myHistoryList->row(theItem) + 1;
+  emit actionsSelected(selectedSize);
+  hide();
+  myHistoryList->clear();
+}
diff --git a/src/XGUI/XGUI_HistoryMenu.h b/src/XGUI/XGUI_HistoryMenu.h
new file mode 100644 (file)
index 0000000..dfcb256
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * XGUI_HistoryMenu.h
+ *
+ *  Created on: Feb 2, 2015
+ *      Author: sbh
+ */
+
+#ifndef XGUI_HISTORYMENU_H_
+#define XGUI_HISTORYMENU_H_
+
+#include <XGUI.h>
+#include <QMenu>
+
+class QListWidget;
+class QToolButton;
+class QListWidgetItem;
+
+class XGUI_EXPORT XGUI_HistoryMenu : public QMenu
+{
+  Q_OBJECT
+ public:
+  explicit XGUI_HistoryMenu(QToolButton* theParent);
+  virtual ~XGUI_HistoryMenu();
+
+ signals:
+  void actionsSelected(int);
+
+ public slots:
+  void setHistory(const QList<QAction*>&);
+
+ protected slots:
+  void setStackSelectedTo(QListWidgetItem *);
+  void onItemPressed(QListWidgetItem *);
+
+ private:
+  QListWidget* myHistoryList;
+};
+
+#endif /* XGUI_OPERATIONSSTACKPOPUP_H_ */
index 69cc9c616c58b32feda738a6194f444cfacd5a26..243e98eafff67da3f6ace9ef8a0520d03c33e68b 100644 (file)
@@ -80,7 +80,7 @@ void XGUI_DataTree::commitData(QWidget* theEditor)
     QString aRes = aEditor->text();
     ObjectPtr aFeature = mySelectedData.first();
     SessionPtr aMgr = ModelAPI_Session::get();
-    aMgr->startOperation();
+    aMgr->startOperation("RenameFeature");
     aFeature->data()->setName(qPrintable(aRes));
     aMgr->finishOperation();
   }
index 2ed8c86f53518e09c160c5ed5b4ae455ed77f916..0dbb7687697715258db406ca3179ae33e987596d 100644 (file)
@@ -16,6 +16,7 @@
 #include "XGUI_ContextMenuMgr.h"
 #include "XGUI_ModuleConnector.h"
 #include <XGUI_QtEvents.h>
+#include <XGUI_HistoryMenu.h>
 
 #include <AppElements_Workbench.h>
 #include <AppElements_Viewer.h>
@@ -68,6 +69,9 @@
 #include <QLayout>
 #include <QThread>
 #include <QObject>
+#include <QMenu>
+#include <QToolButton>
+#include <QAction>
 
 #ifdef _DEBUG
 #include <QDebug>
@@ -256,14 +260,30 @@ void XGUI_Workshop::initMenu()
   aCommand->connectTo(this, SLOT(onSave()));
   //aCommand->disable();
 
-  aCommand = aGroup->addFeature("UNDO_CMD", tr("Undo"), tr("Undo last command"),
+  QString aUndoId = "UNDO_CMD";
+  aCommand = aGroup->addFeature(aUndoId, tr("Undo"), tr("Undo last command"),
                                 QIcon(":pictures/undo.png"), QKeySequence::Undo);
   aCommand->connectTo(this, SLOT(onUndo()));
 
-  aCommand = aGroup->addFeature("REDO_CMD", tr("Redo"), tr("Redo last command"),
+  QToolButton* aToolBtn = qobject_cast<QToolButton*>(aGroup->widget(aUndoId));
+  XGUI_HistoryMenu* aUndoMenu = new XGUI_HistoryMenu(aToolBtn);
+  connect(this,  SIGNAL(updateUndoHistory(const QList<QAction*>&)),
+          aUndoMenu, SLOT(setHistory(const QList<QAction*>&)));
+  connect(aUndoMenu, SIGNAL(actionsSelected(int)),
+          this,  SLOT(onUndo(int)));
+
+  QString aRedoId = "REDO_CMD";
+  aCommand = aGroup->addFeature(aRedoId, tr("Redo"), tr("Redo last command"),
                                 QIcon(":pictures/redo.png"), QKeySequence::Redo);
   aCommand->connectTo(this, SLOT(onRedo()));
 
+  aToolBtn = qobject_cast<QToolButton*>(aGroup->widget(aRedoId));
+  XGUI_HistoryMenu* aRedoMenu = new XGUI_HistoryMenu(aToolBtn);
+  connect(this,  SIGNAL(updateUndoHistory(const QList<QAction*>&)),
+          aRedoMenu, SLOT(setHistory(const QList<QAction*>&)));
+  connect(aRedoMenu, SIGNAL(actionsSelected(int)),
+          this,  SLOT(onUndo(int)));
+
   aCommand = aGroup->addFeature("REBUILD_CMD", tr("Rebuild"), tr("Rebuild data objects"),
     QIcon(":pictures/rebuild.png"), QKeySequence());
   aCommand->connectTo(this, SLOT(onRebuild()));
@@ -675,7 +695,6 @@ void XGUI_Workshop::addFeature(const std::shared_ptr<Config_FeatureMessage>& the
   // Remember features icons
   myIcons[QString::fromStdString(theMessage->id())] = QString::fromStdString(theMessage->icon());
 
-  //Find or create Workbench
   QString aWchName = QString::fromStdString(theMessage->workbenchId());
   QString aNestedFeatures = QString::fromStdString(theMessage->nestedFeatures());
   bool isUsePropPanel = theMessage->isUseInput();
@@ -684,7 +703,7 @@ void XGUI_Workshop::addFeature(const std::shared_ptr<Config_FeatureMessage>& the
     QAction* aAction = salomeConnector()->addFeature(aWchName, aFeatureId,
                                                      QString::fromStdString(theMessage->text()),
                                                      QString::fromStdString(theMessage->tooltip()),
-                                                     QIcon(theMessage->icon().c_str()),
+                                                     QIcon(QString::fromStdString(theMessage->icon())),
                                                      QKeySequence(),
                                                      isUsePropPanel);
     salomeConnector()->setNestedActions(aFeatureId, aNestedFeatures.split(" ", QString::SkipEmptyParts));
@@ -693,7 +712,7 @@ void XGUI_Workshop::addFeature(const std::shared_ptr<Config_FeatureMessage>& the
     myActionsMgr->addCommand(aAction);
     myModule->actionCreated(aAction);
   } else {
-
+    //Find or create Workbench
     AppElements_MainMenu* aMenuBar = myMainWindow->menuObject();
     AppElements_Workbench* aPage = aMenuBar->findWorkbench(aWchName);
     if (!aPage) {
@@ -894,24 +913,28 @@ bool XGUI_Workshop::onSaveAs()
 }
 
 //******************************************************
-void XGUI_Workshop::onUndo()
+void XGUI_Workshop::onUndo(int theTimes)
 {
   objectBrowser()->treeView()->setCurrentIndex(QModelIndex());
   SessionPtr aMgr = ModelAPI_Session::get();
   if (aMgr->isOperation())
     operationMgr()->onAbortOperation();
-  aMgr->undo();
+  for (int i = 0; i < theTimes; ++i) {
+    aMgr->undo();
+  }
   updateCommandStatus();
 }
 
 //******************************************************
-void XGUI_Workshop::onRedo()
+void XGUI_Workshop::onRedo(int theTimes)
 {
   objectBrowser()->treeView()->setCurrentIndex(QModelIndex());
   SessionPtr aMgr = ModelAPI_Session::get();
   if (aMgr->isOperation())
     operationMgr()->onAbortOperation();
-  aMgr->redo();
+  for (int i = 0; i < theTimes; ++i) {
+    aMgr->redo();
+  }
   updateCommandStatus();
 }
 
@@ -921,7 +944,7 @@ void XGUI_Workshop::onRebuild()
   SessionPtr aMgr = ModelAPI_Session::get();
   bool aWasOperation = aMgr->isOperation(); // keep this value
   if (!aWasOperation) {
-    aMgr->startOperation();
+    aMgr->startOperation("Rebuild");
   }
   static const Events_ID aRebuildEvent = Events_Loop::loop()->eventByName("Rebuild");
   Events_Loop::loop()->send(std::shared_ptr<Events_Message>(
@@ -1050,6 +1073,9 @@ void XGUI_Workshop::updateCommandStatus()
     }
     aUndoCmd->setEnabled(aMgr->canUndo() && !aMgr->isOperation());
     aRedoCmd->setEnabled(aMgr->canRedo() && !aMgr->isOperation());
+
+    updateHistory();
+
   } else {
     foreach(QAction* aCmd, aCommands) {
       QString aId = aCmd->data().toString();
@@ -1065,6 +1091,33 @@ void XGUI_Workshop::updateCommandStatus()
   emit commandStatusUpdated();
 }
 
+void XGUI_Workshop::updateHistory()
+{
+  std::list<std::string> aUndoList = ModelAPI_Session::get()->undoList();
+  std::list<std::string>::iterator it = aUndoList.begin();
+  QList<QAction*> aUndoRes;
+  for ( ; it != aUndoList.end(); it++) {
+    QString anId = QString::fromStdString(*it);
+    QIcon aIcon;
+    if (myIcons.contains(anId))
+      aIcon = QIcon(myIcons[anId]);
+    aUndoRes << new QAction(aIcon, anId, NULL);
+  }
+  emit updateUndoHistory(aUndoRes);
+
+  std::list<std::string> aRedoList = ModelAPI_Session::get()->redoList();
+  it = aRedoList.begin();
+  QList<QAction*> aRedoRes;
+  for ( ; it != aRedoList.end(); it++) {
+    QString anId = QString::fromStdString(*it);
+    QIcon aIcon;
+    if (myIcons.contains(anId))
+      aIcon = QIcon(myIcons[anId]);
+    aRedoRes << new QAction(aIcon, anId, NULL);
+  }
+  emit updateRedoHistory(aUndoRes);
+}
+
 //******************************************************
 QDockWidget* XGUI_Workshop::createObjectBrowser(QWidget* theParent)
 {
@@ -1302,7 +1355,7 @@ These features will be deleted also. Would you like to continue?")).arg(aNames),
   }
 
   SessionPtr aMgr = ModelAPI_Session::get();
-  aMgr->startOperation();
+  aMgr->startOperation("DeleteObjects");
   std::set<FeaturePtr>::const_iterator anIt = aRefFeatures.begin(),
                                        aLast = aRefFeatures.end();
   for (; anIt != aLast; anIt++) {
index 80aa6d2f8358d405b313f1a48f18a8b770feae1f..23990f8bc9354130723298b8ac84b95a8becd787 100644 (file)
@@ -215,10 +215,16 @@ signals:
   //! the application is started
   void applicationStarted();
 
+  void updateUndoHistory(const QList<QAction*>&);
+  void updateRedoHistory(const QList<QAction*>&);
+
  public slots:
    /// Update of commands status
   void updateCommandStatus();
 
+  /// update history list (undo/redo commands)
+  void updateHistory();
+
   /// Create a new dokument
   void onNew();
 
@@ -235,10 +241,10 @@ signals:
   void onExit();
 
   /// Undo last command
-  void onUndo();
+  void onUndo(int times = 1);
 
   /// Redo previous command
-  void onRedo();
+  void onRedo(int times = 1);
 
   /// Rebuild data tree
   void onRebuild();