]> SALOME platform Git repositories - modules/shaper.git/blob - src/XGUI/XGUI_DocumentDataModel.cpp
Salome HOME
Migration on new model architecture
[modules/shaper.git] / src / XGUI / XGUI_DocumentDataModel.cpp
1 #include "XGUI_DocumentDataModel.h"
2 #include "XGUI_PartDataModel.h"
3 #include "XGUI_Workshop.h"
4 #include "XGUI_Tools.h"
5
6 #include <ModelAPI_PluginManager.h>
7 #include <ModelAPI_Document.h>
8 #include <ModelAPI_Feature.h>
9 #include <ModelAPI_Data.h>
10 #include <ModelAPI_ResultPart.h>
11 #include <Model_Events.h>
12 #include <ModelAPI_Object.h>
13
14 #include <Events_Loop.h>
15
16 #include <Config_FeatureMessage.h>
17
18 #include <QIcon>
19 #include <QString>
20 #include <QBrush>
21
22
23 #define ACTIVE_COLOR QColor(0,72,140)
24 #define PASSIVE_COLOR Qt::black
25
26 XGUI_DocumentDataModel::XGUI_DocumentDataModel(QObject* theParent)
27   : QAbstractItemModel(theParent), myActivePart(0)
28 {
29   // Register in event loop
30   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
31   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
32   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
33
34   // Create a top part of data tree model
35   myModel = new XGUI_TopDataModel(this);
36   myModel->setItemsColor(ACTIVE_COLOR);
37 }
38
39
40 XGUI_DocumentDataModel::~XGUI_DocumentDataModel()
41 {
42   clearModelIndexes();
43 }
44
45
46 void XGUI_DocumentDataModel::processEvent(const Events_Message* theMessage)
47 {
48   DocumentPtr aRootDoc = ModelAPI_PluginManager::get()->rootDocument();
49
50   // Created object event *******************
51   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)) {
52     const Model_ObjectUpdatedMessage* aUpdMsg = dynamic_cast<const Model_ObjectUpdatedMessage*>(theMessage);
53     std::set<ObjectPtr> aFeatures = aUpdMsg->features();
54
55     std::set<ObjectPtr>::const_iterator aIt;
56     for (aIt = aFeatures.begin(); aIt != aFeatures.end(); ++aIt) {
57       ObjectPtr aFeature = (*aIt);
58       DocumentPtr aDoc = aFeature->document();
59       if (aDoc == aRootDoc) {  // If root objects
60         if (aFeature->groupName().compare(ModelAPI_ResultPart::group()) == 0) { // Update only Parts group
61           // Add a new part
62           int aStart = myPartModels.size();
63           XGUI_PartDataModel* aModel = new XGUI_PartDataModel(this);
64           aModel->setPartId(myPartModels.count());
65           myPartModels.append(aModel);
66           insertRow(aStart, partFolderNode());
67         } else { // Update top groups (other except parts
68           QModelIndex aIndex = myModel->findParent(aFeature);
69           int aStart = myModel->rowCount(aIndex) - 1;
70           aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
71           insertRow(aStart, aIndex);
72         }
73       } else { // if sub-objects of first level nodes
74         XGUI_PartModel* aPartModel = 0;
75         QList<XGUI_PartModel*>::const_iterator aIt;
76         for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
77           if ((*aIt)->hasDocument(aDoc)) {
78             aPartModel = (*aIt);
79             break;
80           }
81         }
82         if (aPartModel) {
83           QModelIndex aIndex = aPartModel->findParent(aFeature);
84           int aStart = aPartModel->rowCount(aIndex) - 1;
85           aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
86           insertRow(aStart, aIndex);
87         }
88       }
89     }
90   // Deleted object event ***********************
91   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
92     const Model_ObjectDeletedMessage* aUpdMsg = dynamic_cast<const Model_ObjectDeletedMessage*>(theMessage);
93     DocumentPtr aDoc = aUpdMsg->document();
94     std::set<std::string> aGroups = aUpdMsg->groups();
95
96     std::set<std::string>::const_iterator aIt;
97     for (aIt = aGroups.begin(); aIt != aGroups.end(); ++aIt) {
98       std::string aGroup = (*aIt);
99       if (aDoc == aRootDoc) {  // If root objects
100         if (aGroup.compare(ModelAPI_ResultPart::group()) == 0) { // Updsate only Parts group
101           int aStart = myPartModels.size() - 1;
102           removeSubModel(aStart);
103           removeRow(aStart, partFolderNode());
104           if (myActivePart && (!isPartSubModel(myActivePart))) {
105             myActivePart = 0;
106             myActivePartIndex = QModelIndex();
107             myModel->setItemsColor(ACTIVE_COLOR);
108           }
109         } else { // Update top groups (other except parts
110           QModelIndex aIndex = myModel->findGroup(aGroup);
111           int aStart = myModel->rowCount(aIndex);
112           aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
113           removeRow(aStart, aIndex);
114         }
115       } else {
116         XGUI_PartModel* aPartModel = 0;
117         QList<XGUI_PartModel*>::const_iterator aIt;
118         for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
119           if ((*aIt)->hasDocument(aDoc)) {
120             aPartModel = (*aIt);
121             break;
122           }
123         }
124         if (aPartModel) {
125           QModelIndex aIndex = aPartModel->findGroup(aGroup);
126           int aStart = aPartModel->rowCount(aIndex);
127           aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
128           removeRow(aStart, aIndex);
129         }
130       }
131     }
132   // Deleted object event ***********************
133   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)) {
134     //const Model_ObjectUpdatedMessage* aUpdMsg = dynamic_cast<const Model_ObjectUpdatedMessage*>(theMessage);
135     //ObjectPtr aFeature = aUpdMsg->feature();
136     //DocumentPtr aDoc = aFeature->document();
137     
138     // TODO: Identify the necessary index by the modified feature
139     QModelIndex aIndex;
140     emit dataChanged(aIndex, aIndex);
141
142   // Reset whole tree **************************
143   } else {  
144     rebuildDataTree();
145   }
146 }
147
148 void XGUI_DocumentDataModel::rebuildDataTree()
149 {
150   DocumentPtr aRootDoc = ModelAPI_PluginManager::get()->rootDocument();
151
152   beginResetModel();
153   clearModelIndexes();
154
155   int aNbParts = aRootDoc->size(ModelAPI_ResultPart::group());
156   if (myPartModels.size() != aNbParts) { // resize internal models
157     while (myPartModels.size() > aNbParts) {
158       delete myPartModels.last();
159       myPartModels.removeLast();
160     }
161     while (myPartModels.size() < aNbParts) {
162       myPartModels.append(new XGUI_PartDataModel(this));
163     }
164     for (int i = 0; i < myPartModels.size(); i++)
165       myPartModels.at(i)->setPartId(i);
166   }
167   endResetModel();
168 }
169
170 QVariant XGUI_DocumentDataModel::data(const QModelIndex& theIndex, int theRole) const
171 {
172   if (!theIndex.isValid())
173     return QVariant();
174   switch (theIndex.internalId()) {
175   case PartsFolder:
176     switch (theRole) {
177     case Qt::DisplayRole:
178       return tr("Parts") + QString(" (%1)").arg(rowCount(theIndex));
179     case Qt::DecorationRole:
180       return QIcon(":pictures/constr_folder.png");
181     case Qt::ToolTipRole:
182       return tr("Parts folder");
183     case Qt::ForegroundRole:
184       if (myActivePart)
185         return QBrush(PASSIVE_COLOR);
186       else
187         return QBrush(ACTIVE_COLOR);
188     default:
189       return QVariant();
190     }
191     break;
192   case HistoryNode:
193     {
194       int aOffset = historyOffset();
195       DocumentPtr aRootDoc = ModelAPI_PluginManager::get()->rootDocument();
196       ObjectPtr aFeature = aRootDoc->object(ModelAPI_Feature::group(), theIndex.row() - aOffset);
197       if (!aFeature)
198         return QVariant();
199       switch (theRole) {
200       case Qt::DisplayRole:
201         if (aFeature)
202           return aFeature->data()->name().c_str();
203         else 
204           return QVariant();
205       case Qt::DecorationRole:
206         return QIcon(XGUI_Workshop::featureIcon(aFeature->getKind()));
207       case Qt::ToolTipRole:
208         return tr("Feature object");
209       case Qt::ForegroundRole:
210         if (myActivePart)
211           return QBrush(PASSIVE_COLOR);
212         else
213           return QBrush(ACTIVE_COLOR);
214       default:
215         return QVariant();
216       }
217     }
218     break;
219   }
220   QModelIndex aParent = theIndex.parent();
221   if (aParent.isValid() && (aParent.internalId() == PartsFolder)) {
222     return myPartModels.at(theIndex.row())->data(QModelIndex(), theRole);
223   }
224   return toSourceModelIndex(theIndex)->data(theRole);
225 }
226
227
228 QVariant XGUI_DocumentDataModel::headerData(int theSection, Qt::Orientation theOrient, int theRole) const
229 {
230   return QVariant();
231 }
232
233 int XGUI_DocumentDataModel::rowCount(const QModelIndex& theParent) const
234 {
235   if (!theParent.isValid()) {
236     DocumentPtr aRootDoc = ModelAPI_PluginManager::get()->rootDocument();
237     // Size of external models
238     int aVal = historyOffset();
239     // Plus history size
240     aVal += aRootDoc->size(ModelAPI_Feature::group());
241     return aVal;
242   }
243   if (theParent.internalId() == PartsFolder) {
244     return myPartModels.size();
245   }
246   if (theParent.internalId() == HistoryNode) {
247     return 0;
248   }
249   QModelIndex* aParent = toSourceModelIndex(theParent);
250   const QAbstractItemModel* aModel = aParent->model();
251   if (!isSubModel(aModel)) 
252     return 0;
253
254   /*if (isPartSubModel(aModel)) {
255     if (aModel != myActivePart)
256       return 0;
257   }*/
258   return aModel->rowCount(*aParent);
259 }
260
261 int XGUI_DocumentDataModel::columnCount(const QModelIndex& theParent) const
262 {
263   return 1;
264 }
265
266 QModelIndex XGUI_DocumentDataModel::index(int theRow, int theColumn, const QModelIndex& theParent) const
267 {
268   QModelIndex aIndex;
269   if (!theParent.isValid()) {
270     int aOffs = myModel->rowCount();
271     if (theRow < aOffs) {
272       aIndex = myModel->index(theRow, theColumn, theParent);
273       aIndex = createIndex(theRow, theColumn, (void*)getModelIndex(aIndex));
274     } else {
275       if (theRow == aOffs)  // Create Parts node
276         aIndex = partFolderNode();
277       else // create history node
278         aIndex = createIndex(theRow, theColumn, HistoryNode);
279     }
280   } else {
281     if (theParent.internalId() == PartsFolder) {
282       aIndex = myPartModels.at(theRow)->index(0, theColumn, QModelIndex());
283     } else {
284       QModelIndex* aParent = (QModelIndex*)theParent.internalPointer();
285       aIndex = aParent->model()->index(theRow, theColumn, (*aParent));
286     }
287     aIndex = createIndex(theRow, theColumn, (void*)getModelIndex(aIndex));
288   }
289   return aIndex;
290 }
291
292
293 QModelIndex XGUI_DocumentDataModel::parent(const QModelIndex& theIndex) const
294 {
295   if ((theIndex.internalId() == PartsFolder) || (theIndex.internalId() == HistoryNode))
296     return QModelIndex();
297
298   QModelIndex* aIndex = toSourceModelIndex(theIndex);
299   const QAbstractItemModel* aModel = aIndex->model();
300   if (!isSubModel(aModel)) 
301     return QModelIndex();
302
303   if (isPartSubModel(aModel)) {
304     if (!aModel->parent(*aIndex).isValid()) {
305       return partFolderNode();
306     }
307   }
308
309   QModelIndex aIndex1 = aModel->parent(*aIndex);
310   if (aIndex1.isValid())
311     return createIndex(aIndex1.row(), aIndex1.column(), (void*)getModelIndex(aIndex1));
312   return aIndex1;
313 }
314
315
316 bool XGUI_DocumentDataModel::hasChildren(const QModelIndex& theParent) const
317 {
318   if (!theParent.isValid())
319     return true;
320   return rowCount(theParent) > 0;
321 }
322
323
324 QModelIndex* XGUI_DocumentDataModel::toSourceModelIndex(const QModelIndex& theProxy) const
325 {
326   QModelIndex* aIndexPtr = static_cast<QModelIndex*>(theProxy.internalPointer());
327   return aIndexPtr;
328 }
329
330
331 QModelIndex* XGUI_DocumentDataModel::findModelIndex(const QModelIndex& theIndex) const
332 {
333   QList<QModelIndex*>::const_iterator aIt;
334   for (aIt = myIndexes.constBegin(); aIt != myIndexes.constEnd(); ++aIt) {
335     QModelIndex* aIndex = (*aIt);
336     if ((*aIndex) == theIndex)
337       return aIndex;
338   }
339   return 0;
340 }
341
342 QModelIndex* XGUI_DocumentDataModel::getModelIndex(const QModelIndex& theIndex) const
343 {
344   QModelIndex* aIndexPtr = findModelIndex(theIndex);
345   if (!aIndexPtr) {
346     aIndexPtr = new QModelIndex(theIndex);
347     XGUI_DocumentDataModel* that = (XGUI_DocumentDataModel*) this;
348     that->myIndexes.append(aIndexPtr);
349   }
350   return aIndexPtr;
351 }
352
353 void XGUI_DocumentDataModel::clearModelIndexes()
354 {
355   QList<QModelIndex*>::const_iterator aIt;
356   for (aIt = myIndexes.constBegin(); aIt != myIndexes.constEnd(); ++aIt) 
357     delete (*aIt);
358   myIndexes.clear();
359 }
360
361 ObjectPtr XGUI_DocumentDataModel::object(const QModelIndex& theIndex) const
362 {
363   if (theIndex.internalId() == PartsFolder)
364     return ObjectPtr();
365   if (theIndex.internalId() == HistoryNode) {
366     DocumentPtr aRootDoc = ModelAPI_PluginManager::get()->rootDocument();
367     int aOffset = historyOffset();
368     return aRootDoc->object(ModelAPI_Feature::group(), theIndex.row() - aOffset);
369   }
370   QModelIndex* aIndex = toSourceModelIndex(theIndex);
371   if (!isSubModel(aIndex->model())) 
372     return ObjectPtr();
373
374   const XGUI_FeaturesModel* aModel = dynamic_cast<const XGUI_FeaturesModel*>(aIndex->model());
375   return aModel->feature(*aIndex);
376 }
377
378 bool XGUI_DocumentDataModel::insertRows(int theRow, int theCount, const QModelIndex& theParent)
379 {
380   beginInsertRows(theParent, theRow, theRow + theCount - 1);
381   //endInsertRows();
382
383   // Update history
384   QModelIndex aRoot;
385   int aRow = rowCount(aRoot);
386   beginInsertRows(aRoot, aRow, aRow);
387   endInsertRows();
388
389   return true;
390 }
391
392 bool XGUI_DocumentDataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent)
393 {
394   beginRemoveRows(theParent, theRow, theRow + theCount - 1);
395   endRemoveRows();
396   return true;
397 }
398
399
400 void XGUI_DocumentDataModel::removeSubModel(int theModelId)
401 {
402   XGUI_PartModel* aModel = myPartModels.at(theModelId);
403   QIntList aToRemove;
404   for (int i = 0; i < myIndexes.size(); i++) {
405     if (myIndexes.at(i)->model() == aModel)
406       aToRemove.append(i);
407   }
408   int aId;
409   while(aToRemove.size() > 0) {
410     aId = aToRemove.last();
411     delete myIndexes.at(aId);
412     myIndexes.removeAt(aId);
413     aToRemove.removeLast();
414   }
415   delete aModel;
416   myPartModels.removeAt(theModelId);
417 }
418
419 bool XGUI_DocumentDataModel::isSubModel(const QAbstractItemModel* theModel) const
420 {
421   if (theModel == myModel)
422     return true;
423   return isPartSubModel(theModel);
424 }
425
426 bool XGUI_DocumentDataModel::isPartSubModel(const QAbstractItemModel* theModel) const
427 {
428   return myPartModels.contains((XGUI_PartModel*)theModel);
429 }
430
431 QModelIndex XGUI_DocumentDataModel::partFolderNode() const
432 {
433   int aPos = myModel->rowCount(QModelIndex());
434   return createIndex(aPos, columnCount() - 1, PartsFolder);
435 }
436
437 int XGUI_DocumentDataModel::historyOffset() const
438 {
439   // Nb of rows of top model + Parts folder
440   return myModel->rowCount(QModelIndex()) + 1;
441 }
442
443 bool XGUI_DocumentDataModel::activatedIndex(const QModelIndex& theIndex)
444 {
445   if ((theIndex.internalId() == PartsFolder) || (theIndex.internalId() == HistoryNode))
446     return false;
447
448   QModelIndex* aIndex = toSourceModelIndex(theIndex);
449   if (!aIndex)
450     return false;
451
452   const QAbstractItemModel* aModel = aIndex->model();
453
454   if (isPartSubModel(aModel)) {
455     // if this is root node (Part item index)
456     if (!aIndex->parent().isValid()) {
457       if (myActivePart) myActivePart->setItemsColor(PASSIVE_COLOR);
458
459       if (myActivePart == aModel) {
460         myActivePart = 0;
461         myActivePartIndex = QModelIndex();
462       } else {
463         myActivePart = (XGUI_PartModel*)aModel;
464         myActivePartIndex = theIndex;
465       }
466
467       if (myActivePart) {
468         myActivePart->setItemsColor(ACTIVE_COLOR);
469         myModel->setItemsColor(PASSIVE_COLOR);
470       } else 
471          myModel->setItemsColor(ACTIVE_COLOR);
472      return true;
473     }
474   }
475   return false;
476 }
477
478 ObjectPtr XGUI_DocumentDataModel::activePart() const
479 {
480   if (myActivePart) 
481     return myActivePart->part();
482   return ObjectPtr();
483 }
484
485 void XGUI_DocumentDataModel::deactivatePart() 
486
487   if (myActivePart) 
488     myActivePart->setItemsColor(PASSIVE_COLOR);
489   myActivePart = 0;
490   myActivePartIndex = QModelIndex();
491   myModel->setItemsColor(ACTIVE_COLOR);
492 }
493  
494 Qt::ItemFlags XGUI_DocumentDataModel::flags(const QModelIndex& theIndex) const
495 {
496   Qt::ItemFlags aFlags = QAbstractItemModel::flags(theIndex);
497   if (object(theIndex)) {
498     aFlags |= Qt::ItemIsEditable;
499   }
500   return aFlags;
501 }
502
503 QModelIndex XGUI_DocumentDataModel::partIndex(const ObjectPtr& theObject) const 
504 {
505   int aRow = -1;
506   XGUI_PartModel* aModel = 0;
507   foreach (XGUI_PartModel* aPartModel, myPartModels) {
508     aRow++;
509     if (aPartModel->part() == theObject) {
510       aModel = aPartModel;
511       break;
512     }
513   }
514   if (aModel) {
515     return createIndex(aRow, 0, (void*)getModelIndex(aModel->index(0, 0, QModelIndex())));
516   }
517   return QModelIndex();
518 }
519
520 QModelIndex XGUI_DocumentDataModel::featureIndex(const ObjectPtr theObject) const
521 {
522   // Check that this feature belongs to root document
523   DocumentPtr aRootDoc = ModelAPI_PluginManager::get()->rootDocument();
524   DocumentPtr aDoc = theObject->document();
525   if (aDoc == aRootDoc) {
526     // This feature belongs to histrory or top model
527     if (theObject->isInHistory()) {
528       int aId;
529       for (aId = 0; aId < aRootDoc->size(ModelAPI_Feature::group()); aId++) {
530         if (theObject == aRootDoc->object(ModelAPI_Feature::group(), aId))
531           break;
532       }
533       return index(aId + historyOffset(), 0, QModelIndex());
534     } else {
535       QModelIndex aIndex = myModel->featureIndex(theObject);
536       return aIndex.isValid()? 
537         createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex)) :
538         QModelIndex();
539     }
540   } else {
541     XGUI_PartModel* aPartModel = 0;
542     foreach(XGUI_PartModel* aModel, myPartModels) {
543       if (aModel->hasDocument(aDoc)) {
544         aPartModel = aModel;
545         break;
546       }
547     }
548     if (aPartModel) {
549       QModelIndex aIndex = aPartModel->featureIndex(theObject);
550       return aIndex.isValid()? 
551         createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex)) :
552         QModelIndex();
553     }
554   }
555   return QModelIndex();
556 }