Salome HOME
Disable undo on active operation (to prevent crash on undo the sketch creation)
[modules/shaper.git] / src / XGUI / XGUI_Workshop.cpp
index 8e8babd3b923b047629ac19c94f095f31e959137..c7a98185b9d71246dce94c5d101a9e77e0bae25b 100644 (file)
@@ -14,7 +14,6 @@
 #include "XGUI_Displayer.h"
 #include "XGUI_OperationMgr.h"
 #include "XGUI_SalomeConnector.h"
-#include "XGUI_SalomeViewer.h"
 #include "XGUI_ActionsMgr.h"
 #include "XGUI_ErrorDialog.h"
 #include "XGUI_ViewerProxy.h"
@@ -22,6 +21,7 @@
 #include "XGUI_ContextMenuMgr.h"
 #include "XGUI_ModuleConnector.h"
 #include "XGUI_Preferences.h"
+#include <XGUI_QtEvents.h>
 
 #include <ModelAPI_Events.h>
 #include <ModelAPI_Session.h>
@@ -43,7 +43,9 @@
 #include <ModuleBase_Operation.h>
 #include <ModuleBase_OperationDescription.h>
 #include <ModuleBase_SelectionValidator.h>
-#include "ModuleBase_WidgetFactory.h"
+#include <ModuleBase_WidgetFactory.h>
+#include <ModuleBase_Tools.h>
+#include <ModuleBase_IViewer.h>
 
 #include <Config_Common.h>
 #include <Config_FeatureMessage.h>
 #include <QPushButton>
 #include <QDockWidget>
 #include <QLayout>
-#include <QTimer>
+#include <QThread>
+#include <QObject>
 
 #ifdef _DEBUG
 #include <QDebug>
+#include <iostream>
 #endif
 
 #ifdef WIN32
@@ -87,7 +91,8 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
       myPropertyPanel(0),
       myObjectBrowser(0),
       myDisplayer(0),
-      myUpdatePrefs(false)
+      myUpdatePrefs(false),
+      myPartActivating(false)
 {
   myMainWindow = mySalomeConnector ? 0 : new XGUI_MainWindow();
 
@@ -108,20 +113,24 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
 
   myModuleConnector = new XGUI_ModuleConnector(this);
 
-  connect(myOperationMgr, SIGNAL(operationStarted()), SLOT(onOperationStarted()));
+  connect(myOperationMgr, SIGNAL(operationStarted(ModuleBase_Operation*)), 
+          SLOT(onOperationStarted()));
   connect(myOperationMgr, SIGNAL(operationResumed()), SLOT(onOperationStarted()));
   connect(myOperationMgr, SIGNAL(operationStopped(ModuleBase_Operation*)),
           SLOT(onOperationStopped(ModuleBase_Operation*)));
   connect(myMainWindow, SIGNAL(exitKeySequence()), SLOT(onExit()));
-  connect(myOperationMgr, SIGNAL(operationStarted()), myActionsMgr, SLOT(update()));
-  connect(myOperationMgr, SIGNAL(operationStopped(ModuleBase_Operation*)), myActionsMgr,
-          SLOT(update()));
+  // TODO(sbh): It seems that application works properly without update on operationStarted
+  connect(myOperationMgr, SIGNAL(operationStarted(ModuleBase_Operation*)),
+          myActionsMgr,   SLOT(update()));
+  connect(myOperationMgr, SIGNAL(operationStopped(ModuleBase_Operation*)),
+          myActionsMgr,   SLOT(update()));
   connect(this, SIGNAL(errorOccurred(const QString&)), myErrorDlg, SLOT(addError(const QString&)));
 }
 
 //******************************************************
 XGUI_Workshop::~XGUI_Workshop(void)
 {
+  delete myDisplayer;
 }
 
 //******************************************************
@@ -131,9 +140,7 @@ void XGUI_Workshop::startApplication()
   //Initialize event listening
   Events_Loop* aLoop = Events_Loop::loop();
   aLoop->registerListener(this, Events_Error::errorID());  //!< Listening application errors.
-  //TODO(sbh): Implement static method to extract event id [SEID]
-  aLoop->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_LOADED));
-  // TODO Is it good to use non standard event within workshop?
+  aLoop->registerListener(this, Events_Loop::eventByName(Config_FeatureMessage::GUI_EVENT()));
   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OPERATION_LAUNCHED));
   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
@@ -141,6 +148,9 @@ void XGUI_Workshop::startApplication()
   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
   aLoop->registerListener(this, Events_Loop::eventByName("LongOperation"));
   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_PLUGIN_LOADED));
+  aLoop->registerListener(this, Events_Loop::eventByName("CurrentDocumentChanged"));
+  aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_TOSHOW));
+  aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_TOHIDE));
 
   registerValidators();
   activateModule();
@@ -169,6 +179,11 @@ void XGUI_Workshop::initMenu()
                                                 false);
     connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onRedo()));
     salomeConnector()->addEditMenuSeparator();
+    aAction = salomeConnector()->addEditCommand("REBUILD_CMD", tr("Rebuild"), tr("Rebuild data objects"),
+                                                QIcon(":pictures/rebuild.png"), QKeySequence(),
+                                                false);
+    connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onRebuild()));
+    salomeConnector()->addEditMenuSeparator();
     return;
   }
   // File commands group
@@ -190,10 +205,11 @@ void XGUI_Workshop::initMenu()
   aCommand->connectTo(this, SLOT(onRedo()));
 
   aCommand = aGroup->addFeature("REBUILD_CMD", tr("Rebuild"), tr("Rebuild data objects"),
-                                QIcon(":pictures/rebuild.png"));
+    QIcon(":pictures/rebuild.png"), QKeySequence());
+  aCommand->connectTo(this, SLOT(onRebuild()));
 
   aCommand = aGroup->addFeature("SAVEAS_CMD", tr("Save as..."), tr("Save the document into a file"),
-                                QIcon(":pictures/save.png"));
+                                QIcon(":pictures/save.png"), QKeySequence());
   aCommand->connectTo(this, SLOT(onSaveAs()));
   //aCommand->disable();
 
@@ -228,12 +244,22 @@ XGUI_Workbench* XGUI_Workshop::addWorkbench(const QString& theName)
 }
 
 //******************************************************
-void XGUI_Workshop::processEvent(const Events_Message* theMessage)
+void XGUI_Workshop::processEvent(const boost::shared_ptr<Events_Message>& theMessage)
 {
+  if (QApplication::instance()->thread() != QThread::currentThread()) {
+    #ifdef _DEBUG
+    std::cout << "XGUI_Workshop::processEvent: " << "Working in another thread." << std::endl;
+    #endif
+    SessionPtr aMgr = ModelAPI_Session::get();
+    PostponeMessageQtEvent* aPostponeEvent = new PostponeMessageQtEvent(theMessage);
+    QApplication::postEvent(this, aPostponeEvent);
+    return;
+  }
+
   //A message to start feature creation received.
-  if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_LOADED)) {
-    const Config_FeatureMessage* aFeatureMsg =
-        dynamic_cast<const Config_FeatureMessage*>(theMessage);
+  if (theMessage->eventID() == Events_Loop::loop()->eventByName(Config_FeatureMessage::GUI_EVENT())) {
+    boost::shared_ptr<Config_FeatureMessage> aFeatureMsg =
+       boost::dynamic_pointer_cast<Config_FeatureMessage>(theMessage);
     if (!aFeatureMsg->isInternal()) {
       addFeature(aFeatureMsg);
     }
@@ -241,8 +267,8 @@ void XGUI_Workshop::processEvent(const Events_Message* theMessage)
 
   // Process creation of Part
   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)) {
-    const ModelAPI_ObjectUpdatedMessage* aUpdMsg =
-        dynamic_cast<const ModelAPI_ObjectUpdatedMessage*>(theMessage);
+    boost::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
+        boost::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
     onFeatureCreatedMsg(aUpdMsg);
     if (myUpdatePrefs) {
       if (mySalomeConnector)
@@ -256,37 +282,58 @@ void XGUI_Workshop::processEvent(const Events_Message* theMessage)
 
   // Redisplay feature
   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY)) {
-    const ModelAPI_ObjectUpdatedMessage* aUpdMsg =
-        dynamic_cast<const ModelAPI_ObjectUpdatedMessage*>(theMessage);
+    boost::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
+        boost::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
     onFeatureRedisplayMsg(aUpdMsg);
   }
 
   //Update property panel on corresponding message. If there is no current operation (no
   //property panel), or received message has different feature to the current - do nothing.
   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)) {
-    const ModelAPI_ObjectUpdatedMessage* anUpdateMsg =
-        dynamic_cast<const ModelAPI_ObjectUpdatedMessage*>(theMessage);
+    boost::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
+        boost::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
     onFeatureUpdatedMsg(anUpdateMsg);
   }
 
   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
-    const ModelAPI_ObjectDeletedMessage* aDelMsg =
-        dynamic_cast<const ModelAPI_ObjectDeletedMessage*>(theMessage);
+    boost::shared_ptr<ModelAPI_ObjectDeletedMessage> aDelMsg =
+        boost::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
     onObjectDeletedMsg(aDelMsg);
   }
 
   else if (theMessage->eventID() == Events_LongOp::eventID()) {
     if (Events_LongOp::isPerformed())
       QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
-    //QTimer::singleShot(10, this, SLOT(onStartWaiting()));
     else
       QApplication::restoreOverrideCursor();
   }
 
+  else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_TOSHOW)) {
+    boost::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
+        boost::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
+    const std::set<ObjectPtr>& aObjList = anUpdateMsg->objects();
+    QList<ObjectPtr> aList;
+    std::set<ObjectPtr>::const_iterator aIt;
+    for (aIt = aObjList.cbegin(); aIt != aObjList.cend(); ++aIt)
+      aList.append(*aIt);
+    showObjects(aList, true);
+  }
+
+  else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_TOHIDE)) {
+    boost::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
+        boost::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
+    const std::set<ObjectPtr>& aObjList = anUpdateMsg->objects();
+    QList<ObjectPtr> aList;
+    std::set<ObjectPtr>::const_iterator aIt;
+    for (aIt = aObjList.cbegin(); aIt != aObjList.cend(); ++aIt)
+      aList.append(*aIt);
+    showObjects(aList, false);
+  }
+
   //An operation passed by message. Start it, process and commit.
   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OPERATION_LAUNCHED)) {
-    const Config_PointerMessage* aPartSetMsg =
-        dynamic_cast<const Config_PointerMessage*>(theMessage);
+    boost::shared_ptr<Config_PointerMessage> aPartSetMsg =
+        boost::dynamic_pointer_cast<Config_PointerMessage>(theMessage);
     //myPropertyPanel->cleanContent();
     ModuleBase_Operation* anOperation = (ModuleBase_Operation*) aPartSetMsg->pointer();
 
@@ -297,9 +344,33 @@ void XGUI_Workshop::processEvent(const Events_Message* theMessage)
           updateCommandStatus();
       }
     }
+  }
+  else if (theMessage->eventID() == Events_Loop::loop()->eventByName("CurrentDocumentChanged")) {
+    myActionsMgr->update();
+    // Find and Activate active part
+    if (myPartActivating)
+      return;
+    SessionPtr aMgr = ModelAPI_Session::get();
+    DocumentPtr aActiveDoc = aMgr->activeDocument();
+    DocumentPtr aDoc = aMgr->moduleDocument();
+    if (aActiveDoc == aDoc) {
+      activatePart(ResultPartPtr()); 
+      return;
+    }
+    std::string aGrpName = ModelAPI_ResultPart::group();
+    for (int i = 0; i < aDoc->size(aGrpName); i++) {
+      ResultPartPtr aPart = boost::dynamic_pointer_cast<ModelAPI_ResultPart>(aDoc->object(aGrpName, i));
+      if (aPart->partDoc() == aActiveDoc) {
+        activatePart(aPart); // Activate a part which corresponds to active Doc
+        return;
+      }
+    }
+    // If not found then activate global document
+    activatePart(ResultPartPtr()); 
+
   } else {
     //Show error dialog if error message received.
-    const Events_Error* anAppError = dynamic_cast<const Events_Error*>(theMessage);
+    boost::shared_ptr<Events_Error> anAppError = boost::dynamic_pointer_cast<Events_Error>(theMessage);
     if (anAppError) {
       emit errorOccurred(QString::fromLatin1(anAppError->description()));
     }
@@ -321,7 +392,7 @@ void XGUI_Workshop::onStartWaiting()
 }
 
 //******************************************************
-void XGUI_Workshop::onFeatureUpdatedMsg(const ModelAPI_ObjectUpdatedMessage* theMsg)
+void XGUI_Workshop::onFeatureUpdatedMsg(const boost::shared_ptr<ModelAPI_ObjectUpdatedMessage>& theMsg)
 {
   std::set<ObjectPtr> aFeatures = theMsg->objects();
   if (myOperationMgr->hasOperation()) {
@@ -335,26 +406,44 @@ void XGUI_Workshop::onFeatureUpdatedMsg(const ModelAPI_ObjectUpdatedMessage* the
       }
     }
   }
-  myOperationMgr->validateCurrentOperation();
+  myOperationMgr->onValidateOperation();
+  if (myObjectBrowser)
+    myObjectBrowser->processEvent(theMsg);
 }
 
 //******************************************************
-void XGUI_Workshop::onFeatureRedisplayMsg(const ModelAPI_ObjectUpdatedMessage* theMsg)
+void XGUI_Workshop::onFeatureRedisplayMsg(const boost::shared_ptr<ModelAPI_ObjectUpdatedMessage>& theMsg)
 {
   std::set<ObjectPtr> aObjects = theMsg->objects();
   std::set<ObjectPtr>::const_iterator aIt;
+  QIntList aModes;
   for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) {
     ObjectPtr aObj = (*aIt);
-    if (!aObj->data() || !aObj->data()->isValid())
+    bool aHide = !aObj->data() || !aObj->data()->isValid();
+    if (!aHide) { // check that this is not hidden result
+      ResultPtr aRes = boost::dynamic_pointer_cast<ModelAPI_Result>(aObj);
+      aHide = aRes && aRes->isConcealed();
+    }
+    if (aHide)
       myDisplayer->erase(aObj, false);
     else {
-      if (myDisplayer->isVisible(aObj))  // TODO VSV: Correction sketch drawing
+      if (myDisplayer->isVisible(aObj))  {
         myDisplayer->display(aObj, false);  // In order to update presentation
-      else {
         if (myOperationMgr->hasOperation()) {
           ModuleBase_Operation* aOperation = myOperationMgr->currentOperation();
-          if (aOperation->hasObject(aObj)) {  // Display only current operation results
+          if (!aOperation->hasObject(aObj))
+            if (!myDisplayer->isActive(aObj))
+              myDisplayer->activate(aObj, aModes);
+        }
+      } else {
+        if (myOperationMgr->hasOperation()) {
+          ModuleBase_Operation* aOperation = myOperationMgr->currentOperation();
+          // Display only current operation results if operation has preview
+          if (aOperation->hasObject(aObj) && aOperation->hasPreview()) {
             myDisplayer->display(aObj, false);
+            // Deactivate object of current operation from selection
+            if (myDisplayer->isActive(aObj))
+              myDisplayer->deactivate(aObj);
           }
         }
       }
@@ -364,7 +453,7 @@ void XGUI_Workshop::onFeatureRedisplayMsg(const ModelAPI_ObjectUpdatedMessage* t
 }
 
 //******************************************************
-void XGUI_Workshop::onFeatureCreatedMsg(const ModelAPI_ObjectUpdatedMessage* theMsg)
+void XGUI_Workshop::onFeatureCreatedMsg(const boost::shared_ptr<ModelAPI_ObjectUpdatedMessage>& theMsg)
 {
   std::set<ObjectPtr> aObjects = theMsg->objects();
 
@@ -385,18 +474,20 @@ void XGUI_Workshop::onFeatureCreatedMsg(const ModelAPI_ObjectUpdatedMessage* the
       }
     }
   }
+  if (myObjectBrowser)
+    myObjectBrowser->processEvent(theMsg);
   if (isDisplayed)
     myDisplayer->updateViewer();
-  if (aHasPart) {
-    //The created part will be created in Object Browser later and we have to activate it
-    // only when it is created everywere
-    QTimer::singleShot(50, this, SLOT(activateLastPart()));
-  }
+  //if (aHasPart) { // TODO: Avoid activate last part on loading of document
+  //  activateLastPart();
+  //}
 }
 
 //******************************************************
-void XGUI_Workshop::onObjectDeletedMsg(const ModelAPI_ObjectDeletedMessage* theMsg)
+void XGUI_Workshop::onObjectDeletedMsg(const boost::shared_ptr<ModelAPI_ObjectDeletedMessage>& theMsg)
 {
+  if (myObjectBrowser)
+    myObjectBrowser->processEvent(theMsg);
   //std::set<ObjectPtr> aFeatures = theMsg->objects();
 }
 
@@ -419,13 +510,12 @@ void XGUI_Workshop::onOperationStarted()
 
     myPropertyPanel->cleanContent();
     aFactory.createWidget(myPropertyPanel->contentWidget());
+    ModuleBase_Tools::zeroMargins(myPropertyPanel->contentWidget());
 
     QList<ModuleBase_ModelWidget*> aWidgets = aFactory.getModelWidgets();
-    QList<ModuleBase_ModelWidget*>::const_iterator anIt = aWidgets.begin(), aLast = aWidgets.end();
-    ModuleBase_ModelWidget* aWidget;
-    for (; anIt != aLast; anIt++) {
-      aWidget = *anIt;
+    foreach (ModuleBase_ModelWidget* aWidget, aWidgets) {
       aWidget->setFeature(aOperation->feature());
+      aWidget->enableFocusProcessing();
       QObject::connect(aWidget, SIGNAL(valuesChanged()), this, SLOT(onWidgetValuesChanged()));
       // Init default values
       if (!aOperation->isEditOperation() && !aWidget->isComputedDefault()) {
@@ -433,8 +523,15 @@ void XGUI_Workshop::onOperationStarted()
       }
     }
 
+    aOperation->setPropertyPanel(myPropertyPanel);
     myPropertyPanel->setModelWidgets(aWidgets);
-    myPropertyPanel->setWindowTitle(aOperation->getDescription()->description());
+    if (!aOperation->activateByPreselection())
+      myPropertyPanel->activateNextWidget(NULL);
+    // Widget activation (from the previous method) may commit the current operation
+    // if pre-selection is enougth for it. So we shouldn't update prop panel's title
+    if(myOperationMgr->isCurrentOperation(aOperation)) {
+      myPropertyPanel->setWindowTitle(aOperation->getDescription()->description());
+    }
   }
   updateCommandStatus();
 }
@@ -448,10 +545,21 @@ void XGUI_Workshop::onOperationStopped(ModuleBase_Operation* theOperation)
   myPropertyPanel->cleanContent();
 }
 
+bool XGUI_Workshop::event(QEvent * theEvent)
+{
+  PostponeMessageQtEvent* aPostponedEv = dynamic_cast<PostponeMessageQtEvent*>(theEvent);
+  if (aPostponedEv) {
+    boost::shared_ptr<Events_Message> aEventPtr = aPostponedEv->postponedMessage();
+    processEvent(aEventPtr);
+    return true;
+  }
+  return false;
+}
+
 /*
  *
  */
-void XGUI_Workshop::addFeature(const Config_FeatureMessage* theMessage)
+void XGUI_Workshop::addFeature(const boost::shared_ptr<Config_FeatureMessage>& theMessage)
 {
   if (!theMessage) {
 #ifdef _DEBUG
@@ -472,8 +580,11 @@ void XGUI_Workshop::addFeature(const Config_FeatureMessage* theMessage)
                                                      QString::fromStdString(theMessage->text()),
                                                      QString::fromStdString(theMessage->tooltip()),
                                                      QIcon(theMessage->icon().c_str()),
-                                                     QKeySequence(), isUsePropPanel);
+                                                     QKeySequence(),
+                                                     isUsePropPanel);
     salomeConnector()->setNestedActions(aFeatureId, aNestedFeatures.split(" ", QString::SkipEmptyParts));
+    salomeConnector()->setDocumentKind(aFeatureId, QString::fromStdString(theMessage->documentKind()));
+
     myActionsMgr->addCommand(aAction);
     myModule->featureCreated(aAction);
   } else {
@@ -489,6 +600,7 @@ void XGUI_Workshop::addFeature(const Config_FeatureMessage* theMessage)
     if (!aGroup) {
       aGroup = aPage->addGroup(aGroupName);
     }
+    QString aDocKind = QString::fromStdString(theMessage->documentKind());
     // Check if hotkey sequence is already defined:
     QKeySequence aHotKey = myActionsMgr->registerShortcut(
         QString::fromStdString(theMessage->keysequence()));
@@ -496,7 +608,9 @@ void XGUI_Workshop::addFeature(const Config_FeatureMessage* theMessage)
     XGUI_Command* aCommand = aGroup->addFeature(aFeatureId,
                                                 QString::fromStdString(theMessage->text()),
                                                 QString::fromStdString(theMessage->tooltip()),
-                                                QIcon(theMessage->icon().c_str()), aHotKey,
+                                                QIcon(theMessage->icon().c_str()),
+                                                aDocKind,
+                                                aHotKey,
                                                 isUsePropPanel);
     aCommand->setNestedCommands(aNestedFeatures.split(" ", QString::SkipEmptyParts));
     myActionsMgr->addCommand(aCommand);
@@ -516,11 +630,14 @@ void XGUI_Workshop::connectWithOperation(ModuleBase_Operation* theOperation)
     aCommand = salomeConnector()->command(theOperation->getDescription()->operationId());
   } else {
     XGUI_MainMenu* aMenu = myMainWindow->menuObject();
-    aCommand = aMenu->feature(theOperation->getDescription()->operationId());
+    FeaturePtr aFeature = theOperation->feature();
+    if(aFeature)
+      aCommand = aMenu->feature(QString::fromStdString(aFeature->getKind()));
   }
   //Abort operation on uncheck the command
-  if (aCommand)
+  if (aCommand) {
     connect(aCommand, SIGNAL(triggered(bool)), theOperation, SLOT(setRunning(bool)));
+  }
 }
 
 /*
@@ -534,6 +651,11 @@ void XGUI_Workshop::saveDocument(const QString& theName, std::list<std::string>&
   QApplication::restoreOverrideCursor();
 }
 
+bool XGUI_Workshop::isActiveOperationAborted()
+{
+  return myOperationMgr->abortAllOperations();
+}
+
 //******************************************************
 void XGUI_Workshop::onExit()
 {
@@ -577,7 +699,7 @@ void XGUI_Workshop::onNew()
 //******************************************************
 void XGUI_Workshop::onOpen()
 {
-  if(!myOperationMgr->abortOperation())
+  if(!isActiveOperationAborted())
     return;
   //save current file before close if modified
   SessionPtr aSession = ModelAPI_Session::get();
@@ -611,14 +733,13 @@ void XGUI_Workshop::onOpen()
   myObjectBrowser->rebuildDataTree();
   displayAllResults();
   updateCommandStatus();
-  myMainWindow->setCurrentDir(myCurrentDir);
   QApplication::restoreOverrideCursor();
 }
 
 //******************************************************
 bool XGUI_Workshop::onSave()
 {
-  if(!myOperationMgr->abortOperation())
+  if(!isActiveOperationAborted())
     return false;
   if (myCurrentDir.isEmpty()) {
     return onSaveAs();
@@ -633,7 +754,7 @@ bool XGUI_Workshop::onSave()
 //******************************************************
 bool XGUI_Workshop::onSaveAs()
 {
-  if(!myOperationMgr->abortOperation())
+  if(!isActiveOperationAborted())
     return false;
   QFileDialog dialog(mainWindow());
   dialog.setWindowTitle(tr("Select directory to save files..."));
@@ -672,7 +793,7 @@ void XGUI_Workshop::onUndo()
   objectBrowser()->treeView()->setCurrentIndex(QModelIndex());
   SessionPtr aMgr = ModelAPI_Session::get();
   if (aMgr->isOperation())
-    operationMgr()->abortOperation();
+    operationMgr()->onAbortOperation();
   aMgr->undo();
   updateCommandStatus();
 }
@@ -683,11 +804,27 @@ void XGUI_Workshop::onRedo()
   objectBrowser()->treeView()->setCurrentIndex(QModelIndex());
   SessionPtr aMgr = ModelAPI_Session::get();
   if (aMgr->isOperation())
-    operationMgr()->abortOperation();
+    operationMgr()->onAbortOperation();
   aMgr->redo();
   updateCommandStatus();
 }
 
+//******************************************************
+void XGUI_Workshop::onRebuild()
+{
+  SessionPtr aMgr = ModelAPI_Session::get();
+  bool aWasOperation = aMgr->isOperation(); // keep this value
+  if (!aWasOperation) {
+    aMgr->startOperation();
+  }
+  static const Events_ID aRebuildEvent = Events_Loop::loop()->eventByName("Rebuild");
+  Events_Loop::loop()->send(boost::shared_ptr<Events_Message>(
+    new Events_Message(aRebuildEvent, this)));
+  if (!aWasOperation) {
+    aMgr->finishOperation();
+  }
+}
+
 //******************************************************
 void XGUI_Workshop::onPreferences()
 {
@@ -756,11 +893,11 @@ ModuleBase_IModule* XGUI_Workshop::loadModule(const QString& theModule)
   }
 #endif
 
-  ModuleBase_IModule* aModule = crtInst ? crtInst(this) : 0;
+  ModuleBase_IModule* aModule = crtInst ? crtInst(myModuleConnector) : 0;
 
   if (!err.isEmpty()) {
     if (mainWindow()) {
-      QMessageBox::warning(mainWindow(), tr("Error"), err);
+      Events_Error::send(err.toStdString());
     } else {
       qWarning(qPrintable(err));
     }
@@ -794,10 +931,8 @@ void XGUI_Workshop::updateCommandStatus()
   }
   SessionPtr aMgr = ModelAPI_Session::get();
   if (aMgr->hasModuleDocument()) {
-    QAction* aUndoCmd;
-    QAction* aRedoCmd;
-    foreach(QAction* aCmd, aCommands)
-    {
+    QAction *aUndoCmd, *aRedoCmd;
+    foreach(QAction* aCmd, aCommands) {
       QString aId = aCmd->data().toString();
       if (aId == "UNDO_CMD")
         aUndoCmd = aCmd;
@@ -807,11 +942,10 @@ void XGUI_Workshop::updateCommandStatus()
         // Enable all commands
         aCmd->setEnabled(true);
     }
-    aUndoCmd->setEnabled(aMgr->canUndo());
-    aRedoCmd->setEnabled(aMgr->canRedo());
+    aUndoCmd->setEnabled(aMgr->canUndo() && !aMgr->isOperation());
+    aRedoCmd->setEnabled(aMgr->canRedo() && !aMgr->isOperation());
   } else {
-    foreach(QAction* aCmd, aCommands)
-    {
+    foreach(QAction* aCmd, aCommands) {
       QString aId = aCmd->data().toString();
       if (aId == "NEW_CMD")
         aCmd->setEnabled(true);
@@ -873,19 +1007,14 @@ void XGUI_Workshop::createDockWidgets()
   hidePropertyPanel();  //<! Invisible by default
   hideObjectBrowser();
   aDesktop->tabifyDockWidget(aObjDock, myPropertyPanel);
+  myPropertyPanel->installEventFilter(myOperationMgr);
 
   QPushButton* aOkBtn = myPropertyPanel->findChild<QPushButton*>(XGUI::PROP_PANEL_OK);
   connect(aOkBtn, SIGNAL(clicked()), myOperationMgr, SLOT(onCommitOperation()));
   QPushButton* aCancelBtn = myPropertyPanel->findChild<QPushButton*>(XGUI::PROP_PANEL_CANCEL);
   connect(aCancelBtn, SIGNAL(clicked()), myOperationMgr, SLOT(onAbortOperation()));
-//TODO(sbh): KeyReleasedProblem
   connect(myPropertyPanel, SIGNAL(keyReleased(QKeyEvent*)), myOperationMgr,
           SLOT(onKeyReleased(QKeyEvent*)));
-
-  connect(myPropertyPanel, SIGNAL(widgetActivated(ModuleBase_ModelWidget*)), myOperationMgr,
-          SLOT(onWidgetActivated(ModuleBase_ModelWidget*)));
-  connect(myOperationMgr, SIGNAL(activateNextWidget(ModuleBase_ModelWidget*)), myPropertyPanel,
-          SLOT(onActivateNextWidget(ModuleBase_ModelWidget*)));
   connect(myOperationMgr, SIGNAL(operationValidated(bool)), myPropertyPanel,
           SLOT(setAcceptEnabled(bool)));
 
@@ -957,7 +1086,7 @@ void XGUI_Workshop::salomeViewerSelectionChanged()
 }
 
 //**************************************************************
-XGUI_SalomeViewer* XGUI_Workshop::salomeViewer() const
+ModuleBase_IViewer* XGUI_Workshop::salomeViewer() const
 {
   return mySalomeConnector->viewer();
 }
@@ -979,6 +1108,12 @@ void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked)
     showObjects(aObjects, false);
   else if (theId == "SHOW_ONLY_CMD")
     showOnlyObjects(aObjects);
+  else if (theId == "SHADING_CMD")
+    setDisplayMode(aObjects, XGUI_Displayer::Shading);
+  else if (theId == "WIREFRAME_CMD")
+    setDisplayMode(aObjects, XGUI_Displayer::Wireframe);
+  else if (theId == "HIDEALL_CMD")
+    myDisplayer->eraseAll();
 }
 
 //**************************************************************
@@ -1005,10 +1140,14 @@ void XGUI_Workshop::onWidgetValuesChanged()
 //**************************************************************
 void XGUI_Workshop::activatePart(ResultPartPtr theFeature)
 {
-  if (theFeature)
-    theFeature->activate();
-  changeCurrentDocument(theFeature);
-  myObjectBrowser->activatePart(theFeature);
+  if (!myPartActivating) {
+    myPartActivating = true;
+    if (theFeature)
+      theFeature->activate();
+    changeCurrentDocument(theFeature);
+    myObjectBrowser->activatePart(theFeature);
+    myPartActivating = false;
+  }
 }
 
 //**************************************************************
@@ -1019,8 +1158,9 @@ void XGUI_Workshop::activateLastPart()
   std::string aGrpName = ModelAPI_ResultPart::group();
   ObjectPtr aLastPart = aDoc->object(aGrpName, aDoc->size(aGrpName) - 1);
   ResultPartPtr aPart = boost::dynamic_pointer_cast<ModelAPI_ResultPart>(aLastPart);
-  if (aPart)
+  if (aPart) {
     activatePart(aPart);
+  }
 }
 
 //**************************************************************
@@ -1082,16 +1222,27 @@ void XGUI_Workshop::showOnlyObjects(const QList<ObjectPtr>& theList)
 //**************************************************************
 void XGUI_Workshop::updateCommandsOnViewSelection()
 {
-  SessionPtr aMgr = ModelAPI_Session::get();
-  ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
   XGUI_Selection* aSelection = mySelector->selection();
   if (aSelection->getSelected().size() == 0)
     return;
 
+  // Restrict validators to manage only nested (child) features
+  // of the current feature i.e. if current feature is Sketch -
+  // Sketch Features & Constraints can be validated.
+  QStringList aNestedIds;
+  if(myOperationMgr->hasOperation()) {
+    FeaturePtr aFeature = myOperationMgr->currentOperation()->feature();
+    if(aFeature) {
+      aNestedIds << myActionsMgr->nestedCommands(QString::fromStdString(aFeature->getKind()));
+    }
+  }
+  SessionPtr aMgr = ModelAPI_Session::get();
+  ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
   QList<QAction*> aActions = getModuleCommands();
-  foreach(QAction* aAction, aActions)
-  {
+  foreach(QAction* aAction, aActions) {
     QString aId = aAction->data().toString();
+    if(!aNestedIds.contains(aId))
+      continue;
     std::list<ModelAPI_Validator*> aValidators;
     std::list<std::list<std::string> > anArguments;
     aFactory->validators(aId.toStdString(), aValidators, anArguments);
@@ -1144,3 +1295,25 @@ void XGUI_Workshop::displayGroupResults(DocumentPtr theDoc, std::string theGroup
   for (int i = 0; i < theDoc->size(theGroup); i++)
     myDisplayer->display(theDoc->object(theGroup, i), false);
 }
+
+//**************************************************************
+void XGUI_Workshop::setDisplayMode(const QList<ObjectPtr>& theList, int theMode)
+{
+  foreach(ObjectPtr aObj, theList) {
+    myDisplayer->setDisplayMode(aObj, (XGUI_Displayer::DisplayMode)theMode, false);
+  }
+  if (theList.size() > 0)
+    myDisplayer->updateViewer();
+}
+
+//**************************************************************
+void XGUI_Workshop::closeDocument()
+{
+  myDisplayer->closeLocalContexts();
+  myDisplayer->eraseAll();
+  objectBrowser()->clearContent();
+
+  SessionPtr aMgr = ModelAPI_Session::get();
+  aMgr->moduleDocument()->close();
+  objectBrowser()->clearContent();
+}