Salome HOME
#1404 Random crash with Shaper: AIS presentations: operation prs, result sketch prs...
[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> 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       if (aObject->data()->isValid()) {
234         QModelIndex aIndex = objectIndex(aObject);
235         if (aIndex.isValid())
236           emit dataChanged(aIndex, aIndex);
237       } else {
238         rebuildDataTree();
239         break;
240       }
241     }
242   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_ORDER_UPDATED)) {
243     std::shared_ptr<ModelAPI_OrderUpdatedMessage> aUpdMsg =
244         std::dynamic_pointer_cast<ModelAPI_OrderUpdatedMessage>(theMessage);
245     DocumentPtr aDoc = aUpdMsg->document();
246     std::string aGroup = aUpdMsg->group();
247
248     QModelIndex aParent;
249     int aStartId = 0;
250     if (aDoc == aRootDoc) {
251       // Update a group under root
252       if (aGroup == myXMLReader->rootType()) // Update objects under root
253         aStartId = foldersCount();
254       else // Update objects in folder under root 
255         aParent = createIndex(folderId(aGroup), 0, -1);
256     } else {
257       // Update a sub-document
258       if (aGroup == myXMLReader->subType()) {
259         // Update sub-document root
260         aParent = findDocumentRootIndex(aDoc.get());
261         aStartId = foldersCount(aDoc.get());
262       } else 
263         // update folder in sub-document
264         aParent = createIndex(folderId(aGroup, aDoc.get()), 0, aDoc.get());
265     }
266     int aChildNb = rowCount(aParent);
267     rebuildBranch(aStartId, aChildNb - aStartId, aParent);
268   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_DOCUMENT_CHANGED)) {
269     DocumentPtr aDoc = ModelAPI_Session::get()->activeDocument();
270     if (aDoc != aRootDoc) {
271       QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get());
272       if (aDocRoot.isValid())
273         emit dataChanged(aDocRoot, aDocRoot);
274       else 
275         // We have got a new document
276         rebuildDataTree();
277     }
278   } 
279 }
280
281 //******************************************************
282 void XGUI_DataModel::clear()
283 {
284
285 }
286
287 //******************************************************
288 void XGUI_DataModel::rebuildDataTree()
289 {
290   beginResetModel();
291   endResetModel();
292   emit treeRebuilt();
293 }
294
295 //******************************************************
296 ObjectPtr XGUI_DataModel::object(const QModelIndex& theIndex) const
297 {
298   if (theIndex.internalId() < 0) // this is a folder
299     return ObjectPtr();
300   ModelAPI_Object* aObj = (ModelAPI_Object*)theIndex.internalPointer();
301   if (getSubDocument(aObj)) // the selected index is a folder of sub-document
302     return ObjectPtr();
303
304   return aObj->data()->owner();
305 }
306
307 //******************************************************
308 QModelIndex XGUI_DataModel::objectIndex(const ObjectPtr theObject) const
309 {
310   std::string aType = theObject->groupName();
311   DocumentPtr aDoc = theObject->document();
312   int aRow = aDoc->index(theObject);
313   if (aRow == -1) {
314     // it could be a part of complex object
315     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
316     if (aFeature.get()) {
317       CompositeFeaturePtr aCompFea = ModelAPI_Tools::compositeOwner(aFeature);
318       if (aCompFea.get()) {
319         for (int i = 0; i < aCompFea->numberOfSubs(true); i++) {
320           if (aCompFea->subFeature(i, true) == theObject) {
321             aRow = i;
322             break;
323           }
324         }
325       }
326     } else {
327       ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
328       if (aResult.get()) {
329         ResultCompSolidPtr aCompRes = ModelAPI_Tools::compSolidOwner(aResult);
330         if (aCompRes.get()) {
331           for (int i = 0; i < aCompRes->numberOfSubs(true); i++) {
332             if (aCompRes->subResult(i, true) == theObject) {
333               aRow = i;
334               break;
335             }
336           }
337         }
338       }
339     }
340     if (aRow == -1)
341       return QModelIndex();
342     else 
343       return createIndex(aRow, 0, theObject.get());
344   }
345   SessionPtr aSession = ModelAPI_Session::get();
346   DocumentPtr aRootDoc = aSession->moduleDocument();
347   if (aDoc == aRootDoc && myXMLReader->rootType() == aType) { 
348     // The object from root document
349     aRow += foldersCount();
350   } else if (myXMLReader->subType() == aType) { 
351     // The object from sub document
352     aRow += foldersCount(aDoc.get());
353   }
354   return createIndex(aRow, 0, theObject.get());
355 }
356
357 //******************************************************
358 QVariant XGUI_DataModel::data(const QModelIndex& theIndex, int theRole) const
359 {
360   SessionPtr aSession = ModelAPI_Session::get();
361   DocumentPtr aRootDoc = aSession->moduleDocument();
362   int aNbFolders = foldersCount();
363   int theIndexRow = theIndex.row();
364
365   if ((theRole == Qt::DecorationRole) && (theIndex == lastHistoryIndex()))
366     return QIcon(":pictures/arrow.png");
367
368   if (theIndex.column() == 1)
369     return QVariant();
370
371   int aParentId = theIndex.internalId();
372   if (aParentId == -1) { // root folders
373     switch (theRole) {
374       case Qt::DisplayRole:
375         return QString(myXMLReader->rootFolderName(theIndexRow).c_str()) + 
376           QString(" (%1)").arg(rowCount(theIndex));
377       case Qt::DecorationRole:
378         return QIcon(myXMLReader->rootFolderIcon(theIndexRow).c_str());
379       case Qt::ForegroundRole:
380         {
381           Qt::ItemFlags aFlags = theIndex.flags();
382           if (aFlags == Qt::ItemFlags())
383             return QBrush(DISABLED_COLOR);
384           if (!aFlags.testFlag(Qt::ItemIsEditable))
385             return QBrush(SELECTABLE_COLOR);
386         }
387         return ACTIVE_COLOR;
388     }
389   } else { // an object or sub-document
390     if (theRole == Qt::ForegroundRole) {
391       Qt::ItemFlags aFlags = theIndex.flags();
392       if (aFlags == Qt::ItemFlags())
393         return QBrush(DISABLED_COLOR);
394       if (!aFlags.testFlag(Qt::ItemIsEditable))
395         return QBrush(SELECTABLE_COLOR);
396       return ACTIVE_COLOR;
397     }
398
399     ModelAPI_Document* aSubDoc = getSubDocument(theIndex.internalPointer());
400     if (aSubDoc) { // this is a folder of sub document
401       QIntList aMissedIdx = missedFolderIndexes(aSubDoc);
402       int aRow = theIndexRow;
403       while (aMissedIdx.contains(aRow)) 
404         aRow++;
405
406       switch (theRole) {
407         case Qt::DisplayRole:
408           return QString(myXMLReader->subFolderName(aRow).c_str()) + 
409             QString(" (%1)").arg(rowCount(theIndex));
410         case Qt::DecorationRole:
411           return QIcon(myXMLReader->subFolderIcon(aRow).c_str());
412       }
413     } else {
414       ModelAPI_Object* aObj = (ModelAPI_Object*)theIndex.internalPointer();
415       switch (theRole) {
416       case Qt::DisplayRole:
417         {
418           if (aObj->groupName() == ModelAPI_ResultParameter::group()) {
419             ModelAPI_ResultParameter* aParam = dynamic_cast<ModelAPI_ResultParameter*>(aObj);
420             AttributeDoublePtr aValueAttribute = aParam->data()->real(ModelAPI_ResultParameter::VALUE());
421             QString aVal = QString::number(aValueAttribute->value());
422             QString aTitle = QString(aObj->data()->name().c_str());
423             return aTitle + " = " + aVal;
424           }
425           QString aSuffix;
426           if (aObj->groupName() == myXMLReader->subType()) {
427             ResultPartPtr aPartRes = getPartResult(aObj);
428             if (aPartRes.get()) {
429               if (aPartRes->partDoc().get() == NULL)
430                 aSuffix = " (Not loaded)";
431             }
432           }
433           return aObj->data()->name().c_str() + aSuffix;
434         }
435       case Qt::DecorationRole:
436         return ModuleBase_IconFactory::get()->getIcon(object(theIndex));
437       }
438     }
439   }
440   return QVariant();
441 }
442
443 //******************************************************
444 QVariant XGUI_DataModel::headerData(int theSection, Qt::Orientation theOrient, int theRole) const
445 {
446   return QVariant();
447 }
448
449 //******************************************************
450 int XGUI_DataModel::rowCount(const QModelIndex& theParent) const
451 {
452   SessionPtr aSession = ModelAPI_Session::get();
453   if (!aSession->hasModuleDocument())
454     return 0;
455   DocumentPtr aRootDoc = aSession->moduleDocument();
456
457   if (!theParent.isValid()) {
458     // Return number of items in root
459     int aNbFolders = foldersCount();
460     int aNbItems = 0;
461     std::string aType = myXMLReader->rootType();
462     if (!aType.empty())
463       aNbItems = aRootDoc->size(aType);
464     return aNbFolders + aNbItems;
465   }
466
467   int aId = theParent.internalId();
468   if (aId == -1) { 
469     // this is a folder under root
470     int aParentPos = theParent.row();
471     std::string aType = myXMLReader->rootFolderType(aParentPos);
472     return aRootDoc->size(aType);
473   } else {
474     // It is an object which could have children
475     ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
476     if (aDoc) { 
477       // a folder of sub-document
478       QIntList aMissedIdx = missedFolderIndexes(aDoc);
479       int aRow = theParent.row();
480       while (aMissedIdx.contains(aRow)) 
481         aRow++;
482       std::string aType = myXMLReader->subFolderType(aRow);
483       return aDoc->size(aType);
484     } else {
485       ModelAPI_Object* aObj = (ModelAPI_Object*)theParent.internalPointer();
486       // Check for Part feature
487       ResultPartPtr aPartRes = getPartResult(aObj);
488       if (aPartRes.get()) {
489         DocumentPtr aSubDoc = aPartRes->partDoc();
490         if (!aSubDoc.get())
491           return 0;
492
493         int aNbSubFolders = foldersCount(aSubDoc.get());
494         int aNbSubItems = 0;
495         std::string aSubType = myXMLReader->subType();
496         if (!aSubType.empty())
497           aNbSubItems = aSubDoc->size(aSubType);
498         return aNbSubItems + aNbSubFolders;
499       } else {
500         // Check for composite object
501         ModelAPI_CompositeFeature* aCompFeature = dynamic_cast<ModelAPI_CompositeFeature*>(aObj);
502         if (aCompFeature) 
503           return aCompFeature->numberOfSubs(true);
504         ModelAPI_ResultCompSolid* aCompRes = dynamic_cast<ModelAPI_ResultCompSolid*>(aObj);
505         if (aCompRes) 
506           return aCompRes->numberOfSubs(true);
507       }
508     }
509   }
510   return 0;
511 }
512
513 //******************************************************
514 int XGUI_DataModel::columnCount(const QModelIndex& theParent) const
515 {
516   return 2;
517 }
518
519 //******************************************************
520 QModelIndex XGUI_DataModel::index(int theRow, int theColumn, const QModelIndex &theParent) const
521 {
522   SessionPtr aSession = ModelAPI_Session::get();
523   DocumentPtr aRootDoc = aSession->moduleDocument();
524   int aNbFolders = foldersCount();
525
526   QModelIndex aIndex;
527
528   if (!theParent.isValid()) {
529     if (theRow < aNbFolders) // Return first level folder index
530       return createIndex(theRow, theColumn, -1);
531     else { // return object under root index
532       std::string aType = myXMLReader->rootType();
533       int aObjId = theRow - aNbFolders;
534       if (aObjId < aRootDoc->size(aType)) {
535         ObjectPtr aObj = aRootDoc->object(aType, aObjId);
536         aIndex = objectIndex(aObj);
537       }
538     }
539   } else {
540     int aId = theParent.internalId();
541     int aParentPos = theParent.row();
542     if (aId == -1) { // return object index inside of first level of folders
543       std::string aType = myXMLReader->rootFolderType(aParentPos);
544       if (theRow < aRootDoc->size(aType)) {
545         ObjectPtr aObj = aRootDoc->object(aType, theRow);
546         aIndex = objectIndex(aObj);
547       }
548     } else {
549       // It is an object which could have children
550       ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
551       if (aDoc) { 
552         // It is a folder of sub-document
553         int aParentRow = aParentPos;
554         QIntList aMissedIdx = missedFolderIndexes(aDoc);
555         while (aMissedIdx.contains(aParentRow))
556           aParentRow++;
557         std::string aType = myXMLReader->subFolderType(aParentRow);
558         if (theRow < aDoc->size(aType)) {
559           ObjectPtr aObj = aDoc->object(aType, theRow);
560           aIndex = objectIndex(aObj);
561         }
562       } else {
563         ModelAPI_Object* aParentObj = (ModelAPI_Object*)theParent.internalPointer();
564
565         // Check for Part feature
566         ResultPartPtr aPartRes = getPartResult(aParentObj);
567         if (aPartRes.get()) {
568           DocumentPtr aSubDoc = aPartRes->partDoc();
569           int aNbSubFolders = foldersCount(aSubDoc.get());
570           if (theRow < aNbSubFolders) { // Create a Folder of sub-document
571             aIndex = createIndex(theRow, theColumn, aSubDoc.get());
572           } else {
573             // this is an object under sub document root
574             std::string aType = myXMLReader->subType();
575             ObjectPtr aObj = aSubDoc->object(aType, theRow - aNbSubFolders);
576             aIndex = objectIndex(aObj);
577           }
578         } else {
579           // Check for composite object
580           ModelAPI_CompositeFeature* aCompFeature = dynamic_cast<ModelAPI_CompositeFeature*>(aParentObj);
581           if (aCompFeature) {
582             aIndex = objectIndex(aCompFeature->subFeature(theRow));
583           } else {
584             ModelAPI_ResultCompSolid* aCompRes = dynamic_cast<ModelAPI_ResultCompSolid*>(aParentObj);
585             if (aCompRes) 
586               aIndex = objectIndex(aCompRes->subResult(theRow));
587           }
588         }
589       }
590     }
591   }
592   if (theColumn != 0)
593     return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
594   return aIndex;
595 }
596
597 //******************************************************
598 static QModelIndex MYLastDeleted;
599 QModelIndex XGUI_DataModel::parent(const QModelIndex& theIndex) const
600 {
601   // To avoid additional request about index which was already deleted
602   if (theIndex == MYLastDeleted)
603     return QModelIndex();
604
605   int aId = theIndex.internalId();
606   if (aId != -1) { // The object is not a root folder
607     ModelAPI_Document* aDoc = getSubDocument(theIndex.internalPointer());
608     if (aDoc) { 
609       // It is a folder of sub-document
610       return findDocumentRootIndex(aDoc);
611     }
612     ObjectPtr aObj = object(theIndex);
613     if (!aObj.get()) {
614       // To avoid additional request about index which was already deleted
615       // If deleted it causes a crash on delete object from Part
616       MYLastDeleted = theIndex;
617       return QModelIndex();
618     }
619     // Check is it object a sub-object of a complex object
620     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
621     if (aFeature.get()) {
622       CompositeFeaturePtr aCompFea = ModelAPI_Tools::compositeOwner(aFeature);
623       if (aCompFea.get()) {
624         return objectIndex(aCompFea);
625       }
626     }
627     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
628     if (aResult.get()) {
629       ResultCompSolidPtr aCompRes = ModelAPI_Tools::compSolidOwner(aResult);
630       if (aCompRes.get()) {
631         return objectIndex(aCompRes);
632       }
633     }
634     // Use as ordinary object
635     std::string aType = aObj->groupName();
636     SessionPtr aSession = ModelAPI_Session::get();
637     DocumentPtr aRootDoc = aSession->moduleDocument();
638     DocumentPtr aSubDoc = aObj->document();
639     if (aSubDoc == aRootDoc) {
640       if (aType == myXMLReader->rootType())
641         return QModelIndex();
642       else {
643         // return first level of folder index
644         int aFolderId = myXMLReader->rootFolderId(aType);
645         // Items in a one row must have the same parent
646         return createIndex(aFolderId, 0, -1);
647       }
648     } else {
649       if (aType == myXMLReader->subType())
650         return findDocumentRootIndex(aSubDoc.get());
651       else {
652         // return first level of folder index
653         int aFolderId = myXMLReader->subFolderId(aType);
654         // Items in a one row must have the same parent
655         return createIndex(aFolderId, 0, aSubDoc.get());
656       }
657     }
658   } 
659   return QModelIndex();
660 }
661
662 //******************************************************
663 bool XGUI_DataModel::hasChildren(const QModelIndex& theParent) const
664 {
665   return rowCount(theParent) > 0;
666 }
667
668 //******************************************************
669 bool XGUI_DataModel::insertRows(int theRow, int theCount, const QModelIndex& theParent)
670 {
671   beginInsertRows(theParent, theRow, theRow + theCount - 1);
672   endInsertRows();
673
674   return true;
675 }
676
677 //******************************************************
678 bool XGUI_DataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent)
679 {
680   beginRemoveRows(theParent, theRow, theRow + theCount - 1);
681   endRemoveRows();
682   return true;
683 }
684
685 //******************************************************
686 Qt::ItemFlags XGUI_DataModel::flags(const QModelIndex& theIndex) const
687 {
688   qint64 aIt = theIndex.internalId();
689   ModelAPI_Object* aObj = 0;
690   ModelAPI_Document* aDoc = 0;
691   SessionPtr aSession = ModelAPI_Session::get();
692   DocumentPtr aActiveDoc = aSession->activeDocument();
693
694   Qt::ItemFlags aNullFlag;
695   Qt::ItemFlags aDefaultFlag = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
696   Qt::ItemFlags aEditingFlag = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
697
698
699   if (aIt == -1) {
700     // Folders under root
701     DocumentPtr aRootDoc = aSession->moduleDocument();
702     if (aRootDoc != aActiveDoc)
703       return aDefaultFlag;
704   } else {
705     aDoc = getSubDocument(theIndex.internalPointer());
706     if (!aDoc)
707       aObj = (ModelAPI_Object*) theIndex.internalPointer();
708   }
709
710   if (aObj) {
711     // An object
712     if (aObj->isDisabled()) 
713       return theIndex.column() == 1? Qt::ItemIsSelectable : aNullFlag;
714     
715     bool isCompositeSub = false;
716     // An object which is sub-object of a composite object can not be accessible in column 1
717     if (theIndex.column() == 1) {
718       ObjectPtr aObjPtr = aObj->data()->owner();
719       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObjPtr);
720       if (aFeature.get()) {
721         CompositeFeaturePtr aCompFea = ModelAPI_Tools::compositeOwner(aFeature);
722         if (aCompFea.get()) 
723           isCompositeSub = true;
724       } else {
725         ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aObjPtr);
726         if (aResult.get()) {
727           ResultCompSolidPtr aCompRes = ModelAPI_Tools::compSolidOwner(aResult);
728           if (aCompRes.get()) 
729             isCompositeSub = true;
730         }
731       }
732     }
733     if (isCompositeSub)
734       return Qt::ItemIsSelectable;
735
736     if (aObj->document() != aActiveDoc) {
737       // The object could be a root of sub-tree
738       ResultPartPtr aPartRes = getPartResult(aObj);
739       if (aPartRes.get()) {
740         if (aPartRes->partDoc() == aActiveDoc)
741           return aEditingFlag;
742       }
743       return aDefaultFlag;
744     }
745   } else if (aDoc) {
746     // A folder under sub-document
747     if (aActiveDoc.get() != aDoc)
748       return aNullFlag;
749   }
750   return aEditingFlag;
751 }
752
753 //******************************************************
754 QModelIndex XGUI_DataModel::findDocumentRootIndex(const ModelAPI_Document* theDoc) const
755 {
756   SessionPtr aSession = ModelAPI_Session::get();
757   DocumentPtr aRootDoc = aSession->moduleDocument();
758   if (myXMLReader->isAttachToResult()) { // If document is attached to result
759     int aNb = aRootDoc->size(ModelAPI_ResultPart::group());
760     ObjectPtr aObj;
761     ResultPartPtr aPartRes;
762     for (int i = 0; i < aNb; i++) {
763       aObj = aRootDoc->object(ModelAPI_ResultPart::group(), i);
764       aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
765       if (aPartRes.get() && (aPartRes->partDoc().get() == theDoc)) {
766         int aRow = i;
767         if (myXMLReader->rootType() == ModelAPI_Feature::group()) {
768           aRow += foldersCount();
769         }
770         return createIndex(aRow, 0, aObj.get());
771       }
772     }
773   } else { // If document is attached to feature
774     int aNb = aRootDoc->size(ModelAPI_Feature::group());
775     ObjectPtr aObj;
776     ResultPartPtr aPartRes;
777     for (int i = 0; i < aNb; i++) {
778       aObj = aRootDoc->object(ModelAPI_Feature::group(), i);
779       aPartRes = getPartResult(aObj.get());
780       if (aPartRes.get() && (aPartRes->partDoc().get() == theDoc)) {
781         int aRow = i;
782         if (myXMLReader->rootType() == ModelAPI_Feature::group())
783           aRow += foldersCount();
784         return createIndex(aRow, 0, aObj.get());
785       }
786     }
787   }
788   return QModelIndex();
789 }
790
791 //******************************************************
792 QModelIndex XGUI_DataModel::documentRootIndex(DocumentPtr theDoc) const
793 {
794   SessionPtr aSession = ModelAPI_Session::get();
795   DocumentPtr aRootDoc = aSession->moduleDocument();
796   if (theDoc == aRootDoc)
797     return QModelIndex();
798   else 
799     return findDocumentRootIndex(theDoc.get());
800 }
801
802 //******************************************************
803 int XGUI_DataModel::foldersCount(ModelAPI_Document* theDoc) const
804 {
805   int aNb = 0;
806   SessionPtr aSession = ModelAPI_Session::get();
807   DocumentPtr aRootDoc = aSession->moduleDocument();
808   if ((theDoc == 0) || (theDoc == aRootDoc.get())) {
809     for (int i = 0; i < myXMLReader->rootFoldersNumber(); i++) {
810       if (myXMLReader->rootShowEmpty(i))
811         aNb++;
812       else {
813         if (aRootDoc->size(myXMLReader->rootFolderType(i)) > 0)
814           aNb++;
815       }
816     }
817   } else {
818     for (int i = 0; i < myXMLReader->subFoldersNumber(); i++) {
819       if (myXMLReader->subShowEmpty(i))
820         aNb++;
821       else {
822         if (theDoc->size(myXMLReader->subFolderType(i)) > 0)
823           aNb++;
824       }
825     }
826   }
827   return aNb;
828 }
829
830
831 //******************************************************
832 QIntList XGUI_DataModel::missedFolderIndexes(ModelAPI_Document* theDoc) const
833 {
834   QIntList aList;
835   SessionPtr aSession = ModelAPI_Session::get();
836   DocumentPtr aRootDoc = aSession->moduleDocument();
837   if ((theDoc == 0) || (theDoc == aRootDoc.get())) {
838     for (int i = 0; i < myXMLReader->rootFoldersNumber(); i++) {
839       if (!myXMLReader->rootShowEmpty(i)) {
840         if (aRootDoc->size(myXMLReader->rootFolderType(i)) == 0)
841           aList.append(i);
842       }
843     }
844   } else {
845     for (int i = 0; i < myXMLReader->subFoldersNumber(); i++) {
846       if (!myXMLReader->subShowEmpty(i)) {
847         if (theDoc->size(myXMLReader->subFolderType(i)) == 0)
848           aList.append(i);
849       }
850     }
851   }
852   return aList;
853 }
854
855
856 //******************************************************
857 QStringList XGUI_DataModel::listOfShowNotEmptyFolders(bool fromRoot) const
858 {
859   QStringList aResult;
860   if (fromRoot) {
861     for (int i = 0; i < myXMLReader->rootFoldersNumber(); i++) {
862       if (!myXMLReader->rootShowEmpty(i))
863         aResult << myXMLReader->rootFolderType(i).c_str();
864     }
865   } else {
866     for (int i = 0; i < myXMLReader->subFoldersNumber(); i++) {
867       if (!myXMLReader->subShowEmpty(i))
868         aResult << myXMLReader->subFolderType(i).c_str();
869     }
870   }
871   return aResult;
872 }
873
874 //******************************************************
875 QModelIndex XGUI_DataModel::lastHistoryIndex() const
876 {
877   SessionPtr aSession = ModelAPI_Session::get();
878   DocumentPtr aCurDoc = aSession->activeDocument();
879   FeaturePtr aFeature = aCurDoc->currentFeature(true);
880   if (aFeature.get()) {
881     QModelIndex aInd = objectIndex(aFeature);
882     return createIndex(aInd.row(), 1, aInd.internalPointer());
883   } else {
884     if (aCurDoc == aSession->moduleDocument())
885       return createIndex(foldersCount() - 1, 1, -1);
886     else 
887       return createIndex(foldersCount(aCurDoc.get()) - 1, 1, aCurDoc.get());
888   }
889 }
890
891 //******************************************************
892 int XGUI_DataModel::folderId(std::string theType, ModelAPI_Document* theDoc)
893 {
894   SessionPtr aSession = ModelAPI_Session::get();
895   ModelAPI_Document* aDoc = theDoc;
896   if (aDoc == 0)
897     aDoc = aSession->moduleDocument().get();
898
899   bool aUseSubDoc = (aDoc != aSession->moduleDocument().get());
900
901   int aRes = -1;
902   if (aUseSubDoc) {
903     int aId = myXMLReader->subFolderId(theType);
904     aRes = aId;
905     for (int i = 0; i < aId; i++) {
906       if (!myXMLReader->subShowEmpty(i)) {
907         if (aDoc->size(myXMLReader->subFolderType(i)) == 0)
908           aRes--;
909       }
910     }
911   } else {
912     int aId = myXMLReader->rootFolderId(theType);
913     aRes = aId;
914     for (int i = 0; i < aId; i++) {
915       if (!myXMLReader->rootShowEmpty(i)) {
916         if (aDoc->size(myXMLReader->rootFolderType(i)) == 0)
917           aRes--;
918       }
919     }
920   }
921   return aRes;
922 }
923
924 //******************************************************
925 void XGUI_DataModel::rebuildBranch(int theRow, int theCount, const QModelIndex& theParent)
926 {
927   if (theCount > 0) {
928     removeRows(theRow, theCount, theParent);
929     insertRows(theRow, theCount, theParent);
930   }
931 }