Salome HOME
Shape plane filter should process shapes of objects selected in object browser.
[modules/shaper.git] / src / ModuleBase / ModuleBase_WidgetMultiSelector.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 /*
4  * ModuleBase_WidgetMultiSelector.cpp
5  *
6  *  Created on: Aug 28, 2014
7  *      Author: sbh
8  */
9
10 #include <ModuleBase_WidgetMultiSelector.h>
11 #include <ModuleBase_WidgetShapeSelector.h>
12 #include <ModuleBase_ISelection.h>
13 #include <ModuleBase_IWorkshop.h>
14 #include <ModuleBase_IViewer.h>
15 #include <ModuleBase_Tools.h>
16 #include <ModuleBase_Definitions.h>
17
18 #include <GeomValidators_ShapeType.h>
19
20 #include <ModelAPI_Data.h>
21 #include <ModelAPI_Object.h>
22
23 #include <Config_WidgetAPI.h>
24
25 #include <QGridLayout>
26 #include <QLabel>
27 #include <QListWidget>
28 #include <QObject>
29 #include <QString>
30 #include <QComboBox>
31 #include <QEvent>
32 #include <QAction>
33 #include <QApplication>
34 #include <QClipboard>
35
36 #include <memory>
37 #include <string>
38
39 //#define DEBUG_SHAPE_VALIDATION_PREVIOUS
40
41 ModuleBase_WidgetMultiSelector::ModuleBase_WidgetMultiSelector(QWidget* theParent,
42                                                                ModuleBase_IWorkshop* theWorkshop,
43                                                                const Config_WidgetAPI* theData,
44                                                                const std::string& theParentId)
45  : ModuleBase_WidgetSelector(theParent, theWorkshop, theData, theParentId)
46 {
47   QGridLayout* aMainLay = new QGridLayout(this);
48   ModuleBase_Tools::adjustMargins(aMainLay);
49
50   QLabel* aTypeLabel = new QLabel(tr("Type"), this);
51   aMainLay->addWidget(aTypeLabel, 0, 0);
52
53   myTypeCombo = new QComboBox(this);
54   // There is no sence to paramerize list of types while we can not parametrize selection mode
55
56   std::string aPropertyTypes = theData->getProperty("type_choice");
57   QString aTypesStr = aPropertyTypes.c_str();
58   QStringList aShapeTypes = aTypesStr.split(' ');
59
60   myIsUseChoice = theData->getBooleanAttribute("use_choice", true);
61
62   myTypeCombo->addItems(aShapeTypes);
63   aMainLay->addWidget(myTypeCombo, 0, 1);
64   // if the xml definition contains one type, the controls to select a type should not be shown
65   if (aShapeTypes.size() == 1 || !myIsUseChoice) {
66     aTypeLabel->setVisible(false);
67     myTypeCombo->setVisible(false);
68   }
69
70   std::string aLabelText = theData->getProperty("label");
71   QLabel* aListLabel = new QLabel(!aLabelText.empty() ? aLabelText.c_str()
72                                                       : tr("Selected objects:"), this);
73   aMainLay->addWidget(aListLabel, 1, 0);
74   // if the xml definition contains one type, an information label should be shown near to the latest
75   if (aShapeTypes.size() == 1) {
76     QString aLabelText = QString::fromStdString(theData->widgetLabel());
77     QString aLabelIcon = QString::fromStdString(theData->widgetIcon());
78     QLabel* aSelectedLabel = new QLabel(aLabelText, this);
79     if (!aLabelIcon.isEmpty())
80       aSelectedLabel->setPixmap(QPixmap(aLabelIcon));
81     aMainLay->addWidget(aSelectedLabel, 1, 1);
82     aMainLay->setColumnStretch(2, 1);
83   }
84
85   myListControl = new QListWidget(this);
86   aMainLay->addWidget(myListControl, 2, 0, 2, -1);
87   aMainLay->setRowStretch(2, 1);
88   aMainLay->addWidget(new QLabel(this)); //FIXME(sbh)???
89   aMainLay->setRowMinimumHeight(3, 20);
90   this->setLayout(aMainLay);
91   connect(myTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onSelectionTypeChanged()));
92
93   myCopyAction = new QAction(QIcon(":pictures/copy.png"), tr("Copy"), this);
94   myCopyAction->setShortcut(QKeySequence::Copy);
95   myCopyAction->setEnabled(false);
96   connect(myCopyAction, SIGNAL(triggered(bool)), SLOT(onCopyItem()));
97   myListControl->addAction(myCopyAction);
98   myListControl->setContextMenuPolicy(Qt::ActionsContextMenu);
99   connect(myListControl, SIGNAL(itemSelectionChanged()), SLOT(onListSelection()));
100 }
101
102 ModuleBase_WidgetMultiSelector::~ModuleBase_WidgetMultiSelector()
103 {
104 }
105
106 //********************************************************************
107 bool ModuleBase_WidgetMultiSelector::storeValueCustom() const
108 {
109   // the value is stored on the selection changed signal processing 
110   // A rare case when plugin was not loaded. 
111   if(!myFeature)
112     return false;
113   DataPtr aData = myFeature->data();
114   AttributeSelectionListPtr aSelectionListAttr = 
115     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
116
117   if (aSelectionListAttr) {
118     // Store shapes type
119      TopAbs_ShapeEnum aCurrentType =
120            ModuleBase_Tools::shapeType(myTypeCombo->currentText());
121      aSelectionListAttr->setSelectionType(myTypeCombo->currentText().toStdString());
122   }   
123    return true;
124 }
125
126 //********************************************************************
127 bool ModuleBase_WidgetMultiSelector::restoreValue()
128 {
129   // A rare case when plugin was not loaded. 
130   if(!myFeature)
131     return false;
132   DataPtr aData = myFeature->data();
133   AttributeSelectionListPtr aSelectionListAttr = 
134     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
135
136   if (aSelectionListAttr) {
137     // Restore shape type
138     if (!aSelectionListAttr->selectionType().empty())
139       setCurrentShapeType(ModuleBase_Tools::shapeType(aSelectionListAttr->selectionType().c_str()));
140     updateSelectionList(aSelectionListAttr);
141     return true;
142   }
143   return false;
144 }
145
146 //********************************************************************
147 void ModuleBase_WidgetMultiSelector::storeAttributeValue()
148 {
149   DataPtr aData = myFeature->data();
150   AttributeSelectionListPtr aSelectionListAttr = 
151     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
152   if (aSelectionListAttr.get() == NULL)
153     return;
154
155   mySelectionType = aSelectionListAttr->selectionType();
156   mySelection.clear();
157   int aSize = aSelectionListAttr->size();
158   for (int i = 0; i < aSelectionListAttr->size(); i++) {
159     AttributeSelectionPtr aSelectAttr = aSelectionListAttr->value(i);
160     mySelection.append(GeomSelection(aSelectAttr->context(), aSelectAttr->value()));
161   }
162 }
163
164 //********************************************************************
165 void ModuleBase_WidgetMultiSelector::clearAttribute()
166 {
167   DataPtr aData = myFeature->data();
168   AttributeSelectionListPtr aSelectionListAttr =
169     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
170   aSelectionListAttr->clear();
171 }
172
173 //********************************************************************
174 void ModuleBase_WidgetMultiSelector::setObject(ObjectPtr theSelectedObject,
175                                                GeomShapePtr theShape)
176 {
177   DataPtr aData = myFeature->data();
178   AttributeSelectionListPtr aSelectionListAttr = 
179     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
180
181   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theSelectedObject);
182   aSelectionListAttr->append(aResult, theShape);
183 }
184
185 //********************************************************************
186 void ModuleBase_WidgetMultiSelector::restoreAttributeValue(bool/* theValid*/)
187 {
188   clearAttribute();
189
190   // Store shape type
191   DataPtr aData = myFeature->data();
192   AttributeSelectionListPtr aSelectionListAttr = 
193     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
194   aSelectionListAttr->setSelectionType(mySelectionType);
195
196   // Store selection in the attribute
197   int aSize = mySelection.size();
198   foreach (GeomSelection aSelec, mySelection) {
199     setObject(aSelec.first, aSelec.second);
200   }
201 }
202
203 //********************************************************************
204 bool ModuleBase_WidgetMultiSelector::setSelection(QList<ModuleBase_ViewerPrs>& theValues,
205                                                   const bool theToValidate)
206 {
207   QList<ModuleBase_ViewerPrs> aSkippedValues;
208
209   QList<ModuleBase_ViewerPrs>::const_iterator anIt = theValues.begin(), aLast = theValues.end();
210   bool isDone = false;
211   for (; anIt != aLast; anIt++) {
212     ModuleBase_ViewerPrs aValue = *anIt;
213     bool aProcessed = false;
214     if (!theToValidate || isValidInFilters(aValue)) {
215       aProcessed = setSelectionCustom(aValue);
216     }
217     else
218       aSkippedValues.append(aValue);
219     // if there is at least one set, the result is true
220     isDone = isDone || aProcessed;
221   }
222   // updateObject - to update/redisplay feature
223   // it is commented in order to perfom it outside the method
224   //if (isDone) {
225     //updateObject(myFeature);
226     // this emit is necessary to call store/restore method an restore type of selection
227     //emit valuesChanged();
228   //}
229   theValues.clear();
230   if (!aSkippedValues.empty())
231     theValues.append(aSkippedValues);
232
233   return isDone;
234 }
235
236 //********************************************************************
237 bool ModuleBase_WidgetMultiSelector::isValidSelectionCustom(const ModuleBase_ViewerPrs& thePrs)
238 {
239   bool aValid = ModuleBase_WidgetSelector::isValidSelectionCustom(thePrs);
240   if (aValid) {
241     ResultPtr aResult = myWorkshop->selection()->getResult(thePrs);
242     aValid = aResult.get() != NULL;
243     if (aValid) {
244       if (myFeature) {
245         // We can not select a result of our feature
246         const std::list<ResultPtr>& aResList = myFeature->results();
247         std::list<ResultPtr>::const_iterator aIt;
248         bool isSkipSelf = false;
249         for (aIt = aResList.cbegin(); aIt != aResList.cend(); ++aIt) {
250           if ((*aIt) == aResult) {
251             isSkipSelf = true;
252             break;
253           }
254         }
255         if (isSkipSelf)
256           aValid = false;
257       }
258     }
259   }
260   return aValid;
261 }
262
263 //********************************************************************
264 QList<QWidget*> ModuleBase_WidgetMultiSelector::getControls() const
265 {
266   QList<QWidget*> result;
267   //result << myTypeCombo;
268   result << myListControl;
269   return result;
270 }
271
272 //********************************************************************
273 void ModuleBase_WidgetMultiSelector::onSelectionTypeChanged()
274 {
275   activateSelection(true);
276   activateFilters(true);
277   QList<ModuleBase_ViewerPrs> anEmptyList;
278   // This method will call Selection changed event which will call onSelectionChanged
279   // To clear mySelection, myListControl and storeValue()
280   // So, we don't need to call it
281   myWorkshop->setSelected(anEmptyList);
282 }
283
284 void ModuleBase_WidgetMultiSelector::updateFocus()
285 {
286   // Set focus to List control in order to make possible 
287   // to use Tab key for transfer the focus to next widgets
288   myListControl->setCurrentRow(myListControl->model()->rowCount() - 1);
289   myListControl->setFocus();
290 }
291
292 //********************************************************************
293 void ModuleBase_WidgetMultiSelector::updateSelectionName()
294 {
295 }
296
297 //********************************************************************
298 QIntList ModuleBase_WidgetMultiSelector::getShapeTypes() const
299 {
300   QIntList aShapeTypes;
301
302   if (myTypeCombo->count() > 1 && myIsUseChoice) {
303     aShapeTypes.append(ModuleBase_Tools::shapeType(myTypeCombo->currentText()));
304   }
305   else {
306     for (int i = 0, aCount = myTypeCombo->count(); i < aCount; i++) {
307       aShapeTypes.append(ModuleBase_Tools::shapeType(myTypeCombo->itemText(i)));
308     }
309   }
310   return aShapeTypes;
311 }
312
313 //********************************************************************
314 void ModuleBase_WidgetMultiSelector::setCurrentShapeType(const TopAbs_ShapeEnum theShapeType)
315 {
316   QString aShapeTypeName;
317   
318   for (int idx = 0; idx < myTypeCombo->count(); ++idx) {
319     aShapeTypeName = myTypeCombo->itemText(idx);
320     TopAbs_ShapeEnum aRefType = ModuleBase_Tools::shapeType(aShapeTypeName);
321     if(aRefType == theShapeType && idx != myTypeCombo->currentIndex()) {
322       activateSelection(false);
323       activateFilters(false);
324       bool isBlocked = myTypeCombo->blockSignals(true);
325       myTypeCombo->setCurrentIndex(idx);
326       myTypeCombo->blockSignals(isBlocked);
327
328       activateSelection(true);
329       activateFilters(true);
330       break;
331     }
332   }
333 }
334
335 QList<ModuleBase_ViewerPrs> ModuleBase_WidgetMultiSelector::getAttributeSelection() const
336 {
337   QList<ModuleBase_ViewerPrs> aSelected;
338   // Restore selection in the viewer by the attribute selection list
339   if(myFeature) {
340     DataPtr aData = myFeature->data();
341     AttributeSelectionListPtr aListAttr = 
342       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
343     if (aListAttr) {
344       for (int i = 0; i < aListAttr->size(); i++) {
345         AttributeSelectionPtr anAttr = aListAttr->value(i);
346         ResultPtr anObject = anAttr->context();
347         if (anObject.get()) {
348           TopoDS_Shape aShape;
349           std::shared_ptr<GeomAPI_Shape> aShapePtr = anAttr->value();
350           if (aShapePtr.get()) {
351             aShape = aShapePtr->impl<TopoDS_Shape>();
352           }
353           aSelected.append(ModuleBase_ViewerPrs(anObject, aShape, NULL));
354         }
355       }
356     }
357   }
358   return aSelected;
359 }
360
361 //********************************************************************
362 void ModuleBase_WidgetMultiSelector::updateSelectionList(AttributeSelectionListPtr theList)
363 {
364   myListControl->clear();
365   for (int i = 0; i < theList->size(); i++) {
366     AttributeSelectionPtr aAttr = theList->value(i);
367     myListControl->addItem(aAttr->namingName().c_str());
368   }
369   // We have to call repaint because sometimes the List control is not updated
370   myListControl->repaint();
371 }
372
373 //********************************************************************
374 std::string ModuleBase_WidgetMultiSelector::validatorType(const QString& theType) const
375 {
376   std::string aType;
377
378   if (theType == "Vertices")
379     aType = "vertex";
380   else if (theType == "Edges")
381     aType = "edge";
382   else if (theType == "Faces")
383     aType = "face";
384   else if (theType == "Solids")
385     aType = "solid";
386
387   return aType;
388 }
389
390 //********************************************************************
391 void ModuleBase_WidgetMultiSelector::onCopyItem()
392 {
393   QList<QListWidgetItem*> aItems = myListControl->selectedItems();
394   QString aRes;
395   foreach(QListWidgetItem* aItem, aItems) {
396     if (!aRes.isEmpty())
397       aRes += "\n";
398     aRes += aItem->text();
399   }
400   if (!aRes.isEmpty()) {
401     QClipboard *clipboard = QApplication::clipboard();
402     clipboard->setText(aRes);
403   }
404 }
405
406 //********************************************************************
407 void ModuleBase_WidgetMultiSelector::onListSelection()
408 {
409   QList<QListWidgetItem*> aItems = myListControl->selectedItems();
410   myCopyAction->setEnabled(!aItems.isEmpty());
411 }