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