Salome HOME
Merge remote-tracking branch 'remotes/origin/Filters_Development_2'
[modules/shaper.git] / src / ModuleBase / ModuleBase_IModule.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 #include "ModelAPI_IReentrant.h"
21 #include "ModelAPI_EventReentrantMessage.h"
22
23 #include "ModuleBase_IModule.h"
24 #include "ModuleBase_IViewer.h"
25 #include "ModuleBase_ViewerPrs.h"
26 #include "ModuleBase_Operation.h"
27 #include "ModuleBase_IPropertyPanel.h"
28 #include "ModuleBase_ISelection.h"
29 #include "ModuleBase_OperationDescription.h"
30 #include "ModuleBase_OperationFeature.h"
31 #include "ModuleBase_ModelWidget.h"
32 #include "ModuleBase_WidgetFactory.h"
33 #include "ModuleBase_PageWidget.h"
34 #include "ModuleBase_Dialog.h"
35 #include "ModuleBase_IErrorMgr.h"
36
37 #include <Events_Loop.h>
38 #include <Events_Message.h>
39
40 #include <ModelAPI_Events.h>
41 #include <ModelAPI_CompositeFeature.h>
42 #include <ModelAPI_Session.h>
43 #include "ModelAPI_Tools.h"
44
45 #include <Config_PointerMessage.h>
46 #include <Config_WidgetReader.h>
47 #include <Config_ModuleReader.h>
48
49 #include <QAction>
50 #include <QMainWindow>
51 #include <QDialog>
52 #include <QLayout>
53 #include <QDialogButtonBox>
54 #include <QPushButton>
55
56 ModuleBase_IModule::ModuleBase_IModule(ModuleBase_IWorkshop* theParent)
57   : QObject(theParent), myWorkshop(theParent)
58 {
59   connect(myWorkshop, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged()));
60
61
62   //connect(myWorkshop->viewer(), SIGNAL(mousePress(QMouseEvent*)), this,
63   //        SLOT(onMousePressed(QMouseEvent*)));
64   //connect(myWorkshop->viewer(), SIGNAL(mouseRelease(QMouseEvent*)), this,
65   //        SLOT(onMouseReleased(QMouseEvent*)));
66   //connect(myWorkshop->viewer(), SIGNAL(mouseMove(QMouseEvent*)), this,
67   //        SLOT(onMouseMoved(QMouseEvent*)));
68   //connect(myWorkshop->viewer(), SIGNAL(keyRelease(QKeyEvent*)), this,
69   //        SLOT(onKeyRelease(QKeyEvent*)));
70   //connect(myWorkshop->viewer(), SIGNAL(mouseDoubleClick(QMouseEvent*)), this,
71   //        SLOT(onMouseDoubleClick(QMouseEvent*)));
72 }
73
74 void ModuleBase_IModule::launchModal(const QString& theCmdId)
75 {
76   bool isCommitted;
77   if (!myWorkshop->canStartOperation(theCmdId, isCommitted))
78     return;
79
80   std::string aXmlCfg, aDescription;
81   getXMLRepresentation(theCmdId.toStdString(), aXmlCfg, aDescription);
82
83   SessionPtr aMgr = ModelAPI_Session::get();
84   aMgr->startOperation(theCmdId.toStdString());
85
86   ModuleBase_Dialog aDlg(myWorkshop, theCmdId, aXmlCfg);
87   if (aDlg.exec() == QDialog::Accepted)
88     aMgr->finishOperation();
89   else
90     aMgr->abortOperation();
91   myWorkshop->updateCommandStatus();
92 }
93
94
95 void ModuleBase_IModule::launchOperation(const QString& theCmdId,
96                                          const bool& isStartAfterCommitOnly)
97 {
98   /// selection should be obtained from workshop before ask if the operation can be started as
99   /// the canStartOperation method performs commit/abort of previous operation.
100   /// Sometimes commit/abort may cause selection clear(Sketch operation) as a result
101   /// it will be lost and is not used for preselection.
102   ModuleBase_ISelection* aSelection = myWorkshop->selection();
103   QList<ModuleBase_ViewerPrsPtr> aPreSelected =
104     aSelection->getSelected(ModuleBase_ISelection::AllControls);
105
106   ModuleBase_OperationFeature* aCurOperation = dynamic_cast<ModuleBase_OperationFeature*>
107                                                          (myWorkshop->currentOperation());
108   QString aCurOperationKind = aCurOperation ? aCurOperation->getDescription()->operationId() : "";
109
110   bool isCommitted;
111   if (!myWorkshop->canStartOperation(theCmdId, isCommitted))
112     return;
113
114   /// reentrant operation(Sketch Line) should not be started if operation is aborted
115   if (isStartAfterCommitOnly && !isCommitted)
116     return;
117
118   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
119                                              (createOperation(theCmdId.toStdString()));
120   if (aFOperation) {
121     std::shared_ptr<Events_Message> aMessage = reentrantMessage();
122     if (aMessage.get()) {
123       setReentrantPreSelection(aMessage);
124     }
125     else if (canUsePreselection(aCurOperationKind, theCmdId)) {
126       // restore of previous opeation is absent or new launched operation has the same kind
127       aFOperation->initSelection(aPreSelected);
128     }
129     workshop()->processLaunchOperation(aFOperation);
130
131     if (aFOperation) {
132       FeaturePtr aFeature = aFOperation->feature();
133       ModelReentrantPtr aReentrantFeature =
134                                       std::dynamic_pointer_cast<ModelAPI_IReentrant>(aFeature);
135       if (aReentrantFeature.get()) {
136         if (aMessage.get()) {
137           ModuleBase_IPropertyPanel* aPanel = workshop()->propertyPanel();
138           std::string aPrevAttribute = aReentrantFeature->processEvent(aMessage);
139           if (!aPrevAttribute.empty()) {
140             workshop()->errorMgr()->updateActions(aFeature);
141             ModuleBase_ModelWidget* aPrevWidget = aPanel->modelWidget(aPrevAttribute);
142             aPanel->activateNextWidget(aPrevWidget);
143           }
144         }
145       }
146     }
147   }
148 }
149
150 Handle(AIS_InteractiveObject) ModuleBase_IModule::createPresentation(const ObjectPtr& theResult)
151 {
152   return Handle(AIS_InteractiveObject)();
153 }
154
155 bool ModuleBase_IModule::canBeShaded(Handle(AIS_InteractiveObject) theAIS) const
156 {
157   return true;
158 }
159
160 QString ModuleBase_IModule::getFeatureError(const FeaturePtr& theFeature)
161 {
162   // Error already translated.
163   std::string aMsg = ModelAPI_Tools::getFeatureError(theFeature);
164   return QString::fromUtf8(aMsg.c_str());
165 }
166
167 void ModuleBase_IModule::grantedOperationIds(ModuleBase_Operation* theOperation,
168                                              QStringList& theIds) const
169 {
170 }
171
172 ModuleBase_Operation* ModuleBase_IModule::getNewOperation(const std::string& theFeatureId)
173 {
174   return new ModuleBase_OperationFeature(theFeatureId.c_str(), this);
175 }
176
177 bool ModuleBase_IModule::customizeObject(ObjectPtr theObject,
178                               const ModuleBase_IModule::ModuleBase_CustomizeFlag& theFlag,
179                               const bool theUpdateViewer)
180 {
181   return false;
182 }
183
184 ModuleBase_Operation* ModuleBase_IModule::createOperation(const std::string& theFeatureId)
185 {
186   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
187                                                           (getNewOperation(theFeatureId));
188   // If the operation is launched as sub-operation of another then we have to initialize
189   // parent feature
190   ModuleBase_OperationFeature* aCurOperation = dynamic_cast<ModuleBase_OperationFeature*>
191                                                          (myWorkshop->currentOperation());
192   if (aCurOperation) {
193     FeaturePtr aFeature = aCurOperation->feature();
194     CompositeFeaturePtr aCompFeature =
195         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
196     if (aCompFeature) {
197       aFOperation->setParentFeature(aCompFeature);
198     }
199   }
200
201   std::string aXmlCfg, aDescription;
202   getXMLRepresentation(theFeatureId, aXmlCfg, aDescription);
203   aFOperation->getDescription()->setDescription(QString::fromStdString(aDescription));
204   aFOperation->getDescription()->setXmlRepresentation(QString::fromStdString(aXmlCfg));
205
206   return aFOperation;
207 }
208
209 void ModuleBase_IModule::createFeatures()
210 {
211   registerValidators();
212   registerProperties();
213
214   Config_ModuleReader aXMLReader = Config_ModuleReader();
215   aXMLReader.readAll();
216   myFeaturesInFiles = aXMLReader.featuresInFiles();
217 }
218
219
220 void ModuleBase_IModule::actionCreated(QAction* theFeature)
221 {
222   connect(theFeature, SIGNAL(triggered(bool)), this, SLOT(onFeatureTriggered()));
223 }
224
225 bool ModuleBase_IModule::canEraseObject(const ObjectPtr& theObject) const
226 {
227   return true;
228 }
229
230 bool ModuleBase_IModule::canDisplayObject(const ObjectPtr& theObject) const
231 {
232   return true;
233 }
234
235 bool ModuleBase_IModule::canUsePreselection(const QString& thePreviousOperationKind,
236                                             const QString& theStartedOperationKind)
237 {
238   // no previous operation
239   if (thePreviousOperationKind.isEmpty())
240     return true;
241   // edit operation
242   if (thePreviousOperationKind.endsWith(ModuleBase_OperationFeature::EditSuffix()))
243     return true;
244
245   // reentrant operation
246   if (thePreviousOperationKind == theStartedOperationKind)
247     return true;
248
249   return false;
250 }
251
252 bool ModuleBase_IModule::canUndo() const
253 {
254   SessionPtr aMgr = ModelAPI_Session::get();
255   return aMgr->hasModuleDocument() && aMgr->canUndo() && !aMgr->isOperation();
256 }
257
258 bool ModuleBase_IModule::canRedo() const
259 {
260   SessionPtr aMgr = ModelAPI_Session::get();
261   return aMgr->hasModuleDocument() && aMgr->canRedo() && !aMgr->isOperation();
262 }
263
264 void ModuleBase_IModule::onFeatureTriggered()
265 {
266   QAction* aCmd = dynamic_cast<QAction*>(sender());
267   //Do nothing on uncheck
268   if (aCmd->isCheckable() && !aCmd->isChecked()) {
269     ModuleBase_Operation* anOperation = myWorkshop->findStartedOperation(aCmd->data().toString());
270     if (myWorkshop->canStopOperation(anOperation)) {
271       bool isCommitted;
272       myWorkshop->stopOperation(anOperation, isCommitted);
273     }
274     else {
275       aCmd->setChecked(true);
276     }
277   }
278   else {
279     QString aCmdId = aCmd->data().toString();
280     std::shared_ptr<Config_FeatureMessage> aInfo = myWorkshop->featureInfo(aCmdId);
281     if (aInfo.get() && aInfo->isModal()) {
282       launchModal(aCmdId);
283     } else {
284       launchOperation(aCmdId, false);
285     }
286   }
287 }
288
289 void ModuleBase_IModule::editFeature(FeaturePtr theFeature)
290 {
291   std::string aFeatureId = theFeature->getKind();
292   bool isCommitted;
293   if (!myWorkshop->canStartOperation(aFeatureId.c_str(), isCommitted))
294     return;
295
296   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
297                                                          (createOperation(aFeatureId));
298   if (aFOperation) {
299     aFOperation->setFeature(theFeature);
300     workshop()->processLaunchOperation(aFOperation);
301   }
302 }
303
304 bool ModuleBase_IModule::canActivateSelection(const ObjectPtr& theObject) const
305 {
306   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
307                                                      (myWorkshop->currentOperation());
308   return !aFOperation || !aFOperation->hasObject(theObject);
309 }
310
311 void ModuleBase_IModule::operationResumed(ModuleBase_Operation* theOperation)
312 {
313   emit resumed(theOperation);
314 }
315
316 void ModuleBase_IModule::getXMLRepresentation(const std::string& theFeatureId,
317                                               std::string& theXmlCfg, std::string& theDescription)
318 {
319   std::string aPluginFileName = myFeaturesInFiles[theFeatureId];
320   Config_WidgetReader aWdgReader = Config_WidgetReader(aPluginFileName);
321   aWdgReader.readAll();
322
323   theXmlCfg = aWdgReader.featureWidgetCfg(theFeatureId);
324   theDescription = aWdgReader.featureDescription(theFeatureId);
325 }