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