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