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