]> SALOME platform Git repositories - modules/shaper.git/blob - src/XGUI/XGUI_Workshop.cpp
Salome HOME
b2bb15a387c6e7fa2d59aaa8d420d26443d3db5e
[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_Tools.h"
5 #include "XGUI_Workshop.h"
6 #include "XGUI_SelectionMgr.h"
7 #include "XGUI_Selection.h"
8 #include "XGUI_ObjectsBrowser.h"
9 #include "XGUI_Displayer.h"
10 #include "XGUI_OperationMgr.h"
11 #include "XGUI_SalomeConnector.h"
12 #include "XGUI_ActionsMgr.h"
13 #include "XGUI_ErrorDialog.h"
14 #include "XGUI_ColorDialog.h"
15 #include "XGUI_ViewerProxy.h"
16 #include "XGUI_PropertyPanel.h"
17 #include "XGUI_ContextMenuMgr.h"
18 #include "XGUI_ModuleConnector.h"
19 #include "XGUI_WorkshopListener.h"
20
21 #include <XGUI_QtEvents.h>
22 #include <XGUI_HistoryMenu.h>
23 #include <XGUI_CustomPrs.h>
24
25 #include <AppElements_Workbench.h>
26 #include <AppElements_Viewer.h>
27 #include <AppElements_Command.h>
28 #include <AppElements_MainMenu.h>
29 #include <AppElements_MainWindow.h>
30 #include <AppElements_MenuGroupPanel.h>
31 #include <AppElements_Button.h>
32
33 #include <ModuleBase_IModule.h>
34 #include <ModuleBase_Preferences.h>
35
36 #include <ModelAPI_Events.h>
37 #include <ModelAPI_Session.h>
38 #include <ModelAPI_Feature.h>
39 #include <ModelAPI_Data.h>
40 #include <ModelAPI_AttributeDocRef.h>
41 #include <ModelAPI_Object.h>
42 #include <ModelAPI_Validator.h>
43 #include <ModelAPI_ResultGroup.h>
44 #include <ModelAPI_ResultConstruction.h>
45 #include <ModelAPI_ResultBody.h>
46 #include <ModelAPI_AttributeIntArray.h>
47 #include <ModelAPI_ResultParameter.h>
48
49 //#include <PartSetPlugin_Part.h>
50
51 #include <Events_Loop.h>
52 #include <Events_Error.h>
53 #include <Events_LongOp.h>
54
55 #include <ModuleBase_Operation.h>
56 #include <ModuleBase_OperationDescription.h>
57 #include <ModuleBase_SelectionValidator.h>
58 #include <ModuleBase_WidgetFactory.h>
59 #include <ModuleBase_Tools.h>
60 #include <ModuleBase_IViewer.h>
61 #include <ModuleBase_FilterFactory.h>
62 #include <ModuleBase_PageBase.h>
63 #include <ModuleBase_Tools.h>
64
65 #include <Config_Common.h>
66 #include <Config_FeatureMessage.h>
67 #include <Config_PointerMessage.h>
68 #include <Config_ModuleReader.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 #ifdef _DEBUG
89 #include <QDebug>
90 #include <iostream>
91 #endif
92
93 #ifdef WIN32
94 #include <windows.h>
95 #else
96 #include <dlfcn.h>
97 #endif
98
99 //#define DEBUG_DELETE
100
101 XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
102     : QObject(),
103       myCurrentDir(QString()),
104       myModule(NULL),
105       mySalomeConnector(theConnector),
106       myPropertyPanel(0),
107       myObjectBrowser(0),
108       myDisplayer(0)
109 {
110   myMainWindow = mySalomeConnector ? 0 : new AppElements_MainWindow();
111
112   if (myMainWindow) {
113     SUIT_ResourceMgr* aResMgr = ModuleBase_Preferences::resourceMgr();
114     bool aCloc = aResMgr->booleanValue("language", "locale", true);
115     if (aCloc)
116       QLocale::setDefault( QLocale::c() );
117     else 
118       QLocale::setDefault( QLocale::system() );
119   }
120
121   myDisplayer = new XGUI_Displayer(this);
122
123   mySelector = new XGUI_SelectionMgr(this);
124   //connect(mySelector, SIGNAL(selectionChanged()), this, SLOT(updateModuleCommands()));
125
126   myOperationMgr = new XGUI_OperationMgr(this, 0);
127   myActionsMgr = new XGUI_ActionsMgr(this);
128   myErrorDlg = new XGUI_ErrorDialog(QApplication::desktop());
129   myContextMenuMgr = new XGUI_ContextMenuMgr(this);
130   connect(myContextMenuMgr, SIGNAL(actionTriggered(const QString&, bool)), this,
131           SLOT(onContextMenuCommand(const QString&, bool)));
132
133   myViewerProxy = new XGUI_ViewerProxy(this);
134   connect(myViewerProxy, SIGNAL(selectionChanged()),
135           myActionsMgr,  SLOT(updateOnViewSelection()));
136
137   myModuleConnector = new XGUI_ModuleConnector(this);
138
139   ModuleBase_IWorkshop* aWorkshop = moduleConnector();
140   myOperationMgr->setWorkshop(aWorkshop);
141
142   myEventsListener = new XGUI_WorkshopListener(aWorkshop);
143
144   connect(myOperationMgr, SIGNAL(operationStarted(ModuleBase_Operation*)), 
145           SLOT(onOperationStarted(ModuleBase_Operation*)));
146   connect(myOperationMgr, SIGNAL(operationResumed(ModuleBase_Operation*)),
147           SLOT(onOperationResumed(ModuleBase_Operation*)));
148   connect(myOperationMgr, SIGNAL(operationStopped(ModuleBase_Operation*)),
149           SLOT(onOperationStopped(ModuleBase_Operation*)));
150   connect(myOperationMgr, SIGNAL(operationCommitted(ModuleBase_Operation*)), 
151           SLOT(onOperationCommitted(ModuleBase_Operation*)));
152   connect(myOperationMgr, SIGNAL(operationAborted(ModuleBase_Operation*)), 
153           SLOT(onOperationAborted(ModuleBase_Operation*)));
154   if (myMainWindow)
155     connect(myMainWindow, SIGNAL(exitKeySequence()), SLOT(onExit()));
156   connect(this, SIGNAL(errorOccurred(const QString&)), myErrorDlg, SLOT(addError(const QString&)));
157   connect(myEventsListener, SIGNAL(errorOccurred(const QString&)),
158           myErrorDlg, SLOT(addError(const QString&)));
159
160   //Config_PropManager::registerProp("Visualization", "object_default_color", "Object color",
161   //                                 Config_Prop::Color, "225,225,225");
162
163   Config_PropManager::registerProp("Visualization", "result_body_color", "Body color",
164                                    Config_Prop::Color, ModelAPI_ResultBody::DEFAULT_COLOR());
165   Config_PropManager::registerProp("Visualization", "result_group_color", "Group color",
166                                    Config_Prop::Color, ModelAPI_ResultGroup::DEFAULT_COLOR());
167   Config_PropManager::registerProp("Visualization", "result_construction_color", "Construction color",
168                                    Config_Prop::Color, ModelAPI_ResultConstruction::DEFAULT_COLOR());
169   Config_PropManager::registerProp("Visualization", "result_part_color", "Part color",
170                                    Config_Prop::Color, ModelAPI_ResultPart::DEFAULT_COLOR());
171 }
172
173 //******************************************************
174 XGUI_Workshop::~XGUI_Workshop(void)
175 {
176   delete myDisplayer;
177 }
178
179 //******************************************************
180 void XGUI_Workshop::startApplication()
181 {
182   initMenu();
183
184   Config_PropManager::registerProp("Plugins", "default_path", "Default Path",
185                                    Config_Prop::Directory, "");
186
187   //Initialize event listening
188   myEventsListener->initializeEventListening();
189
190   registerValidators();
191
192   // Calling of  loadCustomProps before activating module is required
193   // by Config_PropManger to restore user-defined path to plugins
194   ModuleBase_Preferences::loadCustomProps();
195   createModule();
196   if (myMainWindow) {
197     myMainWindow->show();
198     updateCommandStatus();
199   }
200   
201   onNew();
202
203   emit applicationStarted();
204 }
205
206 void XGUI_Workshop::activateModule()
207 {
208   myModule->activateSelectionFilters();
209
210   connect(myDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)),
211     myModule, SLOT(onObjectDisplayed(ObjectPtr, AISObjectPtr)));
212   connect(myDisplayer, SIGNAL(beforeObjectErase(ObjectPtr, AISObjectPtr)),
213     myModule, SLOT(onBeforeObjectErase(ObjectPtr, AISObjectPtr)));
214
215   myActionsMgr->update();
216
217 }
218
219 void XGUI_Workshop::deactivateModule()
220 {
221   myModule->deactivateSelectionFilters();
222
223   disconnect(myDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)),
224     myModule, SLOT(onObjectDisplayed(ObjectPtr, AISObjectPtr)));
225   disconnect(myDisplayer, SIGNAL(beforeObjectErase(ObjectPtr, AISObjectPtr)),
226     myModule, SLOT(onBeforeObjectErase(ObjectPtr, AISObjectPtr)));
227 }
228
229 //******************************************************
230 void XGUI_Workshop::initMenu()
231 {
232   myContextMenuMgr->createActions();
233
234   if (isSalomeMode()) {
235     // Create only Undo, Redo commands
236     QAction* aAction = salomeConnector()->addDesktopCommand("UNDO_CMD", tr("Undo"),
237                                                          tr("Undo last command"),
238                                                          QIcon(":pictures/undo.png"),
239                                                          QKeySequence::Undo, false, "MEN_DESK_EDIT");
240     connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onUndo()));
241     addHistoryMenu(aAction, SIGNAL(updateUndoHistory(const QList<ActionInfo>&)), SLOT(onUndo(int)));
242
243     aAction = salomeConnector()->addDesktopCommand("REDO_CMD", tr("Redo"), tr("Redo last command"),
244                                                 QIcon(":pictures/redo.png"), QKeySequence::Redo,
245                                                 false, "MEN_DESK_EDIT");
246     connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onRedo()));
247     addHistoryMenu(aAction, SIGNAL(updateRedoHistory(const QList<ActionInfo>&)), SLOT(onRedo(int)));
248
249     salomeConnector()->addDesktopMenuSeparator("MEN_DESK_EDIT");
250     aAction = salomeConnector()->addDesktopCommand("REBUILD_CMD", tr("Rebuild"), tr("Rebuild data objects"),
251                                                 QIcon(":pictures/rebuild.png"), QKeySequence(),
252                                                 false, "MEN_DESK_EDIT");
253     connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onRebuild()));
254     salomeConnector()->addDesktopMenuSeparator("MEN_DESK_EDIT");
255
256     aAction = salomeConnector()->addDesktopCommand("SAVEAS_CMD", tr("Export NewGeom..."), tr("Export the current document into a NewGeom file"),
257                                                 QIcon(), QKeySequence(),
258                                                 false, "MEN_DESK_FILE");
259     connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onSaveAs()));
260
261     aAction = salomeConnector()->addDesktopCommand("OPEN_CMD", tr("Import NewGeom..."), tr("Import a NewGeom file"),
262                                                 QIcon(), QKeySequence(),
263                                                 false, "MEN_DESK_FILE");
264     connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onOpen()));
265     salomeConnector()->addDesktopMenuSeparator("MEN_DESK_FILE");
266
267     return;
268   }
269   // File commands group
270   AppElements_MenuGroupPanel* aGroup = myMainWindow->menuObject()->generalPage();
271
272   AppElements_Command* aCommand;
273
274   aCommand = aGroup->addFeature("SAVE_CMD", tr("Save"), tr("Save the document"),
275                                 QIcon(":pictures/save.png"), QKeySequence::Save);
276   aCommand->connectTo(this, SLOT(onSave()));
277   //aCommand->disable();
278
279   QString aUndoId = "UNDO_CMD";
280   aCommand = aGroup->addFeature(aUndoId, tr("Undo"), tr("Undo last command"),
281                                 QIcon(":pictures/undo.png"), QKeySequence::Undo);
282   aCommand->connectTo(this, SLOT(onUndo()));
283   AppElements_Button* aUndoButton = qobject_cast<AppElements_Button*>(aGroup->widget(aUndoId));
284   addHistoryMenu(aUndoButton,
285                  SIGNAL(updateUndoHistory(const QList<ActionInfo>&)),
286                  SLOT(onUndo(int)));
287
288   QString aRedoId = "REDO_CMD";
289   aCommand = aGroup->addFeature(aRedoId, tr("Redo"), tr("Redo last command"),
290                                 QIcon(":pictures/redo.png"), QKeySequence::Redo);
291   aCommand->connectTo(this, SLOT(onRedo()));
292   AppElements_Button* aRedoButton = qobject_cast<AppElements_Button*>(aGroup->widget(aRedoId));
293   addHistoryMenu(aRedoButton,
294                  SIGNAL(updateRedoHistory(const QList<ActionInfo>&)),
295                  SLOT(onRedo(int)));
296
297   aCommand = aGroup->addFeature("REBUILD_CMD", tr("Rebuild"), tr("Rebuild data objects"),
298     QIcon(":pictures/rebuild.png"), QKeySequence());
299   aCommand->connectTo(this, SLOT(onRebuild()));
300
301   aCommand = aGroup->addFeature("SAVEAS_CMD", tr("Save as..."), tr("Save the document into a file"),
302                                 QIcon(":pictures/save.png"), QKeySequence());
303   aCommand->connectTo(this, SLOT(onSaveAs()));
304   //aCommand->disable();
305
306   aCommand = aGroup->addFeature("OPEN_CMD", tr("Open..."), tr("Open a new document"),
307                                 QIcon(":pictures/open.png"), QKeySequence::Open);
308   aCommand->connectTo(this, SLOT(onOpen()));
309
310   //aCommand = aGroup->addFeature("NEW_CMD", tr("New"), tr("Create a new document"),
311   //                              QIcon(":pictures/new.png"), QKeySequence::New);
312   //aCommand->connectTo(this, SLOT(onNew()));
313
314   aCommand = aGroup->addFeature("PREF_CMD", tr("Preferences"), tr("Edit preferences"),
315                                 QIcon(":pictures/preferences.png"), QKeySequence::Preferences);
316   aCommand->connectTo(this, SLOT(onPreferences()));
317
318   aCommand = aGroup->addFeature("EXIT_CMD", tr("Exit"), tr("Exit application"),
319                                 QIcon(":pictures/close.png"), QKeySequence::Close);
320   aCommand->connectTo(this, SLOT(onExit()));
321   //FIXME: SBH's test action. Can be used for some GUI tests.
322 //  #ifdef _DEBUG
323 //    aCommand = aGroup->addFeature("TEST_CMD", "Test!", "Private debug button",
324 //                                  QIcon(":pictures/close.png"), QKeySequence(), true);
325 //    aCommand->connectTo(myMainWindow, SLOT(dockPythonConsole()));
326 //  #endif
327 }
328
329 //******************************************************
330 AppElements_Workbench* XGUI_Workshop::addWorkbench(const QString& theName)
331 {
332   AppElements_MainMenu* aMenuBar = myMainWindow->menuObject();
333   return aMenuBar->addWorkbench(theName);
334 }
335
336 //******************************************************
337 QMainWindow* XGUI_Workshop::desktop() const
338 {
339   return isSalomeMode() ? salomeConnector()->desktop() : myMainWindow;
340 }
341
342 //******************************************************
343 void XGUI_Workshop::onStartWaiting()
344 {
345   if (Events_LongOp::isPerformed()) {
346     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
347   }
348 }
349
350
351 //******************************************************
352 void XGUI_Workshop::deactivateActiveObject(const ObjectPtr& theObject, const bool theUpdateViewer)
353 {
354   if (!myModule->canActivateSelection(theObject)) {
355     if (myDisplayer->isActive(theObject))
356       myDisplayer->deactivate(theObject, theUpdateViewer);
357   }
358 }
359
360 //******************************************************
361 void XGUI_Workshop::onOperationStarted(ModuleBase_Operation* theOperation)
362 {
363   setNestedFeatures(theOperation);
364
365   if (theOperation->getDescription()->hasXmlRepresentation()) {  //!< No need for property panel
366     connectWithOperation(theOperation);
367     setPropertyPanel(theOperation);
368   }
369   updateCommandStatus();
370
371   myModule->onOperationStarted(theOperation);
372
373   // the objects of the current operation should be deactivated
374   QObjectPtrList anObjects;
375   FeaturePtr aFeature = theOperation->feature();
376   anObjects.append(aFeature);
377   std::list<ResultPtr> aResults = aFeature->results();
378   std::list<ResultPtr>::const_iterator aIt;
379   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
380     anObjects.append(*aIt);
381   }
382   QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
383   for (; anIt != aLast; anIt++)
384     deactivateActiveObject(*anIt, false);
385   if (anObjects.size() > 0)
386     myDisplayer->updateViewer();
387
388   // filling the operation values by the selection in the viewer
389   // it should be perfomed at the end of the method because it can commit the operation
390   // if after the controls fill, the operation becomes valid
391   if (!theOperation->isEditOperation())
392     theOperation->activateByPreselection();
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
859   QAction* aAcceptAllAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::AcceptAll);
860   aAcceptAllAct->setEnabled(aParentValid && aCanUndo);
861 }
862
863 void XGUI_Workshop::updateHistory()
864 {
865   std::list<std::string> aUndoList = ModelAPI_Session::get()->undoList();
866   QList<ActionInfo> aUndoRes = processHistoryList(aUndoList);
867   emit updateUndoHistory(aUndoRes);
868
869   std::list<std::string> aRedoList = ModelAPI_Session::get()->redoList();
870   QList<ActionInfo> aRedoRes = processHistoryList(aRedoList);
871   emit updateRedoHistory(aRedoRes);
872 }
873
874 //******************************************************
875 QDockWidget* XGUI_Workshop::createObjectBrowser(QWidget* theParent)
876 {
877   QDockWidget* aObjDock = new QDockWidget(theParent);
878   aObjDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea);
879   aObjDock->setWindowTitle(tr("Object browser"));
880   aObjDock->setStyleSheet(
881       "::title { position: relative; padding-left: 5px; text-align: left center }");
882   myObjectBrowser = new XGUI_ObjectsBrowser(aObjDock);
883   myObjectBrowser->setDataModel(myModule->dataModel());
884   myModule->customizeObjectBrowser(myObjectBrowser);
885   aObjDock->setWidget(myObjectBrowser);
886
887   myContextMenuMgr->connectObjectBrowser();
888   return aObjDock;
889 }
890
891 //******************************************************
892 /*
893  * Creates dock widgets, places them in corresponding area
894  * and tabifies if necessary.
895  */
896 void XGUI_Workshop::createDockWidgets()
897 {
898   QMainWindow* aDesktop = isSalomeMode() ? salomeConnector()->desktop() : myMainWindow;
899   QDockWidget* aObjDock = createObjectBrowser(aDesktop);
900   aDesktop->addDockWidget(Qt::LeftDockWidgetArea, aObjDock);
901   myPropertyPanel = new XGUI_PropertyPanel(aDesktop);
902   myPropertyPanel->setupActions(myActionsMgr);
903   myPropertyPanel->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea);
904   aDesktop->addDockWidget(Qt::LeftDockWidgetArea, myPropertyPanel);
905   hidePropertyPanel();  ///<! Invisible by default
906   hideObjectBrowser();
907   aDesktop->tabifyDockWidget(aObjDock, myPropertyPanel);
908   myPropertyPanel->installEventFilter(myOperationMgr);
909
910   QAction* aOkAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Accept);
911   connect(aOkAct, SIGNAL(triggered()), myOperationMgr, SLOT(onCommitOperation()));
912   QAction* aCancelAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Abort);
913   connect(aCancelAct, SIGNAL(triggered()), myOperationMgr, SLOT(onAbortOperation()));
914   connect(myPropertyPanel, SIGNAL(noMoreWidgets()), myModule, SLOT(onNoMoreWidgets()));
915   connect(myPropertyPanel, SIGNAL(keyReleased(QKeyEvent*)),
916           myOperationMgr,  SLOT(onKeyReleased(QKeyEvent*)));
917   connect(myOperationMgr,  SIGNAL(validationStateChanged(bool)),
918           aOkAct,          SLOT(setEnabled(bool)));
919   QAction* aAcceptAllAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::AcceptAll);
920   connect(myOperationMgr,  SIGNAL(nestedStateChanged(bool)),
921           aAcceptAllAct,   SLOT(setEnabled(bool)));
922
923 }
924
925 //******************************************************
926 void XGUI_Workshop::showPropertyPanel()
927 {
928   QAction* aViewAct = myPropertyPanel->toggleViewAction();
929   ///<! Restore ability to close panel from the window's menu
930   aViewAct->setEnabled(true);
931   myPropertyPanel->show();
932   myPropertyPanel->raise();
933 }
934
935 //******************************************************
936 void XGUI_Workshop::hidePropertyPanel()
937 {
938   QAction* aViewAct = myPropertyPanel->toggleViewAction();
939   ///<! Do not allow to show empty property panel
940   aViewAct->setEnabled(false);
941   myPropertyPanel->hide();
942 }
943
944 //******************************************************
945 void XGUI_Workshop::showObjectBrowser()
946 {
947   myObjectBrowser->parentWidget()->show();
948 }
949
950 //******************************************************
951 void XGUI_Workshop::hideObjectBrowser()
952 {
953   myObjectBrowser->parentWidget()->hide();
954 }
955
956 //******************************************************
957 //void XGUI_Workshop::onFeatureTriggered()
958 //{
959 //  QAction* aCmd = dynamic_cast<QAction*>(sender());
960 //  if (aCmd) {
961 //    QString aId = salomeConnector()->commandId(aCmd);
962 //    if (!aId.isNull())
963 //      myModule->launchOperation(aId);
964 //  }
965 //}
966
967 //******************************************************
968 void XGUI_Workshop::salomeViewerSelectionChanged()
969 {
970   emit salomeViewerSelection();
971 }
972
973 //**************************************************************
974 ModuleBase_IViewer* XGUI_Workshop::salomeViewer() const
975 {
976   return mySalomeConnector->viewer();
977 }
978
979 //**************************************************************
980 void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked)
981 {
982   QObjectPtrList aObjects = mySelector->selection()->selectedObjects();
983   if (theId == "DELETE_CMD")
984     deleteObjects();
985   if (theId == "MOVE_CMD")
986     moveObjects();
987   else if (theId == "COLOR_CMD")
988     changeColor(aObjects);
989   else if (theId == "SHOW_CMD")
990     showObjects(aObjects, true);
991   else if (theId == "HIDE_CMD")
992     showObjects(aObjects, false);
993   else if (theId == "SHOW_ONLY_CMD")
994     showOnlyObjects(aObjects);
995   else if (theId == "SHADING_CMD")
996     setDisplayMode(aObjects, XGUI_Displayer::Shading);
997   else if (theId == "WIREFRAME_CMD")
998     setDisplayMode(aObjects, XGUI_Displayer::Wireframe);
999   else if (theId == "HIDEALL_CMD") {
1000     QObjectPtrList aList = myDisplayer->displayedObjects();
1001     foreach (ObjectPtr aObj, aList)
1002       aObj->setDisplayed(false);
1003     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1004   }
1005 }
1006
1007 //**************************************************************
1008 void XGUI_Workshop::deleteObjects()
1009 {
1010   ModuleBase_IModule* aModule = module();
1011   // 1. allow the module to delete objects, do nothing if it has succeed
1012   if (aModule->deleteObjects()) {
1013     updateCommandStatus();
1014     return;
1015   }
1016
1017   if (!isActiveOperationAborted())
1018     return;
1019   QObjectPtrList anObjects = mySelector->selection()->selectedObjects();
1020   // check whether the object can be deleted. There should not be parts which are not loaded
1021   if (!XGUI_Tools::canRemoveOrRename(myMainWindow, anObjects))
1022     return;
1023
1024   bool hasResult = false;
1025   bool hasFeature = false;
1026   bool hasParameter = false;
1027   bool hasSubFeature = false;
1028   ModuleBase_Tools::checkObjects(anObjects, hasResult, hasFeature, hasParameter, hasSubFeature);
1029   if (!(hasFeature || hasParameter))
1030     return;
1031
1032   // 1. start operation
1033   QString aDescription = contextMenuMgr()->action("DELETE_CMD")->text();
1034   aDescription += tr(" %1");
1035   QStringList aObjectNames;
1036   foreach (ObjectPtr aObj, anObjects) {
1037     if (!aObj->data()->isValid())
1038       continue;
1039     aObjectNames << QString::fromStdString(aObj->data()->name());
1040   }
1041   aDescription = aDescription.arg(aObjectNames.join(", "));
1042
1043   SessionPtr aMgr = ModelAPI_Session::get();
1044   aMgr->startOperation(aDescription.toStdString());
1045   // 2. close the documents of the removed parts if the result part is in a list of selected objects
1046   // this is performed in the RemoveFeature of Part object.
1047   /*foreach (ObjectPtr aObj, anObjects)
1048   {
1049     ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
1050     if (aPart) {
1051       DocumentPtr aDoc = aObj->document();
1052       if (aDoc == aMgr->activeDocument()) {
1053         aDoc->close();
1054       }
1055     }
1056   }*/
1057   // 3. delete objects
1058   QMainWindow* aDesktop = isSalomeMode() ? salomeConnector()->desktop() : myMainWindow;
1059   std::set<FeaturePtr> anIgnoredFeatures;
1060   if (deleteFeatures(anObjects, anIgnoredFeatures, aDesktop, true)) {
1061     myDisplayer->updateViewer();
1062     aMgr->finishOperation();
1063     updateCommandStatus();
1064   }
1065   else {
1066     aMgr->abortOperation();
1067   }
1068 }
1069
1070 //**************************************************************
1071 void XGUI_Workshop::moveObjects()
1072 {
1073   if (!isActiveOperationAborted())
1074     return;
1075
1076   SessionPtr aMgr = ModelAPI_Session::get();
1077
1078   QString aDescription = contextMenuMgr()->action("MOVE_CMD")->text();
1079   aMgr->startOperation(aDescription.toStdString());
1080
1081   QObjectPtrList anObjects = mySelector->selection()->selectedObjects();
1082   DocumentPtr anActiveDocument = aMgr->activeDocument();
1083
1084   FeaturePtr aCurrentFeature = anActiveDocument->currentFeature(true);
1085   foreach (ObjectPtr aObj, anObjects) {
1086     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
1087     if (aFeature.get()) {
1088       anActiveDocument->moveFeature(aFeature, aCurrentFeature);
1089       aCurrentFeature = anActiveDocument->currentFeature(true);
1090     }
1091   }
1092   aMgr->finishOperation();
1093 }
1094
1095 //**************************************************************
1096 bool XGUI_Workshop::deleteFeatures(const QObjectPtrList& theList,
1097                                    const std::set<FeaturePtr>& theIgnoredFeatures,
1098                                    QWidget* theParent,
1099                                    const bool theAskAboutDeleteReferences)
1100 {
1101 #ifdef DEBUG_DELETE
1102   QStringList aDInfo;
1103   QObjectPtrList::const_iterator aDIt = theList.begin(), aDLast = theList.end();
1104   for (; aDIt != aDLast; ++aDIt) {
1105     aDInfo.append(ModuleBase_Tools::objectInfo((*aDIt)));
1106   }
1107   QString anInfoStr = aDInfo.join(", ");
1108   qDebug(QString("deleteFeatures: %1, %2").arg(theList.size()).arg(anInfoStr).toStdString().c_str());
1109 #endif
1110
1111   // 1. find all referenced features
1112   std::set<FeaturePtr> aRefFeatures;
1113   foreach (ObjectPtr aDeletedObj, theList) {
1114     XGUI_Tools::refsToFeatureInAllDocuments(aDeletedObj, aDeletedObj, aRefFeatures);
1115   }
1116   // 2. warn about the references remove, break the delete operation if the user chose it
1117   if (theAskAboutDeleteReferences && !aRefFeatures.empty()) {
1118     QStringList aRefNames;
1119     std::set<FeaturePtr>::const_iterator anIt = aRefFeatures.begin(),
1120                                          aLast = aRefFeatures.end();
1121     for (; anIt != aLast; anIt++) {
1122       aRefNames.append((*anIt)->name().c_str());
1123     }
1124     QString aNames = aRefNames.join(", ");
1125
1126     QMessageBox::StandardButton aRes = QMessageBox::warning(
1127         theParent, tr("Delete features"),
1128         QString(tr("Selected features are used in the following features: %1.\
1129 These features will be deleted also. Would you like to continue?")).arg(aNames),
1130         QMessageBox::No | QMessageBox::Yes, QMessageBox::No);
1131     if (aRes != QMessageBox::Yes)
1132       return false;
1133   }
1134
1135   // 3. remove referenced features
1136   std::set<FeaturePtr>::const_iterator anIt = aRefFeatures.begin(),
1137                                        aLast = aRefFeatures.end();
1138 #ifdef DEBUG_DELETE
1139   QStringList anInfo;
1140 #endif
1141   for (; anIt != aLast; anIt++) {
1142     FeaturePtr aFeature = (*anIt);
1143     DocumentPtr aDoc = aFeature->document();
1144     if (theIgnoredFeatures.find(aFeature) == theIgnoredFeatures.end()) {
1145       aDoc->removeFeature(aFeature);
1146 #ifdef DEBUG_DELETE
1147       anInfo.append(ModuleBase_Tools::objectInfo(aFeature).toStdString().c_str());
1148 #endif
1149     }
1150   }
1151 #ifdef DEBUG_DELETE
1152   qDebug(QString("remove references:%1").arg(anInfo.join("; ")).toStdString().c_str());
1153   anInfo.clear();
1154 #endif
1155
1156   QString anId = QString::fromStdString("DELETE_CMD");
1157   QStringList anObjectGroups = contextMenuMgr()->actionObjectGroups(anId);
1158   // 4. remove the parameter features
1159   foreach (ObjectPtr aObj, theList) {
1160     // features and parameters can be removed here,
1161     // the results are removed only by a corresponded feature remove
1162     std::string aGroupName = aObj->groupName();
1163     if (!anObjectGroups.contains(aGroupName.c_str()))
1164       continue;
1165
1166     FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
1167     if (aFeature) {
1168       // TODO: to learn the workshop to delegate the Part object deletion to the PartSet module
1169       // part features are removed in the PartSet module. This condition should be moved there
1170       if (aFeature->getKind() == "Part")
1171         continue;
1172
1173       DocumentPtr aDoc = aObj->document();
1174       if (theIgnoredFeatures.find(aFeature) == theIgnoredFeatures.end()) {
1175 #ifdef DEBUG_DELETE
1176         QString anInfoStr = ModuleBase_Tools::objectInfo(aFeature);
1177         anInfo.append(anInfoStr);
1178         qDebug(QString("remove feature :%1").arg(anInfoStr).toStdString().c_str());
1179 #endif
1180         aDoc->removeFeature(aFeature);
1181       }
1182     }
1183   }
1184 #ifdef DEBUG_DELETE
1185   qDebug(QString("remove features:%1").arg(anInfo.join("; ")).toStdString().c_str());
1186 #endif
1187   return true;
1188 }
1189
1190 bool hasResults(QObjectPtrList theObjects, const std::set<std::string>& theTypes)
1191 {
1192   bool isFoundResultType = false;
1193   foreach(ObjectPtr anObj, theObjects)
1194   {
1195     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObj);
1196     if (aResult.get() == NULL)
1197       continue;
1198
1199     isFoundResultType = theTypes.find(aResult->groupName()) != theTypes.end();
1200     if (isFoundResultType)
1201       break;
1202   }
1203   return isFoundResultType;
1204 }
1205
1206 //**************************************************************
1207 // Returns the list of features placed between theObject and the current feature
1208 // in the same document. Excludes theObject, includes the current feature.
1209 std::list<FeaturePtr> toCurrentFeatures(const ObjectPtr& theObject)
1210 {
1211   std::list<FeaturePtr> aResult;
1212   DocumentPtr aDocument = theObject->document();
1213   std::list<FeaturePtr> anAllFeatures = aDocument->allFeatures();
1214   // find the object iterator
1215   std::list<FeaturePtr>::iterator aObjectIt = std::find(anAllFeatures.begin(), anAllFeatures.end(), theObject);
1216   if (aObjectIt == anAllFeatures.end()) 
1217     return aResult;
1218   // find the current feature iterator
1219   std::list<FeaturePtr>::iterator aCurrentIt = std::find(anAllFeatures.begin(), anAllFeatures.end(), aDocument->currentFeature(true));
1220   if (aCurrentIt == anAllFeatures.end()) 
1221     return aResult;
1222   // check the right order
1223   if (std::distance(aObjectIt, anAllFeatures.end()) <= std::distance(aCurrentIt, anAllFeatures.end()))
1224     return aResult;
1225   // exclude the object
1226   std::advance(aObjectIt, 1);
1227   // include the current feature
1228   std::advance(aCurrentIt, 1);
1229   return std::list<FeaturePtr>(aObjectIt, aCurrentIt);
1230 }
1231
1232 bool XGUI_Workshop::canMoveFeature()
1233 {
1234   QObjectPtrList aObjects = mySelector->selection()->selectedObjects();
1235   foreach (ObjectPtr aObject, aObjects) {
1236     // 1. Get features placed between selected and current in the document 
1237     std::list<FeaturePtr> aFeaturesBetween = toCurrentFeatures(aObject);
1238     // if aFeaturesBetween is empty it means wrong order or aObject is the current feature
1239     if (aFeaturesBetween.empty())
1240       return false;
1241     std::set<FeaturePtr> aPlacedFeatures(aFeaturesBetween.begin(), aFeaturesBetween.end());
1242     // 2. Get all reference features to the selected object in the document 
1243     std::set<FeaturePtr> aRefFeatures;
1244     XGUI_Tools::refsToFeatureInFeatureDocument(aObject, aRefFeatures);
1245
1246     if (aRefFeatures.empty())
1247       continue;
1248     // 3. Find any placed features in all reference features
1249     std::set<FeaturePtr> aIntersectionFeatures;
1250     std::set_intersection(aRefFeatures.begin(), aRefFeatures.end(),
1251                           aPlacedFeatures.begin(), aPlacedFeatures.end(),
1252                           std::inserter(aIntersectionFeatures, aIntersectionFeatures.begin()));
1253     // 4. Return false if any reference feature is placed before curent feature
1254     if (!aIntersectionFeatures.empty())
1255       return false;
1256   }
1257   return true;
1258 }
1259
1260 //**************************************************************
1261 bool XGUI_Workshop::canChangeColor() const
1262 {
1263   QObjectPtrList aObjects = mySelector->selection()->selectedObjects();
1264
1265   std::set<std::string> aTypes;
1266   aTypes.insert(ModelAPI_ResultGroup::group());
1267   aTypes.insert(ModelAPI_ResultConstruction::group());
1268   aTypes.insert(ModelAPI_ResultBody::group());
1269   aTypes.insert(ModelAPI_ResultPart::group());
1270
1271   return hasResults(aObjects, aTypes);
1272 }
1273
1274 void setColor(ResultPtr theResult, std::vector<int>& theColor)
1275 {
1276   if (!theResult.get())
1277     return;
1278
1279   AttributeIntArrayPtr aColorAttr = theResult->data()->intArray(ModelAPI_Result::COLOR_ID());
1280   if (aColorAttr.get() != NULL) {
1281     if (!aColorAttr->size()) {
1282       aColorAttr->setSize(3);
1283     }
1284     aColorAttr->setValue(0, theColor[0]);
1285     aColorAttr->setValue(1, theColor[1]);
1286     aColorAttr->setValue(2, theColor[2]);
1287   }
1288 }
1289
1290 //**************************************************************
1291 void XGUI_Workshop::changeColor(const QObjectPtrList& theObjects)
1292 {
1293   AttributeIntArrayPtr aColorAttr;
1294   // 1. find the current color of the object. This is a color of AIS presentation
1295   // The objects are iterated until a first valid color is found 
1296   std::vector<int> aColor;
1297   foreach(ObjectPtr anObject, theObjects) {
1298     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1299     if (aResult.get())
1300       XGUI_CustomPrs::getResultColor(aResult, aColor);
1301     else {
1302       // TODO: remove the obtaining a color from the AIS object
1303       // this does not happen never because:
1304       // 1. The color can be changed only on results
1305       // 2. The result can be not visualized in the viewer(e.g. Origin Construction)
1306       AISObjectPtr anAISObj = myDisplayer->getAISObject(anObject);
1307       if (anAISObj.get()) {
1308         aColor.resize(3);
1309         anAISObj->getColor(aColor[0], aColor[1], aColor[2]);
1310       }
1311     }
1312     if (!aColor.empty())
1313       break;
1314   }
1315   if (aColor.size() != 3)
1316     return;
1317
1318   // 2. show the dialog to change the value
1319   XGUI_ColorDialog* aDlg = new XGUI_ColorDialog(mainWindow());
1320   aDlg->setColor(aColor);
1321   aDlg->move(QCursor::pos());
1322   bool isDone = aDlg->exec() == QDialog::Accepted;
1323   if (!isDone)
1324     return;
1325
1326   bool isRandomColor = aDlg->isRandomColor();
1327
1328   // 3. abort the previous operation and start a new one
1329   SessionPtr aMgr = ModelAPI_Session::get();
1330   bool aWasOperation = aMgr->isOperation(); // keep this value
1331   if (!aWasOperation) {
1332     QString aDescription = contextMenuMgr()->action("COLOR_CMD")->text();
1333     aMgr->startOperation(aDescription.toStdString());
1334   }
1335
1336   // 4. set the value to all results
1337   foreach(ObjectPtr anObj, theObjects) {
1338     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObj);
1339     if (aResult.get() != NULL) {
1340       std::vector<int> aColorResult = aDlg->getColor();
1341       setColor(aResult, aColorResult);
1342     }
1343   }
1344   if (!aWasOperation)
1345     aMgr->finishOperation();
1346   updateCommandStatus();
1347 }
1348
1349 //**************************************************************
1350 #define SET_DISPLAY_GROUP(aGroupName, aDisplay) \
1351 for (int i = 0; i < aDoc->size(aGroupName); i++) { \
1352   aDoc->object(aGroupName, i)->setDisplayed(aDisplay); \
1353 }
1354 void XGUI_Workshop::showObjects(const QObjectPtrList& theList, bool isVisible)
1355 {
1356   foreach (ObjectPtr aObj, theList) {
1357     /*
1358     ResultPartPtr aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
1359     if (aPartRes) {
1360       DocumentPtr aDoc = aPartRes->partDoc();
1361       SET_DISPLAY_GROUP(ModelAPI_ResultBody::group(), isVisible)
1362       SET_DISPLAY_GROUP(ModelAPI_ResultConstruction::group(), isVisible)
1363       SET_DISPLAY_GROUP(ModelAPI_ResultGroup::group(), isVisible)
1364     } else {
1365     */
1366       aObj->setDisplayed(isVisible);
1367     //}
1368   }
1369   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1370 }
1371
1372 //**************************************************************
1373 void XGUI_Workshop::showOnlyObjects(const QObjectPtrList& theList)
1374 {
1375   // Hide all displayed objects
1376   QObjectPtrList aList = myDisplayer->displayedObjects();
1377   foreach (ObjectPtr aObj, aList)
1378     aObj->setDisplayed(false);
1379
1380   // Show only objects from the list
1381   foreach (ObjectPtr aObj, theList) {
1382     /*
1383     ResultPartPtr aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
1384     if (aPartRes) {
1385       DocumentPtr aDoc = aPartRes->partDoc();
1386       SET_DISPLAY_GROUP(ModelAPI_ResultBody::group(), true)
1387       SET_DISPLAY_GROUP(ModelAPI_ResultConstruction::group(), true)
1388       SET_DISPLAY_GROUP(ModelAPI_ResultGroup::group(), true)
1389     } else {
1390     */
1391       aObj->setDisplayed(true);
1392     //}
1393   }
1394   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1395
1396 }
1397
1398
1399 //**************************************************************
1400 void XGUI_Workshop::registerValidators() const
1401 {
1402   SessionPtr aMgr = ModelAPI_Session::get();
1403   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
1404 }
1405
1406 //**************************************************************
1407 /*void XGUI_Workshop::displayAllResults()
1408 {
1409   SessionPtr aMgr = ModelAPI_Session::get();
1410   DocumentPtr aRootDoc = aMgr->moduleDocument();
1411   displayDocumentResults(aRootDoc);
1412   for (int i = 0; i < aRootDoc->size(ModelAPI_ResultPart::group()); i++) {
1413     ObjectPtr aObject = aRootDoc->object(ModelAPI_ResultPart::group(), i);
1414     ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObject);
1415     displayDocumentResults(aPart->partDoc());
1416   }
1417   myDisplayer->updateViewer();
1418 }*/
1419
1420 //**************************************************************
1421 void XGUI_Workshop::displayDocumentResults(DocumentPtr theDoc)
1422 {
1423   if (!theDoc)
1424     return;
1425   displayGroupResults(theDoc, ModelAPI_ResultConstruction::group());
1426   displayGroupResults(theDoc, ModelAPI_ResultBody::group());
1427 }
1428
1429 //**************************************************************
1430 void XGUI_Workshop::displayGroupResults(DocumentPtr theDoc, std::string theGroup)
1431 {
1432   for (int i = 0; i < theDoc->size(theGroup); i++) 
1433     theDoc->object(theGroup, i)->setDisplayed(true);
1434     //displayObject(theDoc->object(theGroup, i));
1435   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1436 }
1437
1438 //**************************************************************
1439 void XGUI_Workshop::setDisplayMode(const QObjectPtrList& theList, int theMode)
1440 {
1441   foreach(ObjectPtr aObj, theList) {
1442     myDisplayer->setDisplayMode(aObj, (XGUI_Displayer::DisplayMode)theMode, false);
1443   }
1444   if (theList.size() > 0)
1445     myDisplayer->updateViewer();
1446 }
1447
1448 //**************************************************************
1449 void XGUI_Workshop::closeDocument()
1450 {
1451   ModuleBase_Operation* anOperation = operationMgr()->currentOperation();
1452   while (anOperation) {
1453     anOperation->abort();
1454     anOperation = operationMgr()->currentOperation();
1455   }
1456   myDisplayer->closeLocalContexts();
1457   myDisplayer->eraseAll();
1458   objectBrowser()->clearContent();
1459
1460   SessionPtr aMgr = ModelAPI_Session::get();
1461   aMgr->closeAll();
1462 }
1463
1464 void XGUI_Workshop::addHistoryMenu(QObject* theObject, const char* theSignal, const char* theSlot)
1465 {
1466   XGUI_HistoryMenu* aMenu = NULL;
1467   if (isSalomeMode()) {
1468     QAction* anAction = qobject_cast<QAction*>(theObject);
1469     if (!anAction)
1470       return;
1471     aMenu = new XGUI_HistoryMenu(anAction);
1472   } else {
1473     QToolButton* aButton =  qobject_cast<QToolButton*>(theObject);
1474     aMenu = new XGUI_HistoryMenu(aButton);
1475   }
1476   connect(this, theSignal, aMenu, SLOT(setHistory(const QList<ActionInfo>&)));
1477   connect(aMenu, SIGNAL(actionSelected(int)), this, theSlot);
1478 }
1479
1480 QList<ActionInfo> XGUI_Workshop::processHistoryList(const std::list<std::string>& theList) const
1481 {
1482   QList<ActionInfo> aResult;
1483   std::list<std::string>::const_iterator it = theList.cbegin();
1484   for (; it != theList.cend(); it++) {
1485     QString anId = QString::fromStdString(*it);
1486     bool isEditing = anId.endsWith(ModuleBase_Operation::EditSuffix());
1487     if (isEditing) {
1488       anId.chop(ModuleBase_Operation::EditSuffix().size());
1489     }
1490     ActionInfo anInfo;
1491     QAction* aContextMenuAct = myContextMenuMgr->actionByName(anId);
1492     if (aContextMenuAct) {
1493       anInfo.initFrom(aContextMenuAct);
1494     } else {
1495       anInfo = myActionsMgr->actionInfoById(anId);
1496     }
1497     if (isEditing) {
1498       anInfo.text = anInfo.text.prepend("Modify ");
1499     }
1500     aResult << anInfo;
1501   }
1502   return aResult;
1503 }