Salome HOME
Issue #2916: Remember expanded items before Object Browser update and restore them...
[modules/shaper.git] / src / XGUI / XGUI_DataModel.cpp
1 // Copyright (C) 2014-2019  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
36
37 // Constructor *************************************************
38 XGUI_DataModel::XGUI_DataModel(QObject* theParent) : QAbstractItemModel(theParent)//,
39   //myIsEventsProcessingBlocked(false)
40 {
41   XGUI_ObjectsBrowser* aOB = qobject_cast<XGUI_ObjectsBrowser*>(theParent);
42   myWorkshop = aOB->workshop();
43
44   Events_Loop* aLoop = Events_Loop::loop();
45   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
46   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
47   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
48   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_ORDER_UPDATED));
49   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_DOCUMENT_CHANGED));
50   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
51 }
52
53 XGUI_DataModel::~XGUI_DataModel()
54 {
55   clear();
56 }
57
58 //******************************************************
59 void XGUI_DataModel::processEvent(const std::shared_ptr<Events_Message>& theMessage)
60 {
61   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)) {
62     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
63       std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
64     std::set<ObjectPtr> aObjects = aUpdMsg->objects();
65     QObjectPtrList aCreated;
66     std::set<ObjectPtr>::const_iterator aIt;
67     for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) {
68       if ((*aIt)->isInHistory())
69         aCreated.append(*aIt);
70     }
71     if (aCreated.length() == 0)
72       return;
73
74     emit beforeTreeRebuild();
75     QTreeNodesList aNodes = myRoot->objectCreated(aCreated);
76     ModuleBase_ITreeNode* aParent;
77     int aRow = 0;
78     QModelIndex aParentIndex1, aParentIndex2;
79     ObjectPtr aObj;
80     bool aRebuildAll = false;
81     bool isInserted = false;
82
83     foreach(ModuleBase_ITreeNode* aNode, aNodes) {
84       aObj = aNode->object();
85       aParent = aNode->parent();
86       if (aObj.get() && (aObj->groupName() == ModelAPI_Folder::group())) {
87         aParent->update();
88         aRebuildAll = true;
89       }
90       else {
91         aRow = aParent->nodeRow(aNode);
92         aParentIndex1 = getParentIndex(aNode, 0);
93         aParentIndex2 = getParentIndex(aNode, 2);
94         insertRows(aRow, 1, aParentIndex1);
95         dataChanged(aParentIndex1, aParentIndex2);
96         isInserted = true;
97       }
98     }
99     if (aRebuildAll)
100       rebuildDataTree();
101     else if (isInserted)
102       endInsertRows();
103
104     emit treeRebuilt();
105   }
106   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
107     std::shared_ptr<ModelAPI_ObjectDeletedMessage> aUpdMsg =
108       std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
109     const std::list<std::pair<std::shared_ptr<ModelAPI_Document>, std::string>>& aMsgGroups =
110       aUpdMsg->groups();
111     QTreeNodesList aList;
112     std::list<std::pair<std::shared_ptr<ModelAPI_Document>, std::string>>::const_iterator aIt;
113     emit beforeTreeRebuild();
114     for (aIt = aMsgGroups.cbegin(); aIt != aMsgGroups.cend(); aIt++) {
115       aList.append(myRoot->objectsDeleted(aIt->first, aIt->second.c_str()));
116     }
117     // Remove obsolete nodes
118     QTreeNodesList aRemaining;
119     foreach(ModuleBase_ITreeNode* aNode, aList) {
120       if (myRoot->hasSubNode(aNode))
121         aRemaining.append(aNode);
122     }
123     // Update remaining nodes
124     foreach(ModuleBase_ITreeNode* aNode, aRemaining) {
125       if (aNode->parent())
126         aNode->parent()->update();
127     }
128     rebuildDataTree();
129     emit treeRebuilt();
130   }
131   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)) {
132     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
133       std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
134     std::set<ObjectPtr> aObjects = aUpdMsg->objects();
135
136     QObjectPtrList aCreated;
137     std::set<ObjectPtr>::const_iterator aIt;
138     bool aRebuildAll = false;
139     emit beforeTreeRebuild();
140     for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) {
141       ObjectPtr aObj = (*aIt);
142       if (!aObj->isInHistory())
143         continue;
144
145       if (aObj->data()->isValid()) {
146         if (aObj->groupName() == ModelAPI_Folder::group()) {
147           aRebuildAll = true;
148           break;
149         }
150         aCreated.append(*aIt);
151       }
152     }
153     if (aRebuildAll) {
154       myRoot->update();
155     }
156     else {
157       QSet<ModuleBase_ITreeNode*> aParents;
158       foreach(ObjectPtr aObj, aCreated) {
159         ModuleBase_ITreeNode* aNode = myRoot->subNode(aObj);
160         if (aNode) {
161           if (aNode->parent()) {
162             if (aNode->parent() == myRoot) {
163               aParents.clear();
164               aParents.insert(myRoot);
165               break;
166             }
167             else {
168               aNode = aNode->parent();
169             }
170           }
171           aParents.insert(aNode);
172         }
173       }
174       foreach(ModuleBase_ITreeNode* aNode, aParents) {
175         aNode->update();
176       }
177     }
178     rebuildDataTree();
179     emit treeRebuilt();
180   }
181   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_ORDER_UPDATED)) {
182     std::shared_ptr<ModelAPI_OrderUpdatedMessage> aUpdMsg =
183       std::dynamic_pointer_cast<ModelAPI_OrderUpdatedMessage>(theMessage);
184     if (aUpdMsg->reordered().get()) {
185       DocumentPtr aDoc = aUpdMsg->reordered()->document();
186       std::string aGroup = aUpdMsg->reordered()->group();
187       ModuleBase_ITreeNode* aNode = myRoot->findParent(aDoc, aGroup.c_str());
188       if (aNode) {
189         emit beforeTreeRebuild();
190         aNode->update();
191         rebuildDataTree();
192         emit treeRebuilt();
193       }
194     }
195   }
196   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_DOCUMENT_CHANGED)) {
197     DocumentPtr aDoc = ModelAPI_Session::get()->activeDocument();
198     ModuleBase_ITreeNode* aRoot = myRoot->findRoot(aDoc);
199     if (aRoot) {
200       updateSubTree(aRoot);
201     }
202   }
203   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY)) {
204     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
205       std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
206     std::set<ObjectPtr> aObjects = aUpdMsg->objects();
207
208     QObjectPtrList aCreated;
209     std::set<ObjectPtr>::const_iterator aIt;
210     bool aRebuildAll = false;
211     for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) {
212       ObjectPtr aObj = (*aIt);
213       if (aObj->groupName() == ModelAPI_ResultField::group()) {
214         aCreated.append(aObj);
215       }
216     }
217     if (aCreated.length() == 0)
218       return;
219     bool isInsert = false;
220     bool isRemove = false;
221     emit beforeTreeRebuild();
222     foreach(ObjectPtr aObj, aCreated) {
223       ModuleBase_ITreeNode* aNode = myRoot->subNode(aObj);
224       if (aNode) {
225         int aOldNb = aNode->childrenCount();
226         aNode->update();
227         int aNewNb = aNode->childrenCount();
228
229         QModelIndex aFirstIdx = getIndex(aNode, 0);
230         QModelIndex aLastIdx = getIndex(aNode, 2);
231
232         if (aNewNb > aOldNb) {
233           insertRows(aOldNb - 1, aNewNb - aOldNb, aFirstIdx);
234           isInsert = true;
235         }
236         else if (aNewNb < aOldNb) {
237           if (aNewNb)
238             removeRows(aNewNb - 1, aOldNb - aNewNb, aFirstIdx);
239           else if (aOldNb)
240             removeRows(0, aOldNb, aFirstIdx);
241           isRemove = aNewNb || aOldNb;
242         }
243         dataChanged(aFirstIdx, aLastIdx);
244       }
245     }
246     if (isRemove)
247       endRemoveRows();
248     if (isInsert)
249       endInsertRows();
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   return true;
351 }
352
353 //******************************************************
354 bool XGUI_DataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent)
355 {
356   beginRemoveRows(theParent, theRow, theRow + theCount - 1);
357   return true;
358 }
359
360 //******************************************************
361 Qt::ItemFlags XGUI_DataModel::flags(const QModelIndex& theIndex) const
362 {
363   if (theIndex.isValid()) {
364     ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
365     return aNode->flags(theIndex.column());
366   }
367   return Qt::ItemFlags();
368 }
369
370
371 //******************************************************
372 QModelIndex XGUI_DataModel::documentRootIndex(DocumentPtr theDoc, int theColumn) const
373 {
374   SessionPtr aSession = ModelAPI_Session::get();
375   DocumentPtr aRootDoc = aSession->moduleDocument();
376   if (theDoc == aRootDoc)
377     return QModelIndex();
378   else {
379     ModuleBase_ITreeNode* aDocNode = 0;
380     foreach(ModuleBase_ITreeNode* aNode, myRoot->children()) {
381       if (aNode->document() == theDoc) {
382         aDocNode = aNode;
383         break;
384       }
385     }
386     if (aDocNode)
387       return getIndex(aDocNode, theColumn);
388   }
389   return QModelIndex();
390 }
391
392 //******************************************************
393 bool XGUI_DataModel::hasHiddenState(const QModelIndex& theIndex)
394 {
395   if (theIndex.isValid()) {
396     ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
397     return aNode->visibilityState() == ModuleBase_ITreeNode::Hidden;
398   }
399   return false;
400 }
401
402 //******************************************************
403 bool XGUI_DataModel::hasIndex(const QModelIndex& theIndex) const
404 {
405   ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
406   return myRoot->hasSubNode(aNode);
407 }
408
409 //******************************************************
410 QModelIndex XGUI_DataModel::getParentIndex(ModuleBase_ITreeNode* theNode, int thCol) const
411 {
412   ModuleBase_ITreeNode* aParent = theNode->parent();
413   if (aParent == myRoot) {
414     return QModelIndex();
415   } else {
416     return getIndex(aParent, thCol);
417   }
418 }
419
420 //******************************************************
421 QModelIndex XGUI_DataModel::getIndex(ModuleBase_ITreeNode* theNode, int thCol) const
422 {
423   if (theNode == myRoot)
424     return QModelIndex();
425   int aRow = theNode->parent()->nodeRow(theNode);
426   return createIndex(aRow, thCol, theNode);
427 }
428
429
430 //******************************************************
431 void XGUI_DataModel::updateSubTree(ModuleBase_ITreeNode* theParent)
432 {
433   int aRows = theParent->childrenCount();
434   if (aRows) {
435     QModelIndex aParent = getIndex(theParent, 0);
436     QModelIndex aFirstIdx = aParent.child(0, 0);
437     QModelIndex aLastIdx = aParent.child(aRows - 1, 2);
438     dataChanged(aFirstIdx, aLastIdx);
439   }
440 }
441
442
443 //******************************************************
444 DocumentPtr XGUI_DataModel::document(const QModelIndex& theIndex) const
445 {
446   ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer();
447   return aNode->document();
448 }