Salome HOME
Merge branch 'python_parametric_api' of https://git.salome-platform.org/git/modules...
[modules/shaper.git] / src / XGUI / XGUI_WorkshopListener.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 #include "XGUI_WorkshopListener.h"
4 #include "XGUI_Workshop.h"
5 #include "XGUI_Displayer.h"
6 #include "XGUI_ErrorMgr.h"
7 #include "XGUI_OperationMgr.h"
8 #include "XGUI_SalomeConnector.h"
9 #include "XGUI_ActionsMgr.h"
10 #include "XGUI_PropertyPanel.h"
11 #include "XGUI_ModuleConnector.h"
12 #include "XGUI_QtEvents.h"
13
14 #ifndef HAVE_SALOME
15 #include <AppElements_Workbench.h>
16 #include <AppElements_Command.h>
17 #include <AppElements_MainMenu.h>
18 #include <AppElements_MainWindow.h>
19 #include <AppElements_MenuGroupPanel.h>
20 #include <AppElements_Button.h>
21 #endif
22
23 #include <ModuleBase_IModule.h>
24
25 #include <ModelAPI_Object.h>
26 #include <ModelAPI_Events.h>
27 #include <ModelAPI_Session.h>
28 #include <ModelAPI_Result.h>
29 #include <ModelAPI_Feature.h>
30 #include <ModelAPI_Data.h>
31 #include <ModelAPI_ResultBody.h>
32 #include <ModelAPI_ResultCompSolid.h>
33 #include <ModelAPI_Tools.h>
34
35 #include <Events_Loop.h>
36 #include <Events_Error.h>
37 #include <Events_LongOp.h>
38
39 #include <ModuleBase_IWorkshop.h>
40
41 #include <ModuleBase_Operation.h>
42 #include <ModuleBase_OperationDescription.h>
43 #include <ModuleBase_OperationFeature.h>
44 #include <ModuleBase_Tools.h>
45 #include <ModuleBase_IViewer.h>
46 #include <ModuleBase_FilterFactory.h>
47
48 #include <Config_FeatureMessage.h>
49 #include <Config_PointerMessage.h>
50 #include <Config_SelectionFilterMessage.h>
51 #include <Config_Keywords.h>
52
53 #include <QApplication>
54 #include <QMainWindow>
55 #include <QThread>
56 #include <QAction>
57
58 #ifdef _DEBUG
59 #include <QDebug>
60 #include <iostream>
61 #endif
62
63 //#define DEBUG_FEATURE_CREATED
64 //#define DEBUG_FEATURE_REDISPLAY
65 //#define DEBUG_FEATURE_UPDATED
66 //#define DEBUG_RESULT_COMPSOLID
67
68 #ifdef DEBUG_FEATURE_REDISPLAY
69 const std::string DebugFeatureKind = "Extrusion";
70 #endif
71
72 XGUI_WorkshopListener::XGUI_WorkshopListener(ModuleBase_IWorkshop* theWorkshop)
73   : myWorkshop(theWorkshop),
74     myUpdatePrefs(false)
75 {
76   XGUI_OperationMgr* anOperationMgr = workshop()->operationMgr();
77   //connect(anOperationMgr, SIGNAL(nestedStateChanged(const std::string&, const bool)),
78   //        this, SLOT(onNestedStateChanged(const std::string&, const bool)));
79 }
80
81 //******************************************************
82 XGUI_WorkshopListener::~XGUI_WorkshopListener(void)
83 {
84 }
85
86 //******************************************************
87 void XGUI_WorkshopListener::initializeEventListening()
88 {
89   //Initialize event listening
90   Events_Loop* aLoop = Events_Loop::loop();
91   aLoop->registerListener(this, Events_Error::errorID());  //!< Listening application errors.
92   aLoop->registerListener(this, Events_Loop::eventByName(Config_FeatureMessage::GUI_EVENT()));
93   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OPERATION_LAUNCHED));
94   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
95   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
96   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
97   aLoop->registerListener(this, Events_LongOp::eventID());
98   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_PLUGIN_LOADED));
99   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_SELFILTER_LOADED));
100   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_ERROR_CHANGED));
101
102   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_UPDATE_VIEWER_BLOCKED));
103   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_UPDATE_VIEWER_UNBLOCKED));
104 }
105
106 //******************************************************
107 void XGUI_WorkshopListener::processEvent(const std::shared_ptr<Events_Message>& theMessage)
108 {
109   if (QApplication::instance()->thread() != QThread::currentThread()) {
110     #ifdef _DEBUG
111     std::cout << "XGUI_Workshop::processEvent: " << "Working in another thread." << std::endl;
112     #endif
113     SessionPtr aMgr = ModelAPI_Session::get();
114     PostponeMessageQtEvent* aPostponeEvent = new PostponeMessageQtEvent(theMessage);
115     QApplication::postEvent(this, aPostponeEvent);
116     return;
117   }
118
119   //A message to start feature creation received.
120   if (theMessage->eventID() == Events_Loop::loop()->eventByName(Config_FeatureMessage::GUI_EVENT())) {
121     std::shared_ptr<Config_FeatureMessage> aFeatureMsg =
122        std::dynamic_pointer_cast<Config_FeatureMessage>(theMessage);
123     if (!aFeatureMsg->isInternal()) {
124       addFeature(aFeatureMsg);
125     }
126   }
127   // Process creation of Part
128   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)) {
129     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
130         std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
131     onFeatureCreatedMsg(aUpdMsg);
132     if (myUpdatePrefs) {
133       XGUI_SalomeConnector* aSalomeConnector = workshop()->salomeConnector();
134       if (aSalomeConnector)
135         aSalomeConnector->createPreferences();
136       myUpdatePrefs = false;
137     }
138   }
139   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_PLUGIN_LOADED)) {
140     myUpdatePrefs = true;
141   }
142   // Redisplay feature
143   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY)) {
144     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
145         std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
146     onFeatureRedisplayMsg(aUpdMsg);
147   }
148   //Update property panel on corresponding message. If there is no current operation (no
149   //property panel), or received message has different feature to the current - do nothing.
150   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)) {
151     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
152         std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
153     onFeatureUpdatedMsg(anUpdateMsg);
154   } else if (theMessage->eventID() == Events_LongOp::eventID()) {
155     if (Events_LongOp::isPerformed()) {
156       QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
157     } else {
158       QApplication::restoreOverrideCursor();
159     }
160   }
161   //An operation passed by message. Start it, process and commit.
162   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OPERATION_LAUNCHED)) {
163     std::shared_ptr<Config_PointerMessage> aPartSetMsg =
164         std::dynamic_pointer_cast<Config_PointerMessage>(theMessage);
165     //myPropertyPanel->cleanContent();
166     ModuleBase_Operation* anOperation = (ModuleBase_Operation*) aPartSetMsg->pointer();
167     XGUI_OperationMgr* anOperationMgr = workshop()->operationMgr();
168
169     if (anOperationMgr->startOperation(anOperation)) {
170       ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(anOperation);
171       if (aFOperation)
172         workshop()->propertyPanel()->updateContentWidget(aFOperation->feature());
173       if (!anOperation->getDescription()->hasXmlRepresentation()) {
174         if (anOperation->commit())
175           workshop()->updateCommandStatus();
176       }
177     }
178   } 
179   else if (theMessage->eventID() == Events_Loop::eventByName(EVENT_SELFILTER_LOADED)) {
180     std::shared_ptr<Config_SelectionFilterMessage> aMsg = 
181       std::dynamic_pointer_cast<Config_SelectionFilterMessage>(theMessage);
182     if (aMsg) {
183       ModuleBase_FilterFactory* aFactory = myWorkshop->selectionFilters();
184       if (!aMsg->attributeId().empty()) {
185         aFactory->assignFilter(aMsg->selectionFilterId(), aMsg->featureId(), aMsg->attributeId(),
186                                aMsg->parameters());
187       }
188     }
189   } else if (theMessage->eventID() == Events_Loop::eventByName(EVENT_UPDATE_VIEWER_BLOCKED)) {
190     // the viewer's update context will not happens until viewer updated is emitted
191       workshop()->displayer()->enableUpdateViewer(false);
192   } else if (theMessage->eventID() == Events_Loop::eventByName(EVENT_UPDATE_VIEWER_UNBLOCKED)) {
193     // the viewer's update context is unblocked, the viewer's update works
194     XGUI_Displayer* aDisplayer = workshop()->displayer();
195     aDisplayer->enableUpdateViewer(true);
196   } else if (theMessage->eventID() == Events_Loop::eventByName(EVENT_OBJECT_ERROR_CHANGED)) {
197     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
198         std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
199     std::set<ObjectPtr> aObjects = aUpdMsg->objects();
200
201     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
202                                               (workshop()->operationMgr()->currentOperation());
203     bool aFeatureChanged = false;
204     if(aFOperation ) {
205       FeaturePtr aFeature = aFOperation->feature();
206       if (aFeature.get()) {
207         std::set<ObjectPtr>::const_iterator aIt;
208         for (aIt = aObjects.begin(); aIt != aObjects.end() && !aFeatureChanged; ++aIt) {
209           aFeatureChanged = ModelAPI_Feature::feature(*aIt) == aFeature;
210         }
211       }
212       if (aFeatureChanged)
213         workshop()->operationMgr()->onValidateOperation();
214     }
215   } else {
216     //Show error dialog if error message received.
217     std::shared_ptr<Events_Error> anAppError = std::dynamic_pointer_cast<Events_Error>(theMessage);
218     if (anAppError) {
219       emit errorOccurred(QString::fromLatin1(anAppError->description()));
220     }
221     return;
222   }
223 #ifndef HAVE_SALOME
224     SessionPtr aMgr = ModelAPI_Session::get();
225     AppElements_MainWindow* aMainWindow = workshop()->mainWindow();
226     if (aMgr->isModified() != aMainWindow->isModifiedState())
227       aMainWindow->setModifiedState(aMgr->isModified());
228 #endif
229 }
230
231 //******************************************************
232 void XGUI_WorkshopListener::onFeatureUpdatedMsg(
233                                      const std::shared_ptr<ModelAPI_ObjectUpdatedMessage>& theMsg)
234 {
235 #ifdef DEBUG_FEATURE_UPDATED
236   std::set<ObjectPtr> aObjects = theMsg->objects();
237   std::set<ObjectPtr>::const_iterator aIt;
238   QStringList anInfo;
239   for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) {
240     anInfo.append(ModuleBase_Tools::objectInfo((*aIt)));
241   }
242   QString anInfoStr = anInfo.join(";\t");
243   qDebug(QString("onFeatureUpdatedMsg: %1, %2").arg(aObjects.size()).arg(anInfoStr).toStdString().c_str());
244 #endif
245   std::set<ObjectPtr> aFeatures = theMsg->objects();
246   XGUI_OperationMgr* anOperationMgr = workshop()->operationMgr();
247   if (anOperationMgr->hasOperation()) {
248     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
249                                                       (anOperationMgr->currentOperation());
250     if (aFOperation) {
251       FeaturePtr aCurrentFeature = aFOperation->feature();
252       std::set<ObjectPtr>::const_iterator aIt;
253       for (aIt = aFeatures.begin(); aIt != aFeatures.end(); ++aIt) {
254         ObjectPtr aNewFeature = (*aIt);
255         if (aNewFeature == aCurrentFeature) {
256           workshop()->propertyPanel()->updateContentWidget(aCurrentFeature);
257           break;
258         }
259       }
260     }
261   }
262   //anOperationMgr->onValidateOperation();
263
264   //if (myObjectBrowser)
265   //  myObjectBrowser->processEvent(theMsg);
266 }
267
268 //******************************************************
269 void XGUI_WorkshopListener::onFeatureRedisplayMsg(const std::shared_ptr<ModelAPI_ObjectUpdatedMessage>& theMsg)
270 {
271   std::set<ObjectPtr> aObjects = theMsg->objects();
272   std::set<ObjectPtr>::const_iterator aIt;
273
274 #ifdef DEBUG_FEATURE_REDISPLAY
275   QStringList anInfo;
276   for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) {
277     anInfo.append(ModuleBase_Tools::objectInfo((*aIt)));
278   }
279   QString anInfoStr = anInfo.join(";\t");
280   qDebug(QString("onFeatureRedisplayMsg: %1, %2").arg(aObjects.size()).arg(anInfoStr).toStdString().c_str());
281 #endif
282
283   XGUI_Workshop* aWorkshop = workshop();
284   XGUI_Displayer* aDisplayer = aWorkshop->displayer();
285   bool aFirstVisualizedBody = false;
286
287   bool aRedisplayed = false;
288   for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) {
289     ObjectPtr aObj = (*aIt);
290
291     // Hide the object if it is invalid or concealed one
292     bool aHide = !aObj->data() || !aObj->data()->isValid() || 
293       aObj->isDisabled() || (!aObj->isDisplayed());
294     if (!aHide) { // check that this is not hidden result
295       ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
296       aHide = aRes && aRes->isConcealed();
297     }
298 #ifdef DEBUG_RESULT_COMPSOLID
299     ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
300     if (aRes.get()) {
301       ResultCompSolidPtr aCompSolidRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aRes);
302       if (aCompSolidRes.get()) {
303           qDebug(QString("COMPSOLID, numberOfSubs = %1").arg(aCompSolidRes->numberOfSubs()).toStdString().c_str());
304       }
305       if (ModelAPI_Tools::compSolidOwner(aRes))
306         qDebug("COMPSOLID sub-object");
307     }
308 #endif
309     #ifdef DEBUG_FEATURE_REDISPLAY
310       QString anObjInfo = ModuleBase_Tools::objectInfo((aObj));
311       FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
312       if (aFeature.get()) {
313         std::string aKind = aFeature->getKind();
314         if (aKind == DebugFeatureKind) {
315           qDebug(QString("visible=%1, hide=%2 : display= %2").arg(aDisplayer->isVisible(aObj))
316                                             .arg(aHide).arg(anObjInfo).toStdString().c_str());
317         }
318       }
319     #endif
320     if (aHide) {
321       aRedisplayed = aDisplayer->erase(aObj, false) || aRedisplayed;
322       #ifdef DEBUG_FEATURE_REDISPLAY
323         // Redisplay the visible object or the object of the current operation
324         bool isVisibleObject = aDisplayer->isVisible(aObj);
325
326         QString anObjInfo = ModuleBase_Tools::objectInfo((aObj));
327         //qDebug(QString("visible=%1 : erase  = %2").arg(isVisibleObject).arg(anObjInfo).toStdString().c_str());
328       #endif
329     }
330     else {
331       // Redisplay the visible object or the object of the current operation
332       bool isVisibleObject = aDisplayer->isVisible(aObj);
333       #ifdef DEBUG_FEATURE_REDISPLAY
334         QString anObjInfo = ModuleBase_Tools::objectInfo((aObj));
335         //qDebug(QString("visible=%1 : display= %2").arg(isVisibleObject).arg(anObjInfo).toStdString().c_str());
336       #endif
337
338       if (isVisibleObject)  { // redisplay visible object
339         //displayObject(aObj);  // In order to update presentation
340         // in order to avoid the check whether the object can be redisplayed, the exact method
341         // of redisplay is called. This modification is made in order to have the line is updated
342         // by creation of a horizontal constraint on the line by preselection
343         if (ModelAPI_Tools::hasSubResults(std::dynamic_pointer_cast<ModelAPI_Result>(aObj))) {
344           aRedisplayed = aDisplayer->erase(aObj, false) || aRedisplayed;
345         }
346         else {
347           aRedisplayed = aDisplayer->redisplay(aObj, false) || aRedisplayed;
348           // Deactivate object of current operation from selection
349           aWorkshop->deactivateActiveObject(aObj, false);
350         }
351       } else { // display object if the current operation has it
352         if (displayObject(aObj, aFirstVisualizedBody)) {
353           aRedisplayed = true;
354           // Deactivate object of current operation from selection
355           aWorkshop->deactivateActiveObject(aObj, false);
356         }
357       }
358     }
359   }
360   if (aRedisplayed) {
361     customizeCurrentObject();
362     //VSV FitAll updated viewer by it self
363     if (aFirstVisualizedBody)
364       myWorkshop->viewer()->fitAll();
365     else 
366       aDisplayer->updateViewer();
367   }
368 }
369 //******************************************************
370 void XGUI_WorkshopListener::onFeatureCreatedMsg(const std::shared_ptr<ModelAPI_ObjectUpdatedMessage>& theMsg)
371 {
372   std::set<ObjectPtr> aObjects = theMsg->objects();
373   std::set<ObjectPtr>::const_iterator aIt;
374 #ifdef DEBUG_FEATURE_CREATED
375   QStringList anInfo;
376   for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) {
377     anInfo.append(ModuleBase_Tools::objectInfo((*aIt)));
378   }
379   QString anInfoStr = anInfo.join(";\t");
380   qDebug(QString("onFeatureCreatedMsg: %1, %2").arg(aObjects.size()).arg(anInfoStr).toStdString().c_str());
381 #endif
382
383   bool aFirstVisualizedBody = false;
384
385   //bool aHasPart = false;
386   bool aDisplayed = false;
387   for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) {
388     ObjectPtr anObject = *aIt;
389
390 #ifdef DEBUG_RESULT_COMPSOLID
391     ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
392     if (aRes.get()) {
393       ResultCompSolidPtr aCompSolidRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aRes);
394       if (aCompSolidRes.get()) {
395           qDebug(QString("COMPSOLID, numberOfSubs = %1").arg(aCompSolidRes->numberOfSubs()).toStdString().c_str());
396       }
397       if (ModelAPI_Tools::compSolidOwner(aRes))
398         qDebug("COMPSOLID sub-object");
399     }
400 #endif
401     // the validity of the data should be checked here in order to avoid display of the objects,
402     // which were created, then deleted, but flush for the creation event happens after that
403     // we should not display disabled objects
404     bool aHide = !anObject->data()->isValid() || 
405                  anObject->isDisabled() ||
406                  !anObject->isDisplayed();
407     if (!aHide) {
408       // setDisplayed has to be called in order to synchronize internal state of the object 
409       // with list of displayed objects
410       if (myWorkshop->module()->canDisplayObject(anObject)) {
411         anObject->setDisplayed(true);
412         aDisplayed = displayObject(*aIt, aFirstVisualizedBody);
413       } else 
414         anObject->setDisplayed(false);
415     }
416   }
417
418   //if (myObjectBrowser)
419   //  myObjectBrowser->processEvent(theMsg);
420   if (aDisplayed) {
421     customizeCurrentObject();
422     //VSV FitAll updated viewer by it self
423     if (aFirstVisualizedBody)
424       myWorkshop->viewer()->fitAll();
425     else
426       workshop()->displayer()->updateViewer();
427   }
428   //if (aHasPart) { // TODO: Avoid activate last part on loading of document
429   //  activateLastPart();
430   //}
431 }
432
433 /*void XGUI_WorkshopListener::onNestedStateChanged(const std::string& theFeatureId, const bool theState)
434 {
435   XGUI_Workshop* aWorkshop = workshop();
436
437   //one button is used for all features, which can have nested actions, so it is obtained from
438   // the action manager
439   //bool aActionToBeUpdated = aWorkshop->isFeatureOfNested(theFeatureId);
440   if (aWorkshop->isSalomeMode()) {
441     XGUI_SalomeConnector* aSalomeConnector = aWorkshop->salomeConnector();
442     XGUI_ActionsMgr* anActionsMgr = aWorkshop->actionsMgr();
443     if (aSalomeConnector->isFeatureOfNested(anActionsMgr->action(theFeatureId.c_str())))
444       aActionToBeUpdated = true;
445   } else {
446     AppElements_MainMenu* aMenuBar = aWorkshop->mainWindow()->menuObject();
447     AppElements_Command* aCommand = aMenuBar->feature(theFeatureId.c_str());
448     if (aCommand && aCommand->button()->additionalButtonWidget())
449       aActionToBeUpdated = true;
450   }
451   if (aActionToBeUpdated) {
452     QAction* anAcceptAllAction = aWorkshop->actionsMgr()->operationStateAction(XGUI_ActionsMgr::AcceptAll, NULL);
453     anAcceptAllAction->setEnabled(theState);
454   }
455 }*/
456
457 bool XGUI_WorkshopListener::event(QEvent * theEvent)
458 {
459   PostponeMessageQtEvent* aPostponedEv = dynamic_cast<PostponeMessageQtEvent*>(theEvent);
460   if (aPostponedEv) {
461     std::shared_ptr<Events_Message> aEventPtr = aPostponedEv->postponedMessage();
462     processEvent(aEventPtr);
463     return true;
464   }
465   return false;
466 }
467
468 void XGUI_WorkshopListener::addFeature(const std::shared_ptr<Config_FeatureMessage>& theMessage)
469 {
470   if (!theMessage) {
471 #ifdef _DEBUG
472     qDebug() << "XGUI_WorkshopListener::addFeature: NULL message.";
473 #endif
474     return;
475   }
476   ActionInfo aFeatureInfo;
477   aFeatureInfo.initFrom(theMessage);
478
479   XGUI_Workshop* aWorkshop = workshop();
480
481   QString aWchName = QString::fromStdString(theMessage->workbenchId());
482   QStringList aNestedFeatures =
483       QString::fromStdString(theMessage->nestedFeatures()).split(" ", QString::SkipEmptyParts);
484   QString aDocKind = QString::fromStdString(theMessage->documentKind());
485   QList<QAction*> aNestedActList;
486   bool isColumnButton = !aNestedFeatures.isEmpty();
487   if (isColumnButton) {
488     QString aNestedActions = QString::fromStdString(theMessage->actionsWhenNested());
489     XGUI_OperationMgr* anOperationMgr = aWorkshop->operationMgr();
490     XGUI_ActionsMgr* anActionsMgr = aWorkshop->actionsMgr();
491     if (aNestedActions.contains(FEATURE_WHEN_NESTED_ACCEPT)) {
492       QAction* anAction = anActionsMgr->operationStateAction(XGUI_ActionsMgr::AcceptAll, NULL);
493       connect(anAction, SIGNAL(triggered()), anOperationMgr, SLOT(commitAllOperations()));
494       aNestedActList << anAction;
495     }
496     if (aNestedActions.contains(FEATURE_WHEN_NESTED_ABORT)) {
497       QAction* anAction = anActionsMgr->operationStateAction(XGUI_ActionsMgr::AbortAll, NULL);
498       connect(anAction, SIGNAL(triggered()), anOperationMgr, SLOT(abortAllOperations()));
499       aNestedActList << anAction;
500     }
501   }
502
503 #ifdef HAVE_SALOME
504   XGUI_SalomeConnector* aSalomeConnector = aWorkshop->salomeConnector();
505   QAction* aAction;
506   if (isColumnButton) {
507     aAction = aSalomeConnector->addFeatureOfNested(aWchName, aFeatureInfo, aNestedActList);
508   } else {
509     //Issue #650: in the SALOME mode the tooltip should be same as text
510     aFeatureInfo.toolTip = aFeatureInfo.text;
511     aAction = aSalomeConnector->addFeature(aWchName, aFeatureInfo);
512   }
513   aSalomeConnector->setNestedActions(aFeatureInfo.id, aNestedFeatures);
514   aSalomeConnector->setDocumentKind(aFeatureInfo.id, aDocKind);
515
516   aWorkshop->actionsMgr()->addCommand(aAction);
517   aWorkshop->module()->actionCreated(aAction);
518 #else 
519   //Find or create Workbench
520   AppElements_MainMenu* aMenuBar = aWorkshop->mainWindow()->menuObject();
521   AppElements_Workbench* aPage = aMenuBar->findWorkbench(aWchName);
522   if (!aPage) {
523     aPage = aWorkshop->addWorkbench(aWchName);
524   }
525   //Find or create Group
526   QString aGroupName = QString::fromStdString(theMessage->groupId());
527   AppElements_MenuGroupPanel* aGroup = aPage->findGroup(aGroupName);
528   if (!aGroup) {
529     aGroup = aPage->addGroup(aGroupName);
530   }
531   // Check if hotkey sequence is already defined:
532   XGUI_ActionsMgr* anActionsMgr = aWorkshop->actionsMgr();
533   QKeySequence aHotKey = anActionsMgr->registerShortcut(aFeatureInfo.shortcut);
534   if(aHotKey != aFeatureInfo.shortcut) {
535     aFeatureInfo.shortcut = aHotKey;
536   }
537   // Create feature...
538   AppElements_Command* aCommand = aGroup->addFeature(aFeatureInfo,
539                                                       aDocKind,
540                                                       aNestedFeatures);
541   // Enrich created button with accept/abort buttons if necessary
542   AppElements_Button* aButton = aCommand->button();
543   if (aButton->isColumnButton()) {
544     aButton->setAdditionalButtons(aNestedActList);
545   }
546   aWorkshop->actionsMgr()->addCommand(aCommand);
547   aWorkshop->module()->actionCreated(aCommand);
548 #endif
549 }
550
551
552 //**************************************************************
553 bool XGUI_WorkshopListener::displayObject(ObjectPtr theObj, bool& theFirstVisualizedBody)
554 {
555 #ifdef DEBUG_RESULT_COMPSOLID
556   ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(theObj);
557   if (aRes.get() && (ModelAPI_Tools::hasSubResults(aRes) || ModelAPI_Tools::compSolidOwner(aRes))) {
558     ResultCompSolidPtr aCompSolidRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aRes);
559     if (aCompSolidRes.get()) {
560       qDebug("COMPSOLID: displayObject");
561     }
562   }
563 #endif
564
565   bool aDisplayed = false;
566   XGUI_Workshop* aWorkshop = workshop();
567   // do not display the object if it has sub objects. They should be displayed separately.
568   if (!aWorkshop->module()->canDisplayObject(theObj) ||
569       ModelAPI_Tools::hasSubResults(std::dynamic_pointer_cast<ModelAPI_Result>(theObj)))
570     return aDisplayed;
571
572   XGUI_Displayer* aDisplayer = aWorkshop->displayer();
573   ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(theObj);
574   if (aBody.get() != NULL) {
575     int aNb = aDisplayer->objectsCount();
576     aDisplayed = aDisplayer->display(theObj, false);
577     if (aNb == 0)
578       theFirstVisualizedBody = true;
579   } else 
580     aDisplayed = aDisplayer->display(theObj, false);
581
582   return aDisplayed;
583 }
584
585 bool XGUI_WorkshopListener::customizeCurrentObject()
586 {
587   bool aCustomized = false;
588   XGUI_OperationMgr* anOperationMgr = workshop()->operationMgr();
589   if (anOperationMgr->hasOperation()) {
590     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
591                                                       (anOperationMgr->currentOperation());
592     if (aFOperation) {
593       FeaturePtr aCurrentFeature = aFOperation->feature();
594       if (aCurrentFeature.get())
595         aCustomized = myWorkshop->module()->customizeObject(aCurrentFeature, false);
596     }
597   }
598   return aCustomized;
599 }
600
601 XGUI_Workshop* XGUI_WorkshopListener::workshop() const
602 {
603   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myWorkshop);
604   return aConnector->workshop();
605 }