]> SALOME platform Git repositories - modules/shaper.git/blob - src/XGUI/XGUI_Workshop.cpp
Salome HOME
ec47de5242a4ce85db6ade62e39c38c830ae93ae
[modules/shaper.git] / src / XGUI / XGUI_Workshop.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 //#include "XGUI_Constants.h"
4 #include "XGUI_Workshop.h"
5
6 #include "XGUI_ActionsMgr.h"
7 #include "XGUI_MenuMgr.h"
8 #include "XGUI_ColorDialog.h"
9 #include "XGUI_ContextMenuMgr.h"
10 #include "XGUI_Displayer.h"
11 #include "XGUI_ErrorDialog.h"
12 #include "XGUI_ErrorMgr.h"
13 #include "XGUI_ModuleConnector.h"
14 #include "XGUI_ObjectsBrowser.h"
15 #include "XGUI_OperationMgr.h"
16 #include "XGUI_PropertyPanel.h"
17 #include "XGUI_SalomeConnector.h"
18 #include "XGUI_Selection.h"
19 #include "XGUI_SelectionMgr.h"
20 #include "XGUI_Tools.h"
21 #include "XGUI_ViewerProxy.h"
22 #include "XGUI_WorkshopListener.h"
23 #include <XGUI_CustomPrs.h>
24 #include <XGUI_HistoryMenu.h>
25 #include <XGUI_QtEvents.h>
26
27 #ifndef HAVE_SALOME
28 #include <AppElements_Button.h>
29 #include <AppElements_Command.h>
30 #include <AppElements_MainMenu.h>
31 #include <AppElements_MainWindow.h>
32 #include <AppElements_MenuGroupPanel.h>
33 #include <AppElements_Viewer.h>
34 #include <AppElements_Workbench.h>
35 #endif
36
37 #include <ModelAPI_AttributeDocRef.h>
38 #include <ModelAPI_AttributeIntArray.h>
39 #include <ModelAPI_Data.h>
40 #include <ModelAPI_Events.h>
41 #include <ModelAPI_Feature.h>
42 #include <ModelAPI_Object.h>
43 #include <ModelAPI_ResultBody.h>
44 #include <ModelAPI_ResultConstruction.h>
45 #include <ModelAPI_ResultGroup.h>
46 #include <ModelAPI_ResultParameter.h>
47 #include <ModelAPI_Session.h>
48 #include <ModelAPI_Validator.h>
49 #include <ModelAPI_ResultCompSolid.h>
50 #include <ModelAPI_Tools.h>
51
52 //#include <PartSetPlugin_Part.h>
53
54 #include <Events_Loop.h>
55 #include <Events_Error.h>
56 #include <Events_LongOp.h>
57
58 #include <ModuleBase_FilterFactory.h>
59 #include <ModuleBase_IModule.h>
60 #include <ModuleBase_IViewer.h>
61 #include <ModuleBase_Operation.h>
62 #include <ModuleBase_OperationDescription.h>
63 #include <ModuleBase_PageBase.h>
64 #include <ModuleBase_Preferences.h>
65 #include <ModuleBase_SelectionValidator.h>
66 #include <ModuleBase_Tools.h>
67 #include <ModuleBase_WidgetFactory.h>
68 #include <ModuleBase_OperationFeature.h>
69 #include <ModuleBase_OperationAction.h>
70 #include <ModuleBase_PagedContainer.h>
71 #include <ModuleBase_WidgetValidated.h>
72 #include <ModuleBase_ModelWidget.h>
73
74 #include <Config_Common.h>
75 #include <Config_FeatureMessage.h>
76 #include <Config_ModuleReader.h>
77 #include <Config_PointerMessage.h>
78 #include <Config_PropManager.h>
79 #include <Config_SelectionFilterMessage.h>
80 #include <Config_DataModelReader.h>
81
82 #include <SUIT_ResourceMgr.h>
83
84 #include <QApplication>
85 #include <QFileDialog>
86 #include <QMessageBox>
87 #include <QMdiSubWindow>
88 #include <QMainWindow>
89 #include <QPushButton>
90 #include <QDockWidget>
91 #include <QLayout>
92 #include <QThread>
93 #include <QObject>
94 #include <QMenu>
95 #include <QToolButton>
96 #include <QAction>
97 #include <QDesktopWidget>
98
99 #include <iterator>
100
101 //#define DEBUG_CLEAN_HISTORY
102
103 #ifdef _DEBUG
104 #include <QDebug>
105 #include <iostream>
106 #endif
107
108 #ifdef WIN32
109 #include <windows.h>
110 #else
111 #include <dlfcn.h>
112 #endif
113
114
115 QString XGUI_Workshop::MOVE_TO_END_COMMAND = QObject::tr("Move to the end");
116
117 //#define DEBUG_DELETE
118 //#define DEBUG_FEATURE_NAME
119
120 XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
121     : QObject(),
122       myCurrentDir(QString()),
123       myModule(NULL),
124       mySalomeConnector(theConnector),
125       myPropertyPanel(0),
126       myObjectBrowser(0),
127       myDisplayer(0)
128       //myViewerSelMode(TopAbs_FACE)
129 {
130 #ifndef HAVE_SALOME
131   myMainWindow = new AppElements_MainWindow();
132
133   SUIT_ResourceMgr* aResMgr = ModuleBase_Preferences::resourceMgr();
134   bool aCloc = aResMgr->booleanValue("language", "locale", true);
135   if (aCloc)
136     QLocale::setDefault( QLocale::c() );
137   else 
138     QLocale::setDefault( QLocale::system() );
139 #endif
140
141   myDataModelXMLReader = new Config_DataModelReader();
142   myDataModelXMLReader->readAll();
143
144   myDisplayer = new XGUI_Displayer(this);
145
146   mySelector = new XGUI_SelectionMgr(this);
147   connect(mySelector, SIGNAL(selectionChanged()), this, SLOT(updateCommandStatus()));
148
149   myOperationMgr = new XGUI_OperationMgr(this, 0);
150   myActionsMgr = new XGUI_ActionsMgr(this);
151   myMenuMgr = new XGUI_MenuMgr(this);
152   myErrorDlg = new XGUI_ErrorDialog(QApplication::desktop());
153   myContextMenuMgr = new XGUI_ContextMenuMgr(this);
154   connect(myContextMenuMgr, SIGNAL(actionTriggered(const QString&, bool)), this,
155           SLOT(onContextMenuCommand(const QString&, bool)));
156
157   myViewerProxy = new XGUI_ViewerProxy(this);
158   //connect(myViewerProxy, SIGNAL(selectionChanged()),
159   //        myActionsMgr,  SLOT(updateOnViewSelection()));
160
161   myModuleConnector = new XGUI_ModuleConnector(this);
162
163   ModuleBase_IWorkshop* aWorkshop = moduleConnector();
164   myOperationMgr->setWorkshop(aWorkshop);
165
166   myErrorMgr = new XGUI_ErrorMgr(this, aWorkshop);
167   myEventsListener = new XGUI_WorkshopListener(aWorkshop);
168
169   connect(myOperationMgr, SIGNAL(operationStarted(ModuleBase_Operation*)), 
170           SLOT(onOperationStarted(ModuleBase_Operation*)));
171   connect(myOperationMgr, SIGNAL(operationResumed(ModuleBase_Operation*)),
172           SLOT(onOperationResumed(ModuleBase_Operation*)));
173   connect(myOperationMgr, SIGNAL(operationStopped(ModuleBase_Operation*)),
174           SLOT(onOperationStopped(ModuleBase_Operation*)));
175   connect(myOperationMgr, SIGNAL(operationCommitted(ModuleBase_Operation*)), 
176           SLOT(onOperationCommitted(ModuleBase_Operation*)));
177   connect(myOperationMgr, SIGNAL(operationAborted(ModuleBase_Operation*)), 
178           SLOT(onOperationAborted(ModuleBase_Operation*)));
179
180 #ifndef HAVE_SALOME
181   connect(myMainWindow, SIGNAL(exitKeySequence()), SLOT(onExit()));
182   onTrihedronVisibilityChanged(true);
183 #endif
184
185   connect(this, SIGNAL(errorOccurred(const QString&)), myErrorDlg, SLOT(addError(const QString&)));
186   connect(myEventsListener, SIGNAL(errorOccurred(const QString&)),
187           myErrorDlg, SLOT(addError(const QString&)));
188
189   //Config_PropManager::registerProp("Visualization", "object_default_color", "Object color",
190   //                                 Config_Prop::Color, "225,225,225");
191
192   Config_PropManager::registerProp("Visualization", "result_body_color", "Body color",
193                                    Config_Prop::Color, ModelAPI_ResultBody::DEFAULT_COLOR());
194   Config_PropManager::registerProp("Visualization", "result_group_color", "Group color",
195                                    Config_Prop::Color, ModelAPI_ResultGroup::DEFAULT_COLOR());
196   Config_PropManager::registerProp("Visualization", "result_construction_color", "Construction color",
197                                    Config_Prop::Color, ModelAPI_ResultConstruction::DEFAULT_COLOR());
198   Config_PropManager::registerProp("Visualization", "result_part_color", "Part color",
199                                    Config_Prop::Color, ModelAPI_ResultPart::DEFAULT_COLOR());
200   
201   if (ModuleBase_Preferences::resourceMgr()->booleanValue("Viewer", "face-selection", true))
202     myViewerSelMode.append(TopAbs_FACE);
203   if (ModuleBase_Preferences::resourceMgr()->booleanValue("Viewer", "edge-selection", true))
204     myViewerSelMode.append(TopAbs_EDGE);
205   if (ModuleBase_Preferences::resourceMgr()->booleanValue("Viewer", "vertex-selection", true))
206     myViewerSelMode.append(TopAbs_VERTEX);
207 }
208
209 //******************************************************
210 XGUI_Workshop::~XGUI_Workshop(void)
211 {
212   delete myDisplayer;
213   delete myDataModelXMLReader;
214 }
215
216 //******************************************************
217 void XGUI_Workshop::startApplication()
218 {
219   initMenu();
220
221   Config_PropManager::registerProp("Plugins", "default_path", "Default Path",
222                                    Config_Prop::Directory, "");
223
224   //Initialize event listening
225   myEventsListener->initializeEventListening();
226
227   registerValidators();
228
229   // Calling of  loadCustomProps before activating module is required
230   // by Config_PropManger to restore user-defined path to plugins
231   ModuleBase_Preferences::loadCustomProps();
232   createModule();
233
234 #ifndef HAVE_SALOME
235   myMainWindow->show();
236   updateCommandStatus();
237 #endif
238   
239   onNew();
240
241   myViewerProxy->connectViewProxy();
242   connect(myViewerProxy, SIGNAL(trihedronVisibilityChanged(bool)),
243           SLOT(onTrihedronVisibilityChanged(bool)));
244
245   emit applicationStarted();
246 }
247
248 void XGUI_Workshop::activateModule()
249 {
250   myModule->activateSelectionFilters();
251
252   connect(myDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)),
253     myModule, SLOT(onObjectDisplayed(ObjectPtr, AISObjectPtr)));
254   connect(myDisplayer, SIGNAL(beforeObjectErase(ObjectPtr, AISObjectPtr)),
255     myModule, SLOT(onBeforeObjectErase(ObjectPtr, AISObjectPtr)));
256
257   updateCommandStatus();
258
259   // TODO: get default selection mode
260
261   // activate visualized objects in the viewer
262   activateObjectsSelection(displayer()->displayedObjects());
263   myOperationMgr->activate();
264 }
265
266 void XGUI_Workshop::deactivateModule()
267 {
268   myModule->deactivateSelectionFilters();
269
270   // remove internal displayer filter
271   displayer()->deactivateSelectionFilters();
272
273   disconnect(myDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)),
274     myModule, SLOT(onObjectDisplayed(ObjectPtr, AISObjectPtr)));
275   disconnect(myDisplayer, SIGNAL(beforeObjectErase(ObjectPtr, AISObjectPtr)),
276     myModule, SLOT(onBeforeObjectErase(ObjectPtr, AISObjectPtr)));
277
278   XGUI_Displayer* aDisplayer = displayer();
279   QObjectPtrList aDisplayed = aDisplayer->displayedObjects();
280   aDisplayer->deactivateObjects(aDisplayed, true);
281
282   myOperationMgr->deactivate();
283 }
284
285 //******************************************************
286 void XGUI_Workshop::initMenu()
287 {
288   myContextMenuMgr->createActions();
289
290 #ifdef HAVE_SALOME
291   // Create only Undo, Redo commands
292   QAction* aAction = salomeConnector()->addDesktopCommand("UNDO_CMD", tr("Undo"),
293                                                         tr("Undo last command"),
294                                                         QIcon(":pictures/undo.png"),
295                                                         QKeySequence::Undo, false, "MEN_DESK_EDIT");
296   QString aToolBarTitle = tr( "INF_DESK_TOOLBAR_STANDARD" );
297   salomeConnector()->addActionInToolbar( aAction,aToolBarTitle  );
298
299   connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onUndo()));
300   addHistoryMenu(aAction, SIGNAL(updateUndoHistory(const QList<ActionInfo>&)), SLOT(onUndo(int)));
301
302   aAction = salomeConnector()->addDesktopCommand("REDO_CMD", tr("Redo"), tr("Redo last command"),
303                                               QIcon(":pictures/redo.png"), QKeySequence::Redo,
304                                               false, "MEN_DESK_EDIT");
305   salomeConnector()->addActionInToolbar( aAction, aToolBarTitle );
306
307   connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onRedo()));
308   addHistoryMenu(aAction, SIGNAL(updateRedoHistory(const QList<ActionInfo>&)), SLOT(onRedo(int)));
309
310   salomeConnector()->addDesktopMenuSeparator("MEN_DESK_EDIT");
311   //aAction = salomeConnector()->addDesktopCommand("REBUILD_CMD", tr("Rebuild"), tr("Rebuild data objects"),
312   //                                            QIcon(":pictures/rebuild.png"), QKeySequence(),
313   //                                            false, "MEN_DESK_EDIT");
314   //salomeConnector()->addActionInToolbar( aAction, aToolBarTitle );
315
316   //connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onRebuild()));
317   //salomeConnector()->addDesktopMenuSeparator("MEN_DESK_EDIT");
318
319   aAction = salomeConnector()->addDesktopCommand("SAVEAS_CMD", tr("Export native..."), tr("Export the current document into a native file"),
320                                               QIcon(), QKeySequence(),
321                                               false, "MEN_DESK_FILE");
322   connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onSaveAs()));
323
324   aAction = salomeConnector()->addDesktopCommand("OPEN_CMD", tr("Import native..."), tr("Import native file"),
325                                               QIcon(), QKeySequence(),
326                                               false, "MEN_DESK_FILE");
327   connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onOpen()));
328   salomeConnector()->addDesktopMenuSeparator("MEN_DESK_FILE");
329
330 #else
331   // File commands group
332   AppElements_MenuGroupPanel* aGroup = myMainWindow->menuObject()->generalPage();
333
334   AppElements_Command* aCommand;
335
336   aCommand = aGroup->addFeature("SAVE_CMD", tr("Save"), tr("Save the document"),
337                                 QIcon(":pictures/save.png"), QKeySequence::Save);
338   aCommand->connectTo(this, SLOT(onSave()));
339   //aCommand->disable();
340
341   aCommand = aGroup->addFeature("SAVEAS_CMD", tr("Save as..."), tr("Save the document into a file"),
342                                 QIcon(":pictures/save.png"), QKeySequence());
343   aCommand->connectTo(this, SLOT(onSaveAs()));
344
345   QString aUndoId = "UNDO_CMD";
346   aCommand = aGroup->addFeature(aUndoId, tr("Undo"), tr("Undo last command"),
347                                 QIcon(":pictures/undo.png"), QKeySequence::Undo);
348   aCommand->connectTo(this, SLOT(onUndo()));
349   AppElements_Button* aUndoButton = qobject_cast<AppElements_Button*>(aGroup->widget(aUndoId));
350   addHistoryMenu(aUndoButton,
351                  SIGNAL(updateUndoHistory(const QList<ActionInfo>&)),
352                  SLOT(onUndo(int)));
353
354   QString aRedoId = "REDO_CMD";
355   aCommand = aGroup->addFeature(aRedoId, tr("Redo"), tr("Redo last command"),
356                                 QIcon(":pictures/redo.png"), QKeySequence::Redo);
357   aCommand->connectTo(this, SLOT(onRedo()));
358   AppElements_Button* aRedoButton = qobject_cast<AppElements_Button*>(aGroup->widget(aRedoId));
359   addHistoryMenu(aRedoButton,
360                  SIGNAL(updateRedoHistory(const QList<ActionInfo>&)),
361                  SLOT(onRedo(int)));
362
363   //aCommand = aGroup->addFeature("REBUILD_CMD", tr("Rebuild"), tr("Rebuild data objects"),
364   //  QIcon(":pictures/rebuild.png"), QKeySequence());
365   //aCommand->connectTo(this, SLOT(onRebuild()));
366
367   //aCommand->disable();
368
369   aCommand = aGroup->addFeature("OPEN_CMD", tr("Open..."), tr("Open a new document"),
370                                 QIcon(":pictures/open.png"), QKeySequence::Open);
371   aCommand->connectTo(this, SLOT(onOpen()));
372
373   aCommand = aGroup->addFeature("PREF_CMD", tr("Preferences"), tr("Edit preferences"),
374                                 QIcon(":pictures/preferences.png"), QKeySequence::Preferences);
375   aCommand->connectTo(this, SLOT(onPreferences()));
376
377   aCommand = aGroup->addFeature("EXIT_CMD", tr("Exit"), tr("Exit application"),
378                                 QIcon(":pictures/close.png"), QKeySequence::Close);
379   aCommand->connectTo(this, SLOT(onExit()));
380 #endif
381 }
382
383 #ifndef HAVE_SALOME
384 AppElements_Workbench* XGUI_Workshop::addWorkbench(const QString& theName)
385 {
386   AppElements_MainMenu* aMenuBar = myMainWindow->menuObject();
387   return aMenuBar->addWorkbench(theName);
388 }
389 #endif
390
391 //******************************************************
392 QMainWindow* XGUI_Workshop::desktop() const
393 {
394 #ifdef HAVE_SALOME
395   return salomeConnector()->desktop();
396 #else
397   return myMainWindow;
398 #endif
399 }
400
401 //******************************************************
402 void XGUI_Workshop::onStartWaiting()
403 {
404   if (Events_LongOp::isPerformed()) {
405     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
406   }
407 }
408
409 //******************************************************
410 void XGUI_Workshop::onAcceptActionClicked()
411 {
412   QAction* anAction = dynamic_cast<QAction*>(sender());
413   XGUI_OperationMgr* anOperationMgr = operationMgr();
414   if (anOperationMgr) {
415     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
416                                                     (anOperationMgr->currentOperation());
417     if (aFOperation) {
418       //if (errorMgr()->canProcessClick(anAction, aFOperation->feature()))
419       myOperationMgr->onCommitOperation();
420     }
421   }
422 }
423
424 //******************************************************
425 void XGUI_Workshop::onPreviewActionClicked()
426 {
427   ModuleBase_IPropertyPanel* aPanel = propertyPanel();
428   if (aPanel) {
429     ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
430     if (anActiveWidget && anActiveWidget->getValueState() == ModuleBase_ModelWidget::ModifiedInPP) {
431       anActiveWidget->storeValue();
432     }
433   }
434   std::shared_ptr<Events_Message> aMsg = std::shared_ptr<Events_Message>(
435                 new Events_Message(Events_Loop::eventByName(EVENT_PREVIEW_REQUESTED)));
436   Events_Loop::loop()->send(aMsg);
437 }
438
439 //******************************************************
440 void XGUI_Workshop::deactivateActiveObject(const ObjectPtr& theObject, const bool theUpdateViewer)
441 {
442   if (!myModule->canActivateSelection(theObject)) {
443     if (myDisplayer->isActive(theObject)) {
444       QObjectPtrList anObjects;
445       anObjects.append(theObject);
446       myDisplayer->deactivateObjects(anObjects, theUpdateViewer);
447     }
448   }
449 }
450
451 //******************************************************
452 bool XGUI_Workshop::isFeatureOfNested(const FeaturePtr& theFeature)
453 {
454   bool aHasNested = false;
455   std::string aFeatureKind = theFeature->getKind();
456 #ifdef HAVE_SALOME
457     XGUI_SalomeConnector* aSalomeConnector = salomeConnector();
458     if (aSalomeConnector->isFeatureOfNested(actionsMgr()->action(aFeatureKind.c_str())))
459       aHasNested = true;
460 #else 
461     AppElements_MainMenu* aMenuBar = mainWindow()->menuObject();
462     AppElements_Command* aCommand = aMenuBar->feature(aFeatureKind.c_str());
463     if (aCommand && aCommand->button()->additionalButtonWidget())
464       aHasNested = true;
465 #endif
466   return aHasNested;
467 }
468
469 void XGUI_Workshop::setPropertyPanel(ModuleBase_Operation* theOperation)
470 {
471   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
472   if (!aFOperation)
473     return;
474
475   showPropertyPanel();
476   myPropertyPanel->cleanContent();
477
478   QList<ModuleBase_ModelWidget*> aWidgets;
479   if (!module()->createWidgets(theOperation, aWidgets)) {
480     QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation();
481     ModuleBase_WidgetFactory aFactory(aXmlRepr.toStdString(), myModuleConnector);
482     aFactory.createWidget(myPropertyPanel->contentWidget());
483     aWidgets = aFactory.getModelWidgets();
484   }
485
486   // check compatibility of feature and widgets
487   FeaturePtr aFeature = aFOperation->feature();
488   std::string aFeatureKind = aFeature->getKind();
489   foreach (ModuleBase_ModelWidget* aWidget, aWidgets) {
490     if (!aWidget->attributeID().empty() && !aFeature->attribute(aWidget->attributeID()).get()) {
491       std::string anErrorMsg = "The feature '" + aFeatureKind + "' has no attribute '"
492           + aWidget->attributeID() + "' used by widget '"
493           + aWidget->metaObject()->className() + "'.";
494       Events_Error::send(anErrorMsg);
495       myPropertyPanel->cleanContent();
496       return;
497     }
498   }
499   // for performance purpose, flush should be done after all controls are filled
500   bool isUpdateFlushed = false;
501   foreach (ModuleBase_ModelWidget* aWidget, aWidgets) {
502     bool isStoreValue = !aFOperation->isEditOperation() &&
503                         !aWidget->getDefaultValue().empty() &&
504                         !aWidget->isComputedDefault();
505     aWidget->setFeature(aFeature, isStoreValue, isUpdateFlushed);
506     if (!isStoreValue)
507       aWidget->restoreValue();
508     aWidget->enableFocusProcessing();
509   }
510   ModuleBase_Tools::flushUpdated(aFeature);
511
512   // update visible state of Preview button
513 #ifdef HAVE_SALOME
514   bool anIsAutoPreview = mySalomeConnector->featureInfo(aFeatureKind.c_str())->isAutoPreview();
515 #else
516   AppElements_MainMenu* aMenuBar = mainWindow()->menuObject();
517   AppElements_Command* aCommand = aMenuBar->feature(aFeatureKind.c_str());
518   bool anIsAutoPreview = aCommand && aCommand->featureMessage()->isAutoPreview();
519 #endif
520   if (!anIsAutoPreview) {
521     myPropertyPanel->findButton(PROP_PANEL_PREVIEW)->setVisible(true);
522     // send signal about preview should not be computed automatically, click on preview
523     // button should initiate it
524     std::shared_ptr<Events_Message> aMsg = std::shared_ptr<Events_Message>(
525                   new Events_Message(Events_Loop::eventByName(EVENT_PREVIEW_BLOCKED)));
526     Events_Loop::loop()->send(aMsg);
527   }
528   myPropertyPanel->setModelWidgets(aWidgets);
529   aFOperation->setPropertyPanel(myPropertyPanel);
530
531   myModule->propertyPanelDefined(theOperation);
532
533 #ifndef DEBUG_FEATURE_NAME
534   myPropertyPanel->setWindowTitle(theOperation->getDescription()->description());
535 #else
536   std::string aFeatureName = aFeature->name();
537   myPropertyPanel->setWindowTitle(QString("%1: %2").arg(theOperation->getDescription()->description())
538                                                   .arg(aFeatureName.c_str()));
539 #endif
540
541   myErrorMgr->setPropertyPanel(myPropertyPanel);
542 }
543
544 void XGUI_Workshop::connectToPropertyPanel(const bool isToConnect)
545 {
546   XGUI_PropertyPanel* aPropertyPanel = propertyPanel();
547   if (aPropertyPanel) {
548     const QList<ModuleBase_ModelWidget*>& aWidgets = aPropertyPanel->modelWidgets();
549     foreach (ModuleBase_ModelWidget* aWidget, aWidgets) {
550        myModule->connectToPropertyPanel(aWidget, isToConnect);
551        if (isToConnect) {
552         connect(aWidget, SIGNAL(valueStateChanged(int)), this, SLOT(onWidgetStateChanged(int)));
553         connect(aWidget, SIGNAL(valuesChanged()), this, SLOT(onValuesChanged()));
554         connect(aWidget, SIGNAL(objectUpdated()), this, SLOT(onWidgetObjectUpdated()));
555        }
556       else {
557         disconnect(aWidget, SIGNAL(valueStateChanged(int)), this, SLOT(onWidgetStateChanged(int)));
558         disconnect(aWidget, SIGNAL(valuesChanged()), this, SLOT(onValuesChanged()));
559         disconnect(aWidget, SIGNAL(objectUpdated()), this, SLOT(onWidgetObjectUpdated()));
560       }
561     }
562   }
563 }
564
565 //******************************************************
566 void XGUI_Workshop::onOperationStarted(ModuleBase_Operation* theOperation)
567 {
568   setGrantedFeatures(theOperation);
569   myModule->operationStarted(theOperation);
570 }
571
572 //******************************************************
573 void XGUI_Workshop::onOperationResumed(ModuleBase_Operation* theOperation)
574 {
575   setGrantedFeatures(theOperation);
576
577   if (theOperation->getDescription()->hasXmlRepresentation()) {  //!< No need for property panel
578     setPropertyPanel(theOperation);
579     connectToPropertyPanel(true);
580   }
581   updateCommandStatus();
582
583   myModule->operationResumed(theOperation);
584 }
585
586
587 //******************************************************
588 void XGUI_Workshop::onOperationStopped(ModuleBase_Operation* theOperation)
589 {
590   updateCommandStatus();
591
592   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
593                                                                         (theOperation);
594   if (!aFOperation)
595     return;
596
597   ModuleBase_ISelection* aSel = mySelector->selection();
598   QObjectPtrList aObj = aSel->selectedPresentations();
599   //!< No need for property panel
600   hidePropertyPanel();
601   myPropertyPanel->cleanContent();
602
603   connectToPropertyPanel(false);
604   myModule->operationStopped(aFOperation);
605
606   // the deactivated objects of the current operation should be activated back.
607   // They were deactivated on operation start or an object redisplay
608   QObjectPtrList anObjects;
609   FeaturePtr aFeature = aFOperation->feature();
610   if (aFeature.get()) { // feature may be not created (plugin load fail)
611     if (myDisplayer->isVisible(aFeature) && !myDisplayer->isActive(aFeature))
612       anObjects.append(aFeature);
613     std::list<ResultPtr> aResults = aFeature->results();
614     std::list<ResultPtr>::const_iterator aIt;
615     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
616       ResultPtr anObject = *aIt;
617       if (myDisplayer->isVisible(anObject) && !myDisplayer->isActive(anObject)) {
618         anObjects.append(anObject);
619       }
620     }
621   }
622   activateObjectsSelection(anObjects);
623 }
624
625
626 void XGUI_Workshop::onOperationCommitted(ModuleBase_Operation* theOperation)
627 {
628   myModule->operationCommitted(theOperation);
629 }
630
631 void XGUI_Workshop::onOperationAborted(ModuleBase_Operation* theOperation)
632 {
633   myModule->operationAborted(theOperation);
634 }
635
636 void XGUI_Workshop::setGrantedFeatures(ModuleBase_Operation* theOperation)
637 {
638   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
639   if (!aFOperation)
640     return;
641
642   QStringList aGrantedIds;
643   if (isSalomeMode()) {
644     const std::shared_ptr<Config_FeatureMessage>& anInfo =
645                          mySalomeConnector->featureInfo(theOperation->id());
646     if (anInfo.get())
647       aGrantedIds = QString::fromStdString(anInfo->nestedFeatures())
648                                    .split(" ", QString::SkipEmptyParts);
649   }
650   else
651     aGrantedIds = myActionsMgr->nestedCommands(theOperation->id());
652
653   ModuleBase_IModule* aModule = module();
654   if (aModule)
655     aModule->grantedOperationIds(theOperation, aGrantedIds);
656
657   aFOperation->setGrantedOperationIds(aGrantedIds);
658 }
659
660
661 /*
662  * Saves document with given name.
663  */
664 void XGUI_Workshop::saveDocument(const QString& theName, std::list<std::string>& theFileNames)
665 {
666   QApplication::restoreOverrideCursor();
667   SessionPtr aMgr = ModelAPI_Session::get();
668   aMgr->save(theName.toLatin1().constData(), theFileNames);
669   QApplication::restoreOverrideCursor();
670 }
671
672 bool XGUI_Workshop::abortAllOperations()
673 {
674   return myOperationMgr->abortAllOperations();
675 }
676
677 //******************************************************
678 void XGUI_Workshop::onOpen()
679 {
680   if(!abortAllOperations())
681     return;
682   //save current file before close if modified
683   SessionPtr aSession = ModelAPI_Session::get();
684   if (aSession->isModified()) {
685     //TODO(sbh): re-launch the app?
686     int anAnswer = QMessageBox::question(
687         desktop(), tr("Save current file"),
688         tr("The document is modified, save before opening another?"),
689         QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel);
690     if (anAnswer == QMessageBox::Save) {
691       onSave();
692     } else if (anAnswer == QMessageBox::Cancel) {
693       return;
694     }
695     myCurrentDir = "";
696   }
697
698   //show file dialog, check if readable and open
699   myCurrentDir = QFileDialog::getExistingDirectory(desktop(), tr("Select directory"));
700   if (myCurrentDir.isEmpty())
701     return;
702   QFileInfo aFileInfo(myCurrentDir);
703   if (!aFileInfo.exists() || !aFileInfo.isReadable()) {
704     QMessageBox::critical(desktop(), tr("Warning"), tr("Unable to open the file."));
705     myCurrentDir = "";
706     return;
707   }
708   QApplication::setOverrideCursor(Qt::WaitCursor);
709   aSession->closeAll();
710   aSession->load(myCurrentDir.toLatin1().constData());
711   myObjectBrowser->rebuildDataTree();
712   updateCommandStatus();
713   QApplication::restoreOverrideCursor();
714 }
715
716 //******************************************************
717 void XGUI_Workshop::onNew()
718 {
719   QApplication::setOverrideCursor(Qt::WaitCursor);
720   if (objectBrowser() == 0) {
721     createDockWidgets();
722     mySelector->connectViewers();
723   }
724   myViewerProxy->connectToViewer();
725   showObjectBrowser();
726 #ifndef HAVE_SALOME
727   myMainWindow->showPythonConsole();
728   QMdiSubWindow* aWnd = myMainWindow->viewer()->createView();
729   aWnd->showMaximized();
730   updateCommandStatus();
731 #endif
732   myContextMenuMgr->connectViewer();
733   QApplication::restoreOverrideCursor();
734 }
735
736 #ifndef HAVE_SALOME
737 //******************************************************
738 void XGUI_Workshop::onExit()
739 {
740   SessionPtr aMgr = ModelAPI_Session::get();
741   if (aMgr->isModified()) {
742     int anAnswer = QMessageBox::question(
743         myMainWindow, tr("Save current file"), tr("The document is modified, save before exit?"),
744         QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel);
745     if (anAnswer == QMessageBox::Save) {
746       bool saved = onSave();
747       if (!saved) {
748         return;
749       }
750     } else if (anAnswer == QMessageBox::Cancel) {
751       return;
752     }
753   }
754   qApp->exit();
755 }
756
757 //******************************************************
758 void XGUI_Workshop::onPreferences()
759 {
760   ModuleBase_Prefs aModif;
761   ModuleBase_Preferences::editPreferences(aModif);
762   if (aModif.size() > 0) {
763     QString aSection;
764     foreach (ModuleBase_Pref aPref, aModif)
765     {
766       aSection = aPref.first;
767       if (aSection == ModuleBase_Preferences::VIEWER_SECTION) {
768         myMainWindow->viewer()->updateFromResources();
769       } else if (aSection == ModuleBase_Preferences::MENU_SECTION) {
770         myMainWindow->menuObject()->updateFromResources();
771       }
772     }
773     displayer()->redisplayObjects();
774   }
775 }
776 #endif
777
778 //******************************************************
779 void XGUI_Workshop::onTrihedronVisibilityChanged(bool theState)
780 {
781   XGUI_Displayer* aDisplayer = displayer();
782   if (aDisplayer)
783     aDisplayer->displayTrihedron(theState);
784 }
785
786 //******************************************************
787 bool XGUI_Workshop::onSave()
788 {
789   if(!abortAllOperations())
790     return false;
791   if (myCurrentDir.isEmpty()) {
792     return onSaveAs();
793   }
794   std::list<std::string> aFiles;
795   saveDocument(myCurrentDir, aFiles);
796   updateCommandStatus();
797 #ifndef HAVE_SALOME
798     myMainWindow->setModifiedState(false);
799 #endif
800   return true;
801 }
802
803 //******************************************************
804 bool XGUI_Workshop::onSaveAs()
805 {
806   if(!abortAllOperations())
807     return false;
808   QFileDialog dialog(desktop());
809   dialog.setWindowTitle(tr("Select directory to save files..."));
810   dialog.setFileMode(QFileDialog::Directory);
811   dialog.setFilter(tr("Directories (*)"));
812   dialog.setOptions(QFileDialog::HideNameFilterDetails | QFileDialog::ShowDirsOnly);
813   dialog.setViewMode(QFileDialog::Detail);
814
815   if (!dialog.exec()) {
816     return false;
817   }
818
819   QString aTempDir = dialog.selectedFiles().first();
820   QDir aDir(aTempDir);
821   if (aDir.exists() && !aDir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries).isEmpty()) {
822     int answer = QMessageBox::question(
823         desktop(),
824         //: Title of the dialog which asks user if he wants to save study in existing non-empty folder
825         tr("Save"),
826         tr("The directory already contains some files, save anyway?"),
827         QMessageBox::Save | QMessageBox::Cancel);
828     if (answer == QMessageBox::Cancel) {
829       return false;
830     }
831   }
832   myCurrentDir = aTempDir;
833 #ifndef HAVE_SALOME
834     myMainWindow->setCurrentDir(myCurrentDir, false);
835     myMainWindow->setModifiedState(false);
836 #endif
837   return onSave();
838 }
839
840 //******************************************************
841 void XGUI_Workshop::onUndo(int theTimes)
842 {
843   objectBrowser()->treeView()->setCurrentIndex(QModelIndex());
844   SessionPtr aMgr = ModelAPI_Session::get();
845   std::list<std::string> aUndoList = aMgr->undoList();
846   if (aMgr->isOperation()) {
847     /// this is important for nested operations
848     /// when sketch operation is active, this condition is false and
849     /// the sketch operation is not aborted
850     operationMgr()->onAbortOperation();
851   }
852   std::list<std::string>::const_iterator aIt = aUndoList.cbegin();
853   for (int i = 0; (i < theTimes) && (aIt != aUndoList.cend()); ++i, ++aIt) {
854     aMgr->undo();
855     if (QString((*aIt).c_str()) == MOVE_TO_END_COMMAND)
856       myObjectBrowser->rebuildDataTree();
857   }
858
859   operationMgr()->updateApplyOfOperations();
860   updateCommandStatus();
861 }
862
863 //******************************************************
864 void XGUI_Workshop::onRedo(int theTimes)
865 {
866   // the viewer update should be blocked in order to avoid the features blinking. For the created
867   // feature a results are created, the flush of the created signal caused the viewer redisplay for
868   // each created result. After a redisplay signal is flushed. So, the viewer update is blocked until
869   // redo of all possible objects happens
870   bool isUpdateEnabled = myDisplayer->enableUpdateViewer(false);
871
872   objectBrowser()->treeView()->setCurrentIndex(QModelIndex());
873   SessionPtr aMgr = ModelAPI_Session::get();
874   std::list<std::string> aRedoList = aMgr->redoList();
875   if (aMgr->isOperation()) {
876     /// this is important for nested operations
877     /// when sketch operation is active, this condition is false and
878     /// the sketch operation is not aborted
879     operationMgr()->onAbortOperation();
880   }
881   std::list<std::string>::const_iterator aIt = aRedoList.cbegin();
882   for (int i = 0; (i < theTimes) && (aIt != aRedoList.cend()); ++i, ++aIt) {
883     aMgr->redo();
884     if (QString((*aIt).c_str()) == MOVE_TO_END_COMMAND)
885       myObjectBrowser->rebuildDataTree();
886   }
887   operationMgr()->updateApplyOfOperations();
888   updateCommandStatus();
889
890   // unblock the viewer update functionality and make update on purpose
891   myDisplayer->enableUpdateViewer(isUpdateEnabled);
892   myDisplayer->updateViewer();
893 }
894
895 //******************************************************
896 //void XGUI_Workshop::onRebuild()
897 //{
898 //  SessionPtr aMgr = ModelAPI_Session::get();
899 //  bool aWasOperation = aMgr->isOperation(); // keep this value
900 //  if (!aWasOperation) {
901 //    aMgr->startOperation("Rebuild");
902 //  }
903 //  static const Events_ID aRebuildEvent = Events_Loop::loop()->eventByName("Rebuild");
904 //  Events_Loop::loop()->send(std::shared_ptr<Events_Message>(
905 //    new Events_Message(aRebuildEvent, this)));
906 //  if (!aWasOperation) {
907 //    aMgr->finishOperation();
908 //  }
909 //  updateCommandStatus();
910 //}
911
912 //******************************************************
913 void XGUI_Workshop::onWidgetStateChanged(int thePreviousState)
914 {
915   ModuleBase_ModelWidget* anActiveWidget = 0;
916   ModuleBase_Operation* anOperation = myOperationMgr->currentOperation();
917   if (anOperation) {
918     ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
919     if (aPanel)
920       anActiveWidget = aPanel->activeWidget();
921   }
922   if (anActiveWidget)
923     operationMgr()->onValidateOperation();
924
925   myModule->widgetStateChanged(thePreviousState);
926 }
927
928 //******************************************************
929 void XGUI_Workshop::onValuesChanged()
930 {
931   ModuleBase_ModelWidget* aSenderWidget = (ModuleBase_ModelWidget*)(sender());
932   if (!aSenderWidget || aSenderWidget->canAcceptFocus())
933     return;
934
935   ModuleBase_ModelWidget* anActiveWidget = 0;
936   ModuleBase_Operation* anOperation = myOperationMgr->currentOperation();
937   if (anOperation) {
938     ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
939     if (aPanel)
940       anActiveWidget = aPanel->activeWidget();
941   }
942   if (anActiveWidget) {
943     ModuleBase_WidgetValidated* aWidgetValidated = dynamic_cast<ModuleBase_WidgetValidated*>
944                                                                            (anActiveWidget);
945     if (aWidgetValidated)
946       aWidgetValidated->clearValidatedCash();
947   }
948 }
949
950 void XGUI_Workshop::onWidgetObjectUpdated()
951 {
952   operationMgr()->onValidateOperation();
953 }
954
955 ModuleBase_IModule* XGUI_Workshop::loadModule(const QString& theModule)
956 {
957   QString libName = QString::fromStdString(library(theModule.toStdString()));
958   if (libName.isEmpty()) {
959     qWarning(qPrintable(tr("Information about module \"%1\" doesn't exist.").arg(theModule)));
960     return 0;
961   }
962
963   QString err;
964   CREATE_FUNC crtInst = 0;
965
966 #ifdef WIN32
967   HINSTANCE modLib = ::LoadLibrary((LPTSTR) qPrintable(libName));
968   if (!modLib) {
969     LPVOID lpMsgBuf;
970     ::FormatMessage(
971         FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
972         0, ::GetLastError(), 0, (LPTSTR) & lpMsgBuf, 0, 0);
973     QString aMsg((char*) &lpMsgBuf);
974     err = QString("Failed to load  %1. %2").arg(libName).arg(aMsg);
975     ::LocalFree(lpMsgBuf);
976   } else {
977     crtInst = (CREATE_FUNC) ::GetProcAddress(modLib, CREATE_MODULE);
978     if (!crtInst) {
979       LPVOID lpMsgBuf;
980       ::FormatMessage(
981           FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
982               | FORMAT_MESSAGE_IGNORE_INSERTS,
983           0, ::GetLastError(), 0, (LPTSTR) & lpMsgBuf, 0, 0);
984       QString aMsg((char*) &lpMsgBuf);
985       err = QString("Failed to find  %1 function. %2").arg( CREATE_MODULE).arg(aMsg);
986       ::LocalFree(lpMsgBuf);
987     }
988   }
989 #else
990   void* modLib = dlopen( libName.toLatin1(), RTLD_LAZY | RTLD_GLOBAL );
991   if ( !modLib ) {
992     err = QString( "Can not load library %1. %2" ).arg( libName ).arg( dlerror() );
993   } else {
994     crtInst = (CREATE_FUNC)dlsym( modLib, CREATE_MODULE );
995     if ( !crtInst ) {
996       err = QString( "Failed to find function %1. %2" ).arg( CREATE_MODULE ).arg( dlerror() );
997     }
998   }
999 #endif
1000
1001   ModuleBase_IModule* aModule = crtInst ? crtInst(myModuleConnector) : 0;
1002
1003   if (!err.isEmpty()) {
1004     if (desktop()) {
1005       Events_Error::send(err.toStdString());
1006     } else {
1007       qWarning(qPrintable(err));
1008     }
1009   }
1010   return aModule;
1011 }
1012
1013 //******************************************************
1014 bool XGUI_Workshop::createModule()
1015 {
1016   Config_ModuleReader aModuleReader;
1017   QString moduleName = QString::fromStdString(aModuleReader.getModuleName());
1018   myModule = loadModule(moduleName);
1019   if (!myModule)
1020     return false;
1021
1022   //connect(myDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)),
1023   //  myModule, SLOT(onObjectDisplayed(ObjectPtr, AISObjectPtr)));
1024   //connect(myDisplayer, SIGNAL(beforeObjectErase(ObjectPtr, AISObjectPtr)),
1025   //  myModule, SLOT(onBeforeObjectErase(ObjectPtr, AISObjectPtr)));
1026
1027   myModule->createFeatures();
1028 #ifdef HAVE_SALOME
1029   salomeConnector()->createFeatureActions();
1030 #endif
1031   //myActionsMgr->update();
1032   return true;
1033 }
1034
1035 //******************************************************
1036 void XGUI_Workshop::updateCommandStatus()
1037 {
1038   QList<QAction*> aCommands;
1039 #ifdef HAVE_SALOME
1040     aCommands = salomeConnector()->commandList();
1041 #else
1042     AppElements_MainMenu* aMenuBar = myMainWindow->menuObject();
1043     foreach (AppElements_Command* aCmd, aMenuBar->features())
1044       aCommands.append(aCmd);
1045 #endif
1046   SessionPtr aMgr = ModelAPI_Session::get();
1047   if (aMgr->hasModuleDocument()) {
1048     foreach(QAction* aCmd, aCommands) {
1049       QString aId = aCmd->data().toString();
1050       if (aId == "UNDO_CMD")
1051         aCmd->setEnabled(myModule->canUndo());
1052       else if (aId == "REDO_CMD")
1053         aCmd->setEnabled(myModule->canRedo());
1054       else
1055         // Enable all commands
1056         aCmd->setEnabled(true);
1057     }
1058     updateHistory();
1059   } else {
1060     foreach(QAction* aCmd, aCommands) {
1061       QString aId = aCmd->data().toString();
1062       if (aId == "NEW_CMD")
1063         aCmd->setEnabled(true);
1064       else if (aId == "EXIT_CMD")
1065         aCmd->setEnabled(true);
1066       else
1067         aCmd->setEnabled(false);
1068     }
1069   }
1070   myActionsMgr->updateCommandsStatus();
1071   emit commandStatusUpdated();
1072 }
1073
1074 void XGUI_Workshop::updateHistory()
1075 {
1076   std::list<std::string> aUndoList = ModelAPI_Session::get()->undoList();
1077   QList<ActionInfo> aUndoRes = processHistoryList(aUndoList);
1078   emit updateUndoHistory(aUndoRes);
1079
1080   std::list<std::string> aRedoList = ModelAPI_Session::get()->redoList();
1081   QList<ActionInfo> aRedoRes = processHistoryList(aRedoList);
1082   emit updateRedoHistory(aRedoRes);
1083 }
1084
1085 //******************************************************
1086 QDockWidget* XGUI_Workshop::createObjectBrowser(QWidget* theParent)
1087 {
1088   QDockWidget* aObjDock = new QDockWidget(theParent);
1089   aObjDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea);
1090   aObjDock->setWindowTitle(tr("Object browser"));
1091   aObjDock->setStyleSheet(
1092       "::title { position: relative; padding-left: 5px; text-align: left center }");
1093   myObjectBrowser = new XGUI_ObjectsBrowser(aObjDock);
1094   myObjectBrowser->setXMLReader(myDataModelXMLReader);
1095   myModule->customizeObjectBrowser(myObjectBrowser);
1096   aObjDock->setWidget(myObjectBrowser);
1097
1098   myContextMenuMgr->connectObjectBrowser();
1099   return aObjDock;
1100 }
1101
1102 //******************************************************
1103 /*
1104  * Creates dock widgets, places them in corresponding area
1105  * and tabifies if necessary.
1106  */
1107 void XGUI_Workshop::createDockWidgets()
1108 {
1109   QMainWindow* aDesktop = desktop();
1110   QDockWidget* aObjDock = createObjectBrowser(aDesktop);
1111   aDesktop->addDockWidget(Qt::LeftDockWidgetArea, aObjDock);
1112   myPropertyPanel = new XGUI_PropertyPanel(aDesktop, myOperationMgr);
1113   myPropertyPanel->setupActions(myActionsMgr);
1114   myPropertyPanel->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea);
1115   aDesktop->addDockWidget(Qt::LeftDockWidgetArea, myPropertyPanel);
1116   hidePropertyPanel();  ///<! Invisible by default
1117   hideObjectBrowser();
1118   aDesktop->tabifyDockWidget(aObjDock, myPropertyPanel);
1119   myPropertyPanel->installEventFilter(myOperationMgr);
1120
1121   QAction* aOkAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Accept);
1122   connect(aOkAct, SIGNAL(triggered()), this, SLOT(onAcceptActionClicked()));
1123
1124   QAction* aCancelAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Abort);
1125   connect(aCancelAct, SIGNAL(triggered()), myOperationMgr, SLOT(onAbortOperation()));
1126
1127   QAction* aPreviewAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Preview);
1128   connect(aPreviewAct, SIGNAL(triggered()), this, SLOT(onPreviewActionClicked()));
1129
1130   connect(myPropertyPanel, SIGNAL(keyReleased(QObject*, QKeyEvent*)),
1131           myOperationMgr,  SLOT(onKeyReleased(QObject*, QKeyEvent*)));
1132   connect(myPropertyPanel, SIGNAL(enterClicked(QObject*)),
1133           myOperationMgr,  SLOT(onProcessEnter(QObject*)));
1134 }
1135
1136 //******************************************************
1137 void XGUI_Workshop::showPropertyPanel()
1138 {
1139   QAction* aViewAct = myPropertyPanel->toggleViewAction();
1140   ///<! Restore ability to close panel from the window's menu
1141   aViewAct->setEnabled(true);
1142   myPropertyPanel->show();
1143   myPropertyPanel->raise();
1144
1145   // The next code is necessary to made the property panel the active window
1146   // in order to operation manager could process key events of the panel.
1147   // otherwise they are ignored. It happens only if the same(activateWindow) is
1148   // not happened by property panel activation(e.g. resume operation of Sketch)
1149   ModuleBase_Tools::activateWindow(myPropertyPanel, "XGUI_Workshop::showPropertyPanel()");
1150   ModuleBase_Tools::setFocus(myPropertyPanel, "XGUI_Workshop::showPropertyPanel()");
1151 }
1152
1153 //******************************************************
1154 void XGUI_Workshop::hidePropertyPanel()
1155 {
1156   QAction* aViewAct = myPropertyPanel->toggleViewAction();
1157   ///<! Do not allow to show empty property panel
1158   aViewAct->setEnabled(false);
1159   myPropertyPanel->hide();
1160
1161   // the property panel is active window of the desktop, when it is
1162   // hidden, it is undefined which window becomes active. By this reason
1163   // it is defined to perform the desktop as the active window.
1164   // in SALOME mode, workstack made the PyConsole the active window,
1165   // set the focus on it. As a result, shortcuts of the application, like
1166   // are processed by this console. For example Undo actions.
1167   // It is possible that this code is to be moved to SHAPER package
1168   QMainWindow* aDesktop = desktop();
1169   ModuleBase_Tools::activateWindow(aDesktop, "XGUI_Workshop::hidePropertyPanel()");
1170   ModuleBase_Tools::setFocus(aDesktop, "XGUI_Workshop::showPropertyPanel()");
1171 }
1172
1173 //******************************************************
1174 void XGUI_Workshop::showObjectBrowser()
1175 {
1176   if (!isSalomeMode())
1177     myObjectBrowser->parentWidget()->show();
1178 }
1179
1180 //******************************************************
1181 void XGUI_Workshop::hideObjectBrowser()
1182 {
1183   if (!isSalomeMode())
1184     myObjectBrowser->parentWidget()->hide();
1185 }
1186
1187 //******************************************************
1188 void XGUI_Workshop::salomeViewerSelectionChanged()
1189 {
1190   emit salomeViewerSelection();
1191 }
1192
1193 //**************************************************************
1194 ModuleBase_IViewer* XGUI_Workshop::salomeViewer() const
1195 {
1196   return mySalomeConnector->viewer();
1197 }
1198
1199 //**************************************************************
1200 void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked)
1201 {
1202   QObjectPtrList aObjects = mySelector->selection()->selectedObjects();
1203   if (theId == "DELETE_CMD")
1204     deleteObjects();
1205   else if (theId == "CLEAN_HISTORY_CMD")
1206     cleanHistory();
1207   else if (theId == "MOVE_CMD")
1208     moveObjects();
1209   else if (theId == "COLOR_CMD")
1210     changeColor(aObjects);
1211   else if (theId == "SHOW_CMD") {
1212     showObjects(aObjects, true);
1213     mySelector->updateSelectionBy(ModuleBase_ISelection::Browser);
1214   }
1215   else if (theId == "HIDE_CMD")
1216     showObjects(aObjects, false);
1217   else if (theId == "SHOW_ONLY_CMD") {
1218     showOnlyObjects(aObjects);
1219     mySelector->updateSelectionBy(ModuleBase_ISelection::Browser);
1220   }
1221   else if (theId == "SHADING_CMD")
1222     setDisplayMode(aObjects, XGUI_Displayer::Shading);
1223   else if (theId == "WIREFRAME_CMD")
1224     setDisplayMode(aObjects, XGUI_Displayer::Wireframe);
1225   else if (theId == "HIDEALL_CMD") {
1226     QObjectPtrList aList = myDisplayer->displayedObjects();
1227     foreach (ObjectPtr aObj, aList) {
1228       if (module()->canEraseObject(aObj))
1229         aObj->setDisplayed(false);
1230     }
1231     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1232   } else if (theId == "SELECT_VERTEX_CMD") {
1233     setViewerSelectionMode(TopAbs_VERTEX);
1234   } else if (theId == "SELECT_EDGE_CMD") {
1235     setViewerSelectionMode(TopAbs_EDGE);
1236   } else if (theId == "SELECT_FACE_CMD") {
1237     setViewerSelectionMode(TopAbs_FACE);
1238   } else if (theId == "SELECT_RESULT_CMD") {
1239     setViewerSelectionMode(-1);
1240   } else if (theId == "SHOW_RESULTS_CMD") {
1241     highlightResults(aObjects);
1242   } else if (theId == "SHOW_FEATURE_CMD") {
1243     highlightFeature(aObjects);
1244   }
1245 }
1246
1247 //**************************************************************
1248 void XGUI_Workshop::setViewerSelectionMode(int theMode)
1249 {
1250   if (theMode == -1)
1251     myViewerSelMode.clear();
1252   else {
1253     if (myViewerSelMode.contains(theMode))
1254       myViewerSelMode.removeAll(theMode);
1255     else
1256       myViewerSelMode.append(theMode);
1257   }
1258   activateObjectsSelection(myDisplayer->displayedObjects());
1259 }
1260
1261 //**************************************************************
1262 void XGUI_Workshop::activateObjectsSelection(const QObjectPtrList& theList)
1263 {
1264   QIntList aModes;
1265   module()->activeSelectionModes(aModes);
1266   if (aModes.isEmpty() && (myViewerSelMode.length() > 0))
1267     aModes.append(myViewerSelMode);
1268   myDisplayer->activateObjects(aModes, theList);
1269 }
1270
1271
1272 //**************************************************************
1273 void XGUI_Workshop::deleteObjects()
1274 {
1275   ModuleBase_IModule* aModule = module();
1276   // 1. allow the module to delete objects, do nothing if it has succeed
1277   if (aModule->deleteObjects()) {
1278     updateCommandStatus();
1279     return;
1280   }
1281
1282   QObjectPtrList anObjects = mySelector->selection()->selectedObjects();
1283   if (!abortAllOperations())
1284     return;
1285   // check whether the object can be deleted. There should not be parts which are not loaded
1286   if (!XGUI_Tools::canRemoveOrRename(desktop(), anObjects))
1287     return;
1288
1289   bool hasResult = false;
1290   bool hasFeature = false;
1291   bool hasParameter = false;
1292   bool hasCompositeOwner = false;
1293   ModuleBase_Tools::checkObjects(anObjects, hasResult, hasFeature, hasParameter, hasCompositeOwner);
1294   if (!(hasFeature || hasParameter))
1295     return;
1296
1297   // 3. delete objects
1298   std::set<FeaturePtr> anIgnoredFeatures;
1299   std::set<FeaturePtr> aDirectRefFeatures, aIndirectRefFeatures;
1300   ModuleBase_Tools::findReferences(anObjects, aDirectRefFeatures, aIndirectRefFeatures);
1301
1302   bool doDeleteReferences = true;
1303   if (ModuleBase_Tools::isDeleteFeatureWithReferences(anObjects, aDirectRefFeatures, 
1304       aIndirectRefFeatures, desktop(), doDeleteReferences)) {
1305     // start operation
1306     QString aDescription = contextMenuMgr()->action("DELETE_CMD")->text() + " %1";
1307     aDescription = aDescription.arg(XGUI_Tools::unionOfObjectNames(anObjects, ", "));
1308     ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(aDescription, module());
1309     operationMgr()->startOperation(anOpAction);
1310
1311     // WORKAROUND, should be done before each object remove, if it presents in XGUI_DataModel tree
1312     // It is necessary to clear selection in order to avoid selection changed event during
1313     // deletion and negative consequences connected with processing of already deleted items
1314     mySelector->clearSelection();
1315
1316     // delete and commit/abort operation in model
1317     if (deleteFeaturesInternal(anObjects, aDirectRefFeatures, aIndirectRefFeatures,
1318                                anIgnoredFeatures, doDeleteReferences))
1319       operationMgr()->commitOperation();
1320     else
1321       operationMgr()->abortOperation(operationMgr()->currentOperation());
1322   }
1323 }
1324
1325 //**************************************************************
1326 void addRefsToFeature(const FeaturePtr& theFeature,
1327                       const std::map<FeaturePtr, std::set<FeaturePtr> >& theMainList,
1328                       std::set<FeaturePtr>& theReferences)
1329 {
1330   //if (theReferences.find(theFeature) != theReferences.end())
1331   //  return;
1332   if (theMainList.find(theFeature) == theMainList.end())
1333     return; // this feature is not in the selection list, so exists without references to it
1334   std::set<FeaturePtr> aMainReferences = theMainList.at(theFeature);
1335
1336   std::set<FeaturePtr>::const_iterator anIt = aMainReferences.begin(),
1337                                        aLast = aMainReferences.end();
1338   for (; anIt != aLast; anIt++) {
1339     FeaturePtr aRefFeature = *anIt;
1340     if (theReferences.find(aRefFeature) == theReferences.end())
1341       theReferences.insert(aRefFeature);
1342     addRefsToFeature(aRefFeature, theMainList, theReferences);
1343   }
1344 }
1345
1346 void printMapInfo(const std::map<FeaturePtr, std::set<FeaturePtr> >& theMainList,
1347                   const QString& thePrefix)
1348 {
1349   std::map<FeaturePtr, std::set<FeaturePtr> >::const_iterator aMainIt = theMainList.begin(),
1350                                                               aMainLast = theMainList.end();
1351   QStringList aMapInfo;
1352   for (; aMainIt != aMainLast; aMainIt++) {
1353     QStringList anInfo;
1354     FeaturePtr aMainListFeature = aMainIt->first;
1355     std::set<FeaturePtr> aMainRefList = aMainIt->second;
1356     foreach (FeaturePtr aRefFeature, aMainRefList) {
1357       anInfo.append(aRefFeature->name().c_str());
1358     }
1359     aMapInfo.append(QString("%1: %2\n").arg(aMainListFeature->name().c_str()).arg(anInfo.join(",")));
1360   }
1361   qDebug(QString("%1: %2\n%3").arg(thePrefix).arg(aMapInfo.size()).arg(aMapInfo.join("\n")).toStdString().c_str());
1362 }
1363
1364 //**************************************************************
1365 void XGUI_Workshop::cleanHistory()
1366 {
1367   if (!abortAllOperations())
1368     return;
1369
1370   QObjectPtrList anObjects = mySelector->selection()->selectedObjects();
1371   QObjectPtrList aFeatures;
1372   foreach (ObjectPtr anObject, anObjects) {
1373     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);
1374     // for parameter result, use the corresponded reature to be removed
1375     if (!aFeature.get() && anObject->groupName() == ModelAPI_ResultParameter::group()) {
1376       aFeature = ModelAPI_Feature::feature(anObject);
1377     }
1378     aFeatures.append(aFeature);
1379   }
1380
1381 #ifdef DEBUG_CLEAN_HISTORY
1382   QObjectPtrList::const_iterator aFIt;
1383   QStringList anInfo;
1384   for (aFIt = aFeatures.begin(); aFIt != aFeatures.end(); ++aFIt) {
1385     FeaturePtr aFeature = ModelAPI_Feature::feature(*aFIt);
1386     anInfo.append(aFeature->name().c_str());
1387   }
1388   QString anInfoStr = anInfo.join(";\t");
1389   qDebug(QString("cleanHistory for: [%1] - %2").arg(aFeatures.size()).arg(anInfoStr).toStdString().c_str());
1390 #endif
1391
1392   // For dependencies, find main_list:
1393   // sk_1(ext_1, vertex_1)
1394   // ext_1(bool_1, sk_3)
1395   // vertex_1()
1396   // sk_2(ext_2)
1397   // ext_2(bool_2)
1398   // sk_3()
1399   // Information: bool_1 is not selected
1400   // find all referenced features
1401   std::map<FeaturePtr, std::set<FeaturePtr> > aMainList;
1402   foreach(ObjectPtr anObject, aFeatures) {
1403     FeaturePtr aSelFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);
1404     /// composite ??? see refsDirectToFeatureInAllDocuments
1405     /// other documents ???
1406     if (aSelFeature.get()) {
1407       DocumentPtr aSelFeatureDoc = aSelFeature->document();
1408       std::set<FeaturePtr> aSelRefFeatures;
1409       // 1. find references in the current document
1410       aSelFeatureDoc->refsToFeature(aSelFeature, aSelRefFeatures, false/*do not emit signals*/);
1411       //if (aMainList.find(aSelFeature) != aMainList.end())
1412         aMainList[aSelFeature] = aSelRefFeatures;
1413     }
1414   }
1415 #ifdef DEBUG_CLEAN_HISTORY
1416   printMapInfo(aMainList, "firstDependencies");
1417 #endif
1418   // find all dependencies for each object:
1419   // sk_1(ext_1, vertex_1) + (sk_3, bool_1)
1420   // ext_1(bool_1, sk_3)
1421   // vertex_1()
1422   // sk_2(ext_2) + (bool_1)
1423   // ext_2(bool_1)
1424   // sk_3()
1425   std::map<FeaturePtr, std::set<FeaturePtr> > anExtendedMainList;
1426   std::map<FeaturePtr, std::set<FeaturePtr> >::const_iterator aMainIt = aMainList.begin(),
1427                                                               aMainLast = aMainList.end();
1428   for (; aMainIt != aMainLast; aMainIt++) {
1429     FeaturePtr aMainListFeature = aMainIt->first;
1430     //std::string aName = aMainListFeature->name();
1431     std::set<FeaturePtr> aMainRefList = aMainIt->second;
1432     std::set<FeaturePtr> anAddRefFeatures;
1433     foreach (FeaturePtr aRefFeature, aMainRefList) {
1434       addRefsToFeature(aRefFeature, aMainList, aMainRefList);
1435     }
1436     anExtendedMainList[aMainListFeature] = aMainRefList;
1437   }
1438
1439 #ifdef DEBUG_CLEAN_HISTORY
1440   printMapInfo(anExtendedMainList, "allDependencies");
1441 #endif
1442   // find for each object whether all reference values are in the map as key, that means that there is
1443   // no other reference in the model to this object, so it might be removed by cleaning history
1444   // sk_1(ext_1, vertex_1) + (sk_3, bool_1) - cann't be deleted, dependency to bool_1
1445   // ext_1(bool_1, sk_3)  - cann't be deleted, dependency to bool_1
1446   // vertex_1()
1447   // sk_2(ext_2) + (bool_1)  - cann't be deleted, dependency to bool_1
1448   // ext_2(bool_1)  - cann't be deleted, dependency to bool_1
1449   // sk_3()
1450   // Information: bool_1 is not selected
1451   QList<ObjectPtr> anUnusedObjects;
1452   aMainIt = anExtendedMainList.begin(), aMainLast = anExtendedMainList.end();
1453   for (; aMainIt != aMainLast; aMainIt++) {
1454     FeaturePtr aMainListFeature = aMainIt->first;
1455     std::set<FeaturePtr> aMainRefList = aMainIt->second;
1456     std::set<FeaturePtr>::const_iterator aRefIt = aMainRefList.begin(), aRefLast = aMainRefList.end();
1457     bool aFeatureOutOfTheList = false;
1458     for (; aRefIt != aRefLast && !aFeatureOutOfTheList; aRefIt++) {
1459       FeaturePtr aRefFeature = *aRefIt;
1460       aFeatureOutOfTheList = anExtendedMainList.find(aRefFeature) == anExtendedMainList.end();
1461     }
1462     if (!aFeatureOutOfTheList)
1463       anUnusedObjects.append(aMainListFeature);
1464   }
1465
1466 #ifdef DEBUG_CLEAN_HISTORY
1467   anInfo.clear();
1468   for (aFIt = anUnusedObjects.begin(); aFIt != anUnusedObjects.end(); ++aFIt) {
1469     FeaturePtr aFeature = ModelAPI_Feature::feature(*aFIt);
1470     anInfo.append(aFeature->name().c_str());
1471   }
1472   qDebug(QString("unused objects: [%1] - %2").arg(anInfo.size()).arg(anInfo.join(";\t")).toStdString().c_str());
1473 #endif
1474
1475   // warn about the references remove, break the delete operation if the user chose it
1476   if (!anUnusedObjects.empty()) {
1477     QStringList aNames;
1478     foreach (const ObjectPtr& anObject, anUnusedObjects) {
1479       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);
1480       aNames.append(aFeature->name().c_str());
1481     }
1482     QString anUnusedNames = aNames.join(", ");
1483
1484     QString anActionId = "CLEAN_HISTORY_CMD";
1485     QString aDescription = contextMenuMgr()->action(anActionId)->text();
1486
1487     QMessageBox aMessageBox(desktop());
1488     aMessageBox.setWindowTitle(aDescription);
1489     aMessageBox.setIcon(QMessageBox::Warning);
1490     aMessageBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
1491     aMessageBox.setDefaultButton(QMessageBox::No);
1492
1493     QString aText = QString(tr("Unused features are the following: %1.\nThese features will be deleted.\nWould you like to continue?")
1494                    .arg(anUnusedNames));
1495     aMessageBox.setText(aText);
1496     if (aMessageBox.exec() == QMessageBox::No)
1497       return;
1498
1499     // 1. start operation
1500     aDescription += "by deleting of " + aDescription.arg(XGUI_Tools::unionOfObjectNames(anObjects, ", "));
1501     ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(aDescription, module());
1502     operationMgr()->startOperation(anOpAction);
1503
1504     // WORKAROUND, should be done before each object remove, if it presents in XGUI_DataModel tree
1505     // It is necessary to clear selection in order to avoid selection changed event during
1506     // deletion and negative consequences connected with processing of already deleted items
1507     mySelector->clearSelection();
1508
1509     std::set<FeaturePtr> anIgnoredFeatures;
1510     if (removeFeatures(anUnusedObjects, anIgnoredFeatures, anActionId, true)) {
1511       operationMgr()->commitOperation();
1512     }
1513     else {
1514       operationMgr()->abortOperation(operationMgr()->currentOperation());
1515     }
1516   }
1517   else {
1518     QString anActionId = "CLEAN_HISTORY_CMD";
1519     QString aDescription = contextMenuMgr()->action(anActionId)->text();
1520
1521     QMessageBox aMessageBox(desktop());
1522     aMessageBox.setWindowTitle(aDescription);
1523     aMessageBox.setIcon(QMessageBox::Warning);
1524     aMessageBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
1525     aMessageBox.setDefaultButton(QMessageBox::No);
1526
1527     QString aText;
1528     aMessageBox.setStandardButtons(QMessageBox::Ok);
1529     aMessageBox.setDefaultButton(QMessageBox::Ok);
1530
1531     aText = QString(tr("All features are relevant, there is nothing to be deleted"));
1532     aMessageBox.setText(aText);
1533
1534     if (aMessageBox.exec() == QMessageBox::No)
1535       return;
1536   }
1537 }
1538
1539 //**************************************************************
1540 void XGUI_Workshop::moveObjects()
1541 {
1542   if (!abortAllOperations())
1543     return;
1544
1545   SessionPtr aMgr = ModelAPI_Session::get();
1546
1547   QString anActionId = "MOVE_CMD";
1548   QString aDescription = contextMenuMgr()->action(anActionId)->text();
1549   aMgr->startOperation(aDescription.toStdString());
1550
1551   QObjectPtrList anObjects = mySelector->selection()->selectedObjects();
1552   // It is necessary to clear selection in order to avoid selection changed event during
1553   // moving and negative consequences connected with processing of already moved items
1554   mySelector->clearSelection();
1555   // check whether the object can be moved. There should not be parts which are not loaded
1556   if (!XGUI_Tools::canRemoveOrRename(desktop(), anObjects))
1557     return;
1558
1559   DocumentPtr anActiveDocument = aMgr->activeDocument();
1560   FeaturePtr aCurrentFeature = anActiveDocument->currentFeature(true);
1561   foreach (ObjectPtr aObject, anObjects) {
1562     if (!myModule->canApplyAction(aObject, anActionId))
1563       continue;
1564
1565     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObject);
1566     if (aFeature.get()) {
1567       anActiveDocument->moveFeature(aFeature, aCurrentFeature);
1568       aCurrentFeature = anActiveDocument->currentFeature(true);
1569     }
1570   }
1571   aMgr->finishOperation();
1572 }
1573
1574 //**************************************************************
1575 bool XGUI_Workshop::deleteFeatures(const QObjectPtrList& theFeatures,
1576                                    const std::set<FeaturePtr>& theIgnoredFeatures)
1577 {
1578   std::set<FeaturePtr> aDirectRefFeatures, aIndirectRefFeatures;
1579   ModuleBase_Tools::findReferences(theFeatures, aDirectRefFeatures, aIndirectRefFeatures);
1580   return deleteFeaturesInternal(theFeatures, aDirectRefFeatures, aIndirectRefFeatures,
1581                                 theIgnoredFeatures);
1582 }
1583
1584 bool XGUI_Workshop::deleteFeaturesInternal(const QObjectPtrList& theList,
1585                                            const std::set<FeaturePtr>& aDirectRefFeatures,
1586                                            const std::set<FeaturePtr>& aIndirectRefFeatures,
1587                                            const std::set<FeaturePtr>& theIgnoredFeatures,
1588                                            const bool doDeleteReferences)
1589 {
1590   bool isDone = false;
1591   if (doDeleteReferences) {
1592     std::set<FeaturePtr> aFeaturesToDelete = aDirectRefFeatures;
1593     aFeaturesToDelete.insert(aIndirectRefFeatures.begin(), aIndirectRefFeatures.end());
1594     std::set<FeaturePtr>::const_iterator anIt = aFeaturesToDelete.begin(),
1595                                          aLast = aFeaturesToDelete.end();
1596 #ifdef DEBUG_DELETE
1597     QStringList anInfo;
1598 #endif
1599     for (; anIt != aLast; anIt++) {
1600       FeaturePtr aFeature = (*anIt);
1601       DocumentPtr aDoc = aFeature->document();
1602       if (theIgnoredFeatures.find(aFeature) == theIgnoredFeatures.end()) {
1603         // flush REDISPLAY signal after remove feature
1604         aDoc->removeFeature(aFeature);
1605         isDone = true;
1606 #ifdef DEBUG_DELETE
1607         anInfo.append(ModuleBase_Tools::objectInfo(aFeature).toStdString().c_str());
1608 #endif
1609       }
1610     }
1611 #ifdef DEBUG_DELETE
1612     qDebug(QString("remove references:%1").arg(anInfo.join("; ")).toStdString().c_str());
1613     anInfo.clear();
1614 #endif
1615   }
1616
1617   QString anActionId = "DELETE_CMD";
1618   isDone = removeFeatures(theList, theIgnoredFeatures, anActionId, false) || isDone;
1619
1620   if (isDone) {
1621     // the redisplay signal should be flushed in order to erase the feature presentation in the viewer
1622     // if should be done after removeFeature() of document
1623     Events_Loop::loop()->flush(Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY));
1624   }
1625   return isDone;
1626 }
1627
1628 //**************************************************************
1629 bool XGUI_Workshop::removeFeatures(const QObjectPtrList& theList,
1630                                    const std::set<FeaturePtr>& theIgnoredFeatures,
1631                                    const QString& theActionId,
1632                                    const bool theFlushRedisplay)
1633 {
1634   bool isDone = false;
1635
1636   QString anId = QString::fromStdString(theActionId.toStdString().c_str());
1637   QStringList anObjectGroups = contextMenuMgr()->actionObjectGroups(anId);
1638   // 4. remove the parameter features
1639   foreach (ObjectPtr aObj, theList) {
1640     // features and parameters can be removed here,
1641     // the results are removed only by a corresponded feature remove
1642     std::string aGroupName = aObj->groupName();
1643     if (!anObjectGroups.contains(aGroupName.c_str()))
1644       continue;
1645
1646     FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
1647     if (aFeature) {
1648       /*// TODO: to learn the workshop to delegate the Part object deletion to the PartSet module
1649       // part features are removed in the PartSet module. This condition should be moved there
1650       if (aFeature->getKind() == "Part")
1651         continue;
1652         */
1653       DocumentPtr aDoc = aObj->document();
1654       if (theIgnoredFeatures.find(aFeature) == theIgnoredFeatures.end()) {
1655 #ifdef DEBUG_DELETE
1656         QString anInfoStr = ModuleBase_Tools::objectInfo(aFeature);
1657         anInfo.append(anInfoStr);
1658         qDebug(QString("remove feature :%1").arg(anInfoStr).toStdString().c_str());
1659 #endif
1660         // flush REDISPLAY signal after remove feature
1661         aDoc->removeFeature(aFeature);
1662         isDone = true;
1663       }
1664     }
1665   }
1666   if (isDone && theFlushRedisplay) {
1667     // the redisplay signal should be flushed in order to erase the feature presentation in the viewer
1668     // if should be done after removeFeature() of document
1669     Events_Loop::loop()->flush(Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY));
1670   }
1671
1672 #ifdef DEBUG_DELETE
1673   qDebug(QString("remove features:%1").arg(anInfo.join("; ")).toStdString().c_str());
1674 #endif
1675   return true;
1676 }
1677
1678 bool hasResults(QObjectPtrList theObjects, const std::set<std::string>& theTypes)
1679 {
1680   bool isFoundResultType = false;
1681   foreach(ObjectPtr anObj, theObjects)
1682   {
1683     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObj);
1684     if (aResult.get() == NULL)
1685       continue;
1686
1687     isFoundResultType = theTypes.find(aResult->groupName()) != theTypes.end();
1688     if (isFoundResultType)
1689       break;
1690   }
1691   return isFoundResultType;
1692 }
1693
1694 //**************************************************************
1695 // Returns the list of all features for theDocument and all features of
1696 // all nested parts.
1697 std::list<FeaturePtr> allFeatures(const DocumentPtr& theDocument)
1698 {
1699   std::list<FeaturePtr> aResultList;
1700   std::list<FeaturePtr> anAllFeatures = theDocument->allFeatures();
1701   foreach (const FeaturePtr& aFeature, anAllFeatures) {
1702     // The order of appending features of the part and the part itself is important
1703
1704     // Append features from a part feature
1705     foreach (const ResultPtr& aResult, aFeature->results()) {
1706       ResultPartPtr aResultPart =
1707           std::dynamic_pointer_cast<ModelAPI_ResultPart>(aResult);
1708       if (aResultPart.get() && aResultPart->partDoc().get()) {
1709         // Recursion
1710         std::list<FeaturePtr> anAllFeatures = allFeatures(aResultPart->partDoc());
1711         aResultList.insert(aResultList.end(), anAllFeatures.begin(), anAllFeatures.end());
1712       }
1713     }
1714
1715     aResultList.push_back(aFeature);
1716   }
1717   return aResultList;
1718 }
1719
1720 //**************************************************************
1721 // Returns the list of features placed between theObject and the current feature
1722 // in the same document. Excludes theObject, includes the current feature.
1723 std::list<FeaturePtr> toCurrentFeatures(const ObjectPtr& theObject)
1724 {
1725   std::list<FeaturePtr> aResult;
1726   DocumentPtr aDocument = theObject->document();
1727   std::list<FeaturePtr> anAllFeatures = allFeatures(aDocument);
1728   // find the object iterator
1729   std::list<FeaturePtr>::iterator aObjectIt = std::find(anAllFeatures.begin(), anAllFeatures.end(), theObject);
1730   if (aObjectIt == anAllFeatures.end())
1731     return aResult;
1732   // find the current feature iterator
1733   std::list<FeaturePtr>::iterator aCurrentIt = std::find(anAllFeatures.begin(), anAllFeatures.end(), aDocument->currentFeature(true));
1734   if (aCurrentIt == anAllFeatures.end())
1735     return aResult;
1736   // check the right order
1737   if (std::distance(aObjectIt, anAllFeatures.end()) <= std::distance(aCurrentIt, anAllFeatures.end()))
1738     return aResult;
1739   // exclude the object
1740   std::advance(aObjectIt, 1);
1741   // include the current feature
1742   std::advance(aCurrentIt, 1);
1743   return std::list<FeaturePtr>(aObjectIt, aCurrentIt);
1744 }
1745
1746 bool XGUI_Workshop::canMoveFeature()
1747 {
1748   QString anActionId = "MOVE_CMD";
1749
1750   QObjectPtrList aObjects = mySelector->selection()->selectedObjects();
1751   QObjectPtrList aValidatedObjects;
1752   foreach (ObjectPtr aObject, aObjects) {
1753     if (!myModule->canApplyAction(aObject, anActionId))
1754       continue;
1755     // To be moved feature should be in active document
1756     if (aObject->document() != ModelAPI_Session::get()->activeDocument())
1757       continue;
1758     aValidatedObjects.append(aObject);
1759   }
1760   if (aValidatedObjects.size() != aObjects.size())
1761     aObjects = aValidatedObjects;
1762
1763   bool aCanMove = !aObjects.empty();
1764
1765   QObjectPtrList::const_iterator anIt = aObjects.begin(), aLast = aObjects.end();
1766   for (; anIt != aLast && aCanMove; anIt++) {
1767     ObjectPtr aObject = *anIt;
1768     // 1. Get features placed between selected and current in the document 
1769     std::list<FeaturePtr> aFeaturesBetween = toCurrentFeatures(aObject);
1770     // if aFeaturesBetween is empty it means wrong order or aObject is the current feature
1771     if (aFeaturesBetween.empty())
1772       aCanMove = false;
1773     else {
1774       std::set<FeaturePtr> aPlacedFeatures(aFeaturesBetween.begin(), aFeaturesBetween.end());
1775       // 2. Get all reference features to the selected object in the document 
1776       std::set<FeaturePtr> aRefFeatures;
1777       ModuleBase_Tools::refsToFeatureInFeatureDocument(aObject, aRefFeatures);
1778
1779       if (aRefFeatures.empty())
1780         continue;
1781       else {
1782         // 3. Find any placed features in all reference features
1783         std::set<FeaturePtr> aIntersectionFeatures;
1784         std::set_intersection(aRefFeatures.begin(), aRefFeatures.end(),
1785                               aPlacedFeatures.begin(), aPlacedFeatures.end(),
1786                               std::inserter(aIntersectionFeatures, aIntersectionFeatures.begin()));
1787         // 4. Return false if any reference feature is placed before current feature
1788         if (!aIntersectionFeatures.empty())
1789           aCanMove = false;
1790       }
1791     }
1792   }
1793   return aCanMove;
1794 }
1795
1796 //**************************************************************
1797 bool XGUI_Workshop::canBeShaded(const ObjectPtr& theObject) const
1798 {
1799   bool aCanBeShaded = myDisplayer->canBeShaded(theObject);
1800   if (!aCanBeShaded) {
1801     ResultCompSolidPtr aCompsolidResult =
1802                 std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(theObject);
1803     if (aCompsolidResult.get() != NULL) { // change colors for all sub-solids
1804       for(int i = 0; i < aCompsolidResult->numberOfSubs() && !aCanBeShaded; i++)
1805         aCanBeShaded = myDisplayer->canBeShaded(aCompsolidResult->subResult(i));
1806     }
1807   }
1808   return aCanBeShaded;
1809 }
1810
1811 //**************************************************************
1812 bool XGUI_Workshop::canChangeColor() const
1813 {
1814   QObjectPtrList aObjects = mySelector->selection()->selectedObjects();
1815
1816   std::set<std::string> aTypes;
1817   aTypes.insert(ModelAPI_ResultGroup::group());
1818   aTypes.insert(ModelAPI_ResultConstruction::group());
1819   aTypes.insert(ModelAPI_ResultBody::group());
1820   aTypes.insert(ModelAPI_ResultPart::group());
1821
1822   return hasResults(aObjects, aTypes);
1823 }
1824
1825 void setColor(ResultPtr theResult, const std::vector<int>& theColor)
1826 {
1827   if (!theResult.get())
1828     return;
1829
1830   AttributeIntArrayPtr aColorAttr = theResult->data()->intArray(ModelAPI_Result::COLOR_ID());
1831   if (aColorAttr.get() != NULL) {
1832     if (!aColorAttr->size()) {
1833       aColorAttr->setSize(3);
1834     }
1835     aColorAttr->setValue(0, theColor[0]);
1836     aColorAttr->setValue(1, theColor[1]);
1837     aColorAttr->setValue(2, theColor[2]);
1838   }
1839 }
1840
1841 //**************************************************************
1842 void XGUI_Workshop::changeColor(const QObjectPtrList& theObjects)
1843 {
1844
1845   AttributeIntArrayPtr aColorAttr;
1846   // 1. find the current color of the object. This is a color of AIS presentation
1847   // The objects are iterated until a first valid color is found 
1848   std::vector<int> aColor;
1849   foreach(ObjectPtr anObject, theObjects) {
1850     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1851     if (aResult.get()) {
1852       XGUI_CustomPrs::getResultColor(aResult, aColor);
1853     }
1854     else {
1855       // TODO: remove the obtaining a color from the AIS object
1856       // this does not happen never because:
1857       // 1. The color can be changed only on results
1858       // 2. The result can be not visualized in the viewer(e.g. Origin Construction)
1859       AISObjectPtr anAISObj = myDisplayer->getAISObject(anObject);
1860       if (anAISObj.get()) {
1861         aColor.resize(3);
1862         anAISObj->getColor(aColor[0], aColor[1], aColor[2]);
1863       }
1864     }
1865     if (!aColor.empty())
1866       break;
1867   }
1868   if (aColor.size() != 3)
1869     return;
1870
1871   if (!abortAllOperations())
1872   return; 
1873   // 2. show the dialog to change the value
1874   XGUI_ColorDialog* aDlg = new XGUI_ColorDialog(desktop());
1875   aDlg->setColor(aColor);
1876   aDlg->move(QCursor::pos());
1877   bool isDone = aDlg->exec() == QDialog::Accepted;
1878   if (!isDone)
1879     return;
1880
1881   bool isRandomColor = aDlg->isRandomColor();
1882
1883   // 3. abort the previous operation and start a new one
1884   SessionPtr aMgr = ModelAPI_Session::get();
1885   QString aDescription = contextMenuMgr()->action("COLOR_CMD")->text();
1886   aMgr->startOperation(aDescription.toStdString());
1887
1888   // 4. set the value to all results
1889   std::vector<int> aColorResult = aDlg->getColor();
1890   foreach(ObjectPtr anObj, theObjects) {
1891     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObj);
1892     if (aResult.get() != NULL) {
1893       ResultCompSolidPtr aCompsolidResult = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aResult);
1894       if (aCompsolidResult.get() != NULL) { // change colors for all sub-solids
1895         for(int i = 0; i < aCompsolidResult->numberOfSubs(); i++) {
1896           setColor(aCompsolidResult->subResult(i), !isRandomColor ? aColorResult : aDlg->getRandomColor());
1897         }
1898       }
1899       setColor(aResult, !isRandomColor ? aColorResult : aDlg->getRandomColor());
1900     }
1901   }
1902   aMgr->finishOperation();
1903   updateCommandStatus();
1904 }
1905
1906 //**************************************************************
1907 #define SET_DISPLAY_GROUP(aGroupName, aDisplay) \
1908 for (int i = 0; i < aDoc->size(aGroupName); i++) { \
1909   aDoc->object(aGroupName, i)->setDisplayed(aDisplay); \
1910 }
1911 void XGUI_Workshop::showObjects(const QObjectPtrList& theList, bool isVisible)
1912 {
1913   foreach (ObjectPtr aObj, theList) {
1914     /*
1915     ResultPartPtr aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
1916     if (aPartRes) {
1917       DocumentPtr aDoc = aPartRes->partDoc();
1918       SET_DISPLAY_GROUP(ModelAPI_ResultBody::group(), isVisible)
1919       SET_DISPLAY_GROUP(ModelAPI_ResultConstruction::group(), isVisible)
1920       SET_DISPLAY_GROUP(ModelAPI_ResultGroup::group(), isVisible)
1921     } else {
1922     */
1923       aObj->setDisplayed(isVisible);
1924     //}
1925   }
1926   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1927 }
1928
1929 //**************************************************************
1930 void XGUI_Workshop::showOnlyObjects(const QObjectPtrList& theList)
1931 {
1932   // Hide all displayed objects
1933   QObjectPtrList aList = myDisplayer->displayedObjects();
1934   foreach (ObjectPtr aObj, aList) {
1935     if (module()->canEraseObject(aObj))
1936       aObj->setDisplayed(false);
1937   }
1938
1939   // Show only objects from the list
1940   foreach (ObjectPtr aObj, theList) {
1941     /*
1942     ResultPartPtr aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
1943     if (aPartRes) {
1944       DocumentPtr aDoc = aPartRes->partDoc();
1945       SET_DISPLAY_GROUP(ModelAPI_ResultBody::group(), true)
1946       SET_DISPLAY_GROUP(ModelAPI_ResultConstruction::group(), true)
1947       SET_DISPLAY_GROUP(ModelAPI_ResultGroup::group(), true)
1948     } else {
1949     */
1950       aObj->setDisplayed(true);
1951     //}
1952   }
1953   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1954
1955 }
1956
1957
1958 //**************************************************************
1959 void XGUI_Workshop::registerValidators() const
1960 {
1961   SessionPtr aMgr = ModelAPI_Session::get();
1962   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
1963 }
1964
1965 //**************************************************************
1966 void XGUI_Workshop::displayDocumentResults(DocumentPtr theDoc)
1967 {
1968   if (!theDoc)
1969     return;
1970   displayGroupResults(theDoc, ModelAPI_ResultConstruction::group());
1971   displayGroupResults(theDoc, ModelAPI_ResultBody::group());
1972 }
1973
1974 //**************************************************************
1975 void XGUI_Workshop::displayGroupResults(DocumentPtr theDoc, std::string theGroup)
1976 {
1977   for (int i = 0; i < theDoc->size(theGroup); i++) 
1978     theDoc->object(theGroup, i)->setDisplayed(true);
1979     //displayObject(theDoc->object(theGroup, i));
1980   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1981 }
1982
1983 //**************************************************************
1984 void XGUI_Workshop::setDisplayMode(const QObjectPtrList& theList, int theMode)
1985 {
1986   foreach(ObjectPtr aObj, theList) {
1987     myDisplayer->setDisplayMode(aObj, (XGUI_Displayer::DisplayMode)theMode, false);
1988
1989     ResultCompSolidPtr aCompsolidResult = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aObj);
1990     if (aCompsolidResult.get() != NULL) { // change colors for all sub-solids
1991       for(int i = 0; i < aCompsolidResult->numberOfSubs(); i++) {
1992           myDisplayer->setDisplayMode(aCompsolidResult->subResult(i),
1993                                       (XGUI_Displayer::DisplayMode)theMode, false);
1994       }
1995     }
1996   }
1997   if (theList.size() > 0)
1998     myDisplayer->updateViewer();
1999 }
2000
2001 //**************************************************************
2002 void XGUI_Workshop::closeDocument()
2003 {
2004   ModuleBase_Operation* anOperation = operationMgr()->currentOperation();
2005   while (anOperation) {
2006     anOperation->abort();
2007     anOperation = operationMgr()->currentOperation();
2008   }
2009   myDisplayer->closeLocalContexts();
2010   myDisplayer->eraseAll();
2011   objectBrowser()->clearContent();
2012
2013   module()->closeDocument();
2014
2015   SessionPtr aMgr = ModelAPI_Session::get();
2016   aMgr->closeAll();
2017 }
2018
2019 void XGUI_Workshop::addHistoryMenu(QObject* theObject, const char* theSignal, const char* theSlot)
2020 {
2021   XGUI_HistoryMenu* aMenu = NULL;
2022   if (isSalomeMode()) {
2023     QAction* anAction = qobject_cast<QAction*>(theObject);
2024     if (!anAction)
2025       return;
2026     aMenu = new XGUI_HistoryMenu(anAction);
2027   } else {
2028     QToolButton* aButton =  qobject_cast<QToolButton*>(theObject);
2029     aMenu = new XGUI_HistoryMenu(aButton);
2030   }
2031   connect(this, theSignal, aMenu, SLOT(setHistory(const QList<ActionInfo>&)));
2032   connect(aMenu, SIGNAL(actionSelected(int)), this, theSlot);
2033 }
2034
2035 QList<ActionInfo> XGUI_Workshop::processHistoryList(const std::list<std::string>& theList) const
2036 {
2037   QList<ActionInfo> aResult;
2038   std::list<std::string>::const_iterator it = theList.cbegin();
2039   for (; it != theList.cend(); it++) {
2040     QString anId = QString::fromStdString(*it);
2041     bool isEditing = anId.endsWith(ModuleBase_OperationFeature::EditSuffix());
2042     if (isEditing) {
2043       anId.chop(ModuleBase_OperationFeature::EditSuffix().size());
2044     }
2045     ActionInfo anInfo;
2046     QAction* aContextMenuAct = myContextMenuMgr->actionByName(anId);
2047     if (aContextMenuAct) {
2048       anInfo.initFrom(aContextMenuAct);
2049     } else {
2050       anInfo = myActionsMgr->actionInfoById(anId);
2051     }
2052     if (isEditing) {
2053       anInfo.text = anInfo.text.prepend("Modify ");
2054     }
2055     aResult << anInfo;
2056   }
2057   return aResult;
2058 }
2059
2060 void XGUI_Workshop::synchronizeViewer()
2061 {
2062   SessionPtr aMgr = ModelAPI_Session::get();
2063   DocumentPtr aDoc = aMgr->activeDocument();
2064
2065   synchronizeGroupInViewer(aDoc, ModelAPI_ResultConstruction::group(), false);
2066   synchronizeGroupInViewer(aDoc, ModelAPI_ResultBody::group(), false);
2067   synchronizeGroupInViewer(aDoc, ModelAPI_ResultPart::group(), false);
2068   synchronizeGroupInViewer(aDoc, ModelAPI_ResultGroup::group(), false);
2069 }
2070
2071 void XGUI_Workshop::synchronizeGroupInViewer(const DocumentPtr& theDoc, 
2072                                              const std::string& theGroup, 
2073                                              bool theUpdateViewer)
2074 {
2075   ObjectPtr aObj;
2076   int aSize = theDoc->size(theGroup);
2077   for (int i = 0; i < aSize; i++) {
2078     aObj = theDoc->object(theGroup, i);
2079     if (aObj->isDisplayed()) {
2080       // Hide the presentation with an empty shape. But isDisplayed state of the object should not
2081       // be changed to the object becomes visible when the shape becomes not empty
2082       ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
2083       if (aRes.get() && (!aRes->shape().get() || aRes->shape()->isNull()))
2084         continue;
2085       myDisplayer->display(aObj, false);
2086     }
2087   }
2088   if (theUpdateViewer)
2089     myDisplayer->updateViewer();
2090 }
2091
2092 void XGUI_Workshop::highlightResults(const QObjectPtrList& theObjects)
2093 {
2094   FeaturePtr aFeature;
2095   QObjectPtrList aSelList = theObjects;
2096   std::list<ResultPtr> aResList;
2097   bool aHasHidden = false;
2098   foreach(ObjectPtr aObj, theObjects) {
2099     aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
2100     if (aFeature.get()) {
2101       aResList = aFeature->results();
2102       std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aIt;
2103       for(aIt = aResList.cbegin(); aIt != aResList.cend(); aIt++) {
2104         aHasHidden |= (*aIt)->isConcealed();
2105         aSelList.append(*aIt);
2106       }
2107     }
2108   }
2109   if (aSelList.count() > theObjects.count()) {
2110     // if something was found
2111     bool aBlocked = objectBrowser()->blockSignals(true);
2112     objectBrowser()->setObjectsSelected(aSelList);
2113     objectBrowser()->blockSignals(aBlocked);
2114   }
2115   if (aHasHidden) 
2116     QMessageBox::information(desktop(), tr("Find results"), 
2117                              tr("Results not found"), QMessageBox::Ok);
2118 }
2119
2120 void XGUI_Workshop::highlightFeature(const QObjectPtrList& theObjects)
2121 {
2122   ResultPtr aResult;
2123   QObjectPtrList aSelList = theObjects;
2124   FeaturePtr aFeature;
2125   foreach(ObjectPtr aObj, theObjects) {
2126     aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
2127     if (aResult.get()) {
2128       aFeature = ModelAPI_Feature::feature(aResult);
2129       if (aFeature.get()) {
2130         aSelList.append(aFeature);
2131       }
2132     }
2133   }
2134   if (aSelList.count() > theObjects.count()) {
2135     // if something was found
2136     bool aBlocked = objectBrowser()->blockSignals(true);
2137     objectBrowser()->setObjectsSelected(aSelList);
2138     objectBrowser()->blockSignals(aBlocked);
2139   }
2140 }