Salome HOME
37c78f82a4aec5b3f23d24765e9a8a83bd4b6756
[modules/shaper.git] / src / XGUI / XGUI_DocumentDataModel.cpp
1 #include "XGUI_DocumentDataModel.h"
2 #include "XGUI_PartDataModel.h"
3 #include "XGUI_Workshop.h"
4
5 #include <ModelAPI_PluginManager.h>
6 #include <ModelAPI_Document.h>
7 #include <ModelAPI_Feature.h>
8 #include <ModelAPI_Data.h>
9 #include <Model_Events.h>
10 #include <ModelAPI_Object.h>
11
12 #include <Events_Loop.h>
13
14 #include <Config_FeatureMessage.h>
15
16 #include <QIcon>
17 #include <QString>
18 #include <QBrush>
19
20
21 #define ACTIVE_COLOR QColor(0,72,140)
22 #define PASSIVE_COLOR Qt::black
23
24 XGUI_DocumentDataModel::XGUI_DocumentDataModel(QObject* theParent)
25   : QAbstractItemModel(theParent), myActivePart(0)
26 {
27   // Find Document object
28   PluginManagerPtr aMgr = ModelAPI_PluginManager::get();
29   myDocument = aMgr->currentDocument();
30
31   // Register in event loop
32   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_CREATED));
33   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
34   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_DELETED));
35
36   // Create a top part of data tree model
37   myModel = new XGUI_TopDataModel(myDocument, this);
38   myModel->setItemsColor(ACTIVE_COLOR);
39 }
40
41
42 XGUI_DocumentDataModel::~XGUI_DocumentDataModel()
43 {
44   clearModelIndexes();
45 }
46
47
48 void XGUI_DocumentDataModel::processEvent(const Events_Message* theMessage)
49 {
50   // Created object event *******************
51   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED)) {
52     const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
53     std::set<FeaturePtr> aFeatures = aUpdMsg->features();
54
55     std::set<FeaturePtr>::const_iterator aIt;
56     for (aIt = aFeatures.begin(); aIt != aFeatures.end(); ++aIt) {
57       FeaturePtr aFeature = (*aIt);
58       DocumentPtr aDoc = aFeature->document();
59       if (aDoc == myDocument) {  // If root objects
60         if (aFeature->getGroup().compare(PARTS_GROUP) == 0) { // Update only Parts group
61           // Add a new part
62           int aStart = myPartModels.size();
63           XGUI_PartDataModel* aModel = new XGUI_PartDataModel(myDocument, 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_FEATURE_DELETED)) {
92     const Model_FeatureDeletedMessage* aUpdMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(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 == myDocument) {  // If root objects
100         if (aGroup.compare(PARTS_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_FEATURE_UPDATED)) {
134     //const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
135     //FeaturePtr 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     beginResetModel();
145     int aNbParts = myDocument->size(PARTS_GROUP);
146     if (myPartModels.size() != aNbParts) { // resize internal models
147       while (myPartModels.size() > aNbParts) {
148         delete myPartModels.last();
149         myPartModels.removeLast();
150       }
151       while (myPartModels.size() < aNbParts) {
152         myPartModels.append(new XGUI_PartDataModel(myDocument, this));
153       }
154       for (int i = 0; i < myPartModels.size(); i++)
155         myPartModels.at(i)->setPartId(i);
156     }
157     clearModelIndexes();
158     endResetModel();
159   }
160 }
161
162 QVariant XGUI_DocumentDataModel::data(const QModelIndex& theIndex, int theRole) const
163 {
164   if (!theIndex.isValid())
165     return QVariant();
166   switch (theIndex.internalId()) {
167   case PartsFolder:
168     switch (theRole) {
169     case Qt::DisplayRole:
170       return tr("Parts") + QString(" (%1)").arg(rowCount(theIndex));
171     case Qt::DecorationRole:
172       return QIcon(":pictures/constr_folder.png");
173     case Qt::ToolTipRole:
174       return tr("Parts folder");
175     case Qt::ForegroundRole:
176       if (myActivePart)
177         return QBrush(PASSIVE_COLOR);
178       else
179         return QBrush(ACTIVE_COLOR);
180     default:
181       return QVariant();
182     }
183     break;
184   case HistoryNode:
185     {
186       int aOffset = historyOffset();
187       FeaturePtr aFeature = myDocument->feature(FEATURES_GROUP, theIndex.row() - aOffset);
188       if (!aFeature)
189         return QVariant();
190       switch (theRole) {
191       case Qt::DisplayRole:
192         if (aFeature)
193           return aFeature->data()->getName().c_str();
194         else 
195           return QVariant();
196       case Qt::DecorationRole:
197         return QIcon(XGUI_Workshop::featureIcon(aFeature->getKind()));
198       case Qt::ToolTipRole:
199         return tr("Feature object");
200       case Qt::ForegroundRole:
201         if (myActivePart)
202           return QBrush(PASSIVE_COLOR);
203         else
204           return QBrush(ACTIVE_COLOR);
205       default:
206         return QVariant();
207       }
208     }
209     break;
210   }
211   QModelIndex aParent = theIndex.parent();
212   if (aParent.isValid() && (aParent.internalId() == PartsFolder)) {
213     return myPartModels.at(theIndex.row())->data(QModelIndex(), theRole);
214   }
215   return toSourceModelIndex(theIndex)->data(theRole);
216 }
217
218
219 QVariant XGUI_DocumentDataModel::headerData(int theSection, Qt::Orientation theOrient, int theRole) const
220 {
221   return QVariant();
222 }
223
224 int XGUI_DocumentDataModel::rowCount(const QModelIndex& theParent) const
225 {
226   if (!theParent.isValid()) {
227     // Size of external models
228     int aVal = historyOffset();
229     // Plus history size
230     aVal += myDocument->size(FEATURES_GROUP);
231     return aVal;
232   }
233   if (theParent.internalId() == PartsFolder) {
234     return myPartModels.size();
235   }
236   if (theParent.internalId() == HistoryNode) {
237     return 0;
238   }
239   QModelIndex* aParent = toSourceModelIndex(theParent);
240   const QAbstractItemModel* aModel = aParent->model();
241   if (!isSubModel(aModel)) 
242     return 0;
243
244   /*if (isPartSubModel(aModel)) {
245     if (aModel != myActivePart)
246       return 0;
247   }*/
248   return aModel->rowCount(*aParent);
249 }
250
251 int XGUI_DocumentDataModel::columnCount(const QModelIndex& theParent) const
252 {
253   return 1;
254 }
255
256 QModelIndex XGUI_DocumentDataModel::index(int theRow, int theColumn, const QModelIndex& theParent) const
257 {
258   QModelIndex aIndex;
259   if (!theParent.isValid()) {
260     int aOffs = myModel->rowCount();
261     if (theRow < aOffs) {
262       aIndex = myModel->index(theRow, theColumn, theParent);
263       aIndex = createIndex(theRow, theColumn, (void*)getModelIndex(aIndex));
264     } else {
265       if (theRow == aOffs)  // Create Parts node
266         aIndex = partFolderNode();
267       else // create history node
268         aIndex = createIndex(theRow, theColumn, HistoryNode);
269     }
270   } else {
271     if (theParent.internalId() == PartsFolder) {
272       aIndex = myPartModels.at(theRow)->index(0, theColumn, QModelIndex());
273     } else {
274       QModelIndex* aParent = (QModelIndex*)theParent.internalPointer();
275       aIndex = aParent->model()->index(theRow, theColumn, (*aParent));
276     }
277     aIndex = createIndex(theRow, theColumn, (void*)getModelIndex(aIndex));
278   }
279   return aIndex;
280 }
281
282
283 QModelIndex XGUI_DocumentDataModel::parent(const QModelIndex& theIndex) const
284 {
285   if ((theIndex.internalId() == PartsFolder) || (theIndex.internalId() == HistoryNode))
286     return QModelIndex();
287
288   QModelIndex* aIndex = toSourceModelIndex(theIndex);
289   const QAbstractItemModel* aModel = aIndex->model();
290   if (!isSubModel(aModel)) 
291     return QModelIndex();
292
293   if (isPartSubModel(aModel)) {
294     if (!aModel->parent(*aIndex).isValid()) {
295       return partFolderNode();
296     }
297   }
298
299   QModelIndex aIndex1 = aModel->parent(*aIndex);
300   if (aIndex1.isValid())
301     return createIndex(aIndex1.row(), aIndex1.column(), (void*)getModelIndex(aIndex1));
302   return aIndex1;
303 }
304
305
306 bool XGUI_DocumentDataModel::hasChildren(const QModelIndex& theParent) const
307 {
308   if (!theParent.isValid())
309     return true;
310   return rowCount(theParent) > 0;
311 }
312
313
314 QModelIndex* XGUI_DocumentDataModel::toSourceModelIndex(const QModelIndex& theProxy) const
315 {
316   QModelIndex* aIndexPtr = static_cast<QModelIndex*>(theProxy.internalPointer());
317   return aIndexPtr;
318 }
319
320
321 QModelIndex* XGUI_DocumentDataModel::findModelIndex(const QModelIndex& theIndex) const
322 {
323   QList<QModelIndex*>::const_iterator aIt;
324   for (aIt = myIndexes.constBegin(); aIt != myIndexes.constEnd(); ++aIt) {
325     QModelIndex* aIndex = (*aIt);
326     if ((*aIndex) == theIndex)
327       return aIndex;
328   }
329   return 0;
330 }
331
332 QModelIndex* XGUI_DocumentDataModel::getModelIndex(const QModelIndex& theIndex) const
333 {
334   QModelIndex* aIndexPtr = findModelIndex(theIndex);
335   if (!aIndexPtr) {
336     aIndexPtr = new QModelIndex(theIndex);
337     XGUI_DocumentDataModel* that = (XGUI_DocumentDataModel*) this;
338     that->myIndexes.append(aIndexPtr);
339   }
340   return aIndexPtr;
341 }
342
343 void XGUI_DocumentDataModel::clearModelIndexes()
344 {
345   QList<QModelIndex*>::const_iterator aIt;
346   for (aIt = myIndexes.constBegin(); aIt != myIndexes.constEnd(); ++aIt) 
347     delete (*aIt);
348   myIndexes.clear();
349 }
350
351 FeaturePtr XGUI_DocumentDataModel::feature(const QModelIndex& theIndex) const
352 {
353   if (theIndex.internalId() == PartsFolder)
354     return FeaturePtr();
355   if (theIndex.internalId() == HistoryNode) {
356       int aOffset = historyOffset();
357       return myDocument->feature(FEATURES_GROUP, theIndex.row() - aOffset);
358   }
359   QModelIndex* aIndex = toSourceModelIndex(theIndex);
360   if (!isSubModel(aIndex->model())) 
361     return FeaturePtr();
362
363   const XGUI_FeaturesModel* aModel = dynamic_cast<const XGUI_FeaturesModel*>(aIndex->model());
364   return aModel->feature(*aIndex);
365 }
366
367 bool XGUI_DocumentDataModel::insertRows(int theRow, int theCount, const QModelIndex& theParent)
368 {
369   beginInsertRows(theParent, theRow, theRow + theCount - 1);
370   //endInsertRows();
371
372   // Update history
373   QModelIndex aRoot;
374   int aRow = rowCount(aRoot);
375   beginInsertRows(aRoot, aRow, aRow);
376   endInsertRows();
377
378   return true;
379 }
380
381 bool XGUI_DocumentDataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent)
382 {
383   beginRemoveRows(theParent, theRow, theRow + theCount - 1);
384   endRemoveRows();
385   return true;
386 }
387
388
389 void XGUI_DocumentDataModel::removeSubModel(int theModelId)
390 {
391   XGUI_PartModel* aModel = myPartModels.at(theModelId);
392   QIntList aToRemove;
393   for (int i = 0; i < myIndexes.size(); i++) {
394     if (myIndexes.at(i)->model() == aModel)
395       aToRemove.append(i);
396   }
397   int aId;
398   while(aToRemove.size() > 0) {
399     aId = aToRemove.last();
400     delete myIndexes.at(aId);
401     myIndexes.removeAt(aId);
402     aToRemove.removeLast();
403   }
404   delete aModel;
405   myPartModels.removeAt(theModelId);
406 }
407
408 bool XGUI_DocumentDataModel::isSubModel(const QAbstractItemModel* theModel) const
409 {
410   if (theModel == myModel)
411     return true;
412   return isPartSubModel(theModel);
413 }
414
415 bool XGUI_DocumentDataModel::isPartSubModel(const QAbstractItemModel* theModel) const
416 {
417   return myPartModels.contains((XGUI_PartModel*)theModel);
418 }
419
420 QModelIndex XGUI_DocumentDataModel::partFolderNode() const
421 {
422   int aPos = myModel->rowCount(QModelIndex());
423   return createIndex(aPos, columnCount() - 1, PartsFolder);
424 }
425
426 int XGUI_DocumentDataModel::historyOffset() const
427 {
428   // Nb of rows of top model + Parts folder
429   return myModel->rowCount(QModelIndex()) + 1;
430 }
431
432 bool XGUI_DocumentDataModel::activatedIndex(const QModelIndex& theIndex)
433 {
434   if ((theIndex.internalId() == PartsFolder) || (theIndex.internalId() == HistoryNode))
435     return false;
436
437   QModelIndex* aIndex = toSourceModelIndex(theIndex);
438   if (!aIndex)
439     return false;
440
441   const QAbstractItemModel* aModel = aIndex->model();
442
443   if (isPartSubModel(aModel)) {
444     // if this is root node (Part item index)
445     if (!aIndex->parent().isValid()) {
446       if (myActivePart) myActivePart->setItemsColor(PASSIVE_COLOR);
447
448       if (myActivePart == aModel) {
449         myActivePart = 0;
450         myActivePartIndex = QModelIndex();
451       } else {
452         myActivePart = (XGUI_PartModel*)aModel;
453         myActivePartIndex = theIndex;
454       }
455
456       if (myActivePart) {
457         myActivePart->setItemsColor(ACTIVE_COLOR);
458         myModel->setItemsColor(PASSIVE_COLOR);
459       } else 
460          myModel->setItemsColor(ACTIVE_COLOR);
461      return true;
462     }
463   }
464   return false;
465 }
466
467 FeaturePtr XGUI_DocumentDataModel::activePart() const
468 {
469   if (myActivePart) 
470     return myActivePart->part();
471   return FeaturePtr();
472 }
473
474 void XGUI_DocumentDataModel::deactivatePart() 
475
476   if (myActivePart) 
477     myActivePart->setItemsColor(PASSIVE_COLOR);
478   myActivePart = 0;
479   myActivePartIndex = QModelIndex();
480   myModel->setItemsColor(ACTIVE_COLOR);
481 }
482  
483 Qt::ItemFlags XGUI_DocumentDataModel::flags(const QModelIndex& theIndex) const
484 {
485   Qt::ItemFlags aFlags = QAbstractItemModel::flags(theIndex);
486   if (feature(theIndex)) {
487     aFlags |= Qt::ItemIsEditable;
488   }
489   return aFlags;
490 }
491
492 QModelIndex XGUI_DocumentDataModel::partIndex(const FeaturePtr& theFeature) const 
493 {
494   FeaturePtr aFeature = theFeature;
495   if (!aFeature->data()) {
496     ObjectPtr aObject = boost::dynamic_pointer_cast<ModelAPI_Object>(aFeature);
497     aFeature = aObject->featureRef();
498   }
499   int aRow = -1;
500   XGUI_PartModel* aModel = 0;
501   foreach (XGUI_PartModel* aPartModel, myPartModels) {
502     aRow++;
503     if (aPartModel->part() == aFeature) {
504       aModel = aPartModel;
505       break;
506     }
507   }
508   if (aModel) {
509     return createIndex(aRow, 0, (void*)getModelIndex(aModel->index(0, 0, QModelIndex())));
510   }
511   return QModelIndex();
512 }