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