Salome HOME
1e62ae84e367d05021044188d12ad1cb2d6a232c
[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 aObj = aRootDoc->object(ModelAPI_Feature::group(), theIndex.row() - aOffset);
197       FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
198       if (!aFeature)
199         return QVariant();
200       switch (theRole) {
201       case Qt::DisplayRole:
202         if (aFeature)
203           return aFeature->data()->name().c_str();
204         else 
205           return QVariant();
206       case Qt::DecorationRole:
207         return QIcon(XGUI_Workshop::featureIcon(aFeature->getKind()));
208       case Qt::ToolTipRole:
209         return tr("Feature object");
210       case Qt::ForegroundRole:
211         if (myActivePart)
212           return QBrush(PASSIVE_COLOR);
213         else
214           return QBrush(ACTIVE_COLOR);
215       default:
216         return QVariant();
217       }
218     }
219     break;
220   }
221   QModelIndex aParent = theIndex.parent();
222   if (aParent.isValid() && (aParent.internalId() == PartsFolder)) {
223     return myPartModels.at(theIndex.row())->data(QModelIndex(), theRole);
224   }
225   return toSourceModelIndex(theIndex)->data(theRole);
226 }
227
228
229 QVariant XGUI_DocumentDataModel::headerData(int theSection, Qt::Orientation theOrient, int theRole) const
230 {
231   return QVariant();
232 }
233
234 int XGUI_DocumentDataModel::rowCount(const QModelIndex& theParent) const
235 {
236   if (!theParent.isValid()) {
237     DocumentPtr aRootDoc = ModelAPI_PluginManager::get()->rootDocument();
238     // Size of external models
239     int aVal = historyOffset();
240     // Plus history size
241     aVal += aRootDoc->size(ModelAPI_Feature::group());
242     return aVal;
243   }
244   if (theParent.internalId() == PartsFolder) {
245     return myPartModels.size();
246   }
247   if (theParent.internalId() == HistoryNode) {
248     return 0;
249   }
250   QModelIndex* aParent = toSourceModelIndex(theParent);
251   const QAbstractItemModel* aModel = aParent->model();
252   if (!isSubModel(aModel)) 
253     return 0;
254
255   /*if (isPartSubModel(aModel)) {
256     if (aModel != myActivePart)
257       return 0;
258   }*/
259   return aModel->rowCount(*aParent);
260 }
261
262 int XGUI_DocumentDataModel::columnCount(const QModelIndex& theParent) const
263 {
264   return 1;
265 }
266
267 QModelIndex XGUI_DocumentDataModel::index(int theRow, int theColumn, const QModelIndex& theParent) const
268 {
269   QModelIndex aIndex;
270   if (!theParent.isValid()) {
271     int aOffs = myModel->rowCount();
272     if (theRow < aOffs) {
273       aIndex = myModel->index(theRow, theColumn, theParent);
274       aIndex = createIndex(theRow, theColumn, (void*)getModelIndex(aIndex));
275     } else {
276       if (theRow == aOffs)  // Create Parts node
277         aIndex = partFolderNode();
278       else // create history node
279         aIndex = createIndex(theRow, theColumn, HistoryNode);
280     }
281   } else {
282     if (theParent.internalId() == PartsFolder) {
283       aIndex = myPartModels.at(theRow)->index(0, theColumn, QModelIndex());
284     } else {
285       QModelIndex* aParent = (QModelIndex*)theParent.internalPointer();
286       aIndex = aParent->model()->index(theRow, theColumn, (*aParent));
287     }
288     aIndex = createIndex(theRow, theColumn, (void*)getModelIndex(aIndex));
289   }
290   return aIndex;
291 }
292
293
294 QModelIndex XGUI_DocumentDataModel::parent(const QModelIndex& theIndex) const
295 {
296   if ((theIndex.internalId() == PartsFolder) || (theIndex.internalId() == HistoryNode))
297     return QModelIndex();
298
299   QModelIndex* aIndex = toSourceModelIndex(theIndex);
300   const QAbstractItemModel* aModel = aIndex->model();
301   if (!isSubModel(aModel)) 
302     return QModelIndex();
303
304   if (isPartSubModel(aModel)) {
305     if (!aModel->parent(*aIndex).isValid()) {
306       return partFolderNode();
307     }
308   }
309
310   QModelIndex aIndex1 = aModel->parent(*aIndex);
311   if (aIndex1.isValid())
312     return createIndex(aIndex1.row(), aIndex1.column(), (void*)getModelIndex(aIndex1));
313   return aIndex1;
314 }
315
316
317 bool XGUI_DocumentDataModel::hasChildren(const QModelIndex& theParent) const
318 {
319   if (!theParent.isValid())
320     return true;
321   return rowCount(theParent) > 0;
322 }
323
324
325 QModelIndex* XGUI_DocumentDataModel::toSourceModelIndex(const QModelIndex& theProxy) const
326 {
327   QModelIndex* aIndexPtr = static_cast<QModelIndex*>(theProxy.internalPointer());
328   return aIndexPtr;
329 }
330
331
332 QModelIndex* XGUI_DocumentDataModel::findModelIndex(const QModelIndex& theIndex) const
333 {
334   QList<QModelIndex*>::const_iterator aIt;
335   for (aIt = myIndexes.constBegin(); aIt != myIndexes.constEnd(); ++aIt) {
336     QModelIndex* aIndex = (*aIt);
337     if ((*aIndex) == theIndex)
338       return aIndex;
339   }
340   return 0;
341 }
342
343 QModelIndex* XGUI_DocumentDataModel::getModelIndex(const QModelIndex& theIndex) const
344 {
345   QModelIndex* aIndexPtr = findModelIndex(theIndex);
346   if (!aIndexPtr) {
347     aIndexPtr = new QModelIndex(theIndex);
348     XGUI_DocumentDataModel* that = (XGUI_DocumentDataModel*) this;
349     that->myIndexes.append(aIndexPtr);
350   }
351   return aIndexPtr;
352 }
353
354 void XGUI_DocumentDataModel::clearModelIndexes()
355 {
356   QList<QModelIndex*>::const_iterator aIt;
357   for (aIt = myIndexes.constBegin(); aIt != myIndexes.constEnd(); ++aIt) 
358     delete (*aIt);
359   myIndexes.clear();
360 }
361
362 ObjectPtr XGUI_DocumentDataModel::object(const QModelIndex& theIndex) const
363 {
364   if (theIndex.internalId() == PartsFolder)
365     return ObjectPtr();
366   if (theIndex.internalId() == HistoryNode) {
367     DocumentPtr aRootDoc = ModelAPI_PluginManager::get()->rootDocument();
368     int aOffset = historyOffset();
369     return aRootDoc->object(ModelAPI_Feature::group(), theIndex.row() - aOffset);
370   }
371   QModelIndex* aIndex = toSourceModelIndex(theIndex);
372   if (!isSubModel(aIndex->model())) 
373     return ObjectPtr();
374
375   const XGUI_FeaturesModel* aModel = dynamic_cast<const XGUI_FeaturesModel*>(aIndex->model());
376   return aModel->object(*aIndex);
377 }
378
379 bool XGUI_DocumentDataModel::insertRows(int theRow, int theCount, const QModelIndex& theParent)
380 {
381   beginInsertRows(theParent, theRow, theRow + theCount - 1);
382   //endInsertRows();
383
384   // Update history
385   QModelIndex aRoot;
386   int aRow = rowCount(aRoot);
387   beginInsertRows(aRoot, aRow, aRow);
388   endInsertRows();
389
390   return true;
391 }
392
393 bool XGUI_DocumentDataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent)
394 {
395   beginRemoveRows(theParent, theRow, theRow + theCount - 1);
396   endRemoveRows();
397   return true;
398 }
399
400
401 void XGUI_DocumentDataModel::removeSubModel(int theModelId)
402 {
403   XGUI_PartModel* aModel = myPartModels.at(theModelId);
404   QIntList aToRemove;
405   for (int i = 0; i < myIndexes.size(); i++) {
406     if (myIndexes.at(i)->model() == aModel)
407       aToRemove.append(i);
408   }
409   int aId;
410   while(aToRemove.size() > 0) {
411     aId = aToRemove.last();
412     delete myIndexes.at(aId);
413     myIndexes.removeAt(aId);
414     aToRemove.removeLast();
415   }
416   delete aModel;
417   myPartModels.removeAt(theModelId);
418 }
419
420 bool XGUI_DocumentDataModel::isSubModel(const QAbstractItemModel* theModel) const
421 {
422   if (theModel == myModel)
423     return true;
424   return isPartSubModel(theModel);
425 }
426
427 bool XGUI_DocumentDataModel::isPartSubModel(const QAbstractItemModel* theModel) const
428 {
429   return myPartModels.contains((XGUI_PartModel*)theModel);
430 }
431
432 QModelIndex XGUI_DocumentDataModel::partFolderNode() const
433 {
434   int aPos = myModel->rowCount(QModelIndex());
435   return createIndex(aPos, columnCount() - 1, PartsFolder);
436 }
437
438 int XGUI_DocumentDataModel::historyOffset() const
439 {
440   // Nb of rows of top model + Parts folder
441   return myModel->rowCount(QModelIndex()) + 1;
442 }
443
444 bool XGUI_DocumentDataModel::activatedIndex(const QModelIndex& theIndex)
445 {
446   if ((theIndex.internalId() == PartsFolder) || (theIndex.internalId() == HistoryNode))
447     return false;
448
449   QModelIndex* aIndex = toSourceModelIndex(theIndex);
450   if (!aIndex)
451     return false;
452
453   const QAbstractItemModel* aModel = aIndex->model();
454
455   if (isPartSubModel(aModel)) {
456     // if this is root node (Part item index)
457     if (!aIndex->parent().isValid()) {
458       if (myActivePart) myActivePart->setItemsColor(PASSIVE_COLOR);
459
460       if (myActivePart == aModel) {
461         myActivePart = 0;
462         myActivePartIndex = QModelIndex();
463       } else {
464         myActivePart = (XGUI_PartModel*)aModel;
465         myActivePartIndex = theIndex;
466       }
467
468       if (myActivePart) {
469         myActivePart->setItemsColor(ACTIVE_COLOR);
470         myModel->setItemsColor(PASSIVE_COLOR);
471       } else 
472          myModel->setItemsColor(ACTIVE_COLOR);
473      return true;
474     }
475   }
476   return false;
477 }
478
479 ResultPartPtr XGUI_DocumentDataModel::activePart() const
480 {
481   if (myActivePart) 
482     return myActivePart->part();
483   return ResultPartPtr();
484 }
485
486 void XGUI_DocumentDataModel::deactivatePart() 
487
488   if (myActivePart) 
489     myActivePart->setItemsColor(PASSIVE_COLOR);
490   myActivePart = 0;
491   myActivePartIndex = QModelIndex();
492   myModel->setItemsColor(ACTIVE_COLOR);
493 }
494  
495 Qt::ItemFlags XGUI_DocumentDataModel::flags(const QModelIndex& theIndex) const
496 {
497   Qt::ItemFlags aFlags = QAbstractItemModel::flags(theIndex);
498   if (object(theIndex)) {
499     aFlags |= Qt::ItemIsEditable;
500   }
501   return aFlags;
502 }
503
504 QModelIndex XGUI_DocumentDataModel::partIndex(const ResultPartPtr& theObject) const 
505 {
506   int aRow = -1;
507   XGUI_PartModel* aModel = 0;
508   foreach (XGUI_PartModel* aPartModel, myPartModels) {
509     aRow++;
510     if (aPartModel->part() == theObject) {
511       aModel = aPartModel;
512       break;
513     }
514   }
515   if (aModel) {
516     return createIndex(aRow, 0, (void*)getModelIndex(aModel->index(0, 0, QModelIndex())));
517   }
518   return QModelIndex();
519 }
520
521 QModelIndex XGUI_DocumentDataModel::objectIndex(const ObjectPtr theObject) const
522 {
523   // Check that this feature belongs to root document
524   DocumentPtr aRootDoc = ModelAPI_PluginManager::get()->rootDocument();
525   DocumentPtr aDoc = theObject->document();
526   if (aDoc == aRootDoc) {
527     // This feature belongs to histrory or top model
528     if (theObject->isInHistory()) {
529       int aId;
530       for (aId = 0; aId < aRootDoc->size(ModelAPI_Feature::group()); aId++) {
531         if (theObject == aRootDoc->object(ModelAPI_Feature::group(), aId))
532           break;
533       }
534       return index(aId + historyOffset(), 0, QModelIndex());
535     } else {
536       QModelIndex aIndex = myModel->objectIndex(theObject);
537       return aIndex.isValid()? 
538         createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex)) :
539         QModelIndex();
540     }
541   } else {
542     XGUI_PartModel* aPartModel = 0;
543     foreach(XGUI_PartModel* aModel, myPartModels) {
544       if (aModel->hasDocument(aDoc)) {
545         aPartModel = aModel;
546         break;
547       }
548     }
549     if (aPartModel) {
550       QModelIndex aIndex = aPartModel->objectIndex(theObject);
551       return aIndex.isValid()? 
552         createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex)) :
553         QModelIndex();
554     }
555   }
556   return QModelIndex();
557 }