]> SALOME platform Git repositories - modules/shaper.git/blob - src/XGUI/XGUI_Workshop.cpp
Salome HOME
Warning dialog before deletion shows directly dependent features and indirectly ones.
[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_ColorDialog.h"
8 #include "XGUI_ContextMenuMgr.h"
9 #include "XGUI_Displayer.h"
10 #include "XGUI_ErrorDialog.h"
11 #include "XGUI_ErrorMgr.h"
12 #include "XGUI_ModuleConnector.h"
13 #include "XGUI_ObjectsBrowser.h"
14 #include "XGUI_OperationMgr.h"
15 #include "XGUI_PropertyPanel.h"
16 #include "XGUI_SalomeConnector.h"
17 #include "XGUI_Selection.h"
18 #include "XGUI_SelectionMgr.h"
19 #include "XGUI_Tools.h"
20 #include "XGUI_ViewerProxy.h"
21 #include "XGUI_WorkshopListener.h"
22 #include <XGUI_CustomPrs.h>
23 #include <XGUI_HistoryMenu.h>
24 #include <XGUI_QtEvents.h>
25
26 #include <AppElements_Button.h>
27 #include <AppElements_Command.h>
28 #include <AppElements_MainMenu.h>
29 #include <AppElements_MainWindow.h>
30 #include <AppElements_MenuGroupPanel.h>
31 #include <AppElements_Viewer.h>
32 #include <AppElements_Workbench.h>
33
34 #include <ModelAPI_AttributeDocRef.h>
35 #include <ModelAPI_AttributeIntArray.h>
36 #include <ModelAPI_Data.h>
37 #include <ModelAPI_Events.h>
38 #include <ModelAPI_Feature.h>
39 #include <ModelAPI_Object.h>
40 #include <ModelAPI_ResultBody.h>
41 #include <ModelAPI_ResultConstruction.h>
42 #include <ModelAPI_ResultGroup.h>
43 #include <ModelAPI_ResultParameter.h>
44 #include <ModelAPI_Session.h>
45 #include <ModelAPI_Validator.h>
46 #include <ModelAPI_ResultCompSolid.h>
47
48 //#include <PartSetPlugin_Part.h>
49
50 #include <Events_Loop.h>
51 #include <Events_Error.h>
52 #include <Events_LongOp.h>
53
54 #include <ModuleBase_FilterFactory.h>
55 #include <ModuleBase_IModule.h>
56 #include <ModuleBase_IViewer.h>
57 #include <ModuleBase_Operation.h>
58 #include <ModuleBase_OperationDescription.h>
59 #include <ModuleBase_PageBase.h>
60 #include <ModuleBase_Preferences.h>
61 #include <ModuleBase_SelectionValidator.h>
62 #include <ModuleBase_Tools.h>
63 #include <ModuleBase_WidgetFactory.h>
64
65 #include <Config_Common.h>
66 #include <Config_FeatureMessage.h>
67 #include <Config_ModuleReader.h>
68 #include <Config_PointerMessage.h>
69 #include <Config_PropManager.h>
70 #include <Config_SelectionFilterMessage.h>
71
72 #include <SUIT_ResourceMgr.h>
73
74 #include <QApplication>
75 #include <QFileDialog>
76 #include <QMessageBox>
77 #include <QMdiSubWindow>
78 #include <QPushButton>
79 #include <QDockWidget>
80 #include <QLayout>
81 #include <QThread>
82 #include <QObject>
83 #include <QMenu>
84 #include <QToolButton>
85 #include <QAction>
86 #include <QDesktopWidget>
87
88 #include <iterator>
89
90 #ifdef _DEBUG
91 #include <QDebug>
92 #include <iostream>
93 #endif
94
95 #ifdef WIN32
96 #include <windows.h>
97 #else
98 #include <dlfcn.h>
99 #endif
100
101 //#define DEBUG_DELETE
102
103 XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
104     : QObject(),
105       myCurrentDir(QString()),
106       myModule(NULL),
107       mySalomeConnector(theConnector),
108       myPropertyPanel(0),
109       myObjectBrowser(0),
110       myDisplayer(0)
111 {
112   myMainWindow = mySalomeConnector ? 0 : new AppElements_MainWindow();
113
114   if (myMainWindow) {
115     SUIT_ResourceMgr* aResMgr = ModuleBase_Preferences::resourceMgr();
116     bool aCloc = aResMgr->booleanValue("language", "locale", true);
117     if (aCloc)
118       QLocale::setDefault( QLocale::c() );
119     else 
120       QLocale::setDefault( QLocale::system() );
121   }
122
123   myDisplayer = new XGUI_Displayer(this);
124
125   mySelector = new XGUI_SelectionMgr(this);
126   //connect(mySelector, SIGNAL(selectionChanged()), this, SLOT(updateModuleCommands()));
127
128   myOperationMgr = new XGUI_OperationMgr(this, 0);
129   myActionsMgr = new XGUI_ActionsMgr(this);
130   myErrorDlg = new XGUI_ErrorDialog(QApplication::desktop());
131   myErrorMgr = new XGUI_ErrorMgr(this);
132   myContextMenuMgr = new XGUI_ContextMenuMgr(this);
133   connect(myContextMenuMgr, SIGNAL(actionTriggered(const QString&, bool)), this,
134           SLOT(onContextMenuCommand(const QString&, bool)));
135
136   myViewerProxy = new XGUI_ViewerProxy(this);
137   connect(myViewerProxy, SIGNAL(selectionChanged()),
138           myActionsMgr,  SLOT(updateOnViewSelection()));
139
140   myModuleConnector = new XGUI_ModuleConnector(this);
141
142   ModuleBase_IWorkshop* aWorkshop = moduleConnector();
143   myOperationMgr->setWorkshop(aWorkshop);
144
145   myEventsListener = new XGUI_WorkshopListener(aWorkshop);
146
147   connect(myOperationMgr, SIGNAL(operationStarted(ModuleBase_Operation*)), 
148           SLOT(onOperationStarted(ModuleBase_Operation*)));
149   connect(myOperationMgr, SIGNAL(operationResumed(ModuleBase_Operation*)),
150           SLOT(onOperationResumed(ModuleBase_Operation*)));
151   connect(myOperationMgr, SIGNAL(operationStopped(ModuleBase_Operation*)),
152           SLOT(onOperationStopped(ModuleBase_Operation*)));
153   connect(myOperationMgr, SIGNAL(operationCommitted(ModuleBase_Operation*)), 
154           SLOT(onOperationCommitted(ModuleBase_Operation*)));
155   connect(myOperationMgr, SIGNAL(operationAborted(ModuleBase_Operation*)), 
156           SLOT(onOperationAborted(ModuleBase_Operation*)));
157   connect(myOperationMgr, SIGNAL(validationStateChanged(bool)), 
158           myErrorMgr, SLOT(onValidationStateChanged()));
159
160   if (myMainWindow)
161     connect(myMainWindow, SIGNAL(exitKeySequence()), SLOT(onExit()));
162   connect(this, SIGNAL(errorOccurred(const QString&)), myErrorDlg, SLOT(addError(const QString&)));
163   connect(myEventsListener, SIGNAL(errorOccurred(const QString&)),
164           myErrorDlg, SLOT(addError(const QString&)));
165
166   //Config_PropManager::registerProp("Visualization", "object_default_color", "Object color",
167   //                                 Config_Prop::Color, "225,225,225");
168
169   Config_PropManager::registerProp("Visualization", "result_body_color", "Body color",
170                                    Config_Prop::Color, ModelAPI_ResultBody::DEFAULT_COLOR());
171   Config_PropManager::registerProp("Visualization", "result_group_color", "Group color",
172                                    Config_Prop::Color, ModelAPI_ResultGroup::DEFAULT_COLOR());
173   Config_PropManager::registerProp("Visualization", "result_construction_color", "Construction color",
174                                    Config_Prop::Color, ModelAPI_ResultConstruction::DEFAULT_COLOR());
175   Config_PropManager::registerProp("Visualization", "result_part_color", "Part color",
176                                    Config_Prop::Color, ModelAPI_ResultPart::DEFAULT_COLOR());
177 }
178
179 //******************************************************
180 XGUI_Workshop::~XGUI_Workshop(void)
181 {
182   delete myDisplayer;
183 }
184
185 //******************************************************
186 void XGUI_Workshop::startApplication()
187 {
188   initMenu();
189
190   Config_PropManager::registerProp("Plugins", "default_path", "Default Path",
191                                    Config_Prop::Directory, "");
192
193   //Initialize event listening
194   myEventsListener->initializeEventListening();
195
196   registerValidators();
197
198   // Calling of  loadCustomProps before activating module is required
199   // by Config_PropManger to restore user-defined path to plugins
200   ModuleBase_Preferences::loadCustomProps();
201   createModule();
202   if (myMainWindow) {
203     myMainWindow->show();
204     updateCommandStatus();
205   }
206   
207   onNew();
208
209   emit applicationStarted();
210 }
211
212 void XGUI_Workshop::activateModule()
213 {
214   myModule->activateSelectionFilters();
215
216   connect(myDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)),
217     myModule, SLOT(onObjectDisplayed(ObjectPtr, AISObjectPtr)));
218   connect(myDisplayer, SIGNAL(beforeObjectErase(ObjectPtr, AISObjectPtr)),
219     myModule, SLOT(onBeforeObjectErase(ObjectPtr, AISObjectPtr)));
220
221   myActionsMgr->update();
222
223 }
224
225 void XGUI_Workshop::deactivateModule()
226 {
227   myModule->deactivateSelectionFilters();
228
229   disconnect(myDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)),
230     myModule, SLOT(onObjectDisplayed(ObjectPtr, AISObjectPtr)));
231   disconnect(myDisplayer, SIGNAL(beforeObjectErase(ObjectPtr, AISObjectPtr)),
232     myModule, SLOT(onBeforeObjectErase(ObjectPtr, AISObjectPtr)));
233 }
234
235 //******************************************************
236 void XGUI_Workshop::initMenu()
237 {
238   myContextMenuMgr->createActions();
239
240   if (isSalomeMode()) {
241     // Create only Undo, Redo commands
242     QAction* aAction = salomeConnector()->addDesktopCommand("UNDO_CMD", tr("Undo"),
243                                                          tr("Undo last command"),
244                                                          QIcon(":pictures/undo.png"),
245                                                          QKeySequence::Undo, false, "MEN_DESK_EDIT");
246     connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onUndo()));
247     addHistoryMenu(aAction, SIGNAL(updateUndoHistory(const QList<ActionInfo>&)), SLOT(onUndo(int)));
248
249     aAction = salomeConnector()->addDesktopCommand("REDO_CMD", tr("Redo"), tr("Redo last command"),
250                                                 QIcon(":pictures/redo.png"), QKeySequence::Redo,
251                                                 false, "MEN_DESK_EDIT");
252     connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onRedo()));
253     addHistoryMenu(aAction, SIGNAL(updateRedoHistory(const QList<ActionInfo>&)), SLOT(onRedo(int)));
254
255     salomeConnector()->addDesktopMenuSeparator("MEN_DESK_EDIT");
256     aAction = salomeConnector()->addDesktopCommand("REBUILD_CMD", tr("Rebuild"), tr("Rebuild data objects"),
257                                                 QIcon(":pictures/rebuild.png"), QKeySequence(),
258                                                 false, "MEN_DESK_EDIT");
259     connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onRebuild()));
260     salomeConnector()->addDesktopMenuSeparator("MEN_DESK_EDIT");
261
262     aAction = salomeConnector()->addDesktopCommand("SAVEAS_CMD", tr("Export NewGeom..."), tr("Export the current document into a NewGeom file"),
263                                                 QIcon(), QKeySequence(),
264                                                 false, "MEN_DESK_FILE");
265     connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onSaveAs()));
266
267     aAction = salomeConnector()->addDesktopCommand("OPEN_CMD", tr("Import NewGeom..."), tr("Import a NewGeom file"),
268                                                 QIcon(), QKeySequence(),
269                                                 false, "MEN_DESK_FILE");
270     connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onOpen()));
271     salomeConnector()->addDesktopMenuSeparator("MEN_DESK_FILE");
272
273     return;
274   }
275   // File commands group
276   AppElements_MenuGroupPanel* aGroup = myMainWindow->menuObject()->generalPage();
277
278   AppElements_Command* aCommand;
279
280   aCommand = aGroup->addFeature("SAVE_CMD", tr("Save"), tr("Save the document"),
281                                 QIcon(":pictures/save.png"), QKeySequence::Save);
282   aCommand->connectTo(this, SLOT(onSave()));
283   //aCommand->disable();
284
285   QString aUndoId = "UNDO_CMD";
286   aCommand = aGroup->addFeature(aUndoId, tr("Undo"), tr("Undo last command"),
287                                 QIcon(":pictures/undo.png"), QKeySequence::Undo);
288   aCommand->connectTo(this, SLOT(onUndo()));
289   AppElements_Button* aUndoButton = qobject_cast<AppElements_Button*>(aGroup->widget(aUndoId));
290   addHistoryMenu(aUndoButton,
291                  SIGNAL(updateUndoHistory(const QList<ActionInfo>&)),
292                  SLOT(onUndo(int)));
293
294   QString aRedoId = "REDO_CMD";
295   aCommand = aGroup->addFeature(aRedoId, tr("Redo"), tr("Redo last command"),
296                                 QIcon(":pictures/redo.png"), QKeySequence::Redo);
297   aCommand->connectTo(this, SLOT(onRedo()));
298   AppElements_Button* aRedoButton = qobject_cast<AppElements_Button*>(aGroup->widget(aRedoId));
299   addHistoryMenu(aRedoButton,
300                  SIGNAL(updateRedoHistory(const QList<ActionInfo>&)),
301                  SLOT(onRedo(int)));
302
303   aCommand = aGroup->addFeature("REBUILD_CMD", tr("Rebuild"), tr("Rebuild data objects"),
304     QIcon(":pictures/rebuild.png"), QKeySequence());
305   aCommand->connectTo(this, SLOT(onRebuild()));
306
307   aCommand = aGroup->addFeature("SAVEAS_CMD", tr("Save as..."), tr("Save the document into a file"),
308                                 QIcon(":pictures/save.png"), QKeySequence());
309   aCommand->connectTo(this, SLOT(onSaveAs()));
310   //aCommand->disable();
311
312   aCommand = aGroup->addFeature("OPEN_CMD", tr("Open..."), tr("Open a new document"),
313                                 QIcon(":pictures/open.png"), QKeySequence::Open);
314   aCommand->connectTo(this, SLOT(onOpen()));
315
316   //aCommand = aGroup->addFeature("NEW_CMD", tr("New"), tr("Create a new document"),
317   //                              QIcon(":pictures/new.png"), QKeySequence::New);
318   //aCommand->connectTo(this, SLOT(onNew()));
319
320   aCommand = aGroup->addFeature("PREF_CMD", tr("Preferences"), tr("Edit preferences"),
321                                 QIcon(":pictures/preferences.png"), QKeySequence::Preferences);
322   aCommand->connectTo(this, SLOT(onPreferences()));
323
324   aCommand = aGroup->addFeature("EXIT_CMD", tr("Exit"), tr("Exit application"),
325                                 QIcon(":pictures/close.png"), QKeySequence::Close);
326   aCommand->connectTo(this, SLOT(onExit()));
327   //FIXME: SBH's test action. Can be used for some GUI tests.
328 //  #ifdef _DEBUG
329 //    aCommand = aGroup->addFeature("TEST_CMD", "Test!", "Private debug button",
330 //                                  QIcon(":pictures/close.png"), QKeySequence(), true);
331 //    aCommand->connectTo(myMainWindow, SLOT(dockPythonConsole()));
332 //  #endif
333 }
334
335 //******************************************************
336 AppElements_Workbench* XGUI_Workshop::addWorkbench(const QString& theName)
337 {
338   AppElements_MainMenu* aMenuBar = myMainWindow->menuObject();
339   return aMenuBar->addWorkbench(theName);
340 }
341
342 //******************************************************
343 QMainWindow* XGUI_Workshop::desktop() const
344 {
345   return isSalomeMode() ? salomeConnector()->desktop() : myMainWindow;
346 }
347
348 //******************************************************
349 void XGUI_Workshop::onStartWaiting()
350 {
351   if (Events_LongOp::isPerformed()) {
352     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
353   }
354 }
355
356
357 //******************************************************
358 void XGUI_Workshop::deactivateActiveObject(const ObjectPtr& theObject, const bool theUpdateViewer)
359 {
360   if (!myModule->canActivateSelection(theObject)) {
361     if (myDisplayer->isActive(theObject))
362       myDisplayer->deactivate(theObject, theUpdateViewer);
363   }
364 }
365
366 //******************************************************
367 void XGUI_Workshop::onOperationStarted(ModuleBase_Operation* theOperation)
368 {
369   setNestedFeatures(theOperation);
370
371   if (theOperation->getDescription()->hasXmlRepresentation()) {  //!< No need for property panel
372     connectWithOperation(theOperation);
373     setPropertyPanel(theOperation);
374     // filling the operation values by the current selection
375     // if the operation can be commited after the controls filling, the method perform should
376     // be stopped. Otherwise unnecessary presentations can be shown(e.g. operation prs in sketch)
377     if (!theOperation->isEditOperation()) {
378       theOperation->activateByPreselection();
379       if (operationMgr()->currentOperation() != theOperation)
380         return;
381     }
382   }
383   updateCommandStatus();
384
385   myModule->onOperationStarted(theOperation);
386
387   // the objects of the current operation should be deactivated
388   QObjectPtrList anObjects;
389   FeaturePtr aFeature = theOperation->feature();
390   anObjects.append(aFeature);
391   std::list<ResultPtr> aResults = aFeature->results();
392   std::list<ResultPtr>::const_iterator aIt;
393   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
394     anObjects.append(*aIt);
395   }
396   QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
397   for (; anIt != aLast; anIt++)
398     deactivateActiveObject(*anIt, false);
399   if (anObjects.size() > 0)
400     myDisplayer->updateViewer();
401 }
402
403 //******************************************************
404 void XGUI_Workshop::onOperationResumed(ModuleBase_Operation* theOperation)
405 {
406   setNestedFeatures(theOperation);
407
408   if (theOperation->getDescription()->hasXmlRepresentation()) {  //!< No need for property panel
409     // connectWithOperation(theOperation); already connected
410     setPropertyPanel(theOperation);
411   }
412   updateCommandStatus();
413
414   myModule->onOperationResumed(theOperation);
415 }
416
417
418 //******************************************************
419 void XGUI_Workshop::onOperationStopped(ModuleBase_Operation* theOperation)
420 {
421   ModuleBase_ISelection* aSel = mySelector->selection();
422   QObjectPtrList aObj = aSel->selectedPresentations();
423   //!< No need for property panel
424   updateCommandStatus();
425   hidePropertyPanel();
426   myPropertyPanel->cleanContent();
427
428   myModule->onOperationStopped(theOperation);
429
430   // the deactivated objects of the current operation should be activated back.
431   // They were deactivated on operation start or an object redisplay
432   QObjectPtrList anObjects;
433   FeaturePtr aFeature = theOperation->feature();
434   if (myDisplayer->isVisible(aFeature) && !myDisplayer->isActive(aFeature))
435     anObjects.append(aFeature);
436   std::list<ResultPtr> aResults = aFeature->results();
437   std::list<ResultPtr>::const_iterator aIt;
438   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
439     ResultPtr anObject = *aIt;
440     if (myDisplayer->isVisible(anObject) && !myDisplayer->isActive(anObject)) {
441       anObjects.append(anObject);
442     }
443   }
444   QIntList aModes;
445   module()->activeSelectionModes(aModes);
446   myDisplayer->activateObjects(aModes, anObjects);
447 }
448
449
450 void XGUI_Workshop::onOperationCommitted(ModuleBase_Operation* theOperation)
451 {
452   myModule->onOperationCommitted(theOperation);
453 }
454
455 void XGUI_Workshop::onOperationAborted(ModuleBase_Operation* theOperation)
456 {
457   myModule->onOperationAborted(theOperation);
458 }
459
460 void XGUI_Workshop::setNestedFeatures(ModuleBase_Operation* theOperation)
461 {
462   if (this->isSalomeMode()) 
463     theOperation->setNestedFeatures(mySalomeConnector->nestedActions(theOperation->id()));
464   else 
465     theOperation->setNestedFeatures(myActionsMgr->nestedCommands(theOperation->id()));
466 }
467
468 void XGUI_Workshop::setPropertyPanel(ModuleBase_Operation* theOperation)
469 {
470   showPropertyPanel();
471   QString aXmlRepr = theOperation->getDescription()->xmlRepresentation();
472   ModuleBase_WidgetFactory aFactory = ModuleBase_WidgetFactory(aXmlRepr.toStdString(),
473                                                                 myModuleConnector);
474
475   myPropertyPanel->cleanContent();
476   aFactory.createWidget(myPropertyPanel->contentWidget());
477
478   QList<ModuleBase_ModelWidget*> aWidgets = aFactory.getModelWidgets();
479   foreach (ModuleBase_ModelWidget* aWidget, aWidgets) {
480     bool isStoreValue = !theOperation->isEditOperation() &&
481                         !aWidget->getDefaultValue().empty() &&
482                         !aWidget->isComputedDefault();
483     aWidget->setFeature(theOperation->feature(), isStoreValue);
484     aWidget->enableFocusProcessing();
485   }
486   
487   myPropertyPanel->setModelWidgets(aWidgets);
488   theOperation->setPropertyPanel(myPropertyPanel);
489
490   myModule->propertyPanelDefined(theOperation);
491
492   myPropertyPanel->setWindowTitle(theOperation->getDescription()->description());
493
494   myErrorMgr->setPropertyPanel(myPropertyPanel);
495 }
496
497 /*
498  * Makes a signal/slot connections between Property Panel
499  * and given operation. The given operation becomes a
500  * current operation and previous operation if exists
501  */
502 void XGUI_Workshop::connectWithOperation(ModuleBase_Operation* theOperation)
503 {
504   QAction* aCommand = 0;
505   if (isSalomeMode()) {
506     aCommand = salomeConnector()->command(theOperation->getDescription()->operationId());
507   } else {
508     AppElements_MainMenu* aMenu = myMainWindow->menuObject();
509     FeaturePtr aFeature = theOperation->feature();
510     if(aFeature)
511       aCommand = aMenu->feature(QString::fromStdString(aFeature->getKind()));
512   }
513   //Abort operation on uncheck the command
514   if (aCommand) {
515     connect(aCommand, SIGNAL(triggered(bool)), theOperation, SLOT(setRunning(bool)));
516   }
517 }
518
519 /*
520  * Saves document with given name.
521  */
522 void XGUI_Workshop::saveDocument(const QString& theName, std::list<std::string>& theFileNames)
523 {
524   QApplication::restoreOverrideCursor();
525   SessionPtr aMgr = ModelAPI_Session::get();
526   aMgr->save(theName.toLatin1().constData(), theFileNames);
527   QApplication::restoreOverrideCursor();
528 }
529
530 bool XGUI_Workshop::isActiveOperationAborted()
531 {
532   return myOperationMgr->abortAllOperations();
533 }
534
535 //******************************************************
536 void XGUI_Workshop::onExit()
537 {
538   SessionPtr aMgr = ModelAPI_Session::get();
539   if (aMgr->isModified()) {
540     int anAnswer = QMessageBox::question(
541         myMainWindow, tr("Save current file"), tr("The document is modified, save before exit?"),
542         QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel);
543     if (anAnswer == QMessageBox::Save) {
544       bool saved = onSave();
545       if (!saved) {
546         return;
547       }
548     } else if (anAnswer == QMessageBox::Cancel) {
549       return;
550     }
551   }
552   qApp->exit();
553 }
554
555 //******************************************************
556 void XGUI_Workshop::onNew()
557 {
558   QApplication::setOverrideCursor(Qt::WaitCursor);
559   if (objectBrowser() == 0) {
560     createDockWidgets();
561     mySelector->connectViewers();
562   }
563   myViewerProxy->connectToViewer();
564   showObjectBrowser();
565   if (!isSalomeMode()) {
566     myMainWindow->showPythonConsole();
567     QMdiSubWindow* aWnd = myMainWindow->viewer()->createView();
568     aWnd->showMaximized();
569     updateCommandStatus();
570   }
571   myContextMenuMgr->connectViewer();
572   QApplication::restoreOverrideCursor();
573 }
574
575 //******************************************************
576 void XGUI_Workshop::onOpen()
577 {
578   if(!isActiveOperationAborted())
579     return;
580   //save current file before close if modified
581   SessionPtr aSession = ModelAPI_Session::get();
582   if (aSession->isModified()) {
583     //TODO(sbh): re-launch the app?
584     int anAnswer = QMessageBox::question(
585         myMainWindow, tr("Save current file"),
586         tr("The document is modified, save before opening another?"),
587         QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel);
588     if (anAnswer == QMessageBox::Save) {
589       onSave();
590     } else if (anAnswer == QMessageBox::Cancel) {
591       return;
592     }
593     myCurrentDir = "";
594   }
595
596   //show file dialog, check if readable and open
597   myCurrentDir = QFileDialog::getExistingDirectory(mainWindow(), tr("Select directory"));
598   if (myCurrentDir.isEmpty())
599     return;
600   QFileInfo aFileInfo(myCurrentDir);
601   if (!aFileInfo.exists() || !aFileInfo.isReadable()) {
602     QMessageBox::critical(myMainWindow, tr("Warning"), tr("Unable to open the file."));
603     myCurrentDir = "";
604     return;
605   }
606   QApplication::setOverrideCursor(Qt::WaitCursor);
607   aSession->closeAll();
608   aSession->load(myCurrentDir.toLatin1().constData());
609   myObjectBrowser->rebuildDataTree();
610   //displayAllResults();
611   updateCommandStatus();
612   QApplication::restoreOverrideCursor();
613 }
614
615 //******************************************************
616 bool XGUI_Workshop::onSave()
617 {
618   if(!isActiveOperationAborted())
619     return false;
620   if (myCurrentDir.isEmpty()) {
621     return onSaveAs();
622   }
623   std::list<std::string> aFiles;
624   saveDocument(myCurrentDir, aFiles);
625   updateCommandStatus();
626   if (!isSalomeMode())
627     myMainWindow->setModifiedState(false);
628   return true;
629 }
630
631 //******************************************************
632 bool XGUI_Workshop::onSaveAs()
633 {
634   if(!isActiveOperationAborted())
635     return false;
636   QFileDialog dialog(mainWindow());
637   dialog.setWindowTitle(tr("Select directory to save files..."));
638   dialog.setFileMode(QFileDialog::Directory);
639   dialog.setFilter(tr("Directories (*)"));
640   dialog.setOptions(QFileDialog::HideNameFilterDetails | QFileDialog::ShowDirsOnly);
641   dialog.setViewMode(QFileDialog::Detail);
642
643   if (!dialog.exec()) {
644     return false;
645   }
646
647   QString aTempDir = dialog.selectedFiles().first();
648   QDir aDir(aTempDir);
649   if (aDir.exists() && !aDir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries).isEmpty()) {
650     int answer = QMessageBox::question(
651         myMainWindow,
652         //: Title of the dialog which asks user if he wants to save study in existing non-empty folder
653         tr("Save"),
654         tr("The directory already contains some files, save anyway?"),
655         QMessageBox::Save | QMessageBox::Cancel);
656     if (answer == QMessageBox::Cancel) {
657       return false;
658     }
659   }
660   myCurrentDir = aTempDir;
661   if (!isSalomeMode()) {
662     myMainWindow->setCurrentDir(myCurrentDir, false);
663     myMainWindow->setModifiedState(false);
664   }
665   return onSave();
666 }
667
668 //******************************************************
669 void XGUI_Workshop::onUndo(int theTimes)
670 {
671   objectBrowser()->treeView()->setCurrentIndex(QModelIndex());
672   SessionPtr aMgr = ModelAPI_Session::get();
673   if (aMgr->isOperation())
674     operationMgr()->onAbortOperation();
675   for (int i = 0; i < theTimes; ++i) {
676     aMgr->undo();
677   }
678   updateCompositeActionState();
679   updateCommandStatus();
680 }
681
682 //******************************************************
683 void XGUI_Workshop::onRedo(int theTimes)
684 {
685   // the viewer update should be blocked in order to avoid the features blinking. For the created
686   // feature a results are created, the flush of the created signal caused the viewer redisplay for
687   // each created result. After a redisplay signal is flushed. So, the viewer update is blocked until
688   // redo of all possible objects happens
689   bool isUpdateEnabled = myDisplayer->enableUpdateViewer(false);
690
691   objectBrowser()->treeView()->setCurrentIndex(QModelIndex());
692   SessionPtr aMgr = ModelAPI_Session::get();
693   if (aMgr->isOperation())
694     operationMgr()->onAbortOperation();
695   for (int i = 0; i < theTimes; ++i) {
696     aMgr->redo();
697   }
698   updateCompositeActionState();
699   updateCommandStatus();
700
701   // unblock the viewer update functionality and make update on purpose
702   myDisplayer->enableUpdateViewer(isUpdateEnabled);
703   myDisplayer->updateViewer();
704 }
705
706 //******************************************************
707 void XGUI_Workshop::onRebuild()
708 {
709   SessionPtr aMgr = ModelAPI_Session::get();
710   bool aWasOperation = aMgr->isOperation(); // keep this value
711   if (!aWasOperation) {
712     aMgr->startOperation("Rebuild");
713   }
714   static const Events_ID aRebuildEvent = Events_Loop::loop()->eventByName("Rebuild");
715   Events_Loop::loop()->send(std::shared_ptr<Events_Message>(
716     new Events_Message(aRebuildEvent, this)));
717   if (!aWasOperation) {
718     aMgr->finishOperation();
719   }
720   updateCommandStatus();
721 }
722
723 //******************************************************
724 void XGUI_Workshop::onPreferences()
725 {
726   ModuleBase_Prefs aModif;
727   ModuleBase_Preferences::editPreferences(aModif);
728   if (aModif.size() > 0) {
729     QString aSection;
730     foreach (ModuleBase_Pref aPref, aModif)
731     {
732       aSection = aPref.first;
733       if (aSection == ModuleBase_Preferences::VIEWER_SECTION) {
734         if (!isSalomeMode())
735           myMainWindow->viewer()->updateFromResources();
736       } else if (aSection == ModuleBase_Preferences::MENU_SECTION) {
737         if (!isSalomeMode())
738           myMainWindow->menuObject()->updateFromResources();
739       }
740     }
741   }
742 }
743
744 //******************************************************
745 ModuleBase_IModule* XGUI_Workshop::loadModule(const QString& theModule)
746 {
747   QString libName = QString::fromStdString(library(theModule.toStdString()));
748   if (libName.isEmpty()) {
749     qWarning(qPrintable(tr("Information about module \"%1\" doesn't exist.").arg(theModule)));
750     return 0;
751   }
752
753   QString err;
754   CREATE_FUNC crtInst = 0;
755
756 #ifdef WIN32
757   HINSTANCE modLib = ::LoadLibrary((LPTSTR) qPrintable(libName));
758   if (!modLib) {
759     LPVOID lpMsgBuf;
760     ::FormatMessage(
761         FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
762         0, ::GetLastError(), 0, (LPTSTR) & lpMsgBuf, 0, 0);
763     QString aMsg((char*) &lpMsgBuf);
764     err = QString("Failed to load  %1. %2").arg(libName).arg(aMsg);
765     ::LocalFree(lpMsgBuf);
766   } else {
767     crtInst = (CREATE_FUNC) ::GetProcAddress(modLib, CREATE_MODULE);
768     if (!crtInst) {
769       LPVOID lpMsgBuf;
770       ::FormatMessage(
771           FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
772               | FORMAT_MESSAGE_IGNORE_INSERTS,
773           0, ::GetLastError(), 0, (LPTSTR) & lpMsgBuf, 0, 0);
774       QString aMsg((char*) &lpMsgBuf);
775       err = QString("Failed to find  %1 function. %2").arg( CREATE_MODULE).arg(aMsg);
776       ::LocalFree(lpMsgBuf);
777     }
778   }
779 #else
780   void* modLib = dlopen( libName.toLatin1(), RTLD_LAZY | RTLD_GLOBAL );
781   if ( !modLib ) {
782     err = QString( "Can not load library %1. %2" ).arg( libName ).arg( dlerror() );
783   } else {
784     crtInst = (CREATE_FUNC)dlsym( modLib, CREATE_MODULE );
785     if ( !crtInst ) {
786       err = QString( "Failed to find function %1. %2" ).arg( CREATE_MODULE ).arg( dlerror() );
787     }
788   }
789 #endif
790
791   ModuleBase_IModule* aModule = crtInst ? crtInst(myModuleConnector) : 0;
792
793   if (!err.isEmpty()) {
794     if (mainWindow()) {
795       Events_Error::send(err.toStdString());
796     } else {
797       qWarning(qPrintable(err));
798     }
799   }
800   return aModule;
801 }
802
803 //******************************************************
804 bool XGUI_Workshop::createModule()
805 {
806   Config_ModuleReader aModuleReader;
807   QString moduleName = QString::fromStdString(aModuleReader.getModuleName());
808   myModule = loadModule(moduleName);
809   if (!myModule)
810     return false;
811
812   //connect(myDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)),
813   //  myModule, SLOT(onObjectDisplayed(ObjectPtr, AISObjectPtr)));
814   //connect(myDisplayer, SIGNAL(beforeObjectErase(ObjectPtr, AISObjectPtr)),
815   //  myModule, SLOT(onBeforeObjectErase(ObjectPtr, AISObjectPtr)));
816
817   myModule->createFeatures();
818   //myActionsMgr->update();
819   return true;
820 }
821
822 //******************************************************
823 void XGUI_Workshop::updateCommandStatus()
824 {
825   QList<QAction*> aCommands;
826   if (isSalomeMode()) {  // update commands in SALOME mode
827     aCommands = salomeConnector()->commandList();
828   } else {
829     AppElements_MainMenu* aMenuBar = myMainWindow->menuObject();
830     foreach (AppElements_Command* aCmd, aMenuBar->features())
831       aCommands.append(aCmd);
832   }
833   SessionPtr aMgr = ModelAPI_Session::get();
834   if (aMgr->hasModuleDocument()) {
835     foreach(QAction* aCmd, aCommands) {
836       QString aId = aCmd->data().toString();
837       if (aId == "UNDO_CMD")
838         aCmd->setEnabled(myModule->canUndo());
839       else if (aId == "REDO_CMD")
840         aCmd->setEnabled(myModule->canRedo());
841       else
842         // Enable all commands
843         aCmd->setEnabled(true);
844     }
845     updateHistory();
846   } else {
847     foreach(QAction* aCmd, aCommands) {
848       QString aId = aCmd->data().toString();
849       if (aId == "NEW_CMD")
850         aCmd->setEnabled(true);
851       else if (aId == "EXIT_CMD")
852         aCmd->setEnabled(true);
853       else
854         aCmd->setEnabled(false);
855     }
856   }
857   myActionsMgr->update();
858   emit commandStatusUpdated();
859 }
860
861 //******************************************************
862 void XGUI_Workshop::updateCompositeActionState()
863 {
864   // in order to apply is enabled only if there are modifications in the model
865   // e.g. sketch can be applyed only if at least one nested element create is finished
866   bool aCanUndo = ModelAPI_Session::get()->canUndo();
867   bool aParentValid = operationMgr()->isParentOperationValid();
868   bool aCurrentValid = operationMgr()->currentOperation() &&
869                        operationMgr()->currentOperation()->isValid();
870
871   QAction* aAcceptAllAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::AcceptAll);
872   aAcceptAllAct->setEnabled(aParentValid && (aCanUndo || aCurrentValid));
873 }
874
875 void XGUI_Workshop::updateHistory()
876 {
877   std::list<std::string> aUndoList = ModelAPI_Session::get()->undoList();
878   QList<ActionInfo> aUndoRes = processHistoryList(aUndoList);
879   emit updateUndoHistory(aUndoRes);
880
881   std::list<std::string> aRedoList = ModelAPI_Session::get()->redoList();
882   QList<ActionInfo> aRedoRes = processHistoryList(aRedoList);
883   emit updateRedoHistory(aRedoRes);
884 }
885
886 //******************************************************
887 QDockWidget* XGUI_Workshop::createObjectBrowser(QWidget* theParent)
888 {
889   QDockWidget* aObjDock = new QDockWidget(theParent);
890   aObjDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea);
891   aObjDock->setWindowTitle(tr("Object browser"));
892   aObjDock->setStyleSheet(
893       "::title { position: relative; padding-left: 5px; text-align: left center }");
894   myObjectBrowser = new XGUI_ObjectsBrowser(aObjDock);
895   myObjectBrowser->setDataModel(myModule->dataModel());
896   myModule->customizeObjectBrowser(myObjectBrowser);
897   aObjDock->setWidget(myObjectBrowser);
898
899   myContextMenuMgr->connectObjectBrowser();
900   return aObjDock;
901 }
902
903 //******************************************************
904 /*
905  * Creates dock widgets, places them in corresponding area
906  * and tabifies if necessary.
907  */
908 void XGUI_Workshop::createDockWidgets()
909 {
910   QMainWindow* aDesktop = isSalomeMode() ? salomeConnector()->desktop() : myMainWindow;
911   QDockWidget* aObjDock = createObjectBrowser(aDesktop);
912   aDesktop->addDockWidget(Qt::LeftDockWidgetArea, aObjDock);
913   myPropertyPanel = new XGUI_PropertyPanel(aDesktop);
914   myPropertyPanel->setupActions(myActionsMgr);
915   myPropertyPanel->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea);
916   aDesktop->addDockWidget(Qt::LeftDockWidgetArea, myPropertyPanel);
917   hidePropertyPanel();  ///<! Invisible by default
918   hideObjectBrowser();
919   aDesktop->tabifyDockWidget(aObjDock, myPropertyPanel);
920   myPropertyPanel->installEventFilter(myOperationMgr);
921
922   QAction* aOkAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Accept);
923   connect(aOkAct, SIGNAL(triggered()), myOperationMgr, SLOT(onCommitOperation()));
924   QAction* aCancelAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Abort);
925   connect(aCancelAct, SIGNAL(triggered()), myOperationMgr, SLOT(onAbortOperation()));
926   connect(myPropertyPanel, SIGNAL(noMoreWidgets()), myModule, SLOT(onNoMoreWidgets()));
927   connect(myPropertyPanel, SIGNAL(keyReleased(QKeyEvent*)),
928           myOperationMgr,  SLOT(onKeyReleased(QKeyEvent*)));
929   connect(myOperationMgr,  SIGNAL(validationStateChanged(bool)),
930           aOkAct,          SLOT(setEnabled(bool)));
931   QAction* aAcceptAllAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::AcceptAll);
932   connect(myOperationMgr,  SIGNAL(nestedStateChanged(bool)),
933           aAcceptAllAct,   SLOT(setEnabled(bool)));
934
935 }
936
937 //******************************************************
938 void XGUI_Workshop::showPropertyPanel()
939 {
940   QAction* aViewAct = myPropertyPanel->toggleViewAction();
941   ///<! Restore ability to close panel from the window's menu
942   aViewAct->setEnabled(true);
943   myPropertyPanel->show();
944   myPropertyPanel->raise();
945 }
946
947 //******************************************************
948 void XGUI_Workshop::hidePropertyPanel()
949 {
950   QAction* aViewAct = myPropertyPanel->toggleViewAction();
951   ///<! Do not allow to show empty property panel
952   aViewAct->setEnabled(false);
953   myPropertyPanel->hide();
954 }
955
956 //******************************************************
957 void XGUI_Workshop::showObjectBrowser()
958 {
959   myObjectBrowser->parentWidget()->show();
960 }
961
962 //******************************************************
963 void XGUI_Workshop::hideObjectBrowser()
964 {
965   myObjectBrowser->parentWidget()->hide();
966 }
967
968 //******************************************************
969 //void XGUI_Workshop::onFeatureTriggered()
970 //{
971 //  QAction* aCmd = dynamic_cast<QAction*>(sender());
972 //  if (aCmd) {
973 //    QString aId = salomeConnector()->commandId(aCmd);
974 //    if (!aId.isNull())
975 //      myModule->launchOperation(aId);
976 //  }
977 //}
978
979 //******************************************************
980 void XGUI_Workshop::salomeViewerSelectionChanged()
981 {
982   emit salomeViewerSelection();
983 }
984
985 //**************************************************************
986 ModuleBase_IViewer* XGUI_Workshop::salomeViewer() const
987 {
988   return mySalomeConnector->viewer();
989 }
990
991 //**************************************************************
992 void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked)
993 {
994   QObjectPtrList aObjects = mySelector->selection()->selectedObjects();
995   if (theId == "DELETE_CMD")
996     deleteObjects();
997   if (theId == "MOVE_CMD")
998     moveObjects();
999   else if (theId == "COLOR_CMD")
1000     changeColor(aObjects);
1001   else if (theId == "SHOW_CMD")
1002     showObjects(aObjects, true);
1003   else if (theId == "HIDE_CMD")
1004     showObjects(aObjects, false);
1005   else if (theId == "SHOW_ONLY_CMD")
1006     showOnlyObjects(aObjects);
1007   else if (theId == "SHADING_CMD")
1008     setDisplayMode(aObjects, XGUI_Displayer::Shading);
1009   else if (theId == "WIREFRAME_CMD")
1010     setDisplayMode(aObjects, XGUI_Displayer::Wireframe);
1011   else if (theId == "HIDEALL_CMD") {
1012     QObjectPtrList aList = myDisplayer->displayedObjects();
1013     foreach (ObjectPtr aObj, aList)
1014       aObj->setDisplayed(false);
1015     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1016   }
1017 }
1018
1019 //**************************************************************
1020 void XGUI_Workshop::deleteObjects()
1021 {
1022   ModuleBase_IModule* aModule = module();
1023   // 1. allow the module to delete objects, do nothing if it has succeed
1024   if (aModule->deleteObjects()) {
1025     updateCommandStatus();
1026     return;
1027   }
1028
1029   if (!isActiveOperationAborted())
1030     return;
1031   QObjectPtrList anObjects = mySelector->selection()->selectedObjects();
1032   // It is necessary to clear selection in order to avoid selection changed event during
1033   // deleteion and negative consequences connected with processing of already deleted items
1034   mySelector->clearSelection();
1035   // check whether the object can be deleted. There should not be parts which are not loaded
1036   if (!XGUI_Tools::canRemoveOrRename(myMainWindow, anObjects))
1037     return;
1038
1039   bool hasResult = false;
1040   bool hasFeature = false;
1041   bool hasParameter = false;
1042   bool hasSubFeature = false;
1043   ModuleBase_Tools::checkObjects(anObjects, hasResult, hasFeature, hasParameter, hasSubFeature);
1044   if (!(hasFeature || hasParameter))
1045     return;
1046
1047   // 1. start operation
1048   QString aDescription = contextMenuMgr()->action("DELETE_CMD")->text();
1049   aDescription += tr(" %1");
1050   QStringList aObjectNames;
1051   foreach (ObjectPtr aObj, anObjects) {
1052     if (!aObj->data()->isValid())
1053       continue;
1054     aObjectNames << QString::fromStdString(aObj->data()->name());
1055   }
1056   aDescription = aDescription.arg(aObjectNames.join(", "));
1057
1058   SessionPtr aMgr = ModelAPI_Session::get();
1059   aMgr->startOperation(aDescription.toStdString());
1060   // 2. close the documents of the removed parts if the result part is in a list of selected objects
1061   // this is performed in the RemoveFeature of Part object.
1062   /*foreach (ObjectPtr aObj, anObjects)
1063   {
1064     ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
1065     if (aPart) {
1066       DocumentPtr aDoc = aObj->document();
1067       if (aDoc == aMgr->activeDocument()) {
1068         aDoc->close();
1069       }
1070     }
1071   }*/
1072   // 3. delete objects
1073   QMainWindow* aDesktop = isSalomeMode() ? salomeConnector()->desktop() : myMainWindow;
1074   std::set<FeaturePtr> anIgnoredFeatures;
1075   if (deleteFeatures(anObjects, anIgnoredFeatures, aDesktop, true)) {
1076     myDisplayer->updateViewer();
1077     aMgr->finishOperation();
1078     updateCommandStatus();
1079   }
1080   else {
1081     aMgr->abortOperation();
1082   }
1083 }
1084
1085 //**************************************************************
1086 void XGUI_Workshop::moveObjects()
1087 {
1088   if (!isActiveOperationAborted())
1089     return;
1090
1091   SessionPtr aMgr = ModelAPI_Session::get();
1092
1093   QString anActionId = "MOVE_CMD";
1094   QString aDescription = contextMenuMgr()->action(anActionId)->text();
1095   aMgr->startOperation(aDescription.toStdString());
1096
1097   QObjectPtrList anObjects = mySelector->selection()->selectedObjects();
1098   DocumentPtr anActiveDocument = aMgr->activeDocument();
1099
1100   FeaturePtr aCurrentFeature = anActiveDocument->currentFeature(true);
1101   foreach (ObjectPtr aObject, anObjects) {
1102     if (!myModule->canApplyAction(aObject, anActionId))
1103       continue;
1104
1105     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObject);
1106     if (aFeature.get()) {
1107       anActiveDocument->moveFeature(aFeature, aCurrentFeature);
1108       aCurrentFeature = anActiveDocument->currentFeature(true);
1109     }
1110   }
1111   aMgr->finishOperation();
1112 }
1113
1114 //**************************************************************
1115 bool XGUI_Workshop::deleteFeatures(const QObjectPtrList& theList,
1116                                    const std::set<FeaturePtr>& theIgnoredFeatures,
1117                                    QWidget* theParent,
1118                                    const bool theAskAboutDeleteReferences)
1119 {
1120 #ifdef DEBUG_DELETE
1121   QStringList aDInfo;
1122   QObjectPtrList::const_iterator aDIt = theList.begin(), aDLast = theList.end();
1123   for (; aDIt != aDLast; ++aDIt) {
1124     aDInfo.append(ModuleBase_Tools::objectInfo((*aDIt)));
1125   }
1126   QString anInfoStr = aDInfo.join(", ");
1127   qDebug(QString("deleteFeatures: %1, %2").arg(theList.size()).arg(anInfoStr).toStdString().c_str());
1128 #endif
1129
1130   // 1. find all referenced features
1131   std::set<FeaturePtr> aDirectRefFeatures, aIndirectRefFeatures;
1132   foreach (ObjectPtr aDeletedObj, theList) {
1133     XGUI_Tools::refsToFeatureInAllDocuments(aDeletedObj, aDeletedObj, aDirectRefFeatures, aIndirectRefFeatures);
1134     std::set<FeaturePtr> aDifference;
1135     std::set_difference(aIndirectRefFeatures.begin(), aIndirectRefFeatures.end(), 
1136                         aDirectRefFeatures.begin(), aDirectRefFeatures.end(), 
1137                         std::inserter(aDifference, aDifference.begin()));
1138     aIndirectRefFeatures = aDifference;
1139   }
1140   // 2. warn about the references remove, break the delete operation if the user chose it
1141   if (theAskAboutDeleteReferences && !aDirectRefFeatures.empty()) {
1142     QStringList aDirectRefNames;
1143     foreach(const FeaturePtr& aFeature, aDirectRefFeatures)
1144       aDirectRefNames.append(aFeature->name().c_str());
1145     QString aDirectNames = aDirectRefNames.join(", ");
1146
1147     QStringList aIndirectRefNames;
1148     foreach(const FeaturePtr& aFeature, aIndirectRefFeatures)
1149       aIndirectRefNames.append(aFeature->name().c_str());
1150     QString aIndirectNames = aIndirectRefNames.join(", ");
1151
1152     QMessageBox::StandardButton aRes = QMessageBox::warning(
1153         theParent, tr("Delete features"),
1154         QString(tr("Selected features are used in the following features: %1.\
1155 These features will be deleted.\n%2Would you like to continue?")).arg(aDirectNames)
1156             .arg(aIndirectNames.isEmpty() ? QString() : QString("Also these features will be deleted: %1.\n").arg(aIndirectNames)),
1157         QMessageBox::No | QMessageBox::Yes, QMessageBox::No);
1158     if (aRes != QMessageBox::Yes)
1159       return false;
1160   }
1161
1162   // 3. remove referenced features
1163   std::set<FeaturePtr> aFeaturesToDelete = aDirectRefFeatures;
1164   aFeaturesToDelete.insert(aIndirectRefFeatures.begin(), aIndirectRefFeatures.end());
1165   std::set<FeaturePtr>::const_iterator anIt = aFeaturesToDelete.begin(),
1166                                        aLast = aFeaturesToDelete.end();
1167 #ifdef DEBUG_DELETE
1168   QStringList anInfo;
1169 #endif
1170   for (; anIt != aLast; anIt++) {
1171     FeaturePtr aFeature = (*anIt);
1172     DocumentPtr aDoc = aFeature->document();
1173     if (theIgnoredFeatures.find(aFeature) == theIgnoredFeatures.end()) {
1174       aDoc->removeFeature(aFeature);
1175 #ifdef DEBUG_DELETE
1176       anInfo.append(ModuleBase_Tools::objectInfo(aFeature).toStdString().c_str());
1177 #endif
1178     }
1179   }
1180 #ifdef DEBUG_DELETE
1181   qDebug(QString("remove references:%1").arg(anInfo.join("; ")).toStdString().c_str());
1182   anInfo.clear();
1183 #endif
1184
1185   QString anActionId = "DELETE_CMD";
1186   QString anId = QString::fromStdString(anActionId.toStdString().c_str());
1187   QStringList anObjectGroups = contextMenuMgr()->actionObjectGroups(anId);
1188   // 4. remove the parameter features
1189   foreach (ObjectPtr aObj, theList) {
1190     // features and parameters can be removed here,
1191     // the results are removed only by a corresponded feature remove
1192     std::string aGroupName = aObj->groupName();
1193     if (!anObjectGroups.contains(aGroupName.c_str()))
1194       continue;
1195
1196     if (!myModule->canApplyAction(aObj, anActionId))
1197       continue;
1198
1199     FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
1200     if (aFeature) {
1201       /*// TODO: to learn the workshop to delegate the Part object deletion to the PartSet module
1202       // part features are removed in the PartSet module. This condition should be moved there
1203       if (aFeature->getKind() == "Part")
1204         continue;
1205         */
1206       DocumentPtr aDoc = aObj->document();
1207       if (theIgnoredFeatures.find(aFeature) == theIgnoredFeatures.end()) {
1208 #ifdef DEBUG_DELETE
1209         QString anInfoStr = ModuleBase_Tools::objectInfo(aFeature);
1210         anInfo.append(anInfoStr);
1211         qDebug(QString("remove feature :%1").arg(anInfoStr).toStdString().c_str());
1212 #endif
1213         aDoc->removeFeature(aFeature);
1214       }
1215     }
1216   }
1217 #ifdef DEBUG_DELETE
1218   qDebug(QString("remove features:%1").arg(anInfo.join("; ")).toStdString().c_str());
1219 #endif
1220   return true;
1221 }
1222
1223 bool hasResults(QObjectPtrList theObjects, const std::set<std::string>& theTypes)
1224 {
1225   bool isFoundResultType = false;
1226   foreach(ObjectPtr anObj, theObjects)
1227   {
1228     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObj);
1229     if (aResult.get() == NULL)
1230       continue;
1231
1232     isFoundResultType = theTypes.find(aResult->groupName()) != theTypes.end();
1233     if (isFoundResultType)
1234       break;
1235   }
1236   return isFoundResultType;
1237 }
1238
1239 //**************************************************************
1240 // Returns the list of features placed between theObject and the current feature
1241 // in the same document. Excludes theObject, includes the current feature.
1242 std::list<FeaturePtr> toCurrentFeatures(const ObjectPtr& theObject)
1243 {
1244   std::list<FeaturePtr> aResult;
1245   DocumentPtr aDocument = theObject->document();
1246   std::list<FeaturePtr> anAllFeatures = aDocument->allFeatures();
1247   // find the object iterator
1248   std::list<FeaturePtr>::iterator aObjectIt = std::find(anAllFeatures.begin(), anAllFeatures.end(), theObject);
1249   if (aObjectIt == anAllFeatures.end()) 
1250     return aResult;
1251   // find the current feature iterator
1252   std::list<FeaturePtr>::iterator aCurrentIt = std::find(anAllFeatures.begin(), anAllFeatures.end(), aDocument->currentFeature(true));
1253   if (aCurrentIt == anAllFeatures.end()) 
1254     return aResult;
1255   // check the right order
1256   if (std::distance(aObjectIt, anAllFeatures.end()) <= std::distance(aCurrentIt, anAllFeatures.end()))
1257     return aResult;
1258   // exclude the object
1259   std::advance(aObjectIt, 1);
1260   // include the current feature
1261   std::advance(aCurrentIt, 1);
1262   return std::list<FeaturePtr>(aObjectIt, aCurrentIt);
1263 }
1264
1265 bool XGUI_Workshop::canMoveFeature()
1266 {
1267   QString anActionId = "MOVE_CMD";
1268
1269   QObjectPtrList aObjects = mySelector->selection()->selectedObjects();
1270   QObjectPtrList aValidatedObjects;
1271   foreach (ObjectPtr aObject, aObjects) {
1272     if (myModule->canApplyAction(aObject, anActionId))
1273       aValidatedObjects.append(aObject);
1274   }
1275   if (aValidatedObjects.size() != aObjects.size())
1276     aObjects = aValidatedObjects;
1277
1278   bool aCanMove = !aObjects.empty();
1279
1280   QObjectPtrList::const_iterator anIt = aObjects.begin(), aLast = aObjects.end();
1281   for (; anIt != aLast && aCanMove; anIt++) {
1282     ObjectPtr aObject = *anIt;
1283     // 1. Get features placed between selected and current in the document 
1284     std::list<FeaturePtr> aFeaturesBetween = toCurrentFeatures(aObject);
1285     // if aFeaturesBetween is empty it means wrong order or aObject is the current feature
1286     if (aFeaturesBetween.empty())
1287       aCanMove = false;
1288     else {
1289       std::set<FeaturePtr> aPlacedFeatures(aFeaturesBetween.begin(), aFeaturesBetween.end());
1290       // 2. Get all reference features to the selected object in the document 
1291       std::set<FeaturePtr> aRefFeatures;
1292       XGUI_Tools::refsToFeatureInFeatureDocument(aObject, aRefFeatures);
1293
1294       if (aRefFeatures.empty())
1295         continue;
1296       else {
1297         // 3. Find any placed features in all reference features
1298         std::set<FeaturePtr> aIntersectionFeatures;
1299         std::set_intersection(aRefFeatures.begin(), aRefFeatures.end(),
1300                               aPlacedFeatures.begin(), aPlacedFeatures.end(),
1301                               std::inserter(aIntersectionFeatures, aIntersectionFeatures.begin()));
1302         // 4. Return false if any reference feature is placed before curent feature
1303         if (!aIntersectionFeatures.empty())
1304           aCanMove = false;
1305       }
1306     }
1307   }
1308   return aCanMove;
1309 }
1310
1311 //**************************************************************
1312 bool XGUI_Workshop::canChangeColor() const
1313 {
1314   QObjectPtrList aObjects = mySelector->selection()->selectedObjects();
1315
1316   std::set<std::string> aTypes;
1317   aTypes.insert(ModelAPI_ResultGroup::group());
1318   aTypes.insert(ModelAPI_ResultConstruction::group());
1319   aTypes.insert(ModelAPI_ResultBody::group());
1320   aTypes.insert(ModelAPI_ResultPart::group());
1321
1322   return hasResults(aObjects, aTypes);
1323 }
1324
1325 void setColor(ResultPtr theResult, std::vector<int>& theColor)
1326 {
1327   if (!theResult.get())
1328     return;
1329
1330   AttributeIntArrayPtr aColorAttr = theResult->data()->intArray(ModelAPI_Result::COLOR_ID());
1331   if (aColorAttr.get() != NULL) {
1332     if (!aColorAttr->size()) {
1333       aColorAttr->setSize(3);
1334     }
1335     aColorAttr->setValue(0, theColor[0]);
1336     aColorAttr->setValue(1, theColor[1]);
1337     aColorAttr->setValue(2, theColor[2]);
1338   }
1339 }
1340
1341 //**************************************************************
1342 void XGUI_Workshop::changeColor(const QObjectPtrList& theObjects)
1343 {
1344   AttributeIntArrayPtr aColorAttr;
1345   // 1. find the current color of the object. This is a color of AIS presentation
1346   // The objects are iterated until a first valid color is found 
1347   std::vector<int> aColor;
1348   foreach(ObjectPtr anObject, theObjects) {
1349     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1350     if (aResult.get()) {
1351       XGUI_CustomPrs::getResultColor(aResult, aColor);
1352     }
1353     else {
1354       // TODO: remove the obtaining a color from the AIS object
1355       // this does not happen never because:
1356       // 1. The color can be changed only on results
1357       // 2. The result can be not visualized in the viewer(e.g. Origin Construction)
1358       AISObjectPtr anAISObj = myDisplayer->getAISObject(anObject);
1359       if (anAISObj.get()) {
1360         aColor.resize(3);
1361         anAISObj->getColor(aColor[0], aColor[1], aColor[2]);
1362       }
1363     }
1364     if (!aColor.empty())
1365       break;
1366   }
1367   if (aColor.size() != 3)
1368     return;
1369
1370   // 2. show the dialog to change the value
1371   XGUI_ColorDialog* aDlg = new XGUI_ColorDialog(mainWindow());
1372   aDlg->setColor(aColor);
1373   aDlg->move(QCursor::pos());
1374   bool isDone = aDlg->exec() == QDialog::Accepted;
1375   if (!isDone)
1376     return;
1377
1378   bool isRandomColor = aDlg->isRandomColor();
1379
1380   // 3. abort the previous operation and start a new one
1381   SessionPtr aMgr = ModelAPI_Session::get();
1382   bool aWasOperation = aMgr->isOperation(); // keep this value
1383   if (!aWasOperation) {
1384     QString aDescription = contextMenuMgr()->action("COLOR_CMD")->text();
1385     aMgr->startOperation(aDescription.toStdString());
1386   }
1387
1388   // 4. set the value to all results
1389   std::vector<int> aColorResult = aDlg->getColor();
1390   foreach(ObjectPtr anObj, theObjects) {
1391     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObj);
1392     if (aResult.get() != NULL) {
1393       ResultCompSolidPtr aCompsolidResult = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aResult);
1394       if (aCompsolidResult.get() != NULL) { // change colors for all sub-solids
1395         for(int i = 0; i < aCompsolidResult->numberOfSubs(); i++) {
1396           ResultPtr aSubResult = aCompsolidResult->subResult(i);
1397           if (aSubResult.get())
1398             setColor(aSubResult, aColorResult);
1399         }
1400       }
1401       setColor(aResult, aColorResult);
1402     }
1403   }
1404   if (!aWasOperation)
1405     aMgr->finishOperation();
1406   updateCommandStatus();
1407 }
1408
1409 //**************************************************************
1410 #define SET_DISPLAY_GROUP(aGroupName, aDisplay) \
1411 for (int i = 0; i < aDoc->size(aGroupName); i++) { \
1412   aDoc->object(aGroupName, i)->setDisplayed(aDisplay); \
1413 }
1414 void XGUI_Workshop::showObjects(const QObjectPtrList& theList, bool isVisible)
1415 {
1416   foreach (ObjectPtr aObj, theList) {
1417     /*
1418     ResultPartPtr aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
1419     if (aPartRes) {
1420       DocumentPtr aDoc = aPartRes->partDoc();
1421       SET_DISPLAY_GROUP(ModelAPI_ResultBody::group(), isVisible)
1422       SET_DISPLAY_GROUP(ModelAPI_ResultConstruction::group(), isVisible)
1423       SET_DISPLAY_GROUP(ModelAPI_ResultGroup::group(), isVisible)
1424     } else {
1425     */
1426       aObj->setDisplayed(isVisible);
1427     //}
1428   }
1429   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1430 }
1431
1432 //**************************************************************
1433 void XGUI_Workshop::showOnlyObjects(const QObjectPtrList& theList)
1434 {
1435   // Hide all displayed objects
1436   QObjectPtrList aList = myDisplayer->displayedObjects();
1437   foreach (ObjectPtr aObj, aList)
1438     aObj->setDisplayed(false);
1439
1440   // Show only objects from the list
1441   foreach (ObjectPtr aObj, theList) {
1442     /*
1443     ResultPartPtr aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
1444     if (aPartRes) {
1445       DocumentPtr aDoc = aPartRes->partDoc();
1446       SET_DISPLAY_GROUP(ModelAPI_ResultBody::group(), true)
1447       SET_DISPLAY_GROUP(ModelAPI_ResultConstruction::group(), true)
1448       SET_DISPLAY_GROUP(ModelAPI_ResultGroup::group(), true)
1449     } else {
1450     */
1451       aObj->setDisplayed(true);
1452     //}
1453   }
1454   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1455
1456 }
1457
1458
1459 //**************************************************************
1460 void XGUI_Workshop::registerValidators() const
1461 {
1462   SessionPtr aMgr = ModelAPI_Session::get();
1463   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
1464 }
1465
1466 //**************************************************************
1467 /*void XGUI_Workshop::displayAllResults()
1468 {
1469   SessionPtr aMgr = ModelAPI_Session::get();
1470   DocumentPtr aRootDoc = aMgr->moduleDocument();
1471   displayDocumentResults(aRootDoc);
1472   for (int i = 0; i < aRootDoc->size(ModelAPI_ResultPart::group()); i++) {
1473     ObjectPtr aObject = aRootDoc->object(ModelAPI_ResultPart::group(), i);
1474     ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObject);
1475     displayDocumentResults(aPart->partDoc());
1476   }
1477   myDisplayer->updateViewer();
1478 }*/
1479
1480 //**************************************************************
1481 void XGUI_Workshop::displayDocumentResults(DocumentPtr theDoc)
1482 {
1483   if (!theDoc)
1484     return;
1485   displayGroupResults(theDoc, ModelAPI_ResultConstruction::group());
1486   displayGroupResults(theDoc, ModelAPI_ResultBody::group());
1487 }
1488
1489 //**************************************************************
1490 void XGUI_Workshop::displayGroupResults(DocumentPtr theDoc, std::string theGroup)
1491 {
1492   for (int i = 0; i < theDoc->size(theGroup); i++) 
1493     theDoc->object(theGroup, i)->setDisplayed(true);
1494     //displayObject(theDoc->object(theGroup, i));
1495   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1496 }
1497
1498 //**************************************************************
1499 void XGUI_Workshop::setDisplayMode(const QObjectPtrList& theList, int theMode)
1500 {
1501   foreach(ObjectPtr aObj, theList) {
1502     myDisplayer->setDisplayMode(aObj, (XGUI_Displayer::DisplayMode)theMode, false);
1503   }
1504   if (theList.size() > 0)
1505     myDisplayer->updateViewer();
1506 }
1507
1508 //**************************************************************
1509 void XGUI_Workshop::closeDocument()
1510 {
1511   ModuleBase_Operation* anOperation = operationMgr()->currentOperation();
1512   while (anOperation) {
1513     anOperation->abort();
1514     anOperation = operationMgr()->currentOperation();
1515   }
1516   myDisplayer->closeLocalContexts();
1517   myDisplayer->eraseAll();
1518   objectBrowser()->clearContent();
1519
1520   SessionPtr aMgr = ModelAPI_Session::get();
1521   aMgr->closeAll();
1522 }
1523
1524 void XGUI_Workshop::addHistoryMenu(QObject* theObject, const char* theSignal, const char* theSlot)
1525 {
1526   XGUI_HistoryMenu* aMenu = NULL;
1527   if (isSalomeMode()) {
1528     QAction* anAction = qobject_cast<QAction*>(theObject);
1529     if (!anAction)
1530       return;
1531     aMenu = new XGUI_HistoryMenu(anAction);
1532   } else {
1533     QToolButton* aButton =  qobject_cast<QToolButton*>(theObject);
1534     aMenu = new XGUI_HistoryMenu(aButton);
1535   }
1536   connect(this, theSignal, aMenu, SLOT(setHistory(const QList<ActionInfo>&)));
1537   connect(aMenu, SIGNAL(actionSelected(int)), this, theSlot);
1538 }
1539
1540 QList<ActionInfo> XGUI_Workshop::processHistoryList(const std::list<std::string>& theList) const
1541 {
1542   QList<ActionInfo> aResult;
1543   std::list<std::string>::const_iterator it = theList.cbegin();
1544   for (; it != theList.cend(); it++) {
1545     QString anId = QString::fromStdString(*it);
1546     bool isEditing = anId.endsWith(ModuleBase_Operation::EditSuffix());
1547     if (isEditing) {
1548       anId.chop(ModuleBase_Operation::EditSuffix().size());
1549     }
1550     ActionInfo anInfo;
1551     QAction* aContextMenuAct = myContextMenuMgr->actionByName(anId);
1552     if (aContextMenuAct) {
1553       anInfo.initFrom(aContextMenuAct);
1554     } else {
1555       anInfo = myActionsMgr->actionInfoById(anId);
1556     }
1557     if (isEditing) {
1558       anInfo.text = anInfo.text.prepend("Modify ");
1559     }
1560     aResult << anInfo;
1561   }
1562   return aResult;
1563 }