Salome HOME
Issue #1961: Accept result if selection mode is object
[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   myShapeTypeCombo->setCurrentIndex(getSelectionType(aTypeStr));
503
504   // Get number of components
505   AttributeStringArrayPtr aStringsAttr =
506   aData->stringArray(CollectionPlugin_Field::COMPONENTS_NAMES_ID());
507
508   myCompNamesList.clear();
509   for (int i = 0; i < aStringsAttr->size(); i++) {
510     myCompNamesList.append(aStringsAttr->value(i).c_str());
511   }
512   isBlocked = myNbComponentsSpn->blockSignals(true);
513   myNbComponentsSpn->setValue(myCompNamesList.size());
514   myNbComponentsSpn->blockSignals(isBlocked);
515
516   AttributeTablesPtr aTablesAttr = aData->tables(CollectionPlugin_Field::VALUES_ID());
517   // Get number of steps
518   int aNbSteps = aTablesAttr->tables();
519   myStepSlider->setMaximum(aNbSteps);
520   //myStepSlider->setValue(1);
521   // Clear old tables
522   while (myDataTblList.count() > aNbSteps) {
523     QWidget* aWgt = myStepWgt->widget(myStepWgt->count() - 1);
524     myStepWgt->removeWidget(aWgt);
525     aWgt->deleteLater();
526
527     myStampSpnList.removeLast();
528     myDataTblList.removeLast();
529   }
530   while (myDataTblList.count() < aNbSteps)
531     appendStepControls();
532   //myStepWgt->setCurrentIndex(myStepSlider->value() - 1);
533   clearData();
534
535   // Get Type of the field values
536   isBlocked = myFieldTypeCombo->blockSignals(true);
537   myFieldTypeCombo->setCurrentIndex(aTablesAttr->type());
538   myFieldTypeCombo->blockSignals(isBlocked);
539   myDelegate->setDataType(aTablesAttr->type());
540
541   AttributeIntArrayPtr aStampsAttr = aData->intArray(CollectionPlugin_Field::STAMPS_ID());
542   // Fill data table
543   int aRows = aTablesAttr->rows();
544   int aCols = aTablesAttr->columns();
545
546   // Get width of columns
547   QIntList aColWidth;
548   QTableWidget* aFirstTable = myDataTblList.first();
549   for (int i = 0; i < aFirstTable->columnCount(); i++)
550     aColWidth.append(aFirstTable->columnWidth(i));
551
552   QTableWidgetItem* aItem = 0;
553   for (int i = 0; i < aNbSteps; i++) {
554     myStampSpnList.at(i)->setValue(aStampsAttr->value(i));
555     QTableWidget* aTable = myDataTblList.at(i);
556     isBlocked = aTable->blockSignals(true);
557     aTable->setRowCount(aRows);
558     aTable->setColumnCount(aCols + 1);
559     updateHeaders(aTable);
560     for (int j = 0; j < aCols + 1; j++) {
561       for (int k = 0; k < aRows; k++) {
562         aItem = aTable->item(k, j);
563         if ((j == 0) && (k > 0)) {
564           // Add selection names
565           AttributeSelectionPtr aAttr = aSelList->value(k - 1);
566           if (aItem) {
567             aItem->setText(aAttr->namingName().c_str());
568           } else {
569             aItem = new QTableWidgetItem(aAttr->namingName().c_str());
570             aTable->setItem(k, j, aItem);
571           }
572         } else if (j > 0) {
573           // Add Values
574           ModelAPI_AttributeTables::Value aVal = aTablesAttr->value(k, j - 1, i);
575           if (aItem) {
576             aItem->setText(getValueText(aVal));
577           } else {
578             aItem = createValueItem(aVal);
579             if (k == 0)
580               aItem->setBackgroundColor(Qt::lightGray);
581             aTable->setItem(k, j, aItem);
582           }
583         }
584       }
585     }
586     // Restore columns width
587     for (int i = 0; i < aTable->columnCount(); i++) {
588       if (i < aColWidth.size())
589         aTable->setColumnWidth(i, aColWidth.at(i));
590     }
591
592     aTable->blockSignals(isBlocked);
593   }
594   return true;
595 }
596
597 //**********************************************************************************
598 int CollectionPlugin_WidgetField::getSelectionType(const std::string& theStr) const
599 {
600   QString aType(theStr.c_str());
601   aType = aType.toLower();
602   if (aType == "vertex")
603     return 0;
604   else if (aType == "edge")
605     return 1;
606   else if (aType == "face")
607     return 2;
608   else if (aType == "solid")
609     return 3;
610   else if (aType == "object")
611     return 4;
612   else if (aType == "part")
613     return 5;
614   return -1;
615 }
616
617
618 //**********************************************************************************
619 std::string CollectionPlugin_WidgetField::getSelectionType(int theType) const
620 {
621   switch (theType) {
622   case 0: //"Vertices"
623     return "vertex";
624   case 1: // "Edges"
625     return "edge";
626   case 2: // "Faces"
627     return "face";
628   case 3: // "Solids"
629     return "solid";
630   case 4: // "Results"
631     return "object";
632   case 5: // "Parts"
633     return "part";
634   }
635   return "";
636 }
637
638 //**********************************************************************************
639 QIntList CollectionPlugin_WidgetField::shapeTypes() const
640 {
641   QIntList aRes;
642   switch (myShapeTypeCombo->currentIndex()) {
643   case 0: //"Vertices"
644     aRes.append(ModuleBase_Tools::shapeType("vertex"));
645     break;
646   case 1: // "Edges"
647     aRes.append(ModuleBase_Tools::shapeType("edge"));
648     break;
649   case 2: // "Faces"
650     aRes.append(ModuleBase_Tools::shapeType("face"));
651     break;
652   case 3: // "Solids"
653     aRes.append(ModuleBase_Tools::shapeType("solid"));
654     break;
655   case 4: // "Results"
656     aRes.append(ModuleBase_Tools::shapeType("object"));
657     break;
658   case 5: // "Parts"
659     // TODO: Selection mode for Parts
660     break;
661   }
662   return aRes;
663 }
664
665 //**********************************************************************************
666 ModelAPI_AttributeTables::Value CollectionPlugin_WidgetField::getValue(QString theStrVal) const
667 {
668   ModelAPI_AttributeTables::Value aVal;
669   switch (myFieldTypeCombo->currentIndex()) {
670   case ModelAPI_AttributeTables::BOOLEAN:
671     aVal.myBool = (theStrVal == MYTrue)? true : false;
672     break;
673   case ModelAPI_AttributeTables::DOUBLE:
674     aVal.myDouble = theStrVal.toDouble();
675     break;
676   case ModelAPI_AttributeTables::INTEGER:
677     aVal.myInt = theStrVal.toInt();
678     break;
679   case ModelAPI_AttributeTables::STRING:
680     aVal.myStr = theStrVal.toStdString();
681   }
682   return aVal;
683 }
684
685
686 //**********************************************************************************
687 void CollectionPlugin_WidgetField::onNbCompChanged(int theVal)
688 {
689   int aOldCol = myCompNamesList.count();
690   int aNbRows = myDataTblList.first()->rowCount();
691   int aDif = theVal - aOldCol;
692   QTableWidgetItem* aItem = 0;
693
694   while (myCompNamesList.count() != theVal) {
695     if (aDif > 0)
696       myCompNamesList.append(QString("Comp %1").arg(myCompNamesList.count() + 1));
697     else
698       myCompNamesList.removeLast();
699   }
700
701   AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
702   aTablesAttr->setSize(aNbRows, myCompNamesList.size(), myDataTblList.size());
703
704   foreach(QTableWidget* aDataTbl, myDataTblList) {
705     aDataTbl->setColumnCount(theVal + 1);
706     updateHeaders(aDataTbl);
707     for (int i = aOldCol; i < myCompNamesList.count(); i++) {
708       for (int j = 0; j < aNbRows; j++) {
709         aItem = aDataTbl->item(j, i + 1);
710         if (!aItem) {
711           aItem = createDefaultItem();
712           if (j == 0)
713             aItem->setBackgroundColor(Qt::lightGray);
714           aDataTbl->setItem(j, i + 1, aItem);
715         }
716       }
717     }
718   }
719   emit valuesChanged();
720 }
721
722 //**********************************************************************************
723 void CollectionPlugin_WidgetField::onAddStep()
724 {
725   int aMax = myStepSlider->maximum();
726   aMax++;
727   myStepSlider->setMaximum(aMax);
728   myMaxLbl->setText(QString::number(aMax));
729   appendStepControls();
730   myStepSlider->setValue(aMax);
731
732   AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
733   aTablesAttr->setSize(aTablesAttr->rows(), aTablesAttr->columns(), myDataTblList.size());
734
735
736   AttributeSelectionListPtr aSelList =
737     myFeature->data()->selectionList(CollectionPlugin_Field::SELECTED_ID());
738   if (!aSelList->isInitialized())
739     return;
740   int aSelNb = aSelList->size();
741   if (aSelNb == 0)
742     return;
743
744   int aColumns = myNbComponentsSpn->value() + 1;
745   int aRows = aSelNb + 1;
746   QTableWidget* aTable = myDataTblList.last();
747   aTable->setRowCount(aRows);
748   QTableWidgetItem* aItem = 0;
749   for(int i = 0; i < aColumns; i++) {
750     if (i == 0) {
751       for(int j = 1; j < aRows; j++) {
752         aItem = aTable->item(j, i);
753         if (!aItem) {
754           aItem = new QTableWidgetItem();
755           aTable->setItem(j, i, aItem);
756         }
757         AttributeSelectionPtr aAttr = aSelList->value(j - 1);
758         aItem->setText(aAttr->namingName().c_str());
759         aItem->setToolTip(aAttr->namingName().c_str());
760       }
761     } else {
762       QString aDefVal = aTable->item(0, i)->text();
763       for(int j = 1; j < aRows; j++) {
764         aItem = aTable->item(j, i);
765         if (!aItem) {
766           aItem = new QTableWidgetItem();
767           aTable->setItem(j, i, aItem);
768         }
769         aItem->setText(aDefVal);
770       }
771     }
772   }
773   emit valuesChanged();
774 }
775
776 //**********************************************************************************
777 void CollectionPlugin_WidgetField::onRemoveStep()
778 {
779   int aMax = myStepSlider->maximum();
780   aMax--;
781   myMaxLbl->setText(QString::number(aMax));
782   removeStepControls();
783   myStepSlider->setMaximum(aMax);
784
785   //AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
786   //aTablesAttr->setSize(aTablesAttr->rows(), aTablesAttr->columns(), myDataTblList.size());
787   emit valuesChanged();
788 }
789
790 //**********************************************************************************
791 void CollectionPlugin_WidgetField::clearData()
792 {
793   foreach(QTableWidget* aDataTbl, myDataTblList) {
794     aDataTbl->setRowCount(1);
795   }
796 }
797
798 //**********************************************************************************
799 void CollectionPlugin_WidgetField::onStepMove(int theStep)
800 {
801   myCurStepLbl->setText(QString::number(theStep));
802   myStepWgt->setCurrentIndex(theStep - 1);
803 }
804
805 //**********************************************************************************
806 bool CollectionPlugin_WidgetField::
807   isValidSelectionCustom(const std::shared_ptr<ModuleBase_ViewerPrs>& thePrs)
808 {
809   return (myShapeTypeCombo->currentIndex() == 5)? false : true;
810 }
811
812 //**********************************************************************************
813 bool CollectionPlugin_WidgetField::
814   setSelection(QList<std::shared_ptr<ModuleBase_ViewerPrs>>& theValues, const bool theToValidate)
815 {
816   if (myActivation) {
817     myActivation = false;
818     return false;
819   }
820   // Ignore selection for Parts mode
821   if (myShapeTypeCombo->currentIndex() == 5)
822     return false;
823
824   QList<ModuleBase_ViewerPrsPtr> aSelected;
825   QList<ModuleBase_ViewerPrsPtr>::const_iterator anIt;
826   for (anIt = theValues.begin(); anIt != theValues.end(); anIt++) {
827     ModuleBase_ViewerPrsPtr aValue = *anIt;
828     ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aValue->object());
829     if (theToValidate && aRes.get()) {
830       if (myShapeTypeCombo->currentIndex() > 3)
831         aSelected.append(aValue);
832       else if (acceptSubShape(aValue->shape(), aRes))
833         aSelected.append(aValue);
834     }
835   }
836   AttributeSelectionListPtr aSelList =
837     myFeature->data()->selectionList(CollectionPlugin_Field::SELECTED_ID());
838   aSelList->setSelectionType(getSelectionType(myShapeTypeCombo->currentIndex()));
839   aSelList->clear();
840
841   ResultPtr aResult;
842   GeomShapePtr aShape;
843   int aNbData = 0;
844   foreach(ModuleBase_ViewerPrsPtr aPrs, aSelected) {
845     aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aPrs->object());
846     aShape = aPrs->shape();
847     if (!aResult.get() && !aShape.get())
848       continue;
849     if (!aSelList->isInList(aResult, aShape)) {
850       aSelList->append(aResult, aShape);
851       aNbData++;
852     }
853   }
854   int aColumns = myDataTblList.first()->columnCount();
855   int aRows = myDataTblList.first()->rowCount();
856   int aNewRows = aNbData + 1;
857   AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
858   aTablesAttr->setSize(aNewRows, aColumns - 1, myDataTblList.size());
859
860   QTableWidgetItem* aItem = 0;
861   foreach(QTableWidget* aTable, myDataTblList) {
862     aTable->setRowCount(aNewRows);
863     if (aNewRows > aRows) {
864       // Add new data
865       for(int i = 0; i < aColumns; i++) {
866         if (i == 0) {
867           for(int j = 1; j < aNewRows; j++) {
868             aItem = aTable->item(j, i);
869             if (!aItem) {
870               aItem = new QTableWidgetItem();
871               aTable->setItem(j, i, aItem);
872             }
873             AttributeSelectionPtr aAttr = aSelList->value(j - 1);
874             aItem->setText(aAttr->namingName().c_str());
875             aItem->setToolTip(aAttr->namingName().c_str());
876           }
877         } else {
878           QString aDefVal = aTable->item(0, i)->text();
879           for(int j = aRows; j < aNewRows; j++) {
880             aItem = aTable->item(j, i);
881             if (!aItem) {
882               aItem = new QTableWidgetItem();
883               aTable->setItem(j, i, aItem);
884             }
885             aItem->setText(aDefVal);
886           }
887         }
888       }
889     } else {
890       // Update only selection name
891       for(int j = 1; j < aNewRows - 1; j++) {
892         AttributeSelectionPtr aAttr = aSelList->value(j);
893         aTable->item(j, 0)->setText(aAttr->namingName().c_str());
894         aTable->item(j, 0)->setToolTip(aAttr->namingName().c_str());
895       }
896     }
897   }
898   return true;
899 }
900
901 //**********************************************************************************
902 void CollectionPlugin_WidgetField::onFieldTypeChanged(int theIdx)
903 {
904   ModelAPI_AttributeTables::ValueType aOldType = myDelegate->dataType();
905   if (aOldType != theIdx) {
906     myDelegate->setDataType((ModelAPI_AttributeTables::ValueType)theIdx);
907     int aColumns = myDataTblList.first()->columnCount();
908     int aRows = myDataTblList.first()->rowCount();
909     foreach(QTableWidget* aTable, myDataTblList) {
910       for(int i = 1; i < aColumns; i++) {
911         for(int j = 0; j < aRows; j++) {
912           switch (theIdx) {
913           case ModelAPI_AttributeTables::DOUBLE:
914           case ModelAPI_AttributeTables::INTEGER:
915             aTable->item(j, i)->setText("0");
916             break;
917           case ModelAPI_AttributeTables::BOOLEAN:
918             aTable->item(j, i)->setText(MYFalse);
919             break;
920           case ModelAPI_AttributeTables::STRING:
921             aTable->item(j, i)->setText("");
922             break;
923           }
924         }
925       }
926     }
927     emit valuesChanged();
928   }
929 }
930
931 //**********************************************************************************
932 void CollectionPlugin_WidgetField::onTableEdited(int theRow, int theCol)
933 {
934   // Do not store here column of names
935   if (theCol == 0)
936     return;
937   if (!myFeature.get())
938     return;
939   QTableWidget* aTable = static_cast<QTableWidget*>(sender());
940   int aNb = myDataTblList.indexOf(aTable);
941   if (aNb == -1)
942     return;
943   ModelAPI_AttributeTables::Value aVal = getValue(aTable->item(theRow, theCol)->text());
944
945   AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
946   if (aTablesAttr->isInitialized())
947     aTablesAttr->setValue(aVal,theRow, theCol - 1, aNb);
948   else
949     emit valuesChanged();
950 }
951
952 //**********************************************************************************
953 void CollectionPlugin_WidgetField::onShapeTypeChanged(int theType)
954 {
955   activateSelectionAndFilters(theType == 5? false:true);
956
957   AttributeSelectionListPtr aSelList =
958     myFeature->data()->selectionList(CollectionPlugin_Field::SELECTED_ID());
959
960   std::string aTypeName = getSelectionType(theType);
961   if (aTypeName == aSelList->selectionType())
962     return;
963   aSelList->setSelectionType(aTypeName);
964
965   //Clear old selection
966   clearData();
967   aSelList->clear();
968   AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
969   aTablesAttr->setSize(1, myNbComponentsSpn->value(), myDataTblList.size());
970   emit valuesChanged();
971 }
972
973 //**********************************************************************************
974 bool CollectionPlugin_WidgetField::processEnter()
975 {
976   if (myIsTabEdit) {
977     myIsTabEdit = false;
978     return true;
979   }
980   QWidget* aCurrWgt = qApp->focusWidget();
981   int aCurWgtId = myStepWgt->currentIndex();
982   if ((aCurrWgt == myShapeTypeCombo) ||
983       (aCurrWgt == myFieldTypeCombo) ||
984       (aCurrWgt == myNbComponentsSpn) ||
985       (aCurrWgt == myStampSpnList[aCurWgtId]) ||
986       (aCurrWgt == myDataTblList[aCurWgtId])) {
987     setFocus();
988     return true;
989   }
990   return false;
991 }
992
993 //**********************************************************************************
994 void CollectionPlugin_WidgetField::onFocusChanged(QWidget* theOld, QWidget* theNew)
995 {
996   if (theNew && (!myIsTabEdit))
997     myIsTabEdit = dynamic_cast<QLineEdit*>(theNew);
998 }
999
1000 //**********************************************************************************
1001 void CollectionPlugin_WidgetField::onRangeChanged(int theMin, int theMax)
1002 {
1003   myMaxLbl->setText(QString::number(theMax));
1004   myRemoveBtn->setEnabled(theMax > 1);
1005 }
1006
1007 //**********************************************************************************
1008 void CollectionPlugin_WidgetField::onColumnResize(int theIndex, int theOld, int theNew)
1009 {
1010   if (myDataTblList.count() < 2)
1011     return;
1012   QObject* aSender = sender();
1013   foreach(QTableWidget* aTable, myDataTblList) {
1014     if (aTable->horizontalHeader() != aSender)
1015       aTable->setColumnWidth(theIndex, theNew);
1016   }
1017 }
1018
1019 //**********************************************************************************
1020 QList<std::shared_ptr<ModuleBase_ViewerPrs>>
1021   CollectionPlugin_WidgetField::getAttributeSelection() const
1022 {
1023   QList<std::shared_ptr<ModuleBase_ViewerPrs>> aList;
1024   if(myFeature) {
1025     DataPtr aData = myFeature->data();
1026     AttributeSelectionListPtr aSelList =
1027       aData->selectionList(CollectionPlugin_Field::SELECTED_ID());
1028     AttributeSelectionPtr aAttr;
1029     ObjectPtr anObject;
1030     for (int i = 0; i < aSelList->size(); i++) {
1031       aAttr = aSelList->value(i);
1032       ModuleBase_ViewerPrsPtr
1033         aPrs(new ModuleBase_ViewerPrs(aAttr->context(), aAttr->value(), NULL));
1034       aList.append(aPrs);
1035     }
1036   }
1037   return aList;
1038 }