Salome HOME
Issue #529 : 4.07. Import IGES, export to BREP, STEP, IGES - Remove redundant code...
[modules/shaper.git] / src / ModuleBase / ModuleBase_WidgetMultiSelector.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 /*
4  * ModuleBase_WidgetMultiSelector.cpp
5  *
6  *  Created on: Aug 28, 2014
7  *      Author: sbh
8  */
9
10 #include <ModuleBase_WidgetMultiSelector.h>
11 #include <ModuleBase_WidgetShapeSelector.h>
12 #include <ModuleBase_ISelection.h>
13 #include <ModuleBase_IWorkshop.h>
14 #include <ModuleBase_IViewer.h>
15 #include <ModuleBase_Tools.h>
16 #include <ModuleBase_Definitions.h>
17
18 #include <ModelAPI_Data.h>
19 #include <ModelAPI_Object.h>
20
21 #include <Config_WidgetAPI.h>
22
23 #include <QGridLayout>
24 #include <QLabel>
25 #include <QListWidget>
26 #include <QObject>
27 #include <QString>
28 #include <QComboBox>
29 #include <QEvent>
30 #include <QAction>
31 #include <QApplication>
32 #include <QClipboard>
33
34 #include <memory>
35 #include <string>
36
37 ModuleBase_WidgetMultiSelector::ModuleBase_WidgetMultiSelector(QWidget* theParent,
38                                                                ModuleBase_IWorkshop* theWorkshop,
39                                                                const Config_WidgetAPI* theData,
40                                                                const std::string& theParentId)
41     : ModuleBase_WidgetValidated(theParent, theData, theParentId),
42       myWorkshop(theWorkshop), myIsActive(false)
43 {
44   QGridLayout* aMainLay = new QGridLayout(this);
45   ModuleBase_Tools::adjustMargins(aMainLay);
46
47   QLabel* aTypeLabel = new QLabel(tr("Type"), this);
48   aMainLay->addWidget(aTypeLabel, 0, 0);
49
50   myTypeCombo = new QComboBox(this);
51   // There is no sence to paramerize list of types while we can not parametrize selection mode
52
53   std::string aPropertyTypes = theData->getProperty("type_choice");
54   QString aTypesStr = aPropertyTypes.c_str();
55   QStringList aShapeTypes = aTypesStr.split(' ');
56
57   myTypeCombo->addItems(aShapeTypes);
58   aMainLay->addWidget(myTypeCombo, 0, 1);
59   // if the xml definition contains one type, the controls to select a type should not be shown
60   if (aShapeTypes.size() == 1) {
61     aTypeLabel->setVisible(false);
62     myTypeCombo->setVisible(false);
63   }
64
65   QLabel* aListLabel = new QLabel(tr("Selected objects:"), this);
66   aMainLay->addWidget(aListLabel, 1, 0);
67   // if the xml definition contains one type, an information label should be shown near to the latest
68   if (aShapeTypes.size() == 1) {
69     QString aLabelText = QString::fromStdString(theData->widgetLabel());
70     QString aLabelIcon = QString::fromStdString(theData->widgetIcon());
71     QLabel* aSelectedLabel = new QLabel(aLabelText, this);
72     if (!aLabelIcon.isEmpty())
73       aSelectedLabel->setPixmap(QPixmap(aLabelIcon));
74     aMainLay->addWidget(aSelectedLabel, 1, 1);
75     aMainLay->setColumnStretch(2, 1);
76   }
77
78   myListControl = new QListWidget(this);
79   aMainLay->addWidget(myListControl, 2, 0, 2, -1);
80   aMainLay->setRowStretch(2, 1);
81   aMainLay->addWidget(new QLabel(this)); //FIXME(sbh)???
82   aMainLay->setRowMinimumHeight(3, 20);
83   this->setLayout(aMainLay);
84   connect(myTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onSelectionTypeChanged()));
85
86   myCopyAction = new QAction(QIcon(":pictures/copy.png"), tr("Copy"), this);
87   myCopyAction->setShortcut(QKeySequence::Copy);
88   myCopyAction->setEnabled(false);
89   connect(myCopyAction, SIGNAL(triggered(bool)), SLOT(onCopyItem()));
90   myListControl->addAction(myCopyAction);
91   myListControl->setContextMenuPolicy(Qt::ActionsContextMenu);
92   connect(myListControl, SIGNAL(itemSelectionChanged()), SLOT(onListSelection()));
93 }
94
95 ModuleBase_WidgetMultiSelector::~ModuleBase_WidgetMultiSelector()
96 {
97   myIsActive = false;
98   activateShapeSelection();
99 }
100
101 //********************************************************************
102 void ModuleBase_WidgetMultiSelector::activateCustom()
103 {
104   ModuleBase_IViewer* aViewer = myWorkshop->viewer();
105   connect(myWorkshop, SIGNAL(selectionChanged()), 
106           this,       SLOT(onSelectionChanged()), 
107           Qt::UniqueConnection);
108
109   myIsActive = true;
110   activateShapeSelection();
111
112   QObjectPtrList anObjects;
113   // Restore selection in the viewer by the attribute selection list
114   if(myFeature) {
115     DataPtr aData = myFeature->data();
116     AttributeSelectionListPtr aListAttr = 
117       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
118     if (aListAttr) {
119       for (int i = 0; i < aListAttr->size(); i++) {
120         AttributeSelectionPtr anAttr = aListAttr->value(i);
121         ResultPtr anObject = anAttr->context();
122         if (anObject.get())
123           anObjects.append(anObject);
124       }
125     }
126   }
127   myWorkshop->setSelected(anObjects);
128 }
129
130 //********************************************************************
131 void ModuleBase_WidgetMultiSelector::deactivate()
132 {
133   disconnect(myWorkshop, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged()));
134   myIsActive = false;
135   activateShapeSelection();
136 }
137
138 //********************************************************************
139 bool ModuleBase_WidgetMultiSelector::storeValueCustom() const
140 {
141   // the value is stored on the selection changed signal processing 
142   // A rare case when plugin was not loaded. 
143   if(!myFeature)
144     return false;
145   DataPtr aData = myFeature->data();
146   AttributeSelectionListPtr aSelectionListAttr = 
147     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
148
149   if (aSelectionListAttr) {
150     // Store shapes type
151      TopAbs_ShapeEnum aCurrentType =
152            ModuleBase_Tools::shapeType(myTypeCombo->currentText());
153      aSelectionListAttr->setSelectionType(myTypeCombo->currentText().toStdString());
154   }   
155    return true;
156 }
157
158 //********************************************************************
159 bool ModuleBase_WidgetMultiSelector::restoreValue()
160 {
161   // A rare case when plugin was not loaded. 
162   if(!myFeature)
163     return false;
164   DataPtr aData = myFeature->data();
165   AttributeSelectionListPtr aSelectionListAttr = 
166     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
167
168   if (aSelectionListAttr) {
169     // Restore shape type
170     if (!aSelectionListAttr->selectionType().empty())
171       setCurrentShapeType(ModuleBase_Tools::shapeType(aSelectionListAttr->selectionType().c_str()));
172     updateSelectionList(aSelectionListAttr);
173     return true;
174   }
175   return false;
176 }
177
178 //********************************************************************
179 void ModuleBase_WidgetMultiSelector::storeAttributeValue()
180 {
181   DataPtr aData = myFeature->data();
182   AttributeSelectionListPtr aSelectionListAttr = 
183     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
184   if (aSelectionListAttr.get() == NULL)
185     return;
186
187   mySelectionType = aSelectionListAttr->selectionType();
188   mySelection.clear();
189   int aSize = aSelectionListAttr->size();
190   for (int i = 0; i < aSelectionListAttr->size(); i++) {
191     AttributeSelectionPtr aSelectAttr = aSelectionListAttr->value(i);
192     mySelection.append(GeomSelection(aSelectAttr->context(), aSelectAttr->value()));
193   }
194 }
195
196 //********************************************************************
197 void ModuleBase_WidgetMultiSelector::restoreAttributeValue(bool/* theValid*/)
198 {
199   DataPtr aData = myFeature->data();
200   AttributeSelectionListPtr aSelectionListAttr = 
201     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
202   if (aSelectionListAttr.get() == NULL)
203     return;
204   aSelectionListAttr->clear();
205
206   // Store shapes type
207   aSelectionListAttr->setSelectionType(mySelectionType);
208
209   // Store selection in the attribute
210   int aSize = mySelection.size();
211   foreach (GeomSelection aSelec, mySelection) {
212     aSelectionListAttr->append(aSelec.first, aSelec.second);
213   }
214 }
215
216 //********************************************************************
217 bool ModuleBase_WidgetMultiSelector::setSelection(const QList<ModuleBase_ViewerPrs>& theValues,
218                                                   int& thePosition)
219 {
220   if (thePosition < 0)
221     return false;
222
223   QList<ModuleBase_ViewerPrs>::const_iterator anIt = theValues.begin(), aLast = theValues.end();
224   bool isDone = false;
225   for (int i = thePosition; i < theValues.size(); i++) {
226     ModuleBase_ViewerPrs aValue = theValues[i];
227     thePosition++;
228     bool aProcessed = false;
229     if (isValidSelection(aValue)) {
230       aProcessed = setSelectionCustom(aValue);
231     }
232     // if there is at least one set, the result is true
233     isDone = isDone || aProcessed;
234     // when an object, which do not satisfy the validating process, stop set selection
235     if (!aProcessed)
236       break;
237   }
238   if (isDone) {
239     updateObject(myFeature);
240     emit valuesChanged();
241   }
242   return isDone;
243 }
244
245 //********************************************************************
246 bool ModuleBase_WidgetMultiSelector::setSelectionCustom(const ModuleBase_ViewerPrs& thePrs)
247 {
248   TopoDS_Shape aShape = thePrs.shape();
249   if ((myTypeCombo->count() > 1) && (!aShape.IsNull())) {
250     TopAbs_ShapeEnum aType = ModuleBase_Tools::shapeType(myTypeCombo->currentText());
251     if (aShape.ShapeType() != aType)
252       return false;
253   }
254   ResultPtr aResult;
255   if (!thePrs.owner().IsNull()) {
256     ObjectPtr anObject = myWorkshop->selection()->getSelectableObject(thePrs.owner());
257     aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
258   }
259   else {
260     aResult = std::dynamic_pointer_cast<ModelAPI_Result>(thePrs.object());
261   }
262
263
264   if (myFeature) {
265     // We can not select a result of our feature
266     const std::list<ResultPtr>& aResList = myFeature->results();
267     std::list<ResultPtr>::const_iterator aIt;
268     bool isSkipSelf = false;
269     for (aIt = aResList.cbegin(); aIt != aResList.cend(); ++aIt) {
270       if ((*aIt) == aResult) {
271         isSkipSelf = true;
272         break;
273       }
274     }
275     if(isSkipSelf)
276       return false;
277   }
278
279   // if the result has the similar shap as the parameter shape, just the context is set to the
280   // selection list attribute.
281   DataPtr aData = myFeature->data();
282   AttributeSelectionListPtr aSelectionListAttr = 
283     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
284
285   const TopoDS_Shape& aTDSShape = thePrs.shape();
286   // if only result is selected, an empty shape is set to the model
287   if (aTDSShape.IsNull()) {
288     aSelectionListAttr->append(aResult, GeomShapePtr());
289   }
290   else {
291     GeomShapePtr aShape(new GeomAPI_Shape());
292     aShape->setImpl(new TopoDS_Shape(aTDSShape));
293     // We can not select a result of our feature
294     if (aShape->isEqual(aResult->shape()))
295       aSelectionListAttr->append(aResult, GeomShapePtr());
296     else
297       aSelectionListAttr->append(aResult, aShape);
298   }
299   return true;
300 }
301
302 //********************************************************************
303 QList<QWidget*> ModuleBase_WidgetMultiSelector::getControls() const
304 {
305   QList<QWidget*> result;
306   //result << myTypeCombo;
307   result << myListControl;
308   return result;
309 }
310
311 //********************************************************************
312 bool ModuleBase_WidgetMultiSelector::eventFilter(QObject* theObj, QEvent* theEvent)
313 {
314   //TODO: Remove maybe?
315   return ModuleBase_ModelWidget::eventFilter(theObj, theEvent);
316 }
317
318 //********************************************************************
319 void ModuleBase_WidgetMultiSelector::onSelectionTypeChanged()
320 {
321   activateShapeSelection();
322   QObjectPtrList anEmptyList;
323   // This method will call Selection changed event which will call onSelectionChanged
324   // To clear mySelection, myListControl and storeValue()
325   // So, we don't need to call it
326   myWorkshop->setSelected(anEmptyList);
327 }
328
329 //********************************************************************
330 void ModuleBase_WidgetMultiSelector::onSelectionChanged()
331 {
332   QList<ModuleBase_ViewerPrs> aSelected = getSelectedEntitiesOrObjects(myWorkshop->selection());
333
334   DataPtr aData = myFeature->data();
335   AttributeSelectionListPtr aSelectionListAttr = 
336     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aData->attribute(attributeID()));
337
338   aSelectionListAttr->clear();
339   if (aSelected.size() > 0) {
340     foreach (ModuleBase_ViewerPrs aPrs, aSelected) {
341       if (isValidSelection(aPrs)) {
342         setSelectionCustom(aPrs);
343       }
344     }
345   }
346   emit valuesChanged();
347   // the updateObject method should be called to flush the updated sigal. The workshop listens it,
348   // calls validators for the feature and, as a result, updates the Apply button state.
349   updateObject(myFeature);
350 }
351
352 //********************************************************************
353 void ModuleBase_WidgetMultiSelector::setCurrentShapeType(const TopAbs_ShapeEnum theShapeType)
354 {
355   QString aShapeTypeName;
356   
357   for (int idx = 0; idx < myTypeCombo->count(); ++idx) {
358     aShapeTypeName = myTypeCombo->itemText(idx);
359     TopAbs_ShapeEnum aRefType = ModuleBase_Tools::shapeType(aShapeTypeName);
360     if(aRefType == theShapeType && idx != myTypeCombo->currentIndex()) {
361       myIsActive = false;
362       activateShapeSelection();
363       bool isBlocked = myTypeCombo->blockSignals(true);
364       myTypeCombo->setCurrentIndex(idx);
365       myIsActive = true;
366       myTypeCombo->blockSignals(isBlocked);
367       activateShapeSelection();
368       break;
369     }
370   }
371 }
372
373 void ModuleBase_WidgetMultiSelector::activateShapeSelection()
374 {
375   ModuleBase_IViewer* aViewer = myWorkshop->viewer();
376
377   if (myIsActive) {
378     QString aNewType = myTypeCombo->currentText();
379     QIntList aList;
380     aList.append(ModuleBase_Tools::shapeType(aNewType));
381     myWorkshop->activateSubShapesSelection(aList);
382   } else {
383     myWorkshop->deactivateSubShapesSelection();
384   }
385
386   activateFilters(myWorkshop, myIsActive);
387 }
388
389 //********************************************************************
390 void ModuleBase_WidgetMultiSelector::updateSelectionList(AttributeSelectionListPtr theList)
391 {
392   myListControl->clear();
393   for (int i = 0; i < theList->size(); i++) {
394     AttributeSelectionPtr aAttr = theList->value(i);
395     myListControl->addItem(aAttr->namingName().c_str());
396   }
397   // We have to call repaint because sometimes the List control is not updated
398   myListControl->repaint();
399 }
400
401 //********************************************************************
402 void ModuleBase_WidgetMultiSelector::onCopyItem()
403 {
404   QList<QListWidgetItem*> aItems = myListControl->selectedItems();
405   QString aRes;
406   foreach(QListWidgetItem* aItem, aItems) {
407     if (!aRes.isEmpty())
408       aRes += "\n";
409     aRes += aItem->text();
410   }
411   if (!aRes.isEmpty()) {
412     QClipboard *clipboard = QApplication::clipboard();
413     clipboard->setText(aRes);
414   }
415 }
416
417 //********************************************************************
418 void ModuleBase_WidgetMultiSelector::onListSelection()
419 {
420   QList<QListWidgetItem*> aItems = myListControl->selectedItems();
421   myCopyAction->setEnabled(!aItems.isEmpty());
422 }
423