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