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