]> SALOME platform Git repositories - modules/shaper.git/blob - src/ModuleBase/ModuleBase_WidgetShapeSelector.cpp
Salome HOME
A modification to commit the Lenght and the Radius constraints by the preselection.
[modules/shaper.git] / src / ModuleBase / ModuleBase_WidgetShapeSelector.cpp
1 // File:        ModuleBase_WidgetShapeSelector.h
2 // Created:     2 June 2014
3 // Author:      Vitaly Smetannikov
4
5 #include <ModuleBase_WidgetShapeSelector.h>
6 #include <ModuleBase_Definitions.h>
7 #include <ModuleBase_ISelection.h>
8 #include <ModuleBase_IWorkshop.h>
9 #include <ModuleBase_IViewer.h>
10 #include <ModuleBase_Tools.h>
11 #include <ModuleBase_WidgetValueFeature.h>
12
13 #include <Config_WidgetAPI.h>
14 #include <Events_Loop.h>
15 #include <Events_Message.h>
16 #include <GeomAPI_Interface.h>
17 #include <GeomAPI_Shape.h>
18
19 #include <ModelAPI_AttributeReference.h>
20 #include <ModelAPI_Data.h>
21 #include <ModelAPI_Document.h>
22 #include <ModelAPI_Events.h>
23 #include <ModelAPI_Feature.h>
24 #include <ModelAPI_Result.h>
25 #include <ModelAPI_ResultConstruction.h>
26 #include <ModelAPI_AttributeReference.h>
27 #include <ModelAPI_AttributeSelection.h>
28 #include <ModelAPI_Session.h>
29 #include <ModelAPI_Tools.h>
30 #include <ModelAPI_ResultBody.h>
31 #include <ModelAPI_AttributeRefAttr.h>
32 #include <ModelAPI_Validator.h>
33 #include <ModelAPI_ResultValidator.h>
34 #include <ModelAPI_RefAttrValidator.h>
35
36 #include <Config_WidgetAPI.h>
37 #include <Events_Error.h>
38
39 #include <GeomAPI_Shape.h>
40
41 #include <TopoDS_Shape.hxx>
42 #include <TopExp_Explorer.hxx>
43
44 #include <QWidget>
45 #include <QLayout>
46 #include <QLabel>
47 #include <QLineEdit>
48 #include <QToolButton>
49 #include <QString>
50 #include <QEvent>
51 #include <QDockWidget>
52 #include <QApplication>
53
54 #include <TopExp_Explorer.hxx>
55 #include <TopoDS_Shape.hxx>
56
57 #include <memory>
58
59 #include <list>
60 #include <string>
61
62 typedef QMap<QString, TopAbs_ShapeEnum> ShapeTypes;
63 static ShapeTypes MyShapeTypes;
64
65 TopAbs_ShapeEnum ModuleBase_WidgetShapeSelector::shapeType(const QString& theType)
66 {
67   if (MyShapeTypes.count() == 0) {
68     MyShapeTypes["face"] = TopAbs_FACE;
69     MyShapeTypes["faces"] = TopAbs_FACE;
70     MyShapeTypes["vertex"] = TopAbs_VERTEX;
71     MyShapeTypes["vertices"] = TopAbs_VERTEX;
72     MyShapeTypes["wire"] = TopAbs_WIRE;
73     MyShapeTypes["edge"] = TopAbs_EDGE;
74     MyShapeTypes["edges"] = TopAbs_EDGE;
75     MyShapeTypes["shell"] = TopAbs_SHELL;
76     MyShapeTypes["solid"] = TopAbs_SOLID;
77     MyShapeTypes["solids"] = TopAbs_SOLID;
78   }
79   QString aType = theType.toLower();
80   if (MyShapeTypes.contains(aType))
81     return MyShapeTypes[aType];
82   Events_Error::send("Shape type defined in XML is not implemented!");
83   return TopAbs_SHAPE;
84 }
85
86 ModuleBase_WidgetShapeSelector::ModuleBase_WidgetShapeSelector(QWidget* theParent,
87                                                      ModuleBase_IWorkshop* theWorkshop,
88                                                      const Config_WidgetAPI* theData,
89                                                      const std::string& theParentId)
90     : ModuleBase_ModelWidget(theParent, theData, theParentId),
91       myWorkshop(theWorkshop), myIsActive(false), myUseSubShapes(false)
92 {
93   myContainer = new QWidget(theParent);
94   QHBoxLayout* aLayout = new QHBoxLayout(myContainer);
95   ModuleBase_Tools::adjustMargins(aLayout);
96
97   QString aLabelText = QString::fromStdString(theData->widgetLabel());
98   QString aLabelIcon = QString::fromStdString(theData->widgetIcon());
99   myLabel = new QLabel(aLabelText, myContainer);
100   if (!aLabelIcon.isEmpty())
101     myLabel->setPixmap(QPixmap(aLabelIcon));
102
103   aLayout->addWidget(myLabel);
104
105   QString aToolTip = QString::fromStdString(theData->widgetTooltip());
106   myTextLine = new QLineEdit(myContainer);
107   myTextLine->setReadOnly(true);
108   myTextLine->setToolTip(aToolTip);
109   myTextLine->installEventFilter(this);
110
111   aLayout->addWidget(myTextLine, 1);
112
113   std::string aTypes = theData->getProperty("shape_types");
114   myShapeTypes = QString(aTypes.c_str()).split(' ', QString::SkipEmptyParts);
115
116   std::string aObjTypes = theData->getProperty("object_types");
117   myObjectTypes = QString(aObjTypes.c_str()).split(' ', QString::SkipEmptyParts);
118
119   myUseSubShapes = theData->getBooleanAttribute("use_subshapes", false); 
120 }
121
122 //********************************************************************
123 ModuleBase_WidgetShapeSelector::~ModuleBase_WidgetShapeSelector()
124 {
125   activateSelection(false);
126 }
127
128 //********************************************************************
129 bool ModuleBase_WidgetShapeSelector::storeValue() const
130 {
131   FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(mySelectedObject);
132   if (aSelectedFeature == myFeature)  // In order to avoid selection of the same object
133     return false;
134
135   DataPtr aData = myFeature->data();
136   if (myUseSubShapes) {
137     ResultPtr aBody = std::dynamic_pointer_cast<ModelAPI_Result>(mySelectedObject);
138     if (aBody) {
139       AttributePtr aAttr = aData->attribute(attributeID());
140
141       // We have to check several attributes types
142       AttributeSelectionPtr aSelectAttr = 
143         std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(aAttr);
144       if (aSelectAttr) {
145         aSelectAttr->setValue(aBody, myShape);
146         updateObject(myFeature);
147         return true;
148       } else {
149         AttributeRefAttrPtr aRefAttr = aData->refattr(attributeID());
150         if (aRefAttr) {
151           aRefAttr->setObject(mySelectedObject);
152           updateObject(myFeature);
153           return true;
154         }
155       }
156     }
157   } else {
158     AttributeReferencePtr aRef = aData->reference(attributeID());
159     if (aRef) {
160       ObjectPtr aObject = aRef->value();
161       if (!(aObject && aObject->isSame(mySelectedObject))) {
162         aRef->setValue(mySelectedObject);
163         updateObject(myFeature);
164         return true;
165       }
166     } else {
167       AttributeRefAttrPtr aRefAttr = aData->refattr(attributeID());
168       if (aRefAttr) {
169         ObjectPtr aObject = aRefAttr->object();
170         if (!(aObject && aObject->isSame(mySelectedObject))) {
171           aRefAttr->setObject(mySelectedObject);
172           updateObject(myFeature);
173           return true;
174         }
175       }
176     }
177   }
178   return false;
179 }
180
181 //********************************************************************
182 void ModuleBase_WidgetShapeSelector::clearAttribute()
183 {
184   DataPtr aData = myFeature->data();
185   AttributeSelectionPtr aSelect = aData->selection(attributeID());
186   if (aSelect) {
187     aSelect->setValue(ResultPtr(), std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape()));
188     return;
189   }
190   AttributeRefAttrPtr aRefAttr = aData->refattr(attributeID());
191   if (aRefAttr) {
192     aRefAttr->setObject(ObjectPtr());
193     return;
194   }
195   AttributeReferencePtr aRef = aData->reference(attributeID());
196   if (aRef) {
197     aRef->setObject(ObjectPtr());
198   }
199 }
200
201 //********************************************************************
202 bool ModuleBase_WidgetShapeSelector::restoreValue()
203 {
204   DataPtr aData = myFeature->data();
205   bool isBlocked = this->blockSignals(true);
206   if (myUseSubShapes) {
207     AttributeSelectionPtr aSelect = aData->selection(attributeID());
208     if (aSelect) {
209       mySelectedObject = aSelect->context();
210       myShape = aSelect->value();
211     } else {
212       AttributeRefAttrPtr aRefAttr = aData->refattr(attributeID());
213       if (aRefAttr) {
214         mySelectedObject = aRefAttr->object();
215       }
216     }
217   } else {
218     AttributeReferencePtr aRef = aData->reference(attributeID());
219     if (aRef)
220       mySelectedObject = aRef->value();
221     else {
222       AttributeRefAttrPtr aRefAttr = aData->refattr(attributeID());
223       if (aRefAttr)
224         mySelectedObject = aRefAttr->object();
225     }
226   }
227   updateSelectionName();
228
229   this->blockSignals(isBlocked);
230   return true;
231 }
232
233 //********************************************************************
234 QList<QWidget*> ModuleBase_WidgetShapeSelector::getControls() const
235 {
236   QList<QWidget*> aControls;
237   aControls.append(myTextLine);
238   return aControls;
239 }
240
241 //********************************************************************
242 void ModuleBase_WidgetShapeSelector::onSelectionChanged()
243 {
244   // In order to make reselection possible
245   // TODO: check with MPV clearAttribute();
246
247   QObjectPtrList aObjects = myWorkshop->selection()->selectedPresentations();
248   if (aObjects.size() > 0) {
249     ObjectPtr aObject = aObjects.first();
250     if ((!mySelectedObject) && (!aObject))
251       return;
252
253     // Check that the selected object is result (others can not be accepted)
254     ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aObject);
255     if (!aRes)
256       return;
257
258     if (myFeature) {
259       // We can not select a result of our feature
260       const std::list<std::shared_ptr<ModelAPI_Result>>& aResList = myFeature->results();
261       std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aIt;
262       for (aIt = aResList.cbegin(); aIt != aResList.cend(); ++aIt) {
263         if ((*aIt) == aRes)
264           return;
265       }
266     }
267     // Check that object belongs to active document or PartSet
268     DocumentPtr aDoc = aRes->document();
269     SessionPtr aMgr = ModelAPI_Session::get();
270     if (!(aDoc == aMgr->activeDocument()) && !(aDoc == aMgr->moduleDocument()))
271       return;
272
273     // Check that the result has a shape
274     GeomShapePtr aShape = ModelAPI_Tools::shape(aRes);
275     if (!aShape)
276       return;
277
278     /// Check that object has acceptable type
279     if (!acceptObjectType(aObject)) 
280       return;
281
282     // Get sub-shapes from local selection
283     if (myUseSubShapes) {
284       NCollection_List<TopoDS_Shape> aShapeList;
285       std::list<ObjectPtr> aOwners;
286       myWorkshop->selection()->selectedShapes(aShapeList, aOwners);
287       if (aShapeList.Extent() > 0) {
288         aShape = std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape());
289         aShape->setImpl(new TopoDS_Shape(aShapeList.First()));
290       }
291     }
292
293     // Check that the selection corresponds to selection type
294     if (myUseSubShapes) {
295       if (!acceptSubShape(aShape))
296         return;
297     } else {
298       if (!acceptObjectShape(aObject))
299         return;
300     }
301     if (isValid(aObject, aShape)) {
302       setObject(aObject, aShape);
303       emit focusOutWidget(this);
304     }
305   }
306 }
307
308 //********************************************************************
309 void ModuleBase_WidgetShapeSelector::setObject(ObjectPtr theObj, std::shared_ptr<GeomAPI_Shape> theShape)
310 {
311   mySelectedObject = theObj;
312   myShape = theShape;
313   if (mySelectedObject) {
314     raisePanel();
315   } 
316   updateSelectionName();
317   emit valuesChanged();
318 }
319
320 //********************************************************************
321 bool ModuleBase_WidgetShapeSelector::acceptObjectShape(const ObjectPtr theResult) const
322 {
323   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theResult);
324
325   // Check that the shape of necessary type
326   std::shared_ptr<GeomAPI_Shape> aShapePtr = ModelAPI_Tools::shape(aResult);
327   if (!aShapePtr)
328     return false;
329   TopoDS_Shape aShape = aShapePtr->impl<TopoDS_Shape>();
330   if (aShape.IsNull())
331     return false;
332
333   TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
334   if (aShapeType == TopAbs_COMPOUND) {
335     foreach (QString aType, myShapeTypes) {
336       TopExp_Explorer aEx(aShape, shapeType(aType));
337       if (aEx.More())
338         return true;
339     }
340   } else {
341     foreach (QString aType, myShapeTypes) {
342       if (shapeType(aType) == aShapeType)
343         return true;
344     }
345   }
346   return false;
347 }
348
349 //********************************************************************
350 bool ModuleBase_WidgetShapeSelector::acceptSubShape(std::shared_ptr<GeomAPI_Shape> theShape) const
351 {
352   TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
353   foreach (QString aType, myShapeTypes) {
354     if (aShape.ShapeType() == shapeType(aType))
355       return true;
356   }
357   return false;
358 }
359
360 //********************************************************************
361 bool ModuleBase_WidgetShapeSelector::acceptObjectType(const ObjectPtr theObject) const
362 {
363   // Definition of types is not obligatory. If types are not defined then
364   // it means that accepted any type
365   if (myObjectTypes.isEmpty())
366     return true;
367
368   foreach (QString aType, myObjectTypes) {
369     if (aType.toLower() == "construction") {
370       ResultConstructionPtr aConstr = 
371         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theObject);
372       return (aConstr != NULL);
373     } // ToDo: Process other types of objects
374   }
375   // Object type is defined but not found
376   return false;
377 }
378
379
380 //********************************************************************
381 void ModuleBase_WidgetShapeSelector::updateSelectionName()
382 {
383   if (mySelectedObject) {
384     std::string aName = mySelectedObject->data()->name();
385     myTextLine->setText(QString::fromStdString(aName));
386   } else {
387     if (myIsActive) {
388       myTextLine->setText("");
389     }
390   }
391 }
392
393
394 //********************************************************************
395 void ModuleBase_WidgetShapeSelector::activateSelection(bool toActivate)
396 {
397   if (myIsActive == toActivate)
398     return;
399   myIsActive = toActivate;
400   updateSelectionName();
401
402   if (myIsActive) {
403     connect(myWorkshop, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged()));
404     if (myUseSubShapes) {
405
406       QIntList aList;
407       foreach (QString aType, myShapeTypes)
408         aList.append(shapeType(aType));
409       myWorkshop->activateSubShapesSelection(aList);
410       if (!myObjectTypes.isEmpty()) {
411         myObjTypeFilter = new ModuleBase_ObjectTypesFilter(myWorkshop, myObjectTypes);
412         myWorkshop->viewer()->clearSelectionFilters();
413         myWorkshop->viewer()->addSelectionFilter(myObjTypeFilter);
414       }
415     }
416   } else {
417     disconnect(myWorkshop, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged()));
418     if (myUseSubShapes) {
419       if (!myObjTypeFilter.IsNull()) {
420         myWorkshop->viewer()->removeSelectionFilter(myObjTypeFilter);
421         myObjTypeFilter.Nullify();
422       }
423       myWorkshop->deactivateSubShapesSelection();
424     }
425   }
426 }
427
428 //********************************************************************
429 void ModuleBase_WidgetShapeSelector::raisePanel() const
430 {
431   QWidget* aParent = myContainer->parentWidget();
432   QWidget* aLastPanel = 0;
433   while (!aParent->inherits("QDockWidget")) {
434     aLastPanel = aParent;
435     aParent = aParent->parentWidget();
436     if (!aParent)
437       return;
438   }
439   if (aParent->inherits("QDockWidget")) {
440     QDockWidget* aTabWgt = (QDockWidget*) aParent;
441     aTabWgt->raise();
442   }
443 }
444
445 //********************************************************************
446 bool ModuleBase_WidgetShapeSelector::setValue(ModuleBase_WidgetValue* theValue)
447 {
448   if (theValue) {
449     ModuleBase_WidgetValueFeature* aFeatureValue =
450         dynamic_cast<ModuleBase_WidgetValueFeature*>(theValue);
451     if (aFeatureValue && aFeatureValue->object()) {
452       ObjectPtr aObject = aFeatureValue->object();
453       if (acceptObjectShape(aObject)) {
454         setObject(aObject);
455         return true;
456       }
457     }
458   }
459   return false;
460 }
461
462 //********************************************************************
463 void ModuleBase_WidgetShapeSelector::activate()
464 {
465   activateSelection(true);
466 }
467
468 //********************************************************************
469 void ModuleBase_WidgetShapeSelector::deactivate()
470 {
471   activateSelection(false);
472 }
473
474 //********************************************************************
475 bool ModuleBase_WidgetShapeSelector::isValid(ObjectPtr theObj, std::shared_ptr<GeomAPI_Shape> theShape)
476 {
477   SessionPtr aMgr = ModelAPI_Session::get();
478   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
479   std::list<ModelAPI_Validator*> aValidators;
480   std::list<std::list<std::string> > anArguments;
481   aFactory->validators(parentID(), attributeID(), aValidators, anArguments);
482
483   // Check the type of selected object
484   std::list<ModelAPI_Validator*>::iterator aValidator = aValidators.begin();
485   bool isValid = true;
486   for (; aValidator != aValidators.end(); aValidator++) {
487     const ModelAPI_ResultValidator* aResValidator =
488         dynamic_cast<const ModelAPI_ResultValidator*>(*aValidator);
489     if (aResValidator) {
490       isValid = false;
491       if (aResValidator->isValid(theObj)) {
492         isValid = true;
493         break;
494       }
495     }
496   }
497   if (!isValid)
498     return false;
499
500   // Check the acceptability of the object as attribute
501   aValidator = aValidators.begin();
502   std::list<std::list<std::string> >::iterator aArgs = anArguments.begin();
503   for (; aValidator != aValidators.end(); aValidator++, aArgs++) {
504     const ModelAPI_RefAttrValidator* aAttrValidator =
505         dynamic_cast<const ModelAPI_RefAttrValidator*>(*aValidator);
506     if (aAttrValidator) {
507       if (!aAttrValidator->isValid(myFeature, *aArgs, theObj)) {
508         return false;
509       }
510     }
511   }
512   return true;
513 }