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