1 // Copyright (C) 2020-2023 CEA, EDF
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)
190 theNew->selectValue(theOld);
193 void copyAttribute(AttributePtr theOld, AttributePtr theNew, MapEntities& theMapOldNew)
195 if (theNew->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
196 copyRefAttr(std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theOld),
197 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theNew),
200 else if (theNew->attributeType() == ModelAPI_AttributeReference::typeId()) {
201 copyReference(std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theOld),
202 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theNew),
205 else if (theNew->attributeType() == ModelAPI_AttributeRefAttrList::typeId()) {
206 copyRefAttrList(std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(theOld),
207 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(theNew),
210 else if (theNew->attributeType() == ModelAPI_AttributeRefList::typeId()) {
211 copyRefList(std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theOld),
212 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theNew),
215 else if (theNew->attributeType() == ModelAPI_AttributeSelection::typeId()) {
216 copySelection(std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theOld),
217 std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theNew));
221 static void renameByParent(FeaturePtr theOld, FeaturePtr theNew)
223 AttributeReferencePtr anOldParentRef = theOld->reference(SketchPlugin_SketchEntity::PARENT_ID());
224 if (!anOldParentRef || !anOldParentRef->isInitialized())
227 AttributeReferencePtr aNewParentRef = theNew->reference(SketchPlugin_SketchEntity::PARENT_ID());
229 std::wstring anOldName = anOldParentRef->value()->data()->name();
230 std::wstring aNewName = aNewParentRef->value()->data()->name();
232 // substitute name of old parent by the new one
233 theNew->data()->setName(theOld->name());
234 SketchPlugin_Tools::replaceInName(theNew, anOldName, aNewName);
236 const std::list<ResultPtr>& anOldResults = theOld->results();
237 const std::list<ResultPtr>& aNewResults = theNew->results();
238 for (std::list<ResultPtr>::const_iterator it0 = anOldResults.begin(), it1 = aNewResults.begin();
239 it0 != anOldResults.end() && it1 != aNewResults.end(); ++it0, ++it1) {
240 (*it1)->data()->setName((*it0)->data()->name());
241 SketchPlugin_Tools::replaceInName(*it1, anOldName, aNewName);
245 static void copyFeature(const FeaturePtr theFeature,
246 std::shared_ptr<SketchPlugin_Sketch> theSketch,
247 MapEntities& theMapOldNew)
252 // copy feature and its results
253 FeaturePtr aNewFeature = theSketch->addFeature(theFeature->getKind());
254 theFeature->data()->copyTo(aNewFeature->data());
255 int aResultIndex = 0;
256 for (std::list<ResultPtr>::const_iterator aRIt = theFeature->results().begin();
257 aRIt != theFeature->results().end(); ++aRIt) {
258 ResultConstructionPtr aResult =
259 theSketch->document()->createConstruction(aNewFeature->data(), aResultIndex);
261 GeomAlgoAPI_Copy aCopyAlgo((*aRIt)->shape());
263 aResult->setShape(aCopyAlgo.shape());
264 aResult->setIsInHistory((*aRIt)->isInHistory());
265 aNewFeature->setResult(aResult, aResultIndex++);
267 theMapOldNew.bind(theFeature, aNewFeature);
269 // update referred features and attributes
270 bool aWasBlocked = aNewFeature->data()->blockSendAttributeUpdated(true, false);
271 std::list<AttributePtr> anAttrs =
272 aNewFeature->data()->attributes(std::string());
273 for (std::list<AttributePtr>::iterator anIt = anAttrs.begin(); anIt != anAttrs.end(); ++anIt) {
274 AttributePtr anOldAttr = theFeature->attribute((*anIt)->id());
275 copyAttribute(anOldAttr, *anIt, theMapOldNew);
277 aNewFeature->data()->blockSendAttributeUpdated(aWasBlocked, false);
279 // rename feature according to parent
280 renameByParent(theFeature, aNewFeature);
283 static int index(const std::wstring& theName, const std::wstring& thePrefix)
286 if (theName.find(thePrefix) == 0) {
288 if (theName[thePrefix.size()] == '_') {
289 std::wstring anIndexStr = theName.substr(thePrefix.size() + 1);
290 anIndex = std::stoi(anIndexStr);
297 void SketchPlugin_SketchCopy::execute()
299 FeaturePtr aBaseSketchFeature = ModelAPI_Feature::feature(reference(BASE_ID())->value());
300 CompositeFeaturePtr aBaseSketch =
301 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aBaseSketchFeature);
303 setError("Error: a base feature is not a sketch.");
304 return; // invalid case
307 FeaturePtr aNewSketchFeature = document()->addFeature(aBaseSketch->getKind());
308 std::shared_ptr<SketchPlugin_Sketch> aNewSketch =
309 std::dynamic_pointer_cast<SketchPlugin_Sketch>(aNewSketchFeature);
310 // copy all attributes of sketch, then clear sub-features to be able to copy then one by one
311 aBaseSketch->data()->copyTo(aNewSketch->data());
312 aNewSketch->reflist(SketchPlugin_Sketch::FEATURES_ID())->clear();
314 MapEntities aMapOldNew;
316 std::list<ObjectPtr> aBaseFeatures =
317 aBaseSketch->reflist(SketchPlugin_Sketch::FEATURES_ID())->list();
318 for (std::list<ObjectPtr>::const_iterator aFIt = aBaseFeatures.begin();
319 aFIt != aBaseFeatures.end(); ++aFIt) {
320 FeaturePtr aCurFeature = ModelAPI_Feature::feature(*aFIt);
321 copyFeature(aCurFeature, aNewSketch, aMapOldNew);
324 aNewSketch->execute();
326 // check number of copies of the selected sketch before name the new sketch
327 static const std::wstring SKETCH_NAME_SUFFIX(L"_Copy");
328 std::wstring aSketchName = aBaseSketch->name() + SKETCH_NAME_SUFFIX;
329 int aNewSketchIndex = 0;
330 std::list<FeaturePtr> aFeatures = document()->allFeatures();
331 for (std::list<FeaturePtr>::iterator aFIt = aFeatures.begin(); aFIt != aFeatures.end(); ++aFIt) {
332 if ((*aFIt)->getKind() != SketchPlugin_Sketch::ID())
334 int anIndex = index((*aFIt)->name(), aSketchName);
335 if (anIndex >= aNewSketchIndex)
336 aNewSketchIndex = anIndex + 1;
337 anIndex = index((*aFIt)->lastResult()->data()->name(), aSketchName);
338 if (anIndex >= aNewSketchIndex)
339 aNewSketchIndex = anIndex + 1;
341 std::wostringstream aNameStream;
342 aNameStream << aSketchName;
343 if (aNewSketchIndex > 0)
344 aNameStream << '_' << aNewSketchIndex;
345 aNewSketch->data()->setName(aNameStream.str());
346 aNewSketch->lastResult()->data()->setName(aNameStream.str());