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