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