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