Salome HOME
Selection has been already filtered, so in the setSelection() the filtering flag...
[modules/shaper.git] / src / PartSet / PartSet_DocumentDataModel.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 #include "PartSet_DocumentDataModel.h"
4 #include "PartSet_PartDataModel.h"
5 #include "PartSet_Module.h"
6 //#include "XGUI_Tools.h"
7
8 #include <ModelAPI_Session.h>
9 #include <ModelAPI_Document.h>
10 #include <ModelAPI_Feature.h>
11 #include <ModelAPI_Data.h>
12 #include <ModelAPI_ResultPart.h>
13 #include <ModelAPI_Events.h>
14 #include <ModelAPI_Object.h>
15
16 #include <Events_Loop.h>
17
18 #include <Config_FeatureMessage.h>
19 #include <ModuleBase_Tools.h>
20 #include <ModuleBase_ActionInfo.h>
21
22 #include <PartSetPlugin_Part.h>
23
24 #include <QIcon>
25 #include <QString>
26 #include <QBrush>
27 #include <QTreeView>
28
29 #include <set>
30
31 #define ACTIVE_COLOR QColor(0,72,140)
32 #define PASSIVE_COLOR Qt::black
33
34 QMap<QString, QString> PartSet_DocumentDataModel::myIcons;
35
36
37 PartSet_DocumentDataModel::PartSet_DocumentDataModel(QObject* theParent)
38     : ModuleBase_IDocumentDataModel(theParent),
39       myActivePartModel(0)
40 {
41   // Create a top part of data tree model
42   myModel = new PartSet_TopDataModel(this);
43   myModel->setItemsColor(ACTIVE_COLOR);
44
45   Events_Loop* aLoop = Events_Loop::loop();
46   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
47   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
48   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
49   aLoop->registerListener(this, Events_Loop::eventByName(Config_FeatureMessage::GUI_EVENT()));
50 }
51
52 PartSet_DocumentDataModel::~PartSet_DocumentDataModel()
53 {
54   clearModelIndexes();
55   clearSubModels();
56 }
57
58 void PartSet_DocumentDataModel::processEvent(const std::shared_ptr<Events_Message>& theMessage)
59 {
60   DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
61
62
63   // Created object event *******************
64   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)) {
65     std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
66         std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
67     std::set<ObjectPtr> aObjects = aUpdMsg->objects();
68
69     std::set<ObjectPtr>::const_iterator aIt;
70     for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) {
71       ObjectPtr aObject = (*aIt);
72       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObject);
73       if (aFeature && (!aFeature->isInHistory()))
74         continue;
75
76       DocumentPtr aDoc = aObject->document();
77       if (aDoc == aRootDoc) {  // If root objects
78         if (aObject->groupName() == ModelAPI_ResultPart::group()) {  // Update only Parts group
79             // Add a new part
80           int aStart = aRootDoc->size(ModelAPI_ResultPart::group());
81           if (aStart > 0) {
82             FeaturePtr aPartFeature = ModelAPI_Feature::feature(aObject);
83             PartSet_PartDataModel* aModel = new PartSet_PartDataModel(this);
84             int anId = aRootDoc->index(aPartFeature);
85             aModel->setPart(aPartFeature);
86             myPartModels.append(aModel);
87             insertRow(aStart, partFolderNode(0));
88           }
89         } else {  // Update top groups (other except parts
90           QModelIndex aIndex = myModel->findParent(aObject);
91           int aStart = myModel->rowCount(aIndex) - 1;
92           if (aStart < 0)
93             aStart = 0;
94           aIndex = createIndex(aIndex.row(), aIndex.column(), (void*) getModelIndex(aIndex));
95           insertRow(aStart, aIndex);
96         }
97       } else {  // if sub-objects of first level nodes
98         PartSet_PartModel* aPartModel = 0;
99         foreach (PartSet_PartModel* aPart, myPartModels) {
100           if (aPart->hasDocument(aDoc)) {
101             aPartModel = aPart;
102             break;
103           }
104         }
105         if (aPartModel) {
106           QModelIndex aIndex = aPartModel->findParent(aObject);
107           int aStart = aPartModel->rowCount(aIndex);  // check this index
108           aIndex = createIndex(aIndex.row(), aIndex.column(), (void*) getModelIndex(aIndex));
109           insertRow(aStart, aIndex);
110         } else
111           reset();
112       }
113     }
114     // Deleted object event ***********************
115   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
116     std::shared_ptr<ModelAPI_ObjectDeletedMessage> aUpdMsg =
117         std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
118     DocumentPtr aDoc = aUpdMsg->document();
119     std::set<std::string> aGroups = aUpdMsg->groups();
120
121     std::set<std::string>::const_iterator aIt;
122     for (aIt = aGroups.begin(); aIt != aGroups.end(); ++aIt) {
123       std::string aGroup = (*aIt);
124       if (aDoc == aRootDoc) {  // If root objects
125         if (aGroup == ModelAPI_ResultPart::group()) {  // Update only Parts group
126           PartSet_PartModel* aDelPartModel = 0;
127           foreach (PartSet_PartModel* aPartModel, myPartModels) {
128             if (aPartModel->position() == -1) {
129               aDelPartModel = aPartModel;
130               break;
131             }
132           }
133           if (aDelPartModel) {
134             deactivatePart();
135             int aStart = myPartModels.size() - 1;
136             removeSubModel(aDelPartModel);
137             removeRow(aStart, partFolderNode(0));
138           }
139         } if (aGroup == ModelAPI_Feature::group()) { // Update History node
140           int aRow = historyOffset() + aRootDoc->size(ModelAPI_Feature::group());
141           removeRow(aRow);
142         } else {  // Update top groups (other except parts
143           QModelIndex aIndex = myModel->findGroup(aGroup);
144           int aStart = myModel->rowCount(aIndex);
145           aIndex = createIndex(aIndex.row(), aIndex.column(), (void*) getModelIndex(aIndex));
146           removeRow(aStart, aIndex);
147         }
148       } else {
149         PartSet_PartModel* aPartModel = 0;
150         foreach (PartSet_PartModel* aPart, myPartModels) {
151           if (aPart->hasDocument(aDoc)) {
152             aPartModel = aPart;
153             break;
154           }
155         }
156         if (aPartModel) {
157           QModelIndex aIndex = aPartModel->findGroup(aGroup);
158           if (aIndex.isValid()) {
159             int aStart = aPartModel->rowCount(aIndex);
160             aIndex = createIndex(aIndex.row(), aIndex.column(), (void*) getModelIndex(aIndex));
161             removeRow(aStart, aIndex);
162           } else {
163             int aRow = aPartModel->rowCount();
164             aIndex = createIndex(aPartModel->position() + historyOffset(), 0, HistoryNode);
165             removeRow(aRow, aIndex);
166           }
167         }
168       }
169     }
170     // Deleted object event ***********************
171   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)) {
172     //std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg = std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
173     //ObjectPtr aFeature = aUpdMsg->feature();
174     //DocumentPtr aDoc = aFeature->document();
175
176     // TODO: Identify the necessary index by the modified feature
177     QModelIndex aIndex;
178     emit dataChanged(aIndex, aIndex);
179
180     // Reset whole tree **************************
181   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(Config_FeatureMessage::GUI_EVENT())) {
182     std::shared_ptr<Config_FeatureMessage> aFeatureMsg =
183        std::dynamic_pointer_cast<Config_FeatureMessage>(theMessage);
184     if (!aFeatureMsg->isInternal()) {
185       ActionInfo aFeatureInfo;
186       aFeatureInfo.initFrom(aFeatureMsg);
187       // Remember features icons
188       myIcons[QString::fromStdString(aFeatureMsg->id())] = aFeatureInfo.iconFile;
189     }
190   } else {
191     rebuildDataTree();
192   }
193 }
194
195 void PartSet_DocumentDataModel::rebuildDataTree()
196 {
197   DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
198
199   beginResetModel();
200   clearModelIndexes();
201
202   // Delete extra models
203   ObjectPtr aObj;
204   FeaturePtr aFeature;
205   QList<PartSet_PartModel*> aDelList;
206   foreach (PartSet_PartModel* aPartModel, myPartModels) {
207     if (aPartModel->position() == -1) 
208       aDelList.append(aPartModel);
209   }
210   foreach (PartSet_PartModel* aPartModel, aDelList) {
211     removeSubModel(aPartModel);
212   }
213   // Add non existing models
214   int aHistNb = aRootDoc->size(ModelAPI_Feature::group());
215   for (int i = 0; i < aHistNb; i++) {
216     aObj = aRootDoc->object(ModelAPI_Feature::group(), i);
217     aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
218     if (aFeature->getKind() == PartSetPlugin_Part::ID()) {
219       if (!findPartModel(aFeature)) {
220         PartSet_PartDataModel* aModel = new PartSet_PartDataModel(this);
221         aModel->setPart(aFeature);
222         myPartModels.append(aModel);
223       }
224     }
225   }
226   endResetModel();
227 }
228
229 QVariant PartSet_DocumentDataModel::data(const QModelIndex& theIndex, int theRole) const
230 {
231   if (!theIndex.isValid())
232     return QVariant();
233
234   DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
235   QModelIndex aParent = theIndex.parent();
236   if ((theIndex.column() == 1) ) {
237     if ((theIndex.internalId() >= PartsFolder) && (theIndex.internalId() <= PartResult)) {
238       if (ModelAPI_Session::get()->activeDocument() == aRootDoc) {
239         if (!aParent.isValid()) {
240           switch (theRole) {
241           case Qt::DecorationRole:
242             if (theIndex.row() == lastHistoryRow())
243               return QIcon(":pictures/arrow.png");
244           }
245         }
246       }
247     } else {
248       QModelIndex* aIndex = toSourceModelIndex(theIndex);
249       const QAbstractItemModel* aModel = aIndex->model();
250       if (isPartSubModel(aModel)) {
251         return aModel->data(*aIndex, theRole);
252       }
253     }
254     return QVariant();
255   }
256
257   switch (theIndex.internalId()) {
258     case PartsFolder:
259       switch (theRole) {
260         case Qt::DisplayRole:
261           return tr("Parts") + QString(" (%1)").arg(rowCount(theIndex));
262         case Qt::DecorationRole:
263           return QIcon(":pictures/constr_folder.png");
264         case Qt::ToolTipRole:
265           return tr("Parts folder");
266         case Qt::ForegroundRole:
267           if (myActivePartIndex.isValid())
268               return QBrush(PASSIVE_COLOR);
269             else
270               return QBrush(ACTIVE_COLOR);
271         default:
272           return QVariant();
273       }
274       break;
275     case HistoryNode:
276       {
277         int aOffset = historyOffset();
278         ObjectPtr aObj = aRootDoc->object(ModelAPI_Feature::group(), theIndex.row() - aOffset);
279         FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
280         if (!aFeature)
281           return QVariant();
282         switch (theRole) {
283           case Qt::DisplayRole:
284             if (aFeature)
285               return aFeature->data()->name().c_str();
286             else
287               return QVariant();
288           case Qt::DecorationRole:
289             return featureIcon(aFeature);
290           case Qt::ToolTipRole:
291             return tr("Feature object");
292           case Qt::ForegroundRole:
293             if (theIndex.row() > lastHistoryRow())
294               return QBrush(Qt::lightGray);
295             else {
296               if (myActivePartIndex.isValid())
297                 return QBrush(PASSIVE_COLOR);
298               else
299                 return QBrush(ACTIVE_COLOR);
300             }
301           default:
302             return QVariant();
303         }
304       }
305       break;
306     case PartResult:
307       {
308         ObjectPtr aObject = aRootDoc->object(ModelAPI_ResultPart::group(), theIndex.row());
309         if (aObject) {
310           switch (theRole) {
311             case Qt::DisplayRole:
312               return std::dynamic_pointer_cast<ModelAPI_Object>(aObject)->data()->name().c_str();
313             case Qt::DecorationRole:
314               return QIcon(":pictures/part_ico.png");
315             case Qt::ForegroundRole:
316               {
317                 if (theIndex == myActivePartIndex)
318                   return QBrush(ACTIVE_COLOR);
319                 else
320                   return QBrush(PASSIVE_COLOR);
321               }
322             default:
323               return QVariant();
324           }
325         }
326       }
327       break;
328   }
329   if (aParent.internalId() == HistoryNode) {
330     int aId = aParent.row() - historyOffset();
331     QModelIndex* aIndex = toSourceModelIndex(theIndex);
332     return findPartModel(aId)->data(*aIndex, theRole);
333   }
334   return toSourceModelIndex(theIndex)->data(theRole);
335 }
336
337 QVariant PartSet_DocumentDataModel::headerData(int theSection, Qt::Orientation theOrient,
338                                             int theRole) const
339 {
340   return QVariant();
341 }
342
343 int PartSet_DocumentDataModel::rowCount(const QModelIndex& theParent) const
344 {
345   SessionPtr aSession = ModelAPI_Session::get();
346   if (!aSession->hasModuleDocument())
347     return 0;
348   DocumentPtr aRootDoc = aSession->moduleDocument();
349   if (!theParent.isValid()) {
350     // Size of external models
351     int aVal = historyOffset();
352     // Plus history size
353     aVal += aRootDoc->size(ModelAPI_Feature::group());
354     return aVal;
355   }
356   if (theParent.internalId() == PartsFolder) {
357     return aRootDoc->size(ModelAPI_ResultPart::group());
358     //int aSize = myPartModels.size();
359     //return myPartModels.size();
360   }
361   if (theParent.internalId() == HistoryNode) {
362     int aId = theParent.row() - historyOffset();
363     PartSet_PartModel* aModel = findPartModel(aId);
364     if (aModel)
365       return aModel->rowCount(QModelIndex());
366     return 0;
367   }
368   if (theParent.internalId() == PartResult)
369     return 0;
370  
371   QModelIndex* aParent = toSourceModelIndex(theParent);
372   const QAbstractItemModel* aModel = aParent->model();
373   if (!isSubModel(aModel))
374     return 0;
375
376   /*if (isPartSubModel(aModel)) {
377    if (aModel != myActivePart)
378    return 0;
379    }*/
380   return aModel->rowCount(*aParent);
381 }
382
383 int PartSet_DocumentDataModel::columnCount(const QModelIndex& theParent) const
384 {
385   return 2;
386 }
387
388 QModelIndex PartSet_DocumentDataModel::index(int theRow, int theColumn,
389                                           const QModelIndex& theParent) const
390 {
391   QModelIndex aIndex;
392   if (!theParent.isValid()) {
393     int aOffs = myModel->rowCount();
394     if (theRow < aOffs) {
395       aIndex = myModel->index(theRow, theColumn, theParent);
396       aIndex = createIndex(theRow, theColumn, (void*) getModelIndex(aIndex));
397     } else {
398       if (theRow == aOffs)  // Create Parts node
399         aIndex = partFolderNode(theColumn);
400       else {
401         // create history node
402         aIndex = createIndex(theRow, theColumn, HistoryNode);
403       }
404     }
405   } else {
406     if (theParent.internalId() == PartsFolder) {
407        aIndex = createIndex(theRow, theColumn, PartResult);
408     } else { 
409       if (theParent.internalId() == HistoryNode) {
410         int aId = theParent.row() - historyOffset();
411         aIndex = findPartModel(aId)->index(theRow, theColumn, QModelIndex());
412       } else {
413         QModelIndex* aParent = (QModelIndex*) theParent.internalPointer();
414         aIndex = aParent->model()->index(theRow, theColumn, (*aParent));
415       }
416       aIndex = createIndex(theRow, theColumn, (void*) getModelIndex(aIndex));
417     }
418   }
419   return aIndex;
420 }
421
422 QModelIndex PartSet_DocumentDataModel::parent(const QModelIndex& theIndex) const
423 {
424   if ((theIndex.internalId() == PartsFolder) || (theIndex.internalId() == HistoryNode))
425     return QModelIndex();
426
427   if (theIndex.internalId() == PartResult)
428     return partFolderNode(0);
429
430   QModelIndex* aIndex = toSourceModelIndex(theIndex);
431   const QAbstractItemModel* aModel = aIndex->model();
432   if (!isSubModel(aModel))
433     return QModelIndex();
434
435   QModelIndex aIndex1 = aModel->parent(*aIndex);
436   const PartSet_PartModel* aPartModel = dynamic_cast<const PartSet_PartModel*>(aModel);
437   if (aPartModel && (!aIndex1.isValid())) {
438     int aId = aPartModel->position();
439     int aRow = aId + historyOffset();
440     return createIndex(aRow, 0, (qint32) HistoryNode);
441   }
442
443   if (aIndex1.isValid())
444     return createIndex(aIndex1.row(), 0, (void*) getModelIndex(aIndex1));
445   return aIndex1;
446 }
447
448 bool PartSet_DocumentDataModel::hasChildren(const QModelIndex& theParent) const
449 {
450   if (!theParent.isValid())
451     return true;
452   return rowCount(theParent) > 0;
453 }
454
455 QModelIndex* PartSet_DocumentDataModel::toSourceModelIndex(const QModelIndex& theProxy) const
456 {
457   QModelIndex* aIndexPtr = static_cast<QModelIndex*>(theProxy.internalPointer());
458   return aIndexPtr;
459 }
460
461 QModelIndex* PartSet_DocumentDataModel::findModelIndex(const QModelIndex& theIndex) const
462 {
463   QList<QModelIndex*>::const_iterator aIt;
464   for (aIt = myIndexes.constBegin(); aIt != myIndexes.constEnd(); ++aIt) {
465     QModelIndex* aIndex = (*aIt);
466     if ((*aIndex) == theIndex)
467       return aIndex;
468   }
469   return 0;
470 }
471
472 QModelIndex* PartSet_DocumentDataModel::getModelIndex(const QModelIndex& theIndex) const
473 {
474   QModelIndex* aIndexPtr = findModelIndex(theIndex);
475   if (!aIndexPtr) {
476     aIndexPtr = new QModelIndex(theIndex);
477     PartSet_DocumentDataModel* that = (PartSet_DocumentDataModel*) this;
478     that->myIndexes.append(aIndexPtr);
479   }
480   return aIndexPtr;
481 }
482
483 void PartSet_DocumentDataModel::clearModelIndexes()
484 {
485   foreach (QModelIndex* aIndex, myIndexes) 
486     delete aIndex;
487   myIndexes.clear();
488 }
489
490 void PartSet_DocumentDataModel::clearSubModels()
491 {
492   foreach (PartSet_PartModel* aPart, myPartModels) 
493     delete aPart;
494   myPartModels.clear();
495   myActivePartModel = 0;
496 }
497
498 ObjectPtr PartSet_DocumentDataModel::object(const QModelIndex& theIndex) const
499 {
500   if (theIndex.internalId() == PartsFolder)
501     return ObjectPtr();
502   DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
503   if (theIndex.internalId() == HistoryNode) {
504     int aOffset = historyOffset();
505     return aRootDoc->object(ModelAPI_Feature::group(), theIndex.row() - aOffset);
506   }
507   if (theIndex.internalId() == PartResult) {
508     return aRootDoc->object(ModelAPI_ResultPart::group(), theIndex.row());
509   }
510   QModelIndex* aIndex = toSourceModelIndex(theIndex);
511   if (!isSubModel(aIndex->model()))
512     return ObjectPtr();
513
514   const PartSet_FeaturesModel* aModel = dynamic_cast<const PartSet_FeaturesModel*>(aIndex->model());
515   return aModel->object(*aIndex);
516 }
517
518 bool PartSet_DocumentDataModel::insertRows(int theRow, int theCount, const QModelIndex& theParent)
519 {
520   beginInsertRows(theParent, theRow, theRow + theCount - 1);
521   //endInsertRows();
522
523   // Update history
524   QModelIndex aRoot;
525   int aRow = rowCount(aRoot);
526   beginInsertRows(aRoot, aRow, aRow);
527   endInsertRows();
528
529   return true;
530 }
531
532 bool PartSet_DocumentDataModel::removeRows(int theRow, int theCount, const QModelIndex& theParent)
533 {
534   beginRemoveRows(theParent, theRow, theRow + theCount - 1);
535   endRemoveRows();
536   return true;
537 }
538
539 void PartSet_DocumentDataModel::removeSubModel(int theModelId)
540 {
541   PartSet_PartModel* aModel = myPartModels.at(theModelId);
542   removeSubModel(aModel);
543 }
544
545 void PartSet_DocumentDataModel::removeSubModel(PartSet_PartModel* theModel)
546 {
547   QIntList aToRemove;
548   for (int i = 0; i < myIndexes.size(); i++) {
549     if (myIndexes.at(i)->model() == theModel)
550       aToRemove.append(i);
551   }
552   int aId;
553   while (aToRemove.size() > 0) {
554     aId = aToRemove.last();
555     delete myIndexes.at(aId);
556     myIndexes.removeAt(aId);
557     aToRemove.removeLast();
558   }
559   if (theModel == myActivePartModel)
560     myActivePartModel = 0;
561   myPartModels.removeAll(theModel);
562   delete theModel;
563 }
564
565
566 bool PartSet_DocumentDataModel::isSubModel(const QAbstractItemModel* theModel) const
567 {
568   if (theModel == myModel)
569     return true;
570   return isPartSubModel(theModel);
571 }
572
573 bool PartSet_DocumentDataModel::isPartSubModel(const QAbstractItemModel* theModel) const
574 {
575   return myPartModels.contains((PartSet_PartModel*) theModel);
576 }
577
578 QModelIndex PartSet_DocumentDataModel::partFolderNode(int theColumn) const
579 {
580   int aPos = myModel->rowCount(QModelIndex());
581   return createIndex(aPos, theColumn, PartsFolder);
582 }
583
584 int PartSet_DocumentDataModel::historyOffset() const
585 {
586   // Nb of rows of top model + Parts folder
587   return myModel->rowCount(QModelIndex()) + 1;
588 }
589
590 bool PartSet_DocumentDataModel::activatePart(const QModelIndex& theIndex)
591 {
592   if ((theIndex.internalId() == PartsFolder) || (theIndex.internalId() == HistoryNode))
593     return false;
594
595   if (theIndex.isValid() && (theIndex.internalId() == PartResult)) {
596     myActivePartIndex = theIndex;
597     myModel->setItemsColor(PASSIVE_COLOR);
598     if (myActivePartModel) 
599       myActivePartModel->setItemsColor(PASSIVE_COLOR);
600     
601     // Find activated part feature by its ID
602     ResultPartPtr aPartRes = activePart();
603     FeaturePtr aFeature = ModelAPI_Feature::feature(aPartRes);
604     if (aFeature.get()) {
605       myActivePartModel = findPartModel(aFeature);
606       myActivePartModel->setItemsColor(ACTIVE_COLOR);
607     }
608   } 
609   return true;
610 }
611
612 ResultPartPtr PartSet_DocumentDataModel::activePart() const
613 {
614   if (myActivePartIndex.isValid()) {
615     DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
616     ObjectPtr aObj = aRootDoc->object(ModelAPI_ResultPart::group(), myActivePartIndex.row());
617     return std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
618   }
619   return ResultPartPtr();
620 }
621
622 QModelIndex PartSet_DocumentDataModel::activePartTree() const
623 {
624   if (myActivePartModel) {
625     return createIndex(myActivePartModel->position() + historyOffset(), 0, HistoryNode);
626   }
627   return QModelIndex();
628 }
629
630 void PartSet_DocumentDataModel::deactivatePart()
631 {
632   if (myActivePartIndex.isValid()) {
633     if (myActivePartModel) 
634       myActivePartModel->setItemsColor(PASSIVE_COLOR);
635     myActivePartModel = 0;
636     myActivePartIndex = QModelIndex();
637     myModel->setItemsColor(ACTIVE_COLOR);
638   }
639 }
640
641 Qt::ItemFlags PartSet_DocumentDataModel::flags(const QModelIndex& theIndex) const
642 {
643   if ((theIndex.internalId() >= PartsFolder) && (theIndex.internalId() <= PartResult)) {
644     Qt::ItemFlags aFlags = Qt::ItemIsSelectable;
645     if (object(theIndex).get()) {
646       aFlags |= Qt::ItemIsEditable;
647     }
648     // Disable items which are below of last history row
649     // Do not disable second column
650     if (theIndex.internalId() == HistoryNode) {
651       if (theIndex.row() <= lastHistoryRow() || (theIndex.column() == 1))
652         aFlags |= Qt::ItemIsEnabled;
653     } else
654       aFlags |= Qt::ItemIsEnabled;
655     return aFlags;
656   } else {
657     QModelIndex* aIndex = toSourceModelIndex(theIndex);
658     const QAbstractItemModel* aModel = aIndex->model();
659     Qt::ItemFlags aFlags = aModel->flags(*aIndex);
660     if (aModel == myModel) {
661       if (myModel->object(*aIndex).get())
662         aFlags |= Qt::ItemIsEditable;
663     }
664     return aFlags;
665   }
666 }
667
668 QModelIndex PartSet_DocumentDataModel::partIndex(const ResultPartPtr& theObject) const
669 {
670   DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
671   int aNb = aRootDoc->size(ModelAPI_ResultPart::group());
672   for (int aId = 0; aId < aNb; aId++) {
673     if (theObject == aRootDoc->object(ModelAPI_ResultPart::group(), aId))
674       return createIndex(aId, 0, PartResult);
675   }
676   return QModelIndex();
677 }
678
679 QModelIndex PartSet_DocumentDataModel::objectIndex(const ObjectPtr theObject) const
680 {
681   // Check that this feature belongs to root document
682   DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
683   DocumentPtr aDoc = theObject->document();
684   if (aDoc == aRootDoc) {
685     // This feature belongs to histrory or top model
686     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
687     if (aFeature) {
688       int aId;
689       int aNb = aRootDoc->size(ModelAPI_Feature::group());
690       for (aId = 0; aId < aNb; aId++) {
691         if (theObject == aRootDoc->object(ModelAPI_Feature::group(), aId))
692           break;
693       }
694       if (aId < aNb)
695         return index(aId + historyOffset(), 0, QModelIndex());
696     } else {
697       QModelIndex aIndex = myModel->objectIndex(theObject);
698       return
699           aIndex.isValid() ?
700               createIndex(aIndex.row(), 0, (void*) getModelIndex(aIndex)) :
701               QModelIndex();
702     }
703   } else {
704     PartSet_PartModel* aPartModel = 0;
705     foreach(PartSet_PartModel* aModel, myPartModels) {
706       if (aModel->hasDocument(aDoc)) {
707         aPartModel = aModel;
708         break;
709       }
710     }
711     if (aPartModel) {
712       QModelIndex aIndex = aPartModel->objectIndex(theObject);
713       return aIndex.isValid() ?
714               createIndex(aIndex.row(), 0, (void*) getModelIndex(aIndex)) :
715               QModelIndex();
716     }
717   }
718   return QModelIndex();
719 }
720
721
722 void PartSet_DocumentDataModel::clear()
723 {
724   clearModelIndexes();
725   clearSubModels();
726   //myActivePart = 0;
727   myActivePartIndex = QModelIndex();
728   myModel->setItemsColor(ACTIVE_COLOR);
729 }
730
731 int PartSet_DocumentDataModel::lastHistoryRow() const
732 {
733   DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
734   FeaturePtr aFeature = aRootDoc->currentFeature(true);
735   if (aFeature.get())
736     return historyOffset() + aRootDoc->index(aFeature);
737   else 
738     return historyOffset() - 1;
739 }
740
741 void PartSet_DocumentDataModel::setLastHistoryItem(const QModelIndex& theIndex)
742 {
743   SessionPtr aMgr = ModelAPI_Session::get();
744   DocumentPtr aRootDoc = aMgr->moduleDocument();
745   std::string aOpName = tr("History change").toStdString();
746   if (theIndex.internalId() == HistoryNode) {
747     ObjectPtr aObject = object(theIndex);
748     aMgr->startOperation(aOpName);
749     aRootDoc->setCurrentFeature(std::dynamic_pointer_cast<ModelAPI_Feature>(aObject), true);
750     aMgr->finishOperation();
751   } else {
752     aMgr->startOperation(aOpName);
753     aRootDoc->setCurrentFeature(FeaturePtr(), true);
754     aMgr->finishOperation();
755   }
756 }
757
758 QModelIndex PartSet_DocumentDataModel::lastHistoryItem() const
759 {
760   return index(lastHistoryRow(), 1);
761 }
762
763
764 QIcon PartSet_DocumentDataModel::featureIcon(const FeaturePtr& theFeature)
765 {
766   QIcon anIcon;
767
768   std::string aKind = theFeature->getKind();
769   QString aId(aKind.c_str());
770   if (!myIcons.contains(aId))
771     return anIcon;
772
773   QString anIconString = myIcons[aId];
774
775   ModelAPI_ExecState aState = theFeature->data()->execState();
776   switch(aState) {
777     case ModelAPI_StateDone:
778     case ModelAPI_StateNothing: {
779       anIcon = QIcon(anIconString);
780     }
781     break;
782     case ModelAPI_StateMustBeUpdated: {
783       anIcon = ModuleBase_Tools::lighter(anIconString);
784     }
785     break;
786     case ModelAPI_StateExecFailed: {
787       anIcon = ModuleBase_Tools::composite(":icons/exec_state_failed.png", anIconString);
788     }
789     break;
790     case ModelAPI_StateInvalidArgument: {
791       anIcon = ModuleBase_Tools::composite(":icons/exec_state_invalid_parameters.png",
792                                            anIconString);
793     }
794     break;
795     default: break;  
796   }
797   return anIcon;  
798 }
799
800 void PartSet_DocumentDataModel::onMouseDoubleClick(const QModelIndex& theIndex)
801 {
802   if (theIndex.column() != 1)
803     return;
804   QTreeView* aTreeView = dynamic_cast<QTreeView*>(sender());
805   if ((theIndex.internalId() >= PartsFolder) && (theIndex.internalId() <= PartResult)) {
806     if (myActivePartModel)
807       // It means that the root document is not active
808       return;
809     QModelIndex aNewIndex;
810     if (theIndex.internalId() == HistoryNode) 
811       aNewIndex = theIndex;
812     int aOldId = lastHistoryRow();
813     setLastHistoryItem(theIndex);
814     int aStartRow = std::min(aOldId, theIndex.row());
815     int aEndRow = std::max(aOldId, theIndex.row());
816     for (int i = aStartRow; i <= aEndRow; i++) {
817       aTreeView->update(createIndex(i, 0, HistoryNode));
818       aTreeView->update(createIndex(i, 1, HistoryNode));
819     }
820     
821   } else {
822     QModelIndex* aIndex = toSourceModelIndex(theIndex);
823     const QAbstractItemModel* aModel = aIndex->model();
824     if (isPartSubModel(aModel)) {
825       PartSet_PartDataModel* aPartModel = (PartSet_PartDataModel*)aModel;
826       QModelIndex aOldItem = aPartModel->lastHistoryItem();
827       aPartModel->setLastHistoryItem(*aIndex);
828       QModelIndex aOldIndex = createIndex(aOldItem.row(), aOldItem.column(), (void*) getModelIndex(aOldItem));
829       int aStartRow = std::min(aOldItem.row(), aIndex->row());
830       int aEndRow = std::max(aOldItem.row(), aIndex->row());
831       for (int i = aStartRow; i <= aEndRow; i++) {
832         QModelIndex aInd1 = aPartModel->index(i, 0);
833         QModelIndex aInd2 = createIndex(i, 0, (void*) getModelIndex(aInd1));
834         aTreeView->update(aInd2);
835         aInd1 = aPartModel->index(i, 1);
836         aInd2 = createIndex(i, 1, (void*) getModelIndex(aInd1));
837         aTreeView->update(aInd2);
838       }
839     }
840   }
841
842
843
844 PartSet_PartModel* PartSet_DocumentDataModel::findPartModel(FeaturePtr thePart) const
845 {
846   foreach (PartSet_PartModel* aModel, myPartModels) {
847     if (aModel->part() == thePart)
848       return aModel;
849   }
850   return 0;
851 }
852
853 PartSet_PartModel* PartSet_DocumentDataModel::findPartModel(int thePosition) const
854 {
855   foreach (PartSet_PartModel* aModel, myPartModels) {
856     if (aModel->position() == thePosition)
857       return aModel;
858   }
859   return 0;
860 }