Salome HOME
Update Part item on activation of loaded document
[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 QColor(0,72,140)
30 #define PASSIVE_COLOR Qt::black
31
32 /// Returns ResultPart object if the given object is a Part feature
33 /// Otherwise returns NULL
34 ResultPartPtr getPartResult(ModelAPI_Object* theObj)
35 {
36   ModelAPI_Feature* aFeature = dynamic_cast<ModelAPI_Feature*>(theObj);
37   if (aFeature) {
38     ResultPtr aRes = aFeature->firstResult();
39     if (aRes.get() && (aRes->groupName() == ModelAPI_ResultPart::group())) {
40       return std::dynamic_pointer_cast<ModelAPI_ResultPart>(aRes);
41     }
42   }
43   return ResultPartPtr();
44 }
45
46 /// Returns pointer on document if the given object is document object
47 ModelAPI_Document* getSubDocument(void* theObj)
48 {
49   ModelAPI_Document* aDoc = dynamic_cast<ModelAPI_Document*>((ModelAPI_Entity*)theObj);
50   return aDoc;
51 }
52
53
54
55
56 // Constructor *************************************************
57 XGUI_DataModel::XGUI_DataModel(QObject* theParent) : QAbstractItemModel(theParent)
58 {
59   myXMLReader.readAll();
60
61   Events_Loop* aLoop = Events_Loop::loop();
62   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
63   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
64   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_DOCUMENT_CHANGED));
65 }
66
67 //******************************************************
68 void XGUI_DataModel::processEvent(const std::shared_ptr<Events_Message>& theMessage)
69 {
70   DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
71   std::string aRootType = myXMLReader.rootType();
72   std::string aSubType = myXMLReader.subType();
73   int aNbFolders = foldersCount();
74
75   // Created object event *******************
76   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)) {
77     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
78         std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
79     std::set<ObjectPtr> aObjects = aUpdMsg->objects();
80
81     std::set<ObjectPtr>::const_iterator aIt;
82     std::string aObjType;
83     for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) {
84       ObjectPtr aObject = (*aIt);
85       aObjType = aObject->groupName();
86       DocumentPtr aDoc = aObject->document();
87       if (aDoc == aRootDoc) {
88         // Check that new folders could appear
89         QStringList aNotEmptyFolders = listOfShowNotEmptyFolders();
90         foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
91           if ((aNotEmptyFolder.toStdString() == aObjType) && (aRootDoc->size(aObjType) == 1))
92             // Appears first object in folder which can not be shown empty
93             insertRow(myXMLReader.rootFolderId(aObjType));
94         }
95         // Insert new object
96         int aRow = aRootDoc->size(aObjType) - 1;
97         if (aObjType == aRootType) {
98           insertRow(aRow + aNbFolders + 1);
99         } else {
100           int aFolderId = myXMLReader.rootFolderId(aObjType);
101           if (aFolderId != -1) {
102             insertRow(aRow, createIndex(aFolderId, 0, -1));
103           }
104         } 
105       } else {
106         // Object created in sub-document
107         QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get());
108         if (aDocRoot.isValid()) {
109           // Check that new folders could appear
110           QStringList aNotEmptyFolders = listOfShowNotEmptyFolders(false);
111           foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
112             if ((aNotEmptyFolder.toStdString() == aObjType) && (aDoc->size(aObjType) == 1))
113               // Appears first object in folder which can not be shown empty
114               insertRow(myXMLReader.subFolderId(aObjType), aDocRoot);
115           }
116           int aRow = aDoc->size(aObjType) - 1;
117           int aNbSubFolders = foldersCount(aDoc.get());
118           if (aObjType == aSubType) {
119             // List of objects under document root
120             insertRow(aRow + aNbSubFolders, aDocRoot);
121           } else {
122             // List of objects under a folder
123             if (aRow != -1) {
124               int aFolderId = myXMLReader.subFolderId(aObjType);
125               if (aFolderId != -1) {
126                 insertRow(aRow, createIndex(aFolderId, 0, aDoc.get()));
127               }
128             }
129           }
130         } 
131 #ifdef _DEBUG
132         else
133           Events_Error::send("Problem with Data Model definition of sub-document");
134 #endif
135       }
136     }
137     // Deleted object event ***********************
138   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
139     std::shared_ptr<ModelAPI_ObjectDeletedMessage> aUpdMsg =
140         std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
141     DocumentPtr aDoc = aUpdMsg->document();
142     std::set<std::string> aGroups = aUpdMsg->groups();
143     std::set<std::string>::const_iterator aIt;
144     for (aIt = aGroups.begin(); aIt != aGroups.end(); ++aIt) {
145       std::string aGroup = (*aIt);
146       if (aDoc == aRootDoc) {  // If root objects
147         int aRow = aRootDoc->size(aGroup);
148         if (aGroup == aRootType) {
149           removeRow(aRow + aNbFolders);
150         } else {
151           int aFolderId = myXMLReader.rootFolderId(aGroup);
152           if (aFolderId != -1) {
153             QModelIndex aFolderIndex = createIndex(aFolderId, 0, -1);
154             removeRow(aRow, aFolderIndex);
155           }
156         }
157         // Check that some folders could erased
158         QStringList aNotEmptyFolders = listOfShowNotEmptyFolders();
159         foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
160           if ((aNotEmptyFolder.toStdString() == aGroup) && (aRootDoc->size(aGroup) == 0))
161             // Appears first object in folder which can not be shown empty
162             removeRow(myXMLReader.rootFolderId(aGroup));
163         }
164       } else {
165         // Remove row for sub-document
166         QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get());
167         if (aDocRoot.isValid()) {
168           int aRow = aDoc->size(aGroup);
169           int aNbSubFolders = foldersCount(aDoc.get());
170           if (aGroup == aSubType) {
171             // List of objects under document root
172             removeRow(aRow + aNbSubFolders, aDocRoot);
173           } else {
174             // List of objects under a folder
175             int aFolderId = myXMLReader.subFolderId(aGroup);
176             if (aFolderId != -1) {
177               removeRow(aRow, createIndex(aFolderId, 0, aDoc.get()));
178             }
179           }
180           // Check that some folders could disappear
181           QStringList aNotEmptyFolders = listOfShowNotEmptyFolders(false);
182           foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
183             if ((aNotEmptyFolder.toStdString() == aGroup) && (aDoc->size(aGroup) == 1))
184               // Appears first object in folder which can not be shown empty
185               removeRow(myXMLReader.subFolderId(aGroup), aDocRoot);
186           }
187         } 
188 #ifdef _DEBUG
189         else
190           Events_Error::send("Problem with Data Model definition of sub-document");
191 #endif
192       }
193     }
194   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_DOCUMENT_CHANGED)) {
195     DocumentPtr aDoc = ModelAPI_Session::get()->activeDocument();
196     if (aDoc != aRootDoc) {
197       QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get());
198       if (aDocRoot.isValid())
199         emit dataChanged(aDocRoot, aDocRoot);
200 #ifdef _DEBUG
201       else
202         Events_Error::send("Problem with Data Model definition of sub-document");
203 #endif
204     }
205   } 
206 }
207
208 //******************************************************
209 void XGUI_DataModel::clear()
210 {
211
212 }
213
214 //******************************************************
215 void XGUI_DataModel::rebuildDataTree()
216 {
217
218 }
219
220 //******************************************************
221 ObjectPtr XGUI_DataModel::object(const QModelIndex& theIndex) const
222 {
223   if (theIndex.internalId() < 0) // this is a folder
224     return ObjectPtr();
225   ModelAPI_Object* aObj = (ModelAPI_Object*)theIndex.internalPointer();
226   if (getSubDocument(aObj)) // the selected index is a folder of sub-document
227     return ObjectPtr();
228
229   return aObj->data()->owner();
230 }
231
232 //******************************************************
233 QModelIndex XGUI_DataModel::objectIndex(const ObjectPtr theObject) const
234 {
235   std::string aType = theObject->groupName();
236   DocumentPtr aDoc = theObject->document();
237   int aRow = aDoc->index(theObject);
238   if (aRow == -1) {
239     // it could be a part of complex object
240     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
241     if (aFeature.get()) {
242       CompositeFeaturePtr aCompFea = ModelAPI_Tools::compositeOwner(aFeature);
243       if (aCompFea.get()) {
244         for (int i = 0; i < aCompFea->numberOfSubs(true); i++) {
245           if (aCompFea->subFeature(i, true) == theObject) {
246             aRow = i;
247             break;
248           }
249         }
250       }
251     } else {
252       ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
253       if (aResult.get()) {
254         ResultCompSolidPtr aCompRes = ModelAPI_Tools::compSolidOwner(aResult);
255         if (aCompRes.get()) {
256           for (int i = 0; i < aCompRes->numberOfSubs(true); i++) {
257             if (aCompRes->subResult(i, true) == theObject) {
258               aRow = i;
259               break;
260             }
261           }
262         }
263       }
264     }
265     if (aRow == -1)
266       return QModelIndex();
267     else 
268       return createIndex(aRow, 0, theObject.get());
269   }
270   SessionPtr aSession = ModelAPI_Session::get();
271   DocumentPtr aRootDoc = aSession->moduleDocument();
272   if (aDoc == aRootDoc && myXMLReader.rootType() == aType) { 
273     // The object from root document
274     aRow += foldersCount();
275   } else if (myXMLReader.subType() == aType) { 
276     // The object from sub document
277     aRow += foldersCount(aDoc.get());
278   }
279   return createIndex(aRow, 0, theObject.get());
280 }
281
282 //******************************************************
283 QVariant XGUI_DataModel::data(const QModelIndex& theIndex, int theRole) const
284 {
285   SessionPtr aSession = ModelAPI_Session::get();
286   DocumentPtr aRootDoc = aSession->moduleDocument();
287   int aNbFolders = foldersCount();
288   int theIndexRow = theIndex.row();
289
290   if ((theRole == Qt::DecorationRole) && (theIndex == lastHistoryIndex()))
291     return QIcon(":pictures/arrow.png");
292
293   if (theIndex.column() == 1)
294     return QVariant();
295
296   int aParentId = theIndex.internalId();
297   if (aParentId == -1) { // root folders
298     switch (theRole) {
299       case Qt::DisplayRole:
300         return QString(myXMLReader.rootFolderName(theIndexRow).c_str()) + 
301           QString(" (%1)").arg(rowCount(theIndex));
302       case Qt::DecorationRole:
303         return QIcon(myXMLReader.rootFolderIcon(theIndexRow).c_str());
304       case Qt::ForegroundRole:
305         if (aSession->activeDocument() == aRootDoc)
306           return QBrush(ACTIVE_COLOR);
307         else
308           return QBrush(PASSIVE_COLOR);
309     }
310   } else { // an object or sub-document
311     ModelAPI_Document* aSubDoc = getSubDocument(theIndex.internalPointer());
312
313     if (theRole == Qt::ForegroundRole) {
314       bool aIsActive = false;
315       if (aSubDoc)
316         aIsActive = (aSession->activeDocument().get() == aSubDoc);
317       else {
318         ModelAPI_Object* aObj = (ModelAPI_Object*)theIndex.internalPointer();
319         if (aObj->isDisabled())
320           return QBrush(Qt::lightGray);
321         aIsActive = (aSession->activeDocument() == aObj->document());
322       }
323       if (aIsActive)
324         return QBrush(ACTIVE_COLOR);
325       else
326         return QBrush(PASSIVE_COLOR);
327     }
328
329     if (aSubDoc) { // this is a folder of sub document
330       switch (theRole) {
331         case Qt::DisplayRole:
332           return QString(myXMLReader.subFolderName(theIndexRow).c_str()) + 
333             QString(" (%1)").arg(rowCount(theIndex));
334         case Qt::DecorationRole:
335           return QIcon(myXMLReader.subFolderIcon(theIndexRow).c_str());
336       }
337     } else {
338       ModelAPI_Object* aObj = (ModelAPI_Object*)theIndex.internalPointer();
339       switch (theRole) {
340       case Qt::DisplayRole:
341         if (aObj->groupName() == ModelAPI_ResultParameter::group()) {
342           ModelAPI_ResultParameter* aParam = dynamic_cast<ModelAPI_ResultParameter*>(aObj);
343           AttributeDoublePtr aValueAttribute = aParam->data()->real(ModelAPI_ResultParameter::VALUE());
344           QString aVal = QString::number(aValueAttribute->value());
345           QString aTitle = QString(aObj->data()->name().c_str());
346           return aTitle + " = " + aVal;
347         }
348         return aObj->data()->name().c_str();
349       case Qt::DecorationRole:
350         return ModuleBase_IconFactory::get()->getIcon(object(theIndex));
351       }
352     }
353   }
354   return QVariant();
355 }
356
357 //******************************************************
358 QVariant XGUI_DataModel::headerData(int theSection, Qt::Orientation theOrient, int theRole) const
359 {
360   return QVariant();
361 }
362
363 //******************************************************
364 int XGUI_DataModel::rowCount(const QModelIndex& theParent) const
365 {
366   SessionPtr aSession = ModelAPI_Session::get();
367   if (!aSession->hasModuleDocument())
368     return 0;
369   DocumentPtr aRootDoc = aSession->moduleDocument();
370
371   if (!theParent.isValid()) {
372     // Return number of items in root
373     int aNbFolders = foldersCount();
374     int aNbItems = 0;
375     std::string aType = myXMLReader.rootType();
376     if (!aType.empty())
377       aNbItems = aRootDoc->size(aType);
378     return aNbFolders + aNbItems;
379   }
380
381   int aId = theParent.internalId();
382   if (aId == -1) { 
383     // this is a folder under root
384     int aParentPos = theParent.row();
385     std::string aType = myXMLReader.rootFolderType(aParentPos);
386     //qDebug("### %s = %i\n", aType.c_str(), aRootDoc->size(aType));
387     return aRootDoc->size(aType);
388   } else {
389     // It is an object which could have children
390     ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
391     if (aDoc) { 
392       // a folder of sub-document
393       std::string aType = myXMLReader.subFolderType(theParent.row());
394       return aDoc->size(aType);
395     } else {
396       ModelAPI_Object* aObj = (ModelAPI_Object*)theParent.internalPointer();
397       // Check for Part feature
398       ResultPartPtr aPartRes = getPartResult(aObj);
399       if (aPartRes.get()) {
400         DocumentPtr aSubDoc = aPartRes->partDoc();
401         int aNbSubFolders = foldersCount(aSubDoc.get());
402         int aNbSubItems = 0;
403         std::string aSubType = myXMLReader.subType();
404         if (!aSubType.empty())
405           aNbSubItems = aSubDoc->size(aSubType);
406         return aNbSubItems + aNbSubFolders;
407       } else {
408         // Check for composite object
409         ModelAPI_CompositeFeature* aCompFeature = dynamic_cast<ModelAPI_CompositeFeature*>(aObj);
410         if (aCompFeature) 
411           return aCompFeature->numberOfSubs(true);
412         ModelAPI_ResultCompSolid* aCompRes = dynamic_cast<ModelAPI_ResultCompSolid*>(aObj);
413         if (aCompRes) 
414           return aCompRes->numberOfSubs(true);
415       }
416     }
417   }
418   return 0;
419 }
420
421 //******************************************************
422 int XGUI_DataModel::columnCount(const QModelIndex& theParent) const
423 {
424   return 2;
425 }
426
427 //******************************************************
428 QModelIndex XGUI_DataModel::index(int theRow, int theColumn, const QModelIndex &theParent) const
429 {
430   SessionPtr aSession = ModelAPI_Session::get();
431   DocumentPtr aRootDoc = aSession->moduleDocument();
432   int aNbFolders = foldersCount();
433
434   QModelIndex aIndex;
435
436   if (!theParent.isValid()) {
437     if (theRow < aNbFolders) // Return first level folder index
438       return createIndex(theRow, theColumn, -1);
439     else { // return object under root index
440       std::string aType = myXMLReader.rootType();
441       int aObjId = theRow - aNbFolders;
442       if (aObjId < aRootDoc->size(aType)) {
443         ObjectPtr aObj = aRootDoc->object(aType, aObjId);
444         aIndex = objectIndex(aObj);
445       }
446     }
447   } else {
448     int aId = theParent.internalId();
449     int aParentPos = theParent.row();
450     if (aId == -1) { // return object index inside of first level of folders
451       std::string aType = myXMLReader.rootFolderType(aParentPos);
452       if (theRow < aRootDoc->size(aType)) {
453         ObjectPtr aObj = aRootDoc->object(aType, theRow);
454         aIndex = objectIndex(aObj);
455       }
456     } else {
457       // It is an object which could have children
458       ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
459       if (aDoc) { 
460         // It is a folder of sub-document
461         std::string aType = myXMLReader.subFolderType(aParentPos);
462         if (theRow < aDoc->size(aType)) {
463           ObjectPtr aObj = aDoc->object(aType, theRow);
464           aIndex = objectIndex(aObj);
465         }
466       } else {
467         ModelAPI_Object* aParentObj = (ModelAPI_Object*)theParent.internalPointer();
468
469         // Check for Part feature
470         ResultPartPtr aPartRes = getPartResult(aParentObj);
471         if (aPartRes.get()) {
472           DocumentPtr aSubDoc = aPartRes->partDoc();
473           int aNbSubFolders = foldersCount(aSubDoc.get());
474           if (theRow < aNbSubFolders) { // Create a Folder of sub-document
475             aIndex = createIndex(theRow, theColumn, aSubDoc.get());
476           } else {
477             // this is an object under sub document root
478             std::string aType = myXMLReader.subType();
479             ObjectPtr aObj = aSubDoc->object(aType, theRow - aNbSubFolders);
480             aIndex = objectIndex(aObj);
481           }
482         } else {
483           // Check for composite object
484           ModelAPI_CompositeFeature* aCompFeature = dynamic_cast<ModelAPI_CompositeFeature*>(aParentObj);
485           if (aCompFeature) {
486             aIndex = objectIndex(aCompFeature->subFeature(theRow));
487           } else {
488             ModelAPI_ResultCompSolid* aCompRes = dynamic_cast<ModelAPI_ResultCompSolid*>(aParentObj);
489             if (aCompRes) 
490               aIndex = objectIndex(aCompRes->subResult(theRow));
491           }
492         }
493       }
494     }
495   }
496   if (theColumn != 0)
497     return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
498   return aIndex;
499 }
500
501 //******************************************************
502 static QModelIndex MYLastDeleted;
503 QModelIndex XGUI_DataModel::parent(const QModelIndex& theIndex) const
504 {
505   // To avoid additional request about index which was already deleted
506   if (theIndex == MYLastDeleted)
507     return QModelIndex();
508
509   int aId = theIndex.internalId();
510   if (aId != -1) { // The object is not a root folder
511     ModelAPI_Document* aDoc = getSubDocument(theIndex.internalPointer());
512     if (aDoc) { 
513       // It is a folder of sub-document
514       return findDocumentRootIndex(aDoc);
515     }
516     ObjectPtr aObj = object(theIndex);
517     if (!aObj.get()) {
518       // To avoid additional request about index which was already deleted
519       // If deleted it causes a crash on delete object from Part
520       MYLastDeleted = theIndex;
521       return QModelIndex();
522     }
523     // Check is it object a sub-object of a complex object
524     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
525     if (aFeature.get()) {
526       CompositeFeaturePtr aCompFea = ModelAPI_Tools::compositeOwner(aFeature);
527       if (aCompFea.get()) {
528         return objectIndex(aCompFea);
529       }
530     }
531     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
532     if (aResult.get()) {
533       ResultCompSolidPtr aCompRes = ModelAPI_Tools::compSolidOwner(aResult);
534       if (aCompRes.get()) {
535         return objectIndex(aCompRes);
536       }
537     }
538     // Use as ordinary object
539     std::string aType = aObj->groupName();
540     SessionPtr aSession = ModelAPI_Session::get();
541     DocumentPtr aRootDoc = aSession->moduleDocument();
542     DocumentPtr aSubDoc = aObj->document();
543     if (aSubDoc == aRootDoc) {
544       if (aType == myXMLReader.rootType())
545         return QModelIndex();
546       else {
547         // return first level of folder index
548         int aFolderId = myXMLReader.rootFolderId(aType);
549         // Items in a one row must have the same parent
550         return createIndex(aFolderId, 0, -1);
551       }
552     } else {
553       if (aType == myXMLReader.subType())
554         return findDocumentRootIndex(aSubDoc.get());
555       else {
556         // return first level of folder index
557         int aFolderId = myXMLReader.subFolderId(aType);
558         // Items in a one row must have the same parent
559         return createIndex(aFolderId, 0, aSubDoc.get());
560       }
561     }
562   } 
563   return QModelIndex();
564 }
565
566 //******************************************************
567 bool XGUI_DataModel::hasChildren(const QModelIndex& theParent) const
568 {
569   if (!theParent.isValid()) {
570     int aNbFolders = foldersCount();
571     if (aNbFolders > 0)
572       return true;
573     SessionPtr aSession = ModelAPI_Session::get();
574     DocumentPtr aRootDoc = aSession->moduleDocument();
575     return aRootDoc->size(myXMLReader.rootType()) > 0;
576   }
577   if (theParent.internalId() == -1) {
578     std::string aType = myXMLReader.rootFolderType(theParent.row());
579     if (!aType.empty()) {
580       SessionPtr aSession = ModelAPI_Session::get();
581       DocumentPtr aRootDoc = aSession->moduleDocument();
582       return aRootDoc->size(aType) > 0;
583     }
584   } else {
585     ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
586     if (aDoc) { 
587       // a folder of sub-document
588       std::string aType = myXMLReader.subFolderType(theParent.row());
589       return aDoc->size(aType) > 0;
590     } else {
591       // Check that it could be an object with children
592       ModelAPI_Object* aObj = (ModelAPI_Object*)theParent.internalPointer();
593
594       // Check for Part feature
595       ResultPartPtr aPartRes = getPartResult(aObj);
596       if (aPartRes.get())
597         return aPartRes->partDoc().get() != NULL;
598       else {
599         // Check for composite object
600         ModelAPI_CompositeFeature* aCompFeature = dynamic_cast<ModelAPI_CompositeFeature*>(aObj);
601         if (aCompFeature) 
602           return aCompFeature->numberOfSubs(true) > 0;
603         ModelAPI_ResultCompSolid* aCompRes = dynamic_cast<ModelAPI_ResultCompSolid*>(aObj);
604         if (aCompRes) 
605           return aCompRes->numberOfSubs(true) > 0;
606       }
607     }
608   }
609   return false;
610 }
611
612 //******************************************************
613 bool XGUI_DataModel::insertRows(int theRow, int theCount, const QModelIndex& theParent)
614 {
615   beginInsertRows(theParent, theRow, theRow + theCount - 1);
616   endInsertRows();
617
618   return true;
619 }
620
621 //******************************************************
622 bool XGUI_DataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent)
623 {
624   beginRemoveRows(theParent, theRow, theRow + theCount - 1);
625   endRemoveRows();
626   return true;
627 }
628
629 //******************************************************
630 Qt::ItemFlags XGUI_DataModel::flags(const QModelIndex& theIndex) const
631 {
632   Qt::ItemFlags aFlags = Qt::ItemIsSelectable;
633
634   ModelAPI_Object* aObj = 0;
635   if (theIndex.internalId() != -1) {
636     if (!getSubDocument(theIndex.internalPointer()))
637       aObj = (ModelAPI_Object*) theIndex.internalPointer();
638   }
639   if (aObj) {
640     aFlags |= Qt::ItemIsEditable;
641   
642     if (!aObj->isDisabled())
643       aFlags |= Qt::ItemIsEnabled;
644   } else
645     aFlags |= Qt::ItemIsEnabled;
646   return aFlags;
647 }
648
649 //******************************************************
650 QModelIndex XGUI_DataModel::findDocumentRootIndex(const ModelAPI_Document* theDoc) const
651 {
652   SessionPtr aSession = ModelAPI_Session::get();
653   DocumentPtr aRootDoc = aSession->moduleDocument();
654   if (myXMLReader.isAttachToResult()) { // If document is attached to result
655     int aNb = aRootDoc->size(ModelAPI_ResultPart::group());
656     ObjectPtr aObj;
657     ResultPartPtr aPartRes;
658     for (int i = 0; i < aNb; i++) {
659       aObj = aRootDoc->object(ModelAPI_ResultPart::group(), i);
660       aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
661       if (aPartRes.get() && (aPartRes->partDoc().get() == theDoc)) {
662         int aRow = i;
663         if (myXMLReader.rootType() == ModelAPI_Feature::group())
664           aRow += foldersCount();
665         return createIndex(aRow, 0, aObj.get());
666       }
667     }
668   } else { // If document is attached to feature
669     int aNb = aRootDoc->size(ModelAPI_Feature::group());
670     ObjectPtr aObj;
671     ResultPartPtr aPartRes;
672     for (int i = 0; i < aNb; i++) {
673       aObj = aRootDoc->object(ModelAPI_Feature::group(), i);
674       aPartRes = getPartResult(aObj.get());
675       if (aPartRes.get() && (aPartRes->partDoc().get() == theDoc)) {
676         int aRow = i;
677         if (myXMLReader.rootType() == ModelAPI_Feature::group())
678           aRow += foldersCount();
679         return createIndex(aRow, 0, aObj.get());
680       }
681     }
682   }
683   return QModelIndex();
684 }
685
686 //******************************************************
687 QModelIndex XGUI_DataModel::documentRootIndex(DocumentPtr theDoc) const
688 {
689   SessionPtr aSession = ModelAPI_Session::get();
690   DocumentPtr aRootDoc = aSession->moduleDocument();
691   if (theDoc == aRootDoc)
692     return QModelIndex();
693   else 
694     return findDocumentRootIndex(theDoc.get());
695 }
696
697 //******************************************************
698 int XGUI_DataModel::foldersCount(ModelAPI_Document* theDoc) const
699 {
700   int aNb = 0;
701   SessionPtr aSession = ModelAPI_Session::get();
702   DocumentPtr aRootDoc = aSession->moduleDocument();
703   if ((theDoc == 0) || (theDoc == aRootDoc.get())) {
704     for (int i = 0; i < myXMLReader.rootFoldersNumber(); i++) {
705       if (myXMLReader.rootShowEmpty(i))
706         aNb++;
707       else {
708         if (aRootDoc->size(myXMLReader.rootFolderType(i)) > 0)
709           aNb++;
710       }
711     }
712   } else {
713     for (int i = 0; i < myXMLReader.subFoldersNumber(); i++) {
714       if (myXMLReader.subShowEmpty(i))
715         aNb++;
716       else {
717         if (theDoc->size(myXMLReader.subFolderType(i)) > 0)
718           aNb++;
719       }
720     }
721   }
722   return aNb;
723 }
724
725 //******************************************************
726 QStringList XGUI_DataModel::listOfShowNotEmptyFolders(bool fromRoot) const
727 {
728   QStringList aResult;
729   if (fromRoot) {
730     for (int i = 0; i < myXMLReader.rootFoldersNumber(); i++) {
731       if (!myXMLReader.rootShowEmpty(i))
732         aResult << myXMLReader.rootFolderType(i).c_str();
733     }
734   } else {
735     for (int i = 0; i < myXMLReader.subFoldersNumber(); i++) {
736       if (!myXMLReader.subShowEmpty(i))
737         aResult << myXMLReader.subFolderType(i).c_str();
738     }
739   }
740   return aResult;
741 }
742
743 //******************************************************
744 QModelIndex XGUI_DataModel::lastHistoryIndex() const
745 {
746   SessionPtr aSession = ModelAPI_Session::get();
747   DocumentPtr aCurDoc = aSession->activeDocument();
748   FeaturePtr aFeature = aCurDoc->currentFeature(true);
749   if (aFeature.get()) {
750     QModelIndex aInd = objectIndex(aFeature);
751     return createIndex(aInd.row(), 1, aInd.internalPointer());
752   } else {
753     if (aCurDoc == aSession->moduleDocument())
754       return createIndex(foldersCount() - 1, 1, -1);
755     else 
756       return createIndex(foldersCount(aCurDoc.get()) - 1, 1, aCurDoc.get());
757   }
758 }