1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
3 // File: ModuleBase_IDocumentDataModel.cpp
4 // Created: 28 Apr 2015
5 // Author: Vitaly SMETANNIKOV
7 #include "XGUI_DataModel.h"
9 #include <ModuleBase_IconFactory.h>
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>
22 #include <Config_FeatureMessage.h>
23 #include <Config_DataModelReader.h>
25 #include <Events_Loop.h>
30 #define ACTIVE_COLOR QColor(Qt::black)
31 //#define ACTIVE_COLOR QColor(0,72,140)
32 //#define PASSIVE_COLOR Qt::black
34 /// Returns ResultPart object if the given object is a Part feature
35 /// Otherwise returns NULL
37 #define SELECTABLE_COLOR QColor(80, 80, 80)
38 #define DISABLED_COLOR QColor(200, 200, 200)
41 ResultPartPtr getPartResult(ModelAPI_Object* theObj)
43 ModelAPI_Feature* aFeature = dynamic_cast<ModelAPI_Feature*>(theObj);
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())
53 return ResultPartPtr();
56 /// Returns pointer on document if the given object is document object
57 ModelAPI_Document* getSubDocument(void* theObj)
59 ModelAPI_Document* aDoc = dynamic_cast<ModelAPI_Document*>((ModelAPI_Entity*)theObj);
66 // Constructor *************************************************
67 XGUI_DataModel::XGUI_DataModel(QObject* theParent) : QAbstractItemModel(theParent)//,
68 //myIsEventsProcessingBlocked(false)
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));
78 XGUI_DataModel::~XGUI_DataModel()
82 //******************************************************
83 void XGUI_DataModel::processEvent(const std::shared_ptr<Events_Message>& theMessage)
85 //if (myIsEventsProcessingBlocked)
87 DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
88 std::string aRootType = myXMLReader->rootType();
89 std::string aSubType = myXMLReader->subType();
90 int aNbFolders = foldersCount();
92 // Created object event *******************
93 if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)) {
94 std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
95 std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
96 std::set<ObjectPtr> aObjects = aUpdMsg->objects();
98 std::set<ObjectPtr>::const_iterator aIt;
100 for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) {
101 ObjectPtr aObject = (*aIt);
102 // We do not show objects which does not need to be shown in object browser
103 if (!aObject->isInHistory())
106 aObjType = aObject->groupName();
107 DocumentPtr aDoc = aObject->document();
108 if (aDoc == aRootDoc) {
109 // Check that new folders could appear
110 QStringList aNotEmptyFolders = listOfShowNotEmptyFolders();
111 foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
112 if ((aNotEmptyFolder.toStdString() == aObjType) && (aRootDoc->size(aObjType) == 1))
113 // Appears first object in folder which can not be shown empty
114 insertRow(myXMLReader->rootFolderId(aObjType));
117 int aRow = aRootDoc->size(aObjType) - 1;
119 if (aObjType == aRootType) {
120 insertRow(aRow + aNbFolders + 1);
122 int aFolderId = myXMLReader->rootFolderId(aObjType);
123 if (aFolderId != -1) {
124 insertRow(aRow, createIndex(aFolderId, 0, (void*)Q_NULLPTR));
129 // Object created in sub-document
130 QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get());
131 if (aDocRoot.isValid()) {
132 // Check that new folders could appear
133 QStringList aNotEmptyFolders = listOfShowNotEmptyFolders(false);
134 foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
135 if ((aNotEmptyFolder.toStdString() == aObjType) && (aDoc->size(aObjType) == 1))
136 // Appears first object in folder which can not be shown empty
137 insertRow(myXMLReader->subFolderId(aObjType), aDocRoot);
139 int aRow = aDoc->index(aObject);
141 int aNbSubFolders = foldersCount(aDoc.get());
142 if (aObjType == aSubType) {
143 // List of objects under document root
144 insertRow(aRow + aNbSubFolders, aDocRoot);
146 // List of objects under a folder
148 int aFolderId = folderId(aObjType, aDoc.get());
149 if (aFolderId != -1) {
150 QModelIndex aParentFolder = createIndex(aFolderId, 0, aDoc.get());
151 insertRow(aRow, aParentFolder);
152 emit dataChanged(aParentFolder, aParentFolder);
163 // Deleted object event ***********************
164 } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
165 std::shared_ptr<ModelAPI_ObjectDeletedMessage> aUpdMsg =
166 std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
167 DocumentPtr aDoc = aUpdMsg->document();
168 std::set<std::string> aMsgGroups = aUpdMsg->groups();
170 /// Sort groups because RootType deletion has to be done after others
171 std::string aType = (aDoc == aRootDoc)? aRootType : aSubType;
172 std::list<std::string> aGroups;
173 std::set<std::string>::const_iterator aSetIt;
174 for (aSetIt = aMsgGroups.begin(); aSetIt != aMsgGroups.end(); ++aSetIt) {
175 std::string aGroup = (*aSetIt);
177 aGroups.push_back(aGroup);
179 aGroups.push_front(aGroup);
182 std::list<std::string>::const_iterator aIt;
183 for (aIt = aGroups.begin(); aIt != aGroups.end(); ++aIt) {
184 std::string aGroup = (*aIt);
185 if (aDoc == aRootDoc) { // If root objects
186 int aRow = aRootDoc->size(aGroup);
187 if (aGroup == aRootType) {
188 // Process root folder
189 removeRow(aRow + aNbFolders);
190 rebuildBranch(aNbFolders, aRow);
192 // Process root sub-folder
193 int aFolderId = myXMLReader->rootFolderId(aGroup);
194 if (aFolderId != -1) {
195 QModelIndex aFolderIndex = createIndex(aFolderId, 0, (void*)Q_NULLPTR);
196 removeRow(aRow, aFolderIndex);
197 //rebuildBranch(0, aRow);
200 // Check that some folders could erased
201 QStringList aNotEmptyFolders = listOfShowNotEmptyFolders();
202 foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
203 if ((aNotEmptyFolder.toStdString() == aGroup) && (aRootDoc->size(aGroup) == 0)) {
204 // Appears first object in folder which can not be shown empty
205 removeRow(myXMLReader->rootFolderId(aGroup));
206 //rebuildBranch(0, aNbFolders + aDoc->size(myXMLReader->rootType()));
211 // Remove row for sub-document
212 QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get());
213 if (aDocRoot.isValid()) {
214 int aRow = aDoc->size(aGroup);
215 int aNbSubFolders = foldersCount(aDoc.get());
216 if (aGroup == aSubType) {
217 // List of objects under document root
218 removeRow(aRow + aNbSubFolders, aDocRoot);
219 rebuildBranch(aNbSubFolders, aRow, aDocRoot);
221 // List of objects under a folder
222 int aFolderId = folderId(aGroup, aDoc.get());
223 if (aFolderId != -1) {
224 QModelIndex aFolderRoot = createIndex(aFolderId, 0, aDoc.get());
225 removeRow(aRow, aFolderRoot);
226 //rebuildBranch(0, aRow, aFolderRoot);
229 // Check that some folders could disappear
230 QStringList aNotEmptyFolders = listOfShowNotEmptyFolders(false);
231 int aSize = aDoc->size(aGroup);
232 foreach (QString aNotEmptyFolder, aNotEmptyFolders) {
233 if ((aNotEmptyFolder.toStdString() == aGroup) && (aSize == 0)) {
234 // Appears first object in folder which can not be shown empty
235 removeRow(myXMLReader->subFolderId(aGroup), aDocRoot);
236 //rebuildBranch(0, aNbSubFolders + aDoc->size(myXMLReader->subType()), aDocRoot);
246 } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)) {
247 std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
248 std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
249 std::set<ObjectPtr> aObjects = aUpdMsg->objects();
251 std::set<ObjectPtr>::const_iterator aIt;
252 std::string aObjType;
253 for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) {
254 ObjectPtr aObject = (*aIt);
255 if (aObject->data()->isValid()) {
256 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObject);
257 if (aFeature.get() && aFeature->firstResult().get()
258 && (aFeature->firstResult()->groupName() == ModelAPI_ResultField::group())) {
259 ResultFieldPtr aResult =
260 std::dynamic_pointer_cast<ModelAPI_ResultField>(aFeature->firstResult());
261 QModelIndex aIndex = objectIndex(aResult);
262 removeRows(0, aResult->stepsSize(), aIndex);
264 QModelIndex aIndex = objectIndex(aObject);
265 if (aIndex.isValid()) {
266 emit dataChanged(aIndex, aIndex);
274 } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_ORDER_UPDATED)) {
275 std::shared_ptr<ModelAPI_OrderUpdatedMessage> aUpdMsg =
276 std::dynamic_pointer_cast<ModelAPI_OrderUpdatedMessage>(theMessage);
277 if (aUpdMsg->reordered().get()) {
278 DocumentPtr aDoc = aUpdMsg->reordered()->document();
279 std::string aGroup = aUpdMsg->reordered()->group();
283 if (aDoc == aRootDoc) {
284 // Update a group under root
285 if (aGroup == myXMLReader->rootType()) // Update objects under root
286 aStartId = foldersCount();
287 else // Update objects in folder under root
288 aParent = createIndex(folderId(aGroup), 0, (void*)Q_NULLPTR);
290 // Update a sub-document
291 if (aGroup == myXMLReader->subType()) {
292 // Update sub-document root
293 aParent = findDocumentRootIndex(aDoc.get());
294 aStartId = foldersCount(aDoc.get());
296 // update folder in sub-document
297 aParent = createIndex(folderId(aGroup, aDoc.get()), 0, aDoc.get());
299 int aChildNb = rowCount(aParent);
300 rebuildBranch(aStartId, aChildNb - aStartId, aParent);
304 } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_DOCUMENT_CHANGED)) {
305 DocumentPtr aDoc = ModelAPI_Session::get()->activeDocument();
306 if (aDoc != aRootDoc) {
307 QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get());
308 if (aDocRoot.isValid())
309 emit dataChanged(aDocRoot, aDocRoot);
311 // We have got a new document
317 //******************************************************
318 void XGUI_DataModel::clear()
323 //******************************************************
324 void XGUI_DataModel::rebuildDataTree()
331 //******************************************************
332 ObjectPtr XGUI_DataModel::object(const QModelIndex& theIndex) const
334 if (theIndex.internalId() == 0) // this is a folder
336 ModelAPI_Object* aObj =
337 dynamic_cast<ModelAPI_Object*>((ModelAPI_Entity*)theIndex.internalPointer());
340 if (getSubDocument(aObj)) // the selected index is a folder of sub-document
343 return aObj->data()->owner();
346 //******************************************************
347 QModelIndex XGUI_DataModel::objectIndex(const ObjectPtr theObject) const
349 std::string aType = theObject->groupName();
350 DocumentPtr aDoc = theObject->document();
351 int aRow = aDoc->index(theObject);
353 // it could be a part of complex object
354 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
355 if (aFeature.get()) {
356 CompositeFeaturePtr aCompFea = ModelAPI_Tools::compositeOwner(aFeature);
357 if (aCompFea.get()) {
358 for (int i = 0; i < aCompFea->numberOfSubs(true); i++) {
359 if (aCompFea->subFeature(i, true) == theObject) {
366 ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
368 ResultCompSolidPtr aCompRes = ModelAPI_Tools::compSolidOwner(aResult);
369 if (aCompRes.get()) {
370 for (int i = 0; i < aCompRes->numberOfSubs(true); i++) {
371 if (aCompRes->subResult(i, true) == theObject) {
380 return QModelIndex();
382 return createIndex(aRow, 0, theObject.get());
384 SessionPtr aSession = ModelAPI_Session::get();
385 DocumentPtr aRootDoc = aSession->moduleDocument();
386 if (aDoc == aRootDoc && myXMLReader->rootType() == aType) {
387 // The object from root document
388 aRow += foldersCount();
389 } else if (myXMLReader->subType() == aType) {
390 // The object from sub document
391 aRow += foldersCount(aDoc.get());
393 return createIndex(aRow, 0, theObject.get());
396 //******************************************************
397 QVariant XGUI_DataModel::data(const QModelIndex& theIndex, int theRole) const
399 SessionPtr aSession = ModelAPI_Session::get();
400 DocumentPtr aRootDoc = aSession->moduleDocument();
401 int aNbFolders = foldersCount();
402 int theIndexRow = theIndex.row();
404 if ((theRole == Qt::DecorationRole) && (theIndex == lastHistoryIndex()))
405 return QIcon(":pictures/arrow.png");
407 if (theIndex.column() == 1)
410 quintptr aParentId = theIndex.internalId();
411 if (aParentId == 0) { // root folders
413 case Qt::DisplayRole:
414 return QString(myXMLReader->rootFolderName(theIndexRow).c_str()) +
415 QString(" (%1)").arg(rowCount(theIndex));
416 case Qt::DecorationRole:
417 return QIcon(myXMLReader->rootFolderIcon(theIndexRow).c_str());
418 case Qt::ForegroundRole:
420 Qt::ItemFlags aFlags = theIndex.flags();
421 if (aFlags == Qt::ItemFlags())
422 return QBrush(DISABLED_COLOR);
423 if (!aFlags.testFlag(Qt::ItemIsEditable))
424 return QBrush(SELECTABLE_COLOR);
428 } else { // an object or sub-document
429 if (theRole == Qt::ForegroundRole) {
430 Qt::ItemFlags aFlags = theIndex.flags();
431 if (aFlags == Qt::ItemFlags())
432 return QBrush(DISABLED_COLOR);
433 if (!aFlags.testFlag(Qt::ItemIsEditable))
434 return QBrush(SELECTABLE_COLOR);
438 ModelAPI_Document* aSubDoc = getSubDocument(theIndex.internalPointer());
439 if (aSubDoc) { // this is a folder of sub document
440 QIntList aMissedIdx = missedFolderIndexes(aSubDoc);
441 int aRow = theIndexRow;
442 while (aMissedIdx.contains(aRow))
444 if (aRow < myXMLReader->subFoldersNumber()) {
446 case Qt::DisplayRole:
447 return QString(myXMLReader->subFolderName(aRow).c_str()) +
448 QString(" (%1)").arg(rowCount(theIndex));
449 case Qt::DecorationRole:
450 return QIcon(myXMLReader->subFolderIcon(aRow).c_str());
454 ModelAPI_Object* aObj =
455 dynamic_cast<ModelAPI_Object*>((ModelAPI_Entity*)theIndex.internalPointer());
458 case Qt::DisplayRole:
460 if (aObj->groupName() == ModelAPI_ResultParameter::group()) {
461 ModelAPI_ResultParameter* aParam = dynamic_cast<ModelAPI_ResultParameter*>(aObj);
462 AttributeDoublePtr aValueAttribute =
463 aParam->data()->real(ModelAPI_ResultParameter::VALUE());
464 QString aVal = QString::number(aValueAttribute->value());
465 QString aTitle = QString(aObj->data()->name().c_str());
466 return aTitle + " = " + aVal;
469 if (aObj->groupName() == myXMLReader->subType()) {
470 ResultPartPtr aPartRes = getPartResult(aObj);
471 if (aPartRes.get()) {
472 if (aPartRes->partDoc().get() == NULL)
473 aSuffix = " (Not loaded)";
476 return aObj->data()->name().c_str() + aSuffix;
478 case Qt::DecorationRole:
479 return ModuleBase_IconFactory::get()->getIcon(object(theIndex));
483 case Qt::DisplayRole:
485 ModelAPI_ResultField::ModelAPI_FieldStep* aStep =
486 dynamic_cast<ModelAPI_ResultField::ModelAPI_FieldStep*>
487 ((ModelAPI_Entity*)theIndex.internalPointer());
489 return "Step " + QString::number(aStep->id()) + " " +
490 aStep->field()->textLine(aStep->id()).c_str();
501 //******************************************************
502 QVariant XGUI_DataModel::headerData(int theSection, Qt::Orientation theOrient, int theRole) const
507 //******************************************************
508 int XGUI_DataModel::rowCount(const QModelIndex& theParent) const
510 SessionPtr aSession = ModelAPI_Session::get();
511 if (!aSession->hasModuleDocument())
513 DocumentPtr aRootDoc = aSession->moduleDocument();
515 if (!theParent.isValid()) {
516 // Return number of items in root
517 int aNbFolders = foldersCount();
519 std::string aType = myXMLReader->rootType();
521 aNbItems = aRootDoc->size(aType);
522 return aNbFolders + aNbItems;
525 quintptr aId = theParent.internalId();
527 // this is a folder under root
528 int aParentPos = theParent.row();
529 std::string aType = myXMLReader->rootFolderType(aParentPos);
530 return aRootDoc->size(aType);
532 // It is an object which could have children
533 ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
535 // a folder of sub-document
536 QIntList aMissedIdx = missedFolderIndexes(aDoc);
537 int aRow = theParent.row();
538 while (aMissedIdx.contains(aRow))
540 if (aRow < myXMLReader->subFoldersNumber()) {
541 std::string aType = myXMLReader->subFolderType(aRow);
542 return aDoc->size(aType);
545 ModelAPI_Object* aObj =
546 dynamic_cast<ModelAPI_Object*>((ModelAPI_Entity*)theParent.internalPointer());
547 // Check for Part feature
548 ResultPartPtr aPartRes = getPartResult(aObj);
549 if (aPartRes.get()) {
550 DocumentPtr aSubDoc = aPartRes->partDoc();
554 int aNbSubFolders = foldersCount(aSubDoc.get());
556 std::string aSubType = myXMLReader->subType();
557 if (!aSubType.empty())
558 aNbSubItems = aSubDoc->size(aSubType);
559 return aNbSubItems + aNbSubFolders;
561 // Check for composite object
562 ModelAPI_CompositeFeature* aCompFeature = dynamic_cast<ModelAPI_CompositeFeature*>(aObj);
564 return aCompFeature->numberOfSubs(true);
565 ModelAPI_ResultCompSolid* aCompRes = dynamic_cast<ModelAPI_ResultCompSolid*>(aObj);
567 return aCompRes->numberOfSubs(true);
568 ModelAPI_ResultField* aFieldRes = dynamic_cast<ModelAPI_ResultField*>(aObj);
570 return aFieldRes->stepsSize();
577 //******************************************************
578 int XGUI_DataModel::columnCount(const QModelIndex& theParent) const
583 //******************************************************
584 QModelIndex XGUI_DataModel::index(int theRow, int theColumn, const QModelIndex &theParent) const
586 SessionPtr aSession = ModelAPI_Session::get();
587 DocumentPtr aRootDoc = aSession->moduleDocument();
588 int aNbFolders = foldersCount();
592 if (!theParent.isValid()) {
593 if (theRow < aNbFolders) // Return first level folder index
594 return createIndex(theRow, theColumn, (void*)Q_NULLPTR);
595 else { // return object under root index
596 std::string aType = myXMLReader->rootType();
597 int aObjId = theRow - aNbFolders;
598 if (aObjId < aRootDoc->size(aType)) {
599 ObjectPtr aObj = aRootDoc->object(aType, aObjId);
600 aIndex = objectIndex(aObj);
604 quintptr aId = theParent.internalId();
605 int aParentPos = theParent.row();
606 if (aId == 0) { // return object index inside of first level of folders
607 std::string aType = myXMLReader->rootFolderType(aParentPos);
608 if (theRow < aRootDoc->size(aType)) {
609 ObjectPtr aObj = aRootDoc->object(aType, theRow);
610 aIndex = objectIndex(aObj);
613 // It is an object which could have children
614 ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
616 // It is a folder of sub-document
617 int aParentRow = aParentPos;
618 QIntList aMissedIdx = missedFolderIndexes(aDoc);
619 while (aMissedIdx.contains(aParentRow))
621 if (aParentRow < myXMLReader->subFoldersNumber()) {
622 std::string aType = myXMLReader->subFolderType(aParentRow);
623 if (theRow < aDoc->size(aType)) {
624 ObjectPtr aObj = aDoc->object(aType, theRow);
625 aIndex = objectIndex(aObj);
629 ModelAPI_Object* aParentObj =
630 dynamic_cast<ModelAPI_Object*>((ModelAPI_Entity*)theParent.internalPointer());
632 // Check for Part feature
633 ResultPartPtr aPartRes = getPartResult(aParentObj);
634 if (aPartRes.get()) {
635 DocumentPtr aSubDoc = aPartRes->partDoc();
636 int aNbSubFolders = foldersCount(aSubDoc.get());
637 if (theRow < aNbSubFolders) { // Create a Folder of sub-document
638 aIndex = createIndex(theRow, theColumn, aSubDoc.get());
640 // this is an object under sub document root
641 std::string aType = myXMLReader->subType();
642 ObjectPtr aObj = aSubDoc->object(aType, theRow - aNbSubFolders);
643 aIndex = objectIndex(aObj);
646 // Check for composite object
647 ModelAPI_CompositeFeature* aCompFeature =
648 dynamic_cast<ModelAPI_CompositeFeature*>(aParentObj);
650 aIndex = objectIndex(aCompFeature->subFeature(theRow));
652 ModelAPI_ResultCompSolid* aCompRes =
653 dynamic_cast<ModelAPI_ResultCompSolid*>(aParentObj);
655 aIndex = objectIndex(aCompRes->subResult(theRow));
657 ModelAPI_ResultField* aFieldRes =
658 dynamic_cast<ModelAPI_ResultField*>(aParentObj);
660 aIndex = createIndex(theRow, 0, aFieldRes->step(theRow));
669 return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
673 //******************************************************
674 static QModelIndex MYLastDeleted;
675 QModelIndex XGUI_DataModel::parent(const QModelIndex& theIndex) const
677 if (!theIndex.isValid())
678 return QModelIndex();
679 // To avoid additional request about index which was already deleted
680 if (theIndex == MYLastDeleted)
681 return QModelIndex();
683 SessionPtr aSession = ModelAPI_Session::get();
684 quintptr aId = theIndex.internalId();
685 if (aId != 0) { // The object is not a root folder
686 ModelAPI_Document* aDoc = getSubDocument(theIndex.internalPointer());
688 // It is a folder of sub-document
689 return findDocumentRootIndex(aDoc);
691 ObjectPtr aObj = object(theIndex);
693 // It can b e a step of a field
694 ModelAPI_ResultField::ModelAPI_FieldStep* aStep =
695 dynamic_cast<ModelAPI_ResultField::ModelAPI_FieldStep*>
696 ((ModelAPI_Entity*)theIndex.internalPointer());
698 ModelAPI_ResultField* aField = aStep->field();
699 DocumentPtr aDoc = aSession->activeDocument();
701 for(int i = 0; i < aDoc->size(ModelAPI_ResultField::group()); i++) {
702 aFld = aDoc->object(ModelAPI_ResultField::group(), i);
703 if (aFld.get() == aField)
704 return objectIndex(aFld);
707 // To avoid additional request about index which was already deleted
708 // If deleted it causes a crash on delete object from Part
709 MYLastDeleted = theIndex;
710 return QModelIndex();
712 // Check is it object a sub-object of a complex object
713 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
714 if (aFeature.get()) {
715 CompositeFeaturePtr aCompFea = ModelAPI_Tools::compositeOwner(aFeature);
716 if (aCompFea.get()) {
717 return objectIndex(aCompFea);
720 ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
722 ResultCompSolidPtr aCompRes = ModelAPI_Tools::compSolidOwner(aResult);
723 if (aCompRes.get()) {
724 return objectIndex(aCompRes);
727 // Use as ordinary object
728 std::string aType = aObj->groupName();
729 DocumentPtr aRootDoc = aSession->moduleDocument();
730 DocumentPtr aSubDoc = aObj->document();
731 if (aSubDoc == aRootDoc) {
732 if (aType == myXMLReader->rootType())
733 return QModelIndex();
735 // return first level of folder index
736 int aFolderId = myXMLReader->rootFolderId(aType);
737 // Items in a one row must have the same parent
738 return createIndex(aFolderId, 0, (void*)Q_NULLPTR);
741 if (aType == myXMLReader->subType())
742 return findDocumentRootIndex(aSubDoc.get());
744 // return first level of folder index
745 int aFolderId = folderId(aType, aSubDoc.get());
746 // Items in a one row must have the same parent
747 return createIndex(aFolderId, 0, aSubDoc.get());
751 return QModelIndex();
754 //******************************************************
755 bool XGUI_DataModel::hasChildren(const QModelIndex& theParent) const
757 return rowCount(theParent) > 0;
760 //******************************************************
761 bool XGUI_DataModel::insertRows(int theRow, int theCount, const QModelIndex& theParent)
763 beginInsertRows(theParent, theRow, theRow + theCount - 1);
769 //******************************************************
770 bool XGUI_DataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent)
772 beginRemoveRows(theParent, theRow, theRow + theCount - 1);
777 //******************************************************
778 Qt::ItemFlags XGUI_DataModel::flags(const QModelIndex& theIndex) const
780 quintptr aIt = theIndex.internalId();
781 ModelAPI_Object* aObj = 0;
782 ModelAPI_Document* aDoc = 0;
783 SessionPtr aSession = ModelAPI_Session::get();
784 DocumentPtr aActiveDoc = aSession->activeDocument();
786 Qt::ItemFlags aNullFlag;
787 Qt::ItemFlags aDefaultFlag = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
788 Qt::ItemFlags aEditingFlag = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
792 // Folders under root
793 DocumentPtr aRootDoc = aSession->moduleDocument();
794 if (aRootDoc != aActiveDoc)
797 aDoc = getSubDocument(theIndex.internalPointer());
799 aObj = dynamic_cast<ModelAPI_Object*>((ModelAPI_Entity*)theIndex.internalPointer());
804 if (aObj->isDisabled())
805 return theIndex.column() == 1? Qt::ItemIsSelectable : aNullFlag;
807 if (aSession->moduleDocument() != aObj->document())
808 if (aActiveDoc != aObj->document())
809 return theIndex.column() == 1? Qt::ItemIsSelectable : aNullFlag;
811 bool isCompositeSub = false;
812 // An object which is sub-object of a composite object can not be accessible in column 1
813 if (theIndex.column() == 1) {
814 ObjectPtr aObjPtr = aObj->data()->owner();
815 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObjPtr);
816 if (aFeature.get()) {
817 CompositeFeaturePtr aCompFea = ModelAPI_Tools::compositeOwner(aFeature);
819 isCompositeSub = true;
821 ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aObjPtr);
823 ResultCompSolidPtr aCompRes = ModelAPI_Tools::compSolidOwner(aResult);
825 isCompositeSub = true;
830 return Qt::ItemIsSelectable;
832 if (aObj->document() != aActiveDoc) {
833 // The object could be a root of sub-tree
834 ResultPartPtr aPartRes = getPartResult(aObj);
835 if (aPartRes.get()) {
836 if (aPartRes->partDoc() == aActiveDoc)
842 // A folder under sub-document
843 if (aActiveDoc.get() != aDoc)
849 //******************************************************
850 QModelIndex XGUI_DataModel::findDocumentRootIndex(const ModelAPI_Document* theDoc) const
852 SessionPtr aSession = ModelAPI_Session::get();
853 DocumentPtr aRootDoc = aSession->moduleDocument();
854 if (myXMLReader->isAttachToResult()) { // If document is attached to result
855 int aNb = aRootDoc->size(ModelAPI_ResultPart::group());
857 ResultPartPtr aPartRes;
858 for (int i = 0; i < aNb; i++) {
859 aObj = aRootDoc->object(ModelAPI_ResultPart::group(), i);
860 aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
861 if (aPartRes.get() && (aPartRes->partDoc().get() == theDoc)) {
863 if (myXMLReader->rootType() == ModelAPI_Feature::group()) {
864 aRow += foldersCount();
866 return createIndex(aRow, 0, aObj.get());
869 } else { // If document is attached to feature
870 int aNb = aRootDoc->size(ModelAPI_Feature::group());
872 ResultPartPtr aPartRes;
873 for (int i = 0; i < aNb; i++) {
874 aObj = aRootDoc->object(ModelAPI_Feature::group(), i);
875 aPartRes = getPartResult(aObj.get());
876 if (aPartRes.get() && (aPartRes->partDoc().get() == theDoc)) {
878 if (myXMLReader->rootType() == ModelAPI_Feature::group())
879 aRow += foldersCount();
880 return createIndex(aRow, 0, aObj.get());
884 return QModelIndex();
887 //******************************************************
888 QModelIndex XGUI_DataModel::documentRootIndex(DocumentPtr theDoc) const
890 SessionPtr aSession = ModelAPI_Session::get();
891 DocumentPtr aRootDoc = aSession->moduleDocument();
892 if (theDoc == aRootDoc)
893 return QModelIndex();
895 return findDocumentRootIndex(theDoc.get());
898 //******************************************************
899 int XGUI_DataModel::foldersCount(ModelAPI_Document* theDoc) const
902 SessionPtr aSession = ModelAPI_Session::get();
903 DocumentPtr aRootDoc = aSession->moduleDocument();
904 if ((theDoc == 0) || (theDoc == aRootDoc.get())) {
905 for (int i = 0; i < myXMLReader->rootFoldersNumber(); i++) {
906 if (myXMLReader->rootShowEmpty(i))
909 if (aRootDoc->size(myXMLReader->rootFolderType(i)) > 0)
914 for (int i = 0; i < myXMLReader->subFoldersNumber(); i++) {
915 if (myXMLReader->subShowEmpty(i))
918 if (theDoc->size(myXMLReader->subFolderType(i)) > 0)
927 //******************************************************
928 QIntList XGUI_DataModel::missedFolderIndexes(ModelAPI_Document* theDoc) const
931 SessionPtr aSession = ModelAPI_Session::get();
932 DocumentPtr aRootDoc = aSession->moduleDocument();
933 if ((theDoc == 0) || (theDoc == aRootDoc.get())) {
934 for (int i = 0; i < myXMLReader->rootFoldersNumber(); i++) {
935 if (!myXMLReader->rootShowEmpty(i)) {
936 if (aRootDoc->size(myXMLReader->rootFolderType(i)) == 0)
941 for (int i = 0; i < myXMLReader->subFoldersNumber(); i++) {
942 if (!myXMLReader->subShowEmpty(i)) {
943 if (theDoc->size(myXMLReader->subFolderType(i)) == 0)
952 //******************************************************
953 QStringList XGUI_DataModel::listOfShowNotEmptyFolders(bool fromRoot) const
957 for (int i = 0; i < myXMLReader->rootFoldersNumber(); i++) {
958 if (!myXMLReader->rootShowEmpty(i))
959 aResult << myXMLReader->rootFolderType(i).c_str();
962 for (int i = 0; i < myXMLReader->subFoldersNumber(); i++) {
963 if (!myXMLReader->subShowEmpty(i))
964 aResult << myXMLReader->subFolderType(i).c_str();
970 //******************************************************
971 QModelIndex XGUI_DataModel::lastHistoryIndex() const
973 SessionPtr aSession = ModelAPI_Session::get();
974 DocumentPtr aCurDoc = aSession->activeDocument();
975 FeaturePtr aFeature = aCurDoc->currentFeature(true);
976 if (aFeature.get()) {
977 QModelIndex aInd = objectIndex(aFeature);
978 return createIndex(aInd.row(), 1, aInd.internalPointer());
980 if (aCurDoc == aSession->moduleDocument())
981 return createIndex(foldersCount() - 1, 1, -1);
983 return createIndex(foldersCount(aCurDoc.get()) - 1, 1, aCurDoc.get());
987 //******************************************************
988 int XGUI_DataModel::folderId(std::string theType, ModelAPI_Document* theDoc) const
990 SessionPtr aSession = ModelAPI_Session::get();
991 ModelAPI_Document* aDoc = theDoc;
993 aDoc = aSession->moduleDocument().get();
995 bool aUseSubDoc = (aDoc != aSession->moduleDocument().get());
999 int aId = myXMLReader->subFolderId(theType);
1001 for (int i = 0; i < aId; i++) {
1002 if (!myXMLReader->subShowEmpty(i)) {
1003 if (aDoc->size(myXMLReader->subFolderType(i)) == 0)
1008 int aId = myXMLReader->rootFolderId(theType);
1010 for (int i = 0; i < aId; i++) {
1011 if (!myXMLReader->rootShowEmpty(i)) {
1012 if (aDoc->size(myXMLReader->rootFolderType(i)) == 0)
1020 //******************************************************
1021 void XGUI_DataModel::rebuildBranch(int theRow, int theCount, const QModelIndex& theParent)
1024 removeRows(theRow, theCount, theParent);
1025 insertRows(theRow, theCount, theParent);
1029 //******************************************************
1030 //bool XGUI_DataModel::blockEventsProcessing(const bool theState)
1032 // bool aPreviousState = myIsEventsProcessingBlocked;
1033 // myIsEventsProcessingBlocked = theState;
1034 // return aPreviousState;