]> SALOME platform Git repositories - modules/shaper.git/blob - src/PartSet/PartSet_WidgetSketchCreator.cpp
Salome HOME
Issue #1343. Improvement of Extrusion and Revolution operations: sketch creator setSe...
[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), myIsCustomAttribute(false)
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 AttributePtr PartSet_WidgetSketchCreator::attribute() const
118 {
119   AttributePtr anAttribute;
120   if (myIsCustomAttribute)
121     anAttribute = myFeature->attribute(myAttributeListID);
122   else
123     anAttribute = ModuleBase_WidgetSelector::attribute();
124
125   return anAttribute;
126 }
127
128 //********************************************************************
129 bool PartSet_WidgetSketchCreator::isValidSelection(const ModuleBase_ViewerPrs& theValue)
130 {
131   bool aValid = false;
132   if (getValidState(theValue, aValid)) {
133     return aValid;
134   }
135   // check selection to create new sketh (XML current attribute)
136   aValid = isValidSelectionForAttribute(theValue, attribute());
137   if (!aValid) {
138     // check selection to fill list attribute (myAttributeListID)
139     myIsCustomAttribute = true;
140     aValid = isValidSelectionForAttribute(theValue, attribute());
141     myIsCustomAttribute = false;
142   }
143   storeValidState(theValue, aValid);
144   return aValid;
145 }
146
147 void PartSet_WidgetSketchCreator::activateSelectionControl()
148 {
149   setVisibleSelectionControl(true);
150
151   // we need to call activate here as the widget has no focus accepted controls
152   // if these controls are added here, activate will happens automatically after focusIn()
153   XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
154   XGUI_PropertyPanel* aPanel = aWorkshop->propertyPanel();
155   aPanel->activateWidget(this, false);
156 }
157
158 void PartSet_WidgetSketchCreator::setVisibleSelectionControl(const bool theSelectionControl)
159 {
160   // hide current widget, activate the next widget
161   XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
162   XGUI_PropertyPanel* aPanel = aWorkshop->propertyPanel();
163   const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
164   foreach(ModuleBase_ModelWidget* aWidget, aWidgets) {
165     if (theSelectionControl) { // hide other controls
166       if (aWidget != this)
167         aWidget->setVisible(false);
168     }
169     else { // hide current control
170       if (aWidget == this)
171         aWidget->setVisible(false);
172       else
173         aWidget->setVisible(true);
174     }
175   }
176
177   if (theSelectionControl) {
178     bool aBodyIsVisualized = myPreviewPlanes->hasVisualizedBodies(myWorkshop);
179     if (!aBodyIsVisualized) {
180       // We have to select a plane before any operation
181       myPreviewPlanes->showPreviewPlanes(myWorkshop);
182     }
183   } else {
184     bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
185     myPreviewPlanes->erasePreviewPlanes(myWorkshop);
186     if (aHidePreview)
187       aWorkshop->viewer()->update();
188   }
189 }
190
191 QIntList PartSet_WidgetSketchCreator::getShapeTypes() const
192 {
193   QIntList aShapeTypes;
194   foreach(QString aType, myShapeTypes) {
195     aShapeTypes.append(ModuleBase_Tools::shapeType(aType));
196   }
197   return aShapeTypes;
198 }
199
200 void PartSet_WidgetSketchCreator::setEditingMode(bool isEditing)
201 {
202   ModuleBase_ModelWidget::setEditingMode(isEditing);
203   if (isEditing)
204     setVisibleSelectionControl(false);
205 }
206
207 bool PartSet_WidgetSketchCreator::canCommitCurrentSketch(ModuleBase_IWorkshop* theWorkshop)
208 {
209   bool aCanCommit = true;
210   ModuleBase_Operation* anOperation = theWorkshop->currentOperation();
211   XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(theWorkshop);
212   XGUI_OperationMgr* anOpMgr = aWorkshop->operationMgr();
213   // check if the operation is nested
214   if (anOperation && anOpMgr->operationsCount() > 1) {
215     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(anOperation);
216     FeaturePtr aCurrentFeature = aFOperation ? aFOperation->feature() : FeaturePtr();
217
218     ModuleBase_Operation* aPOperation =  anOpMgr->previousOperation(anOperation);
219     ModuleBase_OperationFeature* aFPOperation = dynamic_cast<ModuleBase_OperationFeature*>(aPOperation);
220     FeaturePtr aParentFeature = aFPOperation ? aFPOperation->feature() : FeaturePtr();
221
222     CompositeFeaturePtr aCompositeFeature = 
223                              std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCurrentFeature);
224     CompositeFeaturePtr aPCompositeFeature = 
225                              std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aParentFeature);
226     // check if both features are composite: extrusion and sketch
227     if (aCompositeFeature.get() && aPCompositeFeature.get()) {
228       // selection attribute list is currently filled in execute(), so we need to call it
229       // if there is no opened transaction, it should be started and finished
230       SessionPtr aMgr = ModelAPI_Session::get();
231       bool aIsOp = aMgr->isOperation();
232       if (!aIsOp)
233         aMgr->startOperation();
234       aPCompositeFeature->execute(); // to fill attribute selection list
235
236       std::list<AttributePtr> aSelListAttributes = aParentFeature->data()->attributes(
237                                                         ModelAPI_AttributeSelectionList::typeId());
238       if (aSelListAttributes.size() == 1) {
239         AttributePtr aFirstAttribute = aSelListAttributes.front();
240
241         SessionPtr aMgr = ModelAPI_Session::get();
242         ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
243         std::string aValidatorID, anError;
244         bool isValidPComposite = aFactory->validate(aFirstAttribute, aValidatorID, anError);
245         if (!isValidPComposite) {
246           int anAnswer = QMessageBox::question(
247               aWorkshop->desktop(), tr("Apply current feature"),
248                             tr("The current feature can not be used as an argument of the parent feature.\n\
249                                After apply it will be deleted. Would you like to continue?"),
250                             QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel);
251           if (anAnswer == QMessageBox::Ok)
252             aCanCommit = true;
253           else
254             aCanCommit = false;
255         }
256       }
257       if (!aIsOp) {
258         if (aCanCommit)
259           aMgr->finishOperation();
260         else
261           aMgr->abortOperation();
262       }
263     }
264   }
265   return aCanCommit;
266 }
267
268 bool PartSet_WidgetSketchCreator::isSelectionMode() const
269 {
270   AttributeSelectionListPtr anAttrList = myFeature->data()->selectionList(myAttributeListID);
271   bool aHasValueInList = anAttrList.get() && anAttrList->size() > 0;
272
273   return !aHasValueInList;
274 }
275
276 bool PartSet_WidgetSketchCreator::setSelection(QList<ModuleBase_ViewerPrs>& theValues,
277                                                const bool theToValidate)
278 {
279   bool aDone = false;
280   if (!startSketchOperation(theValues)) {
281     myIsCustomAttribute = true;
282     QList<ModuleBase_ViewerPrs>::const_iterator anIt = theValues.begin(), aLast = theValues.end();
283     bool aProcessed = false;
284     for (; anIt != aLast; anIt++) {
285       ModuleBase_ViewerPrs aValue = *anIt;
286       if (!theToValidate || isValidInFilters(aValue))
287         aProcessed = setSelectionCustom(aValue) || aProcessed;
288     }
289     myIsCustomAttribute = true;
290     aDone = aProcessed;
291     if (aProcessed) {
292       emit valuesChanged();
293       updateObject(myFeature);
294       setVisibleSelectionControl(false);
295       // manually deactivation because the widget was not activated as has no focus acceptin controls
296       deactivate();
297       emit focusOutWidget(this);
298     }
299   }
300   return aDone;
301 }
302
303 //********************************************************************
304 void PartSet_WidgetSketchCreator::onSelectionChanged()
305 {
306   QList<ModuleBase_ViewerPrs> aSelected = getFilteredSelected();
307   bool isDone = setSelection(aSelected, true/*false*/);
308 }
309
310 //********************************************************************
311 void PartSet_WidgetSketchCreator::updateOnSelectionChanged(const bool theDone)
312 {
313 }
314
315 bool PartSet_WidgetSketchCreator::startSketchOperation(const QList<ModuleBase_ViewerPrs>& theValues)
316 {
317   bool aSketchStarted = false;
318
319   if (theValues.size() != 1)
320     return aSketchStarted;
321
322   ModuleBase_ViewerPrs aValue = theValues.front();
323   if (!PartSet_WidgetSketchLabel::canFillSketch(aValue))
324     return aSketchStarted;
325
326   aSketchStarted = true;
327
328   // manually deactivation because the widget was not activated as has no focus acceptin controls
329   deactivate();
330   bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
331   myPreviewPlanes->erasePreviewPlanes(myWorkshop);
332
333   // Launch Sketch operation
334   CompositeFeaturePtr aCompFeature = 
335     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
336
337   /// add sketch feature without current feature change.
338   /// it is important to do not change the current feature in order to
339   /// after sketch edition, the extrusion cut feature becomes current
340   SessionPtr aMgr = ModelAPI_Session::get();
341   DocumentPtr aDoc = aMgr->activeDocument();
342   FeaturePtr aPreviousCurrentFeature = aDoc->currentFeature(false);
343   FeaturePtr aSketch = aCompFeature->addFeature("Sketch");
344
345   PartSet_WidgetSketchLabel::fillSketchPlaneBySelection(aSketch, aValue);
346
347   aDoc->setCurrentFeature(aPreviousCurrentFeature, false);
348
349   // start edit operation for the sketch
350   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
351                                                             (myModule->createOperation("Sketch"));
352   if (aFOperation)
353     aFOperation->setFeature(aSketch);
354   myModule->sendOperation(aFOperation);
355
356   return aSketchStarted;
357 }
358
359 bool PartSet_WidgetSketchCreator::focusTo()
360 {
361   if (isSelectionMode()) {
362     activateSelectionControl();
363
364     SessionPtr aMgr = ModelAPI_Session::get();
365     bool aIsOp = aMgr->isOperation();
366     if (!aIsOp)
367       aMgr->startOperation(myFeature->getKind());
368     return true;
369   }
370   else {
371     //setVisibleSelectionControl(false);
372
373     connect(myModule, SIGNAL(resumed(ModuleBase_Operation*)), SLOT(onResumed(ModuleBase_Operation*)));
374     SessionPtr aMgr = ModelAPI_Session::get();
375     // Open transaction that is general for the previous nested one: it will be closed on nested commit
376     bool aIsOp = aMgr->isOperation();
377     if (!aIsOp) {
378       const static std::string aNestedOpID("Parameters modification");
379       aMgr->startOperation(aNestedOpID, true);
380     }
381     restoreValue();
382   }
383   return false;
384 }
385
386 void PartSet_WidgetSketchCreator::deactivate()
387 {
388   ModuleBase_WidgetSelector::deactivate();
389
390   bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
391   myPreviewPlanes->erasePreviewPlanes(myWorkshop);
392   if (aHidePreview)
393     XGUI_Tools::workshop(myWorkshop)->viewer()->update();
394
395 }
396
397 void PartSet_WidgetSketchCreator::onResumed(ModuleBase_Operation* theOp)
398 {
399   XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
400
401   CompositeFeaturePtr aCompFeature = 
402     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
403   //CompositeFeaturePtr aSketchFeature = 
404   //  std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
405   if (aCompFeature->numberOfSubs() == 0) {
406     // do nothing, selection control should be hidden
407     setVisibleSelectionControl(false);
408   } else {
409     // check if the created sketch is invalid. Validate attribute selection list
410     // Shetch should be deleted if the attribute is invalid.
411     AttributeSelectionListPtr anAttrList = myFeature->data()->selectionList(myAttributeListID);
412     
413     SessionPtr aMgr = ModelAPI_Session::get();
414     ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
415     std::string aValidatorID, anError;
416     bool isValidPComposite = aFactory->validate(anAttrList, aValidatorID, anError);
417     /// if the sketch is not appropriate fro extrusion, it should be deleted and
418     /// the selection control should be activated again
419     if (!isValidPComposite) {
420       CompositeFeaturePtr aSketchFeature = 
421                std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
422
423       QObjectPtrList anObjects;
424       anObjects.append(aSketchFeature);
425       std::set<FeaturePtr> anIgnoredFeatures;
426       aWorkshop->deleteFeatures(anObjects, anIgnoredFeatures);
427
428       // do nothing, selection control should be shown
429       activateSelectionControl();
430     }
431     else {
432       setVisibleSelectionControl(false);
433       // Update value in attribute selection list
434       XGUI_PropertyPanel* aPanel = aWorkshop->propertyPanel();
435       const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
436       foreach(ModuleBase_ModelWidget* aWidget, aWidgets) {
437         if (aWidget->attributeID() == myAttributeListID)
438           aWidget->restoreValue();
439       }
440
441       // Hide sketcher result
442       CompositeFeaturePtr aSketchFeature = 
443         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
444       std::list<ResultPtr> aResults = aSketchFeature->results();
445       std::list<ResultPtr>::const_iterator aIt;
446       for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
447         (*aIt)->setDisplayed(false);
448       }
449       aSketchFeature->setDisplayed(false);
450       static Events_Loop* aLoop = Events_Loop::loop();
451       aLoop->flush(aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY));
452
453       // Add Selected body were created the sketcher to list of selected objects
454       std::string anObjectsAttribute = FeaturesPlugin_CompositeBoolean::OBJECTS_ID();
455       AttributeSelectionListPtr aSelList = aCompFeature->data()->selectionList(anObjectsAttribute);
456       if (aSelList.get()) {
457         DataPtr aData = aSketchFeature->data();
458         AttributeSelectionPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>
459                                       (aData->attribute(SketchPlugin_SketchEntity::EXTERNAL_ID()));
460         ResultPtr aRes = aSelAttr.get() ? aSelAttr->context() : ResultPtr();
461         if (aRes.get()) {
462           SessionPtr aMgr = ModelAPI_Session::get();
463           ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
464           AttributePtr anAttribute = myFeature->attribute(anObjectsAttribute);
465           std::string aValidatorID, anError;
466           aSelList->append(aRes, GeomShapePtr());
467           if (aFactory->validate(anAttribute, aValidatorID, anError))
468             updateObject(aCompFeature);
469           else
470             aSelList->clear();
471         }
472       }
473     }
474   }
475 }