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