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