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