]> SALOME platform Git repositories - modules/shaper.git/blob - src/PartSet/PartSet_TreeNodes.cpp
Salome HOME
Fix for sketcher rectangle
[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 (visibilityState()) {
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     return (theColumn == 2) ? Qt::ItemIsSelectable : aNullFlag;
139   } else {
140     DocumentPtr aDoc = myObject->document();
141     SessionPtr aSession = ModelAPI_Session::get();
142     if (aSession->activeDocument() == aDoc)
143       return aEditingFlag;
144   }
145   return aDefaultFlag;
146 }
147
148 PartSet_ObjectNode::VisibilityState PartSet_ObjectNode::visibilityState() const
149 {
150   Qt::ItemFlags aFlags = flags(1);
151   if (aFlags == Qt::ItemFlags())
152     return NoneState;
153
154   if (myObject->groupName() == ModelAPI_ResultParameter::group())
155     return NoneState;
156   ResultPtr aResObj = std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
157   if (aResObj.get()) {
158     ModuleBase_IWorkshop* aWork = workshop();
159     ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aResObj);
160     if (aCompRes.get()) {
161       VisibilityState aState = aCompRes->numberOfSubs(true) == 0 ?
162         (aWork->isVisible(aCompRes) ? Visible : Hidden) : NoneState;
163       for (int i = 0; i < aCompRes->numberOfSubs(true); i++) {
164         ResultPtr aSubRes = aCompRes->subResult(i, true);
165         VisibilityState aS = aWork->isVisible(aSubRes) ? Visible : Hidden;
166         if (aState == NoneState)
167           aState = aS;
168         else if (aState != aS) {
169           aState = SemiVisible;
170           break;
171         }
172       }
173       return aState;
174     } else {
175       if (aWork->isVisible(aResObj))
176         return Visible;
177       else
178         return Hidden;
179     }
180   }
181   return NoneState;
182 }
183
184
185 //////////////////////////////////////////////////////////////////////////////////
186 PartSet_FolderNode::PartSet_FolderNode(ModuleBase_ITreeNode* theParent,
187   FolderType theType)
188   : PartSet_TreeNode(theParent), myType(theType)
189 {
190 }
191
192 QString PartSet_FolderNode::name() const
193 {
194   switch (myType) {
195   case ParametersFolder:
196     return QObject::tr("Parameters");
197   case ConstructionFolder:
198     return QObject::tr("Constructions");
199   case PartsFolder:
200     return QObject::tr("Parts");
201   case ResultsFolder:
202     return QObject::tr("Results");
203   case FieldsFolder:
204     return QObject::tr("Fields");
205   case GroupsFolder:
206     return QObject::tr("Groups");
207   }
208   return "NoName";
209 }
210
211
212 QVariant PartSet_FolderNode::data(int theColumn, int theRole) const
213 {
214   static QIcon aParamsIco(":pictures/params_folder.png");
215   static QIcon aConstrIco(":pictures/constr_folder.png");
216
217   if (theColumn == 1) {
218     switch (theRole) {
219     case Qt::DisplayRole:
220       return name() + QString(" (%1)").arg(childrenCount());
221     case Qt::DecorationRole:
222       switch (myType) {
223       case ParametersFolder:
224         return aParamsIco;
225       case ConstructionFolder:
226         return aConstrIco;
227       case PartsFolder:
228         return aConstrIco;
229       case ResultsFolder:
230         return aConstrIco;
231       case FieldsFolder:
232         return aConstrIco;
233       case GroupsFolder:
234         return aConstrIco;
235       }
236     }
237   }
238   return PartSet_TreeNode::data(theColumn, theRole);
239 }
240
241 Qt::ItemFlags PartSet_FolderNode::flags(int theColumn) const
242 {
243   SessionPtr aSession = ModelAPI_Session::get();
244   DocumentPtr aActiveDoc = aSession->activeDocument();
245   if (theColumn == 1) {
246     if (document() == aActiveDoc)
247       return aEditingFlag;
248   }
249   return aDefaultFlag;
250 }
251
252 void PartSet_FolderNode::update()
253 {
254   DocumentPtr aDoc = document();
255   if (!aDoc.get())
256     return;
257
258   // Remove extra sub-nodes
259   QTreeNodesList aDelList;
260   int aIndex;
261   int aId = -1;
262   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
263     aId++;
264     aIndex = aDoc->index(aNode->object(), true);
265     if ((aIndex == -1) || (aId != aIndex))
266       aDelList.append(aNode);
267   }
268   foreach(ModuleBase_ITreeNode* aNode, aDelList) {
269     myChildren.removeAll(aNode);
270     delete aNode;
271   }
272
273   // Add new nodes
274   std::string aGroup = groupName();
275   int aSize = aDoc->size(aGroup, true);
276   for (int i = 0; i < aSize; i++) {
277     ObjectPtr aObj = aDoc->object(aGroup, i, true);
278     if (i < myChildren.size()) {
279       if (myChildren.at(i)->object() != aObj) {
280         PartSet_ObjectNode* aNode = new PartSet_ObjectNode(aObj, this);
281         myChildren.insert(i, aNode);
282       }
283     } else {
284       PartSet_ObjectNode* aNode = new PartSet_ObjectNode(aObj, this);
285       myChildren.append(aNode);
286     }
287   }
288 }
289
290 std::string PartSet_FolderNode::groupName() const
291 {
292   switch (myType) {
293   case ParametersFolder:
294     return ModelAPI_ResultParameter::group();
295   case ConstructionFolder:
296     return ModelAPI_ResultConstruction::group();
297   case PartsFolder:
298     return ModelAPI_ResultPart::group();
299   case ResultsFolder:
300     return ModelAPI_ResultBody::group();
301   case FieldsFolder:
302     return ModelAPI_ResultField::group();
303   case GroupsFolder:
304     return ModelAPI_ResultGroup::group();
305   }
306   return "";
307 }
308
309 QTreeNodesList PartSet_FolderNode::objectCreated(const QObjectPtrList& theObjects)
310 {
311   QTreeNodesList aResult;
312   std::string aName = groupName();
313   DocumentPtr aDoc = document();
314   int aIdx = -1;
315   foreach(ObjectPtr aObj, theObjects) {
316     if ((aObj->document() == aDoc) && (aObj->groupName() == aName)) {
317       aIdx = aDoc->index(aObj, true);
318       if (aIdx != -1) {
319         bool aHasObject = (aIdx < myChildren.size()) && (myChildren.at(aIdx)->object() == aObj);
320         if (!aHasObject) {
321           PartSet_ObjectNode* aNode = new PartSet_ObjectNode(aObj, this);
322           aResult.append(aNode);
323           if (aIdx < myChildren.size())
324             myChildren.insert(aIdx, aNode);
325           else
326             myChildren.append(aNode);
327         }
328       }
329     }
330   }
331   return aResult;
332 }
333
334 QTreeNodesList PartSet_FolderNode::objectsDeleted(const DocumentPtr& theDoc,
335   const QString& theGroup)
336 {
337   DocumentPtr aDoc = document();
338   QTreeNodesList aResult;
339   if ((theGroup.toStdString() == groupName()) && (theDoc == aDoc)) {
340     QTreeNodesList aDelList;
341     int aIndex;
342     int aId = -1;
343     foreach(ModuleBase_ITreeNode* aNode, myChildren) {
344       aId++;
345       aIndex = aDoc->index(aNode->object(), true);
346       if ((aIndex == -1) || (aId != aIndex))
347         aDelList.append(aNode);
348     }
349     if (aDelList.size() > 0) {
350       foreach(ModuleBase_ITreeNode* aNode, aDelList) {
351         myChildren.removeAll(aNode);
352         delete aNode;
353       }
354       aResult.append(this);
355     }
356   }
357   return aResult;
358 }
359
360 //////////////////////////////////////////////////////////////////////////////////
361 QTreeNodesList PartSet_FeatureFolderNode::objectCreated(const QObjectPtrList& theObjects)
362 {
363   QTreeNodesList aResult;
364   // Process all folders
365   ModuleBase_ITreeNode* aFoder = 0;
366   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
367     if ((aNode->type() == PartSet_FolderNode::typeId()) ||
368       (aNode->type() == PartSet_PartRootNode::typeId())) { // aFolder node
369       QTreeNodesList aList = aNode->objectCreated(theObjects);
370       if (aList.size() > 0)
371         aResult.append(aList);
372     }
373   }
374   // Process the root sub-objects
375   DocumentPtr aDoc = document();
376   int aIdx = -1;
377   int aNb = numberOfFolders();
378   foreach(ObjectPtr aObj, theObjects) {
379     if (aDoc == aObj->document()) {
380       if ((aObj->groupName() == ModelAPI_Feature::group()) ||
381         (aObj->groupName() == ModelAPI_Folder::group())){
382         ModuleBase_ITreeNode* aNode = createNode(aObj);
383         aIdx = aDoc->index(aObj, true);
384         if (aIdx != -1) {
385           aIdx += aNb;
386           bool aHasObject = (aIdx < myChildren.size()) && (myChildren.at(aIdx)->object() == aObj);
387           if (!aHasObject) {
388             if (aIdx < myChildren.size())
389               myChildren.insert(aIdx, aNode);
390             else
391               myChildren.append(aNode);
392             aResult.append(aNode);
393           }
394         }
395       }
396     }
397   }
398   // Update sub-folders
399   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
400     if ((aNode->type() == PartSet_ObjectFolderNode::typeId()) ||
401       (aNode->type() == PartSet_PartRootNode::typeId()))
402       aResult.append(aNode->objectCreated(theObjects));
403   }
404   return aResult;
405 }
406
407 QTreeNodesList PartSet_FeatureFolderNode::objectsDeleted(const DocumentPtr& theDoc,
408   const QString& theGroup)
409 {
410   QTreeNodesList aResult;
411
412   // Process sub-folders
413   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
414     if (aNode->childrenCount() > 0) { // aFolder node
415       QTreeNodesList aList = aNode->objectsDeleted(theDoc, theGroup);
416       if (aList.size() > 0)
417         aResult.append(aList);
418     }
419   }
420
421   // Process root
422   DocumentPtr aDoc = document();
423   int aNb = numberOfFolders();
424   bool isGroup = ((theGroup.toStdString() == ModelAPI_Feature::group()) ||
425     (theGroup.toStdString() == ModelAPI_Folder::group()));
426   if ((theDoc == aDoc) && isGroup) {
427     QTreeNodesList aDelList;
428     int aIndex;
429     int aId = -1;
430     foreach(ModuleBase_ITreeNode* aNode, myChildren) {
431       aId++;
432       if (aNode->object().get()) {
433         aIndex = aDoc->index(aNode->object(), true);
434         if ((aIndex == -1) || (aId != (aIndex + aNb)))
435           aDelList.append(aNode);
436       }
437     }
438     if (aDelList.size() > 0) {
439       foreach(ModuleBase_ITreeNode* aNode, aDelList) {
440         myChildren.removeAll(aNode);
441         delete aNode;
442       }
443       aResult.append(this);
444     }
445   }
446   return aResult;
447 }
448
449 ModuleBase_ITreeNode* PartSet_FeatureFolderNode::findParent(const DocumentPtr& theDoc,
450   QString theGroup)
451 {
452   ModuleBase_ITreeNode* aResult = 0;
453   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
454     aResult = aNode->findParent(theDoc, theGroup);
455     if (aResult) {
456       return aResult;
457     }
458   }
459   bool isGroup = ((theGroup.toStdString() == ModelAPI_Feature::group()) ||
460     (theGroup.toStdString() == ModelAPI_Folder::group()));
461   if ((theDoc == document()) && isGroup)
462     return this;
463   return 0;
464 }
465
466
467 //////////////////////////////////////////////////////////////////////////////////
468 PartSet_RootNode::PartSet_RootNode() : PartSet_FeatureFolderNode(0), myWorkshop(0)
469 {
470   SessionPtr aSession = ModelAPI_Session::get();
471   DocumentPtr aDoc = aSession->moduleDocument();
472
473   myParamsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ParametersFolder);
474   myConstrFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ConstructionFolder);
475   myPartsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::PartsFolder);
476
477   myChildren.append(myParamsFolder);
478   myChildren.append(myConstrFolder);
479   myChildren.append(myPartsFolder);
480
481   update();
482 }
483
484
485 void PartSet_RootNode::update()
486 {
487   myParamsFolder->update();
488   myConstrFolder->update();
489   myPartsFolder->update();
490
491   // Update features content
492   DocumentPtr aDoc = document();
493   int aNb = numberOfFolders();
494
495   // Remove extra sub-nodes
496   QTreeNodesList aDelList;
497   int aIndex;
498   int aId = -1;
499   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
500     aId++;
501     if (aNode->object().get()) {
502       aIndex = aDoc->index(aNode->object(), true);
503       if ((aIndex == -1) || (aId != (aIndex + aNb)))
504         aDelList.append(aNode);
505     }
506   }
507   foreach(ModuleBase_ITreeNode* aNode, aDelList) {
508     myChildren.removeAll(aNode);
509     delete aNode;
510   }
511
512   // Add new nodes
513   std::string aGroup = ModelAPI_Feature::group();
514   int aSize = aDoc->size(aGroup, true);
515   FeaturePtr aFeature;
516   for (int i = 0; i < aSize; i++) {
517     ObjectPtr aObj = aDoc->object(aGroup, i, true);
518     aId = i + aNb; // Take into account existing folders
519     if (aId < myChildren.size()) {
520       if (myChildren.at(aId)->object() != aObj) {
521         ModuleBase_ITreeNode* aNode = createNode(aObj);
522         myChildren.insert(aId, aNode);
523       }
524     } else {
525       ModuleBase_ITreeNode* aNode = createNode(aObj);
526       myChildren.append(aNode);
527     }
528   }
529   // Update sub-folders
530   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
531     if ((aNode->type() == PartSet_ObjectFolderNode::typeId()) ||
532       (aNode->type() == PartSet_PartRootNode::typeId()))
533       aNode->update();
534   }
535 }
536
537 DocumentPtr PartSet_RootNode::document() const
538 {
539   return ModelAPI_Session::get()->moduleDocument();
540 }
541
542 ModuleBase_ITreeNode* PartSet_RootNode::createNode(const ObjectPtr& theObj)
543 {
544   if (theObj->groupName() == ModelAPI_Folder::group())
545     return new PartSet_ObjectFolderNode(theObj, this);
546
547   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
548   if (aFeature->getKind() == PartSetPlugin_Part::ID())
549     return new PartSet_PartRootNode(theObj, this);
550
551   return new PartSet_ObjectNode(theObj, this);
552 }
553
554 //////////////////////////////////////////////////////////////////////////////////
555 PartSet_PartRootNode::PartSet_PartRootNode(const ObjectPtr& theObj, ModuleBase_ITreeNode* theParent)
556   : PartSet_FeatureFolderNode(theParent), myObject(theObj)
557 {
558   myParamsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ParametersFolder);
559   myConstrFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ConstructionFolder);
560   myResultsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ResultsFolder);
561   myFieldsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::FieldsFolder);
562   myGroupsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::GroupsFolder);
563
564   myChildren.append(myParamsFolder);
565   myChildren.append(myConstrFolder);
566   myChildren.append(myResultsFolder);
567
568   update();
569 }
570
571 void PartSet_PartRootNode::deleteChildren()
572 {
573   if (!myFieldsFolder->childrenCount()) {
574     delete myFieldsFolder;
575   }
576   if (!myGroupsFolder->childrenCount()) {
577     delete myGroupsFolder;
578   }
579   PartSet_FeatureFolderNode::deleteChildren();
580 }
581
582
583 void PartSet_PartRootNode::update()
584 {
585   DocumentPtr aDoc = document();
586   if (!aDoc.get())
587     return;
588
589   myParamsFolder->update();
590   myConstrFolder->update();
591   myResultsFolder->update();
592   myFieldsFolder->update();
593   myGroupsFolder->update();
594
595   bool aHasFields = myFieldsFolder->childrenCount() > 0;
596   bool aHasGroups = myGroupsFolder->childrenCount() > 0;
597   if (aHasFields && (!myChildren.contains(myFieldsFolder))) {
598     myChildren.insert(3, myFieldsFolder);
599   }
600   if (aHasGroups && (!myChildren.contains(myGroupsFolder))) {
601     myChildren.insert(aHasFields ? 4 : 3, myGroupsFolder);
602   }
603
604   // Update features content
605   int aRows = numberOfFolders();
606
607   // Remove extra sub-nodes
608   QTreeNodesList aDelList;
609   int aIndex = -1;
610   int aId = -1;
611   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
612     aId++;
613     if (aNode->object().get()) {
614       aIndex = aDoc->index(aNode->object(), true);
615       if ((aIndex == -1) || (aId != (aIndex + aRows)))
616         aDelList.append(aNode);
617     }
618   }
619   foreach(ModuleBase_ITreeNode* aNode, aDelList) {
620     myChildren.removeAll(aNode);
621     delete aNode;
622   }
623
624   std::string aGroup = ModelAPI_Feature::group();
625   int aSize = aDoc->size(aGroup, true);
626   FeaturePtr aFeature;
627   for (int i = 0; i < aSize; i++) {
628     ObjectPtr aObj = aDoc->object(aGroup, i, true);
629     aId = i + aRows; // Take into account existing folders
630     if (aId < myChildren.size()) {
631       if (myChildren.at(aId)->object() != aObj) {
632         ModuleBase_ITreeNode* aNode = createNode(aObj);
633         myChildren.insert(aId, aNode);
634       }
635     } else {
636       ModuleBase_ITreeNode* aNode = createNode(aObj);
637       myChildren.append(aNode);
638     }
639   }
640   // Update sub-folders
641   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
642     if (aNode->type() == PartSet_ObjectFolderNode::typeId())
643       aNode->update();
644   }
645 }
646
647 DocumentPtr PartSet_PartRootNode::document() const
648 {
649   ResultPartPtr aPartRes = getPartResult(myObject);
650   if (aPartRes.get())
651     return aPartRes->partDoc();
652   return DocumentPtr();
653 }
654
655 QVariant PartSet_PartRootNode::data(int theColumn, int theRole) const
656 {
657   switch (theColumn) {
658   case 1:
659     switch (theRole) {
660     case Qt::DisplayRole:
661       return QString(myObject->data()->name().c_str());
662     case Qt::DecorationRole:
663       return ModuleBase_IconFactory::get()->getIcon(myObject);
664     }
665   case 2:
666     if (theRole == Qt::DecorationRole)
667       if (isCurrentFeature(myObject))
668         return QIcon(":pictures/arrow.png");
669   }
670   return PartSet_TreeNode::data(theColumn, theRole);
671 }
672
673 Qt::ItemFlags PartSet_PartRootNode::flags(int theColumn) const
674 {
675   SessionPtr aSession = ModelAPI_Session::get();
676   DocumentPtr aActiveDoc = aSession->activeDocument();
677   if ((aActiveDoc == document()) || (myObject->document() == aActiveDoc))
678     return aEditingFlag;
679   return aDefaultFlag;
680 }
681
682 ModuleBase_ITreeNode* PartSet_PartRootNode::createNode(const ObjectPtr& theObj)
683 {
684   if (theObj->groupName() == ModelAPI_Folder::group())
685     return new PartSet_ObjectFolderNode(theObj, this);
686   return new PartSet_ObjectNode(theObj, this);
687 }
688
689 int PartSet_PartRootNode::numberOfFolders() const
690 {
691   int aNb = 3;
692   if (myFieldsFolder->childrenCount() > 0)
693     aNb++;
694   if (myGroupsFolder->childrenCount() > 0)
695     aNb++;
696   return aNb;
697 }
698
699 QTreeNodesList PartSet_PartRootNode::objectCreated(const QObjectPtrList& theObjects)
700 {
701   QTreeNodesList aResult = PartSet_FeatureFolderNode::objectCreated(theObjects);
702   if (!myFieldsFolder->childrenCount()) {
703     QTreeNodesList aList = myFieldsFolder->objectCreated(theObjects);
704     if (aList.size()) {
705       myChildren.insert(3, myFieldsFolder);
706       aResult.append(myFieldsFolder);
707       aResult.append(aList);
708     }
709   }
710   if (!myGroupsFolder->childrenCount()) {
711     QTreeNodesList aList = myGroupsFolder->objectCreated(theObjects);
712     if (aList.size()) {
713       myChildren.insert(myFieldsFolder->childrenCount()? 4 : 3, myGroupsFolder);
714       aResult.append(myGroupsFolder);
715       aResult.append(aList);
716     }
717   }
718   return aResult;
719 }
720
721 QTreeNodesList PartSet_PartRootNode::objectsDeleted(const DocumentPtr& theDoc,
722   const QString& theGroup)
723 {
724   QTreeNodesList aResult;
725   if (myFieldsFolder->childrenCount()) {
726     QTreeNodesList aList = myFieldsFolder->objectsDeleted(theDoc, theGroup);
727     if (aList.size()) {
728       aResult.append(aList);
729       if (!myFieldsFolder->childrenCount())
730         myChildren.removeAll(myFieldsFolder);
731     }
732   }
733   if (myGroupsFolder->childrenCount()) {
734     QTreeNodesList aList = myGroupsFolder->objectsDeleted(theDoc, theGroup);
735     if (aList.size()) {
736       aResult.append(aList);
737       if (!myGroupsFolder->childrenCount())
738         myChildren.removeAll(myGroupsFolder);
739     }
740   }
741   aResult.append(PartSet_FeatureFolderNode::objectsDeleted(theDoc, theGroup));
742   return aResult;
743 }
744
745 //////////////////////////////////////////////////////////////////////////////////
746 void PartSet_ObjectFolderNode::update()
747 {
748   int aFirst, aLast;
749   getFirstAndLastIndex(aFirst, aLast);
750   if ((aFirst == -1) || (aLast == -1)) {
751     deleteChildren();
752     return;
753   }
754
755   int aNbItems = aLast - aFirst + 1;
756   if (!aNbItems) {
757     deleteChildren();
758     return;
759   }
760
761   DocumentPtr aDoc = myObject->document();
762   // Delete obsolete nodes
763   QTreeNodesList aDelList;
764   int aId = -1;
765   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
766     aId++;
767     if ((aFirst + aId) < aDoc->size(ModelAPI_Feature::group(), true)) {
768       if (aNode->object() != aDoc->object(ModelAPI_Feature::group(), aFirst + aId)) {
769         aDelList.append(aNode);
770       }
771     } else {
772       aDelList.append(aNode);
773     }
774   }
775   foreach(ModuleBase_ITreeNode* aNode, aDelList) {
776     myChildren.removeAll(aNode);
777     delete aNode;
778   }
779
780   // Add new nodes
781   ModuleBase_ITreeNode* aNode;
782   for (int i = 0; i < aNbItems; i++) {
783     ObjectPtr aObj = aDoc->object(ModelAPI_Feature::group(), aFirst + i);
784     if (i < myChildren.size()) {
785       if (aObj != myChildren.at(i)->object()) {
786         aNode = new PartSet_ObjectNode(aObj, this);
787         myChildren.insert(i, aNode);
788       }
789     } else {
790       aNode = new PartSet_ObjectNode(aObj, this);
791       myChildren.append(aNode);
792     }
793   }
794 }
795
796 QTreeNodesList PartSet_ObjectFolderNode::objectCreated(const QObjectPtrList& theObjects)
797 {
798   QTreeNodesList aResult;
799   int aFirst, aLast;
800   getFirstAndLastIndex(aFirst, aLast);
801   if ((aFirst == -1) || (aLast == -1)) {
802     return aResult;
803   }
804   int aNbItems = aLast - aFirst + 1;
805   if (!aNbItems) {
806     return aResult;
807   }
808   DocumentPtr aDoc = myObject->document();
809   // Add new nodes
810   ModuleBase_ITreeNode* aNode;
811   for (int i = 0; i < aNbItems; i++) {
812     ObjectPtr aObj = aDoc->object(ModelAPI_Feature::group(), aFirst + i);
813     if (i < myChildren.size()) {
814       if (aObj != myChildren.at(i)->object()) {
815         aNode = new PartSet_ObjectNode(aObj, this);
816         myChildren.insert(i, aNode);
817         aResult.append(aNode);
818       }
819     } else {
820       aNode = new PartSet_ObjectNode(aObj, this);
821       myChildren.append(aNode);
822       aResult.append(aNode);
823     }
824   }
825   return aResult;
826 }
827
828 QTreeNodesList PartSet_ObjectFolderNode::objectsDeleted(const DocumentPtr& theDoc,
829   const QString& theGroup)
830 {
831   QTreeNodesList aResult;
832   int aFirst, aLast;
833   getFirstAndLastIndex(aFirst, aLast);
834   if ((aFirst == -1) || (aLast == -1)) {
835     return aResult;
836   }
837   int aNbItems = aLast - aFirst + 1;
838   if (!aNbItems) {
839     return aResult;
840   }
841   DocumentPtr aDoc = myObject->document();
842   // Delete obsolete nodes
843   QTreeNodesList aDelList;
844   int aId = -1;
845   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
846     aId++;
847     if ((aFirst + aId) < aDoc->size(ModelAPI_Feature::group(), true)) {
848       if (aNode->object() != aDoc->object(ModelAPI_Feature::group(), aFirst + aId)) {
849         aDelList.append(aNode);
850       }
851     } else {
852       aDelList.append(aNode);
853     }
854   }
855   if (aDelList.size() > 0) {
856     aResult.append(this);
857     foreach(ModuleBase_ITreeNode* aNode, aDelList) {
858       myChildren.removeAll(aNode);
859       delete aNode;
860     }
861   }
862   return aResult;
863 }
864
865 FeaturePtr PartSet_ObjectFolderNode::getFeature(const std::string& theId) const
866 {
867   FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(myObject);
868   AttributeReferencePtr aFeatAttr = aFolder->data()->reference(theId);
869   if (aFeatAttr)
870     return ModelAPI_Feature::feature(aFeatAttr->value());
871   return FeaturePtr();
872 }
873
874 void PartSet_ObjectFolderNode::getFirstAndLastIndex(int& theFirst, int& theLast) const
875 {
876   DocumentPtr aDoc = myObject->document();
877   FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(myObject);
878
879   FeaturePtr aFirstFeatureInFolder = getFeature(ModelAPI_Folder::FIRST_FEATURE_ID());
880   if (!aFirstFeatureInFolder.get()) {
881     theFirst = -1;
882     return;
883   }
884   FeaturePtr aLastFeatureInFolder = getFeature(ModelAPI_Folder::LAST_FEATURE_ID());
885   if (!aLastFeatureInFolder.get()) {
886     theLast = -1;
887     return;
888   }
889
890   theFirst = aDoc->index(aFirstFeatureInFolder);
891   theLast = aDoc->index(aLastFeatureInFolder);
892 }