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