]> SALOME platform Git repositories - modules/shaper.git/blob - src/PartSet/PartSet_WidgetSketchCreator.cpp
Salome HOME
Issue #1343. Improvement of Extrusion and Revolution operations: filling extrusion...
[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 #include <ModelAPI_ResultConstruction.h>
32
33 #include <SketchPlugin_SketchEntity.h>
34 #include <FeaturesPlugin_CompositeBoolean.h>
35
36 #include <ModuleBase_Tools.h>
37 #include <ModuleBase_Operation.h>
38 #include <ModuleBase_IPropertyPanel.h>
39 #include <ModuleBase_OperationFeature.h>
40 #include <Config_WidgetAPI.h>
41
42 #include <Events_Loop.h>
43
44 #include <QLabel>
45 #include <QLineEdit>
46 //#include <QFormLayout>
47 #include <QVBoxLayout>
48 #include <QMessageBox>
49 #include <QMainWindow>
50
51 //#define DEBUG_UNDO_INVALID_SKETCH
52
53 PartSet_WidgetSketchCreator::PartSet_WidgetSketchCreator(QWidget* theParent, 
54                                                          PartSet_Module* theModule,
55                                                          const Config_WidgetAPI* theData)
56 : ModuleBase_WidgetSelector(theParent, theModule->workshop(), theData),
57   myModule(theModule), myIsCustomAttribute(false)
58 {
59   myAttributeListID = theData->getProperty("attribute_list_id");
60
61   //QFormLayout* aLayout = new QFormLayout(this);
62   QVBoxLayout* aLayout = new QVBoxLayout(this);
63   ModuleBase_Tools::zeroMargins(aLayout);
64
65   ModuleBase_Tools::adjustMargins(aLayout);
66
67   QString aLabelText = QString::fromStdString(theData->widgetLabel());
68   QString aLabelIcon = QString::fromStdString(theData->widgetIcon());
69
70   myLabel = new QLabel(aLabelText, this);
71   myLabel->setWordWrap(true);
72   aLayout->addWidget(myLabel);
73   aLayout->addStretch(1);
74   /*if (!aLabelIcon.isEmpty())
75     myLabel->setPixmap(QPixmap(aLabelIcon));
76
77
78   QString aToolTip = QString::fromStdString(theData->widgetTooltip());
79   myTextLine = new QLineEdit(this);
80   myTextLine->setReadOnly(true);
81   myTextLine->setToolTip(aToolTip);
82   myTextLine->installEventFilter(this);
83
84   myLabel->setToolTip(aToolTip);
85
86   aLayout->addRow(myLabel, myTextLine);*/
87
88   std::string aTypes = theData->getProperty("shape_types");
89   myShapeTypes = QString(aTypes.c_str()).split(' ', QString::SkipEmptyParts);
90
91   myPreviewPlanes = new PartSet_PreviewPlanes();
92 }
93
94 PartSet_WidgetSketchCreator::~PartSet_WidgetSketchCreator()
95 {
96 }
97
98 QList<QWidget*> PartSet_WidgetSketchCreator::getControls() const
99 {
100   QList<QWidget*> aControls;
101   aControls.append(myLabel);
102   return aControls;
103 }
104
105 bool PartSet_WidgetSketchCreator::restoreValueCustom()
106 {
107   /*CompositeFeaturePtr aCompFeature = 
108     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
109   if (aCompFeature->numberOfSubs() > 0) {
110     FeaturePtr aSubFeature = aCompFeature->subFeature(0);
111     myTextLine->setText(QString::fromStdString(aSubFeature->data()->name()));
112   }*/
113   return true;
114 }
115
116 bool PartSet_WidgetSketchCreator::storeValueCustom() const
117 {
118   return true;
119 }
120
121 AttributePtr PartSet_WidgetSketchCreator::attribute() const
122 {
123   AttributePtr anAttribute;
124   if (myIsCustomAttribute)
125     anAttribute = myFeature->attribute(myAttributeListID);
126   else
127     anAttribute = ModuleBase_WidgetSelector::attribute();
128
129   return anAttribute;
130 }
131
132 //********************************************************************
133 void PartSet_WidgetSketchCreator::openExtrusionTransaction()
134 {
135   SessionPtr aMgr = ModelAPI_Session::get();
136   bool aIsOp = aMgr->isOperation();
137   if (!aIsOp) {
138     const static std::string aNestedOpID("Parameters modification");
139     aMgr->startOperation(aNestedOpID, true);
140   }
141 }
142
143 //********************************************************************
144 bool PartSet_WidgetSketchCreator::isValidSelection(const ModuleBase_ViewerPrs& theValue)
145 {
146   bool aValid = false;
147   if (myIsCustomAttribute) {
148     // check only suiting of the value to custom attribute (myAttributeListID)
149     // do not cash of validation to avoid using states, stored for XML attribute
150     // there is an alternative is to call clearValidatedCash() in setSelection()
151     aValid = isValidSelectionForAttribute(theValue, attribute());
152   }
153   else { /// if the validated attribute is already custom
154     if (getValidState(theValue, aValid)) {
155       return aValid;
156     }
157     aValid = isValidSelectionCustom(theValue);
158     if (!aValid)
159       // check selection to create new sketh (XML current attribute)
160       aValid = isValidSelectionForAttribute(theValue, attribute());
161     if (!aValid) {
162       // check selection to fill list attribute (myAttributeListID)
163       bool isCustomAttribute = myIsCustomAttribute;
164       myIsCustomAttribute = true;
165       aValid = isValidSelectionForAttribute(theValue, attribute());
166       myIsCustomAttribute = isCustomAttribute;
167     }
168   }
169   storeValidState(theValue, aValid);
170   return aValid;
171 }
172
173 //********************************************************************
174 bool PartSet_WidgetSketchCreator::isValidSelectionCustom(const ModuleBase_ViewerPrs& theValue)
175 {
176   return PartSet_WidgetSketchLabel::canFillSketch(theValue);
177 }
178
179 void PartSet_WidgetSketchCreator::activateSelectionControl()
180 {
181   setVisibleSelectionControl(true);
182
183   // we need to call activate here as the widget has no focus accepted controls
184   // if these controls are added here, activate will happens automatically after focusIn()
185   XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
186   XGUI_PropertyPanel* aPanel = aWorkshop->propertyPanel();
187   aPanel->activateWidget(this, false);
188 }
189
190 void PartSet_WidgetSketchCreator::setVisibleSelectionControl(const bool theSelectionControl)
191 {
192   // hide current widget, activate the next widget
193   XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
194   XGUI_PropertyPanel* aPanel = aWorkshop->propertyPanel();
195   const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
196   foreach(ModuleBase_ModelWidget* aWidget, aWidgets) {
197     if (theSelectionControl) { // hide other controls
198       if (aWidget != this)
199         aWidget->setVisible(false);
200     }
201     else { // hide current control
202       if (aWidget == this)
203         aWidget->setVisible(false);
204       else
205         aWidget->setVisible(true);
206     }
207   }
208
209   if (theSelectionControl) {
210     bool aBodyIsVisualized = myPreviewPlanes->hasVisualizedBodies(myWorkshop);
211     if (!aBodyIsVisualized) {
212       // We have to select a plane before any operation
213       myPreviewPlanes->showPreviewPlanes(myWorkshop);
214     }
215   } else {
216     bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
217     myPreviewPlanes->erasePreviewPlanes(myWorkshop);
218     if (aHidePreview)
219       aWorkshop->viewer()->update();
220   }
221 }
222
223 QIntList PartSet_WidgetSketchCreator::getShapeTypes() const
224 {
225   QIntList aShapeTypes;
226   foreach(QString aType, myShapeTypes) {
227     aShapeTypes.append(ModuleBase_Tools::shapeType(aType));
228   }
229   return aShapeTypes;
230 }
231
232 void PartSet_WidgetSketchCreator::setEditingMode(bool isEditing)
233 {
234   ModuleBase_ModelWidget::setEditingMode(isEditing);
235   if (isEditing)
236     setVisibleSelectionControl(false);
237 }
238
239 bool PartSet_WidgetSketchCreator::isSelectionMode() const
240 {
241   AttributeSelectionListPtr anAttrList = myFeature->data()->selectionList(myAttributeListID);
242   bool aHasValueInList = anAttrList.get() && anAttrList->size() > 0;
243
244   return !aHasValueInList;
245 }
246
247 bool PartSet_WidgetSketchCreator::setSelection(QList<ModuleBase_ViewerPrs>& theValues,
248                                                const bool theToValidate)
249 {
250   bool aDone = false;
251   if (!startSketchOperation(theValues)) {
252     myIsCustomAttribute = true;
253     QList<ModuleBase_ViewerPrs>::const_iterator anIt = theValues.begin(), aLast = theValues.end();
254     bool aProcessed = false;
255     for (; anIt != aLast; anIt++) {
256       ModuleBase_ViewerPrs aValue = *anIt;
257       if (!theToValidate || isValidInFilters(aValue))
258         aProcessed = setSelectionCustom(aValue) || aProcessed;
259     }
260     myIsCustomAttribute = false;
261     aDone = aProcessed;
262     if (aProcessed) {
263       emit valuesChanged();
264       updateObject(myFeature);
265       setVisibleSelectionControl(false);
266       // manually deactivation because the widget was not activated as has no focus acceptin controls
267       deactivate();
268       emit focusOutWidget(this);
269     }
270   }
271   return aDone;
272 }
273
274 //********************************************************************
275 void PartSet_WidgetSketchCreator::onSelectionChanged()
276 {
277   QList<ModuleBase_ViewerPrs> aSelected = getFilteredSelected();
278   bool isDone = setSelection(aSelected, true/*false*/);
279 }
280
281 //********************************************************************
282 void PartSet_WidgetSketchCreator::updateOnSelectionChanged(const bool theDone)
283 {
284 }
285
286 bool PartSet_WidgetSketchCreator::startSketchOperation(const QList<ModuleBase_ViewerPrs>& theValues)
287 {
288   bool aSketchStarted = false;
289
290   if (theValues.size() != 1)
291     return aSketchStarted;
292
293   ModuleBase_ViewerPrs aValue = theValues.front();
294   if (!PartSet_WidgetSketchLabel::canFillSketch(aValue))
295     return aSketchStarted;
296
297   aSketchStarted = true;
298
299   // manually deactivation because the widget was not activated as has no focus acceptin controls
300   deactivate();
301   bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
302   myPreviewPlanes->erasePreviewPlanes(myWorkshop);
303
304   // Launch Sketch operation
305   CompositeFeaturePtr aCompFeature = 
306     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
307
308   /// add sketch feature without current feature change.
309   /// it is important to do not change the current feature in order to
310   /// after sketch edition, the extrusion cut feature becomes current
311   SessionPtr aMgr = ModelAPI_Session::get();
312   DocumentPtr aDoc = aMgr->activeDocument();
313   FeaturePtr aPreviousCurrentFeature = aDoc->currentFeature(false);
314   FeaturePtr aSketch = aCompFeature->addFeature("Sketch");
315
316   PartSet_WidgetSketchLabel::fillSketchPlaneBySelection(aSketch, aValue);
317
318   aDoc->setCurrentFeature(aPreviousCurrentFeature, false);
319
320   // start edit operation for the sketch
321   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
322                                                             (myModule->createOperation("Sketch"));
323   if (aFOperation)
324     aFOperation->setFeature(aSketch);
325   myModule->sendOperation(aFOperation);
326
327   return aSketchStarted;
328 }
329
330 bool PartSet_WidgetSketchCreator::focusTo()
331 {
332   // this method is called only in creation mode. In Edition mode this widget is hidden
333   CompositeFeaturePtr aCompFeature = 
334       std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
335   if (isSelectionMode() && aCompFeature->numberOfSubs() == 0) {
336     activateSelectionControl();
337     openExtrusionTransaction();
338     return true;
339   }
340   else
341     connect(myModule, SIGNAL(resumed(ModuleBase_Operation*)), SLOT(onResumed(ModuleBase_Operation*)));
342   return false;
343 }
344
345 void PartSet_WidgetSketchCreator::deactivate()
346 {
347   ModuleBase_WidgetSelector::deactivate();
348
349   bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
350   myPreviewPlanes->erasePreviewPlanes(myWorkshop);
351   if (aHidePreview)
352     XGUI_Tools::workshop(myWorkshop)->viewer()->update();
353
354 }
355
356 void PartSet_WidgetSketchCreator::onResumed(ModuleBase_Operation* theOp)
357 {
358   SessionPtr aMgr = ModelAPI_Session::get();
359   bool aIsOp = aMgr->isOperation();
360   if (aIsOp) {
361     // in current implementation, all transactions are closed when resume happens
362     // so, this is a wrong case, which is not checked.
363     // To provide it, make correction in later rows about abort/undo transactions
364     return;
365   }
366   // Set visible only selection control
367   setVisibleSelectionControl(true);
368
369   // Validate the created sketch. If it is valid, it is set into the composite feature selection
370   // list, otherwise it is removed
371   CompositeFeaturePtr aCompFeature = 
372     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
373   AttributeSelectionListPtr anAttrList = myFeature->data()->selectionList(myAttributeListID);
374   if (aCompFeature->numberOfSubs() > 0) {
375     // set the sub feature to attribute selection list and check whether sketch is valid
376     SessionPtr aMgr = ModelAPI_Session::get();
377     const static std::string aNestedOpID("Set Sketch result into Selection list");
378     aMgr->startOperation(aNestedOpID, false); // false to not attach to Extrusion operation
379     setSketchObjectToList(aCompFeature, anAttrList);
380     aMgr->finishOperation();
381
382     if (!validateSelectionList()) {
383 #ifdef DEBUG_UNDO_INVALID_SKETCH
384       aMgr->undo(); // Extrusion modification parameters: setSketchObjectToList()
385       aMgr->undo(); /// Sketch creation
386 #else
387       aMgr->startOperation("Delete invalid Sketch feature", false);
388
389       // delete invalid sketch
390       CompositeFeaturePtr aSketchFeature = 
391               std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
392       QObjectPtrList anObjects;
393       anObjects.append(aSketchFeature);
394
395       XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
396       aWorkshop->deleteFeatures(anObjects, std::set<FeaturePtr>());
397
398       aMgr->finishOperation();
399 #endif
400     }
401   }
402   openExtrusionTransaction();
403
404   if (aCompFeature->numberOfSubs() > 0) {
405     // check if the created sketch is valid. If it is invalid, it will be deleted with warning else
406     /// the attribute selection list will be filled by result of this sketch.
407     setVisibleSelectionControl(false);
408
409     // Update value in attribute selection list
410     XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
411     XGUI_PropertyPanel* aPanel = aWorkshop->propertyPanel();
412     const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
413     foreach(ModuleBase_ModelWidget* aWidget, aWidgets) {
414       if (aWidget->attributeID() == myAttributeListID)
415         aWidget->restoreValue();
416     }
417
418     // Hide sketcher result
419     CompositeFeaturePtr aSketchFeature = 
420       std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
421     std::list<ResultPtr> aResults = aSketchFeature->results();
422     std::list<ResultPtr>::const_iterator aIt;
423     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
424       (*aIt)->setDisplayed(false);
425     }
426     aSketchFeature->setDisplayed(false);
427     static Events_Loop* aLoop = Events_Loop::loop();
428     aLoop->flush(aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY));
429
430     // Add Selected body were created the sketcher to list of selected objects
431     std::string anObjectsAttribute = FeaturesPlugin_CompositeBoolean::OBJECTS_ID();
432     AttributeSelectionListPtr aSelList = aCompFeature->data()->selectionList(anObjectsAttribute);
433     if (aSelList.get()) {
434       DataPtr aData = aSketchFeature->data();
435       AttributeSelectionPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>
436                                     (aData->attribute(SketchPlugin_SketchEntity::EXTERNAL_ID()));
437       ResultPtr aRes = aSelAttr.get() ? aSelAttr->context() : ResultPtr();
438       if (aRes.get()) {
439         SessionPtr aMgr = ModelAPI_Session::get();
440         ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
441         AttributePtr anAttribute = myFeature->attribute(anObjectsAttribute);
442         std::string aValidatorID, anError;
443         aSelList->append(aRes, GeomShapePtr());
444         if (aFactory->validate(anAttribute, aValidatorID, anError))
445           updateObject(aCompFeature);
446         else
447           aSelList->clear();
448       }
449     }
450   }
451   restoreValue();
452 }
453
454 bool PartSet_WidgetSketchCreator::validateSelectionList() const
455 {
456   AttributeSelectionListPtr anAttrList = myFeature->data()->selectionList(myAttributeListID);
457
458   SessionPtr aMgr = ModelAPI_Session::get();
459   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
460   std::string aValidatorID, anError;
461   bool isValidPComposite = aFactory->validate(anAttrList, aValidatorID, anError);
462   if (!isValidPComposite) {
463     XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
464     QMessageBox::question(aWorkshop->desktop(), tr("Apply current feature"),
465                   tr("Sketch is invalid and will be deleted.\nError: %1").arg(anError.c_str()),
466                   QMessageBox::Ok);
467   }
468   return isValidPComposite;
469 }
470
471 void PartSet_WidgetSketchCreator::setSketchObjectToList(const CompositeFeaturePtr& theCompositeFeature,
472                                                         const AttributePtr& theAttribute)
473 {
474   if (!theCompositeFeature.get() || theCompositeFeature->numberOfSubs() != 1)
475     return;
476
477   AttributeSelectionListPtr aBaseObjectsSelectionList =
478                      std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
479   if(!aBaseObjectsSelectionList.get() || aBaseObjectsSelectionList->isInitialized()) {
480     return;
481   }
482
483   FeaturePtr aSketchFeature = theCompositeFeature->subFeature(0);
484   if(!aSketchFeature.get() || aSketchFeature->results().empty()) {
485     return;
486   }
487
488   ResultPtr aSketchRes = aSketchFeature->results().front();
489   ResultConstructionPtr aConstruction = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aSketchRes);
490   if(!aConstruction.get()) {
491     return;
492   }
493
494   if(aBaseObjectsSelectionList->size() == 0) {
495     aBaseObjectsSelectionList->append(aSketchRes, GeomShapePtr());
496   }
497 }