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