Salome HOME
Issue #979: Manage parameters
[modules/shaper.git] / src / ParametersPlugin / ParametersPlugin_WidgetParamsMgr.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        ParametersPlugin_WidgetParamsMgr.cpp
4 // Created:     11 Apr 2016
5 // Author:      Vitaly SMETANNIKOV
6
7 #include "ParametersPlugin_WidgetParamsMgr.h"
8 #include "ParametersPlugin_Parameter.h"
9
10 #include <ModelAPI_ResultParameter.h>
11 #include <ModelAPI_AttributeString.h>
12 #include <ModelAPI_AttributeRefList.h>
13 #include <ModelAPI_AttributeDouble.h>
14 #include <ModelAPI_AttributeInteger.h>
15 #include <ModelAPI_Events.h>
16 #include <ModelAPI_Session.h>
17
18 #include <Events_Loop.h>
19
20 #include <QLayout>
21 #include <QTreeWidget>
22 #include <QPushButton>
23 #include <QToolButton>
24 #include <QStyledItemDelegate>
25 #include <QPainter>
26 #include <QMessageBox>
27 #include <QTimer>
28
29 enum ColumnType {
30   Col_Name,
31   Col_Equation,
32   Col_Result,
33   Col_Comment
34 };
35
36 const char* NoName = "<NoName>";
37 const char* NoValue = "<NoValue>";
38
39 class ParametersPlugin_ItemDelegate : public QStyledItemDelegate
40 {
41 public:
42   ParametersPlugin_ItemDelegate(QObject* thaParent) : 
43       QStyledItemDelegate(thaParent) {}
44
45   virtual void paint(QPainter* painter, 
46     const QStyleOptionViewItem& option, 
47     const QModelIndex& index ) const;
48   
49   //virtual QWidget* createEditor(QWidget* parent, 
50   //                              const QStyleOptionViewItem& option, 
51   //                              const QModelIndex& index) const;
52
53   bool isEditable(const QModelIndex& theIndex) const;
54 };
55
56 bool ParametersPlugin_ItemDelegate::isEditable(const QModelIndex& theIndex) const
57 {
58   QModelIndex aParent = theIndex.parent();
59   if (aParent.isValid() && (aParent.row() == 0)) {
60     if (theIndex.column() == 2)
61       return false;
62   } else
63     return false;
64   return true;
65 }
66
67 void ParametersPlugin_ItemDelegate::paint(QPainter* painter, 
68                                           const QStyleOptionViewItem& option, 
69                                           const QModelIndex& index ) const
70 {
71   QBrush aBrush = painter->brush();
72   QPen aPen = painter->pen();
73   if (!isEditable(index))
74     painter->setBrush(Qt::lightGray);
75
76   painter->setPen(Qt::darkGray);
77   painter->drawRect(option.rect);
78   painter->setPen(aPen);
79   
80   //QString aText = index.data().toString();
81   //if ((aText == NoName) || (aText == NoValue))
82   //  painter->setPen(Qt::red);
83
84   QStyledItemDelegate::paint(painter, option, index);
85
86   //painter->setPen(aPen);
87   painter->setBrush(aBrush);
88 }
89
90
91 //QWidget* ParametersPlugin_ItemDelegate::createEditor(QWidget* parent, 
92 //                                                    const QStyleOptionViewItem& option, 
93 //                                                    const QModelIndex& index) const
94 //{
95 //  QWidget* aWgt = QStyledItemDelegate::createEditor(parent, option, index); 
96 //  aWgt->setMinimumSize(option.rect.width() - option.decorationSize.width(), 
97 //                       option.rect.height());
98 //  return aWgt;
99 //}
100
101
102 /////////////////////////////////////////////////////////////////////////////////////////////////
103
104 ParametersPlugin_WidgetParamsMgr::ParametersPlugin_WidgetParamsMgr(QWidget* theParent, const Config_WidgetAPI* theData)
105   : ModuleBase_ModelWidget(theParent, theData)
106 {
107   QVBoxLayout* aLayout = new QVBoxLayout(this);
108
109   myTable = new QTreeWidget(this);
110   myTable->setColumnCount(4);
111   QStringList aHeaders;
112   aHeaders << tr("Name") << tr("Equation") << tr("Result") << tr("Comment");
113   myTable->setHeaderLabels(aHeaders);
114   myTable->setColumnWidth(Col_Name, 200);
115   myTable->setColumnWidth(Col_Equation, 100);
116   myTable->setColumnWidth(Col_Result, 80);
117   myTable->setColumnWidth(Col_Comment, 200);
118   myTable->setMinimumWidth(600);
119   myTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
120   connect(myTable, SIGNAL(doubleClicked(const QModelIndex&)),
121           SLOT(onDoubleClick(const QModelIndex&)));
122   //myTable->viewport()->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum));
123
124   myDelegate = new ParametersPlugin_ItemDelegate(myTable);
125   connect(myDelegate, SIGNAL(closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint)), 
126           SLOT(onCloseEditor(QWidget*, QAbstractItemDelegate::EndEditHint)));
127
128   myTable->setItemDelegate(myDelegate);
129   aLayout->addWidget(myTable);
130
131   // Define root nodes
132   QStringList aNames;
133   aNames<<tr("Parameters");
134   myParameters = new QTreeWidgetItem(aNames);
135   myTable->addTopLevelItem(myParameters);
136
137   aNames.clear();
138   aNames<<tr("Features");
139   myFeatures = new QTreeWidgetItem(aNames);
140   myTable->addTopLevelItem(myFeatures);
141
142   QHBoxLayout* aBtnLayout = new QHBoxLayout(this);
143
144   QToolButton* aUpBtn = new QToolButton(this);
145   aUpBtn->setArrowType(Qt::UpArrow);
146   connect(aUpBtn, SIGNAL(clicked(bool)), SLOT(onUp()));
147   aBtnLayout->addWidget(aUpBtn);
148
149   QToolButton* aDownBtn = new QToolButton(this);
150   aDownBtn->setArrowType(Qt::DownArrow);
151   connect(aDownBtn, SIGNAL(clicked(bool)), SLOT(onDown()));
152   aBtnLayout->addWidget(aDownBtn);
153
154   aBtnLayout->addStretch();
155
156   QPushButton* aAddBtn = new QPushButton(tr("Add"), this);
157   connect(aAddBtn, SIGNAL(clicked(bool)), SLOT(onAdd()));
158   aBtnLayout->addWidget(aAddBtn);
159
160   QPushButton* aInsertBtn = new QPushButton(tr("Insert"), this);
161   connect(aInsertBtn, SIGNAL(clicked(bool)), SLOT(onInsert()));
162   aBtnLayout->addWidget(aInsertBtn);
163
164   QPushButton* aRemoveBtn = new QPushButton(tr("Remove"), this);
165   connect(aRemoveBtn, SIGNAL(clicked(bool)), SLOT(onRemove()));
166   aBtnLayout->addWidget(aRemoveBtn);
167
168   aLayout->addLayout(aBtnLayout);
169 }
170
171 QList<QWidget*> ParametersPlugin_WidgetParamsMgr::getControls() const
172 {
173   QList<QWidget*> aList;
174
175   return aList;
176 }
177
178 bool ParametersPlugin_WidgetParamsMgr::storeValueCustom()
179 {
180   for(int i = 0; i < myParameters->childCount(); i++) {
181     QTreeWidgetItem* aItem = myParameters->child(i);
182     if ((aItem->text(Col_Name) == NoName) || (aItem->text(Col_Equation) == NoValue)) {
183       QMessageBox::warning(this, tr("Warning"), tr("Created parameter is not defined properly."));
184
185       // The index of myParameters item
186       QModelIndex aParent = myTable->model()->index(0, 0);
187       int aRow = myParameters->indexOfChild(aItem);
188       QModelIndex aIndex = myTable->model()->index(aRow, Col_Name, aParent);
189       myTable->selectionModel()->select(aIndex, 
190         QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
191       myTable->scrollToItem(aItem);
192       return false;
193     }
194   }
195   return true;
196 }
197
198 bool ParametersPlugin_WidgetParamsMgr::restoreValueCustom()
199 {
200   return true;
201 }
202
203 void ParametersPlugin_WidgetParamsMgr::activateCustom()
204 {
205   FeaturePtr aFeature = feature();
206   DocumentPtr aDoc = aFeature->document();
207   int aNbParam = aDoc->size(ModelAPI_ResultParameter::group());
208   ObjectPtr aObj;
209   QTreeWidgetItem* aItem;
210   ResultParameterPtr aParam;
211   FeaturePtr aParamFeature;
212   for (int i = 0; i < aNbParam; i++) {
213     aObj = aDoc->object(ModelAPI_ResultParameter::group(), i);
214     aParam = std::dynamic_pointer_cast<ModelAPI_ResultParameter>(aObj);
215     if (aParam.get()) {
216       // Set parameter feature
217       aParamFeature = ModelAPI_Feature::feature(aParam);
218
219       QStringList aValues;
220       aValues << aParamFeature->string(ParametersPlugin_Parameter::VARIABLE_ID())->value().c_str();
221       aValues << aParamFeature->string(ParametersPlugin_Parameter::EXPRESSION_ID())->value().c_str();
222
223       AttributeDoublePtr aValueAttribute = aParam->data()->real(ModelAPI_ResultParameter::VALUE());
224       aValues << QString::number(aValueAttribute->value());
225
226       aValues << aParamFeature->string(ParametersPlugin_Parameter::COMMENT_ID())->value().c_str();
227
228       aItem = new QTreeWidgetItem(aValues);
229       aItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled);
230       myParameters->addChild(aItem);
231
232       myParametersList.append(aParamFeature);
233
234       // Set features where the parameter is used
235       const std::set<std::shared_ptr<ModelAPI_Attribute>>& aRefs = aParam->data()->refsToMe();
236       std::set<std::shared_ptr<ModelAPI_Attribute> >::const_iterator aIt;
237       for(aIt = aRefs.cbegin(); aIt != aRefs.cend(); aIt++) {
238         std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
239         FeaturePtr aReferenced = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
240         if (aReferenced.get()) {
241           QStringList aValNames;
242           aValNames << aReferenced->data()->name().c_str();
243
244           AttributeDoublePtr aDouble = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(aAttr);
245           if (aDouble.get()) {
246             aValNames << aDouble->text().c_str();
247             aValNames << QString::number(aDouble->value());
248           } else {
249             AttributeIntegerPtr aInt = std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(aAttr);
250             if (aInt.get()) {
251               aValNames << aInt->text().c_str();
252               aValNames << QString::number(aInt->value());
253             }
254           }
255
256           aItem = new QTreeWidgetItem(aValNames);
257           myFeatures->addChild(aItem);
258         }
259       }
260     }
261   }
262   myFeatures->setExpanded(true);
263   myParameters->setExpanded(true);
264 }
265
266
267 void ParametersPlugin_WidgetParamsMgr::onDoubleClick(const QModelIndex& theIndex)
268 {
269   if (myDelegate->isEditable(theIndex)) {
270     myTable->edit(theIndex);
271     myEditingIndex = theIndex;
272   }
273 }
274
275 void ParametersPlugin_WidgetParamsMgr::onCloseEditor(QWidget* theEditor, 
276                                                      QAbstractItemDelegate::EndEditHint theHint)
277 {
278   FeaturePtr aFeature = myParametersList.at(myEditingIndex.row());
279   QTreeWidgetItem* aItem = myParameters->child(myEditingIndex.row());
280   int aColumn = myEditingIndex.column();
281   QString aText = aItem->text(aColumn);
282   bool isModified = false;
283
284   switch (aColumn) {
285   case Col_Name:
286     {
287       AttributeStringPtr aStringAttr = aFeature->string(ParametersPlugin_Parameter::VARIABLE_ID());
288       if (!aText.isEmpty()) {
289         if (hasName(aText)) {
290           myMessage = tr("Name %1 already exists.").arg(aText);
291           aItem->setText(Col_Name, aStringAttr->value().c_str());
292           QTimer::singleShot(50, this, SLOT(sendWarning()));
293           return;
294         }
295         aStringAttr->setValue(aText.toStdString());
296         isModified = true;
297       } else {
298         aItem->setText(Col_Name, aStringAttr->value().c_str());
299       }
300     }
301     break;
302   case Col_Equation:
303     {
304       AttributeStringPtr aStringAttr = aFeature->string(ParametersPlugin_Parameter::EXPRESSION_ID());
305       if (!aText.isEmpty()) {
306         if (aText != aStringAttr->value().c_str()) {
307           aStringAttr->setValue(aText.toStdString());
308           isModified = true;
309         }
310       } else {
311         aItem->setText(Col_Equation, aStringAttr->value().c_str());
312       }
313     }
314     break;
315   case Col_Comment:
316     {
317       AttributeStringPtr aStringAttr = aFeature->string(ParametersPlugin_Parameter::COMMENT_ID());
318       aStringAttr->setValue(aText.toStdString());
319       isModified = true;
320     }
321     break;
322   }
323
324   if (!isModified)
325     return;
326   Events_Loop* aLoop = Events_Loop::loop();
327   aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
328
329   ResultParameterPtr aResult = 
330     std::dynamic_pointer_cast<ModelAPI_ResultParameter>(aFeature->firstResult());
331   if (aResult.get()) {
332     AttributeDoublePtr aValueAttribute = 
333       aResult->data()->real(ModelAPI_ResultParameter::VALUE());
334     aItem->setText(Col_Result, QString::number(aValueAttribute->value()));
335   }
336   myEditingIndex = QModelIndex();
337   updateFeaturesPart();
338 }
339
340 void ParametersPlugin_WidgetParamsMgr::updateFeaturesPart()
341 {
342   std::shared_ptr<ModelAPI_ResultParameter> aParam;
343   int i = 0;
344   foreach(FeaturePtr aFeature, myParametersList) {
345     aParam = std::dynamic_pointer_cast<ModelAPI_ResultParameter>(aFeature->firstResult());
346     const std::set<std::shared_ptr<ModelAPI_Attribute>>& aRefs = aParam->data()->refsToMe();
347     std::set<std::shared_ptr<ModelAPI_Attribute> >::const_iterator aIt;
348     for(aIt = aRefs.cbegin(); aIt != aRefs.cend(); aIt++) {
349       std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
350       FeaturePtr aReferenced = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
351       if (aReferenced.get()) {
352         QStringList aValNames;
353         aValNames << aReferenced->data()->name().c_str();
354
355         AttributeDoublePtr aDouble = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(aAttr);
356         if (aDouble.get()) {
357           aValNames << aDouble->text().c_str();
358           aValNames << QString::number(aDouble->value());
359         } else {
360           AttributeIntegerPtr aInt = std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(aAttr);
361           if (aInt.get()) {
362             aValNames << aInt->text().c_str();
363             aValNames << QString::number(aInt->value());
364           }
365         }
366
367         QTreeWidgetItem* aItem = myFeatures->child(i++);
368         for(int i = 0; i < aValNames.count(); i++)
369           aItem->setText(i, aValNames.at(i));
370       }
371     }
372   }
373 }
374
375 void ParametersPlugin_WidgetParamsMgr::onAdd()
376 {
377   SessionPtr aMgr = ModelAPI_Session::get();
378   std::shared_ptr<ModelAPI_Document> aDoc = aMgr->activeDocument();
379
380   FeaturePtr aFeature = aDoc->addFeature(ParametersPlugin_Parameter::ID());
381   if (!aFeature.get())
382     return;
383   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
384   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
385
386   QStringList aValues;
387   aValues << NoName;
388   aValues << NoValue;
389
390   QTreeWidgetItem* aItem = new QTreeWidgetItem(aValues);
391   aItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled);
392   myParameters->addChild(aItem);
393   myParametersList.append(aFeature);
394       
395   myTable->scrollToItem(aItem);
396 }
397
398 void ParametersPlugin_WidgetParamsMgr::onInsert()
399 {
400 }
401
402 void ParametersPlugin_WidgetParamsMgr::onRemove()
403 {
404 }
405
406 void ParametersPlugin_WidgetParamsMgr::onUp()
407 {
408 }
409
410 void ParametersPlugin_WidgetParamsMgr::onDown()
411 {
412 }
413
414
415 bool ParametersPlugin_WidgetParamsMgr::hasName(const QString& theName) const
416 {
417   foreach(FeaturePtr aFeature, myParametersList) {
418     if (aFeature->data()->name() == theName.toStdString())
419       return true;
420   }
421   return false;
422 }
423
424 void ParametersPlugin_WidgetParamsMgr::sendWarning()
425 {
426   QMessageBox::warning(this, tr("Warning"), myMessage);
427 }