Salome HOME
Issue #1015: The validate icon must be greyed and inactive instead of red and active
[modules/shaper.git] / src / XGUI / XGUI_ActionsMgr.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 #ifndef HAVE_SALOME
4 #include <AppElements_Command.h>
5 #endif
6
7 #include <XGUI_ActionsMgr.h>
8 #include <XGUI_Workshop.h>
9 #include <XGUI_OperationMgr.h>
10 #include <XGUI_SalomeConnector.h>
11 #include <XGUI_Selection.h>
12 #include <XGUI_SelectionMgr.h>
13
14 #include <Events_Loop.h>
15 #include <Events_Error.h>
16
17 #include <ModelAPI_Session.h>
18 #include <ModelAPI_Events.h>
19 #include <ModelAPI_Validator.h>
20 #include <ModuleBase_Operation.h>
21 #include <ModuleBase_OperationFeature.h>
22 #include <ModuleBase_SelectionValidator.h>
23 #include <ModuleBase_Tools.h>
24
25
26 #include <QAction>
27
28 #ifdef _DEBUG
29 #include <iostream>
30 #include <QDebug>
31 #endif
32
33 XGUI_ActionsMgr::XGUI_ActionsMgr(XGUI_Workshop* theParent)
34     : QObject(theParent),
35       myWorkshop(theParent),
36       myOperationMgr(theParent->operationMgr())
37 {
38   // Default shortcuts
39   myShortcuts << QKeySequence::Save;
40   myShortcuts << QKeySequence::Undo;
41   myShortcuts << QKeySequence::Redo;
42   myShortcuts << QKeySequence::Open;
43   myShortcuts << QKeySequence::Close;
44
45   //Initialize event listening
46   Events_Loop* aLoop = Events_Loop::loop();
47   static Events_ID aStateResponseEventId =
48       Events_Loop::loop()->eventByName(EVENT_FEATURE_STATE_RESPONSE);
49   aLoop->registerListener(this, aStateResponseEventId, NULL, true);
50 }
51
52 XGUI_ActionsMgr::~XGUI_ActionsMgr()
53 {
54 }
55
56 void XGUI_ActionsMgr::addCommand(QAction* theCmd)
57 {
58   QString aId = theCmd->data().toString();
59   if (aId.isEmpty()) {
60     return;
61   }
62   myActions.insert(aId, theCmd);
63 #ifdef HAVE_SALOME
64     XGUI_Workshop* aWorkshop = static_cast<XGUI_Workshop*>(parent());
65     const std::shared_ptr<Config_FeatureMessage>& anInfo =
66                          aWorkshop->salomeConnector()->featureInfo(aId);
67     if (anInfo.get())
68       myNestedActions[aId] = QString::fromStdString(anInfo->nestedFeatures())
69                                    .split(" ", QString::SkipEmptyParts);
70 #else
71   AppElements_Command* aXCmd = dynamic_cast<AppElements_Command*>(theCmd);
72   myNestedActions[aId] = aXCmd->nestedCommands();
73 #endif
74 }
75
76 void XGUI_ActionsMgr::addNestedCommands(const QString& theId, const QStringList& theCommands)
77 {
78   myNestedActions[theId] = theCommands;
79 }
80
81 QStringList XGUI_ActionsMgr::nestedCommands(const QString& theId) const
82 {
83   if (myNestedActions.contains(theId))
84     return myNestedActions[theId];
85   return QStringList();
86 }
87
88 bool XGUI_ActionsMgr::isNested(const QString& theId) const
89 {
90   foreach(QString aId, myNestedActions.keys())
91   {
92     QStringList aList = myNestedActions[aId];
93     if (aList.contains(theId))
94       return true;
95   }
96   return false;
97 }
98
99 void XGUI_ActionsMgr::updateCommandsStatus()
100 {
101   setAllEnabled();
102   XGUI_Selection* aSelection = myWorkshop->selector()->selection();
103   if (aSelection->getSelected(ModuleBase_ISelection::Viewer).size() > 0)
104     updateOnViewSelection();
105
106   FeaturePtr anActiveFeature = FeaturePtr();
107   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
108                                                          (myOperationMgr->currentOperation());
109   if (aFOperation) {
110     anActiveFeature = aFOperation->feature();  
111     QStringList aNested = allNestedCommands(aFOperation);
112     foreach(QString aAction, myActions.keys()) {
113       if (!aNested.contains(aAction))
114         setActionEnabled(aAction, false);
115     }
116   } else 
117     setNestedCommandsEnabled(false);
118
119   updateByPlugins(anActiveFeature);
120   updateByDocumentKind();
121   updateCheckState();
122 }
123
124 void XGUI_ActionsMgr::updateCheckState()
125 {
126   QString eachCommand = QString();
127   foreach(eachCommand, myActions.keys()) {
128     setActionChecked(eachCommand, false);
129   }
130   QStringList ltActiveCommands = myOperationMgr->operationList();
131   foreach(eachCommand, ltActiveCommands) {
132     setActionChecked(eachCommand, true);
133   }
134 }
135
136 void XGUI_ActionsMgr::updateOnViewSelection()
137 {
138   if (!myOperationMgr->hasOperation())
139     return;
140
141   QStringList aIdList = myOperationMgr->operationList();
142   //ModuleBase_Operation* anOperation = myOperationMgr->currentOperation();
143   //FeaturePtr anActiveFeature = anOperation->feature();
144   //if(!anActiveFeature.get())
145   if (aIdList.isEmpty())
146     return;
147
148   ModuleBase_Operation* theOperation = myOperationMgr->currentOperation();
149   //QString aFeatureId = QString::fromStdString(anActiveFeature->getKind());
150   XGUI_Selection* aSelection = myWorkshop->selector()->selection();
151   // only viewer selection is processed
152   SessionPtr aMgr = ModelAPI_Session::get();
153   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
154   foreach(QString aFeatureId, aIdList) {
155     foreach(QString aId, nestedCommands(aFeatureId)) {
156       ModelAPI_ValidatorsFactory::Validators aValidators;
157       aFactory->validators(aId.toStdString(), aValidators);
158       ModelAPI_ValidatorsFactory::Validators::iterator aValidatorIt = aValidators.begin();
159       for (; aValidatorIt != aValidators.end(); ++aValidatorIt) {
160         const ModuleBase_SelectionValidator* aSelValidator =
161             dynamic_cast<const ModuleBase_SelectionValidator*>(aFactory->validator(aValidatorIt->first));
162         if (aSelValidator)
163           setActionEnabled(aId, aSelValidator->isValid(aSelection, theOperation));
164       }
165     }
166   }
167 }
168
169 QKeySequence XGUI_ActionsMgr::registerShortcut(const QKeySequence& theKeySequence)
170 {
171   if (theKeySequence.isEmpty()) {
172     return QKeySequence();
173   }
174   if (myShortcuts.contains(theKeySequence)) {
175     QString aMessage = tr("Shortcut %1 is already defined. Ignore.");
176     aMessage = aMessage.arg(theKeySequence.toString());
177     Events_Error::send(aMessage.toStdString());
178     return QKeySequence();
179   }
180   myShortcuts.append(theKeySequence);
181   return theKeySequence;
182 }
183
184 QKeySequence XGUI_ActionsMgr::registerShortcut(const QString& theKeySequence)
185 {
186   if (theKeySequence.isEmpty()) {
187     return QKeySequence();
188   }
189   QKeySequence aResult(theKeySequence);
190   registerShortcut(aResult);
191   return aResult;
192 }
193
194 void XGUI_ActionsMgr::processEvent(const std::shared_ptr<Events_Message>& theMessage)
195 {
196   const Events_ID kResponseEvent =
197       Events_Loop::loop()->eventByName(EVENT_FEATURE_STATE_RESPONSE);
198   if (theMessage->eventID() == kResponseEvent) {
199     std::shared_ptr<ModelAPI_FeatureStateMessage> aStateMessage =
200         std::dynamic_pointer_cast<ModelAPI_FeatureStateMessage>(theMessage);
201     if (!aStateMessage.get())
202       return;
203     std::list<std::string> aFeaturesList = aStateMessage->features();
204     std::list<std::string>::iterator it = aFeaturesList.begin();
205     for( ; it != aFeaturesList.end(); ++it) {
206       QString anActionId = QString::fromStdString(*it);
207       bool theDefaultState = false;
208       if (myActions.contains(anActionId)) {
209         theDefaultState = myActions[anActionId]->isEnabled();
210       }
211       setActionEnabled(anActionId, aStateMessage->state(*it, theDefaultState));
212     }
213   } else if (theMessage.get()) {
214     #ifdef _DEBUG
215     std::cout << "XGUI_ActionsMgr::processEvent: unhandled message caught: " << std::endl
216               << theMessage->eventID().eventText() << std::endl;
217     #endif
218   }
219 }
220
221 QAction* XGUI_ActionsMgr::operationStateAction(OperationStateActionId theId, QObject* theParent)
222 {
223   QAction* aResult = NULL;
224   if (myOperationActions.contains(theId)) {
225     aResult = myOperationActions.value(theId);
226     if (theParent && aResult->parent() != theParent) {
227       aResult->setParent(theParent);
228     }
229   } else {
230     switch (theId) {
231       case Accept:
232       case AcceptAll: {
233         aResult = ModuleBase_Tools::createAction(QIcon(":pictures/button_ok.png"),
234                             "" /*empty to show error*/, theParent);
235       }
236       break;
237       case Abort:
238       case AbortAll: {
239         aResult = ModuleBase_Tools::createAction(QIcon(":pictures/button_cancel.png"), "Cancel",
240                                                  theParent);
241         if (theId == Abort) {
242           aResult->setShortcut(QKeySequence(Qt::Key_Escape));
243         }
244       }
245       break;
246       case Help: {
247         aResult = ModuleBase_Tools::createAction(QIcon(":pictures/button_help.png"), "Help",
248                                                  theParent);
249       }
250       break;
251       case Preview: {
252         aResult = ModuleBase_Tools::createAction(QIcon(), tr("See preview"), theParent, 0, 0, "Compute preview");
253         aResult->setStatusTip(aResult->toolTip());
254       }
255       break;
256       default:
257         break;
258     }
259     myOperationActions.insert(theId, aResult);
260   }
261   return aResult;
262 }
263
264 QAction* XGUI_ActionsMgr::action(const QString& theId)
265 {
266   QAction* anAction = 0;
267   if(myActions.contains(theId)) {
268     anAction = myActions.value(theId);
269   }
270   return anAction;
271 }
272
273 ActionInfo XGUI_ActionsMgr::actionInfoById(const QString& theId)
274 {
275   ActionInfo aResult;
276   if(myActions.contains(theId)) {
277     aResult.initFrom(myActions.value(theId));
278   } else {
279    aResult.id = theId;
280    aResult.text = theId;
281   }
282   return aResult;
283 }
284
285 void XGUI_ActionsMgr::setAllEnabled()
286 {
287   foreach(QString eachAction, myActions.keys()) {
288     if (myActions.contains(eachAction)) {
289       QAction* aAction = myActions[eachAction];
290       aAction->setEnabled(true);
291     }
292   }
293 }
294
295
296 //!
297 void XGUI_ActionsMgr::setNestedCommandsEnabled(bool theEnabled, const QString& theParent)
298 {
299   QStringList ltNestedActions;
300   if (theParent.isEmpty()) {  //Disable ALL nested
301     foreach(QString eachParent, myNestedActions.keys()) {
302       ltNestedActions << myNestedActions[eachParent];
303     }
304   } else {
305     ltNestedActions << myNestedActions[theParent];
306   }
307   foreach(QString eachNested, ltNestedActions) {
308     setActionEnabled(eachNested, theEnabled);
309   }
310 }
311
312 void XGUI_ActionsMgr::setNestedStackEnabled(ModuleBase_Operation* theOperation)
313 {
314   ModuleBase_OperationFeature* anOperation = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
315   if(!anOperation || !anOperation->feature())
316     return;
317   FeaturePtr aFeature = anOperation->feature();
318   QString aFeatureId = QString::fromStdString(aFeature->getKind());
319   //setActionEnabled(aFeatureId, true);
320   setNestedCommandsEnabled(true, aFeatureId);
321
322   setNestedStackEnabled(myOperationMgr->previousOperation(theOperation));
323 }
324
325 QStringList XGUI_ActionsMgr::allNestedCommands(ModuleBase_Operation* theOperation)
326 {
327   QStringList aFeatures;
328   ModuleBase_OperationFeature* anOperation = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
329   if(!anOperation || !anOperation->feature())
330     return aFeatures;
331   FeaturePtr aFeature = anOperation->feature();
332   QString aFeatureId = QString::fromStdString(aFeature->getKind());
333
334   aFeatures << myNestedActions[aFeatureId];
335   aFeatures << allNestedCommands(myOperationMgr->previousOperation(theOperation));
336   return aFeatures;
337 }
338
339 void XGUI_ActionsMgr::setActionChecked(const QString& theId, const bool theChecked)
340 {
341   if (myActions.contains(theId)) {
342     QAction* anAction = myActions[theId];
343     if (anAction->isCheckable()) {
344       anAction->setChecked(theChecked);
345     }
346   }
347 }
348
349 void XGUI_ActionsMgr::setActionEnabled(const QString& theId, const bool theEnabled)
350 {
351   if (myActions.contains(theId)) {
352     QAction* aAction = myActions[theId];
353     // Initially all actions are enabled
354     // If it was disabled for any reason then we can not enable it
355     if (aAction->isEnabled())
356       aAction->setEnabled(theEnabled);
357   }
358 }
359
360 /*
361  * Disables all actions which have the Document Kind different to
362  * the current document's kind
363  */
364 void XGUI_ActionsMgr::updateByDocumentKind()
365 {
366   std::string aStdDocKind = ModelAPI_Session::get()->activeDocument()->kind();
367   QString aDocKind = QString::fromStdString(aStdDocKind);
368   XGUI_Workshop* aWorkshop = static_cast<XGUI_Workshop*>(parent());
369   foreach(QAction* eachAction, myActions.values()) {
370     QString aCmdDocKind;
371 #ifdef HAVE_SALOME
372     QString aId = eachAction->data().toString();
373     if (!aId.isEmpty()) {
374       aCmdDocKind = QString::fromStdString(
375                  aWorkshop->salomeConnector()->featureInfo(aId)->documentKind());
376     }
377 #else
378     AppElements_Command* aCmd = dynamic_cast<AppElements_Command*>(eachAction);
379     aCmdDocKind = QString::fromStdString(aCmd->featureMessage()->documentKind());
380 #endif
381     if(!aCmdDocKind.isEmpty() && aCmdDocKind != aDocKind) {
382       eachAction->setEnabled(false);
383     }
384   }
385 }
386
387 void XGUI_ActionsMgr::updateByPlugins(FeaturePtr anActiveFeature)
388 {
389   static Events_ID aStateRequestEventId = Events_Loop::loop()->eventByName(
390       EVENT_FEATURE_STATE_REQUEST);
391   std::shared_ptr<ModelAPI_FeatureStateMessage> aMsg(
392       new ModelAPI_FeatureStateMessage(aStateRequestEventId, this));
393   aMsg->setFeature(anActiveFeature);
394   Events_Loop::loop()->send(aMsg, false);
395 }