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