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