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