Salome HOME
Add copyright header according to request of CEA from 06.06.2017
[modules/shaper.git] / src / XGUI / XGUI_ActionsMgr.cpp
1 // Copyright (C) 2014-2017  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<mailto: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 Abort:
258       case AbortAll: {
259         aResult = ModuleBase_Tools::createAction(QIcon(":pictures/button_cancel.png"), "Cancel",
260                                                  aParent);
261       }
262       break;
263       case Help: {
264         aResult = ModuleBase_Tools::createAction(QIcon(":pictures/button_help.png"), "Help",
265                                                  aParent);
266       }
267       break;
268       case Preview: {
269         aResult = ModuleBase_Tools::createAction(QIcon(), tr("See preview"),
270                                                  aParent, 0, 0, "Compute preview");
271         aResult->setStatusTip(aResult->toolTip());
272       }
273       break;
274       default:
275         break;
276     }
277     myOperationActions.insert(theId, aResult);
278   }
279   return aResult;
280 }
281
282 QAction* XGUI_ActionsMgr::action(const QString& theId)
283 {
284   QAction* anAction = 0;
285   if(myActions.contains(theId)) {
286     anAction = myActions.value(theId);
287   }
288   return anAction;
289 }
290
291 ActionInfo XGUI_ActionsMgr::actionInfoById(const QString& theId)
292 {
293   ActionInfo aResult;
294   if(myActions.contains(theId)) {
295     aResult.initFrom(myActions.value(theId));
296   } else {
297    aResult.id = theId;
298    aResult.text = theId;
299   }
300   return aResult;
301 }
302
303 void XGUI_ActionsMgr::setAllEnabled()
304 {
305   foreach(QString eachAction, myActions.keys()) {
306     if (myActions.contains(eachAction)) {
307       QAction* aAction = myActions[eachAction];
308       aAction->setEnabled(true);
309     }
310   }
311 }
312
313
314 //!
315 void XGUI_ActionsMgr::setNestedCommandsEnabled(bool theEnabled, const QString& theParent)
316 {
317   QStringList ltNestedActions;
318   if (theParent.isEmpty()) {  //Disable ALL nested
319     foreach(QString eachParent, myNestedActions.keys()) {
320       ltNestedActions << myNestedActions[eachParent];
321     }
322   } else {
323     ltNestedActions << myNestedActions[theParent];
324   }
325   foreach(QString eachNested, ltNestedActions) {
326     setActionEnabled(eachNested, theEnabled);
327   }
328 }
329
330 void XGUI_ActionsMgr::setNestedStackEnabled(ModuleBase_Operation* theOperation)
331 {
332   ModuleBase_OperationFeature* anOperation =
333     dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
334   if(!anOperation || !anOperation->feature())
335     return;
336   FeaturePtr aFeature = anOperation->feature();
337   QString aFeatureId = QString::fromStdString(aFeature->getKind());
338   //setActionEnabled(aFeatureId, true);
339   setNestedCommandsEnabled(true, aFeatureId);
340
341   setNestedStackEnabled(myOperationMgr->previousOperation(theOperation));
342 }
343
344 QStringList XGUI_ActionsMgr::allNestedCommands(ModuleBase_Operation* theOperation)
345 {
346   QStringList aFeatures;
347   ModuleBase_OperationFeature* anOperation =
348     dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
349   if(!anOperation || !anOperation->feature())
350     return aFeatures;
351   FeaturePtr aFeature = anOperation->feature();
352   QString aFeatureId = QString::fromStdString(aFeature->getKind());
353
354   aFeatures << myNestedActions[aFeatureId];
355   aFeatures << allNestedCommands(myOperationMgr->previousOperation(theOperation));
356   return aFeatures;
357 }
358
359 void XGUI_ActionsMgr::setActionChecked(const QString& theId, const bool theChecked)
360 {
361   if (myActions.contains(theId)) {
362     QAction* anAction = myActions[theId];
363     if (anAction->isCheckable()) {
364       anAction->setChecked(theChecked);
365     }
366   }
367 }
368
369 void XGUI_ActionsMgr::setActionEnabled(const QString& theId, const bool theEnabled)
370 {
371   if (myActions.contains(theId)) {
372     QAction* aAction = myActions[theId];
373     // Initially all actions are enabled
374     // If it was disabled for any reason then we can not enable it
375     if (aAction->isEnabled())
376       aAction->setEnabled(theEnabled);
377   }
378 }
379
380 /*
381  * Disables all actions which have the Document Kind different to
382  * the current document's kind
383  */
384 void XGUI_ActionsMgr::updateByDocumentKind()
385 {
386   std::string aStdDocKind = ModelAPI_Session::get()->activeDocument()->kind();
387   QString aDocKind = QString::fromStdString(aStdDocKind);
388   XGUI_Workshop* aWorkshop = static_cast<XGUI_Workshop*>(parent());
389   foreach(QAction* eachAction, myActions.values()) {
390     QString aCmdDocKind;
391 #ifdef HAVE_SALOME
392     QString aId = eachAction->data().toString();
393     if (!aId.isEmpty()) {
394       aCmdDocKind = QString::fromStdString(
395                  aWorkshop->salomeConnector()->featureInfo(aId)->documentKind());
396     }
397 #else
398     AppElements_Command* aCmd = dynamic_cast<AppElements_Command*>(eachAction);
399     aCmdDocKind = QString::fromStdString(aCmd->featureMessage()->documentKind());
400 #endif
401     if(!aCmdDocKind.isEmpty() && aCmdDocKind != aDocKind) {
402       eachAction->setEnabled(false);
403     }
404   }
405 }
406
407 void XGUI_ActionsMgr::updateByPlugins(FeaturePtr anActiveFeature)
408 {
409   static Events_ID aStateRequestEventId = Events_Loop::loop()->eventByName(
410       EVENT_FEATURE_STATE_REQUEST);
411   std::shared_ptr<ModelAPI_FeatureStateMessage> aMsg(
412       new ModelAPI_FeatureStateMessage(aStateRequestEventId, this));
413   aMsg->setFeature(anActiveFeature);
414   Events_Loop::loop()->send(aMsg, false);
415 }