]> SALOME platform Git repositories - modules/shaper.git/blob - src/PartSet/PartSet_WidgetSketchCreator.cpp
Salome HOME
#1371 Using auxilliary Sketch elements in any Feature: code improvement to separate...
[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::onSelectionChanged()
273 {
274   QList<ModuleBase_ViewerPrs> aSelected = getFilteredSelected();
275   bool isDone = setSelection(aSelected, true/*false*/);
276 }
277
278 //********************************************************************
279 void PartSet_WidgetSketchCreator::updateOnSelectionChanged(const bool theDone)
280 {
281 }
282
283 bool PartSet_WidgetSketchCreator::startSketchOperation(const QList<ModuleBase_ViewerPrs>& theValues)
284 {
285   bool aSketchStarted = false;
286
287   if (theValues.size() != 1)
288     return aSketchStarted;
289
290   ModuleBase_ViewerPrs aValue = theValues.front();
291   if (!PartSet_WidgetSketchLabel::canFillSketch(aValue))
292     return aSketchStarted;
293
294   aSketchStarted = true;
295
296   // manually deactivation because the widget was not activated as has no focus acceptin controls
297   deactivate();
298   bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
299   myPreviewPlanes->erasePreviewPlanes(myWorkshop);
300
301   // Launch Sketch operation
302   CompositeFeaturePtr aCompFeature = 
303     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
304
305   /// add sketch feature without current feature change.
306   /// it is important to do not change the current feature in order to
307   /// after sketch edition, the extrusion cut feature becomes current
308   SessionPtr aMgr = ModelAPI_Session::get();
309   DocumentPtr aDoc = aMgr->activeDocument();
310   FeaturePtr aPreviousCurrentFeature = aDoc->currentFeature(false);
311   FeaturePtr aSketch = aCompFeature->addFeature("Sketch");
312
313   PartSet_WidgetSketchLabel::fillSketchPlaneBySelection(aSketch, aValue);
314
315   aDoc->setCurrentFeature(aPreviousCurrentFeature, false);
316
317   // start edit operation for the sketch
318   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
319                                                             (myModule->createOperation("Sketch"));
320   if (aFOperation)
321     aFOperation->setFeature(aSketch);
322   myModule->sendOperation(aFOperation);
323
324   return aSketchStarted;
325 }
326
327 bool PartSet_WidgetSketchCreator::focusTo()
328 {
329   if (isSelectionMode()) {
330     activateSelectionControl();
331     return true;
332   }
333   else {
334     //setVisibleSelectionControl(false);
335
336     connect(myModule, SIGNAL(resumed(ModuleBase_Operation*)), SLOT(onResumed(ModuleBase_Operation*)));
337     SessionPtr aMgr = ModelAPI_Session::get();
338     // Open transaction that is general for the previous nested one: it will be closed on nested commit
339     bool aIsOp = aMgr->isOperation();
340     if (!aIsOp) {
341       const static std::string aNestedOpID("Parameters modification");
342       aMgr->startOperation(aNestedOpID, true);
343     }
344     restoreValue();
345   }
346   return false;
347 }
348
349 void PartSet_WidgetSketchCreator::deactivate()
350 {
351   ModuleBase_WidgetSelector::deactivate();
352
353   bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
354   myPreviewPlanes->erasePreviewPlanes(myWorkshop);
355   if (aHidePreview)
356     XGUI_Tools::workshop(myWorkshop)->viewer()->update();
357
358 }
359
360 void PartSet_WidgetSketchCreator::onResumed(ModuleBase_Operation* theOp)
361 {
362   XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
363
364   CompositeFeaturePtr aCompFeature = 
365     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
366   //CompositeFeaturePtr aSketchFeature = 
367   //  std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
368   if (aCompFeature->numberOfSubs() == 0) {
369     // do nothing, selection control should be hidden
370     setVisibleSelectionControl(false);
371   } else {
372     // check if the created sketch is invalid. Validate attribute selection list
373     // Shetch should be deleted if the attribute is invalid.
374     AttributeSelectionListPtr anAttrList = myFeature->data()->selectionList(myAttributeListID);
375     
376     SessionPtr aMgr = ModelAPI_Session::get();
377     ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
378     std::string aValidatorID, anError;
379     bool isValidPComposite = aFactory->validate(anAttrList, aValidatorID, anError);
380     /// if the sketch is not appropriate fro extrusion, it should be deleted and
381     /// the selection control should be activated again
382     if (!isValidPComposite) {
383       CompositeFeaturePtr aSketchFeature = 
384                std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
385
386       QObjectPtrList anObjects;
387       anObjects.append(aSketchFeature);
388       std::set<FeaturePtr> anIgnoredFeatures;
389       aWorkshop->deleteFeatures(anObjects, anIgnoredFeatures);
390
391       // do nothing, selection control should be shown
392       activateSelectionControl();
393     }
394     else {
395       setVisibleSelectionControl(false);
396       // Update value in attribute selection list
397       XGUI_PropertyPanel* aPanel = aWorkshop->propertyPanel();
398       const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
399       foreach(ModuleBase_ModelWidget* aWidget, aWidgets) {
400         if (aWidget->attributeID() == myAttributeListID)
401           aWidget->restoreValue();
402       }
403
404       // Hide sketcher result
405       CompositeFeaturePtr aSketchFeature = 
406         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
407       std::list<ResultPtr> aResults = aSketchFeature->results();
408       std::list<ResultPtr>::const_iterator aIt;
409       for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
410         (*aIt)->setDisplayed(false);
411       }
412       aSketchFeature->setDisplayed(false);
413       static Events_Loop* aLoop = Events_Loop::loop();
414       aLoop->flush(aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY));
415
416       // Add Selected body were created the sketcher to list of selected objects
417       std::string anObjectsAttribute = FeaturesPlugin_CompositeBoolean::BOOLEAN_OBJECTS_ID();
418       AttributeSelectionListPtr aSelList = aCompFeature->data()->selectionList(anObjectsAttribute);
419       if (aSelList.get()) {
420         DataPtr aData = aSketchFeature->data();
421         AttributeSelectionPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>
422                                       (aData->attribute(SketchPlugin_SketchEntity::EXTERNAL_ID()));
423         ResultPtr aRes = aSelAttr.get() ? aSelAttr->context() : ResultPtr();
424         if (aRes.get()) {
425           SessionPtr aMgr = ModelAPI_Session::get();
426           ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
427           AttributePtr anAttribute = myFeature->attribute(anObjectsAttribute);
428           std::string aValidatorID, anError;
429           aSelList->append(aRes, GeomShapePtr());
430           if (aFactory->validate(anAttribute, aValidatorID, anError))
431             updateObject(aCompFeature);
432           else
433             aSelList->clear();
434         }
435       }
436     }
437   }
438 }
439
440 bool PartSet_WidgetSketchCreator::setBaseAttributeSelection(const ModuleBase_ViewerPrs& theValue)
441 {
442   bool isDone = false;
443   ObjectPtr anObject;
444   GeomShapePtr aShape;
445   getGeomSelection(theValue, anObject, aShape);
446
447   std::string anAttributeId = myAttributeListID;
448   DataPtr aData = myFeature->data();
449   ModuleBase_Tools::setObject(aData->attribute(anAttributeId), anObject, aShape,
450                               myWorkshop, false);
451   return true;
452 }