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