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 <ModelAPI_Session.h>
10 #include <ModelAPI_Events.h>
11 #include <ModelAPI_ResultParameter.h>
12 #include <ModelAPI_AttributeDouble.h>
13 #include <ModelAPI_ResultPart.h>
15 #include <Config_FeatureMessage.h>
17 #include <Events_Loop.h>
18 #include <Events_Error.h>
22 /// Returns ResultPart object if the given object is a Part feature
23 /// Otherwise returns NULL
24 ResultPartPtr getPartResult(ModelAPI_Object* theObj)
26 ModelAPI_Feature* aFeature = dynamic_cast<ModelAPI_Feature*>(theObj);
28 ResultPtr aRes = aFeature->firstResult();
29 if (aRes.get() && (aRes->groupName() == ModelAPI_ResultPart::group())) {
30 return std::dynamic_pointer_cast<ModelAPI_ResultPart>(aRes);
33 return ResultPartPtr();
36 /// Returns pointer on document if the given object is document object
37 ModelAPI_Document* getSubDocument(void* theObj)
39 ModelAPI_Document* aDoc = dynamic_cast<ModelAPI_Document*>((ModelAPI_Entity*)theObj);
46 // Constructor *************************************************
47 XGUI_DataModel::XGUI_DataModel(QObject* theParent) : QAbstractItemModel(theParent)
49 myXMLReader.readAll();
51 Events_Loop* aLoop = Events_Loop::loop();
52 aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
53 aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
54 aLoop->registerListener(this, Events_Loop::eventByName(Config_FeatureMessage::GUI_EVENT()));
57 //******************************************************
58 void XGUI_DataModel::processEvent(const std::shared_ptr<Events_Message>& theMessage)
60 DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
61 std::string aRootType = myXMLReader.rootType();
62 std::string aSubType = myXMLReader.subType();
63 int aNbFolders = myXMLReader.rootFoldersNumber();
64 int aNbSubFolders = myXMLReader.subFoldersNumber();
66 // Created object event *******************
67 if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)) {
68 std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
69 std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
70 std::set<ObjectPtr> aObjects = aUpdMsg->objects();
72 std::set<ObjectPtr>::const_iterator aIt;
74 for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) {
75 ObjectPtr aObject = (*aIt);
76 aObjType = aObject->groupName();
77 DocumentPtr aDoc = aObject->document();
78 if (aDoc == aRootDoc) {
79 int aRow = aRootDoc->size(aObjType) - 1;
80 if (aObjType == aRootType) {
81 insertRow(aRow + aNbFolders);
83 int aFolderId = myXMLReader.rootFolderId(aObjType);
84 if (aFolderId != -1) {
85 insertRow(aRow, createIndex(aFolderId, 0, -1));
89 // Object created in sub-document
90 QModelIndex aDocRoot = findDocumentRootIndex(aDoc.get());
91 if (aDocRoot.isValid()) {
92 int aRow = aDoc->size(aObjType) - 1;
93 if (aObjType == aSubType) {
94 insertRow(aRow + aNbSubFolders, aDocRoot);
96 int aFolderId = myXMLReader.subFolderId(aObjType);
97 if (aFolderId != -1) {
98 insertRow(aRow, createIndex(aFolderId, 0, aDoc.get()));
104 Events_Error::send("Problem with Data Model definition of sub-document");
109 // Deleted object event ***********************
110 } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
111 std::shared_ptr<ModelAPI_ObjectDeletedMessage> aUpdMsg =
112 std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
113 DocumentPtr aDoc = aUpdMsg->document();
114 std::set<std::string> aGroups = aUpdMsg->groups();
115 std::set<std::string>::const_iterator aIt;
116 for (aIt = aGroups.begin(); aIt != aGroups.end(); ++aIt) {
117 std::string aGroup = (*aIt);
118 if (aDoc == aRootDoc) { // If root objects
119 int aRow = aRootDoc->size(aGroup);
120 if (aGroup == aRootType) {
121 removeRow(aRow + aNbFolders);
123 int aFolderId = myXMLReader.rootFolderId(aGroup);
124 if (aFolderId != -1) {
125 QModelIndex aFolderIndex = createIndex(aFolderId, 0, -1);
126 removeRow(aRow, aFolderIndex);
134 //******************************************************
135 void XGUI_DataModel::clear()
140 //******************************************************
141 void XGUI_DataModel::rebuildDataTree()
146 //******************************************************
147 ObjectPtr XGUI_DataModel::object(const QModelIndex& theIndex) const
149 if (theIndex.internalId() < 0) // this is a folder
151 ModelAPI_Object* aObj = (ModelAPI_Object*)theIndex.internalPointer();
152 if (getSubDocument(aObj)) // the selected index is a folder of sub-document
155 // We can not create the ObjectPtr directly because the pointer will be deleted
156 // with deletion of the ObjectPtr because its counter become to 0.
157 DocumentPtr aDoc = aObj->document();
158 std::string aType = aObj->groupName();
161 for (int i = 0; i < aDoc->size(aType); i++) {
162 aObjPtr = aDoc->object(aType, i);
163 if (aObjPtr.get() == aObj)
169 //******************************************************
170 QModelIndex XGUI_DataModel::objectIndex(const ObjectPtr theObject) const
172 std::string aType = theObject->groupName();
173 DocumentPtr aDoc = theObject->document();
174 int aRow = aDoc->index(theObject);
176 return QModelIndex();
178 SessionPtr aSession = ModelAPI_Session::get();
179 DocumentPtr aRootDoc = aSession->moduleDocument();
180 if (aDoc == aRootDoc && myXMLReader.rootType() == aType) {
181 // The object from root document
182 aRow += myXMLReader.rootFoldersNumber();
183 } else if (myXMLReader.subType() == aType) {
184 // The object from sub document
185 aRow += myXMLReader.subFoldersNumber();
187 return createIndex(aRow, 0, theObject.get());
190 //******************************************************
191 QVariant XGUI_DataModel::data(const QModelIndex& theIndex, int theRole) const
193 SessionPtr aSession = ModelAPI_Session::get();
194 DocumentPtr aRootDoc = aSession->moduleDocument();
195 int aNbFolders = myXMLReader.rootFoldersNumber();
196 int theIndexRow = theIndex.row();
198 if ((theIndex.column() == 1) ) {
199 //if (theIndexRow >= aNbFolders) {
200 // if (theRole == Qt::DecorationRole) {
201 // return QIcon(":pictures/arrow.png");
207 int aParentId = theIndex.internalId();
208 if (aParentId == -1) { // root folders
210 case Qt::DisplayRole:
211 return QString(myXMLReader.rootFolderName(theIndexRow).c_str()) +
212 QString(" (%1)").arg(rowCount(theIndex));
213 case Qt::DecorationRole:
214 return QIcon(myXMLReader.rootFolderIcon(theIndexRow).c_str());
217 ModelAPI_Document* aSubDoc = getSubDocument(theIndex.internalPointer());
218 if (aSubDoc) { // this is a folder of sub document
220 case Qt::DisplayRole:
221 return QString(myXMLReader.subFolderName(theIndexRow).c_str()) +
222 QString(" (%1)").arg(rowCount(theIndex));
223 case Qt::DecorationRole:
224 return QIcon(myXMLReader.subFolderIcon(theIndexRow).c_str());
227 ModelAPI_Object* aObj = (ModelAPI_Object*)theIndex.internalPointer();
229 case Qt::DisplayRole:
230 if (aObj->groupName() == ModelAPI_ResultParameter::group()) {
231 ModelAPI_ResultParameter* aParam = dynamic_cast<ModelAPI_ResultParameter*>(aObj);
232 AttributeDoublePtr aValueAttribute = aParam->data()->real(ModelAPI_ResultParameter::VALUE());
233 QString aVal = QString::number(aValueAttribute->value());
234 QString aTitle = QString(aObj->data()->name().c_str());
235 return aTitle + " = " + aVal;
237 return aObj->data()->name().c_str();
244 //******************************************************
245 QVariant XGUI_DataModel::headerData(int theSection, Qt::Orientation theOrient, int theRole) const
250 //******************************************************
251 int XGUI_DataModel::rowCount(const QModelIndex& theParent) const
253 SessionPtr aSession = ModelAPI_Session::get();
254 if (!aSession->hasModuleDocument())
256 DocumentPtr aRootDoc = aSession->moduleDocument();
258 if (!theParent.isValid()) {
259 // Return number of items in root
260 int aNbFolders = myXMLReader.rootFoldersNumber();
262 std::string aType = myXMLReader.rootType();
264 aNbItems = aRootDoc->size(aType);
265 return aNbFolders + aNbItems;
268 int aId = theParent.internalId();
270 // this is a folder under root
271 int aParentPos = theParent.row();
272 if (aId == -1) { // first level of folders
273 std::string aType = myXMLReader.rootFolderType(aParentPos);
274 return aRootDoc->size(aType);
277 // It is an object which could have children
278 ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
280 // a folder of sub-document
281 std::string aType = myXMLReader.subFolderType(theParent.row());
282 return aDoc->size(aType);
284 // Check for Part feature
285 ModelAPI_Object* aObj = (ModelAPI_Object*)theParent.internalPointer();
286 ResultPartPtr aPartRes = getPartResult(aObj);
287 if (aPartRes.get()) {
288 DocumentPtr aSubDoc = aPartRes->partDoc();
289 int aNbSubFolders = myXMLReader.subFoldersNumber();
291 std::string aSubType = myXMLReader.subType();
292 if (!aSubType.empty())
293 aNbSubItems = aSubDoc->size(aSubType);
294 return aNbSubItems + aNbSubFolders;
301 //******************************************************
302 int XGUI_DataModel::columnCount(const QModelIndex& theParent) const
307 //******************************************************
308 QModelIndex XGUI_DataModel::index(int theRow, int theColumn, const QModelIndex &theParent) const
310 SessionPtr aSession = ModelAPI_Session::get();
311 DocumentPtr aRootDoc = aSession->moduleDocument();
312 int aNbFolders = myXMLReader.rootFoldersNumber();
314 if (!theParent.isValid()) {
315 if (theRow < aNbFolders) // Return first level folder index
316 return createIndex(theRow, theColumn, -1);
317 else { // return object under root index
318 std::string aType = myXMLReader.rootType();
319 int aObjId = theRow - aNbFolders;
320 if (aObjId < aRootDoc->size(aType)) {
321 ObjectPtr aObj = aRootDoc->object(aType, aObjId);
322 QModelIndex aIndex = objectIndex(aObj);
324 return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
327 return QModelIndex();
330 int aId = theParent.internalId();
331 int aParentPos = theParent.row();
332 if (aId == -1) { // return object index inside of first level of folders
333 std::string aType = myXMLReader.rootFolderType(aParentPos);
334 if (theRow < aRootDoc->size(aType)) {
335 ObjectPtr aObj = aRootDoc->object(aType, theRow);
336 QModelIndex aIndex = objectIndex(aObj);
338 return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
342 // It is an object which could have children
343 ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
345 // It is a folder of sub-document
346 std::string aType = myXMLReader.subFolderType(aParentPos);
347 if (theRow < aDoc->size(aType)) {
348 ObjectPtr aObj = aDoc->object(aType, theRow);
349 QModelIndex aIndex = objectIndex(aObj);
351 return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
355 ModelAPI_Object* aParentObj = (ModelAPI_Object*)theParent.internalPointer();
357 // Check for Part feature
358 ResultPartPtr aPartRes = getPartResult(aParentObj);
359 if (aPartRes.get()) {
360 DocumentPtr aSubDoc = aPartRes->partDoc();
361 int aNbSubFolders = myXMLReader.subFoldersNumber();
362 if (theRow < aNbSubFolders) { // Create a Folder of sub-document
363 return createIndex(theRow, theColumn, aSubDoc.get());
365 // this is an object under sub document root
366 std::string aType = myXMLReader.subType();
367 ObjectPtr aObj = aSubDoc->object(aType, theRow - aNbSubFolders);
368 QModelIndex aIndex = objectIndex(aObj);
370 return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
376 return QModelIndex();
379 //******************************************************
380 QModelIndex XGUI_DataModel::parent(const QModelIndex& theIndex) const
382 int aId = theIndex.internalId();
383 if (aId != -1) { // The object is not a root folder
384 ModelAPI_Document* aDoc = getSubDocument(theIndex.internalPointer());
386 // It is a folder of sub-document
387 return findDocumentRootIndex(aDoc);
389 ModelAPI_Object* aObj = (ModelAPI_Object*) theIndex.internalPointer();
390 std::string aType = aObj->groupName();
391 SessionPtr aSession = ModelAPI_Session::get();
392 DocumentPtr aRootDoc = aSession->moduleDocument();
393 DocumentPtr aSubDoc = aObj->document();
394 if (aSubDoc == aRootDoc) {
395 if (aType == myXMLReader.rootType())
396 return QModelIndex();
398 // return first level of folder index
399 int aFolderId = myXMLReader.rootFolderId(aType);
400 // Items in a one row must have the same parent
401 return createIndex(aFolderId, 0, -1);
404 if (aType == myXMLReader.subType())
405 return findDocumentRootIndex(aSubDoc.get());
407 // return first level of folder index
408 int aFolderId = myXMLReader.subFolderId(aType);
409 // Items in a one row must have the same parent
410 return createIndex(aFolderId, 0, aSubDoc.get());
414 return QModelIndex();
417 //******************************************************
418 bool XGUI_DataModel::hasChildren(const QModelIndex& theParent) const
420 int aNbFolders = myXMLReader.rootFoldersNumber();
421 if (!theParent.isValid() && aNbFolders)
423 if (theParent.internalId() == -1) {
424 std::string aType = myXMLReader.rootFolderType(theParent.row());
425 if (!aType.empty()) {
426 SessionPtr aSession = ModelAPI_Session::get();
427 DocumentPtr aRootDoc = aSession->moduleDocument();
428 return aRootDoc->size(aType) > 0;
431 ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
433 // a folder of sub-document
434 std::string aType = myXMLReader.subFolderType(theParent.row());
435 return aDoc->size(aType) > 0;
437 // Check that it could be an object with children
438 ModelAPI_Object* aObj = (ModelAPI_Object*)theParent.internalPointer();
440 // Check for Part feature
441 ResultPartPtr aPartRes = getPartResult(aObj);
449 //******************************************************
450 bool XGUI_DataModel::insertRows(int theRow, int theCount, const QModelIndex& theParent)
452 beginInsertRows(theParent, theRow, theRow + theCount - 1);
458 //******************************************************
459 bool XGUI_DataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent)
461 beginRemoveRows(theParent, theRow, theRow + theCount - 1);
466 //******************************************************
467 Qt::ItemFlags XGUI_DataModel::flags(const QModelIndex& theIndex) const
469 Qt::ItemFlags aFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
470 if (theIndex.internalId() > -1) {
471 aFlags |= Qt::ItemIsEditable;
476 //******************************************************
477 QModelIndex XGUI_DataModel::findDocumentRootIndex(ModelAPI_Document* theDoc) const
479 SessionPtr aSession = ModelAPI_Session::get();
480 DocumentPtr aRootDoc = aSession->moduleDocument();
481 if (myXMLReader.isAttachToResult()) { // If document is attached to result
482 int aNb = aRootDoc->size(ModelAPI_ResultPart::group());
484 ResultPartPtr aPartRes;
485 for (int i = 0; i < aNb; i++) {
486 aObj = aRootDoc->object(ModelAPI_ResultPart::group(), i);
487 aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
488 if (aPartRes.get() && (aPartRes->partDoc().get() == theDoc)) {
490 if (myXMLReader.rootType() == ModelAPI_Feature::group())
491 aRow += myXMLReader.rootFoldersNumber();
492 return createIndex(aRow, 0, aObj.get());
495 } else { // If document is attached to feature
496 int aNb = aRootDoc->size(ModelAPI_Feature::group());
498 ResultPartPtr aPartRes;
499 for (int i = 0; i < aNb; i++) {
500 aObj = aRootDoc->object(ModelAPI_Feature::group(), i);
501 aPartRes = getPartResult(aObj.get());
502 if (aPartRes.get() && (aPartRes->partDoc().get() == theDoc)) {
504 if (myXMLReader.rootType() == ModelAPI_Feature::group())
505 aRow += myXMLReader.rootFoldersNumber();
506 return createIndex(aRow, 0, aObj.get());
510 return QModelIndex();