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