X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModuleBase%2FModuleBase_WidgetMultiSelector.cpp;h=11c502778c71fce36d3cd975b53af32620064191;hb=c155919c16327dae7e09cd1e6a5b6d166e844767;hp=a651aa185eb0372540bf230277e7dcec2a3bd44f;hpb=f571f3c2e76f6fb9cb4e88775bd21c36633e062c;p=modules%2Fshaper.git diff --git a/src/ModuleBase/ModuleBase_WidgetMultiSelector.cpp b/src/ModuleBase/ModuleBase_WidgetMultiSelector.cpp old mode 100755 new mode 100644 index a651aa185..11c502778 --- a/src/ModuleBase/ModuleBase_WidgetMultiSelector.cpp +++ b/src/ModuleBase/ModuleBase_WidgetMultiSelector.cpp @@ -1,22 +1,43 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -/* - * ModuleBase_WidgetMultiSelector.cpp - * - * Created on: Aug 28, 2014 - * Author: sbh - */ +// Copyright (C) 2014-2019 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// #include -#include + +#include + +#include +#include +#include +#include +#include #include -#include +#include +#include #include +#include +#include +#include #include -#include -#include #include -#include +#include +#include +#include #include #include @@ -24,9 +45,12 @@ #include #include #include +#include #include +#include + #include #include #include @@ -34,130 +58,150 @@ #include #include #include -#include #include #include #include +#include +#include +#include #include #include -const int ATTRIBUTE_SELECTION_INDEX_ROLE = Qt::UserRole + 1; +//#define DEBUG_UNDO_REDO -/** -* Customization of a List Widget to make it to be placed on full width of container -*/ -class CustomListWidget : public QListWidget +#ifdef DEBUG_UNDO_REDO +void printHistoryInfo(const QString& theMethodName, int theCurrentHistoryIndex, + QList > > theSelectedHistoryValues) { -public: - /// Constructor - /// \param theParent a parent widget - CustomListWidget( QWidget* theParent ) - : QListWidget( theParent ) - { - } + QStringList aSizes; + for (int i = 0; i < theSelectedHistoryValues.size(); i++) + aSizes.append(QString::number(theSelectedHistoryValues[i].size())); + + std::cout << theMethodName.toStdString() + << " current = " << theCurrentHistoryIndex + << " size(history) = " << theSelectedHistoryValues.size() + << " (" << aSizes.join(", ").toStdString() << ")" + << std::endl; +} +#endif - /// Redefinition of virtual method - virtual QSize sizeHint() const - { - int aHeight = 2*QFontMetrics( font() ).height(); - QSize aSize = QListWidget::sizeHint(); - return QSize( aSize.width(), aHeight ); - } - /// Redefinition of virtual method - virtual QSize minimumSizeHint() const - { - int aHeight = 4/*2*/*QFontMetrics( font() ).height(); - QSize aSize = QListWidget::minimumSizeHint(); - return QSize( aSize.width(), aHeight ); +QStringList getIconsList(const QStringList& theNames) +{ + QStringList aIcons; + foreach (QString aName, theNames) { + QString aUName = aName.toUpper(); + if ((aUName == "VERTICES") || (aUName == "VERTEX")) + aIcons << ":pictures/vertex32.png"; + else if ((aUName == "EDGES") || (aUName == "EDGE")) + aIcons << ":pictures/edge32.png"; + else if ((aUName == "FACES") || (aUName == "FACE")) + aIcons << ":pictures/face32.png"; + else if ((aUName == "SOLIDS") || (aUName == "SOLID")) + aIcons << ":pictures/solid32.png"; } + return aIcons; +} + +/// Stores default values of selected option (selection mode) +/// It is used only in case if myTypeCtrl is used +static QMap defaultValues; -#ifndef WIN32 -// The code is necessary only for Linux because -//it can not update viewport on widget resize -protected: - void resizeEvent(QResizeEvent* theEvent) - { - QListWidget::resizeEvent(theEvent); - QTimer::singleShot(5, viewport(), SLOT(repaint())); - } -#endif -}; ModuleBase_WidgetMultiSelector::ModuleBase_WidgetMultiSelector(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop, const Config_WidgetAPI* theData) -: ModuleBase_WidgetSelector(theParent, theWorkshop, theData) +: ModuleBase_WidgetSelector(theParent, theWorkshop, theData), + myIsSetSelectionBlocked(false), myCurrentHistoryIndex(-1), + myIsFirst(true), myFiltersWgt(0) { - QGridLayout* aMainLay = new QGridLayout(this); - ModuleBase_Tools::adjustMargins(aMainLay); - - QLabel* aTypeLabel = new QLabel(tr("Type"), this); - aMainLay->addWidget(aTypeLabel, 0, 0); - - myTypeCombo = new QComboBox(this); - // There is no sense to parameterize list of types while we can not parameterize selection mode - std::string aPropertyTypes = theData->getProperty("type_choice"); QString aTypesStr = aPropertyTypes.c_str(); - QStringList aShapeTypes = aTypesStr.split(' ', QString::SkipEmptyParts); - + myShapeTypes = aTypesStr.split(' ', QString::SkipEmptyParts); myIsUseChoice = theData->getBooleanAttribute("use_choice", false); - if (!aShapeTypes.empty()) - myTypeCombo->addItems(aShapeTypes); - aMainLay->addWidget(myTypeCombo, 0, 1); + QVBoxLayout* aMainLay = new QVBoxLayout(this); + ModuleBase_Tools::adjustMargins(aMainLay); + + QStringList aIconsList = getIconsList(myShapeTypes); + myTypeCtrl = new ModuleBase_ChoiceCtrl(this, myShapeTypes, aIconsList); + myTypeCtrl->setLabel(tr("Type")); + myTypeCtrl->setValue(0); + aMainLay->addWidget(myTypeCtrl); + myDefMode = myShapeTypes.first().toStdString(); + + // There is no sense to parameterize list of types while we can not parameterize selection mode // if the xml definition contains one type, the controls to select a type should not be shown - if (aShapeTypes.size() <= 1 || !myIsUseChoice) { - aTypeLabel->setVisible(false); - myTypeCombo->setVisible(false); - } - - std::string aLabelText = theData->getProperty("label"); - QLabel* aListLabel = new QLabel(!aLabelText.empty() ? aLabelText.c_str() - : tr("Selected objects:"), this); - aMainLay->addWidget(aListLabel, 1, 0); - // if the xml definition contains one type, an information label should be shown near to the latest - if (aShapeTypes.size() <= 1) { - QString aLabelIcon = QString::fromStdString(theData->widgetIcon()); - if (!aLabelIcon.isEmpty()) { - QLabel* aSelectedLabel = new QLabel("", this); - aSelectedLabel->setPixmap(ModuleBase_IconFactory::loadPixmap(aLabelIcon)); - aMainLay->addWidget(aSelectedLabel, 1, 1); + if (myShapeTypes.size() <= 1 || !myIsUseChoice) { + myTypeCtrl->setVisible(false); + } + + QString aLabelText = translate(theData->getProperty("label")); + if (aLabelText.size() > 0) { + QWidget* aLabelWgt = new QWidget(this); + QHBoxLayout* aLabelLayout = new QHBoxLayout(aLabelWgt); + aLabelLayout->setContentsMargins(0, 0, 0, 0); + aMainLay->addWidget(aLabelWgt); + + QLabel* aListLabel = new QLabel(aLabelText, this); + aLabelLayout->addWidget(aListLabel); + // if the xml definition contains one type, an information label + // should be shown near to the latest + if (myShapeTypes.size() <= 1) { + QString aLabelIcon = QString::fromStdString(theData->widgetIcon()); + if (!aLabelIcon.isEmpty()) { + QLabel* aSelectedLabel = new QLabel("", this); + aSelectedLabel->setPixmap(ModuleBase_IconFactory::loadPixmap(aLabelIcon)); + aLabelLayout->addWidget(aSelectedLabel); + aLabelLayout->addStretch(1); + } } - aMainLay->setColumnStretch(2, 1); } QString aToolTip = QString::fromStdString(theData->widgetTooltip()); - myListControl = new CustomListWidget(this); QString anObjName = QString::fromStdString(attributeID()); - myListControl->setObjectName(anObjName); - myListControl->setToolTip(aToolTip); - myListControl->setSelectionMode(QAbstractItemView::ExtendedSelection); - - aMainLay->addWidget(myListControl, 2, 0, 1, -1); - aMainLay->setRowStretch(2, 1); - //aMainLay->addWidget(new QLabel(this)); //FIXME(sbh)??? - //aMainLay->setRowMinimumHeight(3, 20); - //this->setLayout(aMainLay); - connect(myTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onSelectionTypeChanged())); - - myCopyAction = new QAction(QIcon(":pictures/copy.png"), tr("Copy"), this); - myCopyAction->setShortcut(QKeySequence::Copy); - myCopyAction->setEnabled(false); - connect(myCopyAction, SIGNAL(triggered(bool)), SLOT(onCopyItem())); - myListControl->addAction(myCopyAction); - - myDeleteAction = new QAction(QIcon(":pictures/delete.png"), tr("Delete"), this); - myDeleteAction->setEnabled(false); - connect(myDeleteAction, SIGNAL(triggered(bool)), SLOT(onDeleteItem())); - myListControl->addAction(myDeleteAction); - - myListControl->setContextMenuPolicy(Qt::ActionsContextMenu); - connect(myListControl, SIGNAL(itemSelectionChanged()), SLOT(onListSelection())); + myListView = new ModuleBase_ListView(this, anObjName, aToolTip); + connect(myListView->getControl(), SIGNAL(itemSelectionChanged()), SLOT(onListSelection())); + connect(myListView, SIGNAL(deleteActionClicked()), SLOT(onDeleteItem())); + connect(myListView, SIGNAL(listActivated()), SLOT(onListActivated())); + + aMainLay->addWidget(myListView->getControl()); + connect(myTypeCtrl, SIGNAL(valueChanged(int)), this, SLOT(onSelectionTypeChanged())); + + std::string aUseFilters = theData->getProperty("use_filters"); + if (aUseFilters.length() > 0) { + QWidget* aFltrWgt = new QWidget(this); + QHBoxLayout* aFltrLayout = new QHBoxLayout(aFltrWgt); + + myFiltersWgt = new ModuleBase_FilterStarter(aUseFilters.c_str(), aFltrWgt, theWorkshop); + aFltrLayout->addWidget(myFiltersWgt); + + aFltrLayout->addStretch(); + + QPushButton* aShowBtn = new QPushButton(tr("Show only"), aFltrWgt); + connect(aShowBtn, SIGNAL(clicked(bool)), SLOT(onShowOnly())); + aFltrLayout->addWidget(aShowBtn); + + aMainLay->addWidget(aFltrWgt); + } + + bool aSameTop = theData->getBooleanAttribute("same_topology", false); + if (aSameTop) { + myGeomCheck = new QCheckBox(tr("Add elements that share the same topology"), this); + aMainLay->addWidget(myGeomCheck); + connect(myGeomCheck, SIGNAL(toggled(bool)), SLOT(onSameTopology(bool))); + } + else + myGeomCheck = 0; myIsNeutralPointClear = theData->getBooleanAttribute("clear_in_neutral_point", true); + if (myShapeTypes.size() > 1 || myIsUseChoice) { + if (defaultValues.contains(myFeatureId + attributeID())) { + myDefMode = defaultValues[myFeatureId + attributeID()]; + myTypeCtrl->setValue(myDefMode.c_str()); + } + } } ModuleBase_WidgetMultiSelector::~ModuleBase_WidgetMultiSelector() @@ -171,6 +215,7 @@ void ModuleBase_WidgetMultiSelector::activateCustom() myWorkshop->module()->activateCustomPrs(myFeature, ModuleBase_IModule::CustomizeHighlightedObjects, true); + clearSelectedHistory(); } //******************************************************************** @@ -179,13 +224,28 @@ void ModuleBase_WidgetMultiSelector::deactivate() ModuleBase_WidgetSelector::deactivate(); myWorkshop->module()->deactivateCustomPrs(ModuleBase_IModule::CustomizeHighlightedObjects, true); + clearSelectedHistory(); +} + +//******************************************************************** +void ModuleBase_WidgetMultiSelector::updateAfterDeactivation() +{ + // restore previous Undo/Redo workshop state + myWorkshop->updateCommandStatus(); +} + +//******************************************************************** +void ModuleBase_WidgetMultiSelector::updateAfterActivation() +{ + // fill Undo/Redo actions with current information + myWorkshop->updateCommandStatus(); } //******************************************************************** bool ModuleBase_WidgetMultiSelector::storeValueCustom() { - // the value is stored on the selection changed signal processing - // A rare case when plugin was not loaded. + // the value is stored on the selection changed signal processing + // A rare case when plugin was not loaded. if (!myFeature) return false; @@ -193,7 +253,12 @@ bool ModuleBase_WidgetMultiSelector::storeValueCustom() std::string aType = anAttribute->attributeType(); if (aType == ModelAPI_AttributeSelectionList::typeId()) { AttributeSelectionListPtr aSelectionListAttr = myFeature->data()->selectionList(attributeID()); - aSelectionListAttr->setSelectionType(myTypeCombo->currentText().toStdString()); + std::string aMode = myTypeCtrl->textValue().toStdString(); + if (myTypeCtrl->isVisible() && myIsFirst && (!myDefMode.empty())) + aMode = myDefMode; + + aSelectionListAttr->setSelectionType(aMode); + myIsFirst = false; } return true; } @@ -201,19 +266,24 @@ bool ModuleBase_WidgetMultiSelector::storeValueCustom() //******************************************************************** bool ModuleBase_WidgetMultiSelector::restoreValueCustom() { - // A rare case when plugin was not loaded. + // A rare case when plugin was not loaded. if (!myFeature) return false; AttributePtr anAttribute = myFeature->data()->attribute(attributeID()); + AttributeSelectionListPtr aSelectionListAttr = myFeature->data()->selectionList(attributeID()); std::string aType = anAttribute->attributeType(); if (aType == ModelAPI_AttributeSelectionList::typeId()) { - AttributeSelectionListPtr aSelectionListAttr = myFeature->data()->selectionList(attributeID()); // Restore shape type std::string aSelectionType = aSelectionListAttr->selectionType().c_str(); - if (!aSelectionType.empty()) + if (!aSelectionType.empty()) { setCurrentShapeType(ModuleBase_Tools::shapeType(aSelectionType.c_str())); + myDefMode = aSelectionType; + myIsFirst = false; + } } + if (myGeomCheck) + myGeomCheck->setChecked(aSelectionListAttr->isGeometricalSelection()); updateSelectionList(); return true; } @@ -222,6 +292,9 @@ bool ModuleBase_WidgetMultiSelector::restoreValueCustom() bool ModuleBase_WidgetMultiSelector::setSelection(QList& theValues, const bool theToValidate) { + if (myIsSetSelectionBlocked) + return false; + AttributeSelectionListPtr aSelectionListAttr; if (attribute()->attributeType() == ModelAPI_AttributeSelectionList::typeId()) aSelectionListAttr = std::dynamic_pointer_cast(attribute()); @@ -260,6 +333,12 @@ bool ModuleBase_WidgetMultiSelector::setSelection(QList // if there is at least one set, the result is true isDone = isDone || aProcessed; } + // Check the selection with validators + QString aError = getError(); + if (aError.length() > 0) { + aSelectionListAttr->clear(); + isDone = false; + } // updateObject - to update/redisplay feature // it is commented in order to perfom it outside the method //if (isDone) { @@ -277,7 +356,7 @@ bool ModuleBase_WidgetMultiSelector::setSelection(QList if (isDone) // may be the feature's result is not displayed, but attributes should be myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeArguments, - true);/// hope that something is redisplayed by object updated + true);/// hope that something is redisplayed by object updated return isDone; } @@ -291,20 +370,81 @@ void ModuleBase_WidgetMultiSelector::getHighlighted(QList 0 + : (mySelectedHistoryValues.size() > 0 && + myCurrentHistoryIndex < mySelectedHistoryValues.size() - 1); + } + break; + default: + aCanProcess = ModuleBase_WidgetSelector::canProcessAction(theActionType, isActionEnabled); + break; + } + return aCanProcess; +} + +//******************************************************************** +bool ModuleBase_WidgetMultiSelector::processAction(ModuleBase_ActionType theActionType, + const ActionParamPtr& theParam) +{ + switch (theActionType) { + case ActionUndo: + case ActionRedo: { + ActionIntParamPtr aParam = + std::dynamic_pointer_cast(theParam); + int aNb = aParam->value(); + if (theActionType == ActionUndo) + myCurrentHistoryIndex -= aNb; + else + myCurrentHistoryIndex += aNb; + QList aSelected = mySelectedHistoryValues[myCurrentHistoryIndex]; + // equal vertices should not be used here + ModuleBase_ISelection::filterSelectionOnEqualPoints(aSelected); + bool isDone = setSelection(aSelected, + false /*need not validate because values already was in list*/); + updateOnSelectionChanged(isDone); + + myWorkshop->updateCommandStatus(); +#ifdef DEBUG_UNDO_REDO + printHistoryInfo(QString("processAction %1").arg(theActionType == ActionUndo ? "Undo" + : "Redo"), myCurrentHistoryIndex, mySelectedHistoryValues); +#endif + return true; + } + default: + return ModuleBase_ModelWidget::processAction(theActionType, theParam); + } +} + //******************************************************************** bool ModuleBase_WidgetMultiSelector::isValidSelectionCustom(const ModuleBase_ViewerPrsPtr& thePrs) { bool aValid = ModuleBase_WidgetSelector::isValidSelectionCustom(thePrs); if (aValid) { ResultPtr aResult = myWorkshop->selection()->getResult(thePrs); + if (!aResult.get()) { // In case if a feature was selected + FeaturePtr aFeature = std::dynamic_pointer_cast(thePrs->object()); + if (aFeature.get()) + aResult = aFeature->firstResult(); + } aValid = aResult.get() != NULL; if (aValid) { if (myFeature) { // We can not select a result of our feature - const std::list& aResList = myFeature->results(); + std::list aResults; + ModelAPI_Tools::allResults(myFeature, aResults); std::list::const_iterator aIt; bool isSkipSelf = false; - for (aIt = aResList.cbegin(); aIt != aResList.cend(); ++aIt) { + for (aIt = aResults.cbegin(); aIt != aResults.cend(); ++aIt) { if ((*aIt) == aResult) { isSkipSelf = true; break; @@ -321,11 +461,13 @@ bool ModuleBase_WidgetMultiSelector::isValidSelectionCustom(const ModuleBase_Vie //******************************************************************** bool ModuleBase_WidgetMultiSelector::processDelete() { + appendFirstSelectionInHistory(); + // find attribute indices to delete std::set anAttributeIds; getSelectedAttributeIndices(anAttributeIds); - QModelIndexList aIndexes = myListControl->selectionModel()->selectedIndexes(); + QModelIndexList anIndices = myListView->getControl()->selectionModel()->selectedIndexes(); // refill attribute by the items which indices are not in the list of ids bool aDone = false; @@ -358,61 +500,143 @@ bool ModuleBase_WidgetMultiSelector::processDelete() // may be the feature's result is not displayed, but attributes should be myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeArguments, - true); /// hope that something is redisplayed by object updated + true); /// hope that something is redisplayed by object updated } // Restore selection - int aRows = myListControl->model()->rowCount(); - if (aRows > 0) { - foreach(QModelIndex aIndex, aIndexes) { - if (aIndex.row() < aRows) - myListControl->selectionModel()->select(aIndex, QItemSelectionModel::Select); - else { - QModelIndex aIdx = myListControl->model()->index(aRows - 1, 0); - myListControl->selectionModel()->select(aIdx, QItemSelectionModel::Select); - } - } - } - return aDone; + myListView->restoreSelection(anIndices); + + appendSelectionInHistory(); + return true/*aDone*/; // following #2438 Delete should be processed even if nothing is delete } //******************************************************************** QList ModuleBase_WidgetMultiSelector::getControls() const { QList result; - //result << myTypeCombo; - result << myListControl; + result << myListView->getControl(); return result; } //******************************************************************** void ModuleBase_WidgetMultiSelector::onSelectionTypeChanged() { - activateSelectionAndFilters(true); - QList anEmptyList; - // This method will call Selection changed event which will call onSelectionChanged - // To clear mySelection, myListControl and storeValue() - // So, we don't need to call it - myWorkshop->setSelected(anEmptyList); + // Clear current selection in order to avoid updating of object browser with obsolete indexes + // which can appear because of results deletetion after changing a type of selection + QString aSelectionType = myTypeCtrl->textValue(); + QList aEmptyList; + myWorkshop->setSelected(aEmptyList); + + updateSelectionModesAndFilters(true); + myWorkshop->selectionActivate()->updateSelectionModes(); + + if (!myFeature) + return; + /// store the selected type + AttributePtr anAttribute = myFeature->data()->attribute(attributeID()); + std::string aType = anAttribute->attributeType(); + if (aType == ModelAPI_AttributeSelectionList::typeId()) { + AttributeSelectionListPtr aSelectionListAttr = myFeature->data()->selectionList(attributeID()); + aSelectionListAttr->setSelectionType(aSelectionType.toStdString()); + } + + // clear attribute values + DataPtr aData = myFeature->data(); + if (aType == ModelAPI_AttributeSelectionList::typeId()) { + AttributeSelectionListPtr aSelectionListAttr = aData->selectionList(attributeID()); + aSelectionListAttr->clear(); + } + else if (aType == ModelAPI_AttributeRefList::typeId()) { + AttributeRefListPtr aRefListAttr = aData->reflist(attributeID()); + aRefListAttr->clear(); + } + else if (aType == ModelAPI_AttributeRefAttrList::typeId()) { + AttributeRefAttrListPtr aRefAttrListAttr = aData->refattrlist(attributeID()); + aRefAttrListAttr->clear(); + } + + // update object is necessary to flush update signal. It leads to objects references map update + // and the operation presentation will not contain deleted items visualized as parameters of + // the feature. + updateObject(myFeature); + restoreValue(); + myWorkshop->setSelected(getAttributeSelection()); + // may be the feature's result is not displayed, but attributes should be + myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeArguments, + true); /// hope that something is redisplayed by object updated + // clear history should follow after set selected to do not increase history by setSelected + clearSelectedHistory(); + + if (myWorkshop->propertyPanel()->activeWidget() != this) + myWorkshop->propertyPanel()->activateWidget(this); } //******************************************************************** -void ModuleBase_WidgetMultiSelector::onSelectionChanged() +bool ModuleBase_WidgetMultiSelector::processSelection() { if (!myIsNeutralPointClear) { QList aSelected = getFilteredSelected(); - if (aSelected.size() == 0) - return; + // do not clear selected object + if (aSelected.size() == 0) { + if (!getAttributeSelection().empty()) { + // Restore selection in the viewer by the attribute selection list + // it should be postponed to exit from the selectionChanged processing + static Events_ID anEvent = Events_Loop::eventByName(EVENT_UPDATE_BY_WIDGET_SELECTION); + ModelAPI_EventCreator::get()->sendUpdated(myFeature, anEvent); + Events_Loop::loop()->flush(anEvent); + return true; + } + } + } + appendFirstSelectionInHistory(); + bool aDone = ModuleBase_WidgetSelector::processSelection(); + appendSelectionInHistory(); + return aDone; +} + +void ModuleBase_WidgetMultiSelector::appendFirstSelectionInHistory() +{ + if (mySelectedHistoryValues.empty()) { + myCurrentHistoryIndex++; + mySelectedHistoryValues.append(getAttributeSelection()); + +#ifdef DEBUG_UNDO_REDO + printHistoryInfo("appendSelectionInHistory", myCurrentHistoryIndex, mySelectedHistoryValues); +#endif } - ModuleBase_WidgetSelector::onSelectionChanged(); +} + +void ModuleBase_WidgetMultiSelector::appendSelectionInHistory() +{ + while (myCurrentHistoryIndex != mySelectedHistoryValues.count() - 1) + mySelectedHistoryValues.removeLast(); + + QList aSelected = getFilteredSelected(); + myCurrentHistoryIndex++; + mySelectedHistoryValues.append(aSelected); + myWorkshop->updateCommandStatus(); + +#ifdef DEBUG_UNDO_REDO + printHistoryInfo("appendSelectionInHistory", myCurrentHistoryIndex, mySelectedHistoryValues); +#endif +} + +void ModuleBase_WidgetMultiSelector::clearSelectedHistory() +{ + mySelectedHistoryValues.clear(); + myCurrentHistoryIndex = -1; + myWorkshop->updateCommandStatus(); + +#ifdef DEBUG_UNDO_REDO + printHistoryInfo("clearSelectedHistory", myCurrentHistoryIndex, mySelectedHistoryValues); +#endif } void ModuleBase_WidgetMultiSelector::updateFocus() { - // Set focus to List control in order to make possible + // Set focus to List control in order to make possible // to use Tab key for transfer the focus to next widgets - myListControl->setCurrentRow(myListControl->model()->rowCount() - 1); - ModuleBase_Tools::setFocus(myListControl, + ModuleBase_Tools::setFocus(myListView->getControl(), "ModuleBase_WidgetMultiSelector::onSelectionTypeChanged()"); } @@ -422,41 +646,61 @@ void ModuleBase_WidgetMultiSelector::updateSelectionName() } //******************************************************************** -QIntList ModuleBase_WidgetMultiSelector::getShapeTypes() const +void ModuleBase_WidgetMultiSelector::updateOnSelectionChanged(const bool theDone) +{ + if (myIsSetSelectionBlocked) + return; + ModuleBase_WidgetSelector::updateOnSelectionChanged(theDone); + + // according to #2154 we need to update OB selection when selection in the viewer happens + // it is important to flush sinchronize selection signal after flush of Update/Create/Delete. + // because we need that Object Browser has been already updated when synchronize happens. + + // Restore selection in the viewer by the attribute selection list + // it is possible that diring selection attribute filling, selection in Object Browser + // is changed(some items were removed/added) and as result, selection in the viewer + // differs from the selection come to this method. By next rows, we restore selection + // in the viewer according to content of selection attribute. Case is Edge selection in Group + myIsSetSelectionBlocked = true; + static Events_ID anEvent = Events_Loop::eventByName(EVENT_UPDATE_BY_WIDGET_SELECTION); + ModelAPI_EventCreator::get()->sendUpdated(myFeature, anEvent); + Events_Loop::loop()->flush(anEvent); + myIsSetSelectionBlocked = false; +} + +//******************************************************************** +QIntList ModuleBase_WidgetMultiSelector::shapeTypes() const { QIntList aShapeTypes; - if (myTypeCombo->count() > 1 && myIsUseChoice) { - aShapeTypes.append(ModuleBase_Tools::shapeType(myTypeCombo->currentText())); + if (myShapeTypes.length() > 1 && myIsUseChoice) { + aShapeTypes.append(ModuleBase_Tools::shapeType(myTypeCtrl->textValue())); } else { - for (int i = 0, aCount = myTypeCombo->count(); i < aCount; i++) { - TopAbs_ShapeEnum aType = ModuleBase_Tools::shapeType(myTypeCombo->itemText(i)); - aShapeTypes.append(aType); - if (aType == TopAbs_SOLID) - aShapeTypes.append(TopAbs_COMPSOLID); + foreach (QString aType, myShapeTypes) { + aShapeTypes.append(ModuleBase_Tools::shapeType(aType)); } } return aShapeTypes; } //******************************************************************** -void ModuleBase_WidgetMultiSelector::setCurrentShapeType(const TopAbs_ShapeEnum theShapeType) +void ModuleBase_WidgetMultiSelector::setCurrentShapeType(const int theShapeType) { QString aShapeTypeName; - - for (int idx = 0; idx < myTypeCombo->count(); ++idx) { - aShapeTypeName = myTypeCombo->itemText(idx); - TopAbs_ShapeEnum aRefType = ModuleBase_Tools::shapeType(aShapeTypeName); - if(aRefType == theShapeType && idx != myTypeCombo->currentIndex()) { - bool aWasActivated = activateSelectionAndFilters(false); - bool isBlocked = myTypeCombo->blockSignals(true); - myTypeCombo->setCurrentIndex(idx); - myTypeCombo->blockSignals(isBlocked); - if (aWasActivated) - activateSelectionAndFilters(true); + + int idx = 0; + foreach (QString aShapeTypeName, myShapeTypes) { + int aRefType = ModuleBase_Tools::shapeType(aShapeTypeName); + if(aRefType == theShapeType && idx != myTypeCtrl->value()) { + updateSelectionModesAndFilters(false); + bool isBlocked = myTypeCtrl->blockSignals(true); + myTypeCtrl->setValue(idx); + myTypeCtrl->blockSignals(isBlocked); + updateSelectionModesAndFilters(true); break; } + idx++; } } @@ -470,7 +714,7 @@ QList ModuleBase_WidgetMultiSelector::getAttributeSelec //******************************************************************** void ModuleBase_WidgetMultiSelector::updateSelectionList() { - myListControl->clear(); + myListView->getControl()->clear(); DataPtr aData = myFeature->data(); AttributePtr anAttribute = aData->attribute(attributeID()); @@ -479,9 +723,7 @@ void ModuleBase_WidgetMultiSelector::updateSelectionList() AttributeSelectionListPtr aSelectionListAttr = aData->selectionList(attributeID()); for (int i = 0; i < aSelectionListAttr->size(); i++) { AttributeSelectionPtr aAttr = aSelectionListAttr->value(i); - QListWidgetItem* anItem = new QListWidgetItem(aAttr->namingName().c_str(), myListControl); - anItem->setData(ATTRIBUTE_SELECTION_INDEX_ROLE, i); - myListControl->addItem(anItem); + myListView->addItem(aAttr->namingName().c_str(), i); } } else if (aType == ModelAPI_AttributeRefList::typeId()) { @@ -489,10 +731,7 @@ void ModuleBase_WidgetMultiSelector::updateSelectionList() for (int i = 0; i < aRefListAttr->size(); i++) { ObjectPtr anObject = aRefListAttr->object(i); if (anObject.get()) { - QListWidgetItem* anItem = new QListWidgetItem(anObject->data()->name().c_str(), - myListControl); - anItem->setData(ATTRIBUTE_SELECTION_INDEX_ROLE, i); - myListControl->addItem(anItem); + myListView->addItem(anObject->data()->name().c_str(), i); } } } @@ -502,7 +741,7 @@ void ModuleBase_WidgetMultiSelector::updateSelectionList() AttributePtr anAttribute = aRefAttrListAttr->attribute(i); QString aName; if (anAttribute.get()) { - std::string anAttrName = generateName(anAttribute, myWorkshop); + std::string anAttrName = ModuleBase_Tools::generateName(anAttribute, myWorkshop); aName = QString::fromStdString(anAttrName); } else { @@ -511,14 +750,12 @@ void ModuleBase_WidgetMultiSelector::updateSelectionList() aName = anObject->data()->name().c_str(); } } - QListWidgetItem* anItem = new QListWidgetItem(aName, myListControl); - anItem->setData(ATTRIBUTE_SELECTION_INDEX_ROLE, i); - myListControl->addItem(anItem); + myListView->addItem(aName, i); } } // We have to call repaint because sometimes the List control is not updated - myListControl->repaint(); + myListView->getControl()->repaint(); } //******************************************************************** @@ -539,19 +776,18 @@ std::string ModuleBase_WidgetMultiSelector::validatorType(const QString& theType } //******************************************************************** -void ModuleBase_WidgetMultiSelector::onCopyItem() +void ModuleBase_WidgetMultiSelector::clearSelection() { - QList aItems = myListControl->selectedItems(); - QString aRes; - foreach(QListWidgetItem* aItem, aItems) { - if (!aRes.isEmpty()) - aRes += "\n"; - aRes += aItem->text(); - } - if (!aRes.isEmpty()) { - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(aRes); - } + bool isClearInNeutralPoint = myIsNeutralPointClear; + myIsNeutralPointClear = true; + + QList anEmptyList; + // This method will call Selection changed event which will call onSelectionChanged + // To clear mySelection, myListView and storeValue() + // So, we don't need to call it + myWorkshop->setSelected(anEmptyList); + + myIsNeutralPointClear = isClearInNeutralPoint; } //******************************************************************** @@ -563,10 +799,6 @@ void ModuleBase_WidgetMultiSelector::onDeleteItem() //******************************************************************** void ModuleBase_WidgetMultiSelector::onListSelection() { - QList aItems = myListControl->selectedItems(); - myCopyAction->setEnabled(!aItems.isEmpty()); - myDeleteAction->setEnabled(!aItems.isEmpty()); - myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeHighlightedObjects, true); } @@ -574,16 +806,11 @@ void ModuleBase_WidgetMultiSelector::onListSelection() //******************************************************************** void ModuleBase_WidgetMultiSelector::getSelectedAttributeIndices(std::set& theAttributeIds) { - QList aItems = myListControl->selectedItems(); - foreach(QListWidgetItem* anItem, aItems) { - int anIndex = anItem->data(ATTRIBUTE_SELECTION_INDEX_ROLE).toInt(); - if (theAttributeIds.find(anIndex) == theAttributeIds.end()) - theAttributeIds.insert(anIndex); - } + myListView->getSelectedIndices(theAttributeIds); } void ModuleBase_WidgetMultiSelector::convertIndicesToViewerSelection(std::set theAttributeIds, - QList& theValues) const + QList& theValues) const { if(myFeature.get() == NULL) return; @@ -598,7 +825,7 @@ void ModuleBase_WidgetMultiSelector::convertIndicesToViewerSelection(std::setvalue(i); - ResultPtr anObject = anAttr->context(); + ObjectPtr anObject = anAttr->contextObject(); if (anObject.get()) theValues.append(std::shared_ptr( new ModuleBase_ViewerPrs(anObject, anAttr->value(), NULL))); @@ -648,24 +875,31 @@ bool ModuleBase_WidgetMultiSelector::removeUnusedAttributeObjects std::string aType = anAttribute->attributeType(); std::set aShapes; std::set anIndicesToBeRemoved; + FeaturePtr aFeature; if (aType == ModelAPI_AttributeSelectionList::typeId()) { // iteration through data model to find not selected elements to remove them AttributeSelectionListPtr aSelectionListAttr = aData->selectionList(attributeID()); for (int i = 0; i < aSelectionListAttr->size(); i++) { AttributeSelectionPtr anAttr = aSelectionListAttr->value(i); - bool aFound = findInSelection(anAttr->context(), anAttr->value(), aGeomSelection); - if (!aFound) - anIndicesToBeRemoved.insert(i); + //aFeature = std::dynamic_pointer_cast(anAttr->contextObject()); + //if (!aFeature.get()) { // Feature can not be found as geometry selection + bool aFound = findInSelection( + anAttr->contextObject(), anAttr->value(), aGeomSelection, myWorkshop); + if (!aFound) + anIndicesToBeRemoved.insert(i); +// } } isDone = anIndicesToBeRemoved.size() > 0; - aSelectionListAttr->remove(anIndicesToBeRemoved); + if (isDone) + aSelectionListAttr->remove(anIndicesToBeRemoved); } else if (aType == ModelAPI_AttributeRefList::typeId()) { AttributeRefListPtr aRefListAttr = aData->reflist(attributeID()); for (int i = 0; i < aRefListAttr->size(); i++) { ObjectPtr anObject = aRefListAttr->object(i); if (anObject.get()) { - bool aFound = findInSelection(anObject, GeomShapePtr(), aGeomSelection); + bool aFound = findInSelection(anObject, GeomShapePtr(), aGeomSelection, + myWorkshop); if (!aFound) anIndicesToBeRemoved.insert(i); } @@ -675,7 +909,8 @@ bool ModuleBase_WidgetMultiSelector::removeUnusedAttributeObjects } else if (aType == ModelAPI_AttributeRefAttrList::typeId()) { std::set anAttributes; - QList::const_iterator anIt = theValues.begin(), aLast = theValues.end(); + QList::const_iterator + anIt = theValues.begin(), aLast = theValues.end(); ObjectPtr anObject; GeomShapePtr aShape; for (; anIt != aLast; anIt++) { @@ -694,7 +929,8 @@ bool ModuleBase_WidgetMultiSelector::removeUnusedAttributeObjects aFound = anAttributes.find(anAttribute) != anAttributes.end(); } else { - aFound = findInSelection(aRefAttrListAttr->object(i), GeomShapePtr(), aGeomSelection); + aFound = findInSelection(aRefAttrListAttr->object(i), GeomShapePtr(), aGeomSelection, + myWorkshop); } if (!aFound) anIndicesToBeRemoved.insert(i); @@ -733,20 +969,127 @@ std::map > ModuleBase_WidgetMultiSelector::con } bool ModuleBase_WidgetMultiSelector::findInSelection(const ObjectPtr& theObject, - const GeomShapePtr& theShape, - const std::map >& theGeomSelection) + GeomShapePtr theShape, + const std::map >& theGeomSelection, + ModuleBase_IWorkshop* theWorkshop) { + if (!theObject.get()) + return false; + // issue #2154: we should not remove from list objects hidden in the viewer if selection + // was done with SHIFT button + if (theWorkshop->hasSHIFTPressed() && !theObject->isDisplayed()) + return true; + bool aFound = false; - GeomShapePtr anEmptyShape(new GeomAPI_Shape()); - GeomShapePtr aShape = theShape.get() ? theShape : anEmptyShape; + GeomShapePtr aShape = theShape; + if (!aShape.get()) { + // #2429 (the preselection of a sketch is not taken into account) + ResultPtr aResult = std::dynamic_pointer_cast(theObject); + if (aResult.get()) + aShape = aResult->shape(); + } if (theGeomSelection.find(theObject) != theGeomSelection.end()) {// found const std::set& aShapes = theGeomSelection.at(theObject); std::set::const_iterator anIt = aShapes.begin(), aLast = aShapes.end(); for (; anIt != aLast && !aFound; anIt++) { GeomShapePtr aCShape = *anIt; if (aCShape.get()) - aFound = aCShape->isEqual(aShape); + { + // treat shape equal to context as null: 2219, keep order of shapes in list + if (aCShape->isNull()) { // in selection, shape of result is equal to selected shape + // if so, here we need to check shape of result + ResultPtr aResult = std::dynamic_pointer_cast(theObject); + if (aResult.get()) + aCShape = aResult->shape(); + } + aFound = aCShape->isSame(aShape); + } + } + } + + // issue #2903: (Possibility to hide faces) - check whether given shape is a hidden sub-shape + if (!aFound && theShape.get() && theWorkshop->hasSHIFTPressed() && theObject->isDisplayed()) { + AISObjectPtr anAIS = theWorkshop->findPresentation(theObject); + if (anAIS.get() != NULL) { + Handle(AIS_InteractiveObject) anAISIO = anAIS->impl(); + + Handle(ModuleBase_ResultPrs) aResultPrs = Handle(ModuleBase_ResultPrs)::DownCast(anAISIO); + if (!aResultPrs.IsNull() && aResultPrs->isSubShapeHidden(theShape->impl())) + return true; } } + return aFound; } + +QList + ModuleBase_WidgetMultiSelector::actionsList(ModuleBase_ActionType theActionType) const +{ + QList aList; + if (myCurrentHistoryIndex > -1) { + int i = 0; + QString aTitle("Selection %1 items"); + QString aTit("Selection %1 item"); + QIcon aIcon(":pictures/selection.png"); + int aNb; + switch (theActionType) { + case ActionUndo: + i = 1; + while (i <= myCurrentHistoryIndex) { + aNb = mySelectedHistoryValues.at(i).count(); + if (aNb == 1) { + ActionInfo aInfo(aIcon, aTit.arg(aNb)); + aList.insert(0, aInfo); + } else { + ActionInfo aInfo(aIcon, aTitle.arg(aNb)); + aList.insert(0, aInfo); + } + i++; + } + break; + case ActionRedo: + i = mySelectedHistoryValues.length() - 1; + while (i > myCurrentHistoryIndex) { + aNb = mySelectedHistoryValues.at(i).count(); + if (aNb == 1) { + ActionInfo aInfo(aIcon, aTit.arg(mySelectedHistoryValues.at(i).count())); + aList.insert(0, aInfo); + } else { + ActionInfo aInfo(aIcon, aTitle.arg(mySelectedHistoryValues.at(i).count())); + aList.insert(0, aInfo); + } + i--; + } + break; + } + } + return aList; +} + + +void ModuleBase_WidgetMultiSelector::onFeatureAccepted() +{ + defaultValues[myFeatureId + attributeID()] = myDefMode; +} + +void ModuleBase_WidgetMultiSelector::onListActivated() +{ + //focusTo(); + emitFocusInWidget(); +} + +void ModuleBase_WidgetMultiSelector::onSameTopology(bool theOn) +{ + AttributePtr anAttribute = myFeature->data()->attribute(attributeID()); + std::string aType = anAttribute->attributeType(); + if (aType == ModelAPI_AttributeSelectionList::typeId()) { + AttributeSelectionListPtr aSelectionListAttr = myFeature->data()->selectionList(attributeID()); + aSelectionListAttr->setGeometricalSelection(theOn); + updateObject(myFeature); + } +} + +void ModuleBase_WidgetMultiSelector::onShowOnly() +{ + +}