Salome HOME
Issue #1343 Improvement of Extrusion and Revolution operations: extrusion by preselection
[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
206       std::list<AttributePtr> aSelListAttributes = aParentFeature->data()->attributes(
207                                                         ModelAPI_AttributeSelectionList::typeId());
208       if (aSelListAttributes.size() == 1) {
209         AttributePtr aFirstAttribute = aSelListAttributes.front();
210
211         SessionPtr aMgr = ModelAPI_Session::get();
212         ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
213         std::string aValidatorID, anError;
214         bool isValidPComposite = aFactory->validate(aFirstAttribute, aValidatorID, anError);
215         if (!isValidPComposite) {
216           int anAnswer = QMessageBox::question(
217               aWorkshop->desktop(), tr("Apply current feature"),
218                             tr("The current feature can not be used as an argument of the parent feature.\n\
219                                After apply it will be deleted. Would you like to continue?"),
220                             QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel);
221           if (anAnswer == QMessageBox::Ok)
222             aCanCommit = true;
223           else
224             aCanCommit = false;
225         }
226       }
227       if (!aIsOp) {
228         if (aCanCommit)
229           aMgr->finishOperation();
230         else
231           aMgr->abortOperation();
232       }
233     }
234   }
235   return aCanCommit;
236 }
237
238 bool PartSet_WidgetSketchCreator::isSelectionMode() const
239 {
240   AttributeSelectionListPtr anAttrList = myFeature->data()->selectionList(myAttributeListID);
241   bool aHasValueInList = anAttrList.get() && anAttrList->size() > 0;
242
243   return !aHasValueInList;
244 }
245
246 bool PartSet_WidgetSketchCreator::setSelection(QList<ModuleBase_ViewerPrs>& theValues,
247                                                const bool theToValidate)
248 {
249   bool aDone = false;
250   if (!startSketchOperation(theValues)) {
251     QList<ModuleBase_ViewerPrs>::const_iterator anIt = theValues.begin(), aLast = theValues.end();
252     bool aProcessed = false;
253     for (; anIt != aLast; anIt++) {
254       ModuleBase_ViewerPrs aValue = *anIt;
255       if (!theToValidate || isValidInFilters(aValue))
256         aProcessed = setBaseAttributeSelection(aValue) || aProcessed;
257     }
258     aDone = aProcessed;
259     if (aProcessed) {
260       emit valuesChanged();
261       updateObject(myFeature);
262       setVisibleSelectionControl(false);
263       // manually deactivation because the widget was not activated as has no focus acceptin controls
264       deactivate();
265       emit focusOutWidget(this);
266     }
267   }
268   return aDone;
269 }
270
271 //********************************************************************
272 void PartSet_WidgetSketchCreator::updateOnSelectionChanged(const bool theDone)
273 {
274 }
275
276 bool PartSet_WidgetSketchCreator::startSketchOperation(const QList<ModuleBase_ViewerPrs>& theValues)
277 {
278   bool aSketchStarted = false;
279
280   if (theValues.size() != 1)
281     return aSketchStarted;
282
283   ModuleBase_ViewerPrs aValue = theValues.front();
284   if (!PartSet_WidgetSketchLabel::canFillSketch(aValue))
285     return aSketchStarted;
286
287   aSketchStarted = true;
288
289   // manually deactivation because the widget was not activated as has no focus acceptin controls
290   deactivate();
291   bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
292   myPreviewPlanes->erasePreviewPlanes(myWorkshop);
293
294   // Launch Sketch operation
295   CompositeFeaturePtr aCompFeature = 
296     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
297
298   /// add sketch feature without current feature change.
299   /// it is important to do not change the current feature in order to
300   /// after sketch edition, the extrusion cut feature becomes current
301   SessionPtr aMgr = ModelAPI_Session::get();
302   DocumentPtr aDoc = aMgr->activeDocument();
303   FeaturePtr aPreviousCurrentFeature = aDoc->currentFeature(false);
304   FeaturePtr aSketch = aCompFeature->addFeature("Sketch");
305
306   PartSet_WidgetSketchLabel::fillSketchPlaneBySelection(aSketch, aValue);
307
308   aDoc->setCurrentFeature(aPreviousCurrentFeature, false);
309
310   // start edit operation for the sketch
311   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
312                                                             (myModule->createOperation("Sketch"));
313   if (aFOperation)
314     aFOperation->setFeature(aSketch);
315   myModule->sendOperation(aFOperation);
316
317   return aSketchStarted;
318 }
319
320 bool PartSet_WidgetSketchCreator::focusTo()
321 {
322   if (isSelectionMode()) {
323     activateSelectionControl();
324     return true;
325   }
326   else {
327     //setVisibleSelectionControl(false);
328
329     connect(myModule, SIGNAL(resumed(ModuleBase_Operation*)), SLOT(onResumed(ModuleBase_Operation*)));
330     SessionPtr aMgr = ModelAPI_Session::get();
331     // Open transaction that is general for the previous nested one: it will be closed on nested commit
332     bool aIsOp = aMgr->isOperation();
333     if (!aIsOp) {
334       const static std::string aNestedOpID("Parameters modification");
335       aMgr->startOperation(aNestedOpID, true);
336     }
337     restoreValue();
338   }
339   return false;
340 }
341
342 void PartSet_WidgetSketchCreator::deactivate()
343 {
344   ModuleBase_WidgetSelector::deactivate();
345
346   bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
347   myPreviewPlanes->erasePreviewPlanes(myWorkshop);
348   if (aHidePreview)
349     XGUI_Tools::workshop(myWorkshop)->viewer()->update();
350
351 }
352
353 void PartSet_WidgetSketchCreator::onResumed(ModuleBase_Operation* theOp)
354 {
355   XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
356
357   CompositeFeaturePtr aCompFeature = 
358     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
359   //CompositeFeaturePtr aSketchFeature = 
360   //  std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
361   if (aCompFeature->numberOfSubs() == 0) {
362     // do nothing, selection control should be hidden
363     setVisibleSelectionControl(false);
364   } else {
365     // check if the created sketch is invalid. Validate attribute selection list
366     // Shetch should be deleted if the attribute is invalid.
367     AttributeSelectionListPtr anAttrList = myFeature->data()->selectionList(myAttributeListID);
368     
369     SessionPtr aMgr = ModelAPI_Session::get();
370     ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
371     std::string aValidatorID, anError;
372     bool isValidPComposite = aFactory->validate(anAttrList, aValidatorID, anError);
373     /// if the sketch is not appropriate fro extrusion, it should be deleted and
374     /// the selection control should be activated again
375     if (!isValidPComposite) {
376       CompositeFeaturePtr aSketchFeature = 
377                std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
378
379       QObjectPtrList anObjects;
380       anObjects.append(aSketchFeature);
381       std::set<FeaturePtr> anIgnoredFeatures;
382       aWorkshop->deleteFeatures(anObjects, anIgnoredFeatures);
383
384       // do nothing, selection control should be shown
385       activateSelectionControl();
386     }
387     else {
388       setVisibleSelectionControl(false);
389       // Update value in attribute selection list
390       XGUI_PropertyPanel* aPanel = aWorkshop->propertyPanel();
391       const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
392       foreach(ModuleBase_ModelWidget* aWidget, aWidgets) {
393         if (aWidget->attributeID() == myAttributeListID)
394           aWidget->restoreValue();
395       }
396
397       // Hide sketcher result
398       CompositeFeaturePtr aSketchFeature = 
399         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
400       std::list<ResultPtr> aResults = aSketchFeature->results();
401       std::list<ResultPtr>::const_iterator aIt;
402       for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
403         (*aIt)->setDisplayed(false);
404       }
405       aSketchFeature->setDisplayed(false);
406       static Events_Loop* aLoop = Events_Loop::loop();
407       aLoop->flush(aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY));
408
409       // Add Selected body were created the sketcher to list of selected objects
410       std::string anObjectsAttribute = FeaturesPlugin_CompositeBoolean::BOOLEAN_OBJECTS_ID();
411       AttributeSelectionListPtr aSelList = aCompFeature->data()->selectionList(anObjectsAttribute);
412       if (aSelList.get()) {
413         DataPtr aData = aSketchFeature->data();
414         AttributeSelectionPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>
415                                       (aData->attribute(SketchPlugin_SketchEntity::EXTERNAL_ID()));
416         ResultPtr aRes = aSelAttr.get() ? aSelAttr->context() : ResultPtr();
417         if (aRes.get()) {
418           SessionPtr aMgr = ModelAPI_Session::get();
419           ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
420           AttributePtr anAttribute = myFeature->attribute(anObjectsAttribute);
421           std::string aValidatorID, anError;
422           aSelList->append(aRes, GeomShapePtr());
423           if (aFactory->validate(anAttribute, aValidatorID, anError))
424             updateObject(aCompFeature);
425           else
426             aSelList->clear();
427         }
428       }
429     }
430   }
431 }
432
433 bool PartSet_WidgetSketchCreator::setBaseAttributeSelection(const ModuleBase_ViewerPrs& theValue)
434 {
435   bool isDone = false;
436   ObjectPtr anObject;
437   GeomShapePtr aShape;
438   getGeomSelection(theValue, anObject, aShape);
439
440   std::string anAttributeId = myAttributeListID;
441   DataPtr aData = myFeature->data();
442   ModuleBase_Tools::setObject(aData->attribute(anAttributeId), anObject, aShape,
443                               myWorkshop, false);
444   return true;
445 }