1 // Copyright (C) 2014-2017 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
21 #include <ModuleBase_WidgetMultiSelector.h>
22 #include <ModuleBase_WidgetShapeSelector.h>
23 #include <ModuleBase_ISelection.h>
24 #include <ModuleBase_IWorkshop.h>
25 #include <ModuleBase_IViewer.h>
26 #include <ModuleBase_Tools.h>
27 #include <ModuleBase_Definitions.h>
28 #include <ModuleBase_IModule.h>
29 #include <ModuleBase_ViewerPrs.h>
30 #include <ModuleBase_IconFactory.h>
31 #include <ModuleBase_Events.h>
32 #include <ModuleBase_ChoiceCtrl.h>
34 #include <ModelAPI_Data.h>
35 #include <ModelAPI_Object.h>
36 #include <ModelAPI_AttributeSelectionList.h>
37 #include <ModelAPI_AttributeRefList.h>
38 #include <ModelAPI_AttributeRefAttrList.h>
39 #include <ModelAPI_Tools.h>
40 #include <ModelAPI_Events.h>
42 #include <Config_WidgetAPI.h>
44 #include <QGridLayout>
46 #include <QListWidget>
52 #include <QApplication>
55 #include <QMainWindow>
60 const int ATTRIBUTE_SELECTION_INDEX_ROLE = Qt::UserRole + 1;
62 //#define DEBUG_UNDO_REDO
65 * Customization of a List Widget to make it to be placed on full width of container
67 class CustomListWidget : public QListWidget
71 /// \param theParent a parent widget
72 CustomListWidget( QWidget* theParent )
73 : QListWidget( theParent )
77 /// Redefinition of virtual method
78 virtual QSize sizeHint() const
80 int aHeight = 2*QFontMetrics( font() ).height();
81 QSize aSize = QListWidget::sizeHint();
82 return QSize( aSize.width(), aHeight );
85 /// Redefinition of virtual method
86 virtual QSize minimumSizeHint() const
88 int aHeight = 4/*2*/*QFontMetrics( font() ).height();
89 QSize aSize = QListWidget::minimumSizeHint();
90 return QSize( aSize.width(), aHeight );
94 // The code is necessary only for Linux because
95 //it can not update viewport on widget resize
97 void resizeEvent(QResizeEvent* theEvent)
99 QListWidget::resizeEvent(theEvent);
100 QTimer::singleShot(5, viewport(), SLOT(repaint()));
105 #ifdef DEBUG_UNDO_REDO
106 void printHistoryInfo(const QString& theMethodName, int theCurrentHistoryIndex,
107 QList<QList<std::shared_ptr<ModuleBase_ViewerPrs> > > theSelectedHistoryValues)
110 for (int i = 0; i < theSelectedHistoryValues.size(); i++)
111 aSizes.append(QString::number(theSelectedHistoryValues[i].size()));
113 std::cout << theMethodName.toStdString()
114 << " current = " << theCurrentHistoryIndex
115 << " size(history) = " << theSelectedHistoryValues.size()
116 << " (" << aSizes.join(", ").toStdString() << ")"
122 QStringList getIconsList(const QStringList& theNames)
125 foreach (QString aName, theNames) {
126 QString aUName = aName.toUpper();
127 if ((aUName == "VERTICES") || (aUName == "VERTEX"))
128 aIcons << ":pictures/vertex32.png";
129 else if ((aUName == "EDGES") || (aUName == "EDGE"))
130 aIcons << ":pictures/edge32.png";
131 else if ((aUName == "FACES") || (aUName == "FACE"))
132 aIcons << ":pictures/face32.png";
133 else if ((aUName == "SOLIDS") || (aUName == "SOLID"))
134 aIcons << ":pictures/solid32.png";
141 ModuleBase_WidgetMultiSelector::ModuleBase_WidgetMultiSelector(QWidget* theParent,
142 ModuleBase_IWorkshop* theWorkshop,
143 const Config_WidgetAPI* theData)
144 : ModuleBase_WidgetSelector(theParent, theWorkshop, theData),
145 myIsSetSelectionBlocked(false), myCurrentHistoryIndex(-1)
147 std::string aPropertyTypes = theData->getProperty("type_choice");
148 QString aTypesStr = aPropertyTypes.c_str();
149 myShapeTypes = aTypesStr.split(' ', QString::SkipEmptyParts);
150 myIsUseChoice = theData->getBooleanAttribute("use_choice", false);
152 QGridLayout* aMainLay = new QGridLayout(this);
153 ModuleBase_Tools::adjustMargins(aMainLay);
155 //QLabel* aTypeLabel = new QLabel(tr("Type"), this);
156 //aMainLay->addWidget(aTypeLabel, 0, 0);
158 //myTypeCombo = new QComboBox(this);
159 QStringList aIconsList = getIconsList(myShapeTypes);
160 myTypeCtrl = new ModuleBase_ChoiceCtrl(this, myShapeTypes, aIconsList);
161 myTypeCtrl->setLabel(tr("Type"));
162 myTypeCtrl->setValue(0);
164 // There is no sense to parameterize list of types while we can not parameterize selection mode
165 //if (!aShapeTypes.empty())
166 // myTypeCombo->addItems(aShapeTypes);
167 aMainLay->addWidget(myTypeCtrl, 0, 0, 1, 2);
168 // if the xml definition contains one type, the controls to select a type should not be shown
169 if (myShapeTypes.size() <= 1 || !myIsUseChoice) {
170 myTypeCtrl->setVisible(false);
173 QString aLabelText = translate(theData->getProperty("label"));
174 QLabel* aListLabel = new QLabel(aLabelText, this);
175 aMainLay->addWidget(aListLabel, 1, 0);
176 // if the xml definition contains one type, an information label
177 // should be shown near to the latest
178 if (myShapeTypes.size() <= 1) {
179 QString aLabelIcon = QString::fromStdString(theData->widgetIcon());
180 if (!aLabelIcon.isEmpty()) {
181 QLabel* aSelectedLabel = new QLabel("", this);
182 aSelectedLabel->setPixmap(ModuleBase_IconFactory::loadPixmap(aLabelIcon));
183 aMainLay->addWidget(aSelectedLabel, 1, 1);
185 aMainLay->setColumnStretch(2, 1);
188 QString aToolTip = QString::fromStdString(theData->widgetTooltip());
189 myListControl = new CustomListWidget(this);
190 QString anObjName = QString::fromStdString(attributeID());
191 myListControl->setObjectName(anObjName);
192 myListControl->setToolTip(aToolTip);
193 myListControl->setSelectionMode(QAbstractItemView::ExtendedSelection);
195 aMainLay->addWidget(myListControl, 2, 0, 1, -1);
196 aMainLay->setRowStretch(2, 1);
197 //aMainLay->addWidget(new QLabel(this)); //FIXME(sbh)???
198 //aMainLay->setRowMinimumHeight(3, 20);
199 //this->setLayout(aMainLay);
200 connect(myTypeCtrl, SIGNAL(valueChanged(int)), this, SLOT(onSelectionTypeChanged()));
202 myCopyAction = ModuleBase_Tools::createAction(QIcon(":pictures/copy.png"), tr("Copy"),
203 myWorkshop->desktop(), this, SLOT(onCopyItem()));
204 myCopyAction->setShortcut(QKeySequence::Copy);
205 myCopyAction->setEnabled(false);
206 myListControl->addAction(myCopyAction);
208 myDeleteAction = ModuleBase_Tools::createAction(QIcon(":pictures/delete.png"), tr("Delete"),
209 myWorkshop->desktop(), this, SLOT(onDeleteItem()));
210 myDeleteAction->setEnabled(false);
211 myListControl->addAction(myDeleteAction);
213 myListControl->setContextMenuPolicy(Qt::ActionsContextMenu);
214 connect(myListControl, SIGNAL(itemSelectionChanged()), SLOT(onListSelection()));
216 myIsNeutralPointClear = theData->getBooleanAttribute("clear_in_neutral_point", true);
219 ModuleBase_WidgetMultiSelector::~ModuleBase_WidgetMultiSelector()
223 //********************************************************************
224 void ModuleBase_WidgetMultiSelector::activateCustom()
226 ModuleBase_WidgetSelector::activateCustom();
228 myWorkshop->module()->activateCustomPrs(myFeature,
229 ModuleBase_IModule::CustomizeHighlightedObjects, true);
230 clearSelectedHistory();
231 myWorkshop->updateCommandStatus();
234 //********************************************************************
235 void ModuleBase_WidgetMultiSelector::deactivate()
237 ModuleBase_WidgetSelector::deactivate();
239 myWorkshop->module()->deactivateCustomPrs(ModuleBase_IModule::CustomizeHighlightedObjects, true);
240 clearSelectedHistory();
241 myWorkshop->updateCommandStatus();
244 //********************************************************************
245 bool ModuleBase_WidgetMultiSelector::storeValueCustom()
247 // the value is stored on the selection changed signal processing
248 // A rare case when plugin was not loaded.
252 AttributePtr anAttribute = myFeature->data()->attribute(attributeID());
253 std::string aType = anAttribute->attributeType();
254 if (aType == ModelAPI_AttributeSelectionList::typeId()) {
255 AttributeSelectionListPtr aSelectionListAttr = myFeature->data()->selectionList(attributeID());
256 //aSelectionListAttr->setSelectionType(myTypeCombo->currentText().toStdString());
257 aSelectionListAttr->setSelectionType(myTypeCtrl->textValue().toStdString());
262 //********************************************************************
263 bool ModuleBase_WidgetMultiSelector::restoreValueCustom()
265 // A rare case when plugin was not loaded.
269 AttributePtr anAttribute = myFeature->data()->attribute(attributeID());
270 std::string aType = anAttribute->attributeType();
271 if (aType == ModelAPI_AttributeSelectionList::typeId()) {
272 AttributeSelectionListPtr aSelectionListAttr = myFeature->data()->selectionList(attributeID());
273 // Restore shape type
274 std::string aSelectionType = aSelectionListAttr->selectionType().c_str();
275 if (!aSelectionType.empty())
276 setCurrentShapeType(ModuleBase_Tools::shapeType(aSelectionType.c_str()));
278 updateSelectionList();
282 //********************************************************************
283 bool ModuleBase_WidgetMultiSelector::setSelection(QList<ModuleBase_ViewerPrsPtr>& theValues,
284 const bool theToValidate)
286 if (myIsSetSelectionBlocked)
289 AttributeSelectionListPtr aSelectionListAttr;
290 if (attribute()->attributeType() == ModelAPI_AttributeSelectionList::typeId())
291 aSelectionListAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(attribute());
292 if (aSelectionListAttr.get())
293 aSelectionListAttr->cashValues(true);
295 /// remove unused objects from the model attribute.
296 /// It should be performed before new attributes append.
297 bool isDone = removeUnusedAttributeObjects(theValues);
299 QList<ModuleBase_ViewerPrsPtr> anInvalidValues;
300 QList<ModuleBase_ViewerPrsPtr> anAttributeValues;
301 QList<ModuleBase_ViewerPrsPtr>::const_iterator anIt = theValues.begin(), aLast = theValues.end();
302 for (; anIt != aLast; anIt++) {
303 ModuleBase_ViewerPrsPtr aValue = *anIt;
304 // do not validate and append to attribute selection presentation if it exists in the attribute
307 getGeomSelection(aValue, anObject, aShape);
308 if (ModuleBase_Tools::hasObject(attribute(), anObject, aShape, myWorkshop, myIsInValidate)) {
309 anAttributeValues.append(aValue);
312 if (theToValidate && !isValidInFilters(aValue))
313 anInvalidValues.append(aValue);
315 bool aHasInvalidValues = anInvalidValues.size() > 0;
317 for (anIt = theValues.begin(); anIt != aLast; anIt++) {
318 ModuleBase_ViewerPrsPtr aValue = *anIt;
319 bool aProcessed = false;
320 if ((aHasInvalidValues && anInvalidValues.contains(aValue)) ||
321 anAttributeValues.contains(aValue))
323 aProcessed = setSelectionCustom(aValue); /// it is not optimal as hasObject() is already checked
324 // if there is at least one set, the result is true
325 isDone = isDone || aProcessed;
327 // updateObject - to update/redisplay feature
328 // it is commented in order to perfom it outside the method
330 //updateObject(myFeature);
331 // this emit is necessary to call store/restore method an restore type of selection
332 //emit valuesChanged();
335 if (aSelectionListAttr.get())
336 aSelectionListAttr->cashValues(false);
339 if (!anInvalidValues.empty())
340 theValues.append(anInvalidValues);
342 if (isDone) // may be the feature's result is not displayed, but attributes should be
343 myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeArguments,
344 true);/// hope that something is redisplayed by object updated
349 //********************************************************************
350 void ModuleBase_WidgetMultiSelector::getHighlighted(QList<ModuleBase_ViewerPrsPtr>& theValues)
352 std::set<int> anAttributeIds;
353 getSelectedAttributeIndices(anAttributeIds);
354 if (!anAttributeIds.empty())
355 convertIndicesToViewerSelection(anAttributeIds, theValues);
358 //********************************************************************
359 bool ModuleBase_WidgetMultiSelector::canProcessAction(ModuleBase_ActionType theActionType,
360 bool& isActionEnabled)
362 isActionEnabled = false;
363 bool aCanProcess = false;
364 switch (theActionType) {
368 isActionEnabled = theActionType == ActionUndo ? myCurrentHistoryIndex > 0
369 : (mySelectedHistoryValues.size() > 0 &&
370 myCurrentHistoryIndex < mySelectedHistoryValues.size() - 1);
379 //********************************************************************
380 bool ModuleBase_WidgetMultiSelector::processAction(ModuleBase_ActionType theActionType)
382 switch (theActionType) {
385 if (theActionType == ActionUndo)
386 myCurrentHistoryIndex--;
388 myCurrentHistoryIndex++;
389 QList<ModuleBase_ViewerPrsPtr> aSelected = mySelectedHistoryValues[myCurrentHistoryIndex];
390 // equal vertices should not be used here
391 ModuleBase_ISelection::filterSelectionOnEqualPoints(aSelected);
392 bool isDone = setSelection(aSelected,
393 false /*need not validate because values already was in list*/);
394 updateOnSelectionChanged(isDone);
396 myWorkshop->updateCommandStatus();
397 #ifdef DEBUG_UNDO_REDO
398 printHistoryInfo(QString("processAction %1").arg(theActionType == ActionUndo ? "Undo"
399 : "Redo"), myCurrentHistoryIndex, mySelectedHistoryValues);
404 return ModuleBase_ModelWidget::processAction(theActionType);
408 //********************************************************************
409 bool ModuleBase_WidgetMultiSelector::activateSelectionAndFilters(bool toActivate)
411 myWorkshop->updateCommandStatus(); // update enable state of Undo/Redo application actions
412 return ModuleBase_WidgetSelector::activateSelectionAndFilters(toActivate);
415 //********************************************************************
416 bool ModuleBase_WidgetMultiSelector::isValidSelectionCustom(const ModuleBase_ViewerPrsPtr& thePrs)
418 bool aValid = ModuleBase_WidgetSelector::isValidSelectionCustom(thePrs);
420 ResultPtr aResult = myWorkshop->selection()->getResult(thePrs);
421 aValid = aResult.get() != NULL;
424 // We can not select a result of our feature
425 std::list<ResultPtr> aResults;
426 ModelAPI_Tools::allResults(myFeature, aResults);
427 std::list<ResultPtr>::const_iterator aIt;
428 bool isSkipSelf = false;
429 for (aIt = aResults.cbegin(); aIt != aResults.cend(); ++aIt) {
430 if ((*aIt) == aResult) {
443 //********************************************************************
444 bool ModuleBase_WidgetMultiSelector::processDelete()
446 appendFirstSelectionInHistory();
448 // find attribute indices to delete
449 std::set<int> anAttributeIds;
450 getSelectedAttributeIndices(anAttributeIds);
452 QModelIndexList aIndexes = myListControl->selectionModel()->selectedIndexes();
454 // refill attribute by the items which indices are not in the list of ids
456 DataPtr aData = myFeature->data();
457 AttributePtr anAttribute = aData->attribute(attributeID());
458 std::string aType = anAttribute->attributeType();
459 aDone = !anAttributeIds.empty();
460 if (aType == ModelAPI_AttributeSelectionList::typeId()) {
461 AttributeSelectionListPtr aSelectionListAttr = aData->selectionList(attributeID());
462 aSelectionListAttr->remove(anAttributeIds);
465 else if (aType == ModelAPI_AttributeRefList::typeId()) {
466 AttributeRefListPtr aRefListAttr = aData->reflist(attributeID());
467 aRefListAttr->remove(anAttributeIds);
469 else if (aType == ModelAPI_AttributeRefAttrList::typeId()) {
470 AttributeRefAttrListPtr aRefAttrListAttr = aData->refattrlist(attributeID());
471 aRefAttrListAttr->remove(anAttributeIds);
475 // update object is necessary to flush update signal. It leads to objects references map update
476 // and the operation presentation will not contain deleted items visualized as parameters of
478 updateObject(myFeature);
481 myWorkshop->setSelected(getAttributeSelection());
483 // may be the feature's result is not displayed, but attributes should be
484 myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeArguments,
485 true); /// hope that something is redisplayed by object updated
489 int aRows = myListControl->model()->rowCount();
491 foreach(QModelIndex aIndex, aIndexes) {
492 if (aIndex.row() < aRows)
493 myListControl->selectionModel()->select(aIndex, QItemSelectionModel::Select);
495 QModelIndex aIdx = myListControl->model()->index(aRows - 1, 0);
496 myListControl->selectionModel()->select(aIdx, QItemSelectionModel::Select);
500 appendSelectionInHistory();
504 //********************************************************************
505 QList<QWidget*> ModuleBase_WidgetMultiSelector::getControls() const
507 QList<QWidget*> result;
508 //result << myTypeCombo;
509 result << myListControl;
513 //********************************************************************
514 void ModuleBase_WidgetMultiSelector::onSelectionTypeChanged()
516 activateSelectionAndFilters(true);
520 /// store the selected type
521 AttributePtr anAttribute = myFeature->data()->attribute(attributeID());
522 std::string aType = anAttribute->attributeType();
523 if (aType == ModelAPI_AttributeSelectionList::typeId()) {
524 AttributeSelectionListPtr aSelectionListAttr = myFeature->data()->selectionList(attributeID());
525 aSelectionListAttr->setSelectionType(myTypeCtrl->textValue().toStdString());
528 // clear attribute values
529 DataPtr aData = myFeature->data();
530 if (aType == ModelAPI_AttributeSelectionList::typeId()) {
531 AttributeSelectionListPtr aSelectionListAttr = aData->selectionList(attributeID());
532 aSelectionListAttr->clear();
534 else if (aType == ModelAPI_AttributeRefList::typeId()) {
535 AttributeRefListPtr aRefListAttr = aData->reflist(attributeID());
536 aRefListAttr->clear();
538 else if (aType == ModelAPI_AttributeRefAttrList::typeId()) {
539 AttributeRefAttrListPtr aRefAttrListAttr = aData->refattrlist(attributeID());
540 aRefAttrListAttr->clear();
543 // update object is necessary to flush update signal. It leads to objects references map update
544 // and the operation presentation will not contain deleted items visualized as parameters of
546 updateObject(myFeature);
548 myWorkshop->setSelected(getAttributeSelection());
549 // may be the feature's result is not displayed, but attributes should be
550 myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeArguments,
551 true); /// hope that something is redisplayed by object updated
552 // clear history should follow after set selected to do not increase history by setSelected
553 clearSelectedHistory();
556 //********************************************************************
557 void ModuleBase_WidgetMultiSelector::onSelectionChanged()
559 if (!myIsNeutralPointClear) {
560 QList<ModuleBase_ViewerPrsPtr> aSelected = getFilteredSelected();
561 // do not clear selected object
562 if (aSelected.size() == 0) {
563 if (!getAttributeSelection().empty()) {
564 // Restore selection in the viewer by the attribute selection list
565 // it should be postponed to exit from the selectionChanged processing
566 static Events_ID anEvent = Events_Loop::eventByName(EVENT_UPDATE_BY_WIDGET_SELECTION);
567 ModelAPI_EventCreator::get()->sendUpdated(myFeature, anEvent);
568 Events_Loop::loop()->flush(anEvent);
573 appendFirstSelectionInHistory();
574 ModuleBase_WidgetSelector::onSelectionChanged();
575 appendSelectionInHistory();
578 void ModuleBase_WidgetMultiSelector::appendFirstSelectionInHistory()
580 if (mySelectedHistoryValues.empty()) {
581 myCurrentHistoryIndex++;
582 mySelectedHistoryValues.append(getAttributeSelection());
584 #ifdef DEBUG_UNDO_REDO
585 printHistoryInfo("appendSelectionInHistory", myCurrentHistoryIndex, mySelectedHistoryValues);
590 void ModuleBase_WidgetMultiSelector::appendSelectionInHistory()
592 while (myCurrentHistoryIndex != mySelectedHistoryValues.count() - 1)
593 mySelectedHistoryValues.removeLast();
595 QList<ModuleBase_ViewerPrsPtr> aSelected = getFilteredSelected();
596 myCurrentHistoryIndex++;
597 mySelectedHistoryValues.append(aSelected);
598 myWorkshop->updateCommandStatus();
600 #ifdef DEBUG_UNDO_REDO
601 printHistoryInfo("appendSelectionInHistory", myCurrentHistoryIndex, mySelectedHistoryValues);
605 void ModuleBase_WidgetMultiSelector::clearSelectedHistory()
607 mySelectedHistoryValues.clear();
608 myCurrentHistoryIndex = -1;
609 myWorkshop->updateCommandStatus();
611 #ifdef DEBUG_UNDO_REDO
612 printHistoryInfo("clearSelectedHistory", myCurrentHistoryIndex, mySelectedHistoryValues);
616 void ModuleBase_WidgetMultiSelector::updateFocus()
618 // Set focus to List control in order to make possible
619 // to use Tab key for transfer the focus to next widgets
620 ModuleBase_Tools::setFocus(myListControl,
621 "ModuleBase_WidgetMultiSelector::onSelectionTypeChanged()");
624 //********************************************************************
625 void ModuleBase_WidgetMultiSelector::updateSelectionName()
629 //********************************************************************
630 void ModuleBase_WidgetMultiSelector::updateOnSelectionChanged(const bool theDone)
632 if (myIsSetSelectionBlocked)
634 ModuleBase_WidgetSelector::updateOnSelectionChanged(theDone);
636 // according to #2154 we need to update OB selection when selection in the viewer happens
637 // it is important to flush sinchronize selection signal after flush of Update/Create/Delete.
638 // because we need that Object Browser has been already updated when synchronize happens.
640 // Restore selection in the viewer by the attribute selection list
641 // it is possible that diring selection attribute filling, selection in Object Browser
642 // is changed(some items were removed/added) and as result, selection in the viewer
643 // differs from the selection come to this method. By next rows, we restore selection
644 // in the viewer according to content of selection attribute. Case is Edge selection in Group
645 myIsSetSelectionBlocked = true;
646 static Events_ID anEvent = Events_Loop::eventByName(EVENT_UPDATE_BY_WIDGET_SELECTION);
647 ModelAPI_EventCreator::get()->sendUpdated(myFeature, anEvent);
648 Events_Loop::loop()->flush(anEvent);
649 myIsSetSelectionBlocked = false;
652 //********************************************************************
653 QIntList ModuleBase_WidgetMultiSelector::shapeTypes() const
655 QIntList aShapeTypes;
657 if (myShapeTypes.length() > 1 && myIsUseChoice) {
658 aShapeTypes.append(ModuleBase_Tools::shapeType(myTypeCtrl->textValue()));
661 foreach (QString aType, myShapeTypes) {
662 aShapeTypes.append(ModuleBase_Tools::shapeType(aType));
668 //********************************************************************
669 void ModuleBase_WidgetMultiSelector::setCurrentShapeType(const int theShapeType)
671 QString aShapeTypeName;
673 //for (int idx = 0; idx < myTypeCombo->count(); ++idx) {
674 // aShapeTypeName = myTypeCombo->itemText(idx);
676 foreach (QString aShapeTypeName, myShapeTypes) {
677 int aRefType = ModuleBase_Tools::shapeType(aShapeTypeName);
678 if(aRefType == theShapeType && idx != myTypeCtrl->value()) {
679 bool aWasActivated = activateSelectionAndFilters(false);
680 bool isBlocked = myTypeCtrl->blockSignals(true);
681 myTypeCtrl->setValue(idx);
682 myTypeCtrl->blockSignals(isBlocked);
684 activateSelectionAndFilters(true);
691 QList<ModuleBase_ViewerPrsPtr> ModuleBase_WidgetMultiSelector::getAttributeSelection() const
693 QList<ModuleBase_ViewerPrsPtr> aSelected;
694 convertIndicesToViewerSelection(std::set<int>(), aSelected);
698 //********************************************************************
699 void ModuleBase_WidgetMultiSelector::updateSelectionList()
701 myListControl->clear();
703 DataPtr aData = myFeature->data();
704 AttributePtr anAttribute = aData->attribute(attributeID());
705 std::string aType = anAttribute->attributeType();
706 if (aType == ModelAPI_AttributeSelectionList::typeId()) {
707 AttributeSelectionListPtr aSelectionListAttr = aData->selectionList(attributeID());
708 for (int i = 0; i < aSelectionListAttr->size(); i++) {
709 AttributeSelectionPtr aAttr = aSelectionListAttr->value(i);
710 QListWidgetItem* anItem = new QListWidgetItem(aAttr->namingName().c_str(), myListControl);
711 anItem->setData(ATTRIBUTE_SELECTION_INDEX_ROLE, i);
712 myListControl->addItem(anItem);
715 else if (aType == ModelAPI_AttributeRefList::typeId()) {
716 AttributeRefListPtr aRefListAttr = aData->reflist(attributeID());
717 for (int i = 0; i < aRefListAttr->size(); i++) {
718 ObjectPtr anObject = aRefListAttr->object(i);
719 if (anObject.get()) {
720 QListWidgetItem* anItem = new QListWidgetItem(anObject->data()->name().c_str(),
722 anItem->setData(ATTRIBUTE_SELECTION_INDEX_ROLE, i);
723 myListControl->addItem(anItem);
727 else if (aType == ModelAPI_AttributeRefAttrList::typeId()) {
728 AttributeRefAttrListPtr aRefAttrListAttr = aData->refattrlist(attributeID());
729 for (int i = 0; i < aRefAttrListAttr->size(); i++) {
730 AttributePtr anAttribute = aRefAttrListAttr->attribute(i);
732 if (anAttribute.get()) {
733 std::string anAttrName = generateName(anAttribute, myWorkshop);
734 aName = QString::fromStdString(anAttrName);
737 ObjectPtr anObject = aRefAttrListAttr->object(i);
738 if (anObject.get()) {
739 aName = anObject->data()->name().c_str();
742 QListWidgetItem* anItem = new QListWidgetItem(aName, myListControl);
743 anItem->setData(ATTRIBUTE_SELECTION_INDEX_ROLE, i);
744 myListControl->addItem(anItem);
748 // We have to call repaint because sometimes the List control is not updated
749 myListControl->repaint();
752 //********************************************************************
753 std::string ModuleBase_WidgetMultiSelector::validatorType(const QString& theType) const
757 if (theType == "Vertices")
759 else if (theType == "Edges")
761 else if (theType == "Faces")
763 else if (theType == "Solids")
769 //********************************************************************
770 void ModuleBase_WidgetMultiSelector::clearSelection()
772 bool isClearInNeutralPoint = myIsNeutralPointClear;
773 myIsNeutralPointClear = true;
775 QList<ModuleBase_ViewerPrsPtr> anEmptyList;
776 // This method will call Selection changed event which will call onSelectionChanged
777 // To clear mySelection, myListControl and storeValue()
778 // So, we don't need to call it
779 myWorkshop->setSelected(anEmptyList);
781 myIsNeutralPointClear = isClearInNeutralPoint;
784 //********************************************************************
785 void ModuleBase_WidgetMultiSelector::onCopyItem()
787 QList<QListWidgetItem*> aItems = myListControl->selectedItems();
789 foreach(QListWidgetItem* aItem, aItems) {
792 aRes += aItem->text();
794 if (!aRes.isEmpty()) {
795 QClipboard *clipboard = QApplication::clipboard();
796 clipboard->setText(aRes);
800 //********************************************************************
801 void ModuleBase_WidgetMultiSelector::onDeleteItem()
806 //********************************************************************
807 void ModuleBase_WidgetMultiSelector::onListSelection()
809 QList<QListWidgetItem*> aItems = myListControl->selectedItems();
810 myCopyAction->setEnabled(!aItems.isEmpty());
811 myDeleteAction->setEnabled(!aItems.isEmpty());
813 myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeHighlightedObjects,
817 //********************************************************************
818 void ModuleBase_WidgetMultiSelector::getSelectedAttributeIndices(std::set<int>& theAttributeIds)
820 QList<QListWidgetItem*> aItems = myListControl->selectedItems();
821 foreach(QListWidgetItem* anItem, aItems) {
822 int anIndex = anItem->data(ATTRIBUTE_SELECTION_INDEX_ROLE).toInt();
823 if (theAttributeIds.find(anIndex) == theAttributeIds.end())
824 theAttributeIds.insert(anIndex);
828 void ModuleBase_WidgetMultiSelector::convertIndicesToViewerSelection(std::set<int> theAttributeIds,
829 QList<ModuleBase_ViewerPrsPtr>& theValues) const
831 if(myFeature.get() == NULL)
834 DataPtr aData = myFeature->data();
835 AttributePtr anAttribute = aData->attribute(attributeID());
836 std::string aType = anAttribute->attributeType();
837 if (aType == ModelAPI_AttributeSelectionList::typeId()) {
838 AttributeSelectionListPtr aSelectionListAttr = aData->selectionList(attributeID());
839 for (int i = 0; i < aSelectionListAttr->size(); i++) {
840 // filter by attribute indices only if the container is not empty otherwise return all items
841 if (!theAttributeIds.empty() && theAttributeIds.find(i) == theAttributeIds.end())
843 AttributeSelectionPtr anAttr = aSelectionListAttr->value(i);
844 ResultPtr anObject = anAttr->context();
846 theValues.append(std::shared_ptr<ModuleBase_ViewerPrs>(
847 new ModuleBase_ViewerPrs(anObject, anAttr->value(), NULL)));
850 else if (aType == ModelAPI_AttributeRefList::typeId()) {
851 AttributeRefListPtr aRefListAttr = aData->reflist(attributeID());
852 for (int i = 0; i < aRefListAttr->size(); i++) {
853 // filter by attribute indices only if the container is not empty otherwise return all items
854 if (!theAttributeIds.empty() && theAttributeIds.find(i) == theAttributeIds.end())
856 ObjectPtr anObject = aRefListAttr->object(i);
857 if (anObject.get()) {
858 theValues.append(std::shared_ptr<ModuleBase_ViewerPrs>(
859 new ModuleBase_ViewerPrs(anObject, GeomShapePtr(), NULL)));
863 else if (aType == ModelAPI_AttributeRefAttrList::typeId()) {
864 AttributeRefAttrListPtr aRefAttrListAttr = aData->refattrlist(attributeID());
865 for (int i = 0; i < aRefAttrListAttr->size(); i++) {
866 // filter by attribute indices only if the container is not empty otherwise return all items
867 if (!theAttributeIds.empty() && theAttributeIds.find(i) == theAttributeIds.end())
869 ObjectPtr anObject = aRefAttrListAttr->object(i);
873 AttributePtr anAttribute = aRefAttrListAttr->attribute(i);
874 if (anAttribute.get()) {
875 GeomShapePtr aGeomShape = ModuleBase_Tools::getShape(anAttribute, myWorkshop);
876 theValues.append(std::shared_ptr<ModuleBase_ViewerPrs>(
877 new ModuleBase_ViewerPrs(anObject, aGeomShape, NULL)));
883 bool ModuleBase_WidgetMultiSelector::removeUnusedAttributeObjects
884 (QList<ModuleBase_ViewerPrsPtr>& theValues)
888 std::map<ObjectPtr, std::set<GeomShapePtr> > aGeomSelection = convertSelection(theValues);
889 DataPtr aData = myFeature->data();
890 AttributePtr anAttribute = aData->attribute(attributeID());
891 std::string aType = anAttribute->attributeType();
892 std::set<GeomShapePtr> aShapes;
893 std::set<int> anIndicesToBeRemoved;
894 if (aType == ModelAPI_AttributeSelectionList::typeId()) {
895 // iteration through data model to find not selected elements to remove them
896 AttributeSelectionListPtr aSelectionListAttr = aData->selectionList(attributeID());
897 for (int i = 0; i < aSelectionListAttr->size(); i++) {
898 AttributeSelectionPtr anAttr = aSelectionListAttr->value(i);
899 bool aFound = findInSelection(anAttr->context(), anAttr->value(), aGeomSelection,
902 anIndicesToBeRemoved.insert(i);
904 isDone = anIndicesToBeRemoved.size() > 0;
905 aSelectionListAttr->remove(anIndicesToBeRemoved);
907 else if (aType == ModelAPI_AttributeRefList::typeId()) {
908 AttributeRefListPtr aRefListAttr = aData->reflist(attributeID());
909 for (int i = 0; i < aRefListAttr->size(); i++) {
910 ObjectPtr anObject = aRefListAttr->object(i);
911 if (anObject.get()) {
912 bool aFound = findInSelection(anObject, GeomShapePtr(), aGeomSelection,
915 anIndicesToBeRemoved.insert(i);
918 isDone = anIndicesToBeRemoved.size() > 0;
919 aRefListAttr->remove(anIndicesToBeRemoved);
921 else if (aType == ModelAPI_AttributeRefAttrList::typeId()) {
922 std::set<AttributePtr> anAttributes;
923 QList<ModuleBase_ViewerPrsPtr>::const_iterator
924 anIt = theValues.begin(), aLast = theValues.end();
927 for (; anIt != aLast; anIt++) {
928 ModuleBase_ViewerPrsPtr aPrs = *anIt;
929 getGeomSelection(aPrs, anObject, aShape);
930 AttributePtr anAttr = myWorkshop->module()->findAttribute(anObject, aShape);
931 if (anAttr.get() && anAttributes.find(anAttr) == anAttributes.end())
932 anAttributes.insert(anAttr);
935 AttributeRefAttrListPtr aRefAttrListAttr = aData->refattrlist(attributeID());
936 for (int i = 0; i < aRefAttrListAttr->size(); i++) {
938 if (aRefAttrListAttr->isAttribute(i)) {
939 AttributePtr anAttribute = aRefAttrListAttr->attribute(i);
940 aFound = anAttributes.find(anAttribute) != anAttributes.end();
943 aFound = findInSelection(aRefAttrListAttr->object(i), GeomShapePtr(), aGeomSelection,
947 anIndicesToBeRemoved.insert(i);
949 isDone = anIndicesToBeRemoved.size() > 0;
950 aRefAttrListAttr->remove(anIndicesToBeRemoved);
956 std::map<ObjectPtr, std::set<GeomShapePtr> > ModuleBase_WidgetMultiSelector::convertSelection
957 (QList<ModuleBase_ViewerPrsPtr>& theValues)
959 // convert prs list to objects map
960 std::map<ObjectPtr, std::set<GeomShapePtr> > aGeomSelection;
961 std::set<GeomShapePtr> aShapes;
962 QList<ModuleBase_ViewerPrsPtr>::const_iterator anIt = theValues.begin(), aLast = theValues.end();
965 GeomShapePtr anEmptyShape(new GeomAPI_Shape());
966 for (; anIt != aLast; anIt++) {
967 ModuleBase_ViewerPrsPtr aPrs = *anIt;
968 getGeomSelection(aPrs, anObject, aShape);
970 if (aGeomSelection.find(anObject) != aGeomSelection.end()) // found
971 aShapes = aGeomSelection[anObject];
972 // we need to know if there was an empty shape in selection for the object
974 aShape = anEmptyShape;
975 if (aShape.get() && aShapes.find(aShape) == aShapes.end()) // not found
976 aShapes.insert(aShape);
977 aGeomSelection[anObject] = aShapes;
979 return aGeomSelection;
982 bool ModuleBase_WidgetMultiSelector::findInSelection(const ObjectPtr& theObject,
983 GeomShapePtr theShape,
984 const std::map<ObjectPtr, std::set<GeomShapePtr> >& theGeomSelection,
985 ModuleBase_IWorkshop* theWorkshop)
987 // issue #2154: we should not remove from list objects hidden in the viewer if selection
988 // was done with SHIFT button
989 if (theWorkshop->hasSHIFTPressed() && !theObject->isDisplayed())
993 GeomShapePtr anEmptyShape(new GeomAPI_Shape());
994 if (theShape.get()) { // treat shape equal to context as null: 2219, keep order of shapes in list
995 const ResultPtr aContext = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
996 if (aContext.get() && aContext->shape()->isEqual(theShape))
999 GeomShapePtr aShape = theShape.get() ? theShape : anEmptyShape;
1000 if (theGeomSelection.find(theObject) != theGeomSelection.end()) {// found
1001 const std::set<GeomShapePtr>& aShapes = theGeomSelection.at(theObject);
1002 std::set<GeomShapePtr>::const_iterator anIt = aShapes.begin(), aLast = aShapes.end();
1003 for (; anIt != aLast && !aFound; anIt++) {
1004 GeomShapePtr aCShape = *anIt;
1006 aFound = aCShape->isSame(aShape);