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