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_Document.h>
11 #include <ModelAPI_Events.h>
12 #include <ModelAPI_ResultParameter.h>
13 #include <ModelAPI_AttributeDouble.h>
14 #include <ModelAPI_ResultPart.h>
16 #include <Config_FeatureMessage.h>
18 #include <Events_Loop.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 ModelAPI_Document* getSubDocument(void* theObj)
38 ModelAPI_Document* aDoc = dynamic_cast<ModelAPI_Document*>((ModelAPI_Entity*)theObj);
43 // Constructor *************************************************
44 XGUI_DataModel::XGUI_DataModel(QObject* theParent) : QAbstractItemModel(theParent)
46 myXMLReader.readAll();
48 Events_Loop* aLoop = Events_Loop::loop();
49 aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
50 aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
51 aLoop->registerListener(this, Events_Loop::eventByName(Config_FeatureMessage::GUI_EVENT()));
54 //******************************************************
55 void XGUI_DataModel::processEvent(const std::shared_ptr<Events_Message>& theMessage)
57 DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
58 std::string aRootType = myXMLReader.rootType();
59 int aNbFolders = myXMLReader.rootFoldersNumber();
61 // Created object event *******************
62 if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)) {
63 std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
64 std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
65 std::set<ObjectPtr> aObjects = aUpdMsg->objects();
67 std::set<ObjectPtr>::const_iterator aIt;
69 for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) {
70 ObjectPtr aObject = (*aIt);
71 aObjType = aObject->groupName();
72 DocumentPtr aDoc = aObject->document();
73 if (aDoc == aRootDoc) {
74 int aRow = aRootDoc->size(aObjType) - 1;
76 if (aObjType == aRootType) {
77 insertRow(aRow + aNbFolders);
79 int aFolderId = myXMLReader.rootFolderId(aObjType);
80 if (aFolderId != -1) {
81 insertRow(aRow, createIndex(aFolderId, 0, -1));
87 // Deleted object event ***********************
88 } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
89 std::shared_ptr<ModelAPI_ObjectDeletedMessage> aUpdMsg =
90 std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
91 DocumentPtr aDoc = aUpdMsg->document();
92 std::set<std::string> aGroups = aUpdMsg->groups();
93 std::set<std::string>::const_iterator aIt;
94 for (aIt = aGroups.begin(); aIt != aGroups.end(); ++aIt) {
95 std::string aGroup = (*aIt);
96 if (aDoc == aRootDoc) { // If root objects
97 int aRow = aRootDoc->size(aGroup);
98 if (aGroup == aRootType) {
99 removeRow(aRow + aNbFolders);
101 int aFolderId = myXMLReader.rootFolderId(aGroup);
102 if (aFolderId != -1) {
103 QModelIndex aFolderIndex = createIndex(aFolderId, 0, -1);
104 removeRow(aRow, aFolderIndex);
112 //******************************************************
113 void XGUI_DataModel::clear()
118 //******************************************************
119 void XGUI_DataModel::rebuildDataTree()
124 //******************************************************
125 ObjectPtr XGUI_DataModel::object(const QModelIndex& theIndex) const
127 if (theIndex.internalId() < 0) // this is a folder
129 ModelAPI_Object* aObj = (ModelAPI_Object*)theIndex.internalPointer();
130 // We can not create the ObjectPtr directly because the pointer will be deleted
131 // with deletion of the ObjectPtr because its counter become to 0.
132 DocumentPtr aDoc = aObj->document();
133 std::string aType = aObj->groupName();
136 for (int i = 0; i < aDoc->size(aType); i++) {
137 aObjPtr = aDoc->object(aType, i);
138 if (aObjPtr.get() == aObj)
144 //******************************************************
145 QModelIndex XGUI_DataModel::objectIndex(const ObjectPtr theObject) const
147 std::string aType = theObject->groupName();
148 DocumentPtr aDoc = theObject->document();
149 int aRow = aDoc->index(theObject);
151 return QModelIndex();
153 SessionPtr aSession = ModelAPI_Session::get();
154 DocumentPtr aRootDoc = aSession->moduleDocument();
155 if (aDoc == aRootDoc && myXMLReader.rootType() == aType) {
156 // The object from root document
157 aRow += myXMLReader.rootFoldersNumber();
158 } else if (myXMLReader.subType() == aType) {
159 // The object from sub document
160 aRow += myXMLReader.subFoldersNumber();
162 return createIndex(aRow, 0, theObject.get());
165 //******************************************************
166 QVariant XGUI_DataModel::data(const QModelIndex& theIndex, int theRole) const
168 SessionPtr aSession = ModelAPI_Session::get();
169 DocumentPtr aRootDoc = aSession->moduleDocument();
170 int aNbFolders = myXMLReader.rootFoldersNumber();
171 int theIndexRow = theIndex.row();
173 if ((theIndex.column() == 1) ) {
174 //if (theIndexRow >= aNbFolders) {
175 // if (theRole == Qt::DecorationRole) {
176 // return QIcon(":pictures/arrow.png");
182 int aParentId = theIndex.internalId();
183 if (aParentId == -1) { // root folders
185 case Qt::DisplayRole:
186 return QString(myXMLReader.rootFolderName(theIndexRow).c_str()) +
187 QString(" (%1)").arg(rowCount(theIndex));
188 case Qt::DecorationRole:
189 return QIcon(myXMLReader.rootFolderIcon(theIndexRow).c_str());
192 ModelAPI_Document* aSubDoc = getSubDocument(theIndex.internalPointer());
193 if (aSubDoc) { // this is a folder of sub document
195 case Qt::DisplayRole:
196 return QString(myXMLReader.subFolderName(theIndexRow).c_str()) +
197 QString(" (%1)").arg(rowCount(theIndex));
198 case Qt::DecorationRole:
199 return QIcon(myXMLReader.subFolderIcon(theIndexRow).c_str());
202 ModelAPI_Object* aObj = (ModelAPI_Object*)theIndex.internalPointer();
204 case Qt::DisplayRole:
205 if (aObj->groupName() == ModelAPI_ResultParameter::group()) {
206 ModelAPI_ResultParameter* aParam = dynamic_cast<ModelAPI_ResultParameter*>(aObj);
207 AttributeDoublePtr aValueAttribute = aParam->data()->real(ModelAPI_ResultParameter::VALUE());
208 QString aVal = QString::number(aValueAttribute->value());
209 QString aTitle = QString(aObj->data()->name().c_str());
210 return aTitle + " = " + aVal;
212 return aObj->data()->name().c_str();
219 //******************************************************
220 QVariant XGUI_DataModel::headerData(int theSection, Qt::Orientation theOrient, int theRole) const
225 //******************************************************
226 int XGUI_DataModel::rowCount(const QModelIndex& theParent) const
228 SessionPtr aSession = ModelAPI_Session::get();
229 if (!aSession->hasModuleDocument())
231 DocumentPtr aRootDoc = aSession->moduleDocument();
233 if (!theParent.isValid()) {
234 // Return number of items in root
235 int aNbFolders = myXMLReader.rootFoldersNumber();
237 std::string aType = myXMLReader.rootType();
239 aNbItems = aRootDoc->size(aType);
240 return aNbFolders + aNbItems;
243 int aId = theParent.internalId();
246 int aParentPos = theParent.row();
247 if (aId == -1) { // first level of folders
248 std::string aType = myXMLReader.rootFolderType(aParentPos);
249 return aRootDoc->size(aType);
252 // It is an object which could have children
253 ModelAPI_Object* aObj = (ModelAPI_Object*)theParent.internalPointer();
255 // Check for Part feature
256 ResultPartPtr aPartRes = getPartResult(aObj);
257 if (aPartRes.get()) {
258 DocumentPtr aSubDoc = aPartRes->partDoc();
259 int aNbSubFolders = myXMLReader.subFoldersNumber();
261 std::string aSubType = myXMLReader.subType();
262 if (!aSubType.empty())
263 aNbSubItems = aSubDoc->size(aSubType);
264 return aNbSubItems + aNbSubFolders;
270 //******************************************************
271 int XGUI_DataModel::columnCount(const QModelIndex& theParent) const
276 //******************************************************
277 QModelIndex XGUI_DataModel::index(int theRow, int theColumn, const QModelIndex &theParent) const
279 SessionPtr aSession = ModelAPI_Session::get();
280 DocumentPtr aRootDoc = aSession->moduleDocument();
281 int aNbFolders = myXMLReader.rootFoldersNumber();
283 if (!theParent.isValid()) {
284 if (theRow < aNbFolders) // Return first level folder index
285 return createIndex(theRow, theColumn, -1);
286 else { // return object under root index
287 std::string aType = myXMLReader.rootType();
288 int aObjId = theRow - aNbFolders;
289 if (aObjId < aRootDoc->size(aType)) {
290 ObjectPtr aObj = aRootDoc->object(aType, aObjId);
291 QModelIndex aIndex = objectIndex(aObj);
293 return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
296 return QModelIndex();
299 int aId = theParent.internalId();
300 if (aId == -1) { // return object index inside of first level of folders
301 int aParentPos = theParent.row();
302 std::string aType = myXMLReader.rootFolderType(aParentPos);
303 if (theRow < aRootDoc->size(aType)) {
304 ObjectPtr aObj = aRootDoc->object(aType, theRow);
305 QModelIndex aIndex = objectIndex(aObj);
307 return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
311 // It is an object which could have children
312 ModelAPI_Object* aParentObj = (ModelAPI_Object*)theParent.internalPointer();
314 // Check for Part feature
315 ResultPartPtr aPartRes = getPartResult(aParentObj);
316 if (aPartRes.get()) {
317 DocumentPtr aSubDoc = aPartRes->partDoc();
318 int aNbSubFolders = myXMLReader.subFoldersNumber();
319 if (theRow < aNbSubFolders) { // Create a Folder of sub-document
320 return createIndex(theRow, theColumn, aSubDoc.get());
324 return QModelIndex();
327 //******************************************************
328 QModelIndex XGUI_DataModel::parent(const QModelIndex& theIndex) const
330 int aId = theIndex.internalId();
331 if (aId != -1) { // The object is not a root folder
332 ModelAPI_Document* aDoc = getSubDocument(theIndex.internalPointer());
334 // It is a folder of sub-document
335 SessionPtr aSession = ModelAPI_Session::get();
336 DocumentPtr aRootDoc = aSession->moduleDocument();
337 if (myXMLReader.isAttachToResult()) { // If document is attached to result
338 int aNb = aRootDoc->size(ModelAPI_ResultPart::group());
340 ResultPartPtr aPartRes;
341 for (int i = 0; i < aNb; i++) {
342 aObj = aRootDoc->object(ModelAPI_ResultPart::group(), i);
343 aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
344 if (aPartRes.get() && (aPartRes->partDoc().get() == aDoc)) {
346 if (myXMLReader.rootType() == ModelAPI_Feature::group())
347 aRow += myXMLReader.rootFoldersNumber();
348 return createIndex(aRow, 0, aObj.get());
351 } else { // If document is attached to feature
352 int aNb = aRootDoc->size(ModelAPI_Feature::group());
354 ResultPartPtr aPartRes;
355 for (int i = 0; i < aNb; i++) {
356 aObj = aRootDoc->object(ModelAPI_Feature::group(), i);
357 aPartRes = getPartResult(aObj.get());
358 if (aPartRes.get() && (aPartRes->partDoc().get() == aDoc)) {
360 if (myXMLReader.rootType() == ModelAPI_Feature::group())
361 aRow += myXMLReader.rootFoldersNumber();
362 return createIndex(aRow, 0, aObj.get());
367 ModelAPI_Object* aObj = (ModelAPI_Object*) theIndex.internalPointer();
368 std::string aType = aObj->groupName();
369 if (aType == myXMLReader.rootType())
370 return QModelIndex();
372 // return first level of folder index
373 int aFolderId = myXMLReader.rootFolderId(aType);
374 // Items in a one row must have the same parent
375 return createIndex(aFolderId, 0, -1);
378 return QModelIndex();
381 //******************************************************
382 bool XGUI_DataModel::hasChildren(const QModelIndex& theParent) const
384 int aNbFolders = myXMLReader.rootFoldersNumber();
385 if (!theParent.isValid() && aNbFolders)
387 if (theParent.internalId() == -1) {
388 std::string aType = myXMLReader.rootFolderType(theParent.row());
389 if (!aType.empty()) {
390 SessionPtr aSession = ModelAPI_Session::get();
391 DocumentPtr aRootDoc = aSession->moduleDocument();
392 return aRootDoc->size(aType) > 0;
395 ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
397 // a folder of sub-document
398 std::string aType = myXMLReader.subFolderType(theParent.row());
399 return aDoc->size(aType) > 0;
401 // Check that it could be an object with children
402 ModelAPI_Object* aObj = (ModelAPI_Object*)theParent.internalPointer();
404 // Check for Part feature
405 ResultPartPtr aPartRes = getPartResult(aObj);
413 //******************************************************
414 bool XGUI_DataModel::insertRows(int theRow, int theCount, const QModelIndex& theParent)
416 beginInsertRows(theParent, theRow, theRow + theCount - 1);
422 //******************************************************
423 bool XGUI_DataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent)
425 beginRemoveRows(theParent, theRow, theRow + theCount - 1);
430 //******************************************************
431 Qt::ItemFlags XGUI_DataModel::flags(const QModelIndex& theIndex) const
433 Qt::ItemFlags aFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
434 if (theIndex.internalId() > -1) {
435 aFlags |= Qt::ItemIsEditable;