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