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