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