1 // Copyright (C) 2014-2024 CEA, EDF
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 #include <AppElements_Command.h>
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>
31 #include <Events_Loop.h>
32 #include <Events_InfoMessage.h>
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>
43 #include <QMainWindow>
46 #pragma warning(disable : 4456) // for nested foreach
54 XGUI_ActionsMgr::XGUI_ActionsMgr(XGUI_Workshop* theParent)
56 myWorkshop(theParent),
57 myOperationMgr(theParent->operationMgr())
60 myShortcuts << QKeySequence::Save;
61 myShortcuts << QKeySequence::Undo;
62 myShortcuts << QKeySequence::Redo;
63 myShortcuts << QKeySequence::Open;
64 myShortcuts << QKeySequence::Close;
66 //Initialize event listening
67 Events_Loop* aLoop = Events_Loop::loop();
68 static Events_ID aStateResponseEventId =
69 Events_Loop::loop()->eventByName(EVENT_FEATURE_STATE_RESPONSE);
70 aLoop->registerListener(this, aStateResponseEventId, NULL, true);
73 XGUI_ActionsMgr::~XGUI_ActionsMgr()
77 void XGUI_ActionsMgr::addCommand(QAction* theCmd)
79 QString aId = theCmd->data().toString();
83 myActions.insert(aId, theCmd);
85 XGUI_Workshop* aWorkshop = static_cast<XGUI_Workshop*>(parent());
86 const std::shared_ptr<Config_FeatureMessage>& anInfo =
87 aWorkshop->salomeConnector()->featureInfo(aId);
89 myNestedActions[aId] = QString::fromStdString(anInfo->nestedFeatures())
90 .split(" ", QString::SkipEmptyParts);
92 AppElements_Command* aXCmd = dynamic_cast<AppElements_Command*>(theCmd);
93 myNestedActions[aId] = aXCmd->nestedCommands();
97 void XGUI_ActionsMgr::addNestedCommands(const QString& theId, const QStringList& theCommands)
99 myNestedActions[theId] = theCommands;
102 QStringList XGUI_ActionsMgr::nestedCommands(const QString& theId) const
104 if (myNestedActions.contains(theId))
105 return myNestedActions[theId];
106 return QStringList();
109 bool XGUI_ActionsMgr::isNested(const QString& theId) const
111 foreach(QString aId, myNestedActions.keys())
113 QStringList aList = myNestedActions[aId];
114 if (aList.contains(theId))
120 void XGUI_ActionsMgr::updateCommandsStatus()
123 XGUI_Selection* aSelection = myWorkshop->selector()->selection();
124 if (aSelection->getSelected(ModuleBase_ISelection::AllControls).size() > 0)
125 updateOnViewSelection();
127 FeaturePtr anActiveFeature = FeaturePtr();
128 ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
129 (myOperationMgr->currentOperation());
131 anActiveFeature = aFOperation->feature();
132 QStringList aNested = allNestedCommands(aFOperation);
133 foreach(QString aAction, myActions.keys()) {
134 if (!aNested.contains(aAction))
135 setActionEnabled(aAction, false);
138 setNestedCommandsEnabled(false);
140 updateByPlugins(anActiveFeature);
141 updateByDocumentKind();
145 void XGUI_ActionsMgr::updateCheckState()
147 QString eachCommand = QString();
148 foreach(eachCommand, myActions.keys()) {
149 setActionChecked(eachCommand, false);
151 QStringList ltActiveCommands = myOperationMgr->operationList();
152 foreach(eachCommand, ltActiveCommands) {
153 setActionChecked(eachCommand, true);
157 void XGUI_ActionsMgr::updateOnViewSelection()
159 if (!myOperationMgr->hasOperation())
162 QStringList aIdList = myOperationMgr->operationList();
163 //ModuleBase_Operation* anOperation = myOperationMgr->currentOperation();
164 //FeaturePtr anActiveFeature = anOperation->feature();
165 //if(!anActiveFeature.get())
166 if (aIdList.isEmpty())
169 ModuleBase_Operation* theOperation = myOperationMgr->currentOperation();
170 //QString aFeatureId = QString::fromStdString(anActiveFeature->getKind());
171 XGUI_Selection* aSelection = myWorkshop->selector()->selection();
172 // only viewer selection is processed
173 SessionPtr aMgr = ModelAPI_Session::get();
174 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
175 foreach(QString aFeatureId, aIdList) {
176 foreach(QString aId, nestedCommands(aFeatureId)) {
177 ModelAPI_ValidatorsFactory::Validators aValidators;
178 aFactory->validators(aId.toStdString(), aValidators);
179 ModelAPI_ValidatorsFactory::Validators::iterator aValidatorIt = aValidators.begin();
180 for (; aValidatorIt != aValidators.end(); ++aValidatorIt) {
181 const ModuleBase_SelectionValidator* aSelValidator =
182 dynamic_cast<const ModuleBase_SelectionValidator*>
183 (aFactory->validator(aValidatorIt->first));
185 setActionEnabled(aId, aSelValidator->isValid(aSelection, theOperation));
191 QKeySequence XGUI_ActionsMgr::registerShortcut(const QKeySequence& theKeySequence)
193 if (theKeySequence.isEmpty()) {
194 return QKeySequence();
196 if (myShortcuts.contains(theKeySequence)) {
197 QString aMessage = tr("Shortcut %1 is already defined. Ignore.");
198 aMessage = aMessage.arg(theKeySequence.toString());
199 Events_InfoMessage("XGUI_ActionsMgr", aMessage.toStdString()).send();
200 return QKeySequence();
202 myShortcuts.append(theKeySequence);
203 return theKeySequence;
206 QKeySequence XGUI_ActionsMgr::registerShortcut(const QString& theKeySequence)
208 if (theKeySequence.isEmpty()) {
209 return QKeySequence();
211 QKeySequence aResult(theKeySequence);
212 registerShortcut(aResult);
216 void XGUI_ActionsMgr::processEvent(const std::shared_ptr<Events_Message>& theMessage)
218 const Events_ID kResponseEvent =
219 Events_Loop::loop()->eventByName(EVENT_FEATURE_STATE_RESPONSE);
220 if (theMessage->eventID() == kResponseEvent) {
221 std::shared_ptr<ModelAPI_FeatureStateMessage> aStateMessage =
222 std::dynamic_pointer_cast<ModelAPI_FeatureStateMessage>(theMessage);
223 if (!aStateMessage.get())
225 std::list<std::string> aFeaturesList = aStateMessage->features();
226 std::list<std::string>::iterator it = aFeaturesList.begin();
227 for( ; it != aFeaturesList.end(); ++it) {
228 QString anActionId = QString::fromStdString(*it);
229 bool theDefaultState = false;
230 if (myActions.contains(anActionId)) {
231 theDefaultState = myActions[anActionId]->isEnabled();
233 setActionEnabled(anActionId, aStateMessage->state(*it, theDefaultState));
235 } else if (theMessage.get()) {
237 std::cout << "XGUI_ActionsMgr::processEvent: unhandled message caught: " << std::endl
238 << theMessage->eventID().eventText() << std::endl;
243 QAction* XGUI_ActionsMgr::operationStateAction(OperationStateActionId theId)
245 QAction* aResult = NULL;
246 if (myOperationActions.contains(theId)) {
247 aResult = myOperationActions.value(theId);
248 //if (theParent && aResult->parent() != theParent) {
249 // aResult->setParent(theParent);
252 QWidget* aParent = myWorkshop->desktop();
256 aResult = ModuleBase_Tools::createAction(QIcon(":pictures/button_ok.png"),
257 tr("Apply"), aParent);
261 aResult = ModuleBase_Tools::createAction(QIcon(":pictures/button_ok-plus.png"),
262 tr("Apply and continue"), aParent);
267 aResult = ModuleBase_Tools::createAction(QIcon(":pictures/button_cancel.png"), tr("Cancel"),
272 aResult = ModuleBase_Tools::createAction(QIcon(":pictures/button_help.png"), tr("Help"),
277 aResult = ModuleBase_Tools::createAction(QIcon(), tr("See preview"),
278 aParent, 0, 0, tr("Compute preview"));
279 aResult->setStatusTip(aResult->toolTip());
285 myOperationActions.insert(theId, aResult);
290 QAction* XGUI_ActionsMgr::action(const QString& theId)
292 QAction* anAction = 0;
293 if(myActions.contains(theId)) {
294 anAction = myActions.value(theId);
299 ActionInfo XGUI_ActionsMgr::actionInfoById(const QString& theId)
302 if(myActions.contains(theId)) {
303 aResult.initFrom(myActions.value(theId));
306 aResult.text = theId;
311 void XGUI_ActionsMgr::setAllEnabled()
313 foreach(QString eachAction, myActions.keys()) {
314 if (myActions.contains(eachAction)) {
315 QAction* aAction = myActions[eachAction];
316 aAction->setEnabled(true);
323 void XGUI_ActionsMgr::setNestedCommandsEnabled(bool theEnabled, const QString& theParent)
325 QStringList ltNestedActions;
326 if (theParent.isEmpty()) { //Disable ALL nested
327 foreach(QString eachParent, myNestedActions.keys()) {
328 ltNestedActions << myNestedActions[eachParent];
331 ltNestedActions << myNestedActions[theParent];
333 foreach(QString eachNested, ltNestedActions) {
334 setActionEnabled(eachNested, theEnabled);
338 void XGUI_ActionsMgr::setNestedStackEnabled(ModuleBase_Operation* theOperation)
340 ModuleBase_OperationFeature* anOperation =
341 dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
342 if(!anOperation || !anOperation->feature())
344 FeaturePtr aFeature = anOperation->feature();
345 QString aFeatureId = QString::fromStdString(aFeature->getKind());
346 //setActionEnabled(aFeatureId, true);
347 setNestedCommandsEnabled(true, aFeatureId);
349 setNestedStackEnabled(myOperationMgr->previousOperation(theOperation));
352 QStringList XGUI_ActionsMgr::allNestedCommands(ModuleBase_Operation* theOperation)
354 QStringList aFeatures;
355 ModuleBase_OperationFeature* anOperation =
356 dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
357 if(!anOperation || !anOperation->feature())
359 FeaturePtr aFeature = anOperation->feature();
360 QString aFeatureId = QString::fromStdString(aFeature->getKind());
362 aFeatures << myNestedActions[aFeatureId];
363 aFeatures << allNestedCommands(myOperationMgr->previousOperation(theOperation));
367 void XGUI_ActionsMgr::setActionChecked(const QString& theId, const bool theChecked)
369 if (myActions.contains(theId)) {
370 QAction* anAction = myActions[theId];
371 if (anAction->isCheckable()) {
372 anAction->setChecked(theChecked);
377 void XGUI_ActionsMgr::setActionEnabled(const QString& theId, const bool theEnabled)
379 if (myActions.contains(theId)) {
380 QAction* aAction = myActions[theId];
381 // Initially all actions are enabled
382 // If it was disabled for any reason then we can not enable it
383 if (aAction->isEnabled())
384 aAction->setEnabled(theEnabled);
389 * Disables all actions which have the Document Kind different to
390 * the current document's kind
392 void XGUI_ActionsMgr::updateByDocumentKind()
394 std::string aStdDocKind = ModelAPI_Session::get()->activeDocument()->kind();
395 QString aDocKind = QString::fromStdString(aStdDocKind);
397 XGUI_Workshop* aWorkshop = static_cast<XGUI_Workshop*>(parent());
399 foreach(QAction* eachAction, myActions.values()) {
402 QString aId = eachAction->data().toString();
403 if (!aId.isEmpty()) {
404 aCmdDocKind = QString::fromStdString(
405 aWorkshop->salomeConnector()->featureInfo(aId)->documentKind());
408 AppElements_Command* aCmd = dynamic_cast<AppElements_Command*>(eachAction);
409 aCmdDocKind = QString::fromStdString(aCmd->featureMessage()->documentKind());
411 if(!aCmdDocKind.isEmpty() && aCmdDocKind != aDocKind) {
412 eachAction->setEnabled(false);
417 void XGUI_ActionsMgr::updateByPlugins(FeaturePtr anActiveFeature)
419 static Events_ID aStateRequestEventId = Events_Loop::loop()->eventByName(
420 EVENT_FEATURE_STATE_REQUEST);
421 std::shared_ptr<ModelAPI_FeatureStateMessage> aMsg(
422 new ModelAPI_FeatureStateMessage(aStateRequestEventId, this));
423 aMsg->setFeature(anActiveFeature);
424 Events_Loop::loop()->send(aMsg, false);