]> SALOME platform Git repositories - modules/shaper.git/blob - src/PartSet/PartSet_TreeNodes.cpp
Salome HOME
Provide nesting for tree nodes
[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_ResultBody.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 #include <QMap>
44
45
46 #define ACTIVE_COLOR QColor(Qt::black)
47 #define SELECTABLE_COLOR QColor(100, 100, 100)
48 #define DISABLED_COLOR QColor(200, 200, 200)
49
50 Qt::ItemFlags aNullFlag;
51 Qt::ItemFlags aDefaultFlag = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
52 Qt::ItemFlags aEditingFlag = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
53
54
55 ResultPartPtr getPartResult(const ObjectPtr& theObj)
56 {
57   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
58   if (aFeature) {
59     ResultPtr aRes = aFeature->firstResult();
60     if (aRes.get() && (aRes->groupName() == ModelAPI_ResultPart::group())) {
61       ResultPartPtr aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aRes);
62       // Use only original parts, not a placement results
63       if (aPartRes == aPartRes->original())
64         return aPartRes;
65     }
66   }
67   return ResultPartPtr();
68 }
69
70 bool isCurrentFeature(const ObjectPtr& theObj)
71 {
72   SessionPtr aSession = ModelAPI_Session::get();
73   DocumentPtr aCurDoc = aSession->activeDocument();
74   FeaturePtr aFeature = aCurDoc->currentFeature(true);
75   return aFeature == theObj;
76 }
77
78 //////////////////////////////////////////////////////////////////////////////////
79 QVariant PartSet_TreeNode::data(int theColumn, int theRole) const
80 {
81   if ((theColumn == 1) && (theRole == Qt::ForegroundRole)) {
82     Qt::ItemFlags aFlags = flags(theColumn);
83     if (aFlags == Qt::ItemFlags())
84       return QBrush(DISABLED_COLOR);
85     if (!aFlags.testFlag(Qt::ItemIsEditable))
86       return QBrush(SELECTABLE_COLOR);
87     return ACTIVE_COLOR;
88   }
89   return ModuleBase_ITreeNode::data(theColumn, theRole);
90 }
91
92
93 //////////////////////////////////////////////////////////////////////////////////
94 QVariant PartSet_ObjectNode::data(int theColumn, int theRole) const
95 {
96   switch (theRole) {
97   case Qt::DisplayRole:
98     if (theColumn == 1) {
99       if (myObject->groupName() == ModelAPI_ResultParameter::group()) {
100         ResultParameterPtr aParam = std::dynamic_pointer_cast<ModelAPI_ResultParameter>(myObject);
101         AttributeDoublePtr aValueAttribute =
102           aParam->data()->real(ModelAPI_ResultParameter::VALUE());
103         QString aVal = QString::number(aValueAttribute->value());
104         QString aTitle = QString(myObject->data()->name().c_str());
105         return aTitle + " = " + aVal;
106       }
107       return myObject->data()->name().c_str();
108     }
109     break;
110   case Qt::DecorationRole:
111     switch (theColumn) {
112     case 0:
113       switch (visibilityState()) {
114       case NoneState:
115         return QIcon();
116       case Visible:
117         return QIcon(":pictures/eyeopen.png");
118       case SemiVisible:
119         return QIcon(":pictures/eyemiclosed.png");
120       case Hidden:
121         return QIcon(":pictures/eyeclosed.png");
122       }
123     case 1:
124       if (myObject->groupName() == ModelAPI_Folder::group())
125         return QIcon(":pictures/features_folder.png");
126       else
127         return ModuleBase_IconFactory::get()->getIcon(myObject);
128     case 2:
129       if (isCurrentFeature(myObject))
130         return QIcon(":pictures/arrow.png");
131     }
132   }
133   return PartSet_TreeNode::data(theColumn, theRole);
134 }
135
136 Qt::ItemFlags PartSet_ObjectNode::flags(int theColumn) const
137 {
138   if (myObject->isDisabled()) {
139     return (theColumn == 2) ? Qt::ItemIsSelectable : aNullFlag;
140   } else {
141     DocumentPtr aDoc = myObject->document();
142     SessionPtr aSession = ModelAPI_Session::get();
143     if (aSession->activeDocument() == aDoc)
144       return aEditingFlag;
145   }
146   return aDefaultFlag;
147 }
148
149 PartSet_ObjectNode::VisibilityState PartSet_ObjectNode::visibilityState() const
150 {
151   Qt::ItemFlags aFlags = flags(1);
152   if (aFlags == Qt::ItemFlags())
153     return NoneState;
154
155   if (myObject->groupName() == ModelAPI_ResultParameter::group())
156     return NoneState;
157   ResultPtr aResObj = std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
158   if (aResObj.get()) {
159     ModuleBase_IWorkshop* aWork = workshop();
160     ResultBodyPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aResObj);
161     if (aCompRes.get()) {
162       VisibilityState aState = aCompRes->numberOfSubs(true) == 0 ?
163         (aWork->isVisible(aCompRes) ? Visible : Hidden) : NoneState;
164       for (int i = 0; i < aCompRes->numberOfSubs(true); i++) {
165         ResultPtr aSubRes = aCompRes->subResult(i, true);
166         VisibilityState aS = aWork->isVisible(aSubRes) ? Visible : Hidden;
167         if (aState == NoneState)
168           aState = aS;
169         else if (aState != aS) {
170           aState = SemiVisible;
171           break;
172         }
173       }
174       return aState;
175     } else {
176       if (aWork->isVisible(aResObj))
177         return Visible;
178       else
179         return Hidden;
180     }
181   }
182   return NoneState;
183 }
184
185 void PartSet_ObjectNode::update()
186 {
187   ResultBodyPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultBody>(myObject);
188   if (aCompRes.get()) {
189     int aNb = aCompRes->numberOfSubs(true);
190     ModuleBase_ITreeNode* aNode;
191     ResultBodyPtr aBody;
192     int i;
193     for (i = 0; i < aNb; i++) {
194       aBody = aCompRes->subResult(i, true);
195       if (i < myChildren.size()) {
196         aNode = myChildren.at(i);
197         if (aNode->object() != aBody) {
198           ((PartSet_ObjectNode*)aNode)->setObject(aBody);
199         }
200       } else {
201         aNode = new PartSet_ObjectNode(aBody, this);
202         myChildren.append(aNode);
203       }
204     }
205     // Delete extra objects
206     while (myChildren.size() > aNb) {
207       aNode = myChildren.takeLast();
208       delete aNode;
209     }
210     foreach(ModuleBase_ITreeNode* aNode, myChildren) {
211       aNode->update();
212     }
213   }
214 }
215
216 QTreeNodesList PartSet_ObjectNode::objectCreated(const QObjectPtrList& theObjects)
217 {
218   QTreeNodesList aResult;
219
220   ResultBodyPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultBody>(myObject);
221   if (aCompRes.get()) {
222     int aNb = aCompRes->numberOfSubs(true);
223     ModuleBase_ITreeNode* aNode;
224     ResultBodyPtr aBody;
225     int i;
226     for (i = 0; i < aNb; i++) {
227       aBody = aCompRes->subResult(i, true);
228       if (i < myChildren.size()) {
229         aNode = myChildren.at(i);
230         if (aNode->object() != aBody) {
231           ((PartSet_ObjectNode*)aNode)->setObject(aBody);
232           aResult.append(aNode);
233         }
234       } else {
235         aNode = new PartSet_ObjectNode(aBody, this);
236         myChildren.append(aNode);
237         aResult.append(aNode);
238       }
239     }
240     foreach(ModuleBase_ITreeNode* aNode, myChildren) {
241       aResult.append(aNode->objectCreated(theObjects));
242     }
243   }
244   return aResult;
245 }
246
247 QTreeNodesList PartSet_ObjectNode::objectsDeleted(const DocumentPtr& theDoc, const QString& theGroup)
248 {
249   QTreeNodesList aResult;
250   ResultBodyPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultBody>(myObject);
251   if (aCompRes.get()) {
252     int aNb = aCompRes->numberOfSubs(true);
253     ModuleBase_ITreeNode* aNode;
254     // Delete extra objects
255     bool isDeleted = false;
256     while (myChildren.size() > aNb) {
257       aNode = myChildren.takeLast();
258       delete aNode;
259       isDeleted = true;
260     }
261     if (isDeleted)
262       aResult.append(this);
263     int i = 0;
264     foreach(ModuleBase_ITreeNode* aNode, myChildren) {
265       ((PartSet_ObjectNode*)aNode)->setObject(aCompRes->subResult(i, true));
266       aResult.append(aNode->objectsDeleted(theDoc, theGroup));
267       i++;
268     }
269   }
270   return aResult;
271 }
272 //////////////////////////////////////////////////////////////////////////////////
273 PartSet_FolderNode::PartSet_FolderNode(ModuleBase_ITreeNode* theParent,
274   FolderType theType)
275   : PartSet_TreeNode(theParent), myType(theType)
276 {
277 }
278
279 QString PartSet_FolderNode::name() const
280 {
281   switch (myType) {
282   case ParametersFolder:
283     return QObject::tr("Parameters");
284   case ConstructionFolder:
285     return QObject::tr("Constructions");
286   case PartsFolder:
287     return QObject::tr("Parts");
288   case ResultsFolder:
289     return QObject::tr("Results");
290   case FieldsFolder:
291     return QObject::tr("Fields");
292   case GroupsFolder:
293     return QObject::tr("Groups");
294   }
295   return "NoName";
296 }
297
298
299 QVariant PartSet_FolderNode::data(int theColumn, int theRole) const
300 {
301   static QIcon aParamsIco(":pictures/params_folder.png");
302   static QIcon aConstrIco(":pictures/constr_folder.png");
303
304   if (theColumn == 1) {
305     switch (theRole) {
306     case Qt::DisplayRole:
307       return name() + QString(" (%1)").arg(childrenCount());
308     case Qt::DecorationRole:
309       switch (myType) {
310       case ParametersFolder:
311         return aParamsIco;
312       case ConstructionFolder:
313         return aConstrIco;
314       case PartsFolder:
315         return aConstrIco;
316       case ResultsFolder:
317         return aConstrIco;
318       case FieldsFolder:
319         return aConstrIco;
320       case GroupsFolder:
321         return aConstrIco;
322       }
323     }
324   }
325   return PartSet_TreeNode::data(theColumn, theRole);
326 }
327
328 Qt::ItemFlags PartSet_FolderNode::flags(int theColumn) const
329 {
330   SessionPtr aSession = ModelAPI_Session::get();
331   DocumentPtr aActiveDoc = aSession->activeDocument();
332   if (theColumn == 1) {
333     if (document() == aActiveDoc)
334       return aEditingFlag;
335   }
336   return aDefaultFlag;
337 }
338
339 ModuleBase_ITreeNode* PartSet_FolderNode::createNode(const ObjectPtr& theObj)
340 {
341   //ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(theObj);
342   //if (aCompRes.get())
343   //  return new PartSet_CompsolidNode(theObj, this);
344   return new PartSet_ObjectNode(theObj, this);
345 }
346
347 void PartSet_FolderNode::update()
348 {
349   DocumentPtr aDoc = document();
350   if (!aDoc.get())
351     return;
352
353   // Remove extra sub-nodes
354   int aIndex;
355   int aId = 0;
356   while (aId < myChildren.size()) {
357     ModuleBase_ITreeNode* aNode = myChildren.at(aId);
358     aIndex = aDoc->index(aNode->object(), true);
359     if ((aIndex == -1) || (aId != aIndex)) {
360       myChildren.removeAll(aNode);
361       delete aNode;
362     } else
363       aId++;
364   }
365
366   // Add new nodes
367   std::string aGroup = groupName();
368   int aSize = aDoc->size(aGroup, true);
369   for (int i = 0; i < aSize; i++) {
370     ObjectPtr aObj = aDoc->object(aGroup, i, true);
371     if (i < myChildren.size()) {
372       if (myChildren.at(i)->object() != aObj) {
373         ModuleBase_ITreeNode* aNode = createNode(aObj);
374         myChildren.insert(i, aNode);
375       }
376     } else {
377       ModuleBase_ITreeNode* aNode = createNode(aObj);
378       myChildren.append(aNode);
379     }
380   }
381
382   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
383     aNode->update();
384   }
385 }
386
387 std::string PartSet_FolderNode::groupName() const
388 {
389   switch (myType) {
390   case ParametersFolder:
391     return ModelAPI_ResultParameter::group();
392   case ConstructionFolder:
393     return ModelAPI_ResultConstruction::group();
394   case PartsFolder:
395     return ModelAPI_ResultPart::group();
396   case ResultsFolder:
397     return ModelAPI_ResultBody::group();
398   case FieldsFolder:
399     return ModelAPI_ResultField::group();
400   case GroupsFolder:
401     return ModelAPI_ResultGroup::group();
402   }
403   return "";
404 }
405
406 QTreeNodesList PartSet_FolderNode::objectCreated(const QObjectPtrList& theObjects)
407 {
408   QTreeNodesList aResult;
409   std::string aName = groupName();
410   DocumentPtr aDoc = document();
411   int aIdx = -1;
412   QMap<int, ModuleBase_ITreeNode*> aNewNodes;
413   foreach(ObjectPtr aObj, theObjects) {
414     if ((aObj->document() == aDoc) && (aObj->groupName() == aName)) {
415       aIdx = aDoc->index(aObj, true);
416       if (aIdx != -1) {
417         bool aHasObject = (aIdx < myChildren.size()) && (myChildren.at(aIdx)->object() == aObj);
418         if (!aHasObject) {
419           ModuleBase_ITreeNode* aNode = createNode(aObj);
420           aNewNodes[aIdx] = aNode;
421           aResult.append(aNode);
422         }
423       }
424     }
425   }
426   // Add nodes in correct order
427   int i;
428   for (i = 0; i < myChildren.size(); i++) {
429     if (aNewNodes.contains(i)) {
430       myChildren.insert(i, aNewNodes[i]);
431       aNewNodes.remove(i);
432     }
433   }
434   while (aNewNodes.size()) {
435     i = myChildren.size();
436     myChildren.append(aNewNodes[i]);
437     aNewNodes.remove(i);
438   }
439   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
440     aResult.append(aNode->objectCreated(theObjects));
441   }
442   return aResult;
443 }
444
445 QTreeNodesList PartSet_FolderNode::objectsDeleted(const DocumentPtr& theDoc,
446   const QString& theGroup)
447 {
448   DocumentPtr aDoc = document();
449   QTreeNodesList aResult;
450   if ((theGroup.toStdString() == groupName()) && (theDoc == aDoc)) {
451     QTreeNodesList aDelList;
452     int aIndex;
453     int aId = 0;
454     bool aRemoved = false;
455     while (aId < myChildren.size()) {
456       ModuleBase_ITreeNode* aNode = myChildren.at(aId);
457       aIndex = aDoc->index(aNode->object(), true);
458       if ((aIndex == -1) || (aId != aIndex)) {
459         myChildren.removeAll(aNode);
460         delete aNode;
461         aRemoved = true;
462       }  else
463         aId++;
464     }
465     if (aRemoved)
466       aResult.append(this);
467
468     foreach(ModuleBase_ITreeNode* aNode, myChildren) {
469       aResult.append(aNode->objectsDeleted(theDoc, theGroup));
470     }
471   }
472   return aResult;
473 }
474
475 //////////////////////////////////////////////////////////////////////////////////
476 QTreeNodesList PartSet_FeatureFolderNode::objectCreated(const QObjectPtrList& theObjects)
477 {
478   QTreeNodesList aResult;
479   // Process all folders
480   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
481     if (aNode->type() == PartSet_FolderNode::typeId()) { // aFolder node
482       aResult.append(aNode->objectCreated(theObjects));
483     }
484   }
485   // Process the root sub-objects
486   DocumentPtr aDoc = document();
487   int aIdx = -1;
488   int aNb = numberOfFolders();
489   QMap<int, ModuleBase_ITreeNode*> aNewNodes;
490   foreach(ObjectPtr aObj, theObjects) {
491     if (aDoc == aObj->document()) {
492       if ((aObj->groupName() == ModelAPI_Feature::group()) ||
493         (aObj->groupName() == ModelAPI_Folder::group())){
494         ModuleBase_ITreeNode* aNode = createNode(aObj);
495         aIdx = aDoc->index(aObj, true);
496         if (aIdx != -1) {
497           aIdx += aNb;
498           bool aHasObject = (aIdx < myChildren.size()) && (myChildren.at(aIdx)->object() == aObj);
499           if (!aHasObject) {
500             aNewNodes[aIdx] = aNode;
501             aResult.append(aNode);
502           }
503         }
504       }
505     }
506   }
507   // To add in correct order
508   int i;
509   for (i = 0; i < myChildren.size(); i++) {
510     if (aNewNodes.contains(i)) {
511       myChildren.insert(i, aNewNodes[i]);
512       aNewNodes.remove(i);
513     }
514   }
515   while (aNewNodes.size()) {
516     i = myChildren.size();
517     myChildren.append(aNewNodes[i]);
518     aNewNodes.remove(i);
519   }
520
521   // Update sub-folders
522   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
523     if ((aNode->type() == PartSet_ObjectFolderNode::typeId()) ||
524       (aNode->type() == PartSet_PartRootNode::typeId()))
525       aResult.append(aNode->objectCreated(theObjects));
526   }
527   return aResult;
528 }
529
530 QTreeNodesList PartSet_FeatureFolderNode::objectsDeleted(const DocumentPtr& theDoc,
531   const QString& theGroup)
532 {
533   QTreeNodesList aResult;
534
535   // Process sub-folders
536   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
537     if (aNode->childrenCount() > 0) { // aFolder node
538       QTreeNodesList aList = aNode->objectsDeleted(theDoc, theGroup);
539       if (aList.size() > 0)
540         aResult.append(aList);
541     }
542   }
543
544   // Process root
545   DocumentPtr aDoc = document();
546   int aNb = numberOfFolders();
547   bool isGroup = ((theGroup.toStdString() == ModelAPI_Feature::group()) ||
548     (theGroup.toStdString() == ModelAPI_Folder::group()));
549   if ((theDoc == aDoc) && isGroup) {
550     int aIndex;
551     int aId = 0;
552     bool aRemoved = false;
553     while (aId < myChildren.size()) {
554       ModuleBase_ITreeNode* aNode = myChildren.at(aId);
555       if (aNode->object().get()) {
556         aIndex = aDoc->index(aNode->object(), true);
557         if ((aIndex == -1) || (aId != (aIndex + aNb))) {
558           myChildren.removeAll(aNode);
559           delete aNode;
560           aRemoved = true;
561           continue;
562         }
563       }
564       aId++;
565     }
566     if (aRemoved)
567       aResult.append(this);
568   }
569   return aResult;
570 }
571
572 ModuleBase_ITreeNode* PartSet_FeatureFolderNode::findParent(const DocumentPtr& theDoc,
573   QString theGroup)
574 {
575   ModuleBase_ITreeNode* aResult = 0;
576   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
577     aResult = aNode->findParent(theDoc, theGroup);
578     if (aResult) {
579       return aResult;
580     }
581   }
582   bool isGroup = ((theGroup.toStdString() == ModelAPI_Feature::group()) ||
583     (theGroup.toStdString() == ModelAPI_Folder::group()));
584   if ((theDoc == document()) && isGroup)
585     return this;
586   return 0;
587 }
588
589
590 //////////////////////////////////////////////////////////////////////////////////
591 PartSet_RootNode::PartSet_RootNode() : PartSet_FeatureFolderNode(0), myWorkshop(0)
592 {
593   SessionPtr aSession = ModelAPI_Session::get();
594   DocumentPtr aDoc = aSession->moduleDocument();
595
596   myParamsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ParametersFolder);
597   myConstrFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ConstructionFolder);
598   myPartsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::PartsFolder);
599
600   myChildren.append(myParamsFolder);
601   myChildren.append(myConstrFolder);
602   myChildren.append(myPartsFolder);
603
604   update();
605 }
606
607
608 void PartSet_RootNode::update()
609 {
610   myParamsFolder->update();
611   myConstrFolder->update();
612   myPartsFolder->update();
613
614   // Update features content
615   DocumentPtr aDoc = document();
616   int aNb = numberOfFolders();
617
618   // Remove extra sub-nodes
619   int aIndex;
620   int aId = 0;
621   while (aId < myChildren.size()) {
622     ModuleBase_ITreeNode* aNode = myChildren.at(aId);
623     if (aNode->object().get()) {
624       aIndex = aDoc->index(aNode->object(), true);
625       if ((aIndex == -1) || (aId != (aIndex + aNb))) {
626         myChildren.removeAll(aNode);
627         delete aNode;
628         continue;
629       }
630     }
631     aId++;
632   }
633
634   // Add new nodes
635   std::string aGroup = ModelAPI_Feature::group();
636   int aSize = aDoc->size(aGroup, true);
637   FeaturePtr aFeature;
638   for (int i = 0; i < aSize; i++) {
639     ObjectPtr aObj = aDoc->object(aGroup, i, true);
640     aId = i + aNb; // Take into account existing folders
641     if (aId < myChildren.size()) {
642       if (myChildren.at(aId)->object() != aObj) {
643         ModuleBase_ITreeNode* aNode = createNode(aObj);
644         myChildren.insert(aId, aNode);
645       }
646     } else {
647       ModuleBase_ITreeNode* aNode = createNode(aObj);
648       myChildren.append(aNode);
649     }
650   }
651   // Update sub-folders
652   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
653     if ((aNode->type() == PartSet_ObjectFolderNode::typeId()) ||
654       (aNode->type() == PartSet_PartRootNode::typeId()))
655       aNode->update();
656   }
657 }
658
659 DocumentPtr PartSet_RootNode::document() const
660 {
661   return ModelAPI_Session::get()->moduleDocument();
662 }
663
664 ModuleBase_ITreeNode* PartSet_RootNode::createNode(const ObjectPtr& theObj)
665 {
666   if (theObj->groupName() == ModelAPI_Folder::group())
667     return new PartSet_ObjectFolderNode(theObj, this);
668
669   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
670   if (aFeature->getKind() == PartSetPlugin_Part::ID())
671     return new PartSet_PartRootNode(theObj, this);
672
673   return new PartSet_ObjectNode(theObj, this);
674 }
675
676 //////////////////////////////////////////////////////////////////////////////////
677 PartSet_PartRootNode::PartSet_PartRootNode(const ObjectPtr& theObj, ModuleBase_ITreeNode* theParent)
678   : PartSet_FeatureFolderNode(theParent), myObject(theObj)
679 {
680   myParamsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ParametersFolder);
681   myConstrFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ConstructionFolder);
682   myResultsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ResultsFolder);
683   myFieldsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::FieldsFolder);
684   myGroupsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::GroupsFolder);
685
686   myChildren.append(myParamsFolder);
687   myChildren.append(myConstrFolder);
688   myChildren.append(myResultsFolder);
689
690   update();
691 }
692
693 void PartSet_PartRootNode::deleteChildren()
694 {
695   if (!myFieldsFolder->childrenCount()) {
696     delete myFieldsFolder;
697   }
698   if (!myGroupsFolder->childrenCount()) {
699     delete myGroupsFolder;
700   }
701   PartSet_FeatureFolderNode::deleteChildren();
702 }
703
704
705 void PartSet_PartRootNode::update()
706 {
707   DocumentPtr aDoc = document();
708   if (!aDoc.get())
709     return;
710
711   myParamsFolder->update();
712   myConstrFolder->update();
713   myResultsFolder->update();
714   myFieldsFolder->update();
715   myGroupsFolder->update();
716
717   bool aHasFields = myFieldsFolder->childrenCount() > 0;
718   bool aHasGroups = myGroupsFolder->childrenCount() > 0;
719   if (aHasFields && (!myChildren.contains(myFieldsFolder))) {
720     myChildren.insert(3, myFieldsFolder);
721   }
722   if (aHasGroups && (!myChildren.contains(myGroupsFolder))) {
723     myChildren.insert(aHasFields ? 4 : 3, myGroupsFolder);
724   }
725
726   // Update features content
727   int aRows = numberOfFolders();
728
729   // Remove extra sub-nodes
730   int aIndex = -1;
731   int aId = 0;
732   while (aId < myChildren.size()) {
733     ModuleBase_ITreeNode* aNode = myChildren.at(aId);
734     if (aNode->object().get()) {
735       aIndex = aDoc->index(aNode->object(), true);
736       if ((aIndex == -1) || (aId != (aIndex + aRows))) {
737         myChildren.removeAll(aNode);
738         delete aNode;
739         continue;
740       }
741     }
742     aId++;
743   }
744
745   std::string aGroup = ModelAPI_Feature::group();
746   int aSize = aDoc->size(aGroup, true);
747   FeaturePtr aFeature;
748   for (int i = 0; i < aSize; i++) {
749     ObjectPtr aObj = aDoc->object(aGroup, i, true);
750     aId = i + aRows; // Take into account existing folders
751     if (aId < myChildren.size()) {
752       if (myChildren.at(aId)->object() != aObj) {
753         ModuleBase_ITreeNode* aNode = createNode(aObj);
754         myChildren.insert(aId, aNode);
755       }
756     } else {
757       ModuleBase_ITreeNode* aNode = createNode(aObj);
758       myChildren.append(aNode);
759     }
760   }
761   // Update sub-folders
762   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
763     if (aNode->type() == PartSet_ObjectFolderNode::typeId())
764       aNode->update();
765   }
766 }
767
768 DocumentPtr PartSet_PartRootNode::document() const
769 {
770   ResultPartPtr aPartRes = getPartResult(myObject);
771   if (aPartRes.get())
772     return aPartRes->partDoc();
773   return DocumentPtr();
774 }
775
776 QVariant PartSet_PartRootNode::data(int theColumn, int theRole) const
777 {
778   switch (theColumn) {
779   case 1:
780     switch (theRole) {
781     case Qt::DisplayRole:
782       return QString(myObject->data()->name().c_str());
783     case Qt::DecorationRole:
784       return ModuleBase_IconFactory::get()->getIcon(myObject);
785     }
786   case 2:
787     if (theRole == Qt::DecorationRole)
788       if (isCurrentFeature(myObject))
789         return QIcon(":pictures/arrow.png");
790   }
791   return PartSet_TreeNode::data(theColumn, theRole);
792 }
793
794 Qt::ItemFlags PartSet_PartRootNode::flags(int theColumn) const
795 {
796   SessionPtr aSession = ModelAPI_Session::get();
797   DocumentPtr aActiveDoc = aSession->activeDocument();
798   if ((aActiveDoc == document()) || (myObject->document() == aActiveDoc))
799     return aEditingFlag;
800   return aDefaultFlag;
801 }
802
803 ModuleBase_ITreeNode* PartSet_PartRootNode::createNode(const ObjectPtr& theObj)
804 {
805   if (theObj->groupName() == ModelAPI_Folder::group())
806     return new PartSet_ObjectFolderNode(theObj, this);
807   return new PartSet_ObjectNode(theObj, this);
808 }
809
810 int PartSet_PartRootNode::numberOfFolders() const
811 {
812   int aNb = 3;
813   if (myFieldsFolder->childrenCount() > 0)
814     aNb++;
815   if (myGroupsFolder->childrenCount() > 0)
816     aNb++;
817   return aNb;
818 }
819
820 QTreeNodesList PartSet_PartRootNode::objectCreated(const QObjectPtrList& theObjects)
821 {
822   QTreeNodesList aResult = PartSet_FeatureFolderNode::objectCreated(theObjects);
823   if (!myFieldsFolder->childrenCount()) {
824     QTreeNodesList aList = myFieldsFolder->objectCreated(theObjects);
825     if (aList.size()) {
826       myChildren.insert(3, myFieldsFolder);
827       aResult.append(myFieldsFolder);
828       aResult.append(aList);
829     }
830   }
831   if (!myGroupsFolder->childrenCount()) {
832     QTreeNodesList aList = myGroupsFolder->objectCreated(theObjects);
833     if (aList.size()) {
834       myChildren.insert(myFieldsFolder->childrenCount()? 4 : 3, myGroupsFolder);
835       aResult.append(myGroupsFolder);
836       aResult.append(aList);
837     }
838   }
839   return aResult;
840 }
841
842 QTreeNodesList PartSet_PartRootNode::objectsDeleted(const DocumentPtr& theDoc,
843   const QString& theGroup)
844 {
845   QTreeNodesList aResult;
846   if (myFieldsFolder->childrenCount()) {
847     QTreeNodesList aList = myFieldsFolder->objectsDeleted(theDoc, theGroup);
848     if (aList.size()) {
849       aResult.append(aList);
850       if (!myFieldsFolder->childrenCount())
851         myChildren.removeAll(myFieldsFolder);
852     }
853   }
854   if (myGroupsFolder->childrenCount()) {
855     QTreeNodesList aList = myGroupsFolder->objectsDeleted(theDoc, theGroup);
856     if (aList.size()) {
857       aResult.append(aList);
858       if (!myGroupsFolder->childrenCount())
859         myChildren.removeAll(myGroupsFolder);
860     }
861   }
862   aResult.append(PartSet_FeatureFolderNode::objectsDeleted(theDoc, theGroup));
863   return aResult;
864 }
865
866 //////////////////////////////////////////////////////////////////////////////////
867 void PartSet_ObjectFolderNode::update()
868 {
869   int aFirst, aLast;
870   getFirstAndLastIndex(aFirst, aLast);
871   if ((aFirst == -1) || (aLast == -1)) {
872     deleteChildren();
873     return;
874   }
875
876   int aNbItems = aLast - aFirst + 1;
877   if (!aNbItems) {
878     deleteChildren();
879     return;
880   }
881
882   DocumentPtr aDoc = myObject->document();
883   // Delete obsolete nodes
884   int aId = 0;
885   while (aId < myChildren.size()) {
886     ModuleBase_ITreeNode* aNode = myChildren.at(aId);
887     if ((aFirst + aId) < aDoc->size(ModelAPI_Feature::group(), true)) {
888       if (aNode->object() != aDoc->object(ModelAPI_Feature::group(), aFirst + aId)) {
889         myChildren.removeAll(aNode);
890         delete aNode;
891         continue;
892       }
893     }
894     aId++;
895   }
896
897   // Add new nodes
898   ModuleBase_ITreeNode* aNode;
899   for (int i = 0; i < aNbItems; i++) {
900     ObjectPtr aObj = aDoc->object(ModelAPI_Feature::group(), aFirst + i);
901     if (i < myChildren.size()) {
902       if (aObj != myChildren.at(i)->object()) {
903         aNode = new PartSet_ObjectNode(aObj, this);
904         myChildren.insert(i, aNode);
905       }
906     } else {
907       aNode = new PartSet_ObjectNode(aObj, this);
908       myChildren.append(aNode);
909     }
910   }
911 }
912
913 QTreeNodesList PartSet_ObjectFolderNode::objectCreated(const QObjectPtrList& theObjects)
914 {
915   QTreeNodesList aResult;
916   int aFirst, aLast;
917   getFirstAndLastIndex(aFirst, aLast);
918   if ((aFirst == -1) || (aLast == -1)) {
919     return aResult;
920   }
921   int aNbItems = aLast - aFirst + 1;
922   if (!aNbItems) {
923     return aResult;
924   }
925   DocumentPtr aDoc = myObject->document();
926   // Add new nodes
927   ModuleBase_ITreeNode* aNode;
928   for (int i = 0; i < aNbItems; i++) {
929     ObjectPtr aObj = aDoc->object(ModelAPI_Feature::group(), aFirst + i);
930     if (i < myChildren.size()) {
931       if (aObj != myChildren.at(i)->object()) {
932         aNode = new PartSet_ObjectNode(aObj, this);
933         myChildren.insert(i, aNode);
934         aResult.append(aNode);
935       }
936     } else {
937       aNode = new PartSet_ObjectNode(aObj, this);
938       myChildren.append(aNode);
939       aResult.append(aNode);
940     }
941   }
942   return aResult;
943 }
944
945 QTreeNodesList PartSet_ObjectFolderNode::objectsDeleted(const DocumentPtr& theDoc,
946   const QString& theGroup)
947 {
948   QTreeNodesList aResult;
949   int aFirst, aLast;
950   getFirstAndLastIndex(aFirst, aLast);
951   if ((aFirst == -1) || (aLast == -1)) {
952     return aResult;
953   }
954   int aNbItems = aLast - aFirst + 1;
955   if (!aNbItems) {
956     return aResult;
957   }
958   DocumentPtr aDoc = myObject->document();
959   // Delete obsolete nodes
960   bool aRemoved = false;
961   int aId = 0;
962   while (aId < myChildren.size()) {
963     ModuleBase_ITreeNode* aNode = myChildren.at(aId);
964     if ((aFirst + aId) < aDoc->size(ModelAPI_Feature::group(), true)) {
965       if (aNode->object() != aDoc->object(ModelAPI_Feature::group(), aFirst + aId)) {
966         myChildren.removeAll(aNode);
967         delete aNode;
968         aRemoved = true;
969         continue;
970       }
971     }
972     aId++;
973   }
974   if (aRemoved) {
975     aResult.append(this);
976   }
977   return aResult;
978 }
979
980 FeaturePtr PartSet_ObjectFolderNode::getFeature(const std::string& theId) const
981 {
982   FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(myObject);
983   AttributeReferencePtr aFeatAttr = aFolder->data()->reference(theId);
984   if (aFeatAttr)
985     return ModelAPI_Feature::feature(aFeatAttr->value());
986   return FeaturePtr();
987 }
988
989 void PartSet_ObjectFolderNode::getFirstAndLastIndex(int& theFirst, int& theLast) const
990 {
991   DocumentPtr aDoc = myObject->document();
992   FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(myObject);
993
994   FeaturePtr aFirstFeatureInFolder = getFeature(ModelAPI_Folder::FIRST_FEATURE_ID());
995   if (!aFirstFeatureInFolder.get()) {
996     theFirst = -1;
997     return;
998   }
999   FeaturePtr aLastFeatureInFolder = getFeature(ModelAPI_Folder::LAST_FEATURE_ID());
1000   if (!aLastFeatureInFolder.get()) {
1001     theLast = -1;
1002     return;
1003   }
1004
1005   theFirst = aDoc->index(aFirstFeatureInFolder);
1006   theLast = aDoc->index(aLastFeatureInFolder);
1007 }
1008
1009
1010 //////////////////////////////////////////////////////////////////////////////////
1011 //PartSet_CompsolidNode::PartSet_CompsolidNode(const ObjectPtr& theObj,
1012 //  ModuleBase_ITreeNode* theParent) : PartSet_ObjectNode(theObj, theParent)
1013 //{
1014 //  update();
1015 //}
1016
1017 //void PartSet_CompsolidNode::update()
1018 //{
1019 //  ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(myObject);
1020 //  int aNb = aCompRes->numberOfSubs(true);
1021 //  ModuleBase_ITreeNode* aNode;
1022 //  ResultBodyPtr aBody;
1023 //  int i;
1024 //  for (i = 0; i < aNb; i++) {
1025 //    aBody = aCompRes->subResult(i, true);
1026 //    if (i < myChildren.size()) {
1027 //      aNode = myChildren.at(i);
1028 //      if (aNode->object() != aBody) {
1029 //        ((PartSet_ObjectNode*)aNode)->setObject(aBody);
1030 //      }
1031 //    } else {
1032 //      aNode = new PartSet_ObjectNode(aBody, this);
1033 //      myChildren.append(aNode);
1034 //    }
1035 //  }
1036 //  // Delete extra objects
1037 //  while (myChildren.size() > aNb) {
1038 //    aNode = myChildren.takeLast();
1039 //    delete aNode;
1040 //  }
1041 //}
1042 //
1043 //QTreeNodesList PartSet_CompsolidNode::objectCreated(const QObjectPtrList& theObjects)
1044 //{
1045 //  QTreeNodesList aResult;
1046 //
1047 //  ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(myObject);
1048 //  int aNb = aCompRes->numberOfSubs(true);
1049 //  ModuleBase_ITreeNode* aNode;
1050 //  ResultBodyPtr aBody;
1051 //  int i;
1052 //  for (i = 0; i < aNb; i++) {
1053 //    aBody = aCompRes->subResult(i, true);
1054 //    if (i < myChildren.size()) {
1055 //      aNode = myChildren.at(i);
1056 //      if (aNode->object() != aBody) {
1057 //        ((PartSet_ObjectNode*)aNode)->setObject(aBody);
1058 //        aResult.append(aNode);
1059 //      }
1060 //    } else {
1061 //      aNode = new PartSet_ObjectNode(aBody, this);
1062 //      myChildren.append(aNode);
1063 //      aResult.append(aNode);
1064 //    }
1065 //  }
1066 //  return aResult;
1067 //}
1068 //
1069 //QTreeNodesList PartSet_CompsolidNode::objectsDeleted(const DocumentPtr& theDoc, const QString& theGroup)
1070 //{
1071 //  QTreeNodesList aResult;
1072 //  ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(myObject);
1073 //  int aNb = aCompRes->numberOfSubs(true);
1074 //  ModuleBase_ITreeNode* aNode;
1075 //  // Delete extra objects
1076 //  bool isDeleted = false;
1077 //  while (myChildren.size() > aNb) {
1078 //    aNode = myChildren.takeLast();
1079 //    delete aNode;
1080 //    isDeleted = true;
1081 //  }
1082 //  if (isDeleted)
1083 //    aResult.append(this);
1084 //  return aResult;
1085 //}