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