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