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