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