Salome HOME
Fix for import/export features property panels crashes in some cases.
[modules/shaper.git] / src / ModuleBase / ModuleBase_WidgetMultiSelector.cpp
old mode 100755 (executable)
new mode 100644 (file)
index 8dd4075..1740c62
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+// 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
 //
 // 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
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 //
-// See http://www.salome-platform.org/ or
-// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
 #include <ModuleBase_WidgetMultiSelector.h>
@@ -38,6 +37,7 @@
 #include <ModuleBase_ViewerPrs.h>
 #include <ModuleBase_WidgetShapeSelector.h>
 #include <ModuleBase_ChoiceCtrl.h>
+#include <ModuleBase_WidgetSelectionFilter.h>
 
 #include <ModelAPI_Data.h>
 #include <ModelAPI_Object.h>
@@ -62,6 +62,8 @@
 #include <QClipboard>
 #include <QTimer>
 #include <QMainWindow>
+#include <QCheckBox>
+#include <QPushButton>
 
 #include <memory>
 #include <string>
@@ -112,22 +114,28 @@ ModuleBase_WidgetMultiSelector::ModuleBase_WidgetMultiSelector(QWidget* theParen
                                                                const Config_WidgetAPI* theData)
 : ModuleBase_WidgetSelector(theParent, theWorkshop, theData),
   myIsSetSelectionBlocked(false), myCurrentHistoryIndex(-1),
-  myIsFirst(true)
+  myIsFirst(true), myFiltersWgt(0)
 {
-  std::string aPropertyTypes = theData->getProperty("type_choice");
+  std::string aPropertyTypes = theData->getProperty("shape_types");
   QString aTypesStr = aPropertyTypes.c_str();
   myShapeTypes = aTypesStr.split(' ', QString::SkipEmptyParts);
   myIsUseChoice = theData->getBooleanAttribute("use_choice", false);
 
-  QGridLayout* aMainLay = new QGridLayout(this);
+  QString aAllowedList(theData->getProperty("allow_objects").c_str());
+  if (!aAllowedList.isEmpty())
+    myAllowedObjects = aAllowedList.split(' ', QString::SkipEmptyParts);
+
+  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, 0, 0, 1, 2);
-  myDefMode = myShapeTypes.first().toStdString();
+  if (!myShapeTypes.empty()) {
+    myTypeCtrl->setValue(0);
+    myDefMode = myShapeTypes.first().toStdString();
+  }
+  aMainLay->addWidget(myTypeCtrl);
 
   // 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
@@ -136,18 +144,25 @@ ModuleBase_WidgetMultiSelector::ModuleBase_WidgetMultiSelector(QWidget* theParen
   }
 
   QString aLabelText = translate(theData->getProperty("label"));
-  QLabel* aListLabel = new QLabel(aLabelText, this);
-  aMainLay->addWidget(aListLabel, 1, 0);
-  // 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));
-      aMainLay->addWidget(aSelectedLabel, 1, 1);
+  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());
@@ -155,14 +170,39 @@ ModuleBase_WidgetMultiSelector::ModuleBase_WidgetMultiSelector(QWidget* theParen
   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(), 2, 0, 1, -1);
-  aMainLay->setRowStretch(2, 1);
-  //aMainLay->addWidget(new QLabel(this)); //FIXME(sbh)???
-  //aMainLay->setRowMinimumHeight(3, 20);
-  //this->setLayout(aMainLay);
+  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);
+    aShowBtn->setCheckable(true);
+    aShowBtn->setChecked(false);
+    connect(aShowBtn, SIGNAL(toggled(bool)), SLOT(onShowOnly(bool)));
+    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())) {
@@ -181,18 +221,53 @@ void ModuleBase_WidgetMultiSelector::activateCustom()
 {
   ModuleBase_WidgetSelector::activateCustom();
 
-  myWorkshop->module()->activateCustomPrs(myFeature,
+  ModuleBase_IModule* aModule = myWorkshop->module();
+  aModule->activateCustomPrs(myFeature,
                             ModuleBase_IModule::CustomizeHighlightedObjects, true);
   clearSelectedHistory();
+  if (myAllowedObjects.length() > 0) {
+    Handle(SelectMgr_Filter) aFilter = aModule->selectionFilter(SF_GlobalFilter);
+    if (!aFilter.IsNull()) {
+      Handle(ModuleBase_ShapeDocumentFilter) aDocFilter =
+        Handle(ModuleBase_ShapeDocumentFilter)::DownCast(aFilter);
+      if (!aDocFilter.IsNull()) {
+        QStringList aSelFilters = aDocFilter->nonSelectableTypes();
+        foreach(QString aType, aSelFilters) {
+          if (aSelFilters.contains(aType)) {
+            aDocFilter->removeNonSelectableType(aType);
+            myTmpAllowed.append(aType);
+          }
+        }
+      }
+    }
+  }
 }
 
 //********************************************************************
 void ModuleBase_WidgetMultiSelector::deactivate()
 {
+  myWorkshop->module()->enableCustomModes();
+
   ModuleBase_WidgetSelector::deactivate();
+  if (myVisibleObjects.size())
+    onShowOnly(false);
 
   myWorkshop->module()->deactivateCustomPrs(ModuleBase_IModule::CustomizeHighlightedObjects, true);
   clearSelectedHistory();
+  if (myTmpAllowed.length() > 0) {
+    ModuleBase_IModule* aModule = myWorkshop->module();
+    Handle(SelectMgr_Filter) aFilter = aModule->selectionFilter(SF_GlobalFilter);
+    if (!aFilter.IsNull()) {
+      Handle(ModuleBase_ShapeDocumentFilter) aDocFilter =
+        Handle(ModuleBase_ShapeDocumentFilter)::DownCast(aFilter);
+      if (!aDocFilter.IsNull()) {
+        foreach(QString aType, myTmpAllowed) {
+          aDocFilter->addNonSelectableType(aType);
+        }
+      }
+    }
+    myTmpAllowed.clear();
+  }
 }
 
 //********************************************************************
@@ -221,13 +296,23 @@ bool ModuleBase_WidgetMultiSelector::storeValueCustom()
   std::string aType = anAttribute->attributeType();
   if (aType == ModelAPI_AttributeSelectionList::typeId()) {
     AttributeSelectionListPtr aSelectionListAttr = myFeature->data()->selectionList(attributeID());
+    if (myTypeCtrl->isVisible()) {
+      std::string aMode = myTypeCtrl->textValue().toStdString();
+      if (myIsFirst && (!myDefMode.empty()))
+        aMode = myDefMode;
 
-    std::string aMode = myTypeCtrl->textValue().toStdString();
-    if (myTypeCtrl->isVisible() && myIsFirst && (!myDefMode.empty()))
-      aMode = myDefMode;
-
-    aSelectionListAttr->setSelectionType(aMode);
-    myIsFirst = false;
+      aSelectionListAttr->setSelectionType(aMode);
+      myIsFirst = false;
+    } else { // no type, set the type as a first element of the list shape type when it is appeared
+      if (aSelectionListAttr->size()) {
+        AttributeSelectionPtr aSel = aSelectionListAttr->value(0);
+        GeomShapePtr aFirstVal = aSel->value();
+        if (!aFirstVal.get() && aSel->context().get())
+          aFirstVal = aSel->context()->shape();
+        if (aFirstVal.get() && !aFirstVal->isNull())
+          aSelectionListAttr->setSelectionType(aFirstVal->shapeTypeStr());
+      }
+    }
   }
   return true;
 }
@@ -240,9 +325,9 @@ bool ModuleBase_WidgetMultiSelector::restoreValueCustom()
     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()) {
@@ -251,6 +336,8 @@ bool ModuleBase_WidgetMultiSelector::restoreValueCustom()
       myIsFirst = false;
     }
   }
+  if (myGeomCheck)
+    myGeomCheck->setChecked(aSelectionListAttr->isGeometricalSelection());
   updateSelectionList();
   return true;
 }
@@ -300,6 +387,12 @@ bool ModuleBase_WidgetMultiSelector::setSelection(QList<ModuleBase_ViewerPrsPtr>
     // 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) {
@@ -392,6 +485,11 @@ bool ModuleBase_WidgetMultiSelector::isValidSelectionCustom(const ModuleBase_Vie
   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<ModelAPI_Feature>(thePrs->object());
+      if (aFeature.get())
+        aResult = aFeature->firstResult();
+    }
     aValid = aResult.get() != NULL;
     if (aValid) {
       if (myFeature) {
@@ -479,6 +577,7 @@ void ModuleBase_WidgetMultiSelector::onSelectionTypeChanged()
 {
   // 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<ModuleBase_ViewerPrsPtr> aEmptyList;
   myWorkshop->setSelected(aEmptyList);
 
@@ -492,7 +591,7 @@ void ModuleBase_WidgetMultiSelector::onSelectionTypeChanged()
   std::string aType = anAttribute->attributeType();
   if (aType == ModelAPI_AttributeSelectionList::typeId()) {
     AttributeSelectionListPtr aSelectionListAttr = myFeature->data()->selectionList(attributeID());
-    aSelectionListAttr->setSelectionType(myTypeCtrl->textValue().toStdString());
+    aSelectionListAttr->setSelectionType(aSelectionType.toStdString());
   }
 
   // clear attribute values
@@ -696,7 +795,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 {
@@ -780,7 +879,7 @@ void ModuleBase_WidgetMultiSelector::convertIndicesToViewerSelection(std::set<in
       if (!theAttributeIds.empty() && theAttributeIds.find(i) == theAttributeIds.end())
         continue;
       AttributeSelectionPtr anAttr = aSelectionListAttr->value(i);
-      ResultPtr anObject = anAttr->context();
+      ObjectPtr anObject = anAttr->contextObject();
       if (anObject.get())
         theValues.append(std::shared_ptr<ModuleBase_ViewerPrs>(
                new ModuleBase_ViewerPrs(anObject, anAttr->value(), NULL)));
@@ -830,18 +929,23 @@ bool ModuleBase_WidgetMultiSelector::removeUnusedAttributeObjects
   std::string aType = anAttribute->attributeType();
   std::set<GeomShapePtr> aShapes;
   std::set<int> 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,
-                                    myWorkshop);
-      if (!aFound)
-        anIndicesToBeRemoved.insert(i);
+      //aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(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());
@@ -923,6 +1027,8 @@ bool ModuleBase_WidgetMultiSelector::findInSelection(const ObjectPtr& theObject,
                               const std::map<ObjectPtr, std::set<GeomShapePtr> >& 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())
@@ -1019,3 +1125,56 @@ 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(bool theChecked)
+{
+  std::list<ResultPtr> aResults = myFeature->results();
+   std::list<ResultPtr>::const_iterator aIt;
+  if (theChecked) {
+    myVisibleObjects = myWorkshop->displayedObjects();
+    for (aIt = aResults.cbegin(); aIt != aResults.cend(); aIt++) {
+      myVisibleObjects.removeAll(*aIt);
+    }
+    myWorkshop->module()->disableCustomMode(ModuleBase_IModule::CustomizeArguments);
+  }
+  else
+    myWorkshop->module()->enableCustomModes();
+
+  foreach(ObjectPtr aObj, myVisibleObjects) {
+    aObj->setDisplayed(!theChecked);
+  }
+
+  if (!theChecked) {
+    // Hide and show the group result in order to make it above all objects
+    bool aOldState = myWorkshop->enableUpdateViewer(false);
+    for (aIt = aResults.cbegin(); aIt != aResults.cend(); aIt++) {
+      (*aIt)->setDisplayed(false);
+    }
+    Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
+    for (aIt = aResults.cbegin(); aIt != aResults.cend(); aIt++) {
+      (*aIt)->setDisplayed(true);
+    }
+    Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
+    myWorkshop->enableUpdateViewer(aOldState);
+
+    myVisibleObjects.clear();
+  } else
+    Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
+}