]> SALOME platform Git repositories - modules/shaper.git/blob - src/ModuleBase/ModuleBase_WidgetMultiSelector.cpp
Salome HOME
d20ddf8e82ca0a40aed7871c210a527189bd8e0a
[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 ModuleBase_WidgetMultiSelector::ModuleBase_WidgetMultiSelector(QWidget* theParent,
40                                                                ModuleBase_IWorkshop* theWorkshop,
41                                                                const Config_WidgetAPI* theData,
42                                                                const std::string& theParentId)
43     : ModuleBase_WidgetValidated(theParent, theData, theParentId),
44       myWorkshop(theWorkshop)
45 {
46   QGridLayout* aMainLay = new QGridLayout(this);
47   ModuleBase_Tools::adjustMargins(aMainLay);
48
49   QLabel* aTypeLabel = new QLabel(tr("Type"), this);
50   aMainLay->addWidget(aTypeLabel, 0, 0);
51
52   myTypeCombo = new QComboBox(this);
53   // There is no sence to paramerize list of types while we can not parametrize selection mode
54
55   myShapeValidator = new GeomValidators_ShapeType();
56
57   std::string aPropertyTypes = theData->getProperty("type_choice");
58   QString aTypesStr = aPropertyTypes.c_str();
59   QStringList aShapeTypes = aTypesStr.split(' ');
60
61   //myIsUseChoice = theData->getBooleanAttribute("use_choice", true);
62
63   myTypeCombo->addItems(aShapeTypes);
64   aMainLay->addWidget(myTypeCombo, 0, 1);
65   // if the xml definition contains one type, the controls to select a type should not be shown
66   if (aShapeTypes.size() == 1/* || !myIsUseChoice*/) {
67     aTypeLabel->setVisible(false);
68     myTypeCombo->setVisible(false);
69   }
70
71   QLabel* aListLabel = new QLabel(tr("Selected objects:"), this);
72   aMainLay->addWidget(aListLabel, 1, 0);
73   // if the xml definition contains one type, an information label should be shown near to the latest
74   if (aShapeTypes.size() == 1) {
75     QString aLabelText = QString::fromStdString(theData->widgetLabel());
76     QString aLabelIcon = QString::fromStdString(theData->widgetIcon());
77     QLabel* aSelectedLabel = new QLabel(aLabelText, this);
78     if (!aLabelIcon.isEmpty())
79       aSelectedLabel->setPixmap(QPixmap(aLabelIcon));
80     aMainLay->addWidget(aSelectedLabel, 1, 1);
81     aMainLay->setColumnStretch(2, 1);
82   }
83
84   myListControl = new QListWidget(this);
85   aMainLay->addWidget(myListControl, 2, 0, 2, -1);
86   aMainLay->setRowStretch(2, 1);
87   aMainLay->addWidget(new QLabel(this)); //FIXME(sbh)???
88   aMainLay->setRowMinimumHeight(3, 20);
89   this->setLayout(aMainLay);
90   connect(myTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onSelectionTypeChanged()));
91
92   myCopyAction = new QAction(QIcon(":pictures/copy.png"), tr("Copy"), this);
93   myCopyAction->setShortcut(QKeySequence::Copy);
94   myCopyAction->setEnabled(false);
95   connect(myCopyAction, SIGNAL(triggered(bool)), SLOT(onCopyItem()));
96   myListControl->addAction(myCopyAction);
97   myListControl->setContextMenuPolicy(Qt::ActionsContextMenu);
98   connect(myListControl, SIGNAL(itemSelectionChanged()), SLOT(onListSelection()));
99 }
100
101 ModuleBase_WidgetMultiSelector::~ModuleBase_WidgetMultiSelector()
102 {
103   delete myShapeValidator;
104 }
105
106 //TODO: nds stabilization hotfix
107 void ModuleBase_WidgetMultiSelector::disconnectSignals()
108 {
109   disconnect(myWorkshop, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged()));
110 }
111
112 //********************************************************************
113 void ModuleBase_WidgetMultiSelector::activateCustom()
114 {
115   ModuleBase_IViewer* aViewer = myWorkshop->viewer();
116   connect(myWorkshop, SIGNAL(selectionChanged()), 
117           this,       SLOT(onSelectionChanged()), 
118           Qt::UniqueConnection);
119
120   activateShapeSelection(true);
121
122   // Restore selection in the viewer by the attribute selection list
123   myWorkshop->setSelected(getAttributeSelection());
124
125   activateFilters(myWorkshop, true);
126 }
127
128 //********************************************************************
129 void ModuleBase_WidgetMultiSelector::deactivate()
130 {
131   disconnect(myWorkshop, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged()));
132   activateShapeSelection(false);
133   activateFilters(myWorkshop, false);
134 }
135
136 //********************************************************************
137 bool ModuleBase_WidgetMultiSelector::storeValueCustom() const
138 {
139   // the value is stored on the selection changed signal processing 
140   // A rare case when plugin was not loaded. 
141   if(!myFeature)
142     return false;
143   DataPtr aData = myFeature->data();
144   AttributeSelectionListPtr aSelectionListAttr = 
145     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
146
147   if (aSelectionListAttr) {
148     // Store shapes type
149      TopAbs_ShapeEnum aCurrentType =
150            ModuleBase_Tools::shapeType(myTypeCombo->currentText());
151      aSelectionListAttr->setSelectionType(myTypeCombo->currentText().toStdString());
152   }   
153    return true;
154 }
155
156 //********************************************************************
157 bool ModuleBase_WidgetMultiSelector::restoreValue()
158 {
159   // A rare case when plugin was not loaded. 
160   if(!myFeature)
161     return false;
162   DataPtr aData = myFeature->data();
163   AttributeSelectionListPtr aSelectionListAttr = 
164     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
165
166   if (aSelectionListAttr) {
167     // Restore shape type
168     if (!aSelectionListAttr->selectionType().empty())
169       setCurrentShapeType(ModuleBase_Tools::shapeType(aSelectionListAttr->selectionType().c_str()));
170     updateSelectionList(aSelectionListAttr);
171     return true;
172   }
173   return false;
174 }
175
176 //********************************************************************
177 void ModuleBase_WidgetMultiSelector::storeAttributeValue()
178 {
179   DataPtr aData = myFeature->data();
180   AttributeSelectionListPtr aSelectionListAttr = 
181     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
182   if (aSelectionListAttr.get() == NULL)
183     return;
184
185   mySelectionType = aSelectionListAttr->selectionType();
186   mySelection.clear();
187   int aSize = aSelectionListAttr->size();
188   for (int i = 0; i < aSelectionListAttr->size(); i++) {
189     AttributeSelectionPtr aSelectAttr = aSelectionListAttr->value(i);
190     mySelection.append(GeomSelection(aSelectAttr->context(), aSelectAttr->value()));
191   }
192 }
193
194 //********************************************************************
195 void ModuleBase_WidgetMultiSelector::restoreAttributeValue(bool/* theValid*/)
196 {
197   DataPtr aData = myFeature->data();
198   AttributeSelectionListPtr aSelectionListAttr = 
199     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
200   if (aSelectionListAttr.get() == NULL)
201     return;
202   aSelectionListAttr->clear();
203
204   // Store shapes type
205   aSelectionListAttr->setSelectionType(mySelectionType);
206
207   // Store selection in the attribute
208   int aSize = mySelection.size();
209   foreach (GeomSelection aSelec, mySelection) {
210     aSelectionListAttr->append(aSelec.first, aSelec.second);
211   }
212 }
213
214 //********************************************************************
215 void ModuleBase_WidgetMultiSelector::customValidators(
216                                         std::list<ModelAPI_Validator*>& theValidators,
217                                         std::list<std::list<std::string> >& theArguments) const
218 {
219   return;
220   std::list<std::string> anArguments;
221
222   theValidators.push_back(myShapeValidator);
223   if (true/*myIsUseChoice*/) {
224     QString aType = myTypeCombo->currentText();
225     anArguments.push_back(validatorType(aType));
226   }
227   else {
228     for(int i = 0, aCount = myTypeCombo->count(); i < aCount; i++) {
229       anArguments.push_back(validatorType(myTypeCombo->itemText(i)));
230     }
231   }
232   theArguments.push_back(anArguments);
233 }
234
235 //********************************************************************
236 bool ModuleBase_WidgetMultiSelector::acceptSubShape(const TopoDS_Shape& theShape) const
237 {
238   bool aValid = true;
239   if (theShape.IsNull()) {
240     aValid = true; // do not check the shape type if the shape is empty
241     // extrusion uses a sketch object selectected in Object browser
242   }
243   else {
244     aValid = false;
245     TopAbs_ShapeEnum aShapeType = theShape.ShapeType();
246     if (myTypeCombo->count() > 1) {
247       TopAbs_ShapeEnum aType = ModuleBase_Tools::shapeType(myTypeCombo->currentText());
248       aValid = aShapeType == aType;
249     }
250     else {
251       for(int i = 0, aCount = myTypeCombo->count(); i < aCount && !aValid; i++) {
252         TopAbs_ShapeEnum aType = ModuleBase_Tools::shapeType(myTypeCombo->itemText(i));
253         aValid = aShapeType == aType;
254       }
255     }
256   }
257   return aValid;
258 }
259
260 //********************************************************************
261 bool ModuleBase_WidgetMultiSelector::setSelection(const QList<ModuleBase_ViewerPrs>& theValues,
262                                                   int& thePosition)
263 {
264   if (thePosition < 0)
265     return false;
266
267   QList<ModuleBase_ViewerPrs>::const_iterator anIt = theValues.begin(), aLast = theValues.end();
268   bool isDone = false;
269   for (int i = thePosition; i < theValues.size(); i++) {
270     ModuleBase_ViewerPrs aValue = theValues[i];
271     bool aProcessed = false;
272     if (isValidSelection(aValue)) {
273       aProcessed = setSelectionCustom(aValue);
274     }
275     // if there is at least one set, the result is true
276     isDone = isDone || aProcessed;
277     // when an object, which do not satisfy the validating process, stop set selection
278     if (!aProcessed)
279       break;
280     else
281       thePosition++;
282   }
283   if (isDone) {
284     updateObject(myFeature);
285     // this emit is necessary to call store/restore method an restore type of selection
286     emit valuesChanged();
287   }
288   return isDone;
289 }
290
291 //********************************************************************
292 bool ModuleBase_WidgetMultiSelector::setSelectionCustom(const ModuleBase_ViewerPrs& thePrs)
293 {
294   TopoDS_Shape aShape = thePrs.shape();
295   if (!acceptSubShape(aShape))
296     return false;
297
298   ResultPtr aResult;
299   if (!thePrs.owner().IsNull()) {
300     ObjectPtr anObject = myWorkshop->selection()->getSelectableObject(thePrs.owner());
301     aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
302   }
303   else {
304     aResult = std::dynamic_pointer_cast<ModelAPI_Result>(thePrs.object());
305   }
306
307
308   if (myFeature) {
309     // We can not select a result of our feature
310     const std::list<ResultPtr>& aResList = myFeature->results();
311     std::list<ResultPtr>::const_iterator aIt;
312     bool isSkipSelf = false;
313     for (aIt = aResList.cbegin(); aIt != aResList.cend(); ++aIt) {
314       if ((*aIt) == aResult) {
315         isSkipSelf = true;
316         break;
317       }
318     }
319     if(isSkipSelf)
320       return false;
321   }
322
323   // if the result has the similar shap as the parameter shape, just the context is set to the
324   // selection list attribute.
325   DataPtr aData = myFeature->data();
326   AttributeSelectionListPtr aSelectionListAttr = 
327     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
328
329   const TopoDS_Shape& aTDSShape = thePrs.shape();
330   // if only result is selected, an empty shape is set to the model
331   if (aTDSShape.IsNull()) {
332     aSelectionListAttr->append(aResult, GeomShapePtr());
333   }
334   else {
335     GeomShapePtr aShape(new GeomAPI_Shape());
336     aShape->setImpl(new TopoDS_Shape(aTDSShape));
337     // We can not select a result of our feature
338     if (aShape->isEqual(aResult->shape()))
339       aSelectionListAttr->append(aResult, GeomShapePtr());
340     else
341       aSelectionListAttr->append(aResult, aShape);
342   }
343   return true;
344 }
345
346 //********************************************************************
347 QList<QWidget*> ModuleBase_WidgetMultiSelector::getControls() const
348 {
349   QList<QWidget*> result;
350   //result << myTypeCombo;
351   result << myListControl;
352   return result;
353 }
354
355 //********************************************************************
356 bool ModuleBase_WidgetMultiSelector::eventFilter(QObject* theObj, QEvent* theEvent)
357 {
358   //TODO: Remove maybe?
359   return ModuleBase_ModelWidget::eventFilter(theObj, theEvent);
360 }
361
362 //********************************************************************
363 void ModuleBase_WidgetMultiSelector::onSelectionTypeChanged()
364 {
365   activateShapeSelection(true);
366   activateFilters(myWorkshop, true);
367   QList<ModuleBase_ViewerPrs> anEmptyList;
368   // This method will call Selection changed event which will call onSelectionChanged
369   // To clear mySelection, myListControl and storeValue()
370   // So, we don't need to call it
371   myWorkshop->setSelected(anEmptyList);
372 }
373
374 //********************************************************************
375 void ModuleBase_WidgetMultiSelector::onSelectionChanged()
376 {
377   QList<ModuleBase_ViewerPrs> aSelected = getSelectedEntitiesOrObjects(myWorkshop->selection());
378
379   DataPtr aData = myFeature->data();
380   AttributeSelectionListPtr aSelectionListAttr = 
381     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
382
383   aSelectionListAttr->clear();
384   if (aSelected.size() > 0) {
385     foreach (ModuleBase_ViewerPrs aPrs, aSelected) {
386       if (isValidSelection(aPrs)) {
387         setSelectionCustom(aPrs);
388       }
389     }
390   }
391   emit valuesChanged();
392   // the updateObject method should be called to flush the updated sigal. The workshop listens it,
393   // calls validators for the feature and, as a result, updates the Apply button state.
394   updateObject(myFeature);
395
396   // Set focus to List control in order to make possible 
397   // to use Tab key for transfer the focus to next widgets
398   myListControl->setCurrentRow(myListControl->model()->rowCount() - 1);
399   myListControl->setFocus();
400 }
401
402 //********************************************************************
403 void ModuleBase_WidgetMultiSelector::setCurrentShapeType(const TopAbs_ShapeEnum theShapeType)
404 {
405   QString aShapeTypeName;
406   
407   for (int idx = 0; idx < myTypeCombo->count(); ++idx) {
408     aShapeTypeName = myTypeCombo->itemText(idx);
409     TopAbs_ShapeEnum aRefType = ModuleBase_Tools::shapeType(aShapeTypeName);
410     if(aRefType == theShapeType && idx != myTypeCombo->currentIndex()) {
411       activateShapeSelection(false);
412       activateFilters(myWorkshop, false);
413       bool isBlocked = myTypeCombo->blockSignals(true);
414       myTypeCombo->setCurrentIndex(idx);
415       myTypeCombo->blockSignals(isBlocked);
416
417       activateShapeSelection(true);
418       activateFilters(myWorkshop, true);
419       break;
420     }
421   }
422 }
423
424 void ModuleBase_WidgetMultiSelector::activateShapeSelection(const bool isActivated)
425 {
426   ModuleBase_IViewer* aViewer = myWorkshop->viewer();
427
428   if (isActivated) {
429     QString aNewType = myTypeCombo->currentText();
430     QIntList aList;
431     if (true /*myIsUseChoice*/) {
432       aList.append(ModuleBase_Tools::shapeType(aNewType));
433     }
434     else {
435       for(int i = 0, aCount = myTypeCombo->count(); i < aCount; i++)
436         aList.append(ModuleBase_Tools::shapeType(myTypeCombo->itemText(i)));
437     }
438     myWorkshop->activateSubShapesSelection(aList);
439   } else {
440     myWorkshop->deactivateSubShapesSelection();
441   }
442 }
443
444 QList<ModuleBase_ViewerPrs> ModuleBase_WidgetMultiSelector::getAttributeSelection() const
445 {
446   QList<ModuleBase_ViewerPrs> aSelected;
447   // Restore selection in the viewer by the attribute selection list
448   if(myFeature) {
449     DataPtr aData = myFeature->data();
450     AttributeSelectionListPtr aListAttr = 
451       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
452     if (aListAttr) {
453       for (int i = 0; i < aListAttr->size(); i++) {
454         AttributeSelectionPtr anAttr = aListAttr->value(i);
455         ResultPtr anObject = anAttr->context();
456         if (anObject.get()) {
457           TopoDS_Shape aShape;
458           std::shared_ptr<GeomAPI_Shape> aShapePtr = anAttr->value();
459           if (aShapePtr.get()) {
460             aShape = aShapePtr->impl<TopoDS_Shape>();
461           }
462           aSelected.append(ModuleBase_ViewerPrs(anObject, aShape, NULL));
463         }
464       }
465     }
466   }
467   return aSelected;
468 }
469
470 //********************************************************************
471 void ModuleBase_WidgetMultiSelector::updateSelectionList(AttributeSelectionListPtr theList)
472 {
473   myListControl->clear();
474   for (int i = 0; i < theList->size(); i++) {
475     AttributeSelectionPtr aAttr = theList->value(i);
476     myListControl->addItem(aAttr->namingName().c_str());
477   }
478   // We have to call repaint because sometimes the List control is not updated
479   myListControl->repaint();
480 }
481
482 //********************************************************************
483 std::string ModuleBase_WidgetMultiSelector::validatorType(const QString& theType) const
484 {
485   std::string aType;
486
487   if (theType == "Vertices")
488     aType = "vertex";
489   else if (theType == "Edges")
490     aType = "edge";
491   else if (theType == "Faces")
492     aType = "face";
493   else if (theType == "Solids")
494     aType = "solid";
495
496   return aType;
497 }
498
499 //********************************************************************
500 void ModuleBase_WidgetMultiSelector::onCopyItem()
501 {
502   QList<QListWidgetItem*> aItems = myListControl->selectedItems();
503   QString aRes;
504   foreach(QListWidgetItem* aItem, aItems) {
505     if (!aRes.isEmpty())
506       aRes += "\n";
507     aRes += aItem->text();
508   }
509   if (!aRes.isEmpty()) {
510     QClipboard *clipboard = QApplication::clipboard();
511     clipboard->setText(aRes);
512   }
513 }
514
515 //********************************************************************
516 void ModuleBase_WidgetMultiSelector::onListSelection()
517 {
518   QList<QListWidgetItem*> aItems = myListControl->selectedItems();
519   myCopyAction->setEnabled(!aItems.isEmpty());
520 }
521