Salome HOME
Merge branch 'master' of newgeom:newgeom
[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_Tools.h>
10 #include <ModuleBase_WidgetValueFeature.h>
11 #include <Config_WidgetAPI.h>
12 #include <Events_Loop.h>
13 #include <Events_Message.h>
14 #include <GeomAPI_Interface.h>
15 #include <GeomAPI_Shape.h>
16 #include <ModelAPI_AttributeReference.h>
17 #include <ModelAPI_Data.h>
18 #include <ModelAPI_Document.h>
19 #include <ModelAPI_Events.h>
20 #include <ModelAPI_Feature.h>
21 #include <ModelAPI_Result.h>
22 #include <ModelAPI_AttributeReference.h>
23 #include <ModelAPI_AttributeSelection.h>
24 #include <ModelAPI_Session.h>
25 #include <ModelAPI_Tools.h>
26 #include <Config_WidgetAPI.h>
27 #include <Events_Error.h>
28
29 #include <GeomAPI_Shape.h>
30
31 #include <TopoDS_Shape.hxx>
32 #include <TopExp_Explorer.hxx>
33
34 #include <QWidget>
35 #include <QLayout>
36 #include <QLabel>
37 #include <QLineEdit>
38 #include <QToolButton>
39 #include <QString>
40 #include <QEvent>
41 #include <QDockWidget>
42
43 #include <TopExp_Explorer.hxx>
44 #include <TopoDS_Shape.hxx>
45
46 #include <boost/smart_ptr/shared_ptr.hpp>
47
48 #include <list>
49 #include <string>
50
51 typedef QMap<QString, TopAbs_ShapeEnum> ShapeTypes;
52 static ShapeTypes MyShapeTypes;
53
54 TopAbs_ShapeEnum ModuleBase_WidgetShapeSelector::shapeType(const QString& theType)
55 {
56   if (MyShapeTypes.count() == 0) {
57     MyShapeTypes["face"] = TopAbs_FACE;
58     MyShapeTypes["faces"] = TopAbs_FACE;
59     MyShapeTypes["vertex"] = TopAbs_VERTEX;
60     MyShapeTypes["vertices"] = TopAbs_VERTEX;
61     MyShapeTypes["wire"] = TopAbs_WIRE;
62     MyShapeTypes["edge"] = TopAbs_EDGE;
63     MyShapeTypes["edges"] = TopAbs_EDGE;
64     MyShapeTypes["shell"] = TopAbs_SHELL;
65     MyShapeTypes["solid"] = TopAbs_SOLID;
66     MyShapeTypes["solids"] = TopAbs_SOLID;
67   }
68   QString aType = theType.toLower();
69   if (MyShapeTypes.contains(aType))
70     return MyShapeTypes[aType];
71   Events_Error::send("Shape type defined in XML is not implemented!");
72   return TopAbs_SHAPE;
73 }
74
75 ModuleBase_WidgetShapeSelector::ModuleBase_WidgetShapeSelector(QWidget* theParent,
76                                                      ModuleBase_IWorkshop* theWorkshop,
77                                                      const Config_WidgetAPI* theData,
78                                                      const std::string& theParentId)
79     : ModuleBase_ModelWidget(theParent, theData, theParentId),
80       myWorkshop(theWorkshop), myIsActive(false), myUseSubShapes(false)
81 {
82   myContainer = new QWidget(theParent);
83   QHBoxLayout* aLayout = new QHBoxLayout(myContainer);
84   ModuleBase_Tools::adjustMargins(aLayout);
85
86   QString aLabelText = QString::fromStdString(theData->widgetLabel());
87   QString aLabelIcon = QString::fromStdString(theData->widgetIcon());
88   myLabel = new QLabel(aLabelText, myContainer);
89   if (!aLabelIcon.isEmpty())
90     myLabel->setPixmap(QPixmap(aLabelIcon));
91
92   aLayout->addWidget(myLabel);
93
94   QString aToolTip = QString::fromStdString(theData->widgetTooltip());
95   myTextLine = new QLineEdit(myContainer);
96   myTextLine->setReadOnly(true);
97   myTextLine->setToolTip(aToolTip);
98   myTextLine->installEventFilter(this);
99
100   myBasePalet = myTextLine->palette();
101   myInactivePalet = myBasePalet;
102   myInactivePalet.setBrush(QPalette::Base, QBrush(Qt::gray, Qt::Dense6Pattern));
103   myTextLine->setPalette(myInactivePalet);
104
105   aLayout->addWidget(myTextLine, 1);
106
107   std::string aTypes = theData->getProperty("shape_types");
108   myShapeTypes = QString(aTypes.c_str()).split(' ');
109
110   myUseSubShapes = theData->getBooleanAttribute("use_subshapes", false); 
111 }
112
113 //********************************************************************
114 ModuleBase_WidgetShapeSelector::~ModuleBase_WidgetShapeSelector()
115 {
116   activateSelection(false);
117 }
118
119 //********************************************************************
120 bool ModuleBase_WidgetShapeSelector::storeValue() const
121 {
122   FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(mySelectedObject);
123   if (aSelectedFeature == myFeature)  // In order to avoid selection of the same object
124     return false;
125
126   DataPtr aData = myFeature->data();
127   if (myUseSubShapes) {
128     boost::shared_ptr<ModelAPI_AttributeSelection> aSelect = 
129       boost::dynamic_pointer_cast<ModelAPI_AttributeSelection>(aData->attribute(attributeID()));
130
131     ResultPtr aBody = boost::dynamic_pointer_cast<ModelAPI_Result>(mySelectedObject);
132     if (aBody) {
133       aSelect->setValue(aBody, myShape);
134       updateObject(myFeature);
135       return true;
136     }
137   } else {
138     boost::shared_ptr<ModelAPI_AttributeReference> aRef = 
139       boost::dynamic_pointer_cast<ModelAPI_AttributeReference>(aData->attribute(attributeID()));
140
141     ObjectPtr aObject = aRef->value();
142     if (!(aObject && aObject->isSame(mySelectedObject))) {
143       aRef->setValue(mySelectedObject);
144       updateObject(myFeature);
145       return true;
146     }
147   }
148   return false;
149 }
150
151 //********************************************************************
152 bool ModuleBase_WidgetShapeSelector::restoreValue()
153 {
154   DataPtr aData = myFeature->data();
155   bool isBlocked = this->blockSignals(true);
156   if (myUseSubShapes) {
157     boost::shared_ptr<ModelAPI_AttributeSelection> aSelect = aData->selection(attributeID());
158     if (aSelect) {
159       mySelectedObject = aSelect->context();
160       myShape = aSelect->value();
161     }
162   } else {
163     boost::shared_ptr<ModelAPI_AttributeReference> aRef = aData->reference(attributeID());
164     mySelectedObject = aRef->value();
165   }
166   updateSelectionName();
167
168   this->blockSignals(isBlocked);
169   return true;
170 }
171
172 //********************************************************************
173 QList<QWidget*> ModuleBase_WidgetShapeSelector::getControls() const
174 {
175   QList<QWidget*> aControls;
176   aControls.append(myLabel);
177   aControls.append(myTextLine);
178   return aControls;
179 }
180
181 //********************************************************************
182 void ModuleBase_WidgetShapeSelector::onSelectionChanged()
183 {
184   QList<ObjectPtr> aObjects = myWorkshop->selection()->selectedObjects();
185   if (aObjects.size() > 0) {
186     ObjectPtr aObject = aObjects.first();
187     if ((!mySelectedObject) && (!aObject))
188       return;
189     if (mySelectedObject && aObject && mySelectedObject->isSame(aObject))
190       return;
191
192     // Get sub-shapes from local selection
193     boost::shared_ptr<GeomAPI_Shape> aShape;
194     if (myUseSubShapes) {
195       NCollection_List<TopoDS_Shape> aShapeList;
196       std::list<ObjectPtr> aOwners;
197       myWorkshop->selection()->selectedShapes(aShapeList, aOwners);
198       if (aShapeList.Extent() > 0) {
199         aShape = boost::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape());
200         aShape->setImpl(new TopoDS_Shape(aShapeList.First()));
201       }
202     }
203
204     // Check that the selection corresponds to selection type
205     if (myUseSubShapes) {
206       if (!isAccepted(aShape))
207         return;
208     } else {
209       if (!isAccepted(aObject))
210         return;
211     }
212     setObject(aObject, aShape);
213     emit focusOutWidget(this);
214   }
215 }
216
217 //********************************************************************
218 void ModuleBase_WidgetShapeSelector::setObject(ObjectPtr theObj, boost::shared_ptr<GeomAPI_Shape> theShape)
219 {
220   if (mySelectedObject == theObj)
221     return;
222   mySelectedObject = theObj;
223   myShape = theShape;
224   if (mySelectedObject) {
225     raisePanel();
226     if (!myUseSubShapes) {
227       static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_TOHIDE);
228       ModelAPI_EventCreator::get()->sendUpdated(mySelectedObject, anEvent);
229     }
230   } 
231   updateSelectionName();
232   activateSelection(false);
233   emit valuesChanged();
234 }
235
236 //********************************************************************
237 bool ModuleBase_WidgetShapeSelector::isAccepted(const ObjectPtr theResult) const
238 {
239   ResultPtr aResult = boost::dynamic_pointer_cast<ModelAPI_Result>(theResult);
240   if (myFeature) {
241     // We can not select a result of our feature
242     const std::list<boost::shared_ptr<ModelAPI_Result>>& aRes = myFeature->results();
243     std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aIt;
244     for (aIt = aRes.cbegin(); aIt != aRes.cend(); ++aIt) {
245       if ((*aIt) == aResult)
246         return false;
247     }
248   }
249   // Check that object belongs to active document or PartSet
250   DocumentPtr aDoc = aResult->document();
251   SessionPtr aMgr = ModelAPI_Session::get();
252   if (!(aDoc == aMgr->activeDocument()) || (aDoc == aMgr->moduleDocument()))
253     return false;
254
255   // Check that the shape of necessary type
256   boost::shared_ptr<GeomAPI_Shape> aShapePtr = ModelAPI_Tools::shape(aResult);
257   if (!aShapePtr)
258     return false;
259   TopoDS_Shape aShape = aShapePtr->impl<TopoDS_Shape>();
260   if (aShape.IsNull())
261     return false;
262
263   TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
264   if (aShapeType == TopAbs_COMPOUND) {
265     foreach (QString aType, myShapeTypes) {
266       TopExp_Explorer aEx(aShape, shapeType(aType));
267       if (aEx.More())
268         return true;
269     }
270   } else {
271     foreach (QString aType, myShapeTypes) {
272       if (shapeType(aType) == aShapeType)
273         return true;
274     }
275   }
276   return false;
277 }
278
279 //********************************************************************
280 bool ModuleBase_WidgetShapeSelector::isAccepted(boost::shared_ptr<GeomAPI_Shape> theShape) const
281 {
282   TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
283   foreach (QString aType, myShapeTypes) {
284     if (aShape.ShapeType() == shapeType(aType))
285       return true;
286   }
287   return false;
288 }
289
290 //********************************************************************
291 void ModuleBase_WidgetShapeSelector::updateSelectionName()
292 {
293   if (mySelectedObject) {
294     std::string aName = mySelectedObject->data()->name();
295     myTextLine->setText(QString::fromStdString(aName));
296   } else {
297     if (myIsActive) {
298       QString aMsg = tr("Select a ");
299       int i = 0;
300       foreach (QString aType, myShapeTypes) {
301         if (i > 0)
302           aMsg += " or ";
303         aMsg += aType;
304         i++;
305       }
306       myTextLine->setText(aMsg);
307     } else
308       myTextLine->setText(tr("No object selected"));
309   }
310 }
311
312
313 //********************************************************************
314 void ModuleBase_WidgetShapeSelector::activateSelection(bool toActivate)
315 {
316   myIsActive = toActivate;
317   if (myIsActive)
318     myTextLine->setPalette(myBasePalet);
319   else
320     myTextLine->setPalette(myInactivePalet);
321   updateSelectionName();
322
323   if (myIsActive) {
324     connect(myWorkshop, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged()));
325     if (myUseSubShapes) {
326       QIntList aList;
327       foreach (QString aType, myShapeTypes)
328         aList.append(shapeType(aType));
329       myWorkshop->activateSubShapesSelection(aList);
330     }
331   } else {
332     disconnect(myWorkshop, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged()));
333     if (myUseSubShapes) 
334       myWorkshop->deactivateSubShapesSelection();
335   }
336 }
337
338 //********************************************************************
339 void ModuleBase_WidgetShapeSelector::raisePanel() const
340 {
341   QWidget* aParent = myContainer->parentWidget();
342   QWidget* aLastPanel = 0;
343   while (!aParent->inherits("QDockWidget")) {
344     aLastPanel = aParent;
345     aParent = aParent->parentWidget();
346     if (!aParent)
347       return;
348   }
349   if (aParent->inherits("QDockWidget")) {
350     QDockWidget* aTabWgt = (QDockWidget*) aParent;
351     aTabWgt->raise();
352   }
353 }
354
355 //********************************************************************
356 bool ModuleBase_WidgetShapeSelector::focusTo()
357 {
358   activateSelection(true);
359   return true;
360 }
361
362 //********************************************************************
363 bool ModuleBase_WidgetShapeSelector::eventFilter(QObject* theObj, QEvent* theEvent)
364 {
365   if (theObj == myTextLine) {
366     if (theEvent->type() == QEvent::FocusIn)
367       activateSelection(true);
368   }
369   return ModuleBase_ModelWidget::eventFilter(theObj, theEvent);
370 }
371
372 //********************************************************************
373 bool ModuleBase_WidgetShapeSelector::setValue(ModuleBase_WidgetValue* theValue)
374 {
375   if (theValue) {
376     ModuleBase_WidgetValueFeature* aFeatureValue =
377         dynamic_cast<ModuleBase_WidgetValueFeature*>(theValue);
378     if (aFeatureValue && aFeatureValue->object()) {
379       ObjectPtr aObject = aFeatureValue->object();
380       if (isAccepted(aObject)) {
381         setObject(aObject);
382         return true;
383       }
384     }
385   }
386   return false;
387 }
388