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