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];
234 bool aProcessed = false;
235 if (isValidSelection(aValue)) {
236 aProcessed = setSelectionCustom(aValue);
238 // if there is at least one set, the result is true
239 isDone = isDone || aProcessed;
240 // when an object, which do not satisfy the validating process, stop set selection
245 updateObject(myFeature);
246 // this emit is necessary to call store/restore method an restore type of selection
247 emit valuesChanged();
252 //********************************************************************
253 bool ModuleBase_WidgetMultiSelector::setSelectionCustom(const ModuleBase_ViewerPrs& thePrs)
255 TopoDS_Shape aShape = thePrs.shape();
256 if ((myTypeCombo->count() > 1) && (!aShape.IsNull())) {
257 TopAbs_ShapeEnum aType = ModuleBase_Tools::shapeType(myTypeCombo->currentText());
258 if (aShape.ShapeType() != aType)
262 if (!thePrs.owner().IsNull()) {
263 ObjectPtr anObject = myWorkshop->selection()->getSelectableObject(thePrs.owner());
264 aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
267 aResult = std::dynamic_pointer_cast<ModelAPI_Result>(thePrs.object());
272 // We can not select a result of our feature
273 const std::list<ResultPtr>& aResList = myFeature->results();
274 std::list<ResultPtr>::const_iterator aIt;
275 bool isSkipSelf = false;
276 for (aIt = aResList.cbegin(); aIt != aResList.cend(); ++aIt) {
277 if ((*aIt) == aResult) {
286 // if the result has the similar shap as the parameter shape, just the context is set to the
287 // selection list attribute.
288 DataPtr aData = myFeature->data();
289 AttributeSelectionListPtr aSelectionListAttr =
290 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
292 const TopoDS_Shape& aTDSShape = thePrs.shape();
293 // if only result is selected, an empty shape is set to the model
294 if (aTDSShape.IsNull()) {
295 aSelectionListAttr->append(aResult, GeomShapePtr());
298 GeomShapePtr aShape(new GeomAPI_Shape());
299 aShape->setImpl(new TopoDS_Shape(aTDSShape));
300 // We can not select a result of our feature
301 if (aShape->isEqual(aResult->shape()))
302 aSelectionListAttr->append(aResult, GeomShapePtr());
304 aSelectionListAttr->append(aResult, aShape);
309 //********************************************************************
310 QList<QWidget*> ModuleBase_WidgetMultiSelector::getControls() const
312 QList<QWidget*> result;
313 //result << myTypeCombo;
314 result << myListControl;
318 //********************************************************************
319 bool ModuleBase_WidgetMultiSelector::eventFilter(QObject* theObj, QEvent* theEvent)
321 //TODO: Remove maybe?
322 return ModuleBase_ModelWidget::eventFilter(theObj, theEvent);
325 //********************************************************************
326 void ModuleBase_WidgetMultiSelector::onSelectionTypeChanged()
328 activateShapeSelection(true);
329 activateFilters(myWorkshop, true);
330 QList<ModuleBase_ViewerPrs> anEmptyList;
331 // This method will call Selection changed event which will call onSelectionChanged
332 // To clear mySelection, myListControl and storeValue()
333 // So, we don't need to call it
334 myWorkshop->setSelected(anEmptyList);
337 //********************************************************************
338 void ModuleBase_WidgetMultiSelector::onSelectionChanged()
340 QList<ModuleBase_ViewerPrs> aSelected = getSelectedEntitiesOrObjects(myWorkshop->selection());
342 DataPtr aData = myFeature->data();
343 AttributeSelectionListPtr aSelectionListAttr =
344 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
346 aSelectionListAttr->clear();
347 if (aSelected.size() > 0) {
348 foreach (ModuleBase_ViewerPrs aPrs, aSelected) {
349 if (isValidSelection(aPrs)) {
350 setSelectionCustom(aPrs);
354 emit valuesChanged();
355 // the updateObject method should be called to flush the updated sigal. The workshop listens it,
356 // calls validators for the feature and, as a result, updates the Apply button state.
357 updateObject(myFeature);
359 // Set focus to List control in order to make possible
360 // to use Tab key for transfer the focus to next widgets
361 myListControl->setCurrentRow(myListControl->model()->rowCount() - 1);
362 myListControl->setFocus();
365 //********************************************************************
366 void ModuleBase_WidgetMultiSelector::setCurrentShapeType(const TopAbs_ShapeEnum theShapeType)
368 QString aShapeTypeName;
370 for (int idx = 0; idx < myTypeCombo->count(); ++idx) {
371 aShapeTypeName = myTypeCombo->itemText(idx);
372 TopAbs_ShapeEnum aRefType = ModuleBase_Tools::shapeType(aShapeTypeName);
373 if(aRefType == theShapeType && idx != myTypeCombo->currentIndex()) {
374 activateShapeSelection(false);
375 activateFilters(myWorkshop, false);
376 bool isBlocked = myTypeCombo->blockSignals(true);
377 myTypeCombo->setCurrentIndex(idx);
378 myTypeCombo->blockSignals(isBlocked);
380 activateShapeSelection(true);
381 activateFilters(myWorkshop, true);
387 void ModuleBase_WidgetMultiSelector::activateShapeSelection(const bool isActivated)
389 ModuleBase_IViewer* aViewer = myWorkshop->viewer();
392 QString aNewType = myTypeCombo->currentText();
394 aList.append(ModuleBase_Tools::shapeType(aNewType));
395 myWorkshop->activateSubShapesSelection(aList);
397 myWorkshop->deactivateSubShapesSelection();
401 QList<ModuleBase_ViewerPrs> ModuleBase_WidgetMultiSelector::getAttributeSelection() const
403 QList<ModuleBase_ViewerPrs> aSelected;
404 // Restore selection in the viewer by the attribute selection list
406 DataPtr aData = myFeature->data();
407 AttributeSelectionListPtr aListAttr =
408 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
410 for (int i = 0; i < aListAttr->size(); i++) {
411 AttributeSelectionPtr anAttr = aListAttr->value(i);
412 ResultPtr anObject = anAttr->context();
413 if (anObject.get()) {
415 std::shared_ptr<GeomAPI_Shape> aShapePtr = anAttr->value();
416 if (aShapePtr.get()) {
417 aShape = aShapePtr->impl<TopoDS_Shape>();
419 aSelected.append(ModuleBase_ViewerPrs(anObject, aShape, NULL));
427 //********************************************************************
428 void ModuleBase_WidgetMultiSelector::updateSelectionList(AttributeSelectionListPtr theList)
430 myListControl->clear();
431 for (int i = 0; i < theList->size(); i++) {
432 AttributeSelectionPtr aAttr = theList->value(i);
433 myListControl->addItem(aAttr->namingName().c_str());
435 // We have to call repaint because sometimes the List control is not updated
436 myListControl->repaint();
439 //********************************************************************
440 void ModuleBase_WidgetMultiSelector::onCopyItem()
442 QList<QListWidgetItem*> aItems = myListControl->selectedItems();
444 foreach(QListWidgetItem* aItem, aItems) {
447 aRes += aItem->text();
449 if (!aRes.isEmpty()) {
450 QClipboard *clipboard = QApplication::clipboard();
451 clipboard->setText(aRes);
455 //********************************************************************
456 void ModuleBase_WidgetMultiSelector::onListSelection()
458 QList<QListWidgetItem*> aItems = myListControl->selectedItems();
459 myCopyAction->setEnabled(!aItems.isEmpty());