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