]> SALOME platform Git repositories - modules/shaper.git/blob - src/ModuleBase/ModuleBase_WidgetMultiSelector.cpp
Salome HOME
Remove unused variable
[modules/shaper.git] / src / ModuleBase / ModuleBase_WidgetMultiSelector.cpp
1 // Copyright (C) 2014-2017  CEA/DEN, EDF R&D
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include <ModuleBase_WidgetMultiSelector.h>
22
23 #include <GeomAPI_AISObject.h>
24
25 #include <ModuleBase_ActionIntParameter.h>
26 #include <ModuleBase_Definitions.h>
27 #include <ModuleBase_Events.h>
28 #include <ModuleBase_IconFactory.h>
29 #include <ModuleBase_IModule.h>
30 #include <ModuleBase_ISelection.h>
31 #include <ModuleBase_ISelectionActivate.h>
32 #include <ModuleBase_IPropertyPanel.h>
33 #include <ModuleBase_IViewer.h>
34 #include <ModuleBase_IWorkshop.h>
35 #include <ModuleBase_ListView.h>
36 #include <ModuleBase_ResultPrs.h>
37 #include <ModuleBase_Tools.h>
38 #include <ModuleBase_ViewerPrs.h>
39 #include <ModuleBase_WidgetShapeSelector.h>
40 #include <ModuleBase_ChoiceCtrl.h>
41
42 #include <ModelAPI_Data.h>
43 #include <ModelAPI_Object.h>
44 #include <ModelAPI_AttributeSelectionList.h>
45 #include <ModelAPI_AttributeRefList.h>
46 #include <ModelAPI_AttributeRefAttrList.h>
47 #include <ModelAPI_Tools.h>
48 #include <ModelAPI_Events.h>
49
50 #include <Config_WidgetAPI.h>
51
52 #include <AIS_InteractiveObject.hxx>
53
54 #include <QGridLayout>
55 #include <QLabel>
56 #include <QListWidget>
57 #include <QObject>
58 #include <QString>
59 #include <QComboBox>
60 #include <QEvent>
61 #include <QApplication>
62 #include <QClipboard>
63 #include <QTimer>
64 #include <QMainWindow>
65
66 #include <memory>
67 #include <string>
68
69 //#define DEBUG_UNDO_REDO
70
71 #ifdef DEBUG_UNDO_REDO
72 void printHistoryInfo(const QString& theMethodName, int theCurrentHistoryIndex,
73   QList<QList<std::shared_ptr<ModuleBase_ViewerPrs> > > theSelectedHistoryValues)
74 {
75   QStringList aSizes;
76   for (int i = 0; i < theSelectedHistoryValues.size(); i++)
77     aSizes.append(QString::number(theSelectedHistoryValues[i].size()));
78
79   std::cout << theMethodName.toStdString()
80             << "  current = " << theCurrentHistoryIndex
81             << " size(history) =  " << theSelectedHistoryValues.size()
82             << " (" << aSizes.join(", ").toStdString() << ")"
83             << std::endl;
84 }
85 #endif
86
87
88 QStringList getIconsList(const QStringList& theNames)
89 {
90   QStringList aIcons;
91   foreach (QString aName, theNames) {
92     QString aUName = aName.toUpper();
93     if ((aUName == "VERTICES") || (aUName == "VERTEX"))
94       aIcons << ":pictures/vertex32.png";
95     else if ((aUName == "EDGES") || (aUName == "EDGE"))
96       aIcons << ":pictures/edge32.png";
97     else if ((aUName == "FACES") || (aUName == "FACE"))
98       aIcons << ":pictures/face32.png";
99     else if ((aUName == "SOLIDS") || (aUName == "SOLID"))
100       aIcons << ":pictures/solid32.png";
101   }
102   return aIcons;
103 }
104
105 /// Stores default values of selected option (selection mode)
106 /// It is used only in case if myTypeCtrl is used
107 static QMap<std::string, std::string> defaultValues;
108
109
110 ModuleBase_WidgetMultiSelector::ModuleBase_WidgetMultiSelector(QWidget* theParent,
111                                                                ModuleBase_IWorkshop* theWorkshop,
112                                                                const Config_WidgetAPI* theData)
113 : ModuleBase_WidgetSelector(theParent, theWorkshop, theData),
114   myIsSetSelectionBlocked(false), myCurrentHistoryIndex(-1),
115   myIsFirst(true)
116 {
117   std::string aPropertyTypes = theData->getProperty("type_choice");
118   QString aTypesStr = aPropertyTypes.c_str();
119   myShapeTypes = aTypesStr.split(' ', QString::SkipEmptyParts);
120   myIsUseChoice = theData->getBooleanAttribute("use_choice", false);
121
122   QGridLayout* aMainLay = new QGridLayout(this);
123   ModuleBase_Tools::adjustMargins(aMainLay);
124
125   QStringList aIconsList = getIconsList(myShapeTypes);
126   myTypeCtrl = new ModuleBase_ChoiceCtrl(this, myShapeTypes, aIconsList);
127   myTypeCtrl->setLabel(tr("Type"));
128   myTypeCtrl->setValue(0);
129   aMainLay->addWidget(myTypeCtrl, 0, 0, 1, 2);
130   myDefMode = myShapeTypes.first().toStdString();
131
132   // There is no sense to parameterize list of types while we can not parameterize selection mode
133   // if the xml definition contains one type, the controls to select a type should not be shown
134   if (myShapeTypes.size() <= 1 || !myIsUseChoice) {
135     myTypeCtrl->setVisible(false);
136   }
137
138   QString aLabelText = translate(theData->getProperty("label"));
139   QLabel* aListLabel = new QLabel(aLabelText, this);
140   aMainLay->addWidget(aListLabel, 1, 0);
141   // if the xml definition contains one type, an information label
142   // should be shown near to the latest
143   if (myShapeTypes.size() <= 1) {
144     QString aLabelIcon = QString::fromStdString(theData->widgetIcon());
145     if (!aLabelIcon.isEmpty()) {
146       QLabel* aSelectedLabel = new QLabel("", this);
147       aSelectedLabel->setPixmap(ModuleBase_IconFactory::loadPixmap(aLabelIcon));
148       aMainLay->addWidget(aSelectedLabel, 1, 1);
149     }
150     aMainLay->setColumnStretch(2, 1);
151   }
152
153   QString aToolTip = QString::fromStdString(theData->widgetTooltip());
154   QString anObjName = QString::fromStdString(attributeID());
155   myListView = new ModuleBase_ListView(this, anObjName, aToolTip);
156   connect(myListView->getControl(), SIGNAL(itemSelectionChanged()), SLOT(onListSelection()));
157   connect(myListView, SIGNAL(deleteActionClicked()), SLOT(onDeleteItem()));
158   connect(myListView, SIGNAL(listActivated()), SLOT(onListActivated()));
159
160   aMainLay->addWidget(myListView->getControl(), 2, 0, 1, -1);
161   aMainLay->setRowStretch(2, 1);
162   //aMainLay->addWidget(new QLabel(this)); //FIXME(sbh)???
163   //aMainLay->setRowMinimumHeight(3, 20);
164   //this->setLayout(aMainLay);
165   connect(myTypeCtrl, SIGNAL(valueChanged(int)), this, SLOT(onSelectionTypeChanged()));
166
167   myIsNeutralPointClear = theData->getBooleanAttribute("clear_in_neutral_point", true);
168   if (myShapeTypes.size() > 1 || myIsUseChoice) {
169     if (defaultValues.contains(myFeatureId + attributeID())) {
170       myDefMode = defaultValues[myFeatureId + attributeID()];
171       myTypeCtrl->setValue(myDefMode.c_str());
172     }
173   }
174 }
175
176 ModuleBase_WidgetMultiSelector::~ModuleBase_WidgetMultiSelector()
177 {
178 }
179
180 //********************************************************************
181 void ModuleBase_WidgetMultiSelector::activateCustom()
182 {
183   ModuleBase_WidgetSelector::activateCustom();
184
185   myWorkshop->module()->activateCustomPrs(myFeature,
186                             ModuleBase_IModule::CustomizeHighlightedObjects, true);
187   clearSelectedHistory();
188 }
189
190 //********************************************************************
191 void ModuleBase_WidgetMultiSelector::deactivate()
192 {
193   ModuleBase_WidgetSelector::deactivate();
194
195   myWorkshop->module()->deactivateCustomPrs(ModuleBase_IModule::CustomizeHighlightedObjects, true);
196   clearSelectedHistory();
197 }
198
199 //********************************************************************
200 void ModuleBase_WidgetMultiSelector::updateAfterDeactivation()
201 {
202   // restore previous Undo/Redo workshop state
203   myWorkshop->updateCommandStatus();
204 }
205
206 //********************************************************************
207 void ModuleBase_WidgetMultiSelector::updateAfterActivation()
208 {
209   // fill Undo/Redo actions with current information
210   myWorkshop->updateCommandStatus();
211 }
212
213 //********************************************************************
214 bool ModuleBase_WidgetMultiSelector::storeValueCustom()
215 {
216   // the value is stored on the selection changed signal processing
217   // A rare case when plugin was not loaded.
218   if (!myFeature)
219     return false;
220
221   AttributePtr anAttribute = myFeature->data()->attribute(attributeID());
222   std::string aType = anAttribute->attributeType();
223   if (aType == ModelAPI_AttributeSelectionList::typeId()) {
224     AttributeSelectionListPtr aSelectionListAttr = myFeature->data()->selectionList(attributeID());
225     std::string aMode = myTypeCtrl->textValue().toStdString();
226     if (myTypeCtrl->isVisible() && myIsFirst && (!myDefMode.empty()))
227       aMode = myDefMode;
228
229     aSelectionListAttr->setSelectionType(aMode);
230     myIsFirst = false;
231   }
232   return true;
233 }
234
235 //********************************************************************
236 bool ModuleBase_WidgetMultiSelector::restoreValueCustom()
237 {
238   // A rare case when plugin was not loaded.
239   if (!myFeature)
240     return false;
241
242   AttributePtr anAttribute = myFeature->data()->attribute(attributeID());
243   std::string aType = anAttribute->attributeType();
244   if (aType == ModelAPI_AttributeSelectionList::typeId()) {
245     AttributeSelectionListPtr aSelectionListAttr = myFeature->data()->selectionList(attributeID());
246     // Restore shape type
247     std::string aSelectionType = aSelectionListAttr->selectionType().c_str();
248     if (!aSelectionType.empty()) {
249       setCurrentShapeType(ModuleBase_Tools::shapeType(aSelectionType.c_str()));
250       myDefMode = aSelectionType;
251       myIsFirst = false;
252     }
253   }
254   updateSelectionList();
255   return true;
256 }
257
258 //********************************************************************
259 bool ModuleBase_WidgetMultiSelector::setSelection(QList<ModuleBase_ViewerPrsPtr>& theValues,
260                                                   const bool theToValidate)
261 {
262   if (myIsSetSelectionBlocked)
263     return false;
264
265   AttributeSelectionListPtr aSelectionListAttr;
266   if (attribute()->attributeType() == ModelAPI_AttributeSelectionList::typeId())
267     aSelectionListAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(attribute());
268   if (aSelectionListAttr.get())
269     aSelectionListAttr->cashValues(true);
270
271   /// remove unused objects from the model attribute.
272   /// It should be performed before new attributes append.
273   bool isDone = removeUnusedAttributeObjects(theValues);
274
275   QList<ModuleBase_ViewerPrsPtr> anInvalidValues;
276   QList<ModuleBase_ViewerPrsPtr> anAttributeValues;
277   QList<ModuleBase_ViewerPrsPtr>::const_iterator anIt = theValues.begin(), aLast = theValues.end();
278   for (; anIt != aLast; anIt++) {
279     ModuleBase_ViewerPrsPtr aValue = *anIt;
280     // do not validate and append to attribute selection presentation if it exists in the attribute
281     ObjectPtr anObject;
282     GeomShapePtr aShape;
283     getGeomSelection(aValue, anObject, aShape);
284     if (ModuleBase_Tools::hasObject(attribute(), anObject, aShape, myWorkshop, myIsInValidate)) {
285       anAttributeValues.append(aValue);
286       continue;
287     }
288     if (theToValidate && !isValidInFilters(aValue))
289       anInvalidValues.append(aValue);
290   }
291   bool aHasInvalidValues = anInvalidValues.size() > 0;
292
293   for (anIt = theValues.begin(); anIt != aLast; anIt++) {
294     ModuleBase_ViewerPrsPtr aValue = *anIt;
295     bool aProcessed = false;
296     if ((aHasInvalidValues && anInvalidValues.contains(aValue)) ||
297         anAttributeValues.contains(aValue))
298       continue;
299     aProcessed = setSelectionCustom(aValue); /// it is not optimal as hasObject() is already checked
300     // if there is at least one set, the result is true
301     isDone = isDone || aProcessed;
302   }
303   // Check the selection with validators
304   QString aError = getError();
305   if (aError.length() > 0) {
306     aSelectionListAttr->clear();
307     isDone = false;
308   }
309   // updateObject - to update/redisplay feature
310   // it is commented in order to perfom it outside the method
311   //if (isDone) {
312     //updateObject(myFeature);
313     // this emit is necessary to call store/restore method an restore type of selection
314     //emit valuesChanged();
315   //}
316
317   if (aSelectionListAttr.get())
318     aSelectionListAttr->cashValues(false);
319
320   theValues.clear();
321   if (!anInvalidValues.empty())
322     theValues.append(anInvalidValues);
323
324   if (isDone) // may be the feature's result is not displayed, but attributes should be
325     myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeArguments,
326                              true);/// hope that something is redisplayed by object updated
327
328   return isDone;
329 }
330
331 //********************************************************************
332 void ModuleBase_WidgetMultiSelector::getHighlighted(QList<ModuleBase_ViewerPrsPtr>& theValues)
333 {
334   std::set<int> anAttributeIds;
335   getSelectedAttributeIndices(anAttributeIds);
336   if (!anAttributeIds.empty())
337     convertIndicesToViewerSelection(anAttributeIds, theValues);
338 }
339
340 //********************************************************************
341 bool ModuleBase_WidgetMultiSelector::canProcessAction(ModuleBase_ActionType theActionType,
342                                                       bool& isActionEnabled)
343 {
344   isActionEnabled = false;
345   bool aCanProcess = false;
346   switch (theActionType) {
347     case ActionUndo:
348     case ActionRedo: {
349       aCanProcess = true;
350       isActionEnabled = theActionType == ActionUndo ? myCurrentHistoryIndex > 0
351           : (mySelectedHistoryValues.size() > 0 &&
352              myCurrentHistoryIndex < mySelectedHistoryValues.size() - 1);
353     }
354     break;
355     default:
356       aCanProcess = ModuleBase_WidgetSelector::canProcessAction(theActionType, isActionEnabled);
357     break;
358   }
359   return aCanProcess;
360 }
361
362 //********************************************************************
363 bool ModuleBase_WidgetMultiSelector::processAction(ModuleBase_ActionType theActionType,
364                                                    const ActionParamPtr& theParam)
365 {
366   switch (theActionType) {
367     case ActionUndo:
368     case ActionRedo: {
369       ActionIntParamPtr aParam =
370         std::dynamic_pointer_cast<ModuleBase_ActionIntParameter>(theParam);
371       int aNb = aParam->value();
372       if (theActionType == ActionUndo)
373         myCurrentHistoryIndex -= aNb;
374       else
375         myCurrentHistoryIndex += aNb;
376       QList<ModuleBase_ViewerPrsPtr> aSelected = mySelectedHistoryValues[myCurrentHistoryIndex];
377       // equal vertices should not be used here
378       ModuleBase_ISelection::filterSelectionOnEqualPoints(aSelected);
379       bool isDone = setSelection(aSelected,
380                                  false /*need not validate because values already was in list*/);
381       updateOnSelectionChanged(isDone);
382
383       myWorkshop->updateCommandStatus();
384 #ifdef DEBUG_UNDO_REDO
385       printHistoryInfo(QString("processAction %1").arg(theActionType == ActionUndo ? "Undo"
386         : "Redo"), myCurrentHistoryIndex, mySelectedHistoryValues);
387 #endif
388       return true;
389     }
390     default:
391       return ModuleBase_ModelWidget::processAction(theActionType, theParam);
392   }
393 }
394
395 //********************************************************************
396 bool ModuleBase_WidgetMultiSelector::isValidSelectionCustom(const ModuleBase_ViewerPrsPtr& thePrs)
397 {
398   bool aValid = ModuleBase_WidgetSelector::isValidSelectionCustom(thePrs);
399   if (aValid) {
400     ResultPtr aResult = myWorkshop->selection()->getResult(thePrs);
401     if (!aResult.get()) { // In case if a feature was selected
402       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(thePrs->object());
403       if (aFeature.get())
404         aResult = aFeature->firstResult();
405     }
406     aValid = aResult.get() != NULL;
407     if (aValid) {
408       if (myFeature) {
409         // We can not select a result of our feature
410         std::list<ResultPtr> aResults;
411         ModelAPI_Tools::allResults(myFeature, aResults);
412         std::list<ResultPtr>::const_iterator aIt;
413         bool isSkipSelf = false;
414         for (aIt = aResults.cbegin(); aIt != aResults.cend(); ++aIt) {
415           if ((*aIt) == aResult) {
416             isSkipSelf = true;
417             break;
418           }
419         }
420         if (isSkipSelf)
421           aValid = false;
422       }
423     }
424   }
425   return aValid;
426 }
427
428 //********************************************************************
429 bool ModuleBase_WidgetMultiSelector::processDelete()
430 {
431   appendFirstSelectionInHistory();
432
433   // find attribute indices to delete
434   std::set<int> anAttributeIds;
435   getSelectedAttributeIndices(anAttributeIds);
436
437   QModelIndexList anIndices = myListView->getControl()->selectionModel()->selectedIndexes();
438
439   // refill attribute by the items which indices are not in the list of ids
440   bool aDone = false;
441   DataPtr aData = myFeature->data();
442   AttributePtr anAttribute = aData->attribute(attributeID());
443   std::string aType = anAttribute->attributeType();
444   aDone = !anAttributeIds.empty();
445   if (aType == ModelAPI_AttributeSelectionList::typeId()) {
446     AttributeSelectionListPtr aSelectionListAttr = aData->selectionList(attributeID());
447     aSelectionListAttr->remove(anAttributeIds);
448
449   }
450   else if (aType == ModelAPI_AttributeRefList::typeId()) {
451     AttributeRefListPtr aRefListAttr = aData->reflist(attributeID());
452     aRefListAttr->remove(anAttributeIds);
453   }
454   else if (aType == ModelAPI_AttributeRefAttrList::typeId()) {
455     AttributeRefAttrListPtr aRefAttrListAttr = aData->refattrlist(attributeID());
456     aRefAttrListAttr->remove(anAttributeIds);
457   }
458
459   if (aDone) {
460     // update object is necessary to flush update signal. It leads to objects references map update
461     // and the operation presentation will not contain deleted items visualized as parameters of
462     // the feature.
463     updateObject(myFeature);
464
465     restoreValue();
466     myWorkshop->setSelected(getAttributeSelection());
467
468     // may be the feature's result is not displayed, but attributes should be
469     myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeArguments,
470                               true); /// hope that something is redisplayed by object updated
471   }
472
473   // Restore selection
474   myListView->restoreSelection(anIndices);
475
476   appendSelectionInHistory();
477   return true/*aDone*/; // following #2438 Delete should be processed even if nothing is delete
478 }
479
480 //********************************************************************
481 QList<QWidget*> ModuleBase_WidgetMultiSelector::getControls() const
482 {
483   QList<QWidget*> result;
484   result << myListView->getControl();
485   return result;
486 }
487
488 //********************************************************************
489 void ModuleBase_WidgetMultiSelector::onSelectionTypeChanged()
490 {
491   // Clear current selection in order to avoid updating of object browser with obsolete indexes
492   // which can appear because of results deletetion after changing a type of selection
493   QList<ModuleBase_ViewerPrsPtr> aEmptyList;
494   myWorkshop->setSelected(aEmptyList);
495
496   updateSelectionModesAndFilters(true);
497   myWorkshop->selectionActivate()->updateSelectionModes();
498
499   if (!myFeature)
500     return;
501   /// store the selected type
502   AttributePtr anAttribute = myFeature->data()->attribute(attributeID());
503   std::string aType = anAttribute->attributeType();
504   if (aType == ModelAPI_AttributeSelectionList::typeId()) {
505     AttributeSelectionListPtr aSelectionListAttr = myFeature->data()->selectionList(attributeID());
506     aSelectionListAttr->setSelectionType(myTypeCtrl->textValue().toStdString());
507   }
508
509   // clear attribute values
510   DataPtr aData = myFeature->data();
511   if (aType == ModelAPI_AttributeSelectionList::typeId()) {
512     AttributeSelectionListPtr aSelectionListAttr = aData->selectionList(attributeID());
513     aSelectionListAttr->clear();
514   }
515   else if (aType == ModelAPI_AttributeRefList::typeId()) {
516     AttributeRefListPtr aRefListAttr = aData->reflist(attributeID());
517     aRefListAttr->clear();
518   }
519   else if (aType == ModelAPI_AttributeRefAttrList::typeId()) {
520     AttributeRefAttrListPtr aRefAttrListAttr = aData->refattrlist(attributeID());
521     aRefAttrListAttr->clear();
522   }
523
524   // update object is necessary to flush update signal. It leads to objects references map update
525   // and the operation presentation will not contain deleted items visualized as parameters of
526   // the feature.
527   updateObject(myFeature);
528   restoreValue();
529   myWorkshop->setSelected(getAttributeSelection());
530   // may be the feature's result is not displayed, but attributes should be
531   myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeArguments,
532                             true); /// hope that something is redisplayed by object updated
533   // clear history should follow after set selected to do not increase history by setSelected
534   clearSelectedHistory();
535
536   if (myWorkshop->propertyPanel()->activeWidget() != this)
537     myWorkshop->propertyPanel()->activateWidget(this);
538 }
539
540 //********************************************************************
541 bool ModuleBase_WidgetMultiSelector::processSelection()
542 {
543   if (!myIsNeutralPointClear) {
544     QList<ModuleBase_ViewerPrsPtr> aSelected = getFilteredSelected();
545     // do not clear selected object
546     if (aSelected.size() == 0) {
547       if (!getAttributeSelection().empty()) {
548         // Restore selection in the viewer by the attribute selection list
549         // it should be postponed to exit from the selectionChanged processing
550         static Events_ID anEvent = Events_Loop::eventByName(EVENT_UPDATE_BY_WIDGET_SELECTION);
551         ModelAPI_EventCreator::get()->sendUpdated(myFeature, anEvent);
552         Events_Loop::loop()->flush(anEvent);
553         return true;
554       }
555     }
556   }
557   appendFirstSelectionInHistory();
558   bool aDone = ModuleBase_WidgetSelector::processSelection();
559   appendSelectionInHistory();
560   return aDone;
561 }
562
563 void ModuleBase_WidgetMultiSelector::appendFirstSelectionInHistory()
564 {
565   if (mySelectedHistoryValues.empty()) {
566     myCurrentHistoryIndex++;
567     mySelectedHistoryValues.append(getAttributeSelection());
568
569 #ifdef DEBUG_UNDO_REDO
570     printHistoryInfo("appendSelectionInHistory", myCurrentHistoryIndex, mySelectedHistoryValues);
571 #endif
572   }
573 }
574
575 void ModuleBase_WidgetMultiSelector::appendSelectionInHistory()
576 {
577   while (myCurrentHistoryIndex != mySelectedHistoryValues.count() - 1)
578     mySelectedHistoryValues.removeLast();
579
580   QList<ModuleBase_ViewerPrsPtr> aSelected = getFilteredSelected();
581   myCurrentHistoryIndex++;
582   mySelectedHistoryValues.append(aSelected);
583   myWorkshop->updateCommandStatus();
584
585 #ifdef DEBUG_UNDO_REDO
586   printHistoryInfo("appendSelectionInHistory", myCurrentHistoryIndex, mySelectedHistoryValues);
587 #endif
588 }
589
590 void ModuleBase_WidgetMultiSelector::clearSelectedHistory()
591 {
592   mySelectedHistoryValues.clear();
593   myCurrentHistoryIndex = -1;
594   myWorkshop->updateCommandStatus();
595
596 #ifdef DEBUG_UNDO_REDO
597   printHistoryInfo("clearSelectedHistory", myCurrentHistoryIndex, mySelectedHistoryValues);
598 #endif
599 }
600
601 void ModuleBase_WidgetMultiSelector::updateFocus()
602 {
603   // Set focus to List control in order to make possible
604   // to use Tab key for transfer the focus to next widgets
605   ModuleBase_Tools::setFocus(myListView->getControl(),
606                              "ModuleBase_WidgetMultiSelector::onSelectionTypeChanged()");
607 }
608
609 //********************************************************************
610 void ModuleBase_WidgetMultiSelector::updateSelectionName()
611 {
612 }
613
614 //********************************************************************
615 void ModuleBase_WidgetMultiSelector::updateOnSelectionChanged(const bool theDone)
616 {
617   if (myIsSetSelectionBlocked)
618     return;
619   ModuleBase_WidgetSelector::updateOnSelectionChanged(theDone);
620
621   // according to #2154 we need to update OB selection when selection in the viewer happens
622   // it is important to flush sinchronize selection signal after flush of Update/Create/Delete.
623   // because we need that Object Browser has been already updated when synchronize happens.
624
625   // Restore selection in the viewer by the attribute selection list
626   // it is possible that diring selection attribute filling, selection in Object Browser
627   // is changed(some items were removed/added) and as result, selection in the viewer
628   // differs from the selection come to this method. By next rows, we restore selection
629   // in the viewer according to content of selection attribute. Case is Edge selection in Group
630   myIsSetSelectionBlocked = true;
631   static Events_ID anEvent = Events_Loop::eventByName(EVENT_UPDATE_BY_WIDGET_SELECTION);
632   ModelAPI_EventCreator::get()->sendUpdated(myFeature, anEvent);
633   Events_Loop::loop()->flush(anEvent);
634   myIsSetSelectionBlocked = false;
635 }
636
637 //********************************************************************
638 QIntList ModuleBase_WidgetMultiSelector::shapeTypes() const
639 {
640   QIntList aShapeTypes;
641
642   if (myShapeTypes.length() > 1 && myIsUseChoice) {
643     aShapeTypes.append(ModuleBase_Tools::shapeType(myTypeCtrl->textValue()));
644   }
645   else {
646     foreach (QString aType, myShapeTypes) {
647       aShapeTypes.append(ModuleBase_Tools::shapeType(aType));
648     }
649   }
650   return aShapeTypes;
651 }
652
653 //********************************************************************
654 void ModuleBase_WidgetMultiSelector::setCurrentShapeType(const int theShapeType)
655 {
656   QString aShapeTypeName;
657
658   int idx = 0;
659   foreach (QString aShapeTypeName, myShapeTypes) {
660     int aRefType = ModuleBase_Tools::shapeType(aShapeTypeName);
661     if(aRefType == theShapeType && idx != myTypeCtrl->value()) {
662       updateSelectionModesAndFilters(false);
663       bool isBlocked = myTypeCtrl->blockSignals(true);
664       myTypeCtrl->setValue(idx);
665       myTypeCtrl->blockSignals(isBlocked);
666       updateSelectionModesAndFilters(true);
667       break;
668     }
669     idx++;
670   }
671 }
672
673 QList<ModuleBase_ViewerPrsPtr> ModuleBase_WidgetMultiSelector::getAttributeSelection() const
674 {
675   QList<ModuleBase_ViewerPrsPtr> aSelected;
676   convertIndicesToViewerSelection(std::set<int>(), aSelected);
677   return aSelected;
678 }
679
680 //********************************************************************
681 void ModuleBase_WidgetMultiSelector::updateSelectionList()
682 {
683   myListView->getControl()->clear();
684
685   DataPtr aData = myFeature->data();
686   AttributePtr anAttribute = aData->attribute(attributeID());
687   std::string aType = anAttribute->attributeType();
688   if (aType == ModelAPI_AttributeSelectionList::typeId()) {
689     AttributeSelectionListPtr aSelectionListAttr = aData->selectionList(attributeID());
690     for (int i = 0; i < aSelectionListAttr->size(); i++) {
691       AttributeSelectionPtr aAttr = aSelectionListAttr->value(i);
692       myListView->addItem(aAttr->namingName().c_str(), i);
693     }
694   }
695   else if (aType == ModelAPI_AttributeRefList::typeId()) {
696     AttributeRefListPtr aRefListAttr = aData->reflist(attributeID());
697     for (int i = 0; i < aRefListAttr->size(); i++) {
698       ObjectPtr anObject = aRefListAttr->object(i);
699       if (anObject.get()) {
700         myListView->addItem(anObject->data()->name().c_str(), i);
701       }
702     }
703   }
704   else if (aType == ModelAPI_AttributeRefAttrList::typeId()) {
705     AttributeRefAttrListPtr aRefAttrListAttr = aData->refattrlist(attributeID());
706     for (int i = 0; i < aRefAttrListAttr->size(); i++) {
707       AttributePtr anAttribute = aRefAttrListAttr->attribute(i);
708       QString aName;
709       if (anAttribute.get()) {
710         std::string anAttrName = ModuleBase_Tools::generateName(anAttribute, myWorkshop);
711         aName = QString::fromStdString(anAttrName);
712       }
713       else {
714         ObjectPtr anObject = aRefAttrListAttr->object(i);
715         if (anObject.get()) {
716           aName = anObject->data()->name().c_str();
717         }
718       }
719       myListView->addItem(aName, i);
720     }
721   }
722
723   // We have to call repaint because sometimes the List control is not updated
724   myListView->getControl()->repaint();
725 }
726
727 //********************************************************************
728 std::string ModuleBase_WidgetMultiSelector::validatorType(const QString& theType) const
729 {
730   std::string aType;
731
732   if (theType == "Vertices")
733     aType = "vertex";
734   else if (theType == "Edges")
735     aType = "edge";
736   else if (theType == "Faces")
737     aType = "face";
738   else if (theType == "Solids")
739     aType = "solid";
740
741   return aType;
742 }
743
744 //********************************************************************
745 void ModuleBase_WidgetMultiSelector::clearSelection()
746 {
747   bool isClearInNeutralPoint = myIsNeutralPointClear;
748   myIsNeutralPointClear = true;
749
750   QList<ModuleBase_ViewerPrsPtr> anEmptyList;
751   // This method will call Selection changed event which will call onSelectionChanged
752   // To clear mySelection, myListView and storeValue()
753   // So, we don't need to call it
754   myWorkshop->setSelected(anEmptyList);
755
756   myIsNeutralPointClear = isClearInNeutralPoint;
757 }
758
759 //********************************************************************
760 void ModuleBase_WidgetMultiSelector::onDeleteItem()
761 {
762   processDelete();
763 }
764
765 //********************************************************************
766 void ModuleBase_WidgetMultiSelector::onListSelection()
767 {
768   myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeHighlightedObjects,
769                                         true);
770 }
771
772 //********************************************************************
773 void ModuleBase_WidgetMultiSelector::getSelectedAttributeIndices(std::set<int>& theAttributeIds)
774 {
775   myListView->getSelectedIndices(theAttributeIds);
776 }
777
778 void ModuleBase_WidgetMultiSelector::convertIndicesToViewerSelection(std::set<int> theAttributeIds,
779                                                    QList<ModuleBase_ViewerPrsPtr>& theValues) const
780 {
781   if(myFeature.get() == NULL)
782     return;
783
784   DataPtr aData = myFeature->data();
785   AttributePtr anAttribute = aData->attribute(attributeID());
786   std::string aType = anAttribute->attributeType();
787   if (aType == ModelAPI_AttributeSelectionList::typeId()) {
788     AttributeSelectionListPtr aSelectionListAttr = aData->selectionList(attributeID());
789     for (int i = 0; i < aSelectionListAttr->size(); i++) {
790       // filter by attribute indices only if the container is not empty otherwise return all items
791       if (!theAttributeIds.empty() && theAttributeIds.find(i) == theAttributeIds.end())
792         continue;
793       AttributeSelectionPtr anAttr = aSelectionListAttr->value(i);
794       ObjectPtr anObject = anAttr->contextObject();
795       if (anObject.get())
796         theValues.append(std::shared_ptr<ModuleBase_ViewerPrs>(
797                new ModuleBase_ViewerPrs(anObject, anAttr->value(), NULL)));
798     }
799   }
800   else if (aType == ModelAPI_AttributeRefList::typeId()) {
801     AttributeRefListPtr aRefListAttr = aData->reflist(attributeID());
802     for (int i = 0; i < aRefListAttr->size(); i++) {
803       // filter by attribute indices only if the container is not empty otherwise return all items
804       if (!theAttributeIds.empty() && theAttributeIds.find(i) == theAttributeIds.end())
805         continue;
806       ObjectPtr anObject = aRefListAttr->object(i);
807       if (anObject.get()) {
808         theValues.append(std::shared_ptr<ModuleBase_ViewerPrs>(
809                new ModuleBase_ViewerPrs(anObject, GeomShapePtr(), NULL)));
810       }
811     }
812   }
813   else if (aType == ModelAPI_AttributeRefAttrList::typeId()) {
814     AttributeRefAttrListPtr aRefAttrListAttr = aData->refattrlist(attributeID());
815     for (int i = 0; i < aRefAttrListAttr->size(); i++) {
816       // filter by attribute indices only if the container is not empty otherwise return all items
817       if (!theAttributeIds.empty() && theAttributeIds.find(i) == theAttributeIds.end())
818         continue;
819       ObjectPtr anObject = aRefAttrListAttr->object(i);
820       if (!anObject.get())
821         continue;
822       TopoDS_Shape aShape;
823       AttributePtr anAttribute = aRefAttrListAttr->attribute(i);
824       if (anAttribute.get()) {
825         GeomShapePtr aGeomShape = ModuleBase_Tools::getShape(anAttribute, myWorkshop);
826         theValues.append(std::shared_ptr<ModuleBase_ViewerPrs>(
827                new ModuleBase_ViewerPrs(anObject, aGeomShape, NULL)));
828       }
829     }
830   }
831 }
832
833 bool ModuleBase_WidgetMultiSelector::removeUnusedAttributeObjects
834                                                  (QList<ModuleBase_ViewerPrsPtr>& theValues)
835 {
836   bool isDone = false;
837
838   std::map<ObjectPtr, std::set<GeomShapePtr> > aGeomSelection = convertSelection(theValues);
839   DataPtr aData = myFeature->data();
840   AttributePtr anAttribute = aData->attribute(attributeID());
841   std::string aType = anAttribute->attributeType();
842   std::set<GeomShapePtr> aShapes;
843   std::set<int> anIndicesToBeRemoved;
844   FeaturePtr aFeature;
845   if (aType == ModelAPI_AttributeSelectionList::typeId()) {
846     // iteration through data model to find not selected elements to remove them
847     AttributeSelectionListPtr aSelectionListAttr = aData->selectionList(attributeID());
848     for (int i = 0; i < aSelectionListAttr->size(); i++) {
849       AttributeSelectionPtr anAttr = aSelectionListAttr->value(i);
850       //aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->contextObject());
851       //if (!aFeature.get()) { // Feature can not be found as geometry selection
852         bool aFound = findInSelection(
853           anAttr->contextObject(), anAttr->value(), aGeomSelection, myWorkshop);
854         if (!aFound)
855           anIndicesToBeRemoved.insert(i);
856 //      }
857     }
858     isDone = anIndicesToBeRemoved.size() > 0;
859     if (isDone)
860       aSelectionListAttr->remove(anIndicesToBeRemoved);
861   }
862   else if (aType == ModelAPI_AttributeRefList::typeId()) {
863     AttributeRefListPtr aRefListAttr = aData->reflist(attributeID());
864     for (int i = 0; i < aRefListAttr->size(); i++) {
865       ObjectPtr anObject = aRefListAttr->object(i);
866       if (anObject.get()) {
867         bool aFound = findInSelection(anObject, GeomShapePtr(), aGeomSelection,
868                                       myWorkshop);
869         if (!aFound)
870           anIndicesToBeRemoved.insert(i);
871       }
872     }
873     isDone = anIndicesToBeRemoved.size() > 0;
874     aRefListAttr->remove(anIndicesToBeRemoved);
875   }
876   else if (aType == ModelAPI_AttributeRefAttrList::typeId()) {
877     std::set<AttributePtr> anAttributes;
878     QList<ModuleBase_ViewerPrsPtr>::const_iterator
879       anIt = theValues.begin(), aLast = theValues.end();
880     ObjectPtr anObject;
881     GeomShapePtr aShape;
882     for (; anIt != aLast; anIt++) {
883       ModuleBase_ViewerPrsPtr aPrs = *anIt;
884       getGeomSelection(aPrs, anObject, aShape);
885       AttributePtr anAttr = myWorkshop->module()->findAttribute(anObject, aShape);
886       if (anAttr.get() && anAttributes.find(anAttr) == anAttributes.end())
887         anAttributes.insert(anAttr);
888     }
889
890     AttributeRefAttrListPtr aRefAttrListAttr = aData->refattrlist(attributeID());
891     for (int i = 0; i < aRefAttrListAttr->size(); i++) {
892       bool aFound = false;
893       if (aRefAttrListAttr->isAttribute(i)) {
894         AttributePtr anAttribute = aRefAttrListAttr->attribute(i);
895         aFound = anAttributes.find(anAttribute) != anAttributes.end();
896       }
897       else {
898         aFound = findInSelection(aRefAttrListAttr->object(i), GeomShapePtr(), aGeomSelection,
899                                  myWorkshop);
900       }
901       if (!aFound)
902         anIndicesToBeRemoved.insert(i);
903     }
904     isDone = anIndicesToBeRemoved.size() > 0;
905     aRefAttrListAttr->remove(anIndicesToBeRemoved);
906   }
907
908   return isDone;
909 }
910
911 std::map<ObjectPtr, std::set<GeomShapePtr> > ModuleBase_WidgetMultiSelector::convertSelection
912                                                      (QList<ModuleBase_ViewerPrsPtr>& theValues)
913 {
914   // convert prs list to objects map
915   std::map<ObjectPtr, std::set<GeomShapePtr> > aGeomSelection;
916   std::set<GeomShapePtr> aShapes;
917   QList<ModuleBase_ViewerPrsPtr>::const_iterator anIt = theValues.begin(), aLast = theValues.end();
918   ObjectPtr anObject;
919   GeomShapePtr aShape;
920   GeomShapePtr anEmptyShape(new GeomAPI_Shape());
921   for (; anIt != aLast; anIt++) {
922     ModuleBase_ViewerPrsPtr aPrs = *anIt;
923     getGeomSelection(aPrs, anObject, aShape);
924     aShapes.clear();
925     if (aGeomSelection.find(anObject) != aGeomSelection.end()) // found
926       aShapes = aGeomSelection[anObject];
927     // we need to know if there was an empty shape in selection for the object
928     if (!aShape.get())
929       aShape = anEmptyShape;
930     if (aShape.get() && aShapes.find(aShape) == aShapes.end()) // not found
931       aShapes.insert(aShape);
932     aGeomSelection[anObject] = aShapes;
933   }
934   return aGeomSelection;
935 }
936
937 bool ModuleBase_WidgetMultiSelector::findInSelection(const ObjectPtr& theObject,
938                               GeomShapePtr theShape,
939                               const std::map<ObjectPtr, std::set<GeomShapePtr> >& theGeomSelection,
940                               ModuleBase_IWorkshop* theWorkshop)
941 {
942   // issue #2154: we should not remove from list objects hidden in the viewer if selection
943   // was done with SHIFT button
944   if (theWorkshop->hasSHIFTPressed() && !theObject->isDisplayed())
945     return true;
946
947   bool aFound = false;
948   GeomShapePtr aShape = theShape;
949   if (!aShape.get()) {
950     // #2429 (the preselection of a sketch is not taken into account)
951     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
952     if (aResult.get())
953       aShape = aResult->shape();
954   }
955   if (theGeomSelection.find(theObject) != theGeomSelection.end()) {// found
956     const std::set<GeomShapePtr>& aShapes = theGeomSelection.at(theObject);
957     std::set<GeomShapePtr>::const_iterator anIt = aShapes.begin(), aLast = aShapes.end();
958     for (; anIt != aLast && !aFound; anIt++) {
959       GeomShapePtr aCShape = *anIt;
960       if (aCShape.get())
961       {
962         // treat shape equal to context as null: 2219, keep order of shapes in list
963         if (aCShape->isNull()) { // in selection, shape of result is equal to selected shape
964           // if so, here we need to check shape of result
965           ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
966           if (aResult.get())
967             aCShape = aResult->shape();
968         }
969         aFound = aCShape->isSame(aShape);
970       }
971     }
972   }
973
974   // issue #2903: (Possibility to hide faces) - check whether given shape is a hidden sub-shape
975   if (!aFound && theShape.get() && theWorkshop->hasSHIFTPressed() && theObject->isDisplayed()) {
976     AISObjectPtr anAIS = theWorkshop->findPresentation(theObject);
977     if (anAIS.get() != NULL) {
978       Handle(AIS_InteractiveObject) anAISIO = anAIS->impl<Handle(AIS_InteractiveObject)>();
979
980       Handle(ModuleBase_ResultPrs) aResultPrs = Handle(ModuleBase_ResultPrs)::DownCast(anAISIO);
981       if (!aResultPrs.IsNull() && aResultPrs->isSubShapeHidden(theShape->impl<TopoDS_Shape>()))
982         return true;
983     }
984   }
985
986   return aFound;
987 }
988
989 QList<ActionInfo>
990   ModuleBase_WidgetMultiSelector::actionsList(ModuleBase_ActionType theActionType) const
991 {
992   QList<ActionInfo> aList;
993   if (myCurrentHistoryIndex > -1) {
994     int i = 0;
995     QString aTitle("Selection %1 items");
996     QString aTit("Selection %1 item");
997     QIcon aIcon(":pictures/selection.png");
998     int aNb;
999     switch (theActionType) {
1000     case ActionUndo:
1001       i = 1;
1002       while (i <= myCurrentHistoryIndex) {
1003         aNb = mySelectedHistoryValues.at(i).count();
1004         if (aNb == 1) {
1005           ActionInfo aInfo(aIcon, aTit.arg(aNb));
1006           aList.insert(0, aInfo);
1007         } else {
1008           ActionInfo aInfo(aIcon, aTitle.arg(aNb));
1009           aList.insert(0, aInfo);
1010         }
1011         i++;
1012       }
1013       break;
1014     case ActionRedo:
1015       i = mySelectedHistoryValues.length() - 1;
1016       while (i > myCurrentHistoryIndex) {
1017         aNb = mySelectedHistoryValues.at(i).count();
1018         if (aNb == 1) {
1019           ActionInfo aInfo(aIcon, aTit.arg(mySelectedHistoryValues.at(i).count()));
1020           aList.insert(0, aInfo);
1021         } else {
1022           ActionInfo aInfo(aIcon, aTitle.arg(mySelectedHistoryValues.at(i).count()));
1023           aList.insert(0, aInfo);
1024         }
1025         i--;
1026       }
1027       break;
1028     }
1029   }
1030   return aList;
1031 }
1032
1033
1034 void ModuleBase_WidgetMultiSelector::onFeatureAccepted()
1035 {
1036   defaultValues[myFeatureId + attributeID()] = myDefMode;
1037 }
1038
1039 void ModuleBase_WidgetMultiSelector::onListActivated()
1040 {
1041   //focusTo();
1042   emitFocusInWidget();
1043 }