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