Salome HOME
A separation of WidgetSelector class in order to unite the logic of shape/multi shape...
[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 {
206   QList<ModuleBase_ViewerPrs> aSkippedValues;
207
208   QList<ModuleBase_ViewerPrs>::const_iterator anIt = theValues.begin(), aLast = theValues.end();
209   bool isDone = false;
210   for (; anIt != aLast; anIt++) {
211     ModuleBase_ViewerPrs aValue = *anIt;
212     bool aProcessed = false;
213     if (isValidSelection(aValue)) {
214       aProcessed = setSelectionCustom(aValue);
215     }
216     else
217       aSkippedValues.append(aValue);
218     // if there is at least one set, the result is true
219     isDone = isDone || aProcessed;
220   }
221   // updateObject - to update/redisplay feature
222   // it is commented in order to perfom it outside the method
223   //if (isDone) {
224     //updateObject(myFeature);
225     // this emit is necessary to call store/restore method an restore type of selection
226     //emit valuesChanged();
227   //}
228   theValues.clear();
229   if (!aSkippedValues.empty())
230     theValues.append(aSkippedValues);
231
232   return isDone;
233 }
234
235 //********************************************************************
236 bool ModuleBase_WidgetMultiSelector::isValidSelectionCustom(const ModuleBase_ViewerPrs& thePrs)
237 {
238   bool aValid = ModuleBase_WidgetSelector::isValidSelectionCustom(thePrs);
239   if (aValid) {
240     ResultPtr aResult = myWorkshop->selection()->getResult(thePrs);
241     aValid = aResult.get() != NULL;
242     if (aValid) {
243       if (myFeature) {
244         // We can not select a result of our feature
245         const std::list<ResultPtr>& aResList = myFeature->results();
246         std::list<ResultPtr>::const_iterator aIt;
247         bool isSkipSelf = false;
248         for (aIt = aResList.cbegin(); aIt != aResList.cend(); ++aIt) {
249           if ((*aIt) == aResult) {
250             isSkipSelf = true;
251             break;
252           }
253         }
254         if (isSkipSelf)
255           aValid = false;
256       }
257     }
258   }
259   return aValid;
260 }
261
262 //********************************************************************
263 QList<QWidget*> ModuleBase_WidgetMultiSelector::getControls() const
264 {
265   QList<QWidget*> result;
266   //result << myTypeCombo;
267   result << myListControl;
268   return result;
269 }
270
271 //********************************************************************
272 void ModuleBase_WidgetMultiSelector::onSelectionTypeChanged()
273 {
274   activateSelection(true);
275   activateFilters(myWorkshop, true);
276   QList<ModuleBase_ViewerPrs> anEmptyList;
277   // This method will call Selection changed event which will call onSelectionChanged
278   // To clear mySelection, myListControl and storeValue()
279   // So, we don't need to call it
280   myWorkshop->setSelected(anEmptyList);
281 }
282
283 void ModuleBase_WidgetMultiSelector::updateFocus()
284 {
285   // Set focus to List control in order to make possible 
286   // to use Tab key for transfer the focus to next widgets
287   myListControl->setCurrentRow(myListControl->model()->rowCount() - 1);
288   myListControl->setFocus();
289 }
290
291 //********************************************************************
292 void ModuleBase_WidgetMultiSelector::updateSelectionName()
293 {
294 }
295
296 //********************************************************************
297 QIntList ModuleBase_WidgetMultiSelector::getShapeTypes() const
298 {
299   QIntList aShapeTypes;
300
301   if (myTypeCombo->count() > 1) {
302     aShapeTypes.append(ModuleBase_Tools::shapeType(myTypeCombo->currentText()));
303   }
304   else {
305     for (int i = 0, aCount = myTypeCombo->count(); i < aCount; i++) {
306       aShapeTypes.append(ModuleBase_Tools::shapeType(myTypeCombo->itemText(i)));
307     }
308   }
309   return aShapeTypes;
310 }
311
312 //********************************************************************
313 void ModuleBase_WidgetMultiSelector::setCurrentShapeType(const TopAbs_ShapeEnum theShapeType)
314 {
315   QString aShapeTypeName;
316   
317   for (int idx = 0; idx < myTypeCombo->count(); ++idx) {
318     aShapeTypeName = myTypeCombo->itemText(idx);
319     TopAbs_ShapeEnum aRefType = ModuleBase_Tools::shapeType(aShapeTypeName);
320     if(aRefType == theShapeType && idx != myTypeCombo->currentIndex()) {
321       activateSelection(false);
322       activateFilters(myWorkshop, false);
323       bool isBlocked = myTypeCombo->blockSignals(true);
324       myTypeCombo->setCurrentIndex(idx);
325       myTypeCombo->blockSignals(isBlocked);
326
327       activateSelection(true);
328       activateFilters(myWorkshop, true);
329       break;
330     }
331   }
332 }
333
334 QList<ModuleBase_ViewerPrs> ModuleBase_WidgetMultiSelector::getAttributeSelection() const
335 {
336   QList<ModuleBase_ViewerPrs> aSelected;
337   // Restore selection in the viewer by the attribute selection list
338   if(myFeature) {
339     DataPtr aData = myFeature->data();
340     AttributeSelectionListPtr aListAttr = 
341       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
342     if (aListAttr) {
343       for (int i = 0; i < aListAttr->size(); i++) {
344         AttributeSelectionPtr anAttr = aListAttr->value(i);
345         ResultPtr anObject = anAttr->context();
346         if (anObject.get()) {
347           TopoDS_Shape aShape;
348           std::shared_ptr<GeomAPI_Shape> aShapePtr = anAttr->value();
349           if (aShapePtr.get()) {
350             aShape = aShapePtr->impl<TopoDS_Shape>();
351           }
352           aSelected.append(ModuleBase_ViewerPrs(anObject, aShape, NULL));
353         }
354       }
355     }
356   }
357   return aSelected;
358 }
359
360 //********************************************************************
361 void ModuleBase_WidgetMultiSelector::updateSelectionList(AttributeSelectionListPtr theList)
362 {
363   myListControl->clear();
364   for (int i = 0; i < theList->size(); i++) {
365     AttributeSelectionPtr aAttr = theList->value(i);
366     myListControl->addItem(aAttr->namingName().c_str());
367   }
368   // We have to call repaint because sometimes the List control is not updated
369   myListControl->repaint();
370 }
371
372 //********************************************************************
373 std::string ModuleBase_WidgetMultiSelector::validatorType(const QString& theType) const
374 {
375   std::string aType;
376
377   if (theType == "Vertices")
378     aType = "vertex";
379   else if (theType == "Edges")
380     aType = "edge";
381   else if (theType == "Faces")
382     aType = "face";
383   else if (theType == "Solids")
384     aType = "solid";
385
386   return aType;
387 }
388
389 //********************************************************************
390 void ModuleBase_WidgetMultiSelector::onCopyItem()
391 {
392   QList<QListWidgetItem*> aItems = myListControl->selectedItems();
393   QString aRes;
394   foreach(QListWidgetItem* aItem, aItems) {
395     if (!aRes.isEmpty())
396       aRes += "\n";
397     aRes += aItem->text();
398   }
399   if (!aRes.isEmpty()) {
400     QClipboard *clipboard = QApplication::clipboard();
401     clipboard->setText(aRes);
402   }
403 }
404
405 //********************************************************************
406 void ModuleBase_WidgetMultiSelector::onListSelection()
407 {
408   QList<QListWidgetItem*> aItems = myListControl->selectedItems();
409   myCopyAction->setEnabled(!aItems.isEmpty());
410 }