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