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