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