Salome HOME
Provide displaying of steps in data browser
[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_ISelection.h>
13 #include <ModuleBase_IPropertyPanel.h>
14
15 #include <ModelAPI_AttributeSelectionList.h>
16 #include <ModelAPI_AttributeStringArray.h>
17 #include <ModelAPI_AttributeInteger.h>
18 #include <ModelAPI_AttributeIntArray.h>
19
20 #include <QLayout>
21 #include <QWidget>
22 #include <QFormLayout>
23 #include <QComboBox>
24 #include <QSpinBox>
25 #include <QLabel>
26 #include <QSlider>
27 #include <QTableWidget>
28 #include <QPushButton>
29 #include <QHeaderView>
30 #include <QStackedWidget>
31 #include <QValidator>
32 #include <QStyledItemDelegate>
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 class DataTableItemDelegate : public QStyledItemDelegate
44 {
45 public:
46   DataTableItemDelegate(ModelAPI_AttributeTables::ValueType theType) :
47       QStyledItemDelegate() { myType = theType; }
48
49   virtual QWidget* createEditor(QWidget* theParent,
50                                 const QStyleOptionViewItem & theOption,
51                                 const QModelIndex& theIndex) const;
52
53   ModelAPI_AttributeTables::ValueType dataType() const { return myType; }
54
55   void setDataType(ModelAPI_AttributeTables::ValueType theType) { myType = theType; }
56
57 signals:
58   void startEditing();
59
60 private:
61   ModelAPI_AttributeTables::ValueType myType;
62 };
63
64 QWidget* DataTableItemDelegate::createEditor(QWidget* theParent,
65                                              const QStyleOptionViewItem & theOption,
66                                              const QModelIndex& theIndex ) const
67 {
68   if ((theIndex.column() == 0) && (theIndex.row() > 0)) {
69     QWidget* aWgt = QStyledItemDelegate::createEditor(theParent, theOption, theIndex);
70     QLineEdit* aEdt = static_cast<QLineEdit*>(aWgt);
71     aEdt->setReadOnly(true);
72     return aEdt;
73   } else {
74     QLineEdit* aLineEdt = 0;
75     switch (myType) {
76     case ModelAPI_AttributeTables::DOUBLE:
77       aLineEdt = dynamic_cast<QLineEdit*>(QStyledItemDelegate::createEditor(theParent,
78                                                                             theOption,
79                                                                             theIndex));
80       if (aLineEdt) {
81         aLineEdt->setValidator(new QDoubleValidator(aLineEdt));
82         return aLineEdt;
83       }
84       break;
85     case ModelAPI_AttributeTables::INTEGER:
86       aLineEdt = dynamic_cast<QLineEdit*>(QStyledItemDelegate::createEditor(theParent,
87                                                                             theOption,
88                                                                             theIndex));
89       if (aLineEdt) {
90         aLineEdt->setValidator(new QIntValidator(aLineEdt));
91         return aLineEdt;
92       }
93       break;
94     case ModelAPI_AttributeTables::BOOLEAN:
95       {
96         QComboBox* aBox = new QComboBox(theParent);
97         aBox->addItem(MYFalse);
98         aBox->addItem(MYTrue);
99         return aBox;
100       }
101     }
102   }
103   return QStyledItemDelegate::createEditor(theParent, theOption, theIndex);
104 }
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   appendStepControls();
185
186   // Buttons below
187   QWidget* aBtnWgt = new QWidget(this);
188   aMainLayout->addWidget(aBtnWgt);
189   QHBoxLayout* aBtnLayout = new QHBoxLayout(aBtnWgt);
190   aBtnLayout->setContentsMargins(0, 0, 0, 0);
191
192   QPushButton* aAddBtn = new QPushButton(tr("Add step"), aBtnWgt);
193   aBtnLayout->addWidget(aAddBtn);
194
195   aBtnLayout->addStretch(1);
196
197   myRemoveBtn = new QPushButton(tr("Remove step"), aBtnWgt);
198   aBtnLayout->addWidget(myRemoveBtn);
199   myRemoveBtn->setEnabled(false);
200
201   connect(myNbComponentsSpn, SIGNAL(valueChanged(int)), SLOT(onNbCompChanged(int)));
202   connect(aAddBtn, SIGNAL(clicked(bool)), SLOT(onAddStep()));
203   connect(myRemoveBtn, SIGNAL(clicked(bool)), SLOT(onRemoveStep()));
204   connect(myStepSlider, SIGNAL(valueChanged(int)), SLOT(onStepMove(int)));
205   connect(myStepSlider, SIGNAL(rangeChanged(int, int)), SLOT(onRangeChanged(int, int)));
206   connect(myFieldTypeCombo, SIGNAL(currentIndexChanged(int)), SLOT(onFieldTypeChanged(int)));
207   connect(myShapeTypeCombo, SIGNAL(currentIndexChanged(int)), SLOT(onShapeTypeChanged(int)));
208   connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)), SLOT(onFocusChanged(QWidget*, QWidget*)));
209 }
210
211 //**********************************************************************************
212 void CollectionPlugin_WidgetField::appendStepControls()
213 {
214   QWidget* aWidget = new QWidget(myStepWgt);
215   QGridLayout* aStepLayout = new QGridLayout(aWidget);
216   aStepLayout->setContentsMargins(0, 0, 0, 0);
217
218   aStepLayout->addWidget(new QLabel(tr("Stamp"), aWidget), 0, 0);
219
220   QSpinBox* aStampSpn = new QSpinBox(aWidget);
221   aStepLayout->addWidget(aStampSpn, 0, 1);
222
223   myStampSpnList.append(aStampSpn);
224
225   // Data table
226   QTableWidget* aDataTbl = new QTableWidget(1, myCompNamesList.count() + 1, aWidget);
227   aDataTbl->installEventFilter(this);
228   DataTableItemDelegate* aDelegate = 0;
229   if (myDataTblList.isEmpty())
230     aDelegate = new DataTableItemDelegate(
231       (ModelAPI_AttributeTables::ValueType) myFieldTypeCombo->currentIndex());
232   else
233     aDelegate = dynamic_cast<DataTableItemDelegate*>(myDataTblList.first()->itemDelegate());
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   aDataTbl->setItemDelegate(aDelegate);
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       aDataTbl->setColumnWidth(i, aColWidth.at(i));
268   }
269   aStepLayout->addWidget(aDataTbl, 1, 0, 1, 2);
270   connect(aDataTbl, SIGNAL(cellChanged(int, int)), SLOT(onTableEdited(int, int)));
271
272   QAbstractItemDelegate* aDel = aDataTbl->itemDelegate();
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.push_back(myShapeTypeCombo);
438   aControls.push_back(myFieldTypeCombo);
439   aControls.push_back(myNbComponentsSpn);
440   return aControls;
441 }
442
443 //**********************************************************************************
444 bool CollectionPlugin_WidgetField::storeValueCustom()
445 {
446   DataPtr aData = myFeature->data();
447   // Store number of components
448   AttributeStringArrayPtr aStringsAttr =
449     aData->stringArray(CollectionPlugin_Field::COMPONENTS_NAMES_ID());
450   int aNbComps = myCompNamesList.size();
451   aStringsAttr->setSize(aNbComps);
452   for ( int i = 0; i < aNbComps; i++)
453     aStringsAttr->setValue(i, myCompNamesList.at(i).toStdString());
454
455   AttributeTablesPtr aTablesAttr = aData->tables(CollectionPlugin_Field::VALUES_ID());
456   // Store number of steps
457   int aNbSteps =  myDataTblList.size();
458
459   // Store Type of the field values
460   int aFldType = myFieldTypeCombo->currentIndex();
461
462   AttributeIntArrayPtr aStampsAttr = aData->intArray(CollectionPlugin_Field::STAMPS_ID());
463   aStampsAttr->setSize(aNbSteps);
464   // Store data
465   QTableWidget* aTable = myDataTblList.first();
466   int aRows = aTable->rowCount();
467   // first column contains selected names which should not be stored
468   int aColumns = aTable->columnCount() - 1;
469
470   aTablesAttr->setSize(aRows, aColumns, aNbSteps);
471   aTablesAttr->setType((ModelAPI_AttributeTables::ValueType)aFldType);
472   for (int i = 0; i < aNbSteps; i++) {
473     aStampsAttr->setValue(i, myStampSpnList.at(i)->value());
474     aTable = myDataTblList.at(i);
475     for (int j = 0; j < aColumns; j++) {
476       for (int k = 0; k < aRows; k++) {
477         QString aTblVal = aTable->item(k, j + 1)->text();
478         aTablesAttr->setValue(getValue(aTblVal), k, j, i);
479       }
480     }
481   }
482   updateObject(myFeature);
483   return true;
484 }
485
486 //**********************************************************************************
487 bool CollectionPlugin_WidgetField::restoreValueCustom()
488 {
489   bool isBlocked;
490   DataPtr aData = myFeature->data();
491
492   AttributeSelectionListPtr aSelList = aData->selectionList(CollectionPlugin_Field::SELECTED_ID());
493   std::string aTypeStr = aSelList->selectionType();
494   if (aTypeStr == "")
495     return false; // The attribute is not initialized
496   myShapeTypeCombo->setCurrentIndex(getSelectionType(aTypeStr));
497
498   // Get number of components
499   AttributeStringArrayPtr aStringsAttr =
500   aData->stringArray(CollectionPlugin_Field::COMPONENTS_NAMES_ID());
501
502   myCompNamesList.clear();
503   for (int i = 0; i < aStringsAttr->size(); i++) {
504     myCompNamesList.append(aStringsAttr->value(i).c_str());
505   }
506   isBlocked = myNbComponentsSpn->blockSignals(true);
507   myNbComponentsSpn->setValue(myCompNamesList.size());
508   myNbComponentsSpn->blockSignals(isBlocked);
509
510   AttributeTablesPtr aTablesAttr = aData->tables(CollectionPlugin_Field::VALUES_ID());
511   // Get number of steps
512   int aNbSteps = aTablesAttr->tables();
513   myStepSlider->setMaximum(aNbSteps);
514   //myStepSlider->setValue(1);
515   // Clear old tables
516   while (myDataTblList.count() > aNbSteps) {
517     QWidget* aWgt = myStepWgt->widget(myStepWgt->count() - 1);
518     myStepWgt->removeWidget(aWgt);
519     aWgt->deleteLater();
520
521     myStampSpnList.removeLast();
522     myDataTblList.removeLast();
523   }
524   while (myDataTblList.count() < aNbSteps)
525     appendStepControls();
526   //myStepWgt->setCurrentIndex(myStepSlider->value() - 1);
527   clearData();
528
529   // Get Type of the field values
530   isBlocked = myFieldTypeCombo->blockSignals(true);
531   myFieldTypeCombo->setCurrentIndex(aTablesAttr->type());
532   myFieldTypeCombo->blockSignals(isBlocked);
533
534   AttributeIntArrayPtr aStampsAttr = aData->intArray(CollectionPlugin_Field::STAMPS_ID());
535   // Fill data table
536   int aRows = aTablesAttr->rows();
537   int aCols = aTablesAttr->columns();
538
539   // Get width of columns
540   QIntList aColWidth;
541   QTableWidget* aFirstTable = myDataTblList.first();
542   for (int i = 0; i < aFirstTable->columnCount(); i++)
543     aColWidth.append(aFirstTable->columnWidth(i));
544
545   QTableWidgetItem* aItem = 0;
546   for (int i = 0; i < aNbSteps; i++) {
547     myStampSpnList.at(i)->setValue(aStampsAttr->value(i));
548     QTableWidget* aTable = myDataTblList.at(i);
549     isBlocked = aTable->blockSignals(true);
550     aTable->setRowCount(aRows);
551     for (int j = 0; j < aCols + 1; j++) {
552       for (int k = 0; k < aRows; k++) {
553         aItem = aTable->item(k, j);
554         if ((j == 0) && (k > 0)) {
555           // Add selection names
556           AttributeSelectionPtr aAttr = aSelList->value(k - 1);
557           if (aItem) {
558             aItem->setText(aAttr->namingName().c_str());
559           } else {
560             aItem = new QTableWidgetItem(aAttr->namingName().c_str());
561             aTable->setItem(k, j, aItem);
562           }
563         } else if (j > 0) {
564           // Add Values
565           ModelAPI_AttributeTables::Value aVal = aTablesAttr->value(k, j - 1, i);
566           if (aItem) {
567             aItem->setText(getValueText(aVal));
568           } else {
569             aItem = createValueItem(aVal);
570             if (k == 0)
571               aItem->setBackgroundColor(Qt::lightGray);
572             aTable->setItem(k, j, aItem);
573           }
574         }
575       }
576     }
577     // Restore columns width
578     for (int i = 0; i < aTable->columnCount(); i++)
579       aTable->setColumnWidth(i, aColWidth.at(i));
580
581     aTable->blockSignals(isBlocked);
582   }
583   return true;
584 }
585
586 //**********************************************************************************
587 int CollectionPlugin_WidgetField::getSelectionType(const std::string& theStr) const
588 {
589   QString aType(theStr.c_str());
590   aType = aType.toLower();
591   if (aType == "vertex")
592     return 0;
593   else if (aType == "edge")
594     return 1;
595   else if (aType == "face")
596     return 2;
597   else if (aType == "solid")
598     return 3;
599   else if (aType == "object")
600     return 4;
601   else if (aType == "part")
602     return 5;
603   return -1;
604 }
605
606
607 //**********************************************************************************
608 std::string CollectionPlugin_WidgetField::getSelectionType(int theType) const
609 {
610   switch (theType) {
611   case 0: //"Vertices"
612     return "vertex";
613   case 1: // "Edges"
614     return "edge";
615   case 2: // "Faces"
616     return "face";
617   case 3: // "Solids"
618     return "solid";
619   case 4: // "Results"
620     return "object";
621   case 5: // "Parts"
622     return "part";
623   }
624   return "";
625 }
626
627 //**********************************************************************************
628 QIntList CollectionPlugin_WidgetField::shapeTypes() const
629 {
630   QIntList aRes;
631   switch (myShapeTypeCombo->currentIndex()) {
632   case 0: //"Vertices"
633     aRes.append(ModuleBase_Tools::shapeType("vertex"));
634     break;
635   case 1: // "Edges"
636     aRes.append(ModuleBase_Tools::shapeType("edge"));
637     break;
638   case 2: // "Faces"
639     aRes.append(ModuleBase_Tools::shapeType("face"));
640     break;
641   case 3: // "Solids"
642     aRes.append(ModuleBase_Tools::shapeType("solid"));
643     break;
644   case 4: // "Results"
645     aRes.append(ModuleBase_Tools::shapeType("object"));
646     break;
647   case 5: // "Parts"
648     // TODO: Selection mode for Parts
649     break;
650   }
651   return aRes;
652 }
653
654 //**********************************************************************************
655 ModelAPI_AttributeTables::Value CollectionPlugin_WidgetField::getValue(QString theStrVal) const
656 {
657   ModelAPI_AttributeTables::Value aVal;
658   switch (myFieldTypeCombo->currentIndex()) {
659   case ModelAPI_AttributeTables::BOOLEAN:
660     aVal.myBool = (theStrVal == MYTrue)? true : false;
661     break;
662   case ModelAPI_AttributeTables::DOUBLE:
663     aVal.myDouble = theStrVal.toDouble();
664     break;
665   case ModelAPI_AttributeTables::INTEGER:
666     aVal.myInt = theStrVal.toInt();
667     break;
668   case ModelAPI_AttributeTables::STRING:
669     aVal.myStr = theStrVal.toStdString();
670   }
671   return aVal;
672 }
673
674
675 //**********************************************************************************
676 void CollectionPlugin_WidgetField::onNbCompChanged(int theVal)
677 {
678   int aOldCol = myCompNamesList.count();
679   int aNbRows = myDataTblList.first()->rowCount();
680   int aDif = theVal - aOldCol;
681   QTableWidgetItem* aItem = 0;
682
683   while (myCompNamesList.count() != theVal) {
684     if (aDif > 0)
685       myCompNamesList.append(QString("Comp %1").arg(myCompNamesList.count() + 1));
686     else
687       myCompNamesList.removeLast();
688   }
689
690   AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
691   aTablesAttr->setSize(aNbRows, myCompNamesList.size(), myDataTblList.size());
692
693   foreach(QTableWidget* aDataTbl, myDataTblList) {
694     aDataTbl->setColumnCount(theVal + 1);
695     updateHeaders(aDataTbl);
696     for (int i = aOldCol; i < myCompNamesList.count(); i++) {
697       for (int j = 0; j < aNbRows; j++) {
698         aItem = aDataTbl->item(j, i + 1);
699         if (!aItem) {
700           aItem = createDefaultItem();
701           if (j == 0)
702             aItem->setBackgroundColor(Qt::lightGray);
703           aDataTbl->setItem(j, i + 1, aItem);
704         }
705       }
706     }
707   }
708   emit valuesChanged();
709 }
710
711 //**********************************************************************************
712 void CollectionPlugin_WidgetField::onAddStep()
713 {
714   int aMax = myStepSlider->maximum();
715   aMax++;
716   myStepSlider->setMaximum(aMax);
717   myMaxLbl->setText(QString::number(aMax));
718   appendStepControls();
719   myStepSlider->setValue(aMax);
720
721   AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
722   aTablesAttr->setSize(aTablesAttr->rows(), aTablesAttr->columns(), myDataTblList.size());
723
724
725   AttributeSelectionListPtr aSelList =
726     myFeature->data()->selectionList(CollectionPlugin_Field::SELECTED_ID());
727   if (!aSelList->isInitialized())
728     return;
729   int aSelNb = aSelList->size();
730   if (aSelNb == 0)
731     return;
732
733   int aColumns = myNbComponentsSpn->value() + 1;
734   int aRows = aSelNb + 1;
735   QTableWidget* aTable = myDataTblList.last();
736   aTable->setRowCount(aRows);
737   QTableWidgetItem* aItem = 0;
738   for(int i = 0; i < aColumns; i++) {
739     if (i == 0) {
740       for(int j = 1; j < aRows; j++) {
741         aItem = aTable->item(j, i);
742         if (!aItem) {
743           aItem = new QTableWidgetItem();
744           aTable->setItem(j, i, aItem);
745         }
746         AttributeSelectionPtr aAttr = aSelList->value(j - 1);
747         aItem->setText(aAttr->namingName().c_str());
748         aItem->setToolTip(aAttr->namingName().c_str());
749       }
750     } else {
751       QString aDefVal = aTable->item(0, i)->text();
752       for(int j = 1; j < aRows; j++) {
753         aItem = aTable->item(j, i);
754         if (!aItem) {
755           aItem = new QTableWidgetItem();
756           aTable->setItem(j, i, aItem);
757         }
758         aItem->setText(aDefVal);
759       }
760     }
761   }
762   emit valuesChanged();
763 }
764
765 //**********************************************************************************
766 void CollectionPlugin_WidgetField::onRemoveStep()
767 {
768   int aMax = myStepSlider->maximum();
769   aMax--;
770   myMaxLbl->setText(QString::number(aMax));
771   removeStepControls();
772   myStepSlider->setMaximum(aMax);
773
774   //AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
775   //aTablesAttr->setSize(aTablesAttr->rows(), aTablesAttr->columns(), myDataTblList.size());
776   emit valuesChanged();
777 }
778
779 //**********************************************************************************
780 void CollectionPlugin_WidgetField::clearData()
781 {
782   foreach(QTableWidget* aDataTbl, myDataTblList) {
783     aDataTbl->setRowCount(1);
784   }
785 }
786
787 //**********************************************************************************
788 void CollectionPlugin_WidgetField::onStepMove(int theStep)
789 {
790   myCurStepLbl->setText(QString::number(theStep));
791   myStepWgt->setCurrentIndex(theStep - 1);
792 }
793
794 //**********************************************************************************
795 bool CollectionPlugin_WidgetField::
796   isValidSelectionCustom(const std::shared_ptr<ModuleBase_ViewerPrs>& thePrs)
797 {
798   return (myShapeTypeCombo->currentIndex() == 5)? false : true;
799 }
800
801 //**********************************************************************************
802 void CollectionPlugin_WidgetField::onSelectionChanged()
803 {
804   //if (isEditingMode())
805   //  return;
806
807   if (myActivation) {
808     myActivation = false;
809     return;
810   }
811   // Ignore selection for Parts mode
812   if (myShapeTypeCombo->currentIndex() == 5)
813     return;
814
815   QList<ModuleBase_ViewerPrsPtr> aSelected = getFilteredSelected();
816
817   AttributeSelectionListPtr aSelList =
818     myFeature->data()->selectionList(CollectionPlugin_Field::SELECTED_ID());
819   aSelList->setSelectionType(getSelectionType(myShapeTypeCombo->currentIndex()));
820   aSelList->clear();
821
822   ResultPtr aResult;
823   GeomShapePtr aShape;
824   int aNbData = 0;
825   foreach(ModuleBase_ViewerPrsPtr aPrs, aSelected) {
826     aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aPrs->object());
827     aShape = aPrs->shape();
828     if (!aResult.get() && !aShape.get())
829       continue;
830     if (!aSelList->isInList(aResult, aShape)) {
831       aSelList->append(aResult, aShape);
832       aNbData++;
833     }
834   }
835   int aColumns = myDataTblList.first()->columnCount();
836   int aRows = myDataTblList.first()->rowCount();
837   int aNewRows = aNbData + 1;
838   AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
839   aTablesAttr->setSize(aNewRows, aColumns - 1, myDataTblList.size());
840
841   QTableWidgetItem* aItem = 0;
842   foreach(QTableWidget* aTable, myDataTblList) {
843     aTable->setRowCount(aNewRows);
844     if (aNewRows > aRows) {
845       // Add new data
846       for(int i = 0; i < aColumns; i++) {
847         if (i == 0) {
848           for(int j = 1; j < aNewRows; j++) {
849             aItem = aTable->item(j, i);
850             if (!aItem) {
851               aItem = new QTableWidgetItem();
852               aTable->setItem(j, i, aItem);
853             }
854             AttributeSelectionPtr aAttr = aSelList->value(j - 1);
855             aItem->setText(aAttr->namingName().c_str());
856             aItem->setToolTip(aAttr->namingName().c_str());
857           }
858         } else {
859           QString aDefVal = aTable->item(0, i)->text();
860           for(int j = aRows; j < aNewRows; j++) {
861             aItem = aTable->item(j, i);
862             if (!aItem) {
863               aItem = new QTableWidgetItem();
864               aTable->setItem(j, i, aItem);
865             }
866             aItem->setText(aDefVal);
867           }
868         }
869       }
870     } else {
871       // Update only selection name
872       for(int j = 1; j < aNewRows - 1; j++) {
873         AttributeSelectionPtr aAttr = aSelList->value(j);
874         aTable->item(j, 0)->setText(aAttr->namingName().c_str());
875         aTable->item(j, 0)->setToolTip(aAttr->namingName().c_str());
876       }
877     }
878   }
879   emit valuesChanged();
880 }
881
882 //**********************************************************************************
883 void CollectionPlugin_WidgetField::onFieldTypeChanged(int theIdx)
884 {
885   DataTableItemDelegate* aDelegate = 0;
886   aDelegate = dynamic_cast<DataTableItemDelegate*>(myDataTblList.first()->itemDelegate());
887   if (aDelegate) {
888     ModelAPI_AttributeTables::ValueType aOldType = aDelegate->dataType();
889     if (aOldType != theIdx) {
890       aDelegate->setDataType((ModelAPI_AttributeTables::ValueType)theIdx);
891       int aColumns = myDataTblList.first()->columnCount();
892       int aRows = myDataTblList.first()->rowCount();
893       foreach(QTableWidget* aTable, myDataTblList) {
894         for(int i = 1; i < aColumns; i++) {
895           for(int j = 0; j < aRows; j++) {
896             switch (theIdx) {
897             case ModelAPI_AttributeTables::DOUBLE:
898             case ModelAPI_AttributeTables::INTEGER:
899               if ((aOldType == ModelAPI_AttributeTables::BOOLEAN) ||
900                   (aOldType == ModelAPI_AttributeTables::STRING)) {
901                     aTable->item(j, i)->setText("0");
902               }
903               break;
904             case ModelAPI_AttributeTables::BOOLEAN:
905               aTable->item(j, i)->setText(MYFalse);
906               break;
907             case ModelAPI_AttributeTables::STRING:
908               aTable->item(j, i)->setText("");
909               break;
910             }
911           }
912         }
913       }
914       emit valuesChanged();
915     }
916   }
917 }
918
919 //**********************************************************************************
920 void CollectionPlugin_WidgetField::onTableEdited(int theRow, int theCol)
921 {
922   // Do not store here column of names
923   if (theCol == 0)
924     return;
925   if (!myFeature.get())
926     return;
927   QTableWidget* aTable = static_cast<QTableWidget*>(sender());
928   int aNb = myDataTblList.indexOf(aTable);
929   if (aNb == -1)
930     return;
931   ModelAPI_AttributeTables::Value aVal = getValue(aTable->item(theRow, theCol)->text());
932
933   AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
934   if (aTablesAttr->isInitialized())
935     aTablesAttr->setValue(aVal,theRow, theCol - 1, aNb);
936   else
937     emit valuesChanged();
938 }
939
940 //**********************************************************************************
941 void CollectionPlugin_WidgetField::onShapeTypeChanged(int theType)
942 {
943   activateSelectionAndFilters(theType == 5? false:true);
944
945   AttributeSelectionListPtr aSelList =
946     myFeature->data()->selectionList(CollectionPlugin_Field::SELECTED_ID());
947
948   std::string aTypeName = getSelectionType(theType);
949   if (aTypeName == aSelList->selectionType())
950     return;
951   aSelList->setSelectionType(aTypeName);
952
953   //Clear old selection
954   clearData();
955   aSelList->clear();
956   AttributeTablesPtr aTablesAttr = myFeature->data()->tables(CollectionPlugin_Field::VALUES_ID());
957   aTablesAttr->setSize(1, myNbComponentsSpn->value(), myDataTblList.size());
958   emit valuesChanged();
959 }
960
961 //**********************************************************************************
962 bool CollectionPlugin_WidgetField::processEnter()
963 {
964   if (myIsTabEdit) {
965     myIsTabEdit = false;
966     return true;
967   }
968   return false;
969 }
970
971 //**********************************************************************************
972 void CollectionPlugin_WidgetField::onFocusChanged(QWidget* theOld, QWidget* theNew)
973 {
974   if (theNew && (!myIsTabEdit))
975     myIsTabEdit = dynamic_cast<QLineEdit*>(theNew);
976 }
977
978 //**********************************************************************************
979 void CollectionPlugin_WidgetField::onRangeChanged(int theMin, int theMax)
980 {
981   myMaxLbl->setText(QString::number(theMax));
982   myRemoveBtn->setEnabled(theMax > 1);
983 }
984
985 //**********************************************************************************
986 void CollectionPlugin_WidgetField::onColumnResize(int theIndex, int theOld, int theNew)
987 {
988   if (myDataTblList.count() < 2)
989     return;
990   QObject* aSender = sender();
991   foreach(QTableWidget* aTable, myDataTblList) {
992     if (aTable->horizontalHeader() != aSender)
993       aTable->setColumnWidth(theIndex, theNew);
994   }
995 }