Salome HOME
Optimize updating of the tree
[modules/shaper.git] / src / XGUI / XGUI_DataModel.cpp
1 // Copyright (C) 2014-2017  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
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include "XGUI_DataModel.h"
22 #include "XGUI_ObjectsBrowser.h"
23
24 #include <ModuleBase_IconFactory.h>
25 #include <ModuleBase_ITreeNode.h>
26
27 #include <ModelAPI_Session.h>
28 #include <ModelAPI_ResultField.h>
29
30 #include <Config_FeatureMessage.h>
31
32 #include <Events_Loop.h>
33
34 #include <cassert>
35
36
37
38 // Constructor *************************************************
39 XGUI_DataModel::XGUI_DataModel(QObject* theParent) : QAbstractItemModel(theParent)//,
40   //myIsEventsProcessingBlocked(false)
41 {
42   XGUI_ObjectsBrowser* aOB = qobject_cast<XGUI_ObjectsBrowser*>(theParent);
43   myWorkshop = aOB->workshop();
44
45   Events_Loop* aLoop = Events_Loop::loop();
46   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
47   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
48   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
49   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_ORDER_UPDATED));
50   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_DOCUMENT_CHANGED));
51   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
52 }
53
54 XGUI_DataModel::~XGUI_DataModel()
55 {
56   clear();
57 }
58
59 //******************************************************
60 void XGUI_DataModel::processEvent(const std::shared_ptr<Events_Message>& theMessage)
61 {
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();
66     QObjectPtrList aCreated;
67     std::set<ObjectPtr>::const_iterator aIt;
68     for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) {
69       if ((*aIt)->isInHistory())
70         aCreated.append(*aIt);
71     }
72     QTreeNodesList aNodes = myRoot->objectCreated(aCreated);
73     ModuleBase_ITreeNode* aParent;
74     int aRow = 0;
75     QModelIndex aParentIndex1, aParentIndex2;
76     ObjectPtr aObj;
77     foreach(ModuleBase_ITreeNode* aNode, aNodes) {
78       aObj = aNode->object();
79       aParent = aNode->parent();
80       if (aObj.get() && (aObj->groupName() == ModelAPI_Folder::group())) {
81         aParent->update();
82         rebuildDataTree();
83       }
84       else {
85         aRow = aParent->nodeRow(aNode);
86         aParentIndex1 = getParentIndex(aNode, 0);
87         aParentIndex2 = getParentIndex(aNode, 2);
88         insertRows(aRow, 1, aParentIndex1);
89         dataChanged(aParentIndex1, aParentIndex2);
90       }
91     }
92   }
93   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
94     std::shared_ptr<ModelAPI_ObjectDeletedMessage> aUpdMsg =
95       std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
96     const std::list<std::pair<std::shared_ptr<ModelAPI_Document>, std::string>>& aMsgGroups =
97       aUpdMsg->groups();
98     QTreeNodesList aList;
99     std::list<std::pair<std::shared_ptr<ModelAPI_Document>, std::string>>::const_iterator aIt;
100     for (aIt = aMsgGroups.cbegin(); aIt != aMsgGroups.cend(); aIt++) {
101       aList.append(myRoot->objectsDeleted(aIt->first, aIt->second.c_str()));
102     }
103     // Remove obsolete nodes
104     QTreeNodesList aRemaining;
105     foreach(ModuleBase_ITreeNode* aNode, aList) {
106       if (myRoot->hasSubNode(aNode))
107         aRemaining.append(aNode);
108     }
109     // Update remaining nodes
110     foreach(ModuleBase_ITreeNode* aNode, aRemaining) {
111       if (aNode->parent())
112         aNode->parent()->update();
113     }
114     rebuildDataTree();
115   }
116   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)) {
117     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
118       std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
119     std::set<ObjectPtr> aObjects = aUpdMsg->objects();
120
121     QObjectPtrList aCreated;
122     std::set<ObjectPtr>::const_iterator aIt;
123     bool aRebuildAll = false;
124     for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) {
125       ObjectPtr aObj = (*aIt);
126       if (!aObj->isInHistory())
127         continue;
128
129       if (aObj->data()->isValid()) {
130         if (aObj->groupName() == ModelAPI_Folder::group()) {
131           aRebuildAll = true;
132           break;
133         }
134         aCreated.append(*aIt);
135       }
136     }
137     if (aRebuildAll) {
138       myRoot->update();
139       rebuildDataTree();
140     }
141     else {
142       QTreeNodesList aParents;
143       foreach(ObjectPtr aObj, aCreated) {
144         ModuleBase_ITreeNode* aNode = myRoot->subNode(aObj);
145         if (aNode) {
146           if (aNode->parent())
147             aNode = aNode->parent();
148           if (!aParents.contains(aNode))
149             aParents.append(aNode);
150         }
151       }
152       foreach(ModuleBase_ITreeNode* aNode, aParents) {
153         aNode->update();
154       }
155       rebuildDataTree();
156     }
157   }
158   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_ORDER_UPDATED)) {
159     std::shared_ptr<ModelAPI_OrderUpdatedMessage> aUpdMsg =
160       std::dynamic_pointer_cast<ModelAPI_OrderUpdatedMessage>(theMessage);
161     if (aUpdMsg->reordered().get()) {
162       DocumentPtr aDoc = aUpdMsg->reordered()->document();
163       std::string aGroup = aUpdMsg->reordered()->group();
164       ModuleBase_ITreeNode* aNode = myRoot->findParent(aDoc, aGroup.c_str());
165       if (aNode) {
166         aNode->update();
167         rebuildDataTree();
168       }
169     }
170   }
171   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_DOCUMENT_CHANGED)) {
172     DocumentPtr aDoc = ModelAPI_Session::get()->activeDocument();
173     ModuleBase_ITreeNode* aRoot = myRoot->findRoot(aDoc);
174     if (aRoot) {
175       updateSubTree(aRoot);
176     }
177   }
178   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY)) {
179     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
180       std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
181     std::set<ObjectPtr> aObjects = aUpdMsg->objects();
182
183     QObjectPtrList aCreated;
184     std::set<ObjectPtr>::const_iterator aIt;
185     bool aRebuildAll = false;
186     for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) {
187       ObjectPtr aObj = (*aIt);
188       if (aObj->groupName() == ModelAPI_ResultField::group()) {
189         aCreated.append(aObj);
190       }
191     }
192     foreach(ObjectPtr aObj, aCreated) {
193       ModuleBase_ITreeNode* aNode = myRoot->subNode(aObj);
194       if (aNode) {
195         int aOldNb = aNode->childrenCount();
196         aNode->update();
197         int aNewNb = aNode->childrenCount();
198
199         QModelIndex aFirstIdx = getIndex(aNode, 0);
200         QModelIndex aLastIdx = getIndex(aNode, 2);
201
202         if (aNewNb > aOldNb) {
203           insertRows(aOldNb - 1, aNewNb - aOldNb, aFirstIdx);
204         }
205         else if (aNewNb < aOldNb) {
206           if (aNewNb)
207             removeRows(aNewNb - 1, aOldNb - aNewNb, aFirstIdx);
208           else if (aOldNb)
209             removeRows(0, aOldNb, aFirstIdx);
210         }
211         dataChanged(aFirstIdx, aLastIdx);
212       }
213     }
214   }
215 }
216
217 //******************************************************
218 void XGUI_DataModel::clear()
219 {
220   beginResetModel();
221   endResetModel();
222 }
223
224 //******************************************************
225 void XGUI_DataModel::rebuildDataTree()
226 {
227   beginResetModel();
228   endResetModel();
229   emit treeRebuilt();
230 }
231
232 //******************************************************
233 ObjectPtr XGUI_DataModel::object(const QModelIndex& theIndex) const
234 {
235   if (theIndex.isValid()) {
236     ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
237     return aNode->object();
238   }
239   return ObjectPtr();
240 }
241
242 //******************************************************
243 QModelIndex XGUI_DataModel::objectIndex(const ObjectPtr theObject, int theColumn) const
244 {
245   ModuleBase_ITreeNode* aNode = myRoot->subNode(theObject);
246   if (aNode) {
247     return getIndex(aNode, theColumn);
248   }
249   return QModelIndex();
250 }
251
252 //******************************************************
253 QVariant XGUI_DataModel::data(const QModelIndex& theIndex, int theRole) const
254 {
255   if (theIndex.isValid()) {
256     ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
257     return aNode->data(theIndex.column(), theRole);
258   }
259   return QVariant();
260 }
261
262 //******************************************************
263 QVariant XGUI_DataModel::headerData(int theSection, Qt::Orientation theOrient, int theRole) const
264 {
265   return QVariant();
266 }
267
268 //******************************************************
269 int XGUI_DataModel::rowCount(const QModelIndex& theParent) const
270 {
271   ModuleBase_ITreeNode* aParentNode = (theParent.isValid()) ?
272     (ModuleBase_ITreeNode*)theParent.internalPointer() : myRoot;
273   return aParentNode->childrenCount();
274 }
275
276 //******************************************************
277 int XGUI_DataModel::columnCount(const QModelIndex& theParent) const
278 {
279   return 3;
280 }
281
282 //******************************************************
283 QModelIndex XGUI_DataModel::index(int theRow, int theColumn, const QModelIndex &theParent) const
284 {
285   ModuleBase_ITreeNode* aParentNode = (theParent.isValid()) ?
286     (ModuleBase_ITreeNode*)theParent.internalPointer() : myRoot;
287   ModuleBase_ITreeNode* aSubNode = aParentNode->subNode(theRow);
288   assert(aSubNode);
289   return createIndex(theRow, theColumn, aSubNode);
290 }
291
292 //******************************************************
293 QModelIndex XGUI_DataModel::parent(const QModelIndex& theIndex) const
294 {
295   if (theIndex.isValid()) {
296     ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
297     return getParentIndex(aNode, 1);
298   }
299   return QModelIndex();
300 }
301
302 //******************************************************
303 bool XGUI_DataModel::hasChildren(const QModelIndex& theParent) const
304 {
305   ModuleBase_ITreeNode* aParentNode = (theParent.isValid()) ?
306     (ModuleBase_ITreeNode*)theParent.internalPointer() : myRoot;
307   return aParentNode->childrenCount() > 0;
308 }
309
310 //******************************************************
311 bool XGUI_DataModel::insertRows(int theRow, int theCount, const QModelIndex& theParent)
312 {
313   beginInsertRows(theParent, theRow, theRow + theCount - 1);
314   endInsertRows();
315   return true;
316 }
317
318 //******************************************************
319 bool XGUI_DataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent)
320 {
321   beginRemoveRows(theParent, theRow, theRow + theCount - 1);
322   endRemoveRows();
323   return true;
324 }
325
326 //******************************************************
327 Qt::ItemFlags XGUI_DataModel::flags(const QModelIndex& theIndex) const
328 {
329   if (theIndex.isValid()) {
330     ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
331     return aNode->flags(theIndex.column());
332   }
333   return Qt::ItemFlags();
334 }
335
336
337 //******************************************************
338 QModelIndex XGUI_DataModel::documentRootIndex(DocumentPtr theDoc, int theColumn) const
339 {
340   SessionPtr aSession = ModelAPI_Session::get();
341   DocumentPtr aRootDoc = aSession->moduleDocument();
342   if (theDoc == aRootDoc)
343     return QModelIndex();
344   else {
345     ModuleBase_ITreeNode* aDocNode = 0;
346     foreach(ModuleBase_ITreeNode* aNode, myRoot->children()) {
347       if (aNode->document() == theDoc) {
348         aDocNode = aNode;
349         break;
350       }
351     }
352     if (aDocNode)
353       return getIndex(aDocNode, theColumn);
354   }
355   return QModelIndex();
356 }
357
358 //******************************************************
359 bool XGUI_DataModel::hasHiddenState(const QModelIndex& theIndex)
360 {
361   if (theIndex.isValid()) {
362     ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
363     return aNode->visibilityState() == ModuleBase_ITreeNode::Hidden;
364   }
365   return false;
366 }
367
368 //******************************************************
369 bool XGUI_DataModel::hasIndex(const QModelIndex& theIndex) const
370 {
371   ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
372   return myRoot->hasSubNode(aNode);
373 }
374
375 //******************************************************
376 QModelIndex XGUI_DataModel::getParentIndex(ModuleBase_ITreeNode* theNode, int thCol) const
377 {
378   ModuleBase_ITreeNode* aParent = theNode->parent();
379   if (aParent == myRoot) {
380     return QModelIndex();
381   } else {
382     return getIndex(aParent, thCol);
383   }
384 }
385
386 //******************************************************
387 QModelIndex XGUI_DataModel::getIndex(ModuleBase_ITreeNode* theNode, int thCol) const
388 {
389   if (theNode == myRoot)
390     return QModelIndex();
391   int aRow = theNode->parent()->nodeRow(theNode);
392   return createIndex(aRow, thCol, theNode);
393 }
394
395
396 //******************************************************
397 void XGUI_DataModel::updateSubTree(ModuleBase_ITreeNode* theParent)
398 {
399   int aRows = theParent->childrenCount();
400   if (aRows) {
401     QModelIndex aParent = getIndex(theParent, 0);
402     QModelIndex aFirstIdx = aParent.child(0, 0);
403     QModelIndex aLastIdx = aParent.child(aRows - 1, 2);
404     dataChanged(aFirstIdx, aLastIdx);
405   }
406 }
407
408
409 //******************************************************
410 DocumentPtr XGUI_DataModel::document(const QModelIndex& theIndex) const
411 {
412   ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
413   return aNode->document();
414 }