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