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