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