Salome HOME
Warning dialog before deletion shows directly dependent features and indirectly ones.
[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 #include <ModelAPI_Feature.h>
17
18 #include <Config_FeatureMessage.h>
19
20 #include <Events_Loop.h>
21 #include <Events_Error.h>
22
23 #include <QIcon>
24 #include <QBrush>
25
26 #define ACTIVE_COLOR QColor(0,72,140)
27 #define PASSIVE_COLOR Qt::black
28
29 /// Returns ResultPart object if the given object is a Part feature
30 /// Otherwise returns NULL
31 ResultPartPtr getPartResult(ModelAPI_Object* theObj)
32 {
33   ModelAPI_Feature* aFeature = dynamic_cast<ModelAPI_Feature*>(theObj);
34   if (aFeature) {
35     ResultPtr aRes = aFeature->firstResult();
36     if (aRes.get() && (aRes->groupName() == ModelAPI_ResultPart::group())) {
37       return std::dynamic_pointer_cast<ModelAPI_ResultPart>(aRes);
38     }
39   }
40   return ResultPartPtr();
41 }
42
43 /// Returns pointer on document if the given object is document object
44 ModelAPI_Document* getSubDocument(void* theObj)
45 {
46   ModelAPI_Document* aDoc = dynamic_cast<ModelAPI_Document*>((ModelAPI_Entity*)theObj);
47   return aDoc;
48 }
49
50
51
52
53 // Constructor *************************************************
54 XGUI_DataModel::XGUI_DataModel(QObject* theParent) : QAbstractItemModel(theParent)
55 {
56   myXMLReader.readAll();
57
58   Events_Loop* aLoop = Events_Loop::loop();
59   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
60   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
61 }
62
63 //******************************************************
64 void XGUI_DataModel::processEvent(const std::shared_ptr<Events_Message>& theMessage)
65 {
66   DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
67   std::string aRootType = myXMLReader.rootType();
68   std::string aSubType = myXMLReader.subType();
69   int aNbFolders = foldersCount();
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         // Check that new folders could appear
85         QStringList aNotEmptyFolders = listOfShowNotEmptyFolders();
86         foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
87           if ((aNotEmptyFolder.toStdString() == aObjType) && (aRootDoc->size(aObjType) == 1))
88             // Appears first object in folder which can not be shown empty
89             insertRow(myXMLReader.rootFolderId(aObjType));
90         }
91         // Insert new object
92         int aRow = aRootDoc->size(aObjType) - 1;
93         if (aObjType == aRootType) {
94           insertRow(aRow + aNbFolders + 1);
95         } else {
96           int aFolderId = myXMLReader.rootFolderId(aObjType);
97           if (aFolderId != -1) {
98             insertRow(aRow, createIndex(aFolderId, 0, -1));
99           }
100         } 
101       } else {
102         // Object created in sub-document
103         QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get());
104         if (aDocRoot.isValid()) {
105           // Check that new folders could appear
106           QStringList aNotEmptyFolders = listOfShowNotEmptyFolders(false);
107           foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
108             if ((aNotEmptyFolder.toStdString() == aObjType) && (aDoc->size(aObjType) == 1))
109               // Appears first object in folder which can not be shown empty
110               insertRow(myXMLReader.subFolderId(aObjType), aDocRoot);
111           }
112           int aRow = aDoc->size(aObjType) - 1;
113           int aNbSubFolders = foldersCount(aDoc.get());
114           if (aObjType == aSubType) {
115             // List of objects under document root
116             insertRow(aRow + aNbSubFolders, aDocRoot);
117           } else {
118             // List of objects under a folder
119             if (aRow != -1) {
120               int aFolderId = myXMLReader.subFolderId(aObjType);
121               if (aFolderId != -1) {
122                 insertRow(aRow, createIndex(aFolderId, 0, aDoc.get()));
123               }
124             }
125           }
126         } 
127 #ifdef _DEBUG
128         else {
129           Events_Error::send("Problem with Data Model definition of sub-document");
130         }
131 #endif
132       }
133     }
134     // Deleted object event ***********************
135   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
136     std::shared_ptr<ModelAPI_ObjectDeletedMessage> aUpdMsg =
137         std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
138     DocumentPtr aDoc = aUpdMsg->document();
139     std::set<std::string> aGroups = aUpdMsg->groups();
140     std::set<std::string>::const_iterator aIt;
141     for (aIt = aGroups.begin(); aIt != aGroups.end(); ++aIt) {
142       std::string aGroup = (*aIt);
143       if (aDoc == aRootDoc) {  // If root objects
144         int aRow = aRootDoc->size(aGroup);
145         if (aGroup == aRootType) {
146           removeRow(aRow + aNbFolders);
147         } else {
148           int aFolderId = myXMLReader.rootFolderId(aGroup);
149           if (aFolderId != -1) {
150             QModelIndex aFolderIndex = createIndex(aFolderId, 0, -1);
151             removeRow(aRow, aFolderIndex);
152           }
153         }
154         // Check that some folders could erased
155         QStringList aNotEmptyFolders = listOfShowNotEmptyFolders();
156         foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
157           if ((aNotEmptyFolder.toStdString() == aGroup) && (aRootDoc->size(aGroup) == 0))
158             // Appears first object in folder which can not be shown empty
159             removeRow(myXMLReader.rootFolderId(aGroup));
160         }
161       } else {
162         // Remove row for sub-document
163         QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get());
164         if (aDocRoot.isValid()) {
165           int aRow = aDoc->size(aGroup);
166           int aNbSubFolders = foldersCount(aDoc.get());
167           if (aGroup == aSubType) {
168             // List of objects under document root
169             removeRow(aRow + aNbSubFolders, aDocRoot);
170           } else {
171             // List of objects under a folder
172             int aFolderId = myXMLReader.subFolderId(aGroup);
173             if (aFolderId != -1) {
174               removeRow(aRow, createIndex(aFolderId, 0, aDoc.get()));
175             }
176           }
177           // Check that some folders could disappear
178           QStringList aNotEmptyFolders = listOfShowNotEmptyFolders(false);
179           foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
180             if ((aNotEmptyFolder.toStdString() == aGroup) && (aDoc->size(aGroup) == 1))
181               // Appears first object in folder which can not be shown empty
182               removeRow(myXMLReader.subFolderId(aGroup), aDocRoot);
183           }
184         } 
185 #ifdef _DEBUG
186         else {
187           Events_Error::send("Problem with Data Model definition of sub-document");
188         }
189 #endif
190       }
191     }
192   } 
193 }
194
195 //******************************************************
196 void XGUI_DataModel::clear()
197 {
198
199 }
200
201 //******************************************************
202 void XGUI_DataModel::rebuildDataTree()
203 {
204
205 }
206
207 //******************************************************
208 ObjectPtr XGUI_DataModel::object(const QModelIndex& theIndex) const
209 {
210   if (theIndex.internalId() < 0) // this is a folder
211     return ObjectPtr();
212   ModelAPI_Object* aObj = (ModelAPI_Object*)theIndex.internalPointer();
213   if (getSubDocument(aObj)) // the selected index is a folder of sub-document
214     return ObjectPtr();
215
216   // We can not create the ObjectPtr directly because the pointer will be deleted 
217   // with deletion of the ObjectPtr because its counter become to 0.
218   DocumentPtr aDoc = aObj->document();
219   std::string aType = aObj->groupName();
220
221   ObjectPtr aObjPtr;
222   for (int i = 0; i < aDoc->size(aType); i++) {
223     aObjPtr = aDoc->object(aType, i);
224     if (aObjPtr.get() == aObj)
225       return aObjPtr;
226   }
227   return ObjectPtr();
228 }
229
230 //******************************************************
231 QModelIndex XGUI_DataModel::objectIndex(const ObjectPtr theObject) const
232 {
233   std::string aType = theObject->groupName();
234   DocumentPtr aDoc = theObject->document();
235   int aRow = aDoc->index(theObject);
236   if (aRow == -1)
237     return QModelIndex();
238
239   SessionPtr aSession = ModelAPI_Session::get();
240   DocumentPtr aRootDoc = aSession->moduleDocument();
241   if (aDoc == aRootDoc && myXMLReader.rootType() == aType) { 
242     // The object from root document
243     aRow += foldersCount();
244   } else if (myXMLReader.subType() == aType) { 
245     // The object from sub document
246     aRow += foldersCount(aDoc.get());
247   }
248   return createIndex(aRow, 0, theObject.get());
249 }
250
251 //******************************************************
252 QVariant XGUI_DataModel::data(const QModelIndex& theIndex, int theRole) const
253 {
254   SessionPtr aSession = ModelAPI_Session::get();
255   DocumentPtr aRootDoc = aSession->moduleDocument();
256   int aNbFolders = foldersCount();
257   int theIndexRow = theIndex.row();
258
259   if ((theRole == Qt::DecorationRole) && (theIndex == lastHistoryIndex()))
260     return QIcon(":pictures/arrow.png");
261
262   if (theIndex.column() == 1)
263     return QVariant();
264
265   int aParentId = theIndex.internalId();
266   if (aParentId == -1) { // root folders
267     switch (theRole) {
268       case Qt::DisplayRole:
269         return QString(myXMLReader.rootFolderName(theIndexRow).c_str()) + 
270           QString(" (%1)").arg(rowCount(theIndex));
271       case Qt::DecorationRole:
272         return QIcon(myXMLReader.rootFolderIcon(theIndexRow).c_str());
273       case Qt::ForegroundRole:
274         if (aSession->activeDocument() == aRootDoc)
275           return QBrush(ACTIVE_COLOR);
276         else
277           return QBrush(PASSIVE_COLOR);
278     }
279   } else { // an object or sub-document
280     ModelAPI_Document* aSubDoc = getSubDocument(theIndex.internalPointer());
281
282     if (theRole == Qt::ForegroundRole) {
283       bool aIsActive = false;
284       if (aSubDoc)
285         aIsActive = (aSession->activeDocument().get() == aSubDoc);
286       else {
287         ModelAPI_Object* aObj = (ModelAPI_Object*)theIndex.internalPointer();
288         if (aObj->isDisabled())
289           return QBrush(Qt::lightGray);
290         aIsActive = (aSession->activeDocument() == aObj->document());
291       }
292       if (aIsActive)
293         return QBrush(ACTIVE_COLOR);
294       else
295         return QBrush(PASSIVE_COLOR);
296     }
297
298     if (aSubDoc) { // this is a folder of sub document
299       switch (theRole) {
300         case Qt::DisplayRole:
301           return QString(myXMLReader.subFolderName(theIndexRow).c_str()) + 
302             QString(" (%1)").arg(rowCount(theIndex));
303         case Qt::DecorationRole:
304           return QIcon(myXMLReader.subFolderIcon(theIndexRow).c_str());
305       }
306     } else {
307       ModelAPI_Object* aObj = (ModelAPI_Object*)theIndex.internalPointer();
308       switch (theRole) {
309       case Qt::DisplayRole:
310         if (aObj->groupName() == ModelAPI_ResultParameter::group()) {
311           ModelAPI_ResultParameter* aParam = dynamic_cast<ModelAPI_ResultParameter*>(aObj);
312           AttributeDoublePtr aValueAttribute = aParam->data()->real(ModelAPI_ResultParameter::VALUE());
313           QString aVal = QString::number(aValueAttribute->value());
314           QString aTitle = QString(aObj->data()->name().c_str());
315           return aTitle + " = " + aVal;
316         }
317         return aObj->data()->name().c_str();
318       case Qt::DecorationRole:
319         return ModuleBase_IconFactory::get()->getIcon(object(theIndex));
320       }
321     }
322   }
323   return QVariant();
324 }
325
326 //******************************************************
327 QVariant XGUI_DataModel::headerData(int theSection, Qt::Orientation theOrient, int theRole) const
328 {
329   return QVariant();
330 }
331
332 //******************************************************
333 int XGUI_DataModel::rowCount(const QModelIndex& theParent) const
334 {
335   SessionPtr aSession = ModelAPI_Session::get();
336   if (!aSession->hasModuleDocument())
337     return 0;
338   DocumentPtr aRootDoc = aSession->moduleDocument();
339
340   if (!theParent.isValid()) {
341     // Return number of items in root
342     int aNbFolders = foldersCount();
343     int aNbItems = 0;
344     std::string aType = myXMLReader.rootType();
345     if (!aType.empty())
346       aNbItems = aRootDoc->size(aType);
347     return aNbFolders + aNbItems;
348   }
349
350   int aId = theParent.internalId();
351   if (aId == -1) { 
352     // this is a folder under root
353     int aParentPos = theParent.row();
354     std::string aType = myXMLReader.rootFolderType(aParentPos);
355     //qDebug("### %s = %i\n", aType.c_str(), aRootDoc->size(aType));
356     return aRootDoc->size(aType);
357   } else {
358     // It is an object which could have children
359     ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
360     if (aDoc) { 
361       // a folder of sub-document
362       std::string aType = myXMLReader.subFolderType(theParent.row());
363       return aDoc->size(aType);
364     } else {
365       // Check for Part feature
366       ModelAPI_Object* aObj = (ModelAPI_Object*)theParent.internalPointer();
367       ResultPartPtr aPartRes = getPartResult(aObj);
368       if (aPartRes.get()) {
369         DocumentPtr aSubDoc = aPartRes->partDoc();
370         int aNbSubFolders = foldersCount(aSubDoc.get());
371         int aNbSubItems = 0;
372         std::string aSubType = myXMLReader.subType();
373         if (!aSubType.empty())
374           aNbSubItems = aSubDoc->size(aSubType);
375         return aNbSubItems + aNbSubFolders;
376       }
377     }
378   }
379   return 0;
380 }
381
382 //******************************************************
383 int XGUI_DataModel::columnCount(const QModelIndex& theParent) const
384 {
385   return 2;
386 }
387
388 //******************************************************
389 QModelIndex XGUI_DataModel::index(int theRow, int theColumn, const QModelIndex &theParent) const
390 {
391   SessionPtr aSession = ModelAPI_Session::get();
392   DocumentPtr aRootDoc = aSession->moduleDocument();
393   int aNbFolders = foldersCount();
394
395   if (!theParent.isValid()) {
396     if (theRow < aNbFolders) // Return first level folder index
397       return createIndex(theRow, theColumn, -1);
398     else { // return object under root index
399       std::string aType = myXMLReader.rootType();
400       int aObjId = theRow - aNbFolders;
401       if (aObjId < aRootDoc->size(aType)) {
402         ObjectPtr aObj = aRootDoc->object(aType, aObjId);
403         QModelIndex aIndex = objectIndex(aObj);
404         if (theColumn != 0)
405           return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
406         return aIndex;
407       }
408       return QModelIndex();
409     }
410   }
411   int aId = theParent.internalId();
412   int aParentPos = theParent.row();
413   if (aId == -1) { // return object index inside of first level of folders
414     std::string aType = myXMLReader.rootFolderType(aParentPos);
415     if (theRow < aRootDoc->size(aType)) {
416       ObjectPtr aObj = aRootDoc->object(aType, theRow);
417       QModelIndex aIndex = objectIndex(aObj);
418       if (theColumn != 0)
419         return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
420       return aIndex;
421     }
422   } else {
423     // It is an object which could have children
424     ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
425     if (aDoc) { 
426       // It is a folder of sub-document
427       std::string aType = myXMLReader.subFolderType(aParentPos);
428       if (theRow < aDoc->size(aType)) {
429         ObjectPtr aObj = aDoc->object(aType, theRow);
430         QModelIndex aIndex = objectIndex(aObj);
431         if (theColumn != 0)
432           return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
433         return aIndex;
434       }
435     } else {
436       ModelAPI_Object* aParentObj = (ModelAPI_Object*)theParent.internalPointer();
437
438       // Check for Part feature
439       ResultPartPtr aPartRes = getPartResult(aParentObj);
440       if (aPartRes.get()) {
441         DocumentPtr aSubDoc = aPartRes->partDoc();
442         int aNbSubFolders = foldersCount(aSubDoc.get());
443         if (theRow < aNbSubFolders) { // Create a Folder of sub-document
444           return createIndex(theRow, theColumn, aSubDoc.get());
445         } else {
446           // this is an object under sub document root
447           std::string aType = myXMLReader.subType();
448           ObjectPtr aObj = aSubDoc->object(aType, theRow - aNbSubFolders);
449           QModelIndex aIndex = objectIndex(aObj);
450           if (theColumn != 0)
451             return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
452           return aIndex;
453         }
454       }
455     }
456   }
457   return QModelIndex();
458 }
459
460 //******************************************************
461 QModelIndex XGUI_DataModel::parent(const QModelIndex& theIndex) const
462 {
463   int aId = theIndex.internalId();
464   if (aId != -1) { // The object is not a root folder
465     ModelAPI_Document* aDoc = getSubDocument(theIndex.internalPointer());
466     if (aDoc) { 
467       // It is a folder of sub-document
468       return findDocumentRootIndex(aDoc);
469     }
470     ModelAPI_Object* aObj = (ModelAPI_Object*) theIndex.internalPointer();
471     std::string aType = aObj->groupName();
472     SessionPtr aSession = ModelAPI_Session::get();
473     DocumentPtr aRootDoc = aSession->moduleDocument();
474     DocumentPtr aSubDoc = aObj->document();
475     if (aSubDoc == aRootDoc) {
476       if (aType == myXMLReader.rootType())
477         return QModelIndex();
478       else {
479         // return first level of folder index
480         int aFolderId = myXMLReader.rootFolderId(aType);
481         // Items in a one row must have the same parent
482         return createIndex(aFolderId, 0, -1);
483       }
484     } else {
485       if (aType == myXMLReader.subType())
486         return findDocumentRootIndex(aSubDoc.get());
487       else {
488         // return first level of folder index
489         int aFolderId = myXMLReader.subFolderId(aType);
490         // Items in a one row must have the same parent
491         return createIndex(aFolderId, 0, aSubDoc.get());
492       }
493     }
494   } 
495   return QModelIndex();
496 }
497
498 //******************************************************
499 bool XGUI_DataModel::hasChildren(const QModelIndex& theParent) const
500 {
501   if (!theParent.isValid()) {
502     int aNbFolders = foldersCount();
503     if (aNbFolders > 0)
504       return true;
505     SessionPtr aSession = ModelAPI_Session::get();
506     DocumentPtr aRootDoc = aSession->moduleDocument();
507     return aRootDoc->size(myXMLReader.rootType()) > 0;
508   }
509   if (theParent.internalId() == -1) {
510     std::string aType = myXMLReader.rootFolderType(theParent.row());
511     if (!aType.empty()) {
512       SessionPtr aSession = ModelAPI_Session::get();
513       DocumentPtr aRootDoc = aSession->moduleDocument();
514       return aRootDoc->size(aType) > 0;
515     }
516   } else {
517     ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
518     if (aDoc) { 
519       // a folder of sub-document
520       std::string aType = myXMLReader.subFolderType(theParent.row());
521       return aDoc->size(aType) > 0;
522     } else {
523       // Check that it could be an object with children
524       ModelAPI_Object* aObj = (ModelAPI_Object*)theParent.internalPointer();
525
526       // Check for Part feature
527       ResultPartPtr aPartRes = getPartResult(aObj);
528       if (aPartRes.get())
529         return true;
530     }
531   }
532   return false;
533 }
534
535 //******************************************************
536 bool XGUI_DataModel::insertRows(int theRow, int theCount, const QModelIndex& theParent)
537 {
538   beginInsertRows(theParent, theRow, theRow + theCount - 1);
539   endInsertRows();
540
541   return true;
542 }
543
544 //******************************************************
545 bool XGUI_DataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent)
546 {
547   beginRemoveRows(theParent, theRow, theRow + theCount - 1);
548   endRemoveRows();
549   return true;
550 }
551
552 //******************************************************
553 Qt::ItemFlags XGUI_DataModel::flags(const QModelIndex& theIndex) const
554 {
555   Qt::ItemFlags aFlags = Qt::ItemIsSelectable;
556
557   ModelAPI_Object* aObj = 0;
558   if (theIndex.internalId() != -1) {
559     if (!getSubDocument(theIndex.internalPointer()))
560       aObj = (ModelAPI_Object*) theIndex.internalPointer();
561   }
562   if (aObj) {
563     aFlags |= Qt::ItemIsEditable;
564   
565     if (!aObj->isDisabled())
566       aFlags |= Qt::ItemIsEnabled;
567   } else
568     aFlags |= Qt::ItemIsEnabled;
569   return aFlags;
570 }
571
572 //******************************************************
573 QModelIndex XGUI_DataModel::findDocumentRootIndex(const ModelAPI_Document* theDoc) const
574 {
575   SessionPtr aSession = ModelAPI_Session::get();
576   DocumentPtr aRootDoc = aSession->moduleDocument();
577   if (myXMLReader.isAttachToResult()) { // If document is attached to result
578     int aNb = aRootDoc->size(ModelAPI_ResultPart::group());
579     ObjectPtr aObj;
580     ResultPartPtr aPartRes;
581     for (int i = 0; i < aNb; i++) {
582       aObj = aRootDoc->object(ModelAPI_ResultPart::group(), i);
583       aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
584       if (aPartRes.get() && (aPartRes->partDoc().get() == theDoc)) {
585         int aRow = i;
586         if (myXMLReader.rootType() == ModelAPI_Feature::group())
587           aRow += foldersCount();
588         return createIndex(aRow, 0, aObj.get());
589       }
590     }
591   } else { // If document is attached to feature
592     int aNb = aRootDoc->size(ModelAPI_Feature::group());
593     ObjectPtr aObj;
594     ResultPartPtr aPartRes;
595     for (int i = 0; i < aNb; i++) {
596       aObj = aRootDoc->object(ModelAPI_Feature::group(), i);
597       aPartRes = getPartResult(aObj.get());
598       if (aPartRes.get() && (aPartRes->partDoc().get() == theDoc)) {
599         int aRow = i;
600         if (myXMLReader.rootType() == ModelAPI_Feature::group())
601           aRow += foldersCount();
602         return createIndex(aRow, 0, aObj.get());
603       }
604     }
605   }
606   return QModelIndex();
607 }
608
609 //******************************************************
610 QModelIndex XGUI_DataModel::documentRootIndex(DocumentPtr theDoc) const
611 {
612   SessionPtr aSession = ModelAPI_Session::get();
613   DocumentPtr aRootDoc = aSession->moduleDocument();
614   if (theDoc == aRootDoc)
615     return QModelIndex();
616   else 
617     return findDocumentRootIndex(theDoc.get());
618 }
619
620 //******************************************************
621 int XGUI_DataModel::foldersCount(ModelAPI_Document* theDoc) const
622 {
623   int aNb = 0;
624   SessionPtr aSession = ModelAPI_Session::get();
625   DocumentPtr aRootDoc = aSession->moduleDocument();
626   if ((theDoc == 0) || (theDoc == aRootDoc.get())) {
627     for (int i = 0; i < myXMLReader.rootFoldersNumber(); i++) {
628       if (myXMLReader.rootShowEmpty(i))
629         aNb++;
630       else {
631         if (aRootDoc->size(myXMLReader.rootFolderType(i)) > 0)
632           aNb++;
633       }
634     }
635   } else {
636     for (int i = 0; i < myXMLReader.subFoldersNumber(); i++) {
637       if (myXMLReader.subShowEmpty(i))
638         aNb++;
639       else {
640         if (theDoc->size(myXMLReader.subFolderType(i)) > 0)
641           aNb++;
642       }
643     }
644   }
645   return aNb;
646 }
647
648 //******************************************************
649 QStringList XGUI_DataModel::listOfShowNotEmptyFolders(bool fromRoot) const
650 {
651   QStringList aResult;
652   if (fromRoot) {
653     for (int i = 0; i < myXMLReader.rootFoldersNumber(); i++) {
654       if (!myXMLReader.rootShowEmpty(i))
655         aResult << myXMLReader.rootFolderType(i).c_str();
656     }
657   } else {
658     for (int i = 0; i < myXMLReader.subFoldersNumber(); i++) {
659       if (!myXMLReader.subShowEmpty(i))
660         aResult << myXMLReader.subFolderType(i).c_str();
661     }
662   }
663   return aResult;
664 }
665
666 //******************************************************
667 QModelIndex XGUI_DataModel::lastHistoryIndex() const
668 {
669   SessionPtr aSession = ModelAPI_Session::get();
670   DocumentPtr aCurDoc = aSession->activeDocument();
671   FeaturePtr aFeature = aCurDoc->currentFeature(true);
672   if (aFeature.get()) {
673     QModelIndex aInd = objectIndex(aFeature);
674     return createIndex(aInd.row(), 1, aInd.internalPointer());
675   } else {
676     if (aCurDoc == aSession->moduleDocument())
677       return createIndex(foldersCount() - 1, 1, -1);
678     else 
679       return createIndex(foldersCount(aCurDoc.get()) - 1, 1, aCurDoc.get());
680   }
681 }