Salome HOME
Issue #761 - Check and error for unique parameter name -- Code improvements
[modules/shaper.git] / src / XGUI / XGUI_Tools.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 #include "XGUI_Tools.h"
4
5 #include <TopoDS_Shape.hxx>
6 #include <ModelAPI_Object.h>
7 #include <ModelAPI_Result.h>
8 #include <ModelAPI_ResultParameter.h>
9 #include <ModelAPI_Feature.h>
10 #include <ModelAPI_Session.h>
11 #include <ModelAPI_Document.h>
12 #include <ModelAPI_ResultPart.h>
13 #include <ModelAPI_CompositeFeature.h>
14 #include <ModelAPI_Tools.h>
15
16 #include <GeomAPI_Shape.h>
17
18 #include <QDir>
19 #include <QMessageBox>
20
21 #include <iostream>
22 #include <sstream>
23
24 namespace XGUI_Tools {
25 //******************************************************************
26 QString dir(const QString& path, bool isAbs)
27 {
28   QDir aDir = QFileInfo(path).dir();
29   QString dirPath = isAbs ? aDir.absolutePath() : aDir.path();
30   if (dirPath == QString("."))
31     dirPath = QString();
32   return dirPath;
33 }
34
35 //******************************************************************
36 QString file(const QString& path, bool withExt)
37 {
38   QString fPath = path;
39   while (!fPath.isEmpty() && (fPath[fPath.length() - 1] == '\\' || fPath[fPath.length() - 1] == '/'))
40     fPath.remove(fPath.length() - 1, 1);
41
42   if (withExt)
43     return QFileInfo(fPath).fileName();
44   else
45     return QFileInfo(fPath).completeBaseName();
46 }
47
48 //******************************************************************
49 QString addSlash(const QString& path)
50 {
51   QString res = path;
52   if (!res.isEmpty() && res.at(res.length() - 1) != QChar('/')
53       && res.at(res.length() - 1) != QChar('\\'))
54     res += QDir::separator();
55   return res;
56 }
57
58 //******************************************************************
59 bool isModelObject(FeaturePtr theFeature)
60 {
61   return theFeature && !theFeature->data();
62 }
63
64 //******************************************************************
65 std::string featureInfo(FeaturePtr theFeature)
66 {
67   std::ostringstream aStream;
68   if (theFeature)
69     aStream << theFeature.get() << " " << theFeature->getKind();
70   return QString(aStream.str().c_str()).toStdString();
71 }
72
73 //******************************************************************
74 /*FeaturePtr realFeature(const FeaturePtr theFeature)
75  {
76  if (theFeature->data()) {
77  return theFeature;
78  } else {
79  ObjectPtr aObject = std::dynamic_pointer_cast<ModelAPI_Object>(theFeature);
80  return aObject->featureRef();
81  }
82  }*/
83
84 //******************************************************************
85 bool canRemoveOrRename(QWidget* theParent, const QObjectPtrList& theObjects)
86 {
87   bool aResult = true;
88   QString aNotActivatedNames;
89   if (!XGUI_Tools::allDocumentsActivated(aNotActivatedNames)) {
90     DocumentPtr aModuleDoc = ModelAPI_Session::get()->moduleDocument();
91     bool aFoundPartSetObject = false;
92     foreach (ObjectPtr aObj, theObjects) {
93       if (aObj->groupName() == ModelAPI_ResultPart::group())
94         continue;
95       aFoundPartSetObject = aObj->document() == aModuleDoc;
96     }
97     if (aFoundPartSetObject) {
98       QMessageBox::StandardButton aRes = QMessageBox::warning(theParent, QObject::tr("Warning"),
99                QObject::tr("Selected objects can be used in Part documents which are not loaded: \
100 %1. Whould you like to continue?").arg(aNotActivatedNames),
101                QMessageBox::No | QMessageBox::Yes, QMessageBox::No);
102       aResult = aRes == QMessageBox::Yes;
103     }
104   }
105   return aResult;
106 }
107
108 //******************************************************************
109 bool canRename(QWidget* theParent, const ObjectPtr& theObject, const QString& theName)
110 {
111   if (std::dynamic_pointer_cast<ModelAPI_ResultParameter>(theObject).get()) {
112     double aValue;
113     ResultParameterPtr aParam;
114     if (ModelAPI_Tools::findVariable(theObject->document(), qPrintable(theName), aValue, aParam)) {
115       QMessageBox::information(theParent, QObject::tr("Rename parameter"),
116           QString(QObject::tr("Selected parameter can not be renamed to: %1. \
117 There is a parameter with the same name. Its value is: %2.")).arg(qPrintable(theName)).arg(aValue));
118       return false;
119     }
120   }
121
122   return true;
123 }
124
125 //******************************************************************
126 bool allDocumentsActivated(QString& theNotActivatedNames)
127 {
128   bool anAllPartActivated = true;
129   QStringList aRefNames;
130
131   DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
132   int aSize = aRootDoc->size(ModelAPI_ResultPart::group());
133   for (int i = 0; i < aSize; i++) {
134     ObjectPtr aObject = aRootDoc->object(ModelAPI_ResultPart::group(), i);
135     ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObject);
136     if (!aPart->isActivated()) {
137       anAllPartActivated = false;
138       aRefNames.append(aObject->data()->name().c_str());
139     }
140   }
141   theNotActivatedNames = aRefNames.join(", ");
142   return anAllPartActivated;
143 }
144
145 //**************************************************************
146 void refsToFeatureInFeatureDocument(const ObjectPtr& theObject, std::set<FeaturePtr>& theRefFeatures)
147 {
148   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
149   if (aFeature.get()) {
150     DocumentPtr aFeatureDoc = aFeature->document();
151     // 1. find references in the current document
152     aFeatureDoc->refsToFeature(aFeature, theRefFeatures, false);
153   }
154 }
155
156 //**************************************************************
157 bool isSubOfComposite(const ObjectPtr& theObject, const FeaturePtr& theFeature)
158 {
159   bool isSub = false;
160   CompositeFeaturePtr aComposite = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
161   if (aComposite.get()) {
162     isSub = aComposite->isSub(theObject);
163     // the recursive is possible, the parameters are sketch circle and extrusion cut. They are
164     // separated by composite sketch feature
165     if (!isSub) {
166       int aNbSubs = aComposite->numberOfSubs();
167       for (int aSub = 0; aSub < aNbSubs && !isSub; aSub++) {
168         isSub = isSubOfComposite(theObject, aComposite->subFeature(aSub));
169       }
170     }
171   }
172   return isSub;
173 }
174
175 //**************************************************************
176 void refsToFeatureInAllDocuments(const ObjectPtr& theSourceObject, const ObjectPtr& theObject,
177                                  std::set<FeaturePtr>& theRefFeatures)
178 {
179   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
180   if (!aFeature.get())
181     return;
182
183   // 1. find references in the current document
184   std::set<FeaturePtr> aRefFeatures;
185   refsToFeatureInFeatureDocument(theObject, aRefFeatures);
186   std::set<FeaturePtr>::const_iterator anIt = aRefFeatures.begin(),
187                                        aLast = aRefFeatures.end();
188   for (; anIt != aLast; anIt++) {
189     if (!isSubOfComposite(theSourceObject, *anIt))
190       theRefFeatures.insert(*anIt);
191   }
192
193   // 2. find references in all documents if the document of the feature is
194   // "PartSet". Features of this document can be used in all other documents
195   DocumentPtr aFeatureDoc = aFeature->document();
196
197   SessionPtr aMgr = ModelAPI_Session::get();
198   DocumentPtr aModuleDoc = aMgr->moduleDocument();
199   if (aFeatureDoc == aModuleDoc) {
200     // the feature and results of the feature should be found in references
201     std::list<ObjectPtr> aObjects;
202     aObjects.push_back(aFeature);
203     typedef std::list<std::shared_ptr<ModelAPI_Result> > ResultsList;
204     const ResultsList& aResults = aFeature->results();
205     ResultsList::const_iterator aRIter = aResults.begin();
206     for (; aRIter != aResults.cend(); aRIter++) {
207       ResultPtr aRes = *aRIter;
208       if (aRes.get())
209         aObjects.push_back(aRes);
210     }
211     // get all opened documents; found features in the documents;
212     // get a list of objects where a feature refers;
213     // search in these objects the deleted objects.
214     SessionPtr aMgr = ModelAPI_Session::get();
215     std::list<DocumentPtr> anOpenedDocs = aMgr->allOpenedDocuments();
216     std::list<DocumentPtr>::const_iterator anIt = anOpenedDocs.begin(),
217                                             aLast = anOpenedDocs.end();
218     std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
219     for (; anIt != aLast; anIt++) {
220       DocumentPtr aDocument = *anIt;
221       if (aDocument == aFeatureDoc)
222         continue; // this document has been already processed in 1.1
223
224       int aFeaturesCount = aDocument->size(ModelAPI_Feature::group());
225       for (int aId = 0; aId < aFeaturesCount; aId++) {
226         ObjectPtr anObject = aDocument->object(ModelAPI_Feature::group(), aId);
227         FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);
228         if (!aFeature.get())
229           continue;
230
231         aRefs.clear();
232         aFeature->data()->referencesToObjects(aRefs);
233         std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRef = aRefs.begin();
234         bool aHasReferenceToObject = false;
235         for(; aRef != aRefs.end() && !aHasReferenceToObject; aRef++) {
236           std::list<ObjectPtr>::iterator aRefObj = aRef->second.begin();
237           for(; aRefObj != aRef->second.end() && !aHasReferenceToObject; aRefObj++) {
238             std::list<ObjectPtr>::const_iterator aObjIt = aObjects.begin();
239             for(; aObjIt != aObjects.end() && !aHasReferenceToObject; aObjIt++) {
240               aHasReferenceToObject = *aObjIt == *aRefObj;
241             }
242           }
243         }
244         if (aHasReferenceToObject && !isSubOfComposite(theSourceObject, aFeature))
245           theRefFeatures.insert(aFeature);
246       }
247     }
248   }
249
250   // Run recursion. It is possible recusive dependency, like the folowing: plane, extrusion uses plane,
251   // axis is built on extrusion. Delete of a plane should check the dependency from the axis also.
252   std::set<FeaturePtr> aRecursiveRefFeatures;
253   std::set<FeaturePtr>::const_iterator aFeatureIt = theRefFeatures.begin();
254   for (; aFeatureIt != theRefFeatures.end(); ++aFeatureIt) {
255     refsToFeatureInAllDocuments(theSourceObject, *aFeatureIt, aRecursiveRefFeatures);
256   } 
257   theRefFeatures.insert(aRecursiveRefFeatures.begin(), aRecursiveRefFeatures.end());
258 }
259
260 }