Salome HOME
Issue #2628: Update indexes of data tree
[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     if (document().get()) {
445       FeaturePtr aFeature = document()->currentFeature(true);
446       if (!aFeature.get()) { // There is no current feature
447         ModuleBase_ITreeNode* aLastFolder = 0;
448         foreach(ModuleBase_ITreeNode* aNode, parent()->children()) {
449           if (aNode->type() == PartSet_FolderNode::typeId())
450             aLastFolder = aNode;
451           else
452             break;
453         }
454         if (aLastFolder == this)
455           return QIcon(":pictures/arrow.png");
456       }
457     }
458   }
459   return PartSet_TreeNode::data(theColumn, theRole);
460 }
461
462 Qt::ItemFlags PartSet_FolderNode::flags(int theColumn) const
463 {
464   SessionPtr aSession = ModelAPI_Session::get();
465   DocumentPtr aActiveDoc = aSession->activeDocument();
466   if (theColumn == 1) {
467     if (document() == aActiveDoc)
468       return aEditingFlag;
469   }
470   return aDefaultFlag;
471 }
472
473 ModuleBase_ITreeNode* PartSet_FolderNode::createNode(const ObjectPtr& theObj)
474 {
475   //ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(theObj);
476   //if (aCompRes.get())
477   //  return new PartSet_CompsolidNode(theObj, this);
478   return new PartSet_ObjectNode(theObj, this);
479 }
480
481 void PartSet_FolderNode::update()
482 {
483   DocumentPtr aDoc = document();
484   if (!aDoc.get())
485     return;
486
487   // Remove extra sub-nodes
488   int aIndex;
489   int aId = 0;
490   while (aId < myChildren.size()) {
491     ModuleBase_ITreeNode* aNode = myChildren.at(aId);
492     aIndex = aDoc->index(aNode->object(), true);
493     if ((aIndex == -1) || (aId != aIndex)) {
494       myChildren.removeAll(aNode);
495       delete aNode;
496     } else
497       aId++;
498   }
499
500   // Add new nodes
501   std::string aGroup = groupName();
502   int aSize = aDoc->size(aGroup, true);
503   for (int i = 0; i < aSize; i++) {
504     ObjectPtr aObj = aDoc->object(aGroup, i, true);
505     if (i < myChildren.size()) {
506       if (myChildren.at(i)->object() != aObj) {
507         ModuleBase_ITreeNode* aNode = createNode(aObj);
508         myChildren.insert(i, aNode);
509       }
510     } else {
511       ModuleBase_ITreeNode* aNode = createNode(aObj);
512       myChildren.append(aNode);
513     }
514   }
515
516   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
517     aNode->update();
518   }
519 }
520
521 std::string PartSet_FolderNode::groupName() const
522 {
523   switch (myType) {
524   case ParametersFolder:
525     return ModelAPI_ResultParameter::group();
526   case ConstructionFolder:
527     return ModelAPI_ResultConstruction::group();
528   case PartsFolder:
529     return ModelAPI_ResultPart::group();
530   case ResultsFolder:
531     return ModelAPI_ResultBody::group();
532   case FieldsFolder:
533     return ModelAPI_ResultField::group();
534   case GroupsFolder:
535     return ModelAPI_ResultGroup::group();
536   }
537   return "";
538 }
539
540 QTreeNodesList PartSet_FolderNode::objectCreated(const QObjectPtrList& theObjects)
541 {
542   QTreeNodesList aResult;
543   std::string aName = groupName();
544   DocumentPtr aDoc = document();
545   int aIdx = -1;
546   QMap<int, ModuleBase_ITreeNode*> aNewNodes;
547   foreach(ObjectPtr aObj, theObjects) {
548     if ((aObj->document() == aDoc) && (aObj->groupName() == aName)) {
549       aIdx = aDoc->index(aObj, true);
550       if (aIdx != -1) {
551         bool aHasObject = (aIdx < myChildren.size()) && (myChildren.at(aIdx)->object() == aObj);
552         if (!aHasObject) {
553           ModuleBase_ITreeNode* aNode = createNode(aObj);
554           aNewNodes[aIdx] = aNode;
555           aResult.append(aNode);
556           aNode->update();
557         }
558       }
559     }
560   }
561   // Add nodes in correct order
562   int i;
563   for (i = 0; i < myChildren.size(); i++) {
564     if (aNewNodes.contains(i)) {
565       myChildren.insert(i, aNewNodes[i]);
566       aNewNodes.remove(i);
567     }
568   }
569   while (aNewNodes.size()) {
570     i = myChildren.size();
571     myChildren.append(aNewNodes[i]);
572     aNewNodes.remove(i);
573   }
574   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
575     aResult.append(aNode->objectCreated(theObjects));
576   }
577   return aResult;
578 }
579
580 QTreeNodesList PartSet_FolderNode::objectsDeleted(const DocumentPtr& theDoc,
581   const QString& theGroup)
582 {
583   DocumentPtr aDoc = document();
584   QTreeNodesList aResult;
585   if ((theGroup.toStdString() == groupName()) && (theDoc == aDoc)) {
586     QTreeNodesList aDelList;
587     int aIndex;
588     int aId = 0;
589     bool aRemoved = false;
590     bool aToSort = false;
591     while (aId < myChildren.size()) {
592       ModuleBase_ITreeNode* aNode = myChildren.at(aId);
593       aIndex = aDoc->index(aNode->object(), true);
594       aToSort |= ((aIndex != -1) && (aId != aIndex));
595       if (aIndex == -1) {
596         myChildren.removeAll(aNode);
597         delete aNode;
598         aRemoved = true;
599       }
600       else
601         aId++;
602     }
603     if (aRemoved)
604       aResult.append(this);
605     if (aToSort)
606       sortChildren();
607     foreach(ModuleBase_ITreeNode* aNode, myChildren) {
608       aResult.append(aNode->objectsDeleted(theDoc, theGroup));
609     }
610   }
611   return aResult;
612 }
613
614 //////////////////////////////////////////////////////////////////////////////////
615 QTreeNodesList PartSet_FeatureFolderNode::objectCreated(const QObjectPtrList& theObjects)
616 {
617   QTreeNodesList aResult;
618   // Process the root sub-objects
619   DocumentPtr aDoc = document();
620   int aIdx = -1;
621   int aNb = numberOfFolders();
622   QMap<int, ModuleBase_ITreeNode*> aNewNodes;
623   foreach(ObjectPtr aObj, theObjects) {
624     if (aDoc == aObj->document()) {
625       if ((aObj->groupName() == ModelAPI_Feature::group()) ||
626         (aObj->groupName() == ModelAPI_Folder::group())){
627         aIdx = aDoc->index(aObj, true);
628         if (aIdx != -1) {
629           ModuleBase_ITreeNode* aNode = createNode(aObj);
630           aIdx += aNb;
631           bool aHasObject = (aIdx < myChildren.size()) && (myChildren.at(aIdx)->object() == aObj);
632           if (!aHasObject) {
633             aNewNodes[aIdx] = aNode;
634             aResult.append(aNode);
635             aNode->update();
636           }
637         }
638       }
639     }
640   }
641   // To add in correct order
642   int i;
643   for (i = 0; i < myChildren.size(); i++) {
644     if (aNewNodes.contains(i)) {
645       myChildren.insert(i, aNewNodes[i]);
646       aNewNodes.remove(i);
647     }
648   }
649   while (aNewNodes.size()) {
650     i = myChildren.size();
651     myChildren.append(aNewNodes[i]);
652     aNewNodes.remove(i);
653   }
654
655   // Update sub-folders
656   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
657     aResult.append(aNode->objectCreated(theObjects));
658   }
659   return aResult;
660 }
661
662 QTreeNodesList PartSet_FeatureFolderNode::objectsDeleted(const DocumentPtr& theDoc,
663   const QString& theGroup)
664 {
665   QTreeNodesList aResult;
666
667   // Process sub-folders
668   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
669     if (aNode->childrenCount() > 0) { // aFolder node
670       QTreeNodesList aList = aNode->objectsDeleted(theDoc, theGroup);
671       if (aList.size() > 0)
672         aResult.append(aList);
673     }
674   }
675
676   // Process root
677   DocumentPtr aDoc = document();
678   int aNb = numberOfFolders();
679   bool isGroup = ((theGroup.toStdString() == ModelAPI_Feature::group()) ||
680     (theGroup.toStdString() == ModelAPI_Folder::group()));
681   if ((theDoc == aDoc) && isGroup) {
682     int aIndex;
683     int aId = 0;
684     bool aRemoved = false;
685     bool aToSort = false;
686     while (aId < myChildren.size()) {
687       ModuleBase_ITreeNode* aNode = myChildren.at(aId);
688       if (aNode->object().get()) {
689         aIndex = aDoc->index(aNode->object(), true);
690         aToSort |= ((aIndex != -1) && (aId != (aIndex + aNb)));
691         if (aIndex == -1) {
692           myChildren.removeAll(aNode);
693           delete aNode;
694           aRemoved = true;
695           continue;
696         }
697       }
698       aId++;
699     }
700     if (aRemoved)
701       aResult.append(this);
702     if (aToSort)
703       sortChildren();
704   }
705   return aResult;
706 }
707
708 ModuleBase_ITreeNode* PartSet_FeatureFolderNode::findParent(const DocumentPtr& theDoc,
709   QString theGroup)
710 {
711   ModuleBase_ITreeNode* aResult = 0;
712   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
713     aResult = aNode->findParent(theDoc, theGroup);
714     if (aResult) {
715       return aResult;
716     }
717   }
718   bool isGroup = ((theGroup.toStdString() == ModelAPI_Feature::group()) ||
719     (theGroup.toStdString() == ModelAPI_Folder::group()));
720   if ((theDoc == document()) && isGroup)
721     return this;
722   return 0;
723 }
724
725
726 //////////////////////////////////////////////////////////////////////////////////
727 PartSet_RootNode::PartSet_RootNode() : PartSet_FeatureFolderNode(0), myWorkshop(0)
728 {
729   SessionPtr aSession = ModelAPI_Session::get();
730   DocumentPtr aDoc = aSession->moduleDocument();
731
732   myParamsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ParametersFolder);
733   myConstrFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ConstructionFolder);
734   myPartsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::PartsFolder);
735
736   myChildren.append(myParamsFolder);
737   myChildren.append(myConstrFolder);
738   myChildren.append(myPartsFolder);
739
740   update();
741 }
742
743
744 void PartSet_RootNode::update()
745 {
746   myParamsFolder->update();
747   myConstrFolder->update();
748   myPartsFolder->update();
749
750   // Update features content
751   DocumentPtr aDoc = document();
752   int aNb = numberOfFolders();
753
754   // Remove extra sub-nodes
755   int aIndex;
756   int aId = 0;
757   while (aId < myChildren.size()) {
758     ModuleBase_ITreeNode* aNode = myChildren.at(aId);
759     if (aNode->object().get()) {
760       aIndex = aDoc->index(aNode->object(), true);
761       if ((aIndex == -1) || (aId != (aIndex + aNb))) {
762         myChildren.removeAll(aNode);
763         delete aNode;
764         continue;
765       }
766     }
767     aId++;
768   }
769
770   // Add new nodes
771   std::string aGroup = ModelAPI_Feature::group();
772   int aSize = aDoc->size(aGroup, true);
773   FeaturePtr aFeature;
774   for (int i = 0; i < aSize; i++) {
775     ObjectPtr aObj = aDoc->object(aGroup, i, true);
776     aId = i + aNb; // Take into account existing folders
777     if (aId < myChildren.size()) {
778       if (myChildren.at(aId)->object() != aObj) {
779         ModuleBase_ITreeNode* aNode = createNode(aObj);
780         myChildren.insert(aId, aNode);
781       }
782     } else {
783       ModuleBase_ITreeNode* aNode = createNode(aObj);
784       myChildren.append(aNode);
785     }
786   }
787   // Update sub-folders
788   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
789     if ((aNode->type() == PartSet_ObjectFolderNode::typeId()) ||
790       (aNode->type() == PartSet_PartRootNode::typeId()))
791       aNode->update();
792   }
793 }
794
795 DocumentPtr PartSet_RootNode::document() const
796 {
797   return ModelAPI_Session::get()->moduleDocument();
798 }
799
800 ModuleBase_ITreeNode* PartSet_RootNode::createNode(const ObjectPtr& theObj)
801 {
802   if (theObj->groupName() == ModelAPI_Folder::group())
803     return new PartSet_ObjectFolderNode(theObj, this);
804
805   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObj);
806   if (aFeature->getKind() == PartSetPlugin_Part::ID())
807     return new PartSet_PartRootNode(theObj, this);
808
809   return new PartSet_ObjectNode(theObj, this);
810 }
811
812 //////////////////////////////////////////////////////////////////////////////////
813 PartSet_PartRootNode::PartSet_PartRootNode(const ObjectPtr& theObj, ModuleBase_ITreeNode* theParent)
814   : PartSet_FeatureFolderNode(theParent), myObject(theObj)
815 {
816   myParamsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ParametersFolder);
817   myConstrFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ConstructionFolder);
818   myResultsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::ResultsFolder);
819   myFieldsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::FieldsFolder);
820   myGroupsFolder = new PartSet_FolderNode(this, PartSet_FolderNode::GroupsFolder);
821
822   myChildren.append(myParamsFolder);
823   myChildren.append(myConstrFolder);
824   myChildren.append(myResultsFolder);
825
826   update();
827 }
828
829 void PartSet_PartRootNode::deleteChildren()
830 {
831   if (!myFieldsFolder->childrenCount()) {
832     delete myFieldsFolder;
833   }
834   if (!myGroupsFolder->childrenCount()) {
835     delete myGroupsFolder;
836   }
837   PartSet_FeatureFolderNode::deleteChildren();
838 }
839
840
841 void PartSet_PartRootNode::update()
842 {
843   DocumentPtr aDoc = document();
844   if (!aDoc.get())
845     return;
846
847   myParamsFolder->update();
848   myConstrFolder->update();
849   myResultsFolder->update();
850   myFieldsFolder->update();
851   myGroupsFolder->update();
852
853   bool aHasFields = myFieldsFolder->childrenCount() > 0;
854   bool aHasGroups = myGroupsFolder->childrenCount() > 0;
855   if (aHasFields && (!myChildren.contains(myFieldsFolder))) {
856     myChildren.insert(3, myFieldsFolder);
857   }
858   if (aHasGroups && (!myChildren.contains(myGroupsFolder))) {
859     myChildren.insert(aHasFields ? 4 : 3, myGroupsFolder);
860   }
861
862   // Update features content
863   int aRows = numberOfFolders();
864
865   // Remove extra sub-nodes
866   int aIndex = -1;
867   int aId = aRows;
868   while (aId < myChildren.size()) {
869     ModuleBase_ITreeNode* aNode = myChildren.at(aId);
870     if (aNode->object().get()) {
871       aIndex = aDoc->index(aNode->object(), true);
872       if ((aIndex == -1) || (aId != (aIndex + aRows))) {
873         myChildren.removeAll(aNode);
874         delete aNode;
875         continue;
876       }
877     }
878     aId++;
879   }
880
881   std::string aGroup = ModelAPI_Feature::group();
882   int aSize = aDoc->size(aGroup, true);
883   FeaturePtr aFeature;
884   for (int i = 0; i < aSize; i++) {
885     ObjectPtr aObj = aDoc->object(aGroup, i, true);
886     aId = i + aRows; // Take into account existing folders
887     if (aId < myChildren.size()) {
888       if (myChildren.at(aId)->object() != aObj) {
889         ModuleBase_ITreeNode* aNode = createNode(aObj);
890         myChildren.insert(aId, aNode);
891       }
892     } else {
893       ModuleBase_ITreeNode* aNode = createNode(aObj);
894       myChildren.append(aNode);
895     }
896   }
897   // Update sub-folders
898   foreach(ModuleBase_ITreeNode* aNode, myChildren) {
899     if (aNode->type() == PartSet_ObjectFolderNode::typeId())
900       aNode->update();
901   }
902 }
903
904 DocumentPtr PartSet_PartRootNode::document() const
905 {
906   ResultPartPtr aPartRes = getPartResult(myObject);
907   if (aPartRes.get())
908     return aPartRes->partDoc();
909   return DocumentPtr();
910 }
911
912 QVariant PartSet_PartRootNode::data(int theColumn, int theRole) const
913 {
914   switch (theColumn) {
915   case 1:
916     switch (theRole) {
917     case Qt::DisplayRole:
918     {
919       ResultPartPtr aPartRes = getPartResult(myObject);
920       if (aPartRes.get()) {
921         if (aPartRes->partDoc().get() == NULL)
922           return QString(myObject->data()->name().c_str()) + " (Not loaded)";
923       }
924       return QString(myObject->data()->name().c_str());
925     }
926     case Qt::DecorationRole:
927       return ModuleBase_IconFactory::get()->getIcon(myObject);
928     }
929   }
930   return PartSet_TreeNode::data(theColumn, theRole);
931 }
932
933 Qt::ItemFlags PartSet_PartRootNode::flags(int theColumn) const
934 {
935   SessionPtr aSession = ModelAPI_Session::get();
936   DocumentPtr aActiveDoc = aSession->activeDocument();
937   if ((aActiveDoc == document()) || (myObject->document() == aActiveDoc))
938     return aEditingFlag;
939   return aDefaultFlag;
940 }
941
942 ModuleBase_ITreeNode* PartSet_PartRootNode::createNode(const ObjectPtr& theObj)
943 {
944   if (theObj->groupName() == ModelAPI_Folder::group())
945     return new PartSet_ObjectFolderNode(theObj, this);
946   return new PartSet_ObjectNode(theObj, this);
947 }
948
949 int PartSet_PartRootNode::numberOfFolders() const
950 {
951   int aNb = 3;
952   if (myFieldsFolder->childrenCount() > 0)
953     aNb++;
954   if (myGroupsFolder->childrenCount() > 0)
955     aNb++;
956   return aNb;
957 }
958
959 QTreeNodesList PartSet_PartRootNode::objectCreated(const QObjectPtrList& theObjects)
960 {
961   QTreeNodesList aResult = PartSet_FeatureFolderNode::objectCreated(theObjects);
962   if (!myFieldsFolder->childrenCount()) {
963     QTreeNodesList aList = myFieldsFolder->objectCreated(theObjects);
964     if (aList.size()) {
965       myChildren.insert(3, myFieldsFolder);
966       aResult.append(myFieldsFolder);
967       aResult.append(aList);
968     }
969   }
970   if (!myGroupsFolder->childrenCount()) {
971     QTreeNodesList aList = myGroupsFolder->objectCreated(theObjects);
972     if (aList.size()) {
973       myChildren.insert(myFieldsFolder->childrenCount()? 4 : 3, myGroupsFolder);
974       aResult.append(myGroupsFolder);
975       aResult.append(aList);
976     }
977   }
978   return aResult;
979 }
980
981 QTreeNodesList PartSet_PartRootNode::objectsDeleted(const DocumentPtr& theDoc,
982   const QString& theGroup)
983 {
984   QTreeNodesList aResult;
985   if (myFieldsFolder->childrenCount()) {
986     QTreeNodesList aList = myFieldsFolder->objectsDeleted(theDoc, theGroup);
987     if (aList.size()) {
988       aResult.append(aList);
989       if (!myFieldsFolder->childrenCount())
990         myChildren.removeAll(myFieldsFolder);
991     }
992   }
993   if (myGroupsFolder->childrenCount()) {
994     QTreeNodesList aList = myGroupsFolder->objectsDeleted(theDoc, theGroup);
995     if (aList.size()) {
996       aResult.append(aList);
997       if (!myGroupsFolder->childrenCount())
998         myChildren.removeAll(myGroupsFolder);
999     }
1000   }
1001   aResult.append(PartSet_FeatureFolderNode::objectsDeleted(theDoc, theGroup));
1002   return aResult;
1003 }
1004
1005 //////////////////////////////////////////////////////////////////////////////////
1006 void PartSet_ObjectFolderNode::update()
1007 {
1008   int aFirst, aLast;
1009   getFirstAndLastIndex(aFirst, aLast);
1010   if ((aFirst == -1) || (aLast == -1)) {
1011     deleteChildren();
1012     return;
1013   }
1014
1015   int aNbItems = aLast - aFirst + 1;
1016   if (!aNbItems) {
1017     deleteChildren();
1018     return;
1019   }
1020
1021   DocumentPtr aDoc = myObject->document();
1022   if (aNbItems < myChildren.size()) {
1023     // Delete obsolete nodes
1024     int aId = 0;
1025     int aNbOfFeatures = aDoc->size(ModelAPI_Feature::group(), true);
1026     while (aId < myChildren.size()) {
1027       ModuleBase_ITreeNode* aNode = myChildren.at(aId);
1028       if ((aFirst + aId) < aNbOfFeatures) {
1029         if (aNode->object() != aDoc->object(ModelAPI_Feature::group(), aFirst + aId)) {
1030           myChildren.removeAll(aNode);
1031           delete aNode;
1032           continue;
1033         }
1034       }
1035       else {
1036         myChildren.removeAll(aNode);
1037         delete aNode;
1038         continue;
1039       }
1040       aId++;
1041     }
1042   }
1043   if (aNbItems > myChildren.size()) {
1044     // Add new nodes
1045     ModuleBase_ITreeNode* aNode;
1046     for (int i = 0; i < aNbItems; i++) {
1047       ObjectPtr aObj = aDoc->object(ModelAPI_Feature::group(), aFirst + i);
1048       if (i < myChildren.size()) {
1049         if (aObj != myChildren.at(i)->object()) {
1050           aNode = new PartSet_ObjectNode(aObj, this);
1051           myChildren.insert(i, aNode);
1052         }
1053       }
1054       else {
1055         aNode = new PartSet_ObjectNode(aObj, this);
1056         myChildren.append(aNode);
1057       }
1058     }
1059   }
1060 }
1061
1062 QTreeNodesList PartSet_ObjectFolderNode::objectCreated(const QObjectPtrList& theObjects)
1063 {
1064   QTreeNodesList aResult;
1065   int aFirst, aLast;
1066   getFirstAndLastIndex(aFirst, aLast);
1067   if ((aFirst == -1) || (aLast == -1)) {
1068     return aResult;
1069   }
1070   int aNbItems = aLast - aFirst + 1;
1071   if (!aNbItems) {
1072     return aResult;
1073   }
1074   DocumentPtr aDoc = myObject->document();
1075   // Add new nodes
1076   ModuleBase_ITreeNode* aNode;
1077   for (int i = 0; i < aNbItems; i++) {
1078     ObjectPtr aObj = aDoc->object(ModelAPI_Feature::group(), aFirst + i);
1079     if (i < myChildren.size()) {
1080       if (aObj != myChildren.at(i)->object()) {
1081         aNode = new PartSet_ObjectNode(aObj, this);
1082         myChildren.insert(i, aNode);
1083         aResult.append(aNode);
1084       }
1085     } else {
1086       aNode = new PartSet_ObjectNode(aObj, this);
1087       myChildren.append(aNode);
1088       aResult.append(aNode);
1089     }
1090   }
1091   return aResult;
1092 }
1093
1094 QTreeNodesList PartSet_ObjectFolderNode::objectsDeleted(const DocumentPtr& theDoc,
1095   const QString& theGroup)
1096 {
1097   QTreeNodesList aResult;
1098   int aFirst, aLast;
1099   getFirstAndLastIndex(aFirst, aLast);
1100   if ((aFirst == -1) || (aLast == -1)) {
1101     return aResult;
1102   }
1103   int aNbItems = aLast - aFirst + 1;
1104   if (!aNbItems) {
1105     return aResult;
1106   }
1107   if (aNbItems >= myChildren.size()) // Nothing was deleted here
1108     return aResult;
1109
1110   DocumentPtr aDoc = myObject->document();
1111   // Delete obsolete nodes
1112   bool aRemoved = false;
1113   int aId = 0;
1114   int aNbOfFeatures = aDoc->size(ModelAPI_Feature::group(), true);
1115   while (aId < myChildren.size()) {
1116     ModuleBase_ITreeNode* aNode = myChildren.at(aId);
1117     if ((aFirst + aId) < aNbOfFeatures) {
1118       if (aNode->object() != aDoc->object(ModelAPI_Feature::group(), aFirst + aId)) {
1119         myChildren.removeAll(aNode);
1120         delete aNode;
1121         aRemoved = true;
1122         continue;
1123       }
1124     }
1125     else {
1126       myChildren.removeAll(aNode);
1127       delete aNode;
1128       aRemoved = true;
1129       continue;
1130     }
1131     aId++;
1132   }
1133   if (aRemoved) {
1134     aResult.append(this);
1135   }
1136   return aResult;
1137 }
1138
1139 FeaturePtr PartSet_ObjectFolderNode::getFeature(const std::string& theId) const
1140 {
1141   FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(myObject);
1142   AttributeReferencePtr aFeatAttr = aFolder->data()->reference(theId);
1143   if (aFeatAttr)
1144     return ModelAPI_Feature::feature(aFeatAttr->value());
1145   return FeaturePtr();
1146 }
1147
1148 void PartSet_ObjectFolderNode::getFirstAndLastIndex(int& theFirst, int& theLast) const
1149 {
1150   DocumentPtr aDoc = myObject->document();
1151   FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(myObject);
1152
1153   FeaturePtr aFirstFeatureInFolder = getFeature(ModelAPI_Folder::FIRST_FEATURE_ID());
1154   if (!aFirstFeatureInFolder.get()) {
1155     theFirst = -1;
1156     return;
1157   }
1158   FeaturePtr aLastFeatureInFolder = getFeature(ModelAPI_Folder::LAST_FEATURE_ID());
1159   if (!aLastFeatureInFolder.get()) {
1160     theLast = -1;
1161     return;
1162   }
1163
1164   theFirst = aDoc->index(aFirstFeatureInFolder);
1165   theLast = aDoc->index(aLastFeatureInFolder);
1166 }
1167
1168
1169 //////////////////////////////////////////////////////////////////////////////////
1170 QVariant PartSet_StepNode::data(int theColumn, int theRole) const
1171 {
1172   if ((theColumn == 1) && (theRole == Qt::DisplayRole)) {
1173     ModelAPI_ResultField::ModelAPI_FieldStep* aStep =
1174       dynamic_cast<ModelAPI_ResultField::ModelAPI_FieldStep*>(myEntity);
1175
1176     return "Step " + QString::number(aStep->id() + 1) + " " +
1177       aStep->field()->textLine(aStep->id()).c_str();
1178   }
1179   return PartSet_TreeNode::data(theColumn, theRole);
1180 }