1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
4 * ModuleBase_WidgetMultiSelector.cpp
6 * Created on: Aug 28, 2014
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>
18 #include <GeomValidators_ShapeType.h>
20 #include <ModelAPI_Data.h>
21 #include <ModelAPI_Object.h>
23 #include <Config_WidgetAPI.h>
25 #include <QGridLayout>
27 #include <QListWidget>
33 #include <QApplication>
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)
46 QGridLayout* aMainLay = new QGridLayout(this);
47 ModuleBase_Tools::adjustMargins(aMainLay);
49 QLabel* aTypeLabel = new QLabel(tr("Type"), this);
50 aMainLay->addWidget(aTypeLabel, 0, 0);
52 myTypeCombo = new QComboBox(this);
53 // There is no sence to paramerize list of types while we can not parametrize selection mode
55 myShapeValidator = new GeomValidators_ShapeType();
57 std::string aPropertyTypes = theData->getProperty("type_choice");
58 QString aTypesStr = aPropertyTypes.c_str();
59 QStringList aShapeTypes = aTypesStr.split(' ');
61 myTypeCombo->addItems(aShapeTypes);
62 aMainLay->addWidget(myTypeCombo, 0, 1);
63 // if the xml definition contains one type, the controls to select a type should not be shown
64 if (aShapeTypes.size() == 1) {
65 aTypeLabel->setVisible(false);
66 myTypeCombo->setVisible(false);
69 QLabel* aListLabel = new QLabel(tr("Selected objects:"), this);
70 aMainLay->addWidget(aListLabel, 1, 0);
71 // if the xml definition contains one type, an information label should be shown near to the latest
72 if (aShapeTypes.size() == 1) {
73 QString aLabelText = QString::fromStdString(theData->widgetLabel());
74 QString aLabelIcon = QString::fromStdString(theData->widgetIcon());
75 QLabel* aSelectedLabel = new QLabel(aLabelText, this);
76 if (!aLabelIcon.isEmpty())
77 aSelectedLabel->setPixmap(QPixmap(aLabelIcon));
78 aMainLay->addWidget(aSelectedLabel, 1, 1);
79 aMainLay->setColumnStretch(2, 1);
82 myListControl = new QListWidget(this);
83 aMainLay->addWidget(myListControl, 2, 0, 2, -1);
84 aMainLay->setRowStretch(2, 1);
85 aMainLay->addWidget(new QLabel(this)); //FIXME(sbh)???
86 aMainLay->setRowMinimumHeight(3, 20);
87 this->setLayout(aMainLay);
88 connect(myTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onSelectionTypeChanged()));
90 myCopyAction = new QAction(QIcon(":pictures/copy.png"), tr("Copy"), this);
91 myCopyAction->setShortcut(QKeySequence::Copy);
92 myCopyAction->setEnabled(false);
93 connect(myCopyAction, SIGNAL(triggered(bool)), SLOT(onCopyItem()));
94 myListControl->addAction(myCopyAction);
95 myListControl->setContextMenuPolicy(Qt::ActionsContextMenu);
96 connect(myListControl, SIGNAL(itemSelectionChanged()), SLOT(onListSelection()));
99 ModuleBase_WidgetMultiSelector::~ModuleBase_WidgetMultiSelector()
101 activateShapeSelection(false);
102 activateFilters(myWorkshop, false);
104 delete myShapeValidator;
107 //********************************************************************
108 void ModuleBase_WidgetMultiSelector::activateCustom()
110 ModuleBase_IViewer* aViewer = myWorkshop->viewer();
111 connect(myWorkshop, SIGNAL(selectionChanged()),
112 this, SLOT(onSelectionChanged()),
113 Qt::UniqueConnection);
115 activateShapeSelection(true);
117 // Restore selection in the viewer by the attribute selection list
118 myWorkshop->setSelected(getAttributeSelection());
120 activateFilters(myWorkshop, true);
123 //********************************************************************
124 void ModuleBase_WidgetMultiSelector::deactivate()
126 disconnect(myWorkshop, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged()));
127 activateShapeSelection(false);
128 activateFilters(myWorkshop, false);
131 //********************************************************************
132 bool ModuleBase_WidgetMultiSelector::storeValueCustom() const
134 // the value is stored on the selection changed signal processing
135 // A rare case when plugin was not loaded.
138 DataPtr aData = myFeature->data();
139 AttributeSelectionListPtr aSelectionListAttr =
140 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
142 if (aSelectionListAttr) {
144 TopAbs_ShapeEnum aCurrentType =
145 ModuleBase_Tools::shapeType(myTypeCombo->currentText());
146 aSelectionListAttr->setSelectionType(myTypeCombo->currentText().toStdString());
151 //********************************************************************
152 bool ModuleBase_WidgetMultiSelector::restoreValue()
154 // A rare case when plugin was not loaded.
157 DataPtr aData = myFeature->data();
158 AttributeSelectionListPtr aSelectionListAttr =
159 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
161 if (aSelectionListAttr) {
162 // Restore shape type
163 if (!aSelectionListAttr->selectionType().empty())
164 setCurrentShapeType(ModuleBase_Tools::shapeType(aSelectionListAttr->selectionType().c_str()));
165 updateSelectionList(aSelectionListAttr);
171 //********************************************************************
172 void ModuleBase_WidgetMultiSelector::storeAttributeValue()
174 DataPtr aData = myFeature->data();
175 AttributeSelectionListPtr aSelectionListAttr =
176 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
177 if (aSelectionListAttr.get() == NULL)
180 mySelectionType = aSelectionListAttr->selectionType();
182 int aSize = aSelectionListAttr->size();
183 for (int i = 0; i < aSelectionListAttr->size(); i++) {
184 AttributeSelectionPtr aSelectAttr = aSelectionListAttr->value(i);
185 mySelection.append(GeomSelection(aSelectAttr->context(), aSelectAttr->value()));
189 //********************************************************************
190 void ModuleBase_WidgetMultiSelector::restoreAttributeValue(bool/* theValid*/)
192 DataPtr aData = myFeature->data();
193 AttributeSelectionListPtr aSelectionListAttr =
194 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
195 if (aSelectionListAttr.get() == NULL)
197 aSelectionListAttr->clear();
200 aSelectionListAttr->setSelectionType(mySelectionType);
202 // Store selection in the attribute
203 int aSize = mySelection.size();
204 foreach (GeomSelection aSelec, mySelection) {
205 aSelectionListAttr->append(aSelec.first, aSelec.second);
209 //********************************************************************
210 void ModuleBase_WidgetMultiSelector::customValidators(
211 std::list<ModelAPI_Validator*>& theValidators,
212 std::list<std::list<std::string> >& theArguments) const
214 std::list<std::string> anArguments;
216 theValidators.push_back(myShapeValidator);
217 QString aType = myTypeCombo->currentText();
218 anArguments.push_back(aType.toStdString().c_str());
219 theArguments.push_back(anArguments);
222 //********************************************************************
223 bool ModuleBase_WidgetMultiSelector::setSelection(const QList<ModuleBase_ViewerPrs>& theValues,
229 QList<ModuleBase_ViewerPrs>::const_iterator anIt = theValues.begin(), aLast = theValues.end();
231 for (int i = thePosition; i < theValues.size(); i++) {
232 ModuleBase_ViewerPrs aValue = theValues[i];
233 bool aProcessed = false;
234 if (isValidSelection(aValue)) {
235 aProcessed = setSelectionCustom(aValue);
237 // if there is at least one set, the result is true
238 isDone = isDone || aProcessed;
239 // when an object, which do not satisfy the validating process, stop set selection
246 updateObject(myFeature);
247 // this emit is necessary to call store/restore method an restore type of selection
248 emit valuesChanged();
253 //********************************************************************
254 bool ModuleBase_WidgetMultiSelector::setSelectionCustom(const ModuleBase_ViewerPrs& thePrs)
256 TopoDS_Shape aShape = thePrs.shape();
257 if ((myTypeCombo->count() > 1) && (!aShape.IsNull())) {
258 TopAbs_ShapeEnum aType = ModuleBase_Tools::shapeType(myTypeCombo->currentText());
259 if (aShape.ShapeType() != aType)
263 if (!thePrs.owner().IsNull()) {
264 ObjectPtr anObject = myWorkshop->selection()->getSelectableObject(thePrs.owner());
265 aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
268 aResult = std::dynamic_pointer_cast<ModelAPI_Result>(thePrs.object());
273 // We can not select a result of our feature
274 const std::list<ResultPtr>& aResList = myFeature->results();
275 std::list<ResultPtr>::const_iterator aIt;
276 bool isSkipSelf = false;
277 for (aIt = aResList.cbegin(); aIt != aResList.cend(); ++aIt) {
278 if ((*aIt) == aResult) {
287 // if the result has the similar shap as the parameter shape, just the context is set to the
288 // selection list attribute.
289 DataPtr aData = myFeature->data();
290 AttributeSelectionListPtr aSelectionListAttr =
291 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
293 const TopoDS_Shape& aTDSShape = thePrs.shape();
294 // if only result is selected, an empty shape is set to the model
295 if (aTDSShape.IsNull()) {
296 aSelectionListAttr->append(aResult, GeomShapePtr());
299 GeomShapePtr aShape(new GeomAPI_Shape());
300 aShape->setImpl(new TopoDS_Shape(aTDSShape));
301 // We can not select a result of our feature
302 if (aShape->isEqual(aResult->shape()))
303 aSelectionListAttr->append(aResult, GeomShapePtr());
305 aSelectionListAttr->append(aResult, aShape);
310 //********************************************************************
311 QList<QWidget*> ModuleBase_WidgetMultiSelector::getControls() const
313 QList<QWidget*> result;
314 //result << myTypeCombo;
315 result << myListControl;
319 //********************************************************************
320 bool ModuleBase_WidgetMultiSelector::eventFilter(QObject* theObj, QEvent* theEvent)
322 //TODO: Remove maybe?
323 return ModuleBase_ModelWidget::eventFilter(theObj, theEvent);
326 //********************************************************************
327 void ModuleBase_WidgetMultiSelector::onSelectionTypeChanged()
329 activateShapeSelection(true);
330 activateFilters(myWorkshop, true);
331 QList<ModuleBase_ViewerPrs> anEmptyList;
332 // This method will call Selection changed event which will call onSelectionChanged
333 // To clear mySelection, myListControl and storeValue()
334 // So, we don't need to call it
335 myWorkshop->setSelected(anEmptyList);
338 //********************************************************************
339 void ModuleBase_WidgetMultiSelector::onSelectionChanged()
341 QList<ModuleBase_ViewerPrs> aSelected = getSelectedEntitiesOrObjects(myWorkshop->selection());
343 DataPtr aData = myFeature->data();
344 AttributeSelectionListPtr aSelectionListAttr =
345 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
347 aSelectionListAttr->clear();
348 if (aSelected.size() > 0) {
349 foreach (ModuleBase_ViewerPrs aPrs, aSelected) {
350 if (isValidSelection(aPrs)) {
351 setSelectionCustom(aPrs);
355 emit valuesChanged();
356 // the updateObject method should be called to flush the updated sigal. The workshop listens it,
357 // calls validators for the feature and, as a result, updates the Apply button state.
358 updateObject(myFeature);
360 // Set focus to List control in order to make possible
361 // to use Tab key for transfer the focus to next widgets
362 myListControl->setCurrentRow(myListControl->model()->rowCount() - 1);
363 myListControl->setFocus();
366 //********************************************************************
367 void ModuleBase_WidgetMultiSelector::setCurrentShapeType(const TopAbs_ShapeEnum theShapeType)
369 QString aShapeTypeName;
371 for (int idx = 0; idx < myTypeCombo->count(); ++idx) {
372 aShapeTypeName = myTypeCombo->itemText(idx);
373 TopAbs_ShapeEnum aRefType = ModuleBase_Tools::shapeType(aShapeTypeName);
374 if(aRefType == theShapeType && idx != myTypeCombo->currentIndex()) {
375 activateShapeSelection(false);
376 activateFilters(myWorkshop, false);
377 bool isBlocked = myTypeCombo->blockSignals(true);
378 myTypeCombo->setCurrentIndex(idx);
379 myTypeCombo->blockSignals(isBlocked);
381 activateShapeSelection(true);
382 activateFilters(myWorkshop, true);
388 void ModuleBase_WidgetMultiSelector::activateShapeSelection(const bool isActivated)
390 ModuleBase_IViewer* aViewer = myWorkshop->viewer();
393 QString aNewType = myTypeCombo->currentText();
395 aList.append(ModuleBase_Tools::shapeType(aNewType));
396 myWorkshop->activateSubShapesSelection(aList);
398 myWorkshop->deactivateSubShapesSelection();
402 QList<ModuleBase_ViewerPrs> ModuleBase_WidgetMultiSelector::getAttributeSelection() const
404 QList<ModuleBase_ViewerPrs> aSelected;
405 // Restore selection in the viewer by the attribute selection list
407 DataPtr aData = myFeature->data();
408 AttributeSelectionListPtr aListAttr =
409 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
411 for (int i = 0; i < aListAttr->size(); i++) {
412 AttributeSelectionPtr anAttr = aListAttr->value(i);
413 ResultPtr anObject = anAttr->context();
414 if (anObject.get()) {
416 std::shared_ptr<GeomAPI_Shape> aShapePtr = anAttr->value();
417 if (aShapePtr.get()) {
418 aShape = aShapePtr->impl<TopoDS_Shape>();
420 aSelected.append(ModuleBase_ViewerPrs(anObject, aShape, NULL));
428 //********************************************************************
429 void ModuleBase_WidgetMultiSelector::updateSelectionList(AttributeSelectionListPtr theList)
431 myListControl->clear();
432 for (int i = 0; i < theList->size(); i++) {
433 AttributeSelectionPtr aAttr = theList->value(i);
434 myListControl->addItem(aAttr->namingName().c_str());
436 // We have to call repaint because sometimes the List control is not updated
437 myListControl->repaint();
440 //********************************************************************
441 void ModuleBase_WidgetMultiSelector::onCopyItem()
443 QList<QListWidgetItem*> aItems = myListControl->selectedItems();
445 foreach(QListWidgetItem* aItem, aItems) {
448 aRes += aItem->text();
450 if (!aRes.isEmpty()) {
451 QClipboard *clipboard = QApplication::clipboard();
452 clipboard->setText(aRes);
456 //********************************************************************
457 void ModuleBase_WidgetMultiSelector::onListSelection()
459 QList<QListWidgetItem*> aItems = myListControl->selectedItems();
460 myCopyAction->setEnabled(!aItems.isEmpty());