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