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