1 // Copyright (C) 2020 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include <SketchPlugin_SketchCopy.h>
21 #include <SketchPlugin_Sketch.h>
22 #include <SketchPlugin_SketchEntity.h>
23 #include <SketchPlugin_Tools.h>
25 #include <ModelAPI_AttributeRefAttr.h>
26 #include <ModelAPI_AttributeRefAttrList.h>
27 #include <ModelAPI_AttributeReference.h>
28 #include <ModelAPI_AttributeRefList.h>
29 #include <ModelAPI_CompositeFeature.h>
30 #include <ModelAPI_ResultConstruction.h>
32 #include <GeomAlgoAPI_Copy.h>
40 static void copyAttribute(AttributePtr theOld, AttributePtr theNew, MapEntities& theMapOldNew);
42 /// Internal structure to keep relation between sub-elements of old and new sketch.
46 void bind(FeaturePtr theOld, FeaturePtr theNew)
48 myObjects[theOld] = theNew;
49 checkPostponed(theOld);
51 std::list<ResultPtr> anOldResults = theOld->results();
52 std::list<ResultPtr> aNewResults = theNew->results();
53 for (std::list<ResultPtr>::iterator it1 = anOldResults.begin(), it2 = aNewResults.begin();
54 it1 != anOldResults.end() && it2 != aNewResults.end(); ++it1, ++it2) {
55 myObjects[*it1] = *it2;
60 void postpone(ObjectPtr theOldObject, AttributePtr theOldAttr, AttributePtr theNewAttr)
63 myPostponed[theOldObject][theOldAttr] = theNewAttr;
66 ObjectPtr find(ObjectPtr theOld)
68 auto aFound = myObjects.find(theOld);
69 return aFound == myObjects.end() ? ObjectPtr() : aFound->second;
72 AttributePtr find(AttributePtr theOld)
74 FeaturePtr anOldOwner = ModelAPI_Feature::feature(theOld->owner());
75 FeaturePtr aNewOwner = ModelAPI_Feature::feature(find(anOldOwner));
76 return aNewOwner ? aNewOwner->attribute(theOld->id()) : AttributePtr();
80 void checkPostponed(ObjectPtr theOld)
82 auto aFound = myPostponed.find(theOld);
83 if (aFound == myPostponed.end())
85 for (auto it = aFound->second.begin(); it != aFound->second.end(); ++it)
86 copyAttribute(it->first, it->second, *this);
87 myPostponed.erase(aFound);
91 std::map<ObjectPtr, ObjectPtr> myObjects;
92 std::map<ObjectPtr, std::map<AttributePtr, AttributePtr> > myPostponed;
96 SketchPlugin_SketchCopy::SketchPlugin_SketchCopy() : ModelAPI_Feature()
99 void SketchPlugin_SketchCopy::initAttributes()
101 data()->addAttribute(BASE_ID(), ModelAPI_AttributeReference::typeId());
104 static void copyRefAttr(AttributeRefAttrPtr theOld,
105 AttributeRefAttrPtr theNew,
106 MapEntities& theMapOldNew)
108 if (theOld->isObject()) {
109 ObjectPtr aNew = theMapOldNew.find(theOld->object());
111 theNew->setObject(aNew);
113 theMapOldNew.postpone(theOld->object(), theOld, theNew);
116 AttributePtr aNewAttr = theMapOldNew.find(theOld->attr());
118 theNew->setAttr(aNewAttr);
120 theMapOldNew.postpone(theOld->attr()->owner(), theOld, theNew);
124 static void copyRefAttrList(AttributeRefAttrListPtr theOld,
125 AttributeRefAttrListPtr theNew,
126 MapEntities& theMapOldNew)
128 // copy only if all referred objects/attribute are already transfered
129 std::list<std::pair<ObjectPtr, AttributePtr> > aRefs = theOld->list();
130 for (std::list<std::pair<ObjectPtr, AttributePtr> >::iterator anIt = aRefs.begin();
131 anIt != aRefs.end(); ++anIt) {
132 ObjectPtr aNewObj = anIt->first ? theMapOldNew.find(anIt->first) : ObjectPtr();
133 AttributePtr aNewAttr = anIt->second ? theMapOldNew.find(anIt->second) : AttributePtr();
134 if (aNewObj || aNewAttr)
135 *anIt = std::pair<ObjectPtr, AttributePtr>(aNewObj, aNewAttr);
138 theMapOldNew.postpone(anIt->first, theOld, theNew);
140 theMapOldNew.postpone(anIt->second->owner(), theOld, theNew);
144 // update the RefAttrList
146 for (std::list<std::pair<ObjectPtr, AttributePtr> >::iterator anIt = aRefs.begin();
147 anIt != aRefs.end(); ++anIt) {
149 theNew->append(anIt->first);
151 theNew->append(anIt->second);
155 static void copyReference(AttributeReferencePtr theOld,
156 AttributeReferencePtr theNew,
157 MapEntities& theMapOldNew)
159 ObjectPtr aNew = theMapOldNew.find(theOld->value());
161 theNew->setValue(aNew);
163 theMapOldNew.postpone(theOld->value(), theOld, theNew);
166 static void copyRefList(AttributeRefListPtr theOld,
167 AttributeRefListPtr theNew,
168 MapEntities& theMapOldNew)
170 // copy only if all referred objects are already transfered
171 std::list<ObjectPtr> aRefs = theOld->list();
172 for (std::list<ObjectPtr>::iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) {
173 ObjectPtr aNew = theMapOldNew.find(*anIt);
177 theMapOldNew.postpone(*anIt, theOld, theNew);
183 for (std::list<ObjectPtr>::iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt)
184 theNew->append(*anIt);
187 static void copySelection(AttributeSelectionPtr theOld,
188 AttributeSelectionPtr theNew,
189 MapEntities& theMapOldNew)
191 theNew->selectValue(theOld);
194 void copyAttribute(AttributePtr theOld, AttributePtr theNew, MapEntities& theMapOldNew)
196 if (theNew->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
197 copyRefAttr(std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theOld),
198 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theNew),
201 else if (theNew->attributeType() == ModelAPI_AttributeReference::typeId()) {
202 copyReference(std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theOld),
203 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theNew),
206 else if (theNew->attributeType() == ModelAPI_AttributeRefAttrList::typeId()) {
207 copyRefAttrList(std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(theOld),
208 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(theNew),
211 else if (theNew->attributeType() == ModelAPI_AttributeRefList::typeId()) {
212 copyRefList(std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theOld),
213 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theNew),
216 else if (theNew->attributeType() == ModelAPI_AttributeSelection::typeId()) {
217 copySelection(std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theOld),
218 std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theNew),
223 static void renameByParent(FeaturePtr theOld, FeaturePtr theNew)
225 AttributeReferencePtr anOldParentRef = theOld->reference(SketchPlugin_SketchEntity::PARENT_ID());
226 if (!anOldParentRef || !anOldParentRef->isInitialized())
229 AttributeReferencePtr aNewParentRef = theNew->reference(SketchPlugin_SketchEntity::PARENT_ID());
231 std::string anOldName = anOldParentRef->value()->data()->name();
232 std::string aNewName = aNewParentRef->value()->data()->name();
234 // substitute name of old parent by the new one
235 theNew->data()->setName(theOld->name());
236 SketchPlugin_Tools::replaceInName(theNew, anOldName, aNewName);
238 const std::list<ResultPtr>& anOldResults = theOld->results();
239 const std::list<ResultPtr>& aNewResults = theNew->results();
240 for (std::list<ResultPtr>::const_iterator it0 = anOldResults.begin(), it1 = aNewResults.begin();
241 it0 != anOldResults.end() && it1 != aNewResults.end(); ++it0, ++it1) {
242 (*it1)->data()->setName((*it0)->data()->name());
243 SketchPlugin_Tools::replaceInName(*it1, anOldName, aNewName);
247 static void copyFeature(const FeaturePtr theFeature,
248 std::shared_ptr<SketchPlugin_Sketch> theSketch,
249 MapEntities& theMapOldNew)
254 // copy feature and its results
255 FeaturePtr aNewFeature = theSketch->addFeature(theFeature->getKind());
256 theFeature->data()->copyTo(aNewFeature->data());
257 int aResultIndex = 0;
258 for (std::list<ResultPtr>::const_iterator aRIt = theFeature->results().begin();
259 aRIt != theFeature->results().end(); ++aRIt) {
260 ResultConstructionPtr aResult =
261 theSketch->document()->createConstruction(aNewFeature->data(), aResultIndex);
263 GeomAlgoAPI_Copy aCopyAlgo((*aRIt)->shape());
265 aResult->setShape(aCopyAlgo.shape());
266 aResult->setIsInHistory((*aRIt)->isInHistory());
267 aNewFeature->setResult(aResult, aResultIndex++);
269 theMapOldNew.bind(theFeature, aNewFeature);
271 // update referred features and attributes
272 bool aWasBlocked = aNewFeature->data()->blockSendAttributeUpdated(true, false);
273 std::list<AttributePtr> anAttrs =
274 aNewFeature->data()->attributes(std::string());
275 for (std::list<AttributePtr>::iterator anIt = anAttrs.begin(); anIt != anAttrs.end(); ++anIt) {
276 AttributePtr anOldAttr = theFeature->attribute((*anIt)->id());
277 copyAttribute(anOldAttr, *anIt, theMapOldNew);
279 aNewFeature->data()->blockSendAttributeUpdated(aWasBlocked, false);
281 // rename feature according to parent
282 renameByParent(theFeature, aNewFeature);
285 static int index(const std::string& theName, const std::string& thePrefix)
288 if (theName.find(thePrefix) == 0) {
290 if (theName[thePrefix.size()] == '_') {
291 std::string anIndexStr = theName.substr(thePrefix.size() + 1);
292 anIndex = std::atoi(anIndexStr.c_str());
299 void SketchPlugin_SketchCopy::execute()
301 FeaturePtr aBaseSketchFeature = ModelAPI_Feature::feature(reference(BASE_ID())->value());
302 CompositeFeaturePtr aBaseSketch =
303 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aBaseSketchFeature);
305 setError("Error: a base feature is not a sketch.");
306 return; // invalid case
309 FeaturePtr aNewSketchFeature = document()->addFeature(aBaseSketch->getKind());
310 std::shared_ptr<SketchPlugin_Sketch> aNewSketch =
311 std::dynamic_pointer_cast<SketchPlugin_Sketch>(aNewSketchFeature);
312 // copy all attributes of sketch, then clear sub-features to be able to copy then one by one
313 aBaseSketch->data()->copyTo(aNewSketch->data());
314 aNewSketch->reflist(SketchPlugin_Sketch::FEATURES_ID())->clear();
316 MapEntities aMapOldNew;
318 std::list<ObjectPtr> aBaseFeatures =
319 aBaseSketch->reflist(SketchPlugin_Sketch::FEATURES_ID())->list();
320 for (std::list<ObjectPtr>::const_iterator aFIt = aBaseFeatures.begin();
321 aFIt != aBaseFeatures.end(); ++aFIt) {
322 FeaturePtr aCurFeature = ModelAPI_Feature::feature(*aFIt);
323 copyFeature(aCurFeature, aNewSketch, aMapOldNew);
326 aNewSketch->execute();
328 // check number of copies of the selected sketch before name the new sketch
329 static const std::string SKETCH_NAME_SUFFIX("_Copy");
330 std::string aSketchName = aBaseSketch->name() + SKETCH_NAME_SUFFIX;
331 int aNewSketchIndex = 0;
332 std::list<FeaturePtr> aFeatures = document()->allFeatures();
333 for (std::list<FeaturePtr>::iterator aFIt = aFeatures.begin(); aFIt != aFeatures.end(); ++aFIt) {
334 if ((*aFIt)->getKind() != SketchPlugin_Sketch::ID())
336 int anIndex = index((*aFIt)->name(), aSketchName);
337 if (anIndex >= aNewSketchIndex)
338 aNewSketchIndex = anIndex + 1;
339 anIndex = index((*aFIt)->lastResult()->data()->name(), aSketchName);
340 if (anIndex >= aNewSketchIndex)
341 aNewSketchIndex = anIndex + 1;
343 std::ostringstream aNameStream;
344 aNameStream << aSketchName;
345 if (aNewSketchIndex > 0)
346 aNameStream << '_' << aNewSketchIndex;
347 aNewSketch->data()->setName(aNameStream.str());
348 aNewSketch->lastResult()->data()->setName(aNameStream.str());