X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_Document.cpp;h=ec0c236f6f0389ab60177023a65ab8e30a399696;hb=6a7e53a3d3b52f1f798b7e3aa3c48de9c870d92b;hp=d9905674765c0b51a5160b603ac36c6f21124c49;hpb=46a28bd54e9ce0937d87d305202ab6912c1f5cd2;p=modules%2Fshaper.git diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index d99056747..ec0c236f6 100644 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -13,8 +13,10 @@ #include #include #include +#include #include #include + #include #include @@ -75,7 +77,8 @@ static TCollection_ExtendedString DocFileName(const char* theFileName, const std { TCollection_ExtendedString aPath((const Standard_CString) theFileName); // remove end-separators - while(aPath.Length() && (aPath.Value(aPath.Length()) == '\\' || aPath.Value(aPath.Length()) == '/')) + while(aPath.Length() && + (aPath.Value(aPath.Length()) == '\\' || aPath.Value(aPath.Length()) == '/')) aPath.Remove(aPath.Length()); aPath += _separator_; aPath += theID.c_str(); @@ -83,10 +86,15 @@ static TCollection_ExtendedString DocFileName(const char* theFileName, const std return aPath; } +bool Model_Document::isRoot() const +{ + return this == Model_Session::get()->moduleDocument().get(); +} + bool Model_Document::load(const char* theFileName) { Handle(Model_Application) anApp = Model_Application::getApplication(); - if (this == Model_Session::get()->moduleDocument().get()) { + if (isRoot()) { anApp->setLoadPath(theFileName); } TCollection_ExtendedString aPath(DocFileName(theFileName, myID)); @@ -160,7 +168,7 @@ bool Model_Document::load(const char* theFileName) std::dynamic_pointer_cast(Model_Session::get()); aSession->setActiveDocument(anApp->getDocument(myID), false); aSession->setCheckTransactions(false); - synchronizeFeatures(false, true); + synchronizeFeatures(false, true, true); aSession->setCheckTransactions(true); aSession->setActiveDocument(Model_Session::get()->moduleDocument(), false); aSession->setActiveDocument(anApp->getDocument(myID), true); @@ -172,7 +180,7 @@ bool Model_Document::save(const char* theFileName, std::list& theRe { // create a directory in the root document if it is not yet exist Handle(Model_Application) anApp = Model_Application::getApplication(); - if (this == Model_Session::get()->moduleDocument().get()) { + if (isRoot()) { #ifdef WIN32 CreateDirectory(theFileName, NULL); #else @@ -240,9 +248,9 @@ bool Model_Document::save(const char* theFileName, std::list& theRe void Model_Document::close(const bool theForever) { std::shared_ptr aPM = Model_Session::get(); - if (this != aPM->moduleDocument().get() && this == aPM->activeDocument().get()) { + if (!isRoot() && this == aPM->activeDocument().get()) { aPM->setActiveDocument(aPM->moduleDocument()); - } else if (this == aPM->moduleDocument().get()) { + } else if (isRoot()) { // erase the active document if root is closed aPM->setActiveDocument(DocumentPtr()); } @@ -291,7 +299,7 @@ void Model_Document::startOperation() { if (myDoc->HasOpenCommand()) { // start of nested command if (myDoc->CommitCommand()) { // commit the current: it will contain all nested after compactification - (*myTransactions.rbegin())++; // if has open command, the list is not empty + myTransactions.rbegin()->myOCAFNum++; // if has open command, the list is not empty } myNestedNum.push_back(0); // start of nested operation with zero transactions inside yet myDoc->OpenCommand(); @@ -299,7 +307,7 @@ void Model_Document::startOperation() myDoc->NewCommand(); } // starts a new operation - myTransactions.push_back(0); + myTransactions.push_back(Transaction()); if (!myNestedNum.empty()) (*myNestedNum.rbegin())++; myRedos.clear(); @@ -316,11 +324,11 @@ void Model_Document::compactNested() int aNumToCompact = *(myNestedNum.rbegin()); int aSumOfTransaction = 0; for(int a = 0; a < aNumToCompact; a++) { - aSumOfTransaction += *(myTransactions.rbegin()); + aSumOfTransaction += myTransactions.rbegin()->myOCAFNum; myTransactions.pop_back(); } // the latest transaction is the start of lower-level operation which startes the nested - *(myTransactions.rbegin()) += aSumOfTransaction; + myTransactions.rbegin()->myOCAFNum += aSumOfTransaction; myNestedNum.pop_back(); } } @@ -340,7 +348,7 @@ bool Model_Document::finishOperation() // this must be here just after everything is finished but before real transaction stop // to avoid messages about modifications outside of the transaction // and to rebuild everything after all updates and creates - if (Model_Session::get()->moduleDocument().get() == this) { // once for root document + if (isRoot()) { // once for root document Events_Loop::loop()->autoFlush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); static std::shared_ptr aFinishMsg (new Events_Message(Events_Loop::eventByName("FinishOperation"))); @@ -360,7 +368,7 @@ bool Model_Document::finishOperation() // transaction may be empty if this document was created during this transaction (create part) if (!myTransactions.empty() && myDoc->CommitCommand()) { // if commit is successfull, just increment counters - (*myTransactions.rbegin())++; + myTransactions.rbegin()->myOCAFNum++; aResult = true; } @@ -368,9 +376,9 @@ bool Model_Document::finishOperation() compactNested(); } if (!aResult && !myTransactions.empty() /* it can be for just created part document */) - aResult = *(myTransactions.rbegin()) != 0; + aResult = myTransactions.rbegin()->myOCAFNum != 0; - if (!aResult && Model_Session::get()->moduleDocument().get() == this) { + if (!aResult && isRoot()) { // nothing inside in all documents, so remove this transaction from the transactions list undoInternal(true, false); myDoc->ClearRedos(); @@ -387,7 +395,7 @@ void Model_Document::abortOperation() myDoc->ClearRedos(); myRedos.clear(); } else { // abort the current - int aNumTransactions = *myTransactions.rbegin(); + int aNumTransactions = myTransactions.rbegin()->myOCAFNum; myTransactions.pop_back(); if (!myNestedNum.empty()) (*myNestedNum.rbegin())--; @@ -397,15 +405,16 @@ void Model_Document::abortOperation() myDoc->Undo(); myDoc->ClearRedos(); } - synchronizeFeatures(true, false); // references were not changed since transaction start - // abort for all subs + // abort for all subs, flushes will be later, in the end of root abort const std::set aSubs = subDocuments(true); std::set::iterator aSubIter = aSubs.begin(); for (; aSubIter != aSubs.end(); aSubIter++) subDoc(*aSubIter)->abortOperation(); + // references may be changed because they are set in attributes on the fly + synchronizeFeatures(true, true, isRoot()); } -bool Model_Document::isOperation() +bool Model_Document::isOperation() const { // operation is opened for all documents: no need to check subs return myDoc->HasOpenCommand() == Standard_True ; @@ -419,8 +428,11 @@ bool Model_Document::isModified() bool Model_Document::canUndo() { - if (myDoc->GetAvailableUndos() > 0 && (myNestedNum.empty() || *myNestedNum.rbegin() != 0) && - !myTransactions.empty() /* for omitting the first useless transaction */) + // issue 406 : if transaction is opened, but nothing to undo behind, can not undo + int aCurrentNum = isOperation() ? 1 : 0; + if (myDoc->GetAvailableUndos() > 0 && + (myNestedNum.empty() || *myNestedNum.rbegin() - aCurrentNum > 0) && // there is something to undo in nested + myTransactions.size() - aCurrentNum > 0 /* for omitting the first useless transaction */) return true; // check other subs contains operation that can be undoed const std::set aSubs = subDocuments(true); @@ -433,17 +445,15 @@ bool Model_Document::canUndo() void Model_Document::undoInternal(const bool theWithSubs, const bool theSynchronize) { - int aNumTransactions = *myTransactions.rbegin(); + int aNumTransactions = myTransactions.rbegin()->myOCAFNum; + myRedos.push_back(*myTransactions.rbegin()); myTransactions.pop_back(); - myRedos.push_back(aNumTransactions); if (!myNestedNum.empty()) (*myNestedNum.rbegin())--; // roll back the needed number of transactions for(int a = 0; a < aNumTransactions; a++) myDoc->Undo(); - if (theSynchronize) - synchronizeFeatures(true, true); if (theWithSubs) { // undo for all subs const std::set aSubs = subDocuments(true); @@ -451,6 +461,9 @@ void Model_Document::undoInternal(const bool theWithSubs, const bool theSynchron for (; aSubIter != aSubs.end(); aSubIter++) subDoc(*aSubIter)->undoInternal(theWithSubs, theSynchronize); } + // after redo of all sub-documents to avoid updates on not-modified data (issue 370) + if (theSynchronize) + synchronizeFeatures(true, true, isRoot()); } void Model_Document::undo() @@ -460,7 +473,7 @@ void Model_Document::undo() bool Model_Document::canRedo() { - if (myDoc->GetAvailableRedos() > 0) + if (!myRedos.empty()) return true; // check other subs contains operation that can be redoed const std::set aSubs = subDocuments(true); @@ -475,18 +488,51 @@ void Model_Document::redo() { if (!myNestedNum.empty()) (*myNestedNum.rbegin())++; - int aNumRedos = *myRedos.rbegin(); + int aNumRedos = myRedos.rbegin()->myOCAFNum; + myTransactions.push_back(*myRedos.rbegin()); myRedos.pop_back(); - myTransactions.push_back(aNumRedos); for(int a = 0; a < aNumRedos; a++) myDoc->Redo(); - synchronizeFeatures(true, true); // redo for all subs const std::set aSubs = subDocuments(true); std::set::iterator aSubIter = aSubs.begin(); for (; aSubIter != aSubs.end(); aSubIter++) subDoc(*aSubIter)->redo(); + + // after redo of all sub-documents to avoid updates on not-modified data (issue 370) + synchronizeFeatures(true, true, isRoot()); +} + +std::list Model_Document::undoList() const +{ + std::list aResult; + // the number of skipped current operations (on undo they will be aborted) + int aSkipCurrent = isOperation() ? 1 : 0; + std::list::const_reverse_iterator aTrIter = myTransactions.crbegin(); + int aNumUndo = myTransactions.size(); + if (!myNestedNum.empty()) + aNumUndo = *myNestedNum.rbegin(); + for( ; aNumUndo > 0; aTrIter++, aNumUndo--) { + if (aSkipCurrent == 0) aResult.push_back(aTrIter->myId); + else aSkipCurrent--; + } + return aResult; +} + +std::list Model_Document::redoList() const +{ + std::list aResult; + std::list::const_reverse_iterator aTrIter = myRedos.crbegin(); + for( ; aTrIter != myRedos.crend(); aTrIter++) { + aResult.push_back(aTrIter->myId); + } + return aResult; +} + +void Model_Document::operationId(const std::string& theId) +{ + myTransactions.rbegin()->myId = theId; } /// Append to the array of references a new referenced label @@ -511,11 +557,21 @@ FeaturePtr Model_Document::addFeature(std::string theID) { TDF_Label anEmptyLab; FeaturePtr anEmptyFeature; - FeaturePtr aFeature = ModelAPI_Session::get()->createFeature(theID); + std::shared_ptr aSession = + std::dynamic_pointer_cast(ModelAPI_Session::get()); + FeaturePtr aFeature = aSession->createFeature(theID, this); if (!aFeature) return aFeature; - std::shared_ptr aDocToAdd = std::dynamic_pointer_cast( - aFeature->documentToAdd()); + Model_Document* aDocToAdd; + if (!aFeature->documentToAdd().empty()) { // use the customized document to add + if (aFeature->documentToAdd() != kind()) { // the root document by default + aDocToAdd = std::dynamic_pointer_cast(aSession->moduleDocument()).get(); + } else { + aDocToAdd = this; + } + } else { // if customized is not presented, add to "this" document + aDocToAdd = this; + } if (aFeature) { TDF_Label aFeatureLab; if (!aFeature->isAction()) { // do not add action to the data model @@ -543,10 +599,10 @@ FeaturePtr Model_Document::addFeature(std::string theID) } /// Appenad to the array of references a new referenced label. -/// If theIndex is not -1, removes element at thisindex, not theReferenced. +/// If theIndex is not -1, removes element at this index, not theReferenced. /// \returns the index of removed element -static int RemoveFromRefArray(TDF_Label theArrayLab, TDF_Label theReferenced, const int theIndex = - -1) +static int RemoveFromRefArray(TDF_Label theArrayLab, TDF_Label theReferenced, + const int theIndex = -1) { int aResult = -1; // no returned Handle(TDataStd_ReferenceArray) aRefs; @@ -593,19 +649,19 @@ void Model_Document::refsToFeature(FeaturePtr theFeature, if (aFeature.get() != NULL) theRefs.insert(aFeature); } - - if (!aRefs.empty()) { - FeaturePtr aFeature = ModelAPI_Feature::feature(aResult); - if (aFeature.get() != NULL) - theRefs.insert(aFeature); - } } } // the dependencies can be in the feature itself std::shared_ptr aData = std::dynamic_pointer_cast(theFeature->data()); if (aData && !aData->refsToMe().empty()) { - theRefs.insert(theFeature); + const std::set& aRefs = aData->refsToMe(); + std::set::const_iterator aRefIt = aRefs.begin(), aRefLast = aRefs.end(); + for(; aRefIt != aRefLast; aRefIt++) { + FeaturePtr aFeature = std::dynamic_pointer_cast((*aRefIt)->owner()); + if (aFeature.get() != NULL) + theRefs.insert(aFeature); + } } if (!theRefs.empty() && isSendError) { @@ -623,17 +679,50 @@ void Model_Document::removeFeature(FeaturePtr theFeature/*, const bool theCheck* myObjs.UnBind(aFeatureLabel); else return; // not found feature => do not remove + + // checking that the sub-element of composite feature is removed: if yes, inform the owner + std::set > aRefs; + refsToFeature(theFeature, aRefs, false); + std::set >::iterator aRefIter = aRefs.begin(); + for(; aRefIter != aRefs.end(); aRefIter++) { + std::shared_ptr aComposite = + std::dynamic_pointer_cast(*aRefIter); + if (aComposite.get()) { + aComposite->removeFeature(theFeature); + } + } + // erase fields theFeature->erase(); + static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY); + ModelAPI_EventCreator::get()->sendUpdated(theFeature, EVENT_DISP); // erase all attributes under the label of feature aFeatureLabel.ForgetAllAttributes(); // remove it from the references array if (theFeature->isInHistory()) { RemoveFromRefArray(featuresLabel(), aFeatureLabel); } + // event: feature is deleted + ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), ModelAPI_Feature::group()); + // the redisplay signal should be flushed in order to erase the feature presentation in the viewer + Events_Loop::loop()->flush(EVENT_DISP); + } +} + +void Model_Document::addToHistory(const std::shared_ptr theObject) +{ + TDF_Label aFeaturesLab = featuresLabel(); + std::shared_ptr aData = std::static_pointer_cast(theObject->data()); + if (!aData) { + return; // not found feature => do not remove + } + TDF_Label aFeatureLabel = aData->label().Father(); + // store feature in the history of features array + if (theObject->isInHistory()) { + AddToRefArray(aFeaturesLab, aFeatureLabel); + } else { + RemoveFromRefArray(aFeaturesLab, aFeatureLabel); } - // event: feature is deleted - ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), ModelAPI_Feature::group()); } FeaturePtr Model_Document::feature(TDF_Label& theLabel) const @@ -751,6 +840,37 @@ ObjectPtr Model_Document::object(const std::string& theGroupID, const int theInd return ObjectPtr(); } +std::shared_ptr Model_Document::objectByName( + const std::string& theGroupID, const std::string& theName) +{ + if (theGroupID == ModelAPI_Feature::group()) { + int anIndex = 0; + TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID()); + for (; aLabIter.More(); aLabIter.Next()) { + TDF_Label aFLabel = aLabIter.Value()->Label(); + FeaturePtr aFeature = feature(aFLabel); + if (aFeature && aFeature->name() == theName) + return aFeature; + } + } else { + // comment must be in any feature: it is kind + int anIndex = 0; + TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID()); + for (; aLabIter.More(); aLabIter.Next()) { + TDF_Label aFLabel = aLabIter.Value()->Label(); + FeaturePtr aFeature = feature(aFLabel); + const std::list >& aResults = aFeature->results(); + std::list >::const_iterator aRIter = aResults.begin(); + for (; aRIter != aResults.cend(); aRIter++) { + if ((*aRIter)->groupName() == theGroupID && (*aRIter)->data()->name() == theName) + return *aRIter; + } + } + } + // not found + return ObjectPtr(); +} + int Model_Document::size(const std::string& theGroupID, const bool theHidden) { int aResult = 0; @@ -844,19 +964,26 @@ void Model_Document::initData(ObjectPtr theObj, TDF_Label theLab, const int theT FeaturePtr aFeature = std::dynamic_pointer_cast(theObj); if (aFeature) { setUniqueName(aFeature); // must be before "initAttributes" because duplicate part uses name - aFeature->initAttributes(); } + theObj->initAttributes(); } -void Model_Document::synchronizeFeatures(const bool theMarkUpdated, const bool theUpdateReferences) +void Model_Document::synchronizeFeatures( + const bool theMarkUpdated, const bool theUpdateReferences, const bool theFlush) { std::shared_ptr aThis = Model_Application::getApplication()->getDocument(myID); // after all updates, sends a message that groups of features were created or updated Events_Loop* aLoop = Events_Loop::loop(); + static Events_ID aDispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); + static Events_ID aCreateEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED); + static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); + static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); + static Events_ID aDeleteEvent = Events_Loop::eventByName(EVENT_OBJECT_DELETED); + static Events_ID aToHideEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); aLoop->activateFlushes(false); - // update all objects by checking are they of labels or not + // update all objects by checking are they on labels or not std::set aNewFeatures, aKeptFeatures; TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID()); for (; aLabIter.More(); aLabIter.Next()) { @@ -864,9 +991,9 @@ void Model_Document::synchronizeFeatures(const bool theMarkUpdated, const bool t FeaturePtr aFeature; if (!myObjs.IsBound(aFeatureLabel)) { // a new feature is inserted // create a feature - aFeature = ModelAPI_Session::get()->createFeature( - TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(aLabIter.Value())->Get()) - .ToCString()); + aFeature = std::dynamic_pointer_cast(ModelAPI_Session::get())->createFeature( + TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(aLabIter.Value())->Get()) + .ToCString(), this); if (!aFeature) { // somethig is wrong, most probably, the opened document has invalid structure Events_Error::send("Invalid type of object in the document"); aLabIter.Value()->Label().ForgetAllAttributes(); @@ -878,18 +1005,16 @@ void Model_Document::synchronizeFeatures(const bool theMarkUpdated, const bool t initData(aFeature, aFeatureLabel, TAG_FEATURE_ARGUMENTS); // event: model is updated - static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED); - ModelAPI_EventCreator::get()->sendUpdated(aFeature, anEvent); + ModelAPI_EventCreator::get()->sendUpdated(aFeature, aCreateEvent); } else { // nothing is changed, both iterators are incremented aFeature = myObjs.Find(aFeatureLabel); aKeptFeatures.insert(aFeature); if (theMarkUpdated) { - static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); - ModelAPI_EventCreator::get()->sendUpdated(aFeature, anEvent); + ModelAPI_EventCreator::get()->sendUpdated(aFeature, anUpdateEvent); } } } - // update results of thefeatures (after features created because they may be connected, like sketch and sub elements) + // update results of the features (after features created because they may be connected, like sketch and sub elements) std::list aComposites; // composites must be updated after their subs (issue 360) TDF_ChildIDIterator aLabIter2(featuresLabel(), TDataStd_Comment::GetID()); for (; aLabIter2.More(); aLabIter2.Next()) { @@ -910,23 +1035,20 @@ void Model_Document::synchronizeFeatures(const bool theMarkUpdated, const bool t NCollection_DataMap::Iterator aFIter(myObjs); while (aFIter.More()) { if (aKeptFeatures.find(aFIter.Value()) == aKeptFeatures.end() - && aNewFeatures.find(aFIter.Value()) == aNewFeatures.end()) { - FeaturePtr aFeature = aFIter.Value(); - // event: model is updated - //if (aFeature->isInHistory()) { + && aNewFeatures.find(aFIter.Value()) == aNewFeatures.end()) { + FeaturePtr aFeature = aFIter.Value(); + // event: model is updated + //if (aFeature->isInHistory()) { ModelAPI_EventCreator::get()->sendDeleted(aThis, ModelAPI_Feature::group()); - //} - // results of this feature must be redisplayed (hided) - static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); - const std::list >& aResults = aFeature->results(); - std::list >::const_iterator aRIter = aResults.begin(); - // redisplay also removed feature (used for sketch and AISObject) - ModelAPI_EventCreator::get()->sendUpdated(aFeature, EVENT_DISP); - aFeature->erase(); - // unbind after the "erase" call: on abort sketch is removes sub-objects that corrupts aFIter - myObjs.UnBind(aFIter.Key()); - // reinitialize iterator because unbind may corrupt the previous order in the map - aFIter.Initialize(myObjs); + //} + // results of this feature must be redisplayed (hided) + // redisplay also removed feature (used for sketch and AISObject) + ModelAPI_EventCreator::get()->sendUpdated(aFeature, aRedispEvent); + aFeature->erase(); + // unbind after the "erase" call: on abort sketch is removes sub-objects that corrupts aFIter + myObjs.UnBind(aFIter.Key()); + // reinitialize iterator because unbind may corrupt the previous order in the map + aFIter.Initialize(myObjs); } else aFIter.Next(); } @@ -938,11 +1060,13 @@ void Model_Document::synchronizeFeatures(const bool theMarkUpdated, const bool t myExecuteFeatures = false; aLoop->activateFlushes(true); - aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED)); - aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED)); - aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); - aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); - aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TOHIDE)); + if (theFlush) { + aLoop->flush(aCreateEvent); + aLoop->flush(aDeleteEvent); + aLoop->flush(anUpdateEvent); + aLoop->flush(aRedispEvent); + aLoop->flush(aToHideEvent); + } myExecuteFeatures = true; } @@ -982,7 +1106,8 @@ void Model_Document::synchronizeBackRefs() if (aFData) { std::list > > aRefs; aFData->referencesToObjects(aRefs); - std::list > >::iterator aRefsIter = aRefs.begin(); + std::list > >::iterator + aRefsIter = aRefs.begin(); for(; aRefsIter != aRefs.end(); aRefsIter++) { std::list::iterator aRefTo = aRefsIter->second.begin(); for(; aRefTo != aRefsIter->second.end(); aRefTo++) { @@ -1029,7 +1154,11 @@ void Model_Document::storeResult(std::shared_ptr theFeatureData, theResult->setDoc(aThis); initData(theResult, resultLabel(theFeatureData, theResultIndex), TAG_FEATURE_ARGUMENTS); if (theResult->data()->name().empty()) { // if was not initialized, generate event and set a name - theResult->data()->setName(theFeatureData->name()); + std::stringstream aNewName; + aNewName<name(); + if (theResultIndex > 0) // if there are several results, add unique prefix starting from second + aNewName<<"_"<data()->setName(aNewName.str()); } } @@ -1101,6 +1230,23 @@ std::shared_ptr Model_Document::createGroup( return aResult; } +std::shared_ptr Model_Document::createParameter( + const std::shared_ptr& theFeatureData, const int theIndex) +{ + TDF_Label aLab = resultLabel(theFeatureData, theIndex); + TDataStd_Comment::Set(aLab, ModelAPI_ResultParameter::group().c_str()); + ObjectPtr anOldObject = object(aLab); + std::shared_ptr aResult; + if (anOldObject) { + aResult = std::dynamic_pointer_cast(anOldObject); + } + if (!aResult) { + aResult = std::shared_ptr(new Model_ResultParameter); + storeResult(theFeatureData, aResult, theIndex); + } + return aResult; +} + std::shared_ptr Model_Document::feature( const std::shared_ptr& theResult) {