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