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