Salome HOME
Provide Feature folder processing
[modules/shaper.git] / src / PartSet / PartSet_TreeNodes.cpp
1 // Copyright (C) 2014-2017  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include "PartSet_TreeNodes.h"
22
23 #include <ModuleBase_IconFactory.h>
24 #include <ModuleBase_IWorkshop.h>
25
26 #include <PartSetPlugin_Part.h>
27
28 #include <ModelAPI_Session.h>
29 #include <ModelAPI_ResultParameter.h>
30 #include <ModelAPI_ResultField.h>
31 #include <ModelAPI_ResultGroup.h>
32 #include <ModelAPI_ResultConstruction.h>
33 #include <ModelAPI_ResultPart.h>
34 #include <ModelAPI_ResultBody.h>
35 #include <ModelAPI_Tools.h>
36 #include <ModelAPI_ResultCompSolid.h>
37 #include <ModelAPI_CompositeFeature.h>
38 #include <ModelAPI_AttributeDouble.h>
39 #include <ModelAPI_Folder.h>
40 #include <ModelAPI_AttributeReference.h>
41
42 #include <QBrush>
43
44
45 #define ACTIVE_COLOR QColor(Qt::black)
46 #define SELECTABLE_COLOR QColor(100, 100, 100)
47 #define DISABLED_COLOR QColor(200, 200, 200)
48
49 Qt::ItemFlags aNullFlag;
50 Qt::ItemFlags aDefaultFlag = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
51 Qt::ItemFlags aEditingFlag = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
52
53
54 ResultPartPtr getPartResult(const ObjectPtr& theObj)
55 {
56   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
57   if (aFeature) {
58     ResultPtr aRes = aFeature->firstResult();
59     if (aRes.get() && (aRes->groupName() == ModelAPI_ResultPart::group())) {
60       ResultPartPtr aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aRes);
61       // Use only original parts, not a placement results
62       if (aPartRes == aPartRes->original())
63         return aPartRes;
64     }
65   }
66   return ResultPartPtr();
67 }
68
69 bool isCurrentFeature(const ObjectPtr& theObj)
70 {
71   SessionPtr aSession = ModelAPI_Session::get();
72   DocumentPtr aCurDoc = aSession->activeDocument();
73   FeaturePtr aFeature = aCurDoc->currentFeature(true);
74   return aFeature == theObj;
75 }
76
77 //////////////////////////////////////////////////////////////////////////////////
78 QVariant PartSet_TreeNode::data(int theColumn, int theRole) const
79 {
80   if ((theColumn == 1) && (theRole == Qt::ForegroundRole)) {
81     Qt::ItemFlags aFlags = flags(theColumn);
82     if (aFlags == Qt::ItemFlags())
83       return QBrush(DISABLED_COLOR);
84     if (!aFlags.testFlag(Qt::ItemIsEditable))
85       return QBrush(SELECTABLE_COLOR);
86     return ACTIVE_COLOR;
87   }
88   return ModuleBase_ITreeNode::data(theColumn, theRole);
89 }
90
91
92 //////////////////////////////////////////////////////////////////////////////////
93 QVariant PartSet_ObjectNode::data(int theColumn, int theRole) const
94 {
95   switch (theRole) {
96   case Qt::DisplayRole:
97     if (theColumn == 1) {
98       if (myObject->groupName() == ModelAPI_ResultParameter::group()) {
99         ResultParameterPtr aParam = std::dynamic_pointer_cast<ModelAPI_ResultParameter>(myObject);
100         AttributeDoublePtr aValueAttribute =
101           aParam->data()->real(ModelAPI_ResultParameter::VALUE());
102         QString aVal = QString::number(aValueAttribute->value());
103         QString aTitle = QString(myObject->data()->name().c_str());
104         return aTitle + " = " + aVal;
105       }
106       return myObject->data()->name().c_str();
107     }
108     break;
109   case Qt::DecorationRole:
110     switch (theColumn) {
111     case 0:
112       switch (getVisibilityState()) {
113       case NoneState:
114         return QIcon();
115       case Visible:
116         return QIcon(":pictures/eyeopen.png");
117       case SemiVisible:
118         return QIcon(":pictures/eyemiclosed.png");
119       case Hidden:
120         return QIcon(":pictures/eyeclosed.png");
121       }
122     case 1:
123       if (myObject->groupName() == ModelAPI_Folder::group())
124         return QIcon(":pictures/features_folder.png");
125       else
126         return ModuleBase_IconFactory::get()->getIcon(myObject);
127     case 2:
128       if (isCurrentFeature(myObject))
129         return QIcon(":pictures/arrow.png");
130     }
131   }
132   return PartSet_TreeNode::data(theColumn, theRole);
133 }
134
135 Qt::ItemFlags PartSet_ObjectNode::flags(int theColumn) const
136 {
137   if (!myObject->isDisabled()) {
138     DocumentPtr aDoc = myObject->document();
139     SessionPtr aSession = ModelAPI_Session::get();
140     if (aSession->activeDocument() == aDoc)
141       return aEditingFlag;
142   }
143   return aDefaultFlag;
144 }
145
146 PartSet_ObjectNode::VisibilityState PartSet_ObjectNode::getVisibilityState() const
147 {
148   Qt::ItemFlags aFlags = flags(1);
149   if (aFlags == Qt::ItemFlags())
150     return NoneState;
151
152   if (myObject->groupName() == ModelAPI_ResultParameter::group())
153     return NoneState;
154   ResultPtr aResObj = std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
155   if (aResObj.get()) {
156     ModuleBase_IWorkshop* aWork = workshop();
157     ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aResObj);
158     if (aCompRes.get()) {
159       VisibilityState aState = aCompRes->numberOfSubs(true) == 0 ?
160         (aWork->isVisible(aCompRes) ? Visible : Hidden) : NoneState;
161       for (int i = 0; i < aCompRes->numberOfSubs(true); i++) {
162         ResultPtr aSubRes = aCompRes->subResult(i, true);
163         VisibilityState aS = aWork->isVisible(aSubRes) ? Visible : Hidden;
164         if (aState == NoneState)
165           aState = aS;
166         else if (aState != aS) {
167           aState = SemiVisible;
168           break;
169         }
170       }
171       return aState;
172     } else {
173       if (aWork->isVisible(aResObj))
174         return Visible;
175       else
176         return Hidden;
177     }
178   }
179   return NoneState;
180 }
181
182
183 //////////////////////////////////////////////////////////////////////////////////
184 PartSet_FolderNode::PartSet_FolderNode(ModuleBase_ITreeNode* theParent,
185   FolderType theType)
186   : PartSet_TreeNode(theParent), myType(theType)
187 {
188 }
189
190 QString PartSet_FolderNode::name() const
191 {
192   switch (myType) {
193   case ParametersFolder:
194     return QObject::tr("Parameters");
195   case ConstructionFolder:
196     return QObject::tr("Constructions");
197   case PartsFolder:
198     return QObject::tr("Parts");
199   case ResultsFolder:
200     return QObject::tr("Results");
201   case FieldsFolder:
202     return QObject::tr("Fields");
203   case GroupsFolder:
204     return QObject::tr("Groups");
205   }
206   return "NoName";
207 }
208
209
210 QVariant PartSet_FolderNode::data(int theColumn, int theRole) const
211 {
212   static QIcon aParamsIco(":pictures/params_folder.png");
213   static QIcon aConstrIco(":pictures/constr_folder.png");
214
215   if (theColumn == 1) {
216     switch (theRole) {
217     case Qt::DisplayRole:
218       return name() + QString(" (%1)").arg(childrenCount());
219     case Qt::DecorationRole:
220       switch (myType) {
221       case ParametersFolder:
222         return aParamsIco;
223       case ConstructionFolder:
224         return aConstrIco;
225       case PartsFolder:
226         return aConstrIco;
227       case ResultsFolder:
228         return aConstrIco;
229       case FieldsFolder:
230         return aConstrIco;
231       case GroupsFolder:
232         return aConstrIco;
233       }
234     }
235   }
236   return PartSet_TreeNode::data(theColumn, theRole);
237 }
238
239 Qt::ItemFlags PartSet_FolderNode::flags(int theColumn) const
240 {
241   SessionPtr aSession = ModelAPI_Session::get();
242   DocumentPtr aActiveDoc = aSession->activeDocument();
243   if (theColumn == 1) {
244     if (document() == aActiveDoc)
245       return aEditingFlag;
246   }
247   return aDefaultFlag;
248 }
249
250 void PartSet_FolderNode::update()
251 {
252   DocumentPtr aDoc = document();
253   if (!aDoc.get())
254     return;
255
256   // Remove extra sub-nodes
257   QTreeNodesList aDelList;
258   int aIndex;
259   int aId = -1;
260   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
261     aId++;
262     aIndex = aDoc->index(aNode->object(), true);
263     if ((aIndex == -1) || (aId != aIndex))
264       aDelList.append(aNode);
265   }
266   foreach(ModuleBase_ITreeNode* aNode, aDelList) {
267     myChildren.removeAll(aNode);
268     delete aNode;
269   }
270
271   // Add new nodes
272   std::string aGroup = groupName();
273   int aSize = aDoc->size(aGroup, true);
274   for (int i = 0; i < aSize; i++) {
275     ObjectPtr aObj = aDoc->object(aGroup, i, true);
276     if (i < myChildren.size()) {
277       if (myChildren.at(i)->object() != aObj) {
278         PartSet_ObjectNode* aNode = new PartSet_ObjectNode(aObj, this);
279         myChildren.insert(i, aNode);
280       }
281     } else {
282       PartSet_ObjectNode* aNode = new PartSet_ObjectNode(aObj, this);
283       myChildren.append(aNode);
284     }
285   }
286 }
287
288 std::string PartSet_FolderNode::groupName() const
289 {
290   switch (myType) {
291   case ParametersFolder:
292     return ModelAPI_ResultParameter::group();
293   case ConstructionFolder:
294     return ModelAPI_ResultConstruction::group();
295   case PartsFolder:
296     return ModelAPI_ResultPart::group();
297   case ResultsFolder:
298     return ModelAPI_ResultBody::group();
299   case FieldsFolder:
300     return ModelAPI_ResultField::group();
301   case GroupsFolder:
302     return ModelAPI_ResultGroup::group();
303   }
304   return "";
305 }
306
307 QTreeNodesList PartSet_FolderNode::objectCreated(const QObjectPtrList& theObjects)
308 {
309   QTreeNodesList aResult;
310   std::string aName = groupName();
311   DocumentPtr aDoc = document();
312   int aIdx = -1;
313   foreach(ObjectPtr aObj, theObjects) {
314     if ((aObj->document() == aDoc) && (aObj->groupName() == aName)) {
315       aIdx = aDoc->index(aObj, true);
316       if (aIdx != -1) {
317         bool aHasObject = (aIdx < myChildren.size()) && (myChildren.at(aIdx)->object() == aObj);
318         if (!aHasObject) {
319           PartSet_ObjectNode* aNode = new PartSet_ObjectNode(aObj, this);
320           aResult.append(aNode);
321           if (aIdx < myChildren.size())
322             myChildren.insert(aIdx, aNode);
323           else
324             myChildren.append(aNode);
325         }
326       }
327     }
328   }
329   return aResult;
330 }
331
332 QTreeNodesList PartSet_FolderNode::objectsDeleted(const DocumentPtr& theDoc,
333   const QString& theGroup)
334 {
335   DocumentPtr aDoc = document();
336   QTreeNodesList aResult;
337   if ((theGroup.toStdString() == groupName()) && (theDoc == aDoc)) {
338     QTreeNodesList aDelList;
339     int aIndex;
340     int aId = -1;
341     foreach(ModuleBase_ITreeNode* aNode, myChildren) {
342       aId++;
343       aIndex = aDoc->index(aNode->object(), true);
344       if ((aIndex == -1) || (aId != aIndex))
345         aDelList.append(aNode);
346     }
347     if (aDelList.size() > 0) {
348       foreach(ModuleBase_ITreeNode* aNode, aDelList) {
349         myChildren.removeAll(aNode);
350         delete aNode;
351       }
352       aResult.append(this);
353     }
354   }
355   return aResult;
356 }
357
358 //////////////////////////////////////////////////////////////////////////////////
359 QTreeNodesList PartSet_FeatureFolderNode::objectCreated(const QObjectPtrList& theObjects)
360 {
361   QTreeNodesList aResult;
362   // Process all folders
363   ModuleBase_ITreeNode* aFoder = 0;
364   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
365     aFoder = dynamic_cast<PartSet_FolderNode*>(aNode);
366     if (!aFoder)
367       aFoder = dynamic_cast<PartSet_FeatureFolderNode*>(aNode);
368
369     if (aFoder) { // aFolder node
370       QTreeNodesList aList = aNode->objectCreated(theObjects);
371       if (aList.size() > 0)
372         aResult.append(aList);
373     }
374   }
375   // Process the root sub-objects
376   DocumentPtr aDoc = document();
377   int aIdx = -1;
378   int aNb = numberOfFolders();
379   foreach(ObjectPtr aObj, theObjects) {
380     if (aDoc == aObj->document()) {
381       if ((aObj->groupName() == ModelAPI_Feature::group()) ||
382         (aObj->groupName() == ModelAPI_Folder::group())){
383         ModuleBase_ITreeNode* aNode = createNode(aObj);
384         aIdx = aDoc->index(aObj, true) + aNb;
385         bool aHasObject = (aIdx < myChildren.size()) && (myChildren.at(aIdx)->object() == aObj);
386         if (!aHasObject) {
387           if (aIdx < myChildren.size())
388             myChildren.insert(aIdx, aNode);
389           else
390             myChildren.append(aNode);
391           aResult.append(aNode);
392         }
393       }
394     }
395   }
396   // Update sub-folders
397   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
398     if ((aNode->type() == PartSet_ObjectFolderNode::typeId()) ||
399       (aNode->type() == PartSet_PartRootNode::typeId()))
400       aResult.append(aNode->objectCreated(theObjects));
401   }
402   return aResult;
403 }
404
405 QTreeNodesList PartSet_FeatureFolderNode::objectsDeleted(const DocumentPtr& theDoc,
406   const QString& theGroup)
407 {
408   QTreeNodesList aResult;
409
410   // Process sub-folders
411   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
412     if (aNode->childrenCount() > 0) { // aFolder node
413       QTreeNodesList aList = aNode->objectsDeleted(theDoc, theGroup);
414       if (aList.size() > 0)
415         aResult.append(aList);
416     }
417   }
418
419   // Process root
420   DocumentPtr aDoc = document();
421   int aNb = numberOfFolders();
422   bool isGroup = ((theGroup.toStdString() == ModelAPI_Feature::group()) ||
423     (theGroup.toStdString() == ModelAPI_Folder::group()));
424   if ((theDoc == aDoc) && isGroup) {
425     QTreeNodesList aDelList;
426     int aIndex;
427     int aId = -1;
428     foreach(ModuleBase_ITreeNode* aNode, myChildren) {
429       aId++;
430       if (aNode->object().get()) {
431         aIndex = aDoc->index(aNode->object(), true);
432         if ((aIndex == -1) || (aId != aIndex))
433           aDelList.append(aNode);
434       }
435     }
436     if (aDelList.size() > 0) {
437       foreach(ModuleBase_ITreeNode* aNode, aDelList) {
438         myChildren.removeAll(aNode);
439         delete aNode;
440       }
441       aResult.append(this);
442     }
443   }
444   return aResult;
445 }
446
447 ModuleBase_ITreeNode* PartSet_FeatureFolderNode::findParent(const DocumentPtr& theDoc,
448   QString theGroup)
449 {
450   ModuleBase_ITreeNode* aResult = 0;
451   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
452     aResult = aNode->findParent(theDoc, theGroup);
453     if (aResult) {
454       return aResult;
455     }
456   }
457   bool isGroup = ((theGroup.toStdString() == ModelAPI_Feature::group()) ||
458     (theGroup.toStdString() == ModelAPI_Folder::group()));
459   if ((theDoc == document()) && isGroup)
460     return this;
461   return 0;
462 }
463
464
465 //////////////////////////////////////////////////////////////////////////////////
466 PartSet_RootNode::PartSet_RootNode() : PartSet_FeatureFolderNode(0), myWorkshop(0)
467 {
468   SessionPtr aSession = ModelAPI_Session::get();
469   DocumentPtr aDoc = aSession->moduleDocument();
470
471   myParamsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ParametersFolder);
472   myConstrFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ConstructionFolder);
473   myPartsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::PartsFolder);
474
475   myChildren.append(myParamsFolder);
476   myChildren.append(myConstrFolder);
477   myChildren.append(myPartsFolder);
478
479   update();
480 }
481
482
483 void PartSet_RootNode::update()
484 {
485   myParamsFolder->update();
486   myConstrFolder->update();
487   myPartsFolder->update();
488
489   // Update features content
490   DocumentPtr aDoc = document();
491   int aNb = numberOfFolders();
492
493   // Remove extra sub-nodes
494   QTreeNodesList aDelList;
495   int aIndex;
496   int aId = -1;
497   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
498     aId++;
499     if (aNode->object().get()) {
500       aIndex = aDoc->index(aNode->object(), true);
501       if ((aIndex == -1) || (aId != (aIndex + aNb)))
502         aDelList.append(aNode);
503     }
504   }
505   foreach(ModuleBase_ITreeNode* aNode, aDelList) {
506     myChildren.removeAll(aNode);
507     delete aNode;
508   }
509
510   // Add new nodes
511   std::string aGroup = ModelAPI_Feature::group();
512   int aSize = aDoc->size(aGroup, true);
513   FeaturePtr aFeature;
514   for (int i = 0; i < aSize; i++) {
515     ObjectPtr aObj = aDoc->object(aGroup, i, true);
516     aId = i + aNb; // Take into account existing folders
517     if (aId < myChildren.size()) {
518       if (myChildren.at(aId)->object() != aObj) {
519         ModuleBase_ITreeNode* aNode = createNode(aObj);
520         myChildren.insert(aId, aNode);
521       }
522     } else {
523       ModuleBase_ITreeNode* aNode = createNode(aObj);
524       myChildren.append(aNode);
525     }
526   }
527   // Update sub-folders
528   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
529     if ((aNode->type() == PartSet_ObjectFolderNode::typeId()) ||
530       (aNode->type() == PartSet_PartRootNode::typeId()))
531       aNode->update();
532   }
533 }
534
535 DocumentPtr PartSet_RootNode::document() const
536 {
537   return ModelAPI_Session::get()->moduleDocument();
538 }
539
540 ModuleBase_ITreeNode* PartSet_RootNode::createNode(const ObjectPtr& theObj)
541 {
542   if (theObj->groupName() == ModelAPI_Folder::group())
543     return new PartSet_ObjectFolderNode(theObj, this);
544
545   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
546   if (aFeature->getKind() == PartSetPlugin_Part::ID())
547     return new PartSet_PartRootNode(theObj, this);
548
549   return new PartSet_ObjectNode(theObj, this);
550 }
551
552 //////////////////////////////////////////////////////////////////////////////////
553 PartSet_PartRootNode::PartSet_PartRootNode(const ObjectPtr& theObj, ModuleBase_ITreeNode* theParent)
554   : PartSet_FeatureFolderNode(theParent), myObject(theObj)
555 {
556   myParamsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ParametersFolder);
557   myConstrFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ConstructionFolder);
558   myResultsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ResultsFolder);
559   myFieldsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::FieldsFolder);
560   myGroupsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::GroupsFolder);
561
562   myChildren.append(myParamsFolder);
563   myChildren.append(myConstrFolder);
564   myChildren.append(myResultsFolder);
565
566   update();
567 }
568
569 void PartSet_PartRootNode::deleteChildren()
570 {
571   if (!myFieldsFolder->childrenCount()) {
572     delete myFieldsFolder;
573   }
574   if (!myGroupsFolder->childrenCount()) {
575     delete myGroupsFolder;
576   }
577   PartSet_FeatureFolderNode::deleteChildren();
578 }
579
580
581 void PartSet_PartRootNode::update()
582 {
583   DocumentPtr aDoc = document();
584   if (!aDoc.get())
585     return;
586
587   myParamsFolder->update();
588   myConstrFolder->update();
589   myResultsFolder->update();
590   myFieldsFolder->update();
591   myGroupsFolder->update();
592
593   bool aHasFields = myFieldsFolder->childrenCount() > 0;
594   bool aHasGroups = myGroupsFolder->childrenCount() > 0;
595   if (aHasFields && (!myChildren.contains(myFieldsFolder))) {
596     myChildren.insert(3, myFieldsFolder);
597   }
598   if (aHasGroups && (!myChildren.contains(myGroupsFolder))) {
599     myChildren.insert(aHasFields ? 4 : 3, myGroupsFolder);
600   }
601
602   // Update features content
603   int aRows = numberOfFolders();
604
605   // Remove extra sub-nodes
606   QTreeNodesList aDelList;
607   int aIndex = -1;
608   int aId = -1;
609   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
610     aId++;
611     if (aNode->object().get()) {
612       aIndex = aDoc->index(aNode->object(), true);
613       if ((aIndex == -1) || (aId != (aIndex + aRows)))
614         aDelList.append(aNode);
615     }
616   }
617   foreach(ModuleBase_ITreeNode* aNode, aDelList) {
618     myChildren.removeAll(aNode);
619     delete aNode;
620   }
621
622   std::string aGroup = ModelAPI_Feature::group();
623   int aSize = aDoc->size(aGroup, true);
624   FeaturePtr aFeature;
625   for (int i = 0; i < aSize; i++) {
626     ObjectPtr aObj = aDoc->object(aGroup, i, true);
627     aId = i + aRows; // Take into account existing folders
628     if (aId < myChildren.size()) {
629       if (myChildren.at(aId)->object() != aObj) {
630         ModuleBase_ITreeNode* aNode = createNode(aObj);
631         myChildren.insert(aId, aNode);
632       }
633     } else {
634       ModuleBase_ITreeNode* aNode = createNode(aObj);
635       myChildren.append(aNode);
636     }
637   }
638   // Update sub-folders
639   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
640     if (aNode->type() == PartSet_ObjectFolderNode::typeId())
641       aNode->update();
642   }
643 }
644
645 DocumentPtr PartSet_PartRootNode::document() const
646 {
647   ResultPartPtr aPartRes = getPartResult(myObject);
648   if (aPartRes.get())
649     return aPartRes->partDoc();
650   return DocumentPtr();
651 }
652
653 QVariant PartSet_PartRootNode::data(int theColumn, int theRole) const
654 {
655   switch (theColumn) {
656   case 1:
657     switch (theRole) {
658     case Qt::DisplayRole:
659       return QString(myObject->data()->name().c_str());
660     case Qt::DecorationRole:
661       return ModuleBase_IconFactory::get()->getIcon(myObject);
662     }
663   case 2:
664     if (theRole == Qt::DecorationRole)
665       if (isCurrentFeature(myObject))
666         return QIcon(":pictures/arrow.png");
667   }
668   return PartSet_TreeNode::data(theColumn, theRole);
669 }
670
671 Qt::ItemFlags PartSet_PartRootNode::flags(int theColumn) const
672 {
673   SessionPtr aSession = ModelAPI_Session::get();
674   DocumentPtr aActiveDoc = aSession->activeDocument();
675   if ((aActiveDoc == document()) || (myObject->document() == aActiveDoc))
676     return aEditingFlag;
677   return aDefaultFlag;
678 }
679
680 ModuleBase_ITreeNode* PartSet_PartRootNode::createNode(const ObjectPtr& theObj)
681 {
682   if (theObj->groupName() == ModelAPI_Folder::group())
683     return new PartSet_ObjectFolderNode(theObj, this);
684   return new PartSet_ObjectNode(theObj, this);
685 }
686
687 int PartSet_PartRootNode::numberOfFolders() const
688 {
689   int aNb = 3;
690   if (myFieldsFolder->childrenCount() > 0)
691     aNb++;
692   if (myGroupsFolder->childrenCount() > 0)
693     aNb++;
694   return aNb;
695 }
696
697 QTreeNodesList PartSet_PartRootNode::objectCreated(const QObjectPtrList& theObjects)
698 {
699   QTreeNodesList aResult = PartSet_FeatureFolderNode::objectCreated(theObjects);
700   if (!myFieldsFolder->childrenCount()) {
701     QTreeNodesList aList = myFieldsFolder->objectCreated(theObjects);
702     if (aList.size()) {
703       myChildren.insert(3, myFieldsFolder);
704       aResult.append(myFieldsFolder);
705       aResult.append(aList);
706     }
707   }
708   if (!myGroupsFolder->childrenCount()) {
709     QTreeNodesList aList = myGroupsFolder->objectCreated(theObjects);
710     if (aList.size()) {
711       myChildren.insert(myFieldsFolder->childrenCount()? 4 : 3, myGroupsFolder);
712       aResult.append(myGroupsFolder);
713       aResult.append(aList);
714     }
715   }
716   return aResult;
717 }
718
719 QTreeNodesList PartSet_PartRootNode::objectsDeleted(const DocumentPtr& theDoc,
720   const QString& theGroup)
721 {
722   QTreeNodesList aResult;
723   if (myFieldsFolder->childrenCount()) {
724     QTreeNodesList aList = myFieldsFolder->objectsDeleted(theDoc, theGroup);
725     if (aList.size()) {
726       aResult.append(aList);
727       if (!myFieldsFolder->childrenCount())
728         myChildren.removeAll(myFieldsFolder);
729     }
730   }
731   if (myGroupsFolder->childrenCount()) {
732     QTreeNodesList aList = myGroupsFolder->objectsDeleted(theDoc, theGroup);
733     if (aList.size()) {
734       aResult.append(aList);
735       if (!myGroupsFolder->childrenCount())
736         myChildren.removeAll(myGroupsFolder);
737     }
738   }
739   aResult.append(PartSet_FeatureFolderNode::objectsDeleted(theDoc, theGroup));
740   return aResult;
741 }
742
743 //////////////////////////////////////////////////////////////////////////////////
744 void PartSet_ObjectFolderNode::update()
745 {
746   int aFirst, aLast;
747   getFirstAndLastIndex(aFirst, aLast);
748   if ((aFirst == -1) || (aLast == -1)) {
749     deleteChildren();
750     return;
751   }
752
753   int aNbItems = aLast - aFirst + 1;
754   if (!aNbItems) {
755     deleteChildren();
756     return;
757   }
758
759   DocumentPtr aDoc = myObject->document();
760   // Delete obsolete nodes
761   QTreeNodesList aDelList;
762   int aId = -1;
763   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
764     aId++;
765     if ((aFirst + aId) < aDoc->size(ModelAPI_Feature::group(), true)) {
766       if (aNode->object() != aDoc->object(ModelAPI_Feature::group(), aFirst + aId)) {
767         aDelList.append(aNode);
768       }
769     } else {
770       aDelList.append(aNode);
771     }
772   }
773   foreach(ModuleBase_ITreeNode* aNode, aDelList) {
774     myChildren.removeAll(aNode);
775     delete aNode;
776   }
777
778   // Add new nodes
779   ModuleBase_ITreeNode* aNode;
780   for (int i = 0; i < aNbItems; i++) {
781     ObjectPtr aObj = aDoc->object(ModelAPI_Feature::group(), aFirst + i);
782     if (i < myChildren.size()) {
783       if (aObj != myChildren.at(i)->object()) {
784         aNode = new PartSet_ObjectNode(aObj, this);
785         myChildren.insert(i, aNode);
786       }
787     } else {
788       aNode = new PartSet_ObjectNode(aObj, this);
789       myChildren.append(aNode);
790     }
791   }
792 }
793
794 QTreeNodesList PartSet_ObjectFolderNode::objectCreated(const QObjectPtrList& theObjects)
795 {
796   QTreeNodesList aResult;
797   int aFirst, aLast;
798   getFirstAndLastIndex(aFirst, aLast);
799   if ((aFirst == -1) || (aLast == -1)) {
800     return aResult;
801   }
802   int aNbItems = aLast - aFirst + 1;
803   if (!aNbItems) {
804     return aResult;
805   }
806   DocumentPtr aDoc = myObject->document();
807   // Add new nodes
808   ModuleBase_ITreeNode* aNode;
809   for (int i = 0; i < aNbItems; i++) {
810     ObjectPtr aObj = aDoc->object(ModelAPI_Feature::group(), aFirst + i);
811     if (i < myChildren.size()) {
812       if (aObj != myChildren.at(i)->object()) {
813         aNode = new PartSet_ObjectNode(aObj, this);
814         myChildren.insert(i, aNode);
815         aResult.append(aNode);
816       }
817     } else {
818       aNode = new PartSet_ObjectNode(aObj, this);
819       myChildren.append(aNode);
820       aResult.append(aNode);
821     }
822   }
823   return aResult;
824 }
825
826 QTreeNodesList PartSet_ObjectFolderNode::objectsDeleted(const DocumentPtr& theDoc,
827   const QString& theGroup)
828 {
829   QTreeNodesList aResult;
830   int aFirst, aLast;
831   getFirstAndLastIndex(aFirst, aLast);
832   if ((aFirst == -1) || (aLast == -1)) {
833     return aResult;
834   }
835   int aNbItems = aLast - aFirst + 1;
836   if (!aNbItems) {
837     return aResult;
838   }
839   DocumentPtr aDoc = myObject->document();
840   // Delete obsolete nodes
841   QTreeNodesList aDelList;
842   int aId = -1;
843   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
844     aId++;
845     if ((aFirst + aId) < aDoc->size(ModelAPI_Feature::group(), true)) {
846       if (aNode->object() != aDoc->object(ModelAPI_Feature::group(), aFirst + aId)) {
847         aDelList.append(aNode);
848       }
849     } else {
850       aDelList.append(aNode);
851     }
852   }
853   if (aDelList.size() > 0) {
854     aResult.append(this);
855     foreach(ModuleBase_ITreeNode* aNode, aDelList) {
856       myChildren.removeAll(aNode);
857       delete aNode;
858     }
859   }
860   return aResult;
861 }
862
863 FeaturePtr PartSet_ObjectFolderNode::getFeature(const std::string& theId) const
864 {
865   FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(myObject);
866   AttributeReferencePtr aFeatAttr = aFolder->data()->reference(theId);
867   if (aFeatAttr)
868     return ModelAPI_Feature::feature(aFeatAttr->value());
869   return FeaturePtr();
870 }
871
872 void PartSet_ObjectFolderNode::getFirstAndLastIndex(int& theFirst, int& theLast) const
873 {
874   DocumentPtr aDoc = myObject->document();
875   FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(myObject);
876
877   FeaturePtr aFirstFeatureInFolder = getFeature(ModelAPI_Folder::FIRST_FEATURE_ID());
878   if (!aFirstFeatureInFolder.get()) {
879     theFirst = -1;
880     return;
881   }
882   FeaturePtr aLastFeatureInFolder = getFeature(ModelAPI_Folder::LAST_FEATURE_ID());
883   if (!aLastFeatureInFolder.get()) {
884     theLast = -1;
885     return;
886   }
887
888   theFirst = aDoc->index(aFirstFeatureInFolder);
889   theLast = aDoc->index(aLastFeatureInFolder);
890 }