X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_Document.cpp;h=ec0c236f6f0389ab60177023a65ab8e30a399696;hb=6a7e53a3d3b52f1f798b7e3aa3c48de9c870d92b;hp=f1f10b103763dca05342c19888f0d014678b9146;hpb=f47b586aeeaa4a6cfe924e8a1c9663419f918907;p=modules%2Fshaper.git diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index f1f10b103..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)); @@ -156,10 +164,14 @@ bool Model_Document::load(const char* theFileName) if (!isError) { myDoc->SetUndoLimit(UNDO_LIMIT); // to avoid the problem that feature is created in the current, not this, document - Model_Session::get()->setActiveDocument(anApp->getDocument(myID), false); - synchronizeFeatures(false, true); - Model_Session::get()->setActiveDocument(Model_Session::get()->moduleDocument(), false); - Model_Session::get()->setActiveDocument(anApp->getDocument(myID), true); + std::shared_ptr aSession = + std::dynamic_pointer_cast(Model_Session::get()); + aSession->setActiveDocument(anApp->getDocument(myID), false); + aSession->setCheckTransactions(false); + synchronizeFeatures(false, true, true); + aSession->setCheckTransactions(true); + aSession->setActiveDocument(Model_Session::get()->moduleDocument(), false); + aSession->setActiveDocument(anApp->getDocument(myID), true); } return !isError; } @@ -168,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 @@ -236,8 +248,11 @@ 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 (isRoot()) { + // erase the active document if root is closed + aPM->setActiveDocument(DocumentPtr()); } // close all subs const std::set aSubs = subDocuments(true); @@ -284,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(); @@ -292,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(); @@ -309,24 +324,20 @@ 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(); } } -void Model_Document::finishOperation() +bool Model_Document::finishOperation() { bool isNestedClosed = !myDoc->HasOpenCommand() && !myNestedNum.empty(); static std::shared_ptr aSession = std::static_pointer_cast(Model_Session::get()); - // just to be sure that everybody knows that changes were performed - if (isNestedClosed) { - aSession->setCheckTransactions(false); // for nested transaction commit - } synchronizeBackRefs(); Events_Loop* aLoop = Events_Loop::loop(); aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED)); @@ -337,7 +348,7 @@ void 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"))); @@ -347,34 +358,44 @@ void Model_Document::finishOperation() // to avoid "updated" message appearance by updater //aLoop->clear(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); - if (isNestedClosed) { - aSession->setCheckTransactions(true); // for nested transaction commit - } - // finish for all subs first: to avoid nested finishing and "isOperation" calls problems inside + bool aResult = false; const std::set aSubs = subDocuments(true); std::set::iterator aSubIter = aSubs.begin(); for (; aSubIter != aSubs.end(); aSubIter++) - subDoc(*aSubIter)->finishOperation(); + if (subDoc(*aSubIter)->finishOperation()) + aResult = true; - if (myDoc->CommitCommand()) { // if commit is successfull, just increment counters - (*myTransactions.rbegin())++; + // 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()->myOCAFNum++; + aResult = true; } if (isNestedClosed) { compactNested(); } + if (!aResult && !myTransactions.empty() /* it can be for just created part document */) + aResult = myTransactions.rbegin()->myOCAFNum != 0; + + if (!aResult && isRoot()) { + // nothing inside in all documents, so remove this transaction from the transactions list + undoInternal(true, false); + myDoc->ClearRedos(); + myRedos.clear(); + } + return aResult; } void Model_Document::abortOperation() { if (!myNestedNum.empty() && !myDoc->HasOpenCommand()) { // abort all what was done in nested compactNested(); - undoInternal(false); + undoInternal(false, false); 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())--; @@ -384,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 ; @@ -406,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); @@ -418,11 +443,11 @@ bool Model_Document::canUndo() return false; } -void Model_Document::undoInternal(const bool theWithSubs) +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 @@ -430,23 +455,25 @@ void Model_Document::undoInternal(const bool theWithSubs) myDoc->Undo(); if (theWithSubs) { - synchronizeFeatures(true, true); // undo for all subs const std::set aSubs = subDocuments(true); std::set::iterator aSubIter = aSubs.begin(); for (; aSubIter != aSubs.end(); aSubIter++) - subDoc(*aSubIter)->undo(); + 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() { - undoInternal(true); + undoInternal(true, true); } 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); @@ -461,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 @@ -497,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 @@ -529,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; @@ -560,22 +630,48 @@ static int RemoveFromRefArray(TDF_Label theArrayLab, TDF_Label theReferenced, co return aResult; } -void Model_Document::removeFeature(FeaturePtr theFeature, const bool theCheck) +void Model_Document::refsToFeature(FeaturePtr theFeature, + std::set >& theRefs, + const bool isSendError) { - if (theCheck) { - // check the feature: it must have no depended objects on it - std::list::const_iterator aResIter = theFeature->results().cbegin(); - for(; aResIter != theFeature->results().cend(); aResIter++) { - std::shared_ptr aData = - std::dynamic_pointer_cast((*aResIter)->data()); - if (aData && !aData->refsToMe().empty()) { - Events_Error::send( - "Feature '" + theFeature->data()->name() + "' is used and can not be deleted"); - return; + // check the feature: it must have no depended objects on it + // the dependencies can be in the feature results + std::list::const_iterator aResIter = theFeature->results().cbegin(); + for(; aResIter != theFeature->results().cend(); aResIter++) { + ResultPtr aResult = (*aResIter); + std::shared_ptr aData = + std::dynamic_pointer_cast(aResult->data()); + if (aData.get() != NULL) { + 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); } } } + // the dependencies can be in the feature itself + std::shared_ptr aData = + std::dynamic_pointer_cast(theFeature->data()); + if (aData && !aData->refsToMe().empty()) { + 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) { + Events_Error::send( + "Feature '" + theFeature->data()->name() + "' is used and can not be deleted"); + } +} + +void Model_Document::removeFeature(FeaturePtr theFeature/*, const bool theCheck*/) +{ std::shared_ptr aData = std::static_pointer_cast(theFeature->data()); if (aData) { TDF_Label aFeatureLabel = aData->label().Father(); @@ -583,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 @@ -711,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; @@ -804,21 +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 - std::static_pointer_cast(Model_Session::get()) - ->setCheckTransactions(false); 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()) { @@ -826,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(); @@ -840,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()) { @@ -872,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 - TDF_Label aLab = aFIter.Key(); - aFIter.Next(); - myObjs.UnBind(aLab); + //} + // 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(); } @@ -900,13 +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)); - std::static_pointer_cast(Model_Session::get()) - ->setCheckTransactions(true); + if (theFlush) { + aLoop->flush(aCreateEvent); + aLoop->flush(aDeleteEvent); + aLoop->flush(anUpdateEvent); + aLoop->flush(aRedispEvent); + aLoop->flush(aToHideEvent); + } myExecuteFeatures = true; } @@ -946,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++) { @@ -993,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()); } } @@ -1065,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) {