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