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