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