]> SALOME platform Git repositories - modules/shaper.git/blob - src/XGUI/XGUI_DataModel.cpp
Salome HOME
Check the multi coincidence between different types of entities (issue #751)
[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       MYLastDeleted = theIndex;
510       return QModelIndex();
511     }
512     // Check is it object a sub-object of a complex object
513     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
514     if (aFeature.get()) {
515       CompositeFeaturePtr aCompFea = ModelAPI_Tools::compositeOwner(aFeature);
516       if (aCompFea.get()) {
517         return objectIndex(aCompFea);
518       }
519     }
520     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
521     if (aResult.get()) {
522       ResultCompSolidPtr aCompRes = ModelAPI_Tools::compSolidOwner(aResult);
523       if (aCompRes.get()) {
524         return objectIndex(aCompRes);
525       }
526     }
527     // Use as ordinary object
528     std::string aType = aObj->groupName();
529     SessionPtr aSession = ModelAPI_Session::get();
530     DocumentPtr aRootDoc = aSession->moduleDocument();
531     DocumentPtr aSubDoc = aObj->document();
532     if (aSubDoc == aRootDoc) {
533       if (aType == myXMLReader.rootType())
534         return QModelIndex();
535       else {
536         // return first level of folder index
537         int aFolderId = myXMLReader.rootFolderId(aType);
538         // Items in a one row must have the same parent
539         return createIndex(aFolderId, 0, -1);
540       }
541     } else {
542       if (aType == myXMLReader.subType())
543         return findDocumentRootIndex(aSubDoc.get());
544       else {
545         // return first level of folder index
546         int aFolderId = myXMLReader.subFolderId(aType);
547         // Items in a one row must have the same parent
548         return createIndex(aFolderId, 0, aSubDoc.get());
549       }
550     }
551   } 
552   return QModelIndex();
553 }
554
555 //******************************************************
556 bool XGUI_DataModel::hasChildren(const QModelIndex& theParent) const
557 {
558   if (!theParent.isValid()) {
559     int aNbFolders = foldersCount();
560     if (aNbFolders > 0)
561       return true;
562     SessionPtr aSession = ModelAPI_Session::get();
563     DocumentPtr aRootDoc = aSession->moduleDocument();
564     return aRootDoc->size(myXMLReader.rootType()) > 0;
565   }
566   if (theParent.internalId() == -1) {
567     std::string aType = myXMLReader.rootFolderType(theParent.row());
568     if (!aType.empty()) {
569       SessionPtr aSession = ModelAPI_Session::get();
570       DocumentPtr aRootDoc = aSession->moduleDocument();
571       return aRootDoc->size(aType) > 0;
572     }
573   } else {
574     ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
575     if (aDoc) { 
576       // a folder of sub-document
577       std::string aType = myXMLReader.subFolderType(theParent.row());
578       return aDoc->size(aType) > 0;
579     } else {
580       // Check that it could be an object with children
581       ModelAPI_Object* aObj = (ModelAPI_Object*)theParent.internalPointer();
582
583       // Check for Part feature
584       ResultPartPtr aPartRes = getPartResult(aObj);
585       if (aPartRes.get())
586         return true;
587       else {
588         // Check for composite object
589         ModelAPI_CompositeFeature* aCompFeature = dynamic_cast<ModelAPI_CompositeFeature*>(aObj);
590         if (aCompFeature) 
591           return aCompFeature->numberOfSubs(true) > 0;
592         ModelAPI_ResultCompSolid* aCompRes = dynamic_cast<ModelAPI_ResultCompSolid*>(aObj);
593         if (aCompRes) 
594           return aCompRes->numberOfSubs(true) > 0;
595       }
596     }
597   }
598   return false;
599 }
600
601 //******************************************************
602 bool XGUI_DataModel::insertRows(int theRow, int theCount, const QModelIndex& theParent)
603 {
604   beginInsertRows(theParent, theRow, theRow + theCount - 1);
605   endInsertRows();
606
607   return true;
608 }
609
610 //******************************************************
611 bool XGUI_DataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent)
612 {
613   beginRemoveRows(theParent, theRow, theRow + theCount - 1);
614   endRemoveRows();
615   return true;
616 }
617
618 //******************************************************
619 Qt::ItemFlags XGUI_DataModel::flags(const QModelIndex& theIndex) const
620 {
621   Qt::ItemFlags aFlags = Qt::ItemIsSelectable;
622
623   ModelAPI_Object* aObj = 0;
624   if (theIndex.internalId() != -1) {
625     if (!getSubDocument(theIndex.internalPointer()))
626       aObj = (ModelAPI_Object*) theIndex.internalPointer();
627   }
628   if (aObj) {
629     aFlags |= Qt::ItemIsEditable;
630   
631     if (!aObj->isDisabled())
632       aFlags |= Qt::ItemIsEnabled;
633   } else
634     aFlags |= Qt::ItemIsEnabled;
635   return aFlags;
636 }
637
638 //******************************************************
639 QModelIndex XGUI_DataModel::findDocumentRootIndex(const ModelAPI_Document* theDoc) const
640 {
641   SessionPtr aSession = ModelAPI_Session::get();
642   DocumentPtr aRootDoc = aSession->moduleDocument();
643   if (myXMLReader.isAttachToResult()) { // If document is attached to result
644     int aNb = aRootDoc->size(ModelAPI_ResultPart::group());
645     ObjectPtr aObj;
646     ResultPartPtr aPartRes;
647     for (int i = 0; i < aNb; i++) {
648       aObj = aRootDoc->object(ModelAPI_ResultPart::group(), i);
649       aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
650       if (aPartRes.get() && (aPartRes->partDoc().get() == theDoc)) {
651         int aRow = i;
652         if (myXMLReader.rootType() == ModelAPI_Feature::group())
653           aRow += foldersCount();
654         return createIndex(aRow, 0, aObj.get());
655       }
656     }
657   } else { // If document is attached to feature
658     int aNb = aRootDoc->size(ModelAPI_Feature::group());
659     ObjectPtr aObj;
660     ResultPartPtr aPartRes;
661     for (int i = 0; i < aNb; i++) {
662       aObj = aRootDoc->object(ModelAPI_Feature::group(), i);
663       aPartRes = getPartResult(aObj.get());
664       if (aPartRes.get() && (aPartRes->partDoc().get() == theDoc)) {
665         int aRow = i;
666         if (myXMLReader.rootType() == ModelAPI_Feature::group())
667           aRow += foldersCount();
668         return createIndex(aRow, 0, aObj.get());
669       }
670     }
671   }
672   return QModelIndex();
673 }
674
675 //******************************************************
676 QModelIndex XGUI_DataModel::documentRootIndex(DocumentPtr theDoc) const
677 {
678   SessionPtr aSession = ModelAPI_Session::get();
679   DocumentPtr aRootDoc = aSession->moduleDocument();
680   if (theDoc == aRootDoc)
681     return QModelIndex();
682   else 
683     return findDocumentRootIndex(theDoc.get());
684 }
685
686 //******************************************************
687 int XGUI_DataModel::foldersCount(ModelAPI_Document* theDoc) const
688 {
689   int aNb = 0;
690   SessionPtr aSession = ModelAPI_Session::get();
691   DocumentPtr aRootDoc = aSession->moduleDocument();
692   if ((theDoc == 0) || (theDoc == aRootDoc.get())) {
693     for (int i = 0; i < myXMLReader.rootFoldersNumber(); i++) {
694       if (myXMLReader.rootShowEmpty(i))
695         aNb++;
696       else {
697         if (aRootDoc->size(myXMLReader.rootFolderType(i)) > 0)
698           aNb++;
699       }
700     }
701   } else {
702     for (int i = 0; i < myXMLReader.subFoldersNumber(); i++) {
703       if (myXMLReader.subShowEmpty(i))
704         aNb++;
705       else {
706         if (theDoc->size(myXMLReader.subFolderType(i)) > 0)
707           aNb++;
708       }
709     }
710   }
711   return aNb;
712 }
713
714 //******************************************************
715 QStringList XGUI_DataModel::listOfShowNotEmptyFolders(bool fromRoot) const
716 {
717   QStringList aResult;
718   if (fromRoot) {
719     for (int i = 0; i < myXMLReader.rootFoldersNumber(); i++) {
720       if (!myXMLReader.rootShowEmpty(i))
721         aResult << myXMLReader.rootFolderType(i).c_str();
722     }
723   } else {
724     for (int i = 0; i < myXMLReader.subFoldersNumber(); i++) {
725       if (!myXMLReader.subShowEmpty(i))
726         aResult << myXMLReader.subFolderType(i).c_str();
727     }
728   }
729   return aResult;
730 }
731
732 //******************************************************
733 QModelIndex XGUI_DataModel::lastHistoryIndex() const
734 {
735   SessionPtr aSession = ModelAPI_Session::get();
736   DocumentPtr aCurDoc = aSession->activeDocument();
737   FeaturePtr aFeature = aCurDoc->currentFeature(true);
738   if (aFeature.get()) {
739     QModelIndex aInd = objectIndex(aFeature);
740     return createIndex(aInd.row(), 1, aInd.internalPointer());
741   } else {
742     if (aCurDoc == aSession->moduleDocument())
743       return createIndex(foldersCount() - 1, 1, -1);
744     else 
745       return createIndex(foldersCount(aCurDoc.get()) - 1, 1, aCurDoc.get());
746   }
747 }