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