Salome HOME
Exclude sub-features from history functionality
[modules/shaper.git] / src / PartSet / PartSet_PartDataModel.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 #include "PartSet_PartDataModel.h"
4 #include "PartSet_Module.h"
5 #include "PartSet_DocumentDataModel.h"
6
7 #include <ModelAPI_Session.h>
8 #include <ModelAPI_Document.h>
9 #include <ModelAPI_Feature.h>
10 #include <ModelAPI_Result.h>
11 #include <ModelAPI_Data.h>
12 #include <ModelAPI_AttributeDocRef.h>
13 #include <ModelAPI_Object.h>
14 #include <ModelAPI_ResultPart.h>
15 #include <ModelAPI_ResultConstruction.h>
16 #include <ModelAPI_ResultParameter.h>
17 #include <ModelAPI_ResultBody.h>
18 #include <ModelAPI_ResultGroup.h>
19 #include <ModelAPI_AttributeDouble.h>
20 #include <ModelAPI_Events.h>
21 #include <ModelAPI_Tools.h>
22
23 #include <Events_Loop.h>
24
25 #include <QIcon>
26 #include <QBrush>
27
28
29 PartSet_PartDataModel::PartSet_PartDataModel(QObject* theParent)
30     : PartSet_PartModel(theParent)
31 {
32 }
33
34 PartSet_PartDataModel::~PartSet_PartDataModel()
35 {
36 }
37
38 QVariant PartSet_PartDataModel::data(const QModelIndex& theIndex, int theRole) const
39 {
40   DocumentPtr aPartDoc = partDocument();
41   if (theIndex.column() == 1) {
42     DocumentPtr aActiveDoc = ModelAPI_Session::get()->activeDocument();
43     QModelIndex aParent = theIndex.parent();
44     if (aActiveDoc == aPartDoc) {
45       if (!aParent.isValid()) {
46         switch (theRole) {
47         case Qt::DecorationRole:
48           if (theIndex.row() == lastHistoryRow())
49             return QIcon(":pictures/arrow.png");
50         }
51       }
52     }
53     return QVariant();
54   }
55
56   if (theIndex.internalId() >= 0) {
57     ObjectPtr aObj = object(theIndex);
58     switch (theRole) {
59       case Qt::DisplayRole:
60         return aObj->data()->name().c_str();
61       case Qt::DecorationRole: 
62         {
63           FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
64           if (aFeature)
65             return PartSet_DocumentDataModel::featureIcon(aFeature);
66         }
67         break;
68       case Qt::ForegroundRole:
69         if (theIndex.internalId() > lastHistoryRow())
70           return QBrush(Qt::lightGray);
71         return QBrush(myItemsColor);
72     }
73   }
74
75   switch (theRole) {
76     case Qt::DisplayRole:
77       // return a name
78       switch (theIndex.internalId()) {
79         //case MyRoot: {
80         //  DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
81         //  ObjectPtr aObject = aRootDoc->object(ModelAPI_ResultPart::group(), myId);
82         //  if (aObject)
83         //    return std::dynamic_pointer_cast<ModelAPI_Object>(aObject)->data()->name().c_str();
84         //}
85         case ParamsFolder:
86           return tr("Parameters") + QString(" (%1)").arg(rowCount(theIndex));
87         case ConstructFolder:
88           return tr("Constructions") + QString(" (%1)").arg(rowCount(theIndex));
89         case BodiesFolder:
90           return tr("Bodies") + QString(" (%1)").arg(rowCount(theIndex));
91         case GroupsFolder:
92           return tr("Groups") + QString(" (%1)").arg(rowCount(theIndex));
93         case ParamObject: {
94           ObjectPtr aObject = aPartDoc->object(ModelAPI_ResultParameter::group(), theIndex.row());
95           if (aObject) {
96             ResultParameterPtr aParam = std::dynamic_pointer_cast<ModelAPI_ResultParameter>(aObject);
97             AttributeDoublePtr aValueAttribute = aParam->data()->real(ModelAPI_ResultParameter::VALUE());
98             QString aVal = QString::number(aValueAttribute->value());
99             QString aTitle = QString(aObject->data()->name().c_str());
100             return aTitle + " = " + aVal;
101           }
102         }
103           break;
104         case ConstructObject: {
105           ObjectPtr aObject = aPartDoc->object(ModelAPI_ResultConstruction::group(), theIndex.row());
106           if (aObject)
107             return std::dynamic_pointer_cast<ModelAPI_Object>(aObject)->data()->name().c_str();
108         }
109           break;
110         case BodiesObject: {
111           ObjectPtr aObject = aPartDoc->object(ModelAPI_ResultBody::group(), theIndex.row());
112           if (aObject)
113             return aObject->data()->name().c_str();
114         }
115           break;
116         case GroupObject: {
117           ObjectPtr aObject = aPartDoc->object(ModelAPI_ResultGroup::group(), theIndex.row());
118           if (aObject)
119             return aObject->data()->name().c_str();
120         }
121         case HistoryObject: {
122           ObjectPtr aObject = aPartDoc->object(ModelAPI_Feature::group(), theIndex.row() - getRowsNumber());
123           if (aObject)
124             return aObject->data()->name().c_str();
125         }
126       }
127       break;
128     case Qt::DecorationRole:
129       // return an Icon
130       switch (theIndex.internalId()) {
131         //case MyRoot:
132         //  return QIcon(":pictures/part_ico.png");
133         case ParamsFolder:
134           return QIcon(":pictures/params_folder.png");
135         case ConstructFolder:
136         case BodiesFolder:
137           return QIcon(":pictures/constr_folder.png");
138         case GroupsFolder:
139           return QIcon(":pictures/constr_folder.png");
140         case ConstructObject:
141         case GroupObject:
142         case BodiesObject: {
143           std::string aGroup = theIndex.internalId() == ConstructObject ?
144             ModelAPI_ResultConstruction::group() : ModelAPI_ResultBody::group();
145           ObjectPtr anObject = aPartDoc->object(aGroup, theIndex.row());
146           if (anObject && anObject->data() && 
147               anObject->data()->execState() == ModelAPI_StateMustBeUpdated) {
148             return QIcon(":pictures/constr_object_modified.png");
149           }
150           return QIcon(":pictures/constr_object.png");
151         }
152         case HistoryObject: {
153           ObjectPtr aObject = aPartDoc->object(ModelAPI_Feature::group(), theIndex.row() - getRowsNumber());
154           FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObject);
155           if (aFeature)
156             return PartSet_DocumentDataModel::featureIcon(aFeature);
157         }
158       }
159       break;
160     case Qt::ToolTipRole:
161       // return Tooltip
162       break;
163     case Qt::ForegroundRole:
164       if (theIndex.internalId() == HistoryObject) {
165         if (theIndex.row() > lastHistoryRow())
166           return QBrush(Qt::lightGray);
167       }
168       return QBrush(myItemsColor);
169   }
170   return QVariant();
171 }
172
173 QVariant PartSet_PartDataModel::headerData(int section, Qt::Orientation orientation, int role) const
174 {
175   return QVariant();
176 }
177
178 int PartSet_PartDataModel::rowCount(const QModelIndex& parent) const
179 {
180   if (!parent.isValid()) {
181     DocumentPtr aDoc = partDocument();
182     if (aDoc.get()) {
183       return getRowsNumber() + aDoc->size(ModelAPI_Feature::group());
184     } else 
185       return 0;
186   }
187   switch (parent.internalId()) {
188     case ParamsFolder:
189       return partDocument()->size(ModelAPI_ResultParameter::group());
190     case ConstructFolder:
191       return partDocument()->size(ModelAPI_ResultConstruction::group());
192     case BodiesFolder:
193       return partDocument()->size(ModelAPI_ResultBody::group());
194     case GroupsFolder:
195       return partDocument()->size(ModelAPI_ResultGroup::group());
196     case HistoryObject:
197       {
198         ObjectPtr aObj = object(parent);
199         CompositeFeaturePtr aCompFeature = 
200           std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aObj);
201         if (aCompFeature.get()) {
202           return aCompFeature->numberOfSubs(true);
203         }
204       }
205   }
206   return 0;
207 }
208
209 int PartSet_PartDataModel::columnCount(const QModelIndex &parent) const
210 {
211   return 2;
212 }
213
214 QModelIndex PartSet_PartDataModel::index(int theRow, int theColumn, const QModelIndex &theParent) const
215 {
216   if (!theParent.isValid()) {
217     switch (theRow) {
218       case 0:
219         return createIndex(theRow, theColumn, (qint32) ParamsFolder);
220       case 1:
221         return createIndex(theRow, theColumn, (qint32) ConstructFolder);
222       case 2:
223         return createIndex(theRow, theColumn, (qint32) BodiesFolder);
224       case 3:
225         {
226         int aSize = partDocument()->size(ModelAPI_ResultGroup::group());
227         if (aSize > 0)
228           return createIndex(theRow, theColumn, (qint32) GroupsFolder);
229         else
230           return createIndex(theRow, theColumn, (qint32) HistoryObject);
231         }
232       default:
233         return createIndex(theRow, theColumn, (qint32) HistoryObject);
234     }
235   } else {
236     int aId = (int) theParent.internalId();
237     switch (aId) {
238       case ParamsFolder:
239         return createIndex(theRow, theColumn, (qint32) ParamObject);
240       case ConstructFolder:
241         return createIndex(theRow, theColumn, (qint32) ConstructObject);
242       case BodiesFolder:
243         return createIndex(theRow, theColumn, (qint32) BodiesObject);
244       case GroupsFolder:
245         return createIndex(theRow, theColumn, (qint32) GroupObject);
246       case HistoryObject:
247         {
248           return createIndex(theRow, theColumn, (qint32) theParent.row());
249         }
250     }
251   }
252   return QModelIndex();
253 }
254
255 QModelIndex PartSet_PartDataModel::parent(const QModelIndex& theIndex) const
256 {
257   if (theIndex.internalId() >= 0) {
258     int aPRow = theIndex.internalId();
259     return createIndex(aPRow, 0, (qint32) HistoryObject);
260   }
261   switch (theIndex.internalId()) {
262     case ParamsFolder:
263     case ConstructFolder:
264     case BodiesFolder:
265     case GroupsFolder:
266     case HistoryObject:
267       return QModelIndex();
268
269     case ParamObject:
270       return createIndex(0, 0, (qint32) ParamsFolder);
271     case ConstructObject:
272       return createIndex(1, 0, (qint32) ConstructFolder);
273     case BodiesObject:
274       return createIndex(2, 0, (qint32) BodiesFolder);
275     case GroupObject:
276       return createIndex(3, 0, (qint32) GroupsFolder);
277   }
278   return QModelIndex();
279 }
280
281 bool PartSet_PartDataModel::hasChildren(const QModelIndex& theParent) const
282 {
283   return rowCount(theParent) > 0;
284 }
285
286 DocumentPtr PartSet_PartDataModel::partDocument() const
287 {
288   ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(myPart->firstResult()); 
289   if (aPart.get()) // this may be null is Part feature is disabled
290     return aPart->partDoc();
291   return DocumentPtr();
292 }
293
294 ObjectPtr PartSet_PartDataModel::object(const QModelIndex& theIndex) const
295 {
296   if (theIndex.internalId() >= 0) {
297     int aPRow = theIndex.internalId();
298     ObjectPtr aObj = 
299       partDocument()->object(ModelAPI_Feature::group(), aPRow - getRowsNumber());
300     CompositeFeaturePtr aCompFeature = 
301       std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aObj);
302     if (aCompFeature.get()) {
303       return aCompFeature->subFeature(theIndex.row(), true);
304     }
305     return ObjectPtr();
306   }
307   switch (theIndex.internalId()) {
308     case ParamsFolder:
309     case ConstructFolder:
310     case BodiesFolder:
311     case GroupsFolder:
312       return ObjectPtr();
313
314     case ParamObject:
315       return partDocument()->object(ModelAPI_ResultParameter::group(), theIndex.row());
316     case ConstructObject:
317       return partDocument()->object(ModelAPI_ResultConstruction::group(), theIndex.row());
318     case BodiesObject:
319       return partDocument()->object(ModelAPI_ResultBody::group(), theIndex.row());
320     case GroupObject:
321       return partDocument()->object(ModelAPI_ResultGroup::group(), theIndex.row());
322     case HistoryObject:
323       return partDocument()->object(ModelAPI_Feature::group(), theIndex.row() - getRowsNumber());
324   }
325   return ObjectPtr();
326 }
327
328 bool PartSet_PartDataModel::hasDocument(const DocumentPtr& theDoc) const
329 {
330   return (partDocument() == theDoc);
331 }
332
333 QModelIndex PartSet_PartDataModel::findParent(const ObjectPtr& theObject) const
334 {
335   return findGroup(theObject->groupName().c_str());
336 }
337
338 QModelIndex PartSet_PartDataModel::findGroup(const std::string& theGroup) const
339 {
340   if (theGroup == ModelAPI_ResultParameter::group())
341     return createIndex(0, 0, (qint32) ParamsFolder);
342   if (theGroup == ModelAPI_ResultConstruction::group())
343     return createIndex(1, 0, (qint32) ConstructFolder);
344   if (theGroup == ModelAPI_ResultBody::group())
345     return createIndex(2, 0, (qint32) BodiesFolder);
346   if (theGroup == ModelAPI_ResultGroup::group())
347     return createIndex(3, 0, (qint32) GroupsFolder);
348   return QModelIndex();
349 }
350
351 QModelIndex PartSet_PartDataModel::objectIndex(const ObjectPtr& theObject) const
352 {
353   QModelIndex aIndex;
354   if (theObject) {
355     if (part() == theObject)
356       return aIndex;
357
358     std::string aGroup = theObject->groupName();
359     DocumentPtr aDoc = theObject->document();
360     int aNb = aDoc->size(aGroup);
361     int aRow = -1;
362     for (int i = 0; i < aNb; i++) {
363       if (aDoc->object(aGroup, i) == theObject) {
364         aRow = i;
365         break;
366       }
367     }
368     if (aRow == -1)
369       return aIndex;
370     if (aGroup == ModelAPI_ResultParameter::group())
371       return createIndex(aRow, 0, (qint32) ParamObject);
372     else if (aGroup == ModelAPI_ResultConstruction::group())
373       return createIndex(aRow, 0, (qint32) ConstructObject);
374     else if (aGroup == ModelAPI_ResultBody::group())
375       return createIndex(aRow, 0, (qint32) BodiesObject);
376     else if (aGroup == ModelAPI_ResultGroup::group())
377       return createIndex(aRow, 0, (qint32) GroupObject);
378     else
379       return createIndex(aRow + getRowsNumber(), 0, (qint32) HistoryObject);
380   }
381   return aIndex;
382 }
383
384
385 int PartSet_PartDataModel::getRowsNumber() const
386 {
387   int aSize = partDocument()->size(ModelAPI_ResultGroup::group());
388   if (aSize == 0) // If there are no groups then do not show group folder
389     return 3;
390   return 4;
391 }
392
393 int PartSet_PartDataModel::lastHistoryRow() const
394 {
395   DocumentPtr aDoc = partDocument();
396   FeaturePtr aFeature = aDoc->currentFeature(true);
397   if (aFeature.get())
398     return getRowsNumber() + aDoc->index(aFeature);
399   else
400     return getRowsNumber() - 1;
401 }
402
403 void PartSet_PartDataModel::setLastHistoryItem(const QModelIndex& theIndex)
404 {
405   SessionPtr aMgr = ModelAPI_Session::get();
406   DocumentPtr aDoc = partDocument();
407   std::string aOpName = tr("History change").toStdString();
408   if (theIndex.internalId() == HistoryObject) {
409     ObjectPtr aObject = object(theIndex);
410     aMgr->startOperation(aOpName);
411     aDoc->setCurrentFeature(std::dynamic_pointer_cast<ModelAPI_Feature>(aObject), true);
412     aMgr->finishOperation();
413   } else {
414     aMgr->startOperation(aOpName);
415     aDoc->setCurrentFeature(FeaturePtr(), true);
416     aMgr->finishOperation();
417   }
418 }
419
420 QModelIndex PartSet_PartDataModel::lastHistoryItem() const
421 {
422   return index(lastHistoryRow(), 1);
423 }
424
425 Qt::ItemFlags PartSet_PartDataModel::flags(const QModelIndex& theIndex) const
426 {
427   // Disable sub-features at column 1
428   if ((theIndex.column() == 1)  && (theIndex.internalId() >= 0))
429     return 0;
430
431   Qt::ItemFlags aFlags = Qt::ItemIsSelectable;
432   if (object(theIndex)) {
433     aFlags |= Qt::ItemIsEditable;
434   }
435
436   if (theIndex.internalId() == HistoryObject) {
437     if (theIndex.row() <= lastHistoryRow() || (theIndex.column() == 1))
438       aFlags |= Qt::ItemIsEnabled;
439   } else
440     aFlags |= Qt::ItemIsEnabled;
441   return aFlags;
442 }