Salome HOME
#Initial implementation of support of dump and save to hdf in case SHAPER module...
[modules/shaper.git] / src / XGUI / XGUI_DataModel.cpp
1 // Copyright (C) 2014-2020  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "XGUI_DataModel.h"
21 #include "XGUI_ObjectsBrowser.h"
22
23 #include <ModuleBase_IconFactory.h>
24 #include <ModuleBase_ITreeNode.h>
25
26 #include <ModelAPI_Session.h>
27 #include <ModelAPI_ResultField.h>
28
29 #include <Config_FeatureMessage.h>
30
31 #include <Events_Loop.h>
32
33 #include <cassert>
34
35 #ifdef _MSC_VER
36 #pragma warning(disable: 4100)
37 #endif
38
39
40
41 // Constructor *************************************************
42 XGUI_DataModel::XGUI_DataModel(QObject* theParent) : QAbstractItemModel(theParent)//,
43   //myIsEventsProcessingBlocked(false)
44 {
45   XGUI_ObjectsBrowser* aOB = qobject_cast<XGUI_ObjectsBrowser*>(theParent);
46   myWorkshop = aOB->workshop();
47
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(EVENT_OBJECT_UPDATED));
52   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_ORDER_UPDATED));
53   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_DOCUMENT_CHANGED));
54   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
55 }
56
57 XGUI_DataModel::~XGUI_DataModel()
58 {
59   clear();
60 }
61
62 //******************************************************
63 void XGUI_DataModel::processEvent(const std::shared_ptr<Events_Message>& theMessage)
64 {
65   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)) {
66     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
67       std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
68     std::set<ObjectPtr> aObjects = aUpdMsg->objects();
69     QObjectPtrList aCreated;
70     std::set<ObjectPtr>::const_iterator aIt;
71     for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) {
72       if ((*aIt)->isInHistory())
73         aCreated.append(*aIt);
74       if ((*aIt)->groupName() == ModelAPI_ResultPart::group()) {
75         emit beforeTreeRebuild();
76         myRoot->update();
77         rebuildDataTree();
78         emit treeRebuilt();
79         return;
80       }
81     }
82     if (aCreated.length() == 0)
83       return;
84
85     emit beforeTreeRebuild();
86     QTreeNodesList aNodes = myRoot->objectCreated(aCreated);
87     ModuleBase_ITreeNode* aParent;
88     int aRow = 0;
89     QModelIndex aParentIndex1, aParentIndex2;
90     ObjectPtr aObj;
91     bool aRebuildAll = false;
92
93     foreach(ModuleBase_ITreeNode* aNode, aNodes) {
94       aObj = aNode->object();
95       aParent = aNode->parent();
96       if (aObj.get() && (aObj->groupName() == ModelAPI_Folder::group())) {
97         aParent->update();
98         aRebuildAll = true;
99       }
100       else {
101         aRow = aParent->nodeRow(aNode);
102         aParentIndex1 = getParentIndex(aNode, 0);
103         aParentIndex2 = getParentIndex(aNode, 2);
104         insertRows(aRow, 1, aParentIndex1);
105         dataChanged(aParentIndex1, aParentIndex2);
106       }
107     }
108     if (aRebuildAll)
109       rebuildDataTree();
110
111     emit treeRebuilt();
112   }
113   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
114     std::shared_ptr<ModelAPI_ObjectDeletedMessage> aUpdMsg =
115       std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
116     const std::list<std::pair<std::shared_ptr<ModelAPI_Document>, std::string>>& aMsgGroups =
117       aUpdMsg->groups();
118     QTreeNodesList aList;
119     std::list<std::pair<std::shared_ptr<ModelAPI_Document>, std::string>>::const_iterator aIt;
120     emit beforeTreeRebuild();
121     for (aIt = aMsgGroups.cbegin(); aIt != aMsgGroups.cend(); aIt++) {
122       aList.append(myRoot->objectsDeleted(aIt->first, aIt->second.c_str()));
123     }
124     // Remove obsolete nodes
125     QTreeNodesList aRemaining;
126     foreach(ModuleBase_ITreeNode* aNode, aList) {
127       if (myRoot->hasSubNode(aNode))
128         aRemaining.append(aNode);
129     }
130     // Update remaining nodes
131     foreach(ModuleBase_ITreeNode* aNode, aRemaining) {
132       if (aNode->parent())
133         aNode->parent()->update();
134     }
135     rebuildDataTree();
136     emit treeRebuilt();
137   }
138   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)) {
139     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
140       std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
141     std::set<ObjectPtr> aObjects = aUpdMsg->objects();
142
143     QObjectPtrList aCreated;
144     std::set<ObjectPtr>::const_iterator aIt;
145     bool aRebuildAll = false;
146     emit beforeTreeRebuild();
147     for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) {
148       ObjectPtr aObj = (*aIt);
149       if (!aObj->isInHistory())
150         continue;
151
152       if (aObj->data()->isValid()) {
153         if (aObj->groupName() == ModelAPI_Folder::group()) {
154           aRebuildAll = true;
155           break;
156         }
157         aCreated.append(*aIt);
158       }
159     }
160     if (aRebuildAll) {
161       myRoot->update();
162     }
163     else {
164       QSet<ModuleBase_ITreeNode*> aParents;
165       foreach(ObjectPtr aObj, aCreated) {
166         ModuleBase_ITreeNode* aNode = myRoot->subNode(aObj);
167         if (aNode) {
168           if (aNode->parent()) {
169             if (aNode->parent() == myRoot) {
170               aParents.clear();
171               aParents.insert(myRoot);
172               break;
173             }
174             else {
175               aNode = aNode->parent();
176             }
177           }
178           aParents.insert(aNode);
179         }
180       }
181       foreach(ModuleBase_ITreeNode* aNode, aParents) {
182         aNode->update();
183       }
184     }
185     rebuildDataTree();
186     emit treeRebuilt();
187   }
188   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_ORDER_UPDATED)) {
189     std::shared_ptr<ModelAPI_OrderUpdatedMessage> aUpdMsg =
190       std::dynamic_pointer_cast<ModelAPI_OrderUpdatedMessage>(theMessage);
191     if (aUpdMsg->reordered().get()) {
192       DocumentPtr aDoc = aUpdMsg->reordered()->document();
193       std::string aGroup = aUpdMsg->reordered()->group();
194       ModuleBase_ITreeNode* aNode = myRoot->findParent(aDoc, aGroup.c_str());
195       if (aNode) {
196         emit beforeTreeRebuild();
197         aNode->update();
198         rebuildDataTree();
199         emit treeRebuilt();
200       }
201     }
202   }
203   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_DOCUMENT_CHANGED)) {
204     if (ModelAPI_Session::get()->hasModuleDocument()) {
205       DocumentPtr aDoc = ModelAPI_Session::get()->activeDocument();
206       ModuleBase_ITreeNode* aRoot = myRoot->findRoot(aDoc);
207       if (aRoot) {
208         updateSubTree(aRoot);
209       }
210     }
211   }
212   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY)) {
213     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
214       std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
215     std::set<ObjectPtr> aObjects = aUpdMsg->objects();
216
217     QObjectPtrList aCreated;
218     std::set<ObjectPtr>::const_iterator aIt;
219     for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) {
220       ObjectPtr aObj = (*aIt);
221       if (aObj->groupName() == ModelAPI_ResultField::group()) {
222         aCreated.append(aObj);
223       }
224     }
225     if (aCreated.length() == 0)
226       return;
227     emit beforeTreeRebuild();
228     foreach(ObjectPtr aObj, aCreated) {
229       ModuleBase_ITreeNode* aNode = myRoot->subNode(aObj);
230       if (aNode) {
231         int aOldNb = aNode->childrenCount();
232         aNode->update();
233         int aNewNb = aNode->childrenCount();
234
235         QModelIndex aFirstIdx = getIndex(aNode, 0);
236         QModelIndex aLastIdx = getIndex(aNode, 2);
237
238         if (aNewNb > aOldNb) {
239           insertRows(aOldNb - 1, aNewNb - aOldNb, aFirstIdx);
240         }
241         else if (aNewNb < aOldNb) {
242           if (aNewNb)
243             removeRows(aNewNb - 1, aOldNb - aNewNb, aFirstIdx);
244           else if (aOldNb)
245             removeRows(0, aOldNb, aFirstIdx);
246         }
247         dataChanged(aFirstIdx, aLastIdx);
248       }
249     }
250     emit treeRebuilt();
251   }
252 }
253
254 //******************************************************
255 void XGUI_DataModel::clear()
256 {
257   beginResetModel();
258   endResetModel();
259 }
260
261 //******************************************************
262 void XGUI_DataModel::rebuildDataTree()
263 {
264   beginResetModel();
265   endResetModel();
266 }
267
268 //******************************************************
269 ObjectPtr XGUI_DataModel::object(const QModelIndex& theIndex) const
270 {
271   if (theIndex.isValid()) {
272     ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
273     return aNode->object();
274   }
275   return ObjectPtr();
276 }
277
278 //******************************************************
279 QModelIndex XGUI_DataModel::objectIndex(const ObjectPtr theObject, int theColumn) const
280 {
281   ModuleBase_ITreeNode* aNode = myRoot->subNode(theObject);
282   if (aNode) {
283     return getIndex(aNode, theColumn);
284   }
285   return QModelIndex();
286 }
287
288 //******************************************************
289 QVariant XGUI_DataModel::data(const QModelIndex& theIndex, int theRole) const
290 {
291   if (theIndex.isValid()) {
292     ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
293     return aNode->data(theIndex.column(), theRole);
294   }
295   return QVariant();
296 }
297
298 //******************************************************
299 QVariant XGUI_DataModel::headerData(int theSection, Qt::Orientation theOrient, int theRole) const
300 {
301   return QVariant();
302 }
303
304 //******************************************************
305 int XGUI_DataModel::rowCount(const QModelIndex& theParent) const
306 {
307   ModuleBase_ITreeNode* aParentNode = (theParent.isValid()) ?
308     (ModuleBase_ITreeNode*)theParent.internalPointer() : myRoot;
309   return aParentNode->childrenCount();
310 }
311
312 //******************************************************
313 int XGUI_DataModel::columnCount(const QModelIndex& theParent) const
314 {
315   return 3;
316 }
317
318 //******************************************************
319 QModelIndex XGUI_DataModel::index(int theRow, int theColumn, const QModelIndex &theParent) const
320 {
321   ModuleBase_ITreeNode* aParentNode = (theParent.isValid()) ?
322     (ModuleBase_ITreeNode*)theParent.internalPointer() : myRoot;
323   ModuleBase_ITreeNode* aSubNode = aParentNode->subNode(theRow);
324   assert(aSubNode);
325   return createIndex(theRow, theColumn, aSubNode);
326 }
327
328 //******************************************************
329 QModelIndex XGUI_DataModel::parent(const QModelIndex& theIndex) const
330 {
331   if (theIndex.isValid()) {
332     ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
333     return getParentIndex(aNode, 1);
334   }
335   return QModelIndex();
336 }
337
338 //******************************************************
339 bool XGUI_DataModel::hasChildren(const QModelIndex& theParent) const
340 {
341   ModuleBase_ITreeNode* aParentNode = (theParent.isValid()) ?
342     (ModuleBase_ITreeNode*)theParent.internalPointer() : myRoot;
343   return aParentNode->childrenCount() > 0;
344 }
345
346 //******************************************************
347 bool XGUI_DataModel::insertRows(int theRow, int theCount, const QModelIndex& theParent)
348 {
349   beginInsertRows(theParent, theRow, theRow + theCount - 1);
350   endInsertRows();
351   return true;
352 }
353
354 //******************************************************
355 bool XGUI_DataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent)
356 {
357   beginRemoveRows(theParent, theRow, theRow + theCount - 1);
358   endRemoveRows();
359   return true;
360 }
361
362 //******************************************************
363 Qt::ItemFlags XGUI_DataModel::flags(const QModelIndex& theIndex) const
364 {
365   if (theIndex.isValid()) {
366     ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
367     return aNode->flags(theIndex.column());
368   }
369   return Qt::ItemFlags();
370 }
371
372
373 //******************************************************
374 QModelIndex XGUI_DataModel::documentRootIndex(DocumentPtr theDoc, int theColumn) const
375 {
376   SessionPtr aSession = ModelAPI_Session::get();
377   DocumentPtr aRootDoc = aSession->moduleDocument();
378   if (theDoc == aRootDoc)
379     return QModelIndex();
380   else {
381     ModuleBase_ITreeNode* aDocNode = 0;
382     foreach(ModuleBase_ITreeNode* aNode, myRoot->children()) {
383       if (aNode->document() == theDoc) {
384         aDocNode = aNode;
385         break;
386       }
387     }
388     if (aDocNode)
389       return getIndex(aDocNode, theColumn);
390   }
391   return QModelIndex();
392 }
393
394 //******************************************************
395 bool XGUI_DataModel::hasHiddenState(const QModelIndex& theIndex)
396 {
397   if (theIndex.isValid()) {
398     ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
399     return aNode->visibilityState() == ModuleBase_ITreeNode::Hidden;
400   }
401   return false;
402 }
403
404 //******************************************************
405 bool XGUI_DataModel::hasIndex(const QModelIndex& theIndex) const
406 {
407   ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
408   return myRoot->hasSubNode(aNode);
409 }
410
411 //******************************************************
412 QModelIndex XGUI_DataModel::getParentIndex(ModuleBase_ITreeNode* theNode, int thCol) const
413 {
414   ModuleBase_ITreeNode* aParent = theNode->parent();
415   if (aParent == myRoot) {
416     return QModelIndex();
417   } else {
418     return getIndex(aParent, thCol);
419   }
420 }
421
422 //******************************************************
423 QModelIndex XGUI_DataModel::getIndex(ModuleBase_ITreeNode* theNode, int thCol) const
424 {
425   if (theNode == myRoot)
426     return QModelIndex();
427   int aRow = theNode->parent()->nodeRow(theNode);
428   return createIndex(aRow, thCol, theNode);
429 }
430
431
432 //******************************************************
433 void XGUI_DataModel::updateSubTree(ModuleBase_ITreeNode* theParent)
434 {
435   int aRows = theParent->childrenCount();
436   if (aRows) {
437     QModelIndex aParent = getIndex(theParent, 0);
438     QModelIndex aFirstIdx = aParent.child(0, 0);
439     QModelIndex aLastIdx = aParent.child(aRows - 1, 2);
440     dataChanged(aFirstIdx, aLastIdx);
441   }
442 }
443
444
445 //******************************************************
446 DocumentPtr XGUI_DataModel::document(const QModelIndex& theIndex) const
447 {
448   ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
449   return aNode->document();
450 }
451
452
453 //******************************************************
454 bool XGUI_DataModel::hasNode(ModuleBase_ITreeNode* theNode) const
455 {
456   return myRoot->hasSubNode(theNode);
457 }