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