]> SALOME platform Git repositories - modules/shaper.git/blob - src/PartSet/PartSet_WidgetSketchCreator.cpp
Salome HOME
Issue #1343 Improvement of Extrusion and Revolution operations: use transaction to...
[modules/shaper.git] / src / PartSet / PartSet_WidgetSketchCreator.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        PartSet_WidgetSketchCreator.cpp
4 // Created:     08 June 2015
5 // Author:      Vitaly SMETANNIKOV
6
7 #include "PartSet_WidgetSketchCreator.h"
8 #include "PartSet_Module.h"
9 #include "PartSet_WidgetSketchLabel.h"
10 #include "PartSet_PreviewPlanes.h"
11
12 #include <Config_Keywords.h>
13
14 #include <XGUI_ModuleConnector.h>
15 #include <XGUI_Workshop.h>
16 #include <XGUI_Displayer.h>
17 #include <XGUI_SelectionMgr.h>
18 #include <XGUI_OperationMgr.h>
19 #include <XGUI_PropertyPanel.h>
20 #include <XGUI_Tools.h>
21 #include <XGUI_ViewerProxy.h>
22
23 #include <GeomAPI_Face.h>
24
25 #include <ModelAPI_Session.h>
26 #include <ModelAPI_ResultBody.h>
27 #include <ModelAPI_AttributeSelection.h>
28 #include <ModelAPI_AttributeSelectionList.h>
29 #include <ModelAPI_Validator.h>
30 #include <ModelAPI_Events.h>
31
32 #include <SketchPlugin_SketchEntity.h>
33 #include <FeaturesPlugin_CompositeBoolean.h>
34
35 #include <ModuleBase_Tools.h>
36 #include <ModuleBase_Operation.h>
37 #include <ModuleBase_IPropertyPanel.h>
38 #include <ModuleBase_OperationFeature.h>
39 #include <Config_WidgetAPI.h>
40
41 #include <Events_Loop.h>
42
43 #include <QLabel>
44 #include <QLineEdit>
45 //#include <QFormLayout>
46 #include <QVBoxLayout>
47 #include <QMessageBox>
48 #include <QMainWindow>
49
50 PartSet_WidgetSketchCreator::PartSet_WidgetSketchCreator(QWidget* theParent, 
51                                                          PartSet_Module* theModule,
52                                                          const Config_WidgetAPI* theData)
53 : ModuleBase_WidgetSelector(theParent, theModule->workshop(), theData),
54   myModule(theModule)
55 {
56   myAttributeListID = theData->getProperty("attribute_list_id");
57
58   //QFormLayout* aLayout = new QFormLayout(this);
59   QVBoxLayout* aLayout = new QVBoxLayout(this);
60   ModuleBase_Tools::zeroMargins(aLayout);
61
62   ModuleBase_Tools::adjustMargins(aLayout);
63
64   QString aLabelText = QString::fromStdString(theData->widgetLabel());
65   QString aLabelIcon = QString::fromStdString(theData->widgetIcon());
66
67   myLabel = new QLabel(aLabelText, this);
68   myLabel->setWordWrap(true);
69   aLayout->addWidget(myLabel);
70   /*if (!aLabelIcon.isEmpty())
71     myLabel->setPixmap(QPixmap(aLabelIcon));
72
73
74   QString aToolTip = QString::fromStdString(theData->widgetTooltip());
75   myTextLine = new QLineEdit(this);
76   myTextLine->setReadOnly(true);
77   myTextLine->setToolTip(aToolTip);
78   myTextLine->installEventFilter(this);
79
80   myLabel->setToolTip(aToolTip);
81
82   aLayout->addRow(myLabel, myTextLine);*/
83
84   std::string aTypes = theData->getProperty("shape_types");
85   myShapeTypes = QString(aTypes.c_str()).split(' ', QString::SkipEmptyParts);
86
87   myPreviewPlanes = new PartSet_PreviewPlanes();
88 }
89
90 PartSet_WidgetSketchCreator::~PartSet_WidgetSketchCreator()
91 {
92 }
93
94 QList<QWidget*> PartSet_WidgetSketchCreator::getControls() const
95 {
96   QList<QWidget*> aControls;
97   aControls.append(myLabel);
98   return aControls;
99 }
100
101 bool PartSet_WidgetSketchCreator::restoreValueCustom()
102 {
103   /*CompositeFeaturePtr aCompFeature = 
104     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
105   if (aCompFeature->numberOfSubs() > 0) {
106     FeaturePtr aSubFeature = aCompFeature->subFeature(0);
107     myTextLine->setText(QString::fromStdString(aSubFeature->data()->name()));
108   }*/
109   return true;
110 }
111
112 bool PartSet_WidgetSketchCreator::storeValueCustom() const
113 {
114   return true;
115 }
116
117 void PartSet_WidgetSketchCreator::activateSelectionControl()
118 {
119   setVisibleSelectionControl(true);
120
121   // we need to call activate here as the widget has no focus accepted controls
122   // if these controls are added here, activate will happens automatically after focusIn()
123   XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
124   XGUI_PropertyPanel* aPanel = aWorkshop->propertyPanel();
125   aPanel->activateWidget(this, false);
126 }
127
128 void PartSet_WidgetSketchCreator::setVisibleSelectionControl(const bool theSelectionControl)
129 {
130   // hide current widget, activate the next widget
131   XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
132   XGUI_PropertyPanel* aPanel = aWorkshop->propertyPanel();
133   const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
134   foreach(ModuleBase_ModelWidget* aWidget, aWidgets) {
135     if (theSelectionControl) { // hide other controls
136       if (aWidget != this)
137         aWidget->setVisible(false);
138     }
139     else { // hide current control
140       if (aWidget == this)
141         aWidget->setVisible(false);
142       else
143         aWidget->setVisible(true);
144     }
145   }
146
147   if (theSelectionControl) {
148     bool aBodyIsVisualized = myPreviewPlanes->hasVisualizedBodies(myWorkshop);
149     if (!aBodyIsVisualized) {
150       // We have to select a plane before any operation
151       myPreviewPlanes->showPreviewPlanes(myWorkshop);
152     }
153   } else {
154     bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
155     myPreviewPlanes->erasePreviewPlanes(myWorkshop);
156     if (aHidePreview)
157       aWorkshop->viewer()->update();
158   }
159 }
160
161 QIntList PartSet_WidgetSketchCreator::getShapeTypes() const
162 {
163   QIntList aShapeTypes;
164   foreach(QString aType, myShapeTypes) {
165     aShapeTypes.append(ModuleBase_Tools::shapeType(aType));
166   }
167   return aShapeTypes;
168 }
169
170 void PartSet_WidgetSketchCreator::setEditingMode(bool isEditing)
171 {
172   ModuleBase_ModelWidget::setEditingMode(isEditing);
173   if (isEditing)
174     setVisibleSelectionControl(false);
175 }
176
177 bool PartSet_WidgetSketchCreator::canCommitCurrentSketch(ModuleBase_IWorkshop* theWorkshop)
178 {
179   bool aCanCommit = true;
180   ModuleBase_Operation* anOperation = theWorkshop->currentOperation();
181   XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(theWorkshop);
182   XGUI_OperationMgr* anOpMgr = aWorkshop->operationMgr();
183   // check if the operation is nested
184   if (anOperation && anOpMgr->operationsCount() > 1) {
185     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(anOperation);
186     FeaturePtr aCurrentFeature = aFOperation ? aFOperation->feature() : FeaturePtr();
187
188     ModuleBase_Operation* aPOperation =  anOpMgr->previousOperation(anOperation);
189     ModuleBase_OperationFeature* aFPOperation = dynamic_cast<ModuleBase_OperationFeature*>(aPOperation);
190     FeaturePtr aParentFeature = aFPOperation ? aFPOperation->feature() : FeaturePtr();
191
192     CompositeFeaturePtr aCompositeFeature = 
193                              std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCurrentFeature);
194     CompositeFeaturePtr aPCompositeFeature = 
195                              std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aParentFeature);
196     // check if both features are composite: extrusion and sketch
197     if (aCompositeFeature.get() && aPCompositeFeature.get()) {
198       // selection attribute list is currently filled in execute(), so we need to call it
199       // if there is no opened transaction, it should be started and finished
200       SessionPtr aMgr = ModelAPI_Session::get();
201       bool aIsOp = aMgr->isOperation();
202       if (!aIsOp)
203         aMgr->startOperation();
204       aPCompositeFeature->execute(); // to fill attribute selection list
205       if (!aIsOp)
206         aMgr->finishOperation();
207
208       std::list<AttributePtr> aSelListAttributes = aParentFeature->data()->attributes(
209                                                         ModelAPI_AttributeSelectionList::typeId());
210       if (aSelListAttributes.size() == 1) {
211         AttributePtr aFirstAttribute = aSelListAttributes.front();
212
213         SessionPtr aMgr = ModelAPI_Session::get();
214         ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
215         std::string aValidatorID, anError;
216         bool isValidPComposite = aFactory->validate(aFirstAttribute, aValidatorID, anError);
217         if (!isValidPComposite) {
218           int anAnswer = QMessageBox::question(
219               aWorkshop->desktop(), tr("Apply current feature"),
220                             tr("The current feature can not be used as an argument of the parent feature.\n\
221                                After apply it will be deleted. Would you like to continue?"),
222                             QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel);
223           if (anAnswer == QMessageBox::Ok)
224             aCanCommit = true;
225           else
226             aCanCommit = false;
227         }
228       }
229     }
230   }
231   return aCanCommit;
232 }
233
234 bool PartSet_WidgetSketchCreator::isSelectionMode() const
235 {
236   AttributeSelectionListPtr anAttrList = myFeature->data()->selectionList(myAttributeListID);
237   bool aHasValueInList = anAttrList.get() && anAttrList->size() > 0;
238
239   return !aHasValueInList;
240 }
241
242 void PartSet_WidgetSketchCreator::onSelectionChanged()
243 {
244   QList<ModuleBase_ViewerPrs> aSelected = getFilteredSelected();
245
246   if (!startSketchOperation(aSelected)) {
247     QList<ModuleBase_ViewerPrs>::const_iterator anIt = aSelected.begin(), aLast = aSelected.end();
248     bool aProcessed = false;
249     for (; anIt != aLast; anIt++) {
250       ModuleBase_ViewerPrs aValue = *anIt;
251       if (isValidInFilters(aValue))
252         aProcessed = setSelectionCustom(aValue) || aProcessed;
253     }
254     if (aProcessed) {
255       emit valuesChanged();
256       updateObject(myFeature);
257       setVisibleSelectionControl(false);
258       // manually deactivation because the widget was not activated as has no focus acceptin controls
259       deactivate();
260       emit focusOutWidget(this);
261     }
262   }
263 }
264
265 //********************************************************************
266 void PartSet_WidgetSketchCreator::setObject(ObjectPtr theSelectedObject,
267                                             GeomShapePtr theShape)
268 {
269   // do nothing because all processing is in onSelectionChanged()
270 }
271
272 bool PartSet_WidgetSketchCreator::startSketchOperation(const QList<ModuleBase_ViewerPrs>& theValues)
273 {
274   bool aSketchStarted = false;
275
276   if (theValues.size() != 1)
277     return aSketchStarted;
278
279   ModuleBase_ViewerPrs aValue = theValues.front();
280   if (!PartSet_WidgetSketchLabel::canFillSketch(aValue))
281     return aSketchStarted;
282
283   aSketchStarted = true;
284
285   // manually deactivation because the widget was not activated as has no focus acceptin controls
286   deactivate();
287   bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
288   myPreviewPlanes->erasePreviewPlanes(myWorkshop);
289
290   // Launch Sketch operation
291   CompositeFeaturePtr aCompFeature = 
292     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
293
294   /// add sketch feature without current feature change.
295   /// it is important to do not change the current feature in order to
296   /// after sketch edition, the extrusion cut feature becomes current
297   SessionPtr aMgr = ModelAPI_Session::get();
298   DocumentPtr aDoc = aMgr->activeDocument();
299   FeaturePtr aPreviousCurrentFeature = aDoc->currentFeature(false);
300   FeaturePtr aSketch = aCompFeature->addFeature("Sketch");
301
302   PartSet_WidgetSketchLabel::fillSketchPlaneBySelection(aSketch, aValue);
303
304   aDoc->setCurrentFeature(aPreviousCurrentFeature, false);
305
306   // start edit operation for the sketch
307   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
308                                                             (myModule->createOperation("Sketch"));
309   if (aFOperation)
310     aFOperation->setFeature(aSketch);
311   myModule->sendOperation(aFOperation);
312
313   return aSketchStarted;
314 }
315
316 bool PartSet_WidgetSketchCreator::focusTo()
317 {
318   if (isSelectionMode()) {
319     activateSelectionControl();
320     return true;
321   }
322   else {
323     //setVisibleSelectionControl(false);
324
325     connect(myModule, SIGNAL(resumed(ModuleBase_Operation*)), SLOT(onResumed(ModuleBase_Operation*)));
326     SessionPtr aMgr = ModelAPI_Session::get();
327     // Open transaction that is general for the previous nested one: it will be closed on nested commit
328     bool aIsOp = aMgr->isOperation();
329     if (!aIsOp) {
330       const static std::string aNestedOpID("Parameters modification");
331       aMgr->startOperation(aNestedOpID, true);
332     }
333     restoreValue();
334   }
335   return false;
336 }
337
338 void PartSet_WidgetSketchCreator::deactivate()
339 {
340   ModuleBase_WidgetSelector::deactivate();
341
342   bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
343   myPreviewPlanes->erasePreviewPlanes(myWorkshop);
344   if (aHidePreview)
345     XGUI_Tools::workshop(myWorkshop)->viewer()->update();
346
347 }
348
349 void PartSet_WidgetSketchCreator::onResumed(ModuleBase_Operation* theOp)
350 {
351   XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
352
353   CompositeFeaturePtr aCompFeature = 
354     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
355   //CompositeFeaturePtr aSketchFeature = 
356   //  std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
357   if (aCompFeature->numberOfSubs() == 0) {
358     // do nothing, selection control should be hidden
359     setVisibleSelectionControl(false);
360   } else {
361     // check if the created sketch is invalid. Validate attribute selection list
362     // Shetch should be deleted if the attribute is invalid.
363     AttributeSelectionListPtr anAttrList = myFeature->data()->selectionList(myAttributeListID);
364     
365     SessionPtr aMgr = ModelAPI_Session::get();
366     ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
367     std::string aValidatorID, anError;
368     bool isValidPComposite = aFactory->validate(anAttrList, aValidatorID, anError);
369     /// if the sketch is not appropriate fro extrusion, it should be deleted and
370     /// the selection control should be activated again
371     if (!isValidPComposite) {
372       CompositeFeaturePtr aSketchFeature = 
373                std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
374
375       QObjectPtrList anObjects;
376       anObjects.append(aSketchFeature);
377       std::set<FeaturePtr> anIgnoredFeatures;
378       aWorkshop->deleteFeatures(anObjects, anIgnoredFeatures);
379
380       // do nothing, selection control should be shown
381       activateSelectionControl();
382       return;
383     }
384     // do nothing, selection control should be hidden
385     setVisibleSelectionControl(false);
386     // Update value in attribute selection list
387     XGUI_PropertyPanel* aPanel = aWorkshop->propertyPanel();
388     const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
389     foreach(ModuleBase_ModelWidget* aWidget, aWidgets) {
390       if (aWidget->attributeID() == myAttributeListID)
391         aWidget->restoreValue();
392     }
393
394     // Hide sketcher result
395     CompositeFeaturePtr aSketchFeature = 
396       std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
397     std::list<ResultPtr> aResults = aSketchFeature->results();
398     std::list<ResultPtr>::const_iterator aIt;
399     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
400       (*aIt)->setDisplayed(false);
401     }
402     aSketchFeature->setDisplayed(false);
403
404     // restore value in the selection control
405
406
407     // Add Selected body were created the sketcher to list of selected objects
408     std::string anObjectsAttribute = FeaturesPlugin_CompositeBoolean::BOOLEAN_OBJECTS_ID();
409     AttributeSelectionListPtr aSelList = aCompFeature->data()->selectionList(anObjectsAttribute);
410     if (aSelList.get()) {
411       DataPtr aData = aSketchFeature->data();
412       AttributeSelectionPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>
413                                     (aData->attribute(SketchPlugin_SketchEntity::EXTERNAL_ID()));
414       ResultPtr aRes = aSelAttr.get() ? aSelAttr->context() : ResultPtr();
415       if (aRes.get()) {
416         SessionPtr aMgr = ModelAPI_Session::get();
417         ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
418         AttributePtr anAttribute = myFeature->attribute(anObjectsAttribute);
419         std::string aValidatorID, anError;
420         aSelList->append(aRes, GeomShapePtr());
421         if (aFactory->validate(anAttribute, aValidatorID, anError))
422           updateObject(aCompFeature);
423         else
424           aSelList->clear();
425       }
426     }
427   }
428 }