Salome HOME
Issue #1961: Filter not acceptable shapes and objects
[modules/shaper.git] / src / CollectionPlugin / CollectionPlugin_WidgetField.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        CollectionPlugin_WidgetField.cpp
4 // Created:     16 Nov 2016
5 // Author:      Vitaly SMETANNIKOV
6
7 #include "CollectionPlugin_WidgetField.h"
8 #include "CollectionPlugin_Field.h"
9
10 #include <ModuleBase_Tools.h>
11 #include <ModuleBase_IWorkshop.h>
12 #include <ModuleBase_IModule.h>
13 #include <ModuleBase_ISelection.h>
14 #include <ModuleBase_IPropertyPanel.h>
15
16 #include <ModelAPI_AttributeSelectionList.h>
17 #include <ModelAPI_AttributeStringArray.h>
18 #include <ModelAPI_AttributeInteger.h>
19 #include <ModelAPI_AttributeIntArray.h>
20
21 #include <QLayout>
22 #include <QWidget>
23 #include <QFormLayout>
24 #include <QComboBox>
25 #include <QSpinBox>
26 #include <QLabel>
27 #include <QSlider>
28 #include <QTableWidget>
29 #include <QPushButton>
30 #include <QHeaderView>
31 #include <QStackedWidget>
32 #include <QValidator>
33 #include <QLineEdit>
34 #include <QEvent>
35 #include <QMouseEvent>
36 #include <QScrollBar>
37 #include <QApplication>
38
39 const char* MYFirstCol = "Shape";
40 const char* MYTrue = "True";
41 const char* MYFalse = "False";
42
43 QWidget* DataTableItemDelegate::createEditor(QWidget* theParent,
44                                              const QStyleOptionViewItem & theOption,
45                                              const QModelIndex& theIndex ) const
46 {
47   if ((theIndex.column() == 0) && (theIndex.row() > 0)) {
48     QWidget* aWgt = QStyledItemDelegate::createEditor(theParent, theOption, theIndex);
49     QLineEdit* aEdt = static_cast<QLineEdit*>(aWgt);
50     aEdt->setReadOnly(true);
51     return aEdt;
52   } else {
53     QLineEdit* aLineEdt = 0;
54     switch (myType) {
55     case ModelAPI_AttributeTables::DOUBLE:
56       aLineEdt = dynamic_cast<QLineEdit*>(QStyledItemDelegate::createEditor(theParent,
57                                                                             theOption,
58                                                                             theIndex));
59       if (aLineEdt) {
60         aLineEdt->setValidator(new QDoubleValidator(aLineEdt));
61         return aLineEdt;
62       }
63       break;
64     case ModelAPI_AttributeTables::INTEGER:
65       aLineEdt = dynamic_cast<QLineEdit*>(QStyledItemDelegate::createEditor(theParent,
66                                                                             theOption,
67                                                                             theIndex));
68       if (aLineEdt) {
69         aLineEdt->setValidator(new QIntValidator(aLineEdt));
70         return aLineEdt;
71       }
72       break;
73     case ModelAPI_AttributeTables::BOOLEAN:
74       {
75         QComboBox* aBox = new QComboBox(theParent);
76         aBox->addItem(MYFalse);
77         aBox->addItem(MYTrue);
78         return aBox;
79       }
80     }
81   }
82   return QStyledItemDelegate::createEditor(theParent, theOption, theIndex);
83 }
84
85
86
87 //**********************************************************************************
88 //**********************************************************************************
89 //**********************************************************************************
90 CollectionPlugin_WidgetField::
91   CollectionPlugin_WidgetField(QWidget* theParent,
92                                ModuleBase_IWorkshop* theWorkshop,
93                                const Config_WidgetAPI* theData):
94 ModuleBase_WidgetSelector(theParent, theWorkshop, theData), myHeaderEditor(0),
95   myIsTabEdit(false), myActivation(false)
96 {
97   QVBoxLayout* aMainLayout = new QVBoxLayout(this);
98
99   // Types definition controls
100   QWidget* aTypesWgt = new QWidget(this);
101   QFormLayout* aTypesLayout = new QFormLayout(aTypesWgt);
102   aTypesLayout->setContentsMargins(0, 0, 0, 0);
103   aMainLayout->addWidget(aTypesWgt);
104
105   // Type of shapes
106   myShapeTypeCombo = new QComboBox(aTypesWgt);
107   QStringList aShapeTypes;
108   aShapeTypes << tr("Vertices") << tr("Edges") << tr("Faces")
109     << tr("Solids") << tr("Objects") << tr("Parts");
110   myShapeTypeCombo->addItems(aShapeTypes);
111   aTypesLayout->addRow(tr("Type of shapes"), myShapeTypeCombo);
112
113   // Type of field
114   myFieldTypeCombo = new QComboBox(aTypesWgt);
115   QStringList aFieldTypes;
116   aFieldTypes << tr("Boolean") << tr("Integer") << tr("Double")
117     << tr("String");
118   myFieldTypeCombo->addItems(aFieldTypes);
119   myFieldTypeCombo->setCurrentIndex(2);
120   aTypesLayout->addRow(tr("Type of field"), myFieldTypeCombo);
121
122   // Number of components
123   myNbComponentsSpn = new QSpinBox(aTypesWgt);
124   myNbComponentsSpn->setMinimum(1);
125   aTypesLayout->addRow(tr("Nb. of components"), myNbComponentsSpn);
126
127   // Steps controls
128   QFrame* aStepFrame = new QFrame(this);
129   aStepFrame->setFrameShape(QFrame::Box);
130   aStepFrame->setFrameStyle(QFrame::StyledPanel);
131   QGridLayout* aStepLayout = new QGridLayout(aStepFrame);
132   aMainLayout->addWidget(aStepFrame);
133
134   // Current step label
135   aStepLayout->addWidget(new QLabel(tr("Current step"), aStepFrame), 0, 0);
136   myCurStepLbl = new QLabel("1", aStepFrame);
137   QFont aFont = myCurStepLbl->font();
138   aFont.setBold(true);
139   myCurStepLbl->setFont(aFont);
140   aStepLayout->addWidget(myCurStepLbl, 0, 1);
141
142   // Steps slider
143   QWidget* aSliderWidget = new QWidget(aStepFrame);
144   aStepLayout->addWidget(aSliderWidget, 1, 0, 1, 2);
145   QHBoxLayout* aSliderLayout = new QHBoxLayout(aSliderWidget);
146   aSliderLayout->setContentsMargins(0, 0, 0, 0);
147
148   aSliderLayout->addWidget(new QLabel("1", aSliderWidget));
149
150   myStepSlider = new QSlider(Qt::Horizontal, aSliderWidget);
151   myStepSlider->setTickPosition(QSlider::TicksBelow);
152   myStepSlider->setRange(1, 1);
153   myStepSlider->setPageStep(myStepSlider->singleStep());
154   aSliderLayout->addWidget(myStepSlider, 1);
155
156   myMaxLbl = new QLabel("1", aSliderWidget);
157   aSliderLayout->addWidget(myMaxLbl);
158
159   // Stamp value
160   myCompNamesList << "Comp 1";
161   myStepWgt = new QStackedWidget(aStepFrame);
162   aStepLayout->addWidget(myStepWgt, 2, 0, 1, 2);
163
164   myDelegate =
165     new DataTableItemDelegate((ModelAPI_AttributeTables::ValueType)
166     myFieldTypeCombo->currentIndex());
167
168   appendStepControls();
169
170   // Buttons below
171   QWidget* aBtnWgt = new QWidget(this);
172   aMainLayout->addWidget(aBtnWgt);
173   QHBoxLayout* aBtnLayout = new QHBoxLayout(aBtnWgt);
174   aBtnLayout->setContentsMargins(0, 0, 0, 0);
175
176   QPushButton* aAddBtn = new QPushButton(tr("Add step"), aBtnWgt);
177   aBtnLayout->addWidget(aAddBtn);
178
179   aBtnLayout->addStretch(1);
180
181   myRemoveBtn = new QPushButton(tr("Remove step"), aBtnWgt);
182   aBtnLayout->addWidget(myRemoveBtn);
183   myRemoveBtn->setEnabled(false);
184
185   connect(myNbComponentsSpn, SIGNAL(valueChanged(int)), SLOT(onNbCompChanged(int)));
186   connect(aAddBtn, SIGNAL(clicked(bool)), SLOT(onAddStep()));
187   connect(myRemoveBtn, SIGNAL(clicked(bool)), SLOT(onRemoveStep()));
188   connect(myStepSlider, SIGNAL(valueChanged(int)), SLOT(onStepMove(int)));
189   connect(myStepSlider, SIGNAL(rangeChanged(int, int)), SLOT(onRangeChanged(int, int)));
190   connect(myFieldTypeCombo, SIGNAL(currentIndexChanged(int)), SLOT(onFieldTypeChanged(int)));
191   connect(myShapeTypeCombo, SIGNAL(currentIndexChanged(int)), SLOT(onShapeTypeChanged(int)));
192   connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)), SLOT(onFocusChanged(QWidget*, QWidget*)));
193 }
194
195 //**********************************************************************************
196 void CollectionPlugin_WidgetField::appendStepControls()
197 {
198   QWidget* aWidget = new QWidget(myStepWgt);
199   QGridLayout* aStepLayout = new QGridLayout(aWidget);
200   aStepLayout->setContentsMargins(0, 0, 0, 0);
201
202   aStepLayout->addWidget(new QLabel(tr("Stamp"), aWidget), 0, 0);
203
204   QSpinBox* aStampSpn = new QSpinBox(aWidget);
205   aStepLayout->addWidget(aStampSpn, 0, 1);
206
207   myStampSpnList.append(aStampSpn);
208
209   // Data table
210   QTableWidget* aDataTbl = new QTableWidget(1, myCompNamesList.count() + 1, aWidget);
211   aDataTbl->installEventFilter(this);
212   aDataTbl->setItemDelegate(myDelegate);
213
214   QIntList aColWidth;
215   if (!myDataTblList.isEmpty()) {
216     QTableWidget* aFirstTable = myDataTblList.first();
217     for (int i = 0; i < aFirstTable->columnCount(); i++)
218       aColWidth.append(aFirstTable->columnWidth(i));
219   }
220   myDataTblList.append(aDataTbl);
221
222   aDataTbl->verticalHeader()->hide();
223   aDataTbl->setRowHeight(0, 25);
224   aDataTbl->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
225
226   connect(aDataTbl->horizontalHeader(), SIGNAL(sectionResized(int, int, int)),
227           SLOT(onColumnResize(int, int, int)));
228
229   updateHeaders(aDataTbl);
230
231   QTableWidgetItem* aItem = new QTableWidgetItem("Default value");
232   aItem->setBackgroundColor(Qt::lightGray);
233   aItem->setFlags(Qt::NoItemFlags | Qt::ItemIsEnabled);
234   aDataTbl->setItem(0, 0, aItem);
235
236   // Set default value item
237   for (int i = 0; i < myCompNamesList.count(); i++) {
238     aItem = createDefaultItem();
239     aItem->setBackgroundColor(Qt::lightGray);
240     aDataTbl->setItem(0, i + 1, aItem);
241   }
242
243   if (aColWidth.length() > 0) {
244     for (int i = 0; i < aDataTbl->columnCount(); i++) {
245       if (i < aColWidth.size())
246       aDataTbl->setColumnWidth(i, aColWidth.at(i));
247     }
248   }
249   aStepLayout->addWidget(aDataTbl, 1, 0, 1, 2);
250   connect(aDataTbl, SIGNAL(cellChanged(int, int)), SLOT(onTableEdited(int, int)));
251
252   myStepWgt->addWidget(aWidget);
253   aDataTbl->horizontalHeader()->viewport()->installEventFilter(this);
254 }
255
256 //**********************************************************************************
257 void CollectionPlugin_WidgetField::deactivate()
258 {
259   ModuleBase_WidgetSelector::deactivate();
260   storeValueCustom();
261 }
262
263 //**********************************************************************************
264 //void CollectionPlugin_WidgetField::showEvent(QShowEvent* theEvent)
265 //{
266 //  myShapeTypeCombo->setEnabled(!isEditingMode());
267 //  myFieldTypeCombo->setEnabled(!isEditingMode());
268 //  myNbComponentsSpn->setEnabled(!isEditingMode());
269 //}
270
271 //**********************************************************************************
272 bool CollectionPlugin_WidgetField::eventFilter(QObject* theObject, QEvent* theEvent)
273 {
274   QObject* aObject = 0;
275   foreach(QTableWidget* aTable, myDataTblList) {
276     if (aTable->horizontalHeader()->viewport() == theObject) {
277       aObject = theObject;
278       break;
279     }
280   }
281   if (aObject) {
282     if (theEvent->type() == QEvent::MouseButtonDblClick) {
283       if (myHeaderEditor) { //delete previous editor
284         myHeaderEditor->deleteLater();
285         myHeaderEditor = 0;
286       }
287       QMouseEvent* aMouseEvent = static_cast<QMouseEvent*>(theEvent);
288       QHeaderView* aHeader = static_cast<QHeaderView*>(aObject->parent());
289       QTableWidget* aTable = static_cast<QTableWidget*>(aHeader->parentWidget());
290
291       int aShift = aTable->horizontalScrollBar()->value();
292       int aPos = aMouseEvent->x();
293       int aIndex = aHeader->logicalIndex(aHeader->visualIndexAt(aPos));
294       if (aIndex > 0) {
295         QRect aRect;
296         aRect.setLeft(aHeader->sectionPosition(aIndex));
297         aRect.setWidth(aHeader->sectionSize(aIndex));
298         aRect.setTop(0);
299         aRect.setHeight(aHeader->height());
300         aRect.adjust(1, 1, -1, -1);
301         aRect.translate(-aShift, 0);
302
303         myHeaderEditor = new QLineEdit(aHeader->viewport());
304         myHeaderEditor->move(aRect.topLeft());
305         myHeaderEditor->resize(aRect.size());
306         myHeaderEditor->setFrame(false);
307         QString aText = aHeader->model()->
308           headerData(aIndex, aHeader->orientation()).toString();
309         myHeaderEditor->setText(aText);
310         myHeaderEditor->setFocus();
311         myEditIndex = aIndex; //save for future use
312         myHeaderEditor->installEventFilter(this); //catch focus out event
313         //if user presses Enter it should close editor
314         connect(myHeaderEditor, SIGNAL(returnPressed()), aTable, SLOT(setFocus()));
315         myHeaderEditor->show();
316         return true;
317       }
318     }
319   } else if ((theObject == myHeaderEditor) && (theEvent->type() == QEvent::FocusOut)) {
320     QString aNewTitle = myHeaderEditor->text();
321     //save item text
322     myCompNamesList.replace(myEditIndex - 1, aNewTitle);
323     myHeaderEditor->deleteLater(); //safely delete editor
324     myHeaderEditor = 0;
325     // Store into data model
326     AttributeStringArrayPtr aStringsAttr =
327       myFeature->data()->stringArray(CollectionPlugin_Field::COMPONENTS_NAMES_ID());
328     aStringsAttr->setValue(myEditIndex - 1, aNewTitle.toStdString());
329     foreach(QTableWidget* aTable, myDataTblList) {
330       updateHeaders(aTable);
331     }
332   } else if (theEvent->type() == QEvent::FocusIn) {
333     QTableWidget* aTable = dynamic_cast<QTableWidget*>(theObject);
334     if (aTable) {
335       ModuleBase_IPropertyPanel* aPanel = myWorkshop->propertyPanel();
336       if (aPanel->activeWidget() != this) {
337         myActivation = true;
338         aPanel->activateWidget(this, false);
339       }
340     }
341   }
342   return ModuleBase_WidgetSelector::eventFilter(theObject, theEvent);
343 }
344
345 //**********************************************************************************
346 QTableWidgetItem* CollectionPlugin_WidgetField::createDefaultItem() const
347 {
348   QTableWidgetItem* aItem = new QTableWidgetItem();
349   switch (myFieldTypeCombo->currentIndex()) {
350   case ModelAPI_AttributeTables::DOUBLE:
351   case ModelAPI_AttributeTables::INTEGER:
352     aItem->setText("0");
353     break;
354   case ModelAPI_AttributeTables::BOOLEAN:
355     aItem->setText(MYFalse);
356     break;
357   case ModelAPI_AttributeTables::STRING:
358     aItem->setText("");
359     break;
360   }
361   return aItem;
362 }
363
364 //**********************************************************************************
365 QTableWidgetItem* CollectionPlugin_WidgetField::
366   createValueItem(ModelAPI_AttributeTables::Value& theVal) const
367 {
368   QTableWidgetItem* aItem = new QTableWidgetItem();
369   aItem->setText(getValueText(theVal));
370   return aItem;
371 }
372
373 //**********************************************************************************
374 QString CollectionPlugin_WidgetField::getValueText(ModelAPI_AttributeTables::Value& theVal) const
375 {
376   switch (myFieldTypeCombo->currentIndex()) {
377   case ModelAPI_AttributeTables::DOUBLE:
378     return QString::number(theVal.myDouble);
379   case ModelAPI_AttributeTables::INTEGER:
380     return QString::number(theVal.myInt);
381   case ModelAPI_AttributeTables::BOOLEAN:
382     return theVal.myBool? MYTrue : MYFalse;
383   case ModelAPI_AttributeTables::STRING:
384     return theVal.myStr.c_str();
385   }
386   return "";
387 }
388
389
390 //**********************************************************************************
391 void CollectionPlugin_WidgetField::updateHeaders(QTableWidget* theDataTbl) const
392 {
393   QStringList aHeaders;
394   aHeaders << tr(MYFirstCol);
395   aHeaders << myCompNamesList;
396   theDataTbl->setHorizontalHeaderLabels(aHeaders);
397 }
398
399 //**********************************************************************************
400 void CollectionPlugin_WidgetField::removeStepControls()
401 {
402   int aCurWgtId = myStepWgt->currentIndex();
403   QWidget* aWgt = myStepWgt->currentWidget();
404   myStepWgt->removeWidget(aWgt);
405
406   myStampSpnList.removeAt(aCurWgtId);
407   myDataTblList.removeAt(aCurWgtId);
408   aWgt->deleteLater();
409 }
410
411 //**********************************************************************************
412 QList<QWidget*> CollectionPlugin_WidgetField::getControls() const
413 {
414   QList<QWidget*> aControls;
415   // this control will accept focus and will be highlighted in the Property Panel
416   aControls.push_back(myShapeTypeCombo);
417   aControls.push_back(myFieldTypeCombo);
418   aControls.push_back(myNbComponentsSpn);
419   return aControls;
420 }
421
422 //**********************************************************************************
423 bool CollectionPlugin_WidgetField::storeValueCustom()
424 {
425   DataPtr aData = myFeature->data();
426   // Store number of components
427   AttributeStringArrayPtr aStringsAttr =
428     aData->stringArray(CollectionPlugin_Field::COMPONENTS_NAMES_ID());
429   int aNbComps = myCompNamesList.size();
430   aStringsAttr->setSize(aNbComps);
431   for ( int i = 0; i < aNbComps; i++)
432     aStringsAttr->setValue(i, myCompNamesList.at(i).toStdString());
433
434   AttributeTablesPtr aTablesAttr = aData->tables(CollectionPlugin_Field::VALUES_ID());
435   // Store number of steps
436   int aNbSteps =  myDataTblList.size();
437
438   // Store Type of the field values
439   int aFldType = myFieldTypeCombo->currentIndex();
440
441   AttributeIntArrayPtr aStampsAttr = aData->intArray(CollectionPlugin_Field::STAMPS_ID());
442   aStampsAttr->setSize(aNbSteps);
443   // Store data
444   QTableWidget* aTable = myDataTblList.first();
445   int aRows = aTable->rowCount();
446   // first column contains selected names which should not be stored
447   int aColumns = aTable->columnCount() - 1;
448
449   aTablesAttr->setSize(aRows, aColumns, aNbSteps);
450   aTablesAttr->setType((ModelAPI_AttributeTables::ValueType)aFldType);
451   for (int i = 0; i < aNbSteps; i++) {
452     aStampsAttr->setValue(i, myStampSpnList.at(i)->value());
453     aTable = myDataTblList.at(i);
454     for (int j = 0; j < aColumns; j++) {
455       for (int k = 0; k < aRows; k++) {
456         QString aTblVal = aTable->item(k, j + 1)->text();
457         aTablesAttr->setValue(getValue(aTblVal), k, j, i);
458       }
459     }
460   }
461   updateObject(myFeature);
462   return true;
463 }
464
465 //**********************************************************************************
466 bool CollectionPlugin_WidgetField::restoreValueCustom()
467 {
468   bool isBlocked;
469   DataPtr aData = myFeature->data();
470
471   AttributeSelectionListPtr aSelList = aData->selectionList(CollectionPlugin_Field::SELECTED_ID());
472   std::string aTypeStr = aSelList->selectionType();
473   if (aTypeStr == "")
474     return false; // The attribute is not initialized
475   myShapeTypeCombo->setCurrentIndex(getSelectionType(aTypeStr));
476
477   // Get number of components
478   AttributeStringArrayPtr aStringsAttr =
479   aData->stringArray(CollectionPlugin_Field::COMPONENTS_NAMES_ID());
480
481   myCompNamesList.clear();
482   for (int i = 0; i < aStringsAttr->size(); i++) {
483     myCompNamesList.append(aStringsAttr->value(i).c_str());
484   }
485   isBlocked = myNbComponentsSpn->blockSignals(true);
486   myNbComponentsSpn->setValue(myCompNamesList.size());
487   myNbComponentsSpn->blockSignals(isBlocked);
488
489   AttributeTablesPtr aTablesAttr = aData->tables(CollectionPlugin_Field::VALUES_ID());
490   // Get number of steps
491   int aNbSteps = aTablesAttr->tables();
492   myStepSlider->setMaximum(aNbSteps);
493   //myStepSlider->setValue(1);
494   // Clear old tables
495   while (myDataTblList.count() > aNbSteps) {
496     QWidget* aWgt = myStepWgt->widget(myStepWgt->count() - 1);
497     myStepWgt->removeWidget(aWgt);
498     aWgt->deleteLater();
499
500     myStampSpnList.removeLast();
501     myDataTblList.removeLast();
502   }
503   while (myDataTblList.count() < aNbSteps)
504     appendStepControls();
505   //myStepWgt->setCurrentIndex(myStepSlider->value() - 1);
506   clearData();
507
508   // Get Type of the field values
509   isBlocked = myFieldTypeCombo->blockSignals(true);
510   myFieldTypeCombo->setCurrentIndex(aTablesAttr->type());
511   myFieldTypeCombo->blockSignals(isBlocked);
512   myDelegate->setDataType(aTablesAttr->type());
513
514   AttributeIntArrayPtr aStampsAttr = aData->intArray(CollectionPlugin_Field::STAMPS_ID());
515   // Fill data table
516   int aRows = aTablesAttr->rows();
517   int aCols = aTablesAttr->columns();
518
519   // Get width of columns
520   QIntList aColWidth;
521   QTableWidget* aFirstTable = myDataTblList.first();
522   for (int i = 0; i < aFirstTable->columnCount(); i++)
523     aColWidth.append(aFirstTable->columnWidth(i));
524
525   QTableWidgetItem* aItem = 0;
526   for (int i = 0; i < aNbSteps; i++) {
527     myStampSpnList.at(i)->setValue(aStampsAttr->value(i));
528     QTableWidget* aTable = myDataTblList.at(i);
529     isBlocked = aTable->blockSignals(true);
530     aTable->setRowCount(aRows);
531     aTable->setColumnCount(aCols + 1);
532     updateHeaders(aTable);
533     for (int j = 0; j < aCols + 1; j++) {
534       for (int k = 0; k < aRows; k++) {
535         aItem = aTable->item(k, j);
536         if ((j == 0) && (k > 0)) {
537           // Add selection names
538           AttributeSelectionPtr aAttr = aSelList->value(k - 1);
539           if (aItem) {
540             aItem->setText(aAttr->namingName().c_str());
541           } else {
542             aItem = new QTableWidgetItem(aAttr->namingName().c_str());
543             aTable->setItem(k, j, aItem);
544           }
545         } else if (j > 0) {
546           // Add Values
547           ModelAPI_AttributeTables::Value aVal = aTablesAttr->value(k, j - 1, i);
548           if (aItem) {
549             aItem->setText(getValueText(aVal));
550           } else {
551             aItem = createValueItem(aVal);
552             if (k == 0)
553               aItem->setBackgroundColor(Qt::lightGray);
554             aTable->setItem(k, j, aItem);
555           }
556         }
557       }
558     }
559     // Restore columns width
560     for (int i = 0; i < aTable->columnCount(); i++) {
561       if (i < aColWidth.size())
562         aTable->setColumnWidth(i, aColWidth.at(i));
563     }
564
565     aTable->blockSignals(isBlocked);
566   }
567   return true;
568 }
569
570 //**********************************************************************************
571 int CollectionPlugin_WidgetField::getSelectionType(const std::string& theStr) const
572 {
573   QString aType(theStr.c_str());
574   aType = aType.toLower();
575   if (aType == "vertex")
576     return 0;
577   else if (aType == "edge")
578     return 1;
579   else if (aType == "face")
580     return 2;
581   else if (aType == "solid")
582     return 3;
583   else if (aType == "object")
584     return 4;
585   else if (aType == "part")
586     return 5;
587   return -1;
588 }
589
590
591 //**********************************************************************************
592 std::string CollectionPlugin_WidgetField::getSelectionType(int theType) const
593 {
594   switch (theType) {
595   case 0: //"Vertices"
596     return "vertex";
597   case 1: // "Edges"
598     return "edge";
599   case 2: // "Faces"
600     return "face";
601   case 3: // "Solids"
602     return "solid";
603   case 4: // "Results"
604     return "object";
605   case 5: // "Parts"
606     return "part";
607   }
608   return "";
609 }
610
611 //**********************************************************************************
612 QIntList CollectionPlugin_WidgetField::shapeTypes() const
613 {
614   QIntList aRes;
615   switch (myShapeTypeCombo->currentIndex()) {
616   case 0: //"Vertices"
617     aRes.append(ModuleBase_Tools::shapeType("vertex"));
618     break;
619   case 1: // "Edges"
620     aRes.append(ModuleBase_Tools::shapeType("edge"));
621     break;
622   case 2: // "Faces"
623     aRes.append(ModuleBase_Tools::shapeType("face"));
624     break;
625   case 3: // "Solids"
626     aRes.append(ModuleBase_Tools::shapeType("solid"));
627     break;
628   case 4: // "Results"
629     aRes.append(ModuleBase_Tools::shapeType("object"));
630     break;
631   case 5: // "Parts"
632     // TODO: Selection mode for Parts
633     break;
634   }
635   return aRes;
636 }
637
638 //**********************************************************************************
639 ModelAPI_AttributeTables::Value CollectionPlugin_WidgetField::getValue(QString theStrVal) const
640 {
641   ModelAPI_AttributeTables::Value aVal;
642   switch (myFieldTypeCombo->currentIndex()) {
643   case ModelAPI_AttributeTables::BOOLEAN:
644     aVal.myBool = (theStrVal == MYTrue)? true : false;
645     break;
646   case ModelAPI_AttributeTables::DOUBLE:
647     aVal.myDouble = theStrVal.toDouble();
648     break;
649   case ModelAPI_AttributeTables::INTEGER:
650     aVal.myInt = theStrVal.toInt();
651     break;
652   case ModelAPI_AttributeTables::STRING:
653     aVal.myStr = theStrVal.toStdString();
654   }
655   return aVal;
656 }
657
658
659 //**********************************************************************************
660 void CollectionPlugin_WidgetField::onNbCompChanged(int theVal)
661 {
662   int aOldCol = myCompNamesList.count();
663   int aNbRows = myDataTblList.first()->rowCount();
664   int aDif = theVal - aOldCol;
665   QTableWidgetItem* aItem = 0;
666
667   while (myCompNamesList.count() != theVal) {
668     if (aDif > 0)
669       myCompNamesList.append(QString("Comp %1").arg(myCompNamesList.count() + 1));
670     else
671       myCompNamesList.removeLast();
672   }
673
674   AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
675   aTablesAttr->setSize(aNbRows, myCompNamesList.size(), myDataTblList.size());
676
677   foreach(QTableWidget* aDataTbl, myDataTblList) {
678     aDataTbl->setColumnCount(theVal + 1);
679     updateHeaders(aDataTbl);
680     for (int i = aOldCol; i < myCompNamesList.count(); i++) {
681       for (int j = 0; j < aNbRows; j++) {
682         aItem = aDataTbl->item(j, i + 1);
683         if (!aItem) {
684           aItem = createDefaultItem();
685           if (j == 0)
686             aItem->setBackgroundColor(Qt::lightGray);
687           aDataTbl->setItem(j, i + 1, aItem);
688         }
689       }
690     }
691   }
692   emit valuesChanged();
693 }
694
695 //**********************************************************************************
696 void CollectionPlugin_WidgetField::onAddStep()
697 {
698   int aMax = myStepSlider->maximum();
699   aMax++;
700   myStepSlider->setMaximum(aMax);
701   myMaxLbl->setText(QString::number(aMax));
702   appendStepControls();
703   myStepSlider->setValue(aMax);
704
705   AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
706   aTablesAttr->setSize(aTablesAttr->rows(), aTablesAttr->columns(), myDataTblList.size());
707
708
709   AttributeSelectionListPtr aSelList =
710     myFeature->data()->selectionList(CollectionPlugin_Field::SELECTED_ID());
711   if (!aSelList->isInitialized())
712     return;
713   int aSelNb = aSelList->size();
714   if (aSelNb == 0)
715     return;
716
717   int aColumns = myNbComponentsSpn->value() + 1;
718   int aRows = aSelNb + 1;
719   QTableWidget* aTable = myDataTblList.last();
720   aTable->setRowCount(aRows);
721   QTableWidgetItem* aItem = 0;
722   for(int i = 0; i < aColumns; i++) {
723     if (i == 0) {
724       for(int j = 1; j < aRows; j++) {
725         aItem = aTable->item(j, i);
726         if (!aItem) {
727           aItem = new QTableWidgetItem();
728           aTable->setItem(j, i, aItem);
729         }
730         AttributeSelectionPtr aAttr = aSelList->value(j - 1);
731         aItem->setText(aAttr->namingName().c_str());
732         aItem->setToolTip(aAttr->namingName().c_str());
733       }
734     } else {
735       QString aDefVal = aTable->item(0, i)->text();
736       for(int j = 1; j < aRows; j++) {
737         aItem = aTable->item(j, i);
738         if (!aItem) {
739           aItem = new QTableWidgetItem();
740           aTable->setItem(j, i, aItem);
741         }
742         aItem->setText(aDefVal);
743       }
744     }
745   }
746   emit valuesChanged();
747 }
748
749 //**********************************************************************************
750 void CollectionPlugin_WidgetField::onRemoveStep()
751 {
752   int aMax = myStepSlider->maximum();
753   aMax--;
754   myMaxLbl->setText(QString::number(aMax));
755   removeStepControls();
756   myStepSlider->setMaximum(aMax);
757
758   //AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
759   //aTablesAttr->setSize(aTablesAttr->rows(), aTablesAttr->columns(), myDataTblList.size());
760   emit valuesChanged();
761 }
762
763 //**********************************************************************************
764 void CollectionPlugin_WidgetField::clearData()
765 {
766   foreach(QTableWidget* aDataTbl, myDataTblList) {
767     aDataTbl->setRowCount(1);
768   }
769 }
770
771 //**********************************************************************************
772 void CollectionPlugin_WidgetField::onStepMove(int theStep)
773 {
774   myCurStepLbl->setText(QString::number(theStep));
775   myStepWgt->setCurrentIndex(theStep - 1);
776 }
777
778 //**********************************************************************************
779 bool CollectionPlugin_WidgetField::
780   isValidSelectionCustom(const std::shared_ptr<ModuleBase_ViewerPrs>& thePrs)
781 {
782   return (myShapeTypeCombo->currentIndex() == 5)? false : true;
783 }
784
785 //**********************************************************************************
786 bool CollectionPlugin_WidgetField::
787   setSelection(QList<std::shared_ptr<ModuleBase_ViewerPrs>>& theValues, const bool theToValidate)
788 {
789   if (myActivation) {
790     myActivation = false;
791     return false;
792   }
793   // Ignore selection for Parts mode
794   if (myShapeTypeCombo->currentIndex() == 5)
795     return false;
796
797   QList<ModuleBase_ViewerPrsPtr> aSelected;
798   QList<ModuleBase_ViewerPrsPtr>::const_iterator anIt;
799   for (anIt = theValues.begin(); anIt != theValues.end(); anIt++) {
800     ModuleBase_ViewerPrsPtr aValue = *anIt;
801     ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aValue->object());
802     if (theToValidate && aRes.get() && acceptSubShape(aValue->shape(), aRes))
803       aSelected.append(aValue);
804   }
805   AttributeSelectionListPtr aSelList =
806     myFeature->data()->selectionList(CollectionPlugin_Field::SELECTED_ID());
807   aSelList->setSelectionType(getSelectionType(myShapeTypeCombo->currentIndex()));
808   aSelList->clear();
809
810   ResultPtr aResult;
811   GeomShapePtr aShape;
812   int aNbData = 0;
813   foreach(ModuleBase_ViewerPrsPtr aPrs, aSelected) {
814     aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aPrs->object());
815     aShape = aPrs->shape();
816     if (!aResult.get() && !aShape.get())
817       continue;
818     if (!aSelList->isInList(aResult, aShape)) {
819       aSelList->append(aResult, aShape);
820       aNbData++;
821     }
822   }
823   int aColumns = myDataTblList.first()->columnCount();
824   int aRows = myDataTblList.first()->rowCount();
825   int aNewRows = aNbData + 1;
826   AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
827   aTablesAttr->setSize(aNewRows, aColumns - 1, myDataTblList.size());
828
829   QTableWidgetItem* aItem = 0;
830   foreach(QTableWidget* aTable, myDataTblList) {
831     aTable->setRowCount(aNewRows);
832     if (aNewRows > aRows) {
833       // Add new data
834       for(int i = 0; i < aColumns; i++) {
835         if (i == 0) {
836           for(int j = 1; j < aNewRows; j++) {
837             aItem = aTable->item(j, i);
838             if (!aItem) {
839               aItem = new QTableWidgetItem();
840               aTable->setItem(j, i, aItem);
841             }
842             AttributeSelectionPtr aAttr = aSelList->value(j - 1);
843             aItem->setText(aAttr->namingName().c_str());
844             aItem->setToolTip(aAttr->namingName().c_str());
845           }
846         } else {
847           QString aDefVal = aTable->item(0, i)->text();
848           for(int j = aRows; j < aNewRows; j++) {
849             aItem = aTable->item(j, i);
850             if (!aItem) {
851               aItem = new QTableWidgetItem();
852               aTable->setItem(j, i, aItem);
853             }
854             aItem->setText(aDefVal);
855           }
856         }
857       }
858     } else {
859       // Update only selection name
860       for(int j = 1; j < aNewRows - 1; j++) {
861         AttributeSelectionPtr aAttr = aSelList->value(j);
862         aTable->item(j, 0)->setText(aAttr->namingName().c_str());
863         aTable->item(j, 0)->setToolTip(aAttr->namingName().c_str());
864       }
865     }
866   }
867   return true;
868 }
869
870 //**********************************************************************************
871 void CollectionPlugin_WidgetField::onFieldTypeChanged(int theIdx)
872 {
873   ModelAPI_AttributeTables::ValueType aOldType = myDelegate->dataType();
874   if (aOldType != theIdx) {
875     myDelegate->setDataType((ModelAPI_AttributeTables::ValueType)theIdx);
876     int aColumns = myDataTblList.first()->columnCount();
877     int aRows = myDataTblList.first()->rowCount();
878     foreach(QTableWidget* aTable, myDataTblList) {
879       for(int i = 1; i < aColumns; i++) {
880         for(int j = 0; j < aRows; j++) {
881           switch (theIdx) {
882           case ModelAPI_AttributeTables::DOUBLE:
883           case ModelAPI_AttributeTables::INTEGER:
884             aTable->item(j, i)->setText("0");
885             break;
886           case ModelAPI_AttributeTables::BOOLEAN:
887             aTable->item(j, i)->setText(MYFalse);
888             break;
889           case ModelAPI_AttributeTables::STRING:
890             aTable->item(j, i)->setText("");
891             break;
892           }
893         }
894       }
895     }
896     emit valuesChanged();
897   }
898 }
899
900 //**********************************************************************************
901 void CollectionPlugin_WidgetField::onTableEdited(int theRow, int theCol)
902 {
903   // Do not store here column of names
904   if (theCol == 0)
905     return;
906   if (!myFeature.get())
907     return;
908   QTableWidget* aTable = static_cast<QTableWidget*>(sender());
909   int aNb = myDataTblList.indexOf(aTable);
910   if (aNb == -1)
911     return;
912   ModelAPI_AttributeTables::Value aVal = getValue(aTable->item(theRow, theCol)->text());
913
914   AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
915   if (aTablesAttr->isInitialized())
916     aTablesAttr->setValue(aVal,theRow, theCol - 1, aNb);
917   else
918     emit valuesChanged();
919 }
920
921 //**********************************************************************************
922 void CollectionPlugin_WidgetField::onShapeTypeChanged(int theType)
923 {
924   activateSelectionAndFilters(theType == 5? false:true);
925
926   AttributeSelectionListPtr aSelList =
927     myFeature->data()->selectionList(CollectionPlugin_Field::SELECTED_ID());
928
929   std::string aTypeName = getSelectionType(theType);
930   if (aTypeName == aSelList->selectionType())
931     return;
932   aSelList->setSelectionType(aTypeName);
933
934   //Clear old selection
935   clearData();
936   aSelList->clear();
937   AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
938   aTablesAttr->setSize(1, myNbComponentsSpn->value(), myDataTblList.size());
939   emit valuesChanged();
940 }
941
942 //**********************************************************************************
943 bool CollectionPlugin_WidgetField::processEnter()
944 {
945   if (myIsTabEdit) {
946     myIsTabEdit = false;
947     return true;
948   }
949   return false;
950 }
951
952 //**********************************************************************************
953 void CollectionPlugin_WidgetField::onFocusChanged(QWidget* theOld, QWidget* theNew)
954 {
955   if (theNew && (!myIsTabEdit))
956     myIsTabEdit = dynamic_cast<QLineEdit*>(theNew);
957 }
958
959 //**********************************************************************************
960 void CollectionPlugin_WidgetField::onRangeChanged(int theMin, int theMax)
961 {
962   myMaxLbl->setText(QString::number(theMax));
963   myRemoveBtn->setEnabled(theMax > 1);
964 }
965
966 //**********************************************************************************
967 void CollectionPlugin_WidgetField::onColumnResize(int theIndex, int theOld, int theNew)
968 {
969   if (myDataTblList.count() < 2)
970     return;
971   QObject* aSender = sender();
972   foreach(QTableWidget* aTable, myDataTblList) {
973     if (aTable->horizontalHeader() != aSender)
974       aTable->setColumnWidth(theIndex, theNew);
975   }
976 }
977
978 //**********************************************************************************
979 QList<std::shared_ptr<ModuleBase_ViewerPrs>>
980   CollectionPlugin_WidgetField::getAttributeSelection() const
981 {
982   QList<std::shared_ptr<ModuleBase_ViewerPrs>> aList;
983   if(myFeature) {
984     DataPtr aData = myFeature->data();
985     AttributeSelectionListPtr aSelList =
986       aData->selectionList(CollectionPlugin_Field::SELECTED_ID());
987     AttributeSelectionPtr aAttr;
988     ObjectPtr anObject;
989     for (int i = 0; i < aSelList->size(); i++) {
990       aAttr = aSelList->value(i);
991       ModuleBase_ViewerPrsPtr
992         aPrs(new ModuleBase_ViewerPrs(aAttr->context(), aAttr->value(), NULL));
993       aList.append(aPrs);
994     }
995   }
996   return aList;
997 }