Salome HOME
35cadb93c0fab97a8d1b51acd7794f83207f99cb
[modules/shaper.git] / src / XGUI / XGUI_DataModel.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        ModuleBase_IDocumentDataModel.cpp
4 // Created:     28 Apr 2015
5 // Author:      Vitaly SMETANNIKOV
6
7 #include "XGUI_DataModel.h"
8
9 #include <ModelAPI_Session.h>
10 #include <ModelAPI_Events.h>
11 #include <ModelAPI_ResultParameter.h>
12 #include <ModelAPI_AttributeDouble.h>
13 #include <ModelAPI_ResultPart.h>
14
15 #include <Config_FeatureMessage.h>
16
17 #include <Events_Loop.h>
18 #include <Events_Error.h>
19
20 #include <QIcon>
21
22 /// Returns ResultPart object if the given object is a Part feature
23 /// Otherwise returns NULL
24 ResultPartPtr getPartResult(ModelAPI_Object* theObj)
25 {
26   ModelAPI_Feature* aFeature = dynamic_cast<ModelAPI_Feature*>(theObj);
27   if (aFeature) {
28     ResultPtr aRes = aFeature->firstResult();
29     if (aRes.get() && (aRes->groupName() == ModelAPI_ResultPart::group())) {
30       return std::dynamic_pointer_cast<ModelAPI_ResultPart>(aRes);
31     }
32   }
33   return ResultPartPtr();
34 }
35
36 /// Returns pointer on document if the given object is document object
37 ModelAPI_Document* getSubDocument(void* theObj)
38 {
39   ModelAPI_Document* aDoc = dynamic_cast<ModelAPI_Document*>((ModelAPI_Entity*)theObj);
40   return aDoc;
41 }
42
43
44
45
46 // Constructor *************************************************
47 XGUI_DataModel::XGUI_DataModel(QObject* theParent) : QAbstractItemModel(theParent)
48 {
49   myXMLReader.readAll();
50
51   Events_Loop* aLoop = Events_Loop::loop();
52   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
53   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
54   aLoop->registerListener(this, Events_Loop::eventByName(Config_FeatureMessage::GUI_EVENT()));
55 }
56
57 //******************************************************
58 void XGUI_DataModel::processEvent(const std::shared_ptr<Events_Message>& theMessage)
59 {
60   DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
61   std::string aRootType = myXMLReader.rootType();
62   std::string aSubType = myXMLReader.subType();
63   int aNbFolders = myXMLReader.rootFoldersNumber();
64   int aNbSubFolders = myXMLReader.subFoldersNumber();
65
66   // Created object event *******************
67   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)) {
68     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
69         std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
70     std::set<ObjectPtr> aObjects = aUpdMsg->objects();
71
72     std::set<ObjectPtr>::const_iterator aIt;
73     std::string aObjType;
74     for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) {
75       ObjectPtr aObject = (*aIt);
76       aObjType = aObject->groupName();
77       DocumentPtr aDoc = aObject->document();
78       if (aDoc == aRootDoc) {
79         int aRow = aRootDoc->size(aObjType) - 1;
80         if (aObjType == aRootType) {
81           insertRow(aRow + aNbFolders);
82         } else {
83           int aFolderId = myXMLReader.rootFolderId(aObjType);
84           if (aFolderId != -1) {
85             insertRow(aRow, createIndex(aFolderId, 0, -1));
86           }
87         } 
88       } else {
89         // Object created in sub-document
90         QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get());
91         if (aDocRoot.isValid()) {
92           int aRow = aDoc->size(aObjType) - 1;
93           if (aObjType == aSubType) {
94             insertRow(aRow + aNbSubFolders, aDocRoot);
95           } else {
96             int aFolderId = myXMLReader.subFolderId(aObjType);
97             if (aFolderId != -1) {
98               insertRow(aRow, createIndex(aFolderId, 0, aDoc.get()));
99             }
100           }
101         } 
102 #ifdef _DEBUG
103         else {
104           Events_Error::send("Problem with Data Model definition of sub-document");
105         }
106 #endif
107       }
108     }
109     // Deleted object event ***********************
110   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
111     std::shared_ptr<ModelAPI_ObjectDeletedMessage> aUpdMsg =
112         std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
113     DocumentPtr aDoc = aUpdMsg->document();
114     std::set<std::string> aGroups = aUpdMsg->groups();
115     std::set<std::string>::const_iterator aIt;
116     for (aIt = aGroups.begin(); aIt != aGroups.end(); ++aIt) {
117       std::string aGroup = (*aIt);
118       if (aDoc == aRootDoc) {  // If root objects
119         int aRow = aRootDoc->size(aGroup);
120         if (aGroup == aRootType) {
121           removeRow(aRow + aNbFolders);
122         } else {
123           int aFolderId = myXMLReader.rootFolderId(aGroup);
124           if (aFolderId != -1) {
125             QModelIndex aFolderIndex = createIndex(aFolderId, 0, -1);
126             removeRow(aRow, aFolderIndex);
127           }
128         }
129       }
130     }
131   } 
132 }
133
134 //******************************************************
135 void XGUI_DataModel::clear()
136 {
137
138 }
139
140 //******************************************************
141 void XGUI_DataModel::rebuildDataTree()
142 {
143
144 }
145
146 //******************************************************
147 ObjectPtr XGUI_DataModel::object(const QModelIndex& theIndex) const
148 {
149   if (theIndex.internalId() < 0) // this is a folder
150     return ObjectPtr();
151   ModelAPI_Object* aObj = (ModelAPI_Object*)theIndex.internalPointer();
152   if (getSubDocument(aObj)) // the selected index is a folder of sub-document
153     return ObjectPtr();
154
155   // We can not create the ObjectPtr directly because the pointer will be deleted 
156   // with deletion of the ObjectPtr because its counter become to 0.
157   DocumentPtr aDoc = aObj->document();
158   std::string aType = aObj->groupName();
159
160   ObjectPtr aObjPtr;
161   for (int i = 0; i < aDoc->size(aType); i++) {
162     aObjPtr = aDoc->object(aType, i);
163     if (aObjPtr.get() == aObj)
164       return aObjPtr;
165   }
166   return ObjectPtr();
167 }
168
169 //******************************************************
170 QModelIndex XGUI_DataModel::objectIndex(const ObjectPtr theObject) const
171 {
172   std::string aType = theObject->groupName();
173   DocumentPtr aDoc = theObject->document();
174   int aRow = aDoc->index(theObject);
175   if (aRow == -1)
176     return QModelIndex();
177
178   SessionPtr aSession = ModelAPI_Session::get();
179   DocumentPtr aRootDoc = aSession->moduleDocument();
180   if (aDoc == aRootDoc && myXMLReader.rootType() == aType) { 
181     // The object from root document
182     aRow += myXMLReader.rootFoldersNumber();
183   } else if (myXMLReader.subType() == aType) { 
184     // The object from sub document
185     aRow += myXMLReader.subFoldersNumber();
186   }
187   return createIndex(aRow, 0, theObject.get());
188 }
189
190 //******************************************************
191 QVariant XGUI_DataModel::data(const QModelIndex& theIndex, int theRole) const
192 {
193   SessionPtr aSession = ModelAPI_Session::get();
194   DocumentPtr aRootDoc = aSession->moduleDocument();
195   int aNbFolders = myXMLReader.rootFoldersNumber();
196   int theIndexRow = theIndex.row();
197
198   if ((theIndex.column() == 1) ) {
199     //if (theIndexRow >= aNbFolders) {
200     //  if (theRole == Qt::DecorationRole) {
201     //    return QIcon(":pictures/arrow.png");
202     //  }
203     //}
204     return QVariant();
205   }
206
207   int aParentId = theIndex.internalId();
208   if (aParentId == -1) { // root folders
209     switch (theRole) {
210       case Qt::DisplayRole:
211         return QString(myXMLReader.rootFolderName(theIndexRow).c_str()) + 
212           QString(" (%1)").arg(rowCount(theIndex));
213       case Qt::DecorationRole:
214         return QIcon(myXMLReader.rootFolderIcon(theIndexRow).c_str());
215     }
216   } else {
217     ModelAPI_Document* aSubDoc = getSubDocument(theIndex.internalPointer());
218     if (aSubDoc) { // this is a folder of sub document
219       switch (theRole) {
220         case Qt::DisplayRole:
221           return QString(myXMLReader.subFolderName(theIndexRow).c_str()) + 
222             QString(" (%1)").arg(rowCount(theIndex));
223         case Qt::DecorationRole:
224           return QIcon(myXMLReader.subFolderIcon(theIndexRow).c_str());
225       }
226     } else {
227       ModelAPI_Object* aObj = (ModelAPI_Object*)theIndex.internalPointer();
228       switch (theRole) {
229       case Qt::DisplayRole:
230         if (aObj->groupName() == ModelAPI_ResultParameter::group()) {
231           ModelAPI_ResultParameter* aParam = dynamic_cast<ModelAPI_ResultParameter*>(aObj);
232           AttributeDoublePtr aValueAttribute = aParam->data()->real(ModelAPI_ResultParameter::VALUE());
233           QString aVal = QString::number(aValueAttribute->value());
234           QString aTitle = QString(aObj->data()->name().c_str());
235           return aTitle + " = " + aVal;
236         }
237         return aObj->data()->name().c_str();
238       }
239     }
240   }
241   return QVariant();
242 }
243
244 //******************************************************
245 QVariant XGUI_DataModel::headerData(int theSection, Qt::Orientation theOrient, int theRole) const
246 {
247   return QVariant();
248 }
249
250 //******************************************************
251 int XGUI_DataModel::rowCount(const QModelIndex& theParent) const
252 {
253   SessionPtr aSession = ModelAPI_Session::get();
254   if (!aSession->hasModuleDocument())
255     return 0;
256   DocumentPtr aRootDoc = aSession->moduleDocument();
257
258   if (!theParent.isValid()) {
259     // Return number of items in root
260     int aNbFolders = myXMLReader.rootFoldersNumber();
261     int aNbItems = 0;
262     std::string aType = myXMLReader.rootType();
263     if (!aType.empty())
264       aNbItems = aRootDoc->size(aType);
265     return aNbFolders + aNbItems;
266   }
267
268   int aId = theParent.internalId();
269   if (aId == -1) { 
270     // this is a folder under root
271     int aParentPos = theParent.row();
272     if (aId == -1) { // first level of folders
273       std::string aType = myXMLReader.rootFolderType(aParentPos);
274       return aRootDoc->size(aType);
275     }
276   } else {
277     // It is an object which could have children
278     ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
279     if (aDoc) { 
280       // a folder of sub-document
281       std::string aType = myXMLReader.subFolderType(theParent.row());
282       return aDoc->size(aType);
283     } else {
284       // Check for Part feature
285       ModelAPI_Object* aObj = (ModelAPI_Object*)theParent.internalPointer();
286       ResultPartPtr aPartRes = getPartResult(aObj);
287       if (aPartRes.get()) {
288         DocumentPtr aSubDoc = aPartRes->partDoc();
289         int aNbSubFolders = myXMLReader.subFoldersNumber();
290         int aNbSubItems = 0;
291         std::string aSubType = myXMLReader.subType();
292         if (!aSubType.empty())
293           aNbSubItems = aSubDoc->size(aSubType);
294         return aNbSubItems + aNbSubFolders;
295       }
296     }
297   }
298   return 0;
299 }
300
301 //******************************************************
302 int XGUI_DataModel::columnCount(const QModelIndex& theParent) const
303 {
304   return 2;
305 }
306
307 //******************************************************
308 QModelIndex XGUI_DataModel::index(int theRow, int theColumn, const QModelIndex &theParent) const
309 {
310   SessionPtr aSession = ModelAPI_Session::get();
311   DocumentPtr aRootDoc = aSession->moduleDocument();
312   int aNbFolders = myXMLReader.rootFoldersNumber();
313
314   if (!theParent.isValid()) {
315     if (theRow < aNbFolders) // Return first level folder index
316       return createIndex(theRow, theColumn, -1);
317     else { // return object under root index
318       std::string aType = myXMLReader.rootType();
319       int aObjId = theRow - aNbFolders;
320       if (aObjId < aRootDoc->size(aType)) {
321         ObjectPtr aObj = aRootDoc->object(aType, aObjId);
322         QModelIndex aIndex = objectIndex(aObj);
323         if (theColumn != 0)
324           return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
325         return aIndex;
326       }
327       return QModelIndex();
328     }
329   }
330   int aId = theParent.internalId();
331   int aParentPos = theParent.row();
332   if (aId == -1) { // return object index inside of first level of folders
333     std::string aType = myXMLReader.rootFolderType(aParentPos);
334     if (theRow < aRootDoc->size(aType)) {
335       ObjectPtr aObj = aRootDoc->object(aType, theRow);
336       QModelIndex aIndex = objectIndex(aObj);
337       if (theColumn != 0)
338         return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
339       return aIndex;
340     }
341   } else {
342     // It is an object which could have children
343     ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
344     if (aDoc) { 
345       // It is a folder of sub-document
346       std::string aType = myXMLReader.subFolderType(aParentPos);
347       if (theRow < aDoc->size(aType)) {
348         ObjectPtr aObj = aDoc->object(aType, theRow);
349         QModelIndex aIndex = objectIndex(aObj);
350         if (theColumn != 0)
351           return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
352         return aIndex;
353       }
354     } else {
355       ModelAPI_Object* aParentObj = (ModelAPI_Object*)theParent.internalPointer();
356
357       // Check for Part feature
358       ResultPartPtr aPartRes = getPartResult(aParentObj);
359       if (aPartRes.get()) {
360         DocumentPtr aSubDoc = aPartRes->partDoc();
361         int aNbSubFolders = myXMLReader.subFoldersNumber();
362         if (theRow < aNbSubFolders) { // Create a Folder of sub-document
363           return createIndex(theRow, theColumn, aSubDoc.get());
364         } else {
365           // this is an object under sub document root
366           std::string aType = myXMLReader.subType();
367           ObjectPtr aObj = aSubDoc->object(aType, theRow - aNbSubFolders);
368           QModelIndex aIndex = objectIndex(aObj);
369           if (theColumn != 0)
370             return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
371           return aIndex;
372         }
373       }
374     }
375   }
376   return QModelIndex();
377 }
378
379 //******************************************************
380 QModelIndex XGUI_DataModel::parent(const QModelIndex& theIndex) const
381 {
382   int aId = theIndex.internalId();
383   if (aId != -1) { // The object is not a root folder
384     ModelAPI_Document* aDoc = getSubDocument(theIndex.internalPointer());
385     if (aDoc) { 
386       // It is a folder of sub-document
387       return findDocumentRootIndex(aDoc);
388     }
389     ModelAPI_Object* aObj = (ModelAPI_Object*) theIndex.internalPointer();
390     std::string aType = aObj->groupName();
391     SessionPtr aSession = ModelAPI_Session::get();
392     DocumentPtr aRootDoc = aSession->moduleDocument();
393     DocumentPtr aSubDoc = aObj->document();
394     if (aSubDoc == aRootDoc) {
395       if (aType == myXMLReader.rootType())
396         return QModelIndex();
397       else {
398         // return first level of folder index
399         int aFolderId = myXMLReader.rootFolderId(aType);
400         // Items in a one row must have the same parent
401         return createIndex(aFolderId, 0, -1);
402       }
403     } else {
404       if (aType == myXMLReader.subType())
405         return findDocumentRootIndex(aSubDoc.get());
406       else {
407         // return first level of folder index
408         int aFolderId = myXMLReader.subFolderId(aType);
409         // Items in a one row must have the same parent
410         return createIndex(aFolderId, 0, aSubDoc.get());
411       }
412     }
413   } 
414   return QModelIndex();
415 }
416
417 //******************************************************
418 bool XGUI_DataModel::hasChildren(const QModelIndex& theParent) const
419 {
420   int aNbFolders = myXMLReader.rootFoldersNumber();
421   if (!theParent.isValid() && aNbFolders)
422     return true;
423   if (theParent.internalId() == -1) {
424     std::string aType = myXMLReader.rootFolderType(theParent.row());
425     if (!aType.empty()) {
426       SessionPtr aSession = ModelAPI_Session::get();
427       DocumentPtr aRootDoc = aSession->moduleDocument();
428       return aRootDoc->size(aType) > 0;
429     }
430   } else {
431     ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
432     if (aDoc) { 
433       // a folder of sub-document
434       std::string aType = myXMLReader.subFolderType(theParent.row());
435       return aDoc->size(aType) > 0;
436     } else {
437       // Check that it could be an object with children
438       ModelAPI_Object* aObj = (ModelAPI_Object*)theParent.internalPointer();
439
440       // Check for Part feature
441       ResultPartPtr aPartRes = getPartResult(aObj);
442       if (aPartRes.get())
443         return true;
444     }
445   }
446   return false;
447 }
448
449 //******************************************************
450 bool XGUI_DataModel::insertRows(int theRow, int theCount, const QModelIndex& theParent)
451 {
452   beginInsertRows(theParent, theRow, theRow + theCount - 1);
453   endInsertRows();
454
455   return true;
456 }
457
458 //******************************************************
459 bool XGUI_DataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent)
460 {
461   beginRemoveRows(theParent, theRow, theRow + theCount - 1);
462   endRemoveRows();
463   return true;
464 }
465
466 //******************************************************
467 Qt::ItemFlags XGUI_DataModel::flags(const QModelIndex& theIndex) const
468 {
469   Qt::ItemFlags aFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
470   if (theIndex.internalId() > -1) {
471     aFlags |= Qt::ItemIsEditable;
472   }
473   return aFlags;
474 }
475
476 //******************************************************
477 QModelIndex XGUI_DataModel::findDocumentRootIndex(ModelAPI_Document* theDoc) const
478 {
479   SessionPtr aSession = ModelAPI_Session::get();
480   DocumentPtr aRootDoc = aSession->moduleDocument();
481   if (myXMLReader.isAttachToResult()) { // If document is attached to result
482     int aNb = aRootDoc->size(ModelAPI_ResultPart::group());
483     ObjectPtr aObj;
484     ResultPartPtr aPartRes;
485     for (int i = 0; i < aNb; i++) {
486       aObj = aRootDoc->object(ModelAPI_ResultPart::group(), i);
487       aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
488       if (aPartRes.get() && (aPartRes->partDoc().get() == theDoc)) {
489         int aRow = i;
490         if (myXMLReader.rootType() == ModelAPI_Feature::group())
491           aRow += myXMLReader.rootFoldersNumber();
492         return createIndex(aRow, 0, aObj.get());
493       }
494     }
495   } else { // If document is attached to feature
496     int aNb = aRootDoc->size(ModelAPI_Feature::group());
497     ObjectPtr aObj;
498     ResultPartPtr aPartRes;
499     for (int i = 0; i < aNb; i++) {
500       aObj = aRootDoc->object(ModelAPI_Feature::group(), i);
501       aPartRes = getPartResult(aObj.get());
502       if (aPartRes.get() && (aPartRes->partDoc().get() == theDoc)) {
503         int aRow = i;
504         if (myXMLReader.rootType() == ModelAPI_Feature::group())
505           aRow += myXMLReader.rootFoldersNumber();
506         return createIndex(aRow, 0, aObj.get());
507       }
508     }
509   }
510   return QModelIndex();
511 }