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