From b14d19b6b3653386e498f107e76ee37784fb4d94 Mon Sep 17 00:00:00 2001 From: mpv Date: Mon, 17 Aug 2015 16:50:54 +0300 Subject: [PATCH] Issue #661: on abort, undo or redo of operation, only the updated features are updated, not everything. --- src/Model/Model_Document.cpp | 52 +++++++++++++++++++++++++++++++----- src/Model/Model_Objects.cpp | 22 ++++++++++++--- src/Model/Model_Objects.h | 5 ++-- src/Model/Model_Session.cpp | 6 +++-- 4 files changed, 71 insertions(+), 14 deletions(-) diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index efdc253aa..3a2cb0d2c 100644 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -28,8 +28,12 @@ #include #include #include +#include #include #include +#include +#include +#include #include #ifndef WIN32 @@ -383,10 +387,37 @@ bool Model_Document::finishOperation() return aResult; } +/// Returns in theDelta labels that has been modified in the latest transaction of theDoc +static void modifiedLabels(const Handle(TDocStd_Document)& theDoc, TDF_LabelList& theDelta, + const bool isRedo = false) { + Handle(TDF_Delta) aDelta; + if (isRedo) + aDelta = theDoc->GetRedos().First(); + else + aDelta = theDoc->GetUndos().Last(); + aDelta->Labels(theDelta); + // add also label of the modified attributes + const TDF_AttributeDeltaList& anAttrs = aDelta->AttributeDeltas(); + for (TDF_ListIteratorOfAttributeDeltaList anAttr(anAttrs); anAttr.More(); anAttr.Next()) { + theDelta.Append(anAttr.Value()->Label()); + } +} + void Model_Document::abortOperation() { + TDF_LabelList aDeltaLabels; // labels that are updated during "abort" if (!myNestedNum.empty() && !myDoc->HasOpenCommand()) { // abort all what was done in nested compactNested(); + // store undo-delta here as undo actually does in the method later + int a, aNumTransactions = myTransactions.rbegin()->myOCAFNum; + for(a = 0; a < aNumTransactions; a++) { + modifiedLabels(myDoc, aDeltaLabels); + myDoc->Undo(); + } + for(a = 0; a < aNumTransactions; a++) { + myDoc->Redo(); + } + undoInternal(false, false); myDoc->ClearRedos(); myRedos.clear(); @@ -397,8 +428,10 @@ void Model_Document::abortOperation() (*myNestedNum.rbegin())--; // roll back the needed number of transactions myDoc->AbortCommand(); - for(int a = 0; a < aNumTransactions; a++) + for(int a = 0; a < aNumTransactions; a++) { + modifiedLabels(myDoc, aDeltaLabels); myDoc->Undo(); + } myDoc->ClearRedos(); } // abort for all subs, flushes will be later, in the end of root abort @@ -407,7 +440,7 @@ void Model_Document::abortOperation() for (; aSubIter != aSubs.end(); aSubIter++) subDoc(*aSubIter)->abortOperation(); // references may be changed because they are set in attributes on the fly - myObjs->synchronizeFeatures(true, true, isRoot()); + myObjs->synchronizeFeatures(aDeltaLabels, true, isRoot()); } bool Model_Document::isOperation() const @@ -452,8 +485,12 @@ void Model_Document::undoInternal(const bool theWithSubs, const bool theSynchron if (!myNestedNum.empty()) (*myNestedNum.rbegin())--; // roll back the needed number of transactions - for(int a = 0; a < aNumTransactions; a++) + TDF_LabelList aDeltaLabels; + for(int a = 0; a < aNumTransactions; a++) { + if (theSynchronize) + modifiedLabels(myDoc, aDeltaLabels); myDoc->Undo(); + } if (theWithSubs) { // undo for all subs @@ -467,7 +504,7 @@ void Model_Document::undoInternal(const bool theWithSubs, const bool theSynchron } // after redo of all sub-documents to avoid updates on not-modified data (issue 370) if (theSynchronize) { - myObjs->synchronizeFeatures(true, true, isRoot()); + myObjs->synchronizeFeatures(aDeltaLabels, true, isRoot()); // update the current features status setCurrentFeature(currentFeature(false), false); } @@ -501,8 +538,11 @@ void Model_Document::redo() int aNumRedos = myRedos.rbegin()->myOCAFNum; myTransactions.push_back(*myRedos.rbegin()); myRedos.pop_back(); - for(int a = 0; a < aNumRedos; a++) + TDF_LabelList aDeltaLabels; + for(int a = 0; a < aNumRedos; a++) { + modifiedLabels(myDoc, aDeltaLabels, true); myDoc->Redo(); + } // redo for all subs const std::set aSubs = subDocuments(true); @@ -511,7 +551,7 @@ void Model_Document::redo() subDoc(*aSubIter)->redo(); // after redo of all sub-documents to avoid updates on not-modified data (issue 370) - myObjs->synchronizeFeatures(true, true, isRoot()); + myObjs->synchronizeFeatures(aDeltaLabels, true, isRoot()); // update the current features status setCurrentFeature(currentFeature(false), false); } diff --git a/src/Model/Model_Objects.cpp b/src/Model/Model_Objects.cpp index 6375e4e2c..49e922a80 100644 --- a/src/Model/Model_Objects.cpp +++ b/src/Model/Model_Objects.cpp @@ -31,6 +31,8 @@ #include #include #include +#include +#include static const int TAG_OBJECTS = 2; // tag of the objects sub-tree (features, results) @@ -51,7 +53,8 @@ void Model_Objects::setOwner(DocumentPtr theDoc) { myDoc = theDoc; // update all fields and recreate features and result objects if needed - synchronizeFeatures(false, true, true); + TDF_LabelList aNoUpdated; + synchronizeFeatures(aNoUpdated, true, true); myHistory.clear(); } @@ -542,7 +545,7 @@ void Model_Objects::initData(ObjectPtr theObj, TDF_Label theLab, const int theTa } void Model_Objects::synchronizeFeatures( - const bool theMarkUpdated, const bool theUpdateReferences, const bool theFlush) + const TDF_LabelList& theUpdated, const bool theUpdateReferences, const bool theFlush) { Model_Document* anOwner = std::dynamic_pointer_cast(myDoc).get(); if (!anOwner) // this may happen on creation of document: nothing there, so nothing to synchronize @@ -557,6 +560,17 @@ void Model_Objects::synchronizeFeatures( static Events_ID aToHideEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); bool isActive = aLoop->activateFlushes(false); + // collect all updated labels map + TDF_LabelMap anUpdatedMap; + TDF_ListIteratorOfLabelList anUpdatedIter(theUpdated); + for(; anUpdatedIter.More(); anUpdatedIter.Next()) { + TDF_Label& aFeatureLab = anUpdatedIter.Value(); + while(aFeatureLab.Depth() > 3) + aFeatureLab = aFeatureLab.Father(); + if (myFeatures.IsBound(aFeatureLab)) + anUpdatedMap.Add(aFeatureLab); + } + // update all objects by checking are they on labels or not std::set aNewFeatures, aKeptFeatures; TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID()); @@ -585,7 +599,7 @@ void Model_Objects::synchronizeFeatures( } else { // nothing is changed, both iterators are incremented aFeature = myFeatures.Find(aFeatureLabel); aKeptFeatures.insert(aFeature); - if (theMarkUpdated) { + if (anUpdatedMap.Contains(aFeatureLabel)) { ModelAPI_EventCreator::get()->sendUpdated(aFeature, anUpdateEvent); } } @@ -639,7 +653,7 @@ void Model_Objects::synchronizeFeatures( if (theUpdateReferences) { synchronizeBackRefs(); } - if (theMarkUpdated) { // this means there is no control what was modified => remove history cash + if (!theUpdated.IsEmpty()) { // this means there is no control what was modified => remove history cash myHistory.clear(); } diff --git a/src/Model/Model_Objects.h b/src/Model/Model_Objects.h index 91124d483..114be09df 100644 --- a/src/Model/Model_Objects.h +++ b/src/Model/Model_Objects.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -137,10 +138,10 @@ class Model_Objects void setUniqueName(FeaturePtr theFeature); //! Synchronizes myFeatures list with the updated document - //! \param theMarkUpdated causes the "update" event for all features + //! \param theUpdated list of labels that are marked as modified, so featrues must be also //! \param theUpdateReferences causes the update of back-references //! \param theFlush makes flush all events in the end of all modifications of this method - void synchronizeFeatures(const bool theMarkUpdated, const bool theUpdateReferences, + void synchronizeFeatures(const TDF_LabelList& theUpdated, const bool theUpdateReferences, const bool theFlush); //! Synchronizes the BackReferences list in Data of Features and Results void synchronizeBackRefs(); diff --git a/src/Model/Model_Session.cpp b/src/Model/Model_Session.cpp index ff74e5bf3..e66e434a1 100644 --- a/src/Model/Model_Session.cpp +++ b/src/Model/Model_Session.cpp @@ -240,7 +240,8 @@ void Model_Session::setActiveDocument( if (aDoc.get()) { bool aWasChecked = myCheckTransactions; setCheckTransactions(false); - aDoc->objects()->synchronizeFeatures(false, true, true); + TDF_LabelList anEmptyUpdated; + aDoc->objects()->synchronizeFeatures(anEmptyUpdated, true, true); if (aWasChecked) setCheckTransactions(true); } @@ -314,7 +315,8 @@ std::shared_ptr Model_Session::copy( aRT->SetRelocation(aSourceRoot, aTargetRoot); TDF_CopyTool::Copy(aDS, aRT); - aNew->objects()->synchronizeFeatures(false, true, true); + TDF_LabelList anEmptyUpdated; + aNew->objects()->synchronizeFeatures(anEmptyUpdated, true, true); return aNew; } -- 2.39.2