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