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