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