]> SALOME platform Git repositories - modules/shaper.git/blob - src/XGUI/XGUI_DataModel.cpp
Salome HOME
6bf061dcf0365e440e8d2818b97e7bcf345fbc82
[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_ResultField.h>
20 #include <ModelAPI_Tools.h>
21
22 #include <Config_FeatureMessage.h>
23 #include <Config_DataModelReader.h>
24
25 #include <Events_Loop.h>
26
27 #include <QIcon>
28 #include <QBrush>
29
30 #define ACTIVE_COLOR QColor(Qt::black)
31 //#define ACTIVE_COLOR QColor(0,72,140)
32 //#define PASSIVE_COLOR Qt::black
33
34 /// Returns ResultPart object if the given object is a Part feature
35 /// Otherwise returns NULL
36
37 #define SELECTABLE_COLOR QColor(80, 80, 80)
38 #define DISABLED_COLOR QColor(200, 200, 200)
39
40
41 ResultPartPtr getPartResult(ModelAPI_Object* theObj)
42 {
43   ModelAPI_Feature* aFeature = dynamic_cast<ModelAPI_Feature*>(theObj);
44   if (aFeature) {
45     ResultPtr aRes = aFeature->firstResult();
46     if (aRes.get() && (aRes->groupName() == ModelAPI_ResultPart::group())) {
47       ResultPartPtr aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aRes);
48       // Use only original parts, not a placement results
49       if (aPartRes == aPartRes->original())
50       return aPartRes;
51     }
52   }
53   return ResultPartPtr();
54 }
55
56 /// Returns pointer on document if the given object is document object
57 ModelAPI_Document* getSubDocument(void* theObj)
58 {
59   ModelAPI_Document* aDoc = dynamic_cast<ModelAPI_Document*>((ModelAPI_Entity*)theObj);
60   return aDoc;
61 }
62
63
64
65
66 // Constructor *************************************************
67 XGUI_DataModel::XGUI_DataModel(QObject* theParent) : QAbstractItemModel(theParent)//,
68   //myIsEventsProcessingBlocked(false)
69 {
70   Events_Loop* aLoop = Events_Loop::loop();
71   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
72   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
73   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
74   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_ORDER_UPDATED));
75   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_DOCUMENT_CHANGED));
76 }
77
78 XGUI_DataModel::~XGUI_DataModel()
79 {
80   clear();
81 }
82
83 //******************************************************
84 void XGUI_DataModel::processEvent(const std::shared_ptr<Events_Message>& theMessage)
85 {
86   //if (myIsEventsProcessingBlocked)
87   //  return;
88   DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
89   std::string aRootType = myXMLReader->rootType();
90   std::string aSubType = myXMLReader->subType();
91   int aNbFolders = foldersCount();
92
93   // Created object event *******************
94   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)) {
95     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
96         std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
97     std::set<ObjectPtr> aObjects = aUpdMsg->objects();
98
99     std::set<ObjectPtr>::const_iterator aIt;
100     std::string aObjType;
101     for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) {
102       ObjectPtr aObject = (*aIt);
103       // We do not show objects which does not need to be shown in object browser
104       if (!aObject->isInHistory())
105         continue;
106
107       aObjType = aObject->groupName();
108       DocumentPtr aDoc = aObject->document();
109       if (aDoc == aRootDoc) {
110         // Check that new folders could appear
111         QStringList aNotEmptyFolders = listOfShowNotEmptyFolders();
112         foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
113           if ((aNotEmptyFolder.toStdString() == aObjType) && (aRootDoc->size(aObjType) == 1))
114             // Appears first object in folder which can not be shown empty
115             insertRow(myXMLReader->rootFolderId(aObjType));
116         }
117         // Insert new object
118         int aRow = aRootDoc->size(aObjType) - 1;
119         if (aRow != -1) {
120           if (aObjType == aRootType) {
121             insertRow(aRow + aNbFolders + 1);
122           } else {
123             int aFolderId = myXMLReader->rootFolderId(aObjType);
124             if (aFolderId != -1) {
125               insertRow(aRow, createIndex(aFolderId, 0, (void*)Q_NULLPTR));
126             }
127           }
128         }
129       } else {
130         // Object created in sub-document
131         QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get());
132         if (aDocRoot.isValid()) {
133           // Check that new folders could appear
134           QStringList aNotEmptyFolders = listOfShowNotEmptyFolders(false);
135           foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
136             if ((aNotEmptyFolder.toStdString() == aObjType) && (aDoc->size(aObjType) == 1))
137               // Appears first object in folder which can not be shown empty
138               insertRow(myXMLReader->subFolderId(aObjType), aDocRoot);
139           }
140           int aRow = aDoc->index(aObject);
141           if (aRow != -1) {
142             int aNbSubFolders = foldersCount(aDoc.get());
143             if (aObjType == aSubType) {
144               // List of objects under document root
145               insertRow(aRow + aNbSubFolders, aDocRoot);
146             } else {
147               // List of objects under a folder
148               if (aRow != -1) {
149                 int aFolderId = folderId(aObjType, aDoc.get());
150                 if (aFolderId != -1) {
151                   QModelIndex aParentFolder = createIndex(aFolderId, 0, aDoc.get());
152                   insertRow(aRow, aParentFolder);
153                   emit dataChanged(aParentFolder, aParentFolder);
154                 }
155               }
156             }
157           }
158         } else {
159           rebuildDataTree();
160           break;
161         }
162       }
163     }
164     // Deleted object event ***********************
165   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
166     std::shared_ptr<ModelAPI_ObjectDeletedMessage> aUpdMsg =
167         std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
168     DocumentPtr aDoc = aUpdMsg->document();
169     std::set<std::string> aMsgGroups = aUpdMsg->groups();
170
171     /// Sort groups because RootType deletion has to be done after others
172     std::string aType = (aDoc == aRootDoc)? aRootType : aSubType;
173     std::list<std::string> aGroups;
174     std::set<std::string>::const_iterator aSetIt;
175     for (aSetIt = aMsgGroups.begin(); aSetIt != aMsgGroups.end(); ++aSetIt) {
176       std::string aGroup = (*aSetIt);
177       if (aGroup == aType)
178         aGroups.push_back(aGroup);
179       else
180         aGroups.push_front(aGroup);
181     }
182
183     std::list<std::string>::const_iterator aIt;
184     for (aIt = aGroups.begin(); aIt != aGroups.end(); ++aIt) {
185       std::string aGroup = (*aIt);
186       if (aDoc == aRootDoc) {  // If root objects
187         int aRow = aRootDoc->size(aGroup);
188         if (aGroup == aRootType) {
189           // Process root folder
190           removeRow(aRow + aNbFolders);
191           rebuildBranch(aNbFolders, aRow);
192         } else {
193           // Process root sub-folder
194           int aFolderId = myXMLReader->rootFolderId(aGroup);
195           if (aFolderId != -1) {
196             QModelIndex aFolderIndex = createIndex(aFolderId, 0, (void*)Q_NULLPTR);
197             removeRow(aRow, aFolderIndex);
198             //rebuildBranch(0, aRow);
199           }
200         }
201         // Check that some folders could erased
202         QStringList aNotEmptyFolders = listOfShowNotEmptyFolders();
203         foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
204           if ((aNotEmptyFolder.toStdString() == aGroup) && (aRootDoc->size(aGroup) == 0)) {
205             // Appears first object in folder which can not be shown empty
206             removeRow(myXMLReader->rootFolderId(aGroup));
207             //rebuildBranch(0, aNbFolders + aDoc->size(myXMLReader->rootType()));
208             break;
209           }
210         }
211       } else {
212         // Remove row for sub-document
213         QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get());
214         if (aDocRoot.isValid()) {
215           int aRow = aDoc->size(aGroup);
216           int aNbSubFolders = foldersCount(aDoc.get());
217           if (aGroup == aSubType) {
218             // List of objects under document root
219             removeRow(aRow + aNbSubFolders, aDocRoot);
220             rebuildBranch(aNbSubFolders, aRow, aDocRoot);
221           } else {
222             // List of objects under a folder
223             int aFolderId = folderId(aGroup, aDoc.get());
224             if (aFolderId != -1) {
225               QModelIndex aFolderRoot = createIndex(aFolderId, 0, aDoc.get());
226               removeRow(aRow, aFolderRoot);
227               //rebuildBranch(0, aRow, aFolderRoot);
228             }
229           }
230           // Check that some folders could disappear
231           QStringList aNotEmptyFolders = listOfShowNotEmptyFolders(false);
232           int aSize = aDoc->size(aGroup);
233           foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
234             if ((aNotEmptyFolder.toStdString() == aGroup) && (aSize == 0)) {
235               // Appears first object in folder which can not be shown empty
236               removeRow(myXMLReader->subFolderId(aGroup), aDocRoot);
237               //rebuildBranch(0, aNbSubFolders + aDoc->size(myXMLReader->subType()), aDocRoot);
238               break;
239             }
240           }
241         } else {
242           rebuildDataTree();
243           break;
244         }
245       }
246     }
247   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)) {
248     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
249         std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
250     std::set<ObjectPtr> aObjects = aUpdMsg->objects();
251
252     std::set<ObjectPtr>::const_iterator aIt;
253     std::string aObjType;
254     for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) {
255       ObjectPtr aObject = (*aIt);
256       if (aObject->data()->isValid()) {
257         FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObject);
258         if (aFeature.get() && aFeature->firstResult().get()
259           && (aFeature->firstResult()->groupName() == ModelAPI_ResultField::group())) {
260             ResultFieldPtr aResult =
261               std::dynamic_pointer_cast<ModelAPI_ResultField>(aFeature->firstResult());
262             QModelIndex aIndex = objectIndex(aResult);
263             removeRows(0, aResult->stepsSize(), aIndex);
264         } else {
265           QModelIndex aIndex = objectIndex(aObject);
266           if (aIndex.isValid()) {
267             emit dataChanged(aIndex, aIndex);
268           }
269         }
270       } else {
271         rebuildDataTree();
272         break;
273       }
274     }
275   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_ORDER_UPDATED)) {
276     std::shared_ptr<ModelAPI_OrderUpdatedMessage> aUpdMsg =
277         std::dynamic_pointer_cast<ModelAPI_OrderUpdatedMessage>(theMessage);
278     if (aUpdMsg->reordered().get()) {
279       DocumentPtr aDoc = aUpdMsg->reordered()->document();
280       std::string aGroup = aUpdMsg->reordered()->group();
281
282       QModelIndex aParent;
283       int aStartId = 0;
284       if (aDoc == aRootDoc) {
285         // Update a group under root
286         if (aGroup == myXMLReader->rootType()) // Update objects under root
287           aStartId = foldersCount();
288         else // Update objects in folder under root
289           aParent = createIndex(folderId(aGroup), 0, (void*)Q_NULLPTR);
290       } else {
291         // Update a sub-document
292         if (aGroup == myXMLReader->subType()) {
293           // Update sub-document root
294           aParent = findDocumentRootIndex(aDoc.get());
295           aStartId = foldersCount(aDoc.get());
296         } else
297           // update folder in sub-document
298           aParent = createIndex(folderId(aGroup, aDoc.get()), 0, aDoc.get());
299       }
300       int aChildNb = rowCount(aParent);
301       rebuildBranch(aStartId, aChildNb - aStartId, aParent);
302     } else {
303       rebuildDataTree();
304     }
305   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_DOCUMENT_CHANGED)) {
306     DocumentPtr aDoc = ModelAPI_Session::get()->activeDocument();
307     if (aDoc != aRootDoc) {
308       QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get());
309       if (aDocRoot.isValid())
310         emit dataChanged(aDocRoot, aDocRoot);
311       else
312         // We have got a new document
313         rebuildDataTree();
314     }
315   }
316 }
317
318 //******************************************************
319 void XGUI_DataModel::clear()
320 {
321   beginResetModel();
322   endResetModel();
323 }
324
325 //******************************************************
326 void XGUI_DataModel::rebuildDataTree()
327 {
328   beginResetModel();
329   endResetModel();
330   emit treeRebuilt();
331 }
332
333 //******************************************************
334 ObjectPtr XGUI_DataModel::object(const QModelIndex& theIndex) const
335 {
336   if (theIndex.internalId() == 0) // this is a folder
337     return ObjectPtr();
338   ModelAPI_Object* aObj =
339     dynamic_cast<ModelAPI_Object*>((ModelAPI_Entity*)theIndex.internalPointer());
340   if (!aObj)
341     return ObjectPtr();
342   if (getSubDocument(aObj)) // the selected index is a folder of sub-document
343     return ObjectPtr();
344
345   return aObj->data()->owner();
346 }
347
348 //******************************************************
349 QModelIndex XGUI_DataModel::objectIndex(const ObjectPtr theObject) const
350 {
351   std::string aType = theObject->groupName();
352   DocumentPtr aDoc = theObject->document();
353   int aRow = aDoc->index(theObject);
354   if (aRow == -1) {
355     // it could be a part of complex object
356     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
357     if (aFeature.get()) {
358       CompositeFeaturePtr aCompFea = ModelAPI_Tools::compositeOwner(aFeature);
359       if (aCompFea.get()) {
360         for (int i = 0; i < aCompFea->numberOfSubs(true); i++) {
361           if (aCompFea->subFeature(i, true) == theObject) {
362             aRow = i;
363             break;
364           }
365         }
366       }
367     } else {
368       ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
369       if (aResult.get()) {
370         ResultCompSolidPtr aCompRes = ModelAPI_Tools::compSolidOwner(aResult);
371         if (aCompRes.get()) {
372           for (int i = 0; i < aCompRes->numberOfSubs(true); i++) {
373             if (aCompRes->subResult(i, true) == theObject) {
374               aRow = i;
375               break;
376             }
377           }
378         }
379       }
380     }
381     if (aRow == -1)
382       return QModelIndex();
383     else
384       return createIndex(aRow, 0, theObject.get());
385   }
386   SessionPtr aSession = ModelAPI_Session::get();
387   DocumentPtr aRootDoc = aSession->moduleDocument();
388   if (aDoc == aRootDoc && myXMLReader->rootType() == aType) {
389     // The object from root document
390     aRow += foldersCount();
391   } else if (myXMLReader->subType() == aType) {
392     // The object from sub document
393     aRow += foldersCount(aDoc.get());
394   }
395   return createIndex(aRow, 0, theObject.get());
396 }
397
398 //******************************************************
399 QVariant XGUI_DataModel::data(const QModelIndex& theIndex, int theRole) const
400 {
401   SessionPtr aSession = ModelAPI_Session::get();
402   DocumentPtr aRootDoc = aSession->moduleDocument();
403   int aNbFolders = foldersCount();
404   int theIndexRow = theIndex.row();
405
406   if ((theRole == Qt::DecorationRole) && (theIndex == lastHistoryIndex()))
407     return QIcon(":pictures/arrow.png");
408
409   if (theIndex.column() == 1)
410     return QVariant();
411
412   quintptr aParentId = theIndex.internalId();
413   if (aParentId == 0) { // root folders
414     switch (theRole) {
415       case Qt::DisplayRole:
416         return QString(myXMLReader->rootFolderName(theIndexRow).c_str()) +
417           QString(" (%1)").arg(rowCount(theIndex));
418       case Qt::DecorationRole:
419         return QIcon(myXMLReader->rootFolderIcon(theIndexRow).c_str());
420       case Qt::ForegroundRole:
421         {
422           Qt::ItemFlags aFlags = theIndex.flags();
423           if (aFlags == Qt::ItemFlags())
424             return QBrush(DISABLED_COLOR);
425           if (!aFlags.testFlag(Qt::ItemIsEditable))
426             return QBrush(SELECTABLE_COLOR);
427         }
428         return ACTIVE_COLOR;
429     }
430   } else { // an object or sub-document
431     if (theRole == Qt::ForegroundRole) {
432       Qt::ItemFlags aFlags = theIndex.flags();
433       if (aFlags == Qt::ItemFlags())
434         return QBrush(DISABLED_COLOR);
435       if (!aFlags.testFlag(Qt::ItemIsEditable))
436         return QBrush(SELECTABLE_COLOR);
437       return ACTIVE_COLOR;
438     }
439
440     ModelAPI_Document* aSubDoc = getSubDocument(theIndex.internalPointer());
441     if (aSubDoc) { // this is a folder of sub document
442       QIntList aMissedIdx = missedFolderIndexes(aSubDoc);
443       int aRow = theIndexRow;
444       while (aMissedIdx.contains(aRow))
445         aRow++;
446       if (aRow < myXMLReader->subFoldersNumber()) {
447         switch (theRole) {
448           case Qt::DisplayRole:
449             return QString(myXMLReader->subFolderName(aRow).c_str()) +
450               QString(" (%1)").arg(rowCount(theIndex));
451           case Qt::DecorationRole:
452             return QIcon(myXMLReader->subFolderIcon(aRow).c_str());
453         }
454       }
455     } else {
456       ModelAPI_Object* aObj =
457         dynamic_cast<ModelAPI_Object*>((ModelAPI_Entity*)theIndex.internalPointer());
458       if (aObj) {
459         switch (theRole) {
460         case Qt::DisplayRole:
461           {
462             if (aObj->groupName() == ModelAPI_ResultParameter::group()) {
463               ModelAPI_ResultParameter* aParam = dynamic_cast<ModelAPI_ResultParameter*>(aObj);
464               AttributeDoublePtr aValueAttribute =
465                 aParam->data()->real(ModelAPI_ResultParameter::VALUE());
466               QString aVal = QString::number(aValueAttribute->value());
467               QString aTitle = QString(aObj->data()->name().c_str());
468               return aTitle + " = " + aVal;
469             }
470             QString aSuffix;
471             if (aObj->groupName() == myXMLReader->subType()) {
472               ResultPartPtr aPartRes = getPartResult(aObj);
473               if (aPartRes.get()) {
474                 if (aPartRes->partDoc().get() == NULL)
475                   aSuffix = " (Not loaded)";
476               }
477             }
478             return aObj->data()->name().c_str() + aSuffix;
479           }
480         case Qt::DecorationRole:
481           return ModuleBase_IconFactory::get()->getIcon(object(theIndex));
482         }
483       } else {
484         switch (theRole) {
485         case Qt::DisplayRole:
486           {
487             ModelAPI_ResultField::ModelAPI_FieldStep* aStep =
488               dynamic_cast<ModelAPI_ResultField::ModelAPI_FieldStep*>
489               ((ModelAPI_Entity*)theIndex.internalPointer());
490             if (aStep) {
491               return "Step " + QString::number(aStep->id() + 1) + " " +
492                 aStep->field()->textLine(aStep->id()).c_str();
493             }
494           }
495           break;
496         }
497       }
498     }
499   }
500   return QVariant();
501 }
502
503 //******************************************************
504 QVariant XGUI_DataModel::headerData(int theSection, Qt::Orientation theOrient, int theRole) const
505 {
506   return QVariant();
507 }
508
509 //******************************************************
510 int XGUI_DataModel::rowCount(const QModelIndex& theParent) const
511 {
512   SessionPtr aSession = ModelAPI_Session::get();
513   if (!aSession->hasModuleDocument())
514     return 0;
515   DocumentPtr aRootDoc = aSession->moduleDocument();
516
517   if (!theParent.isValid()) {
518     // Return number of items in root
519     int aNbFolders = foldersCount();
520     int aNbItems = 0;
521     std::string aType = myXMLReader->rootType();
522     if (!aType.empty())
523       aNbItems = aRootDoc->size(aType);
524     return aNbFolders + aNbItems;
525   }
526
527   quintptr aId = theParent.internalId();
528   if (aId == 0) {
529     // this is a folder under root
530     int aParentPos = theParent.row();
531     std::string aType = myXMLReader->rootFolderType(aParentPos);
532     return aRootDoc->size(aType);
533   } else {
534     // It is an object which could have children
535     ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
536     if (aDoc) {
537       // a folder of sub-document
538       QIntList aMissedIdx = missedFolderIndexes(aDoc);
539       int aRow = theParent.row();
540       while (aMissedIdx.contains(aRow))
541         aRow++;
542       if (aRow < myXMLReader->subFoldersNumber()) {
543         std::string aType = myXMLReader->subFolderType(aRow);
544         return aDoc->size(aType);
545       }
546     } else {
547       ModelAPI_Object* aObj =
548         dynamic_cast<ModelAPI_Object*>((ModelAPI_Entity*)theParent.internalPointer());
549       // Check for Part feature
550       ResultPartPtr aPartRes = getPartResult(aObj);
551       if (aPartRes.get()) {
552         DocumentPtr aSubDoc = aPartRes->partDoc();
553         if (!aSubDoc.get())
554           return 0;
555
556         int aNbSubFolders = foldersCount(aSubDoc.get());
557         int aNbSubItems = 0;
558         std::string aSubType = myXMLReader->subType();
559         if (!aSubType.empty())
560           aNbSubItems = aSubDoc->size(aSubType);
561         return aNbSubItems + aNbSubFolders;
562       } else {
563         // Check for composite object
564         ModelAPI_CompositeFeature* aCompFeature = dynamic_cast<ModelAPI_CompositeFeature*>(aObj);
565         if (aCompFeature)
566           return aCompFeature->numberOfSubs(true);
567         ModelAPI_ResultCompSolid* aCompRes = dynamic_cast<ModelAPI_ResultCompSolid*>(aObj);
568         if (aCompRes)
569           return aCompRes->numberOfSubs(true);
570         ModelAPI_ResultField* aFieldRes = dynamic_cast<ModelAPI_ResultField*>(aObj);
571         if (aFieldRes)
572           return aFieldRes->stepsSize();
573       }
574     }
575   }
576   return 0;
577 }
578
579 //******************************************************
580 int XGUI_DataModel::columnCount(const QModelIndex& theParent) const
581 {
582   return 2;
583 }
584
585 //******************************************************
586 QModelIndex XGUI_DataModel::index(int theRow, int theColumn, const QModelIndex &theParent) const
587 {
588   SessionPtr aSession = ModelAPI_Session::get();
589   DocumentPtr aRootDoc = aSession->moduleDocument();
590   int aNbFolders = foldersCount();
591
592   QModelIndex aIndex;
593
594   if (!theParent.isValid()) {
595     if (theRow < aNbFolders) // Return first level folder index
596       return createIndex(theRow, theColumn, (void*)Q_NULLPTR);
597     else { // return object under root index
598       std::string aType = myXMLReader->rootType();
599       int aObjId = theRow - aNbFolders;
600       if (aObjId < aRootDoc->size(aType)) {
601         ObjectPtr aObj = aRootDoc->object(aType, aObjId);
602         aIndex = objectIndex(aObj);
603       }
604     }
605   } else {
606     quintptr aId = theParent.internalId();
607     int aParentPos = theParent.row();
608     if (aId == 0) { // return object index inside of first level of folders
609       std::string aType = myXMLReader->rootFolderType(aParentPos);
610       if (theRow < aRootDoc->size(aType)) {
611         ObjectPtr aObj = aRootDoc->object(aType, theRow);
612         aIndex = objectIndex(aObj);
613       }
614     } else {
615       // It is an object which could have children
616       ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
617       if (aDoc) {
618         // It is a folder of sub-document
619         int aParentRow = aParentPos;
620         QIntList aMissedIdx = missedFolderIndexes(aDoc);
621         while (aMissedIdx.contains(aParentRow))
622           aParentRow++;
623         if (aParentRow < myXMLReader->subFoldersNumber()) {
624           std::string aType = myXMLReader->subFolderType(aParentRow);
625           if (theRow < aDoc->size(aType)) {
626             ObjectPtr aObj = aDoc->object(aType, theRow);
627             aIndex = objectIndex(aObj);
628           }
629         }
630       } else {
631         ModelAPI_Object* aParentObj =
632           dynamic_cast<ModelAPI_Object*>((ModelAPI_Entity*)theParent.internalPointer());
633
634         // Check for Part feature
635         ResultPartPtr aPartRes = getPartResult(aParentObj);
636         if (aPartRes.get()) {
637           DocumentPtr aSubDoc = aPartRes->partDoc();
638           int aNbSubFolders = foldersCount(aSubDoc.get());
639           if (theRow < aNbSubFolders) { // Create a Folder of sub-document
640             aIndex = createIndex(theRow, theColumn, aSubDoc.get());
641           } else {
642             // this is an object under sub document root
643             std::string aType = myXMLReader->subType();
644             ObjectPtr aObj = aSubDoc->object(aType, theRow - aNbSubFolders);
645             aIndex = objectIndex(aObj);
646           }
647         } else {
648           // Check for composite object
649           ModelAPI_CompositeFeature* aCompFeature =
650             dynamic_cast<ModelAPI_CompositeFeature*>(aParentObj);
651           if (aCompFeature) {
652             aIndex = objectIndex(aCompFeature->subFeature(theRow));
653           } else {
654             ModelAPI_ResultCompSolid* aCompRes =
655               dynamic_cast<ModelAPI_ResultCompSolid*>(aParentObj);
656             if (aCompRes)
657               aIndex = objectIndex(aCompRes->subResult(theRow));
658             else {
659               ModelAPI_ResultField* aFieldRes =
660                 dynamic_cast<ModelAPI_ResultField*>(aParentObj);
661               if (aFieldRes) {
662                 aIndex = createIndex(theRow, 0, aFieldRes->step(theRow));
663               }
664             }
665           }
666         }
667       }
668     }
669   }
670   if (theColumn != 0)
671     return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
672   return aIndex;
673 }
674
675 //******************************************************
676 static QModelIndex MYLastDeleted;
677 QModelIndex XGUI_DataModel::parent(const QModelIndex& theIndex) const
678 {
679   if (!theIndex.isValid())
680     return QModelIndex();
681   // To avoid additional request about index which was already deleted
682   if (theIndex == MYLastDeleted)
683     return QModelIndex();
684
685   SessionPtr aSession = ModelAPI_Session::get();
686   quintptr aId = theIndex.internalId();
687   if (aId != 0) { // The object is not a root folder
688     ModelAPI_Document* aDoc = getSubDocument(theIndex.internalPointer());
689     if (aDoc) {
690       // It is a folder of sub-document
691       return findDocumentRootIndex(aDoc);
692     }
693     ObjectPtr aObj = object(theIndex);
694     if (!aObj.get()) {
695       // It can b e a step of a field
696       ModelAPI_ResultField::ModelAPI_FieldStep* aStep =
697         dynamic_cast<ModelAPI_ResultField::ModelAPI_FieldStep*>
698         ((ModelAPI_Entity*)theIndex.internalPointer());
699       if (aStep) {
700         ModelAPI_ResultField* aField = aStep->field();
701         DocumentPtr aDoc = aSession->activeDocument();
702         ObjectPtr aFld;
703         for(int i = 0; i < aDoc->size(ModelAPI_ResultField::group()); i++) {
704           aFld = aDoc->object(ModelAPI_ResultField::group(), i);
705           if (aFld.get() == aField)
706             return objectIndex(aFld);
707         }
708       }
709       // To avoid additional request about index which was already deleted
710       // If deleted it causes a crash on delete object from Part
711       MYLastDeleted = theIndex;
712       return QModelIndex();
713     }
714     // Check is it object a sub-object of a complex object
715     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
716     if (aFeature.get()) {
717       CompositeFeaturePtr aCompFea = ModelAPI_Tools::compositeOwner(aFeature);
718       if (aCompFea.get()) {
719         return objectIndex(aCompFea);
720       }
721     }
722     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
723     if (aResult.get()) {
724       ResultCompSolidPtr aCompRes = ModelAPI_Tools::compSolidOwner(aResult);
725       if (aCompRes.get()) {
726         return objectIndex(aCompRes);
727       }
728     }
729     // Use as ordinary object
730     std::string aType = aObj->groupName();
731     DocumentPtr aRootDoc = aSession->moduleDocument();
732     DocumentPtr aSubDoc = aObj->document();
733     if (aSubDoc == aRootDoc) {
734       if (aType == myXMLReader->rootType())
735         return QModelIndex();
736       else {
737         // return first level of folder index
738         int aFolderId = myXMLReader->rootFolderId(aType);
739         // Items in a one row must have the same parent
740         return createIndex(aFolderId, 0, (void*)Q_NULLPTR);
741       }
742     } else {
743       if (aType == myXMLReader->subType())
744         return findDocumentRootIndex(aSubDoc.get());
745       else {
746         // return first level of folder index
747         int aFolderId = folderId(aType, aSubDoc.get());
748         // Items in a one row must have the same parent
749         return createIndex(aFolderId, 0, aSubDoc.get());
750       }
751     }
752   }
753   return QModelIndex();
754 }
755
756 //******************************************************
757 bool XGUI_DataModel::hasChildren(const QModelIndex& theParent) const
758 {
759   return rowCount(theParent) > 0;
760 }
761
762 //******************************************************
763 bool XGUI_DataModel::insertRows(int theRow, int theCount, const QModelIndex& theParent)
764 {
765   beginInsertRows(theParent, theRow, theRow + theCount - 1);
766   endInsertRows();
767
768   return true;
769 }
770
771 //******************************************************
772 bool XGUI_DataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent)
773 {
774   beginRemoveRows(theParent, theRow, theRow + theCount - 1);
775   endRemoveRows();
776   return true;
777 }
778
779 //******************************************************
780 Qt::ItemFlags XGUI_DataModel::flags(const QModelIndex& theIndex) const
781 {
782   quintptr aIt = theIndex.internalId();
783   ModelAPI_Object* aObj = 0;
784   ModelAPI_Document* aDoc = 0;
785   SessionPtr aSession = ModelAPI_Session::get();
786   DocumentPtr aActiveDoc = aSession->activeDocument();
787
788   Qt::ItemFlags aNullFlag;
789   Qt::ItemFlags aDefaultFlag = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
790   Qt::ItemFlags aEditingFlag = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
791
792
793   if (aIt == 0) {
794     // Folders under root
795     DocumentPtr aRootDoc = aSession->moduleDocument();
796     if (aRootDoc != aActiveDoc)
797       return aDefaultFlag;
798   } else {
799     aDoc = getSubDocument(theIndex.internalPointer());
800     if (!aDoc)
801       aObj = dynamic_cast<ModelAPI_Object*>((ModelAPI_Entity*)theIndex.internalPointer());
802   }
803
804   if (aObj) {
805     // An object
806     if (aObj->isDisabled())
807       return theIndex.column() == 1? Qt::ItemIsSelectable : aNullFlag;
808
809     if (aSession->moduleDocument() != aObj->document())
810       if (aActiveDoc != aObj->document())
811         return theIndex.column() == 1? Qt::ItemIsSelectable : aNullFlag;
812
813     bool isCompositeSub = false;
814     // An object which is sub-object of a composite object can not be accessible in column 1
815     if (theIndex.column() == 1) {
816       ObjectPtr aObjPtr = aObj->data()->owner();
817       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObjPtr);
818       if (aFeature.get()) {
819         CompositeFeaturePtr aCompFea = ModelAPI_Tools::compositeOwner(aFeature);
820         if (aCompFea.get())
821           isCompositeSub = true;
822       } else {
823         ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aObjPtr);
824         if (aResult.get()) {
825           ResultCompSolidPtr aCompRes = ModelAPI_Tools::compSolidOwner(aResult);
826           if (aCompRes.get())
827             isCompositeSub = true;
828         }
829       }
830     }
831     if (isCompositeSub)
832       return Qt::ItemIsSelectable;
833
834     if (aObj->document() != aActiveDoc) {
835       // The object could be a root of sub-tree
836       ResultPartPtr aPartRes = getPartResult(aObj);
837       if (aPartRes.get()) {
838         if (aPartRes->partDoc() == aActiveDoc)
839           return aEditingFlag;
840       }
841       return aDefaultFlag;
842     }
843   } else if (aDoc) {
844     // A folder under sub-document
845     if (aActiveDoc.get() != aDoc)
846       return aNullFlag;
847   }
848   return aEditingFlag;
849 }
850
851 //******************************************************
852 QModelIndex XGUI_DataModel::findDocumentRootIndex(const ModelAPI_Document* theDoc) const
853 {
854   SessionPtr aSession = ModelAPI_Session::get();
855   DocumentPtr aRootDoc = aSession->moduleDocument();
856   if (myXMLReader->isAttachToResult()) { // If document is attached to result
857     int aNb = aRootDoc->size(ModelAPI_ResultPart::group());
858     ObjectPtr aObj;
859     ResultPartPtr aPartRes;
860     for (int i = 0; i < aNb; i++) {
861       aObj = aRootDoc->object(ModelAPI_ResultPart::group(), i);
862       aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
863       if (aPartRes.get() && (aPartRes->partDoc().get() == theDoc)) {
864         int aRow = i;
865         if (myXMLReader->rootType() == ModelAPI_Feature::group()) {
866           aRow += foldersCount();
867         }
868         return createIndex(aRow, 0, aObj.get());
869       }
870     }
871   } else { // If document is attached to feature
872     int aNb = aRootDoc->size(ModelAPI_Feature::group());
873     ObjectPtr aObj;
874     ResultPartPtr aPartRes;
875     for (int i = 0; i < aNb; i++) {
876       aObj = aRootDoc->object(ModelAPI_Feature::group(), i);
877       aPartRes = getPartResult(aObj.get());
878       if (aPartRes.get() && (aPartRes->partDoc().get() == theDoc)) {
879         int aRow = i;
880         if (myXMLReader->rootType() == ModelAPI_Feature::group())
881           aRow += foldersCount();
882         return createIndex(aRow, 0, aObj.get());
883       }
884     }
885   }
886   return QModelIndex();
887 }
888
889 //******************************************************
890 QModelIndex XGUI_DataModel::documentRootIndex(DocumentPtr theDoc) const
891 {
892   SessionPtr aSession = ModelAPI_Session::get();
893   DocumentPtr aRootDoc = aSession->moduleDocument();
894   if (theDoc == aRootDoc)
895     return QModelIndex();
896   else
897     return findDocumentRootIndex(theDoc.get());
898 }
899
900 //******************************************************
901 int XGUI_DataModel::foldersCount(ModelAPI_Document* theDoc) const
902 {
903   int aNb = 0;
904   SessionPtr aSession = ModelAPI_Session::get();
905   DocumentPtr aRootDoc = aSession->moduleDocument();
906   if ((theDoc == 0) || (theDoc == aRootDoc.get())) {
907     for (int i = 0; i < myXMLReader->rootFoldersNumber(); i++) {
908       if (myXMLReader->rootShowEmpty(i))
909         aNb++;
910       else {
911         if (aRootDoc->size(myXMLReader->rootFolderType(i)) > 0)
912           aNb++;
913       }
914     }
915   } else {
916     for (int i = 0; i < myXMLReader->subFoldersNumber(); i++) {
917       if (myXMLReader->subShowEmpty(i))
918         aNb++;
919       else {
920         if (theDoc->size(myXMLReader->subFolderType(i)) > 0)
921           aNb++;
922       }
923     }
924   }
925   return aNb;
926 }
927
928
929 //******************************************************
930 QIntList XGUI_DataModel::missedFolderIndexes(ModelAPI_Document* theDoc) const
931 {
932   QIntList aList;
933   SessionPtr aSession = ModelAPI_Session::get();
934   DocumentPtr aRootDoc = aSession->moduleDocument();
935   if ((theDoc == 0) || (theDoc == aRootDoc.get())) {
936     for (int i = 0; i < myXMLReader->rootFoldersNumber(); i++) {
937       if (!myXMLReader->rootShowEmpty(i)) {
938         if (aRootDoc->size(myXMLReader->rootFolderType(i)) == 0)
939           aList.append(i);
940       }
941     }
942   } else {
943     for (int i = 0; i < myXMLReader->subFoldersNumber(); i++) {
944       if (!myXMLReader->subShowEmpty(i)) {
945         if (theDoc->size(myXMLReader->subFolderType(i)) == 0)
946           aList.append(i);
947       }
948     }
949   }
950   return aList;
951 }
952
953
954 //******************************************************
955 QStringList XGUI_DataModel::listOfShowNotEmptyFolders(bool fromRoot) const
956 {
957   QStringList aResult;
958   if (fromRoot) {
959     for (int i = 0; i < myXMLReader->rootFoldersNumber(); i++) {
960       if (!myXMLReader->rootShowEmpty(i))
961         aResult << myXMLReader->rootFolderType(i).c_str();
962     }
963   } else {
964     for (int i = 0; i < myXMLReader->subFoldersNumber(); i++) {
965       if (!myXMLReader->subShowEmpty(i))
966         aResult << myXMLReader->subFolderType(i).c_str();
967     }
968   }
969   return aResult;
970 }
971
972 //******************************************************
973 QModelIndex XGUI_DataModel::lastHistoryIndex() const
974 {
975   SessionPtr aSession = ModelAPI_Session::get();
976   DocumentPtr aCurDoc = aSession->activeDocument();
977   FeaturePtr aFeature = aCurDoc->currentFeature(true);
978   if (aFeature.get()) {
979     QModelIndex aInd = objectIndex(aFeature);
980     return createIndex(aInd.row(), 1, aInd.internalPointer());
981   } else {
982     if (aCurDoc == aSession->moduleDocument())
983       return createIndex(foldersCount() - 1, 1, -1);
984     else
985       return createIndex(foldersCount(aCurDoc.get()) - 1, 1, aCurDoc.get());
986   }
987 }
988
989 //******************************************************
990 int XGUI_DataModel::folderId(std::string theType, ModelAPI_Document* theDoc) const
991 {
992   SessionPtr aSession = ModelAPI_Session::get();
993   ModelAPI_Document* aDoc = theDoc;
994   if (aDoc == 0)
995     aDoc = aSession->moduleDocument().get();
996
997   bool aUseSubDoc = (aDoc != aSession->moduleDocument().get());
998
999   int aRes = -1;
1000   if (aUseSubDoc) {
1001     int aId = myXMLReader->subFolderId(theType);
1002     aRes = aId;
1003     for (int i = 0; i < aId; i++) {
1004       if (!myXMLReader->subShowEmpty(i)) {
1005         if (aDoc->size(myXMLReader->subFolderType(i)) == 0)
1006           aRes--;
1007       }
1008     }
1009   } else {
1010     int aId = myXMLReader->rootFolderId(theType);
1011     aRes = aId;
1012     for (int i = 0; i < aId; i++) {
1013       if (!myXMLReader->rootShowEmpty(i)) {
1014         if (aDoc->size(myXMLReader->rootFolderType(i)) == 0)
1015           aRes--;
1016       }
1017     }
1018   }
1019   return aRes;
1020 }
1021
1022 //******************************************************
1023 void XGUI_DataModel::rebuildBranch(int theRow, int theCount, const QModelIndex& theParent)
1024 {
1025   if (theCount > 0) {
1026     removeRows(theRow, theCount, theParent);
1027     insertRows(theRow, theCount, theParent);
1028   }
1029 }
1030
1031 //******************************************************
1032 //bool XGUI_DataModel::blockEventsProcessing(const bool theState)
1033 //{
1034 //  bool aPreviousState = myIsEventsProcessingBlocked;
1035 //  myIsEventsProcessingBlocked = theState;
1036 //  return aPreviousState;
1037 //}