#include <TDF_Reference.hxx>
#include <TDF_ChildIDIterator.hxx>
#include <TDF_LabelMapHasher.hxx>
+#include <TDF_Delta.hxx>
#include <OSD_File.hxx>
#include <OSD_Path.hxx>
+#include <TDF_AttributeDelta.hxx>
+#include <TDF_AttributeDeltaList.hxx>
+#include <TDF_ListIteratorOfAttributeDeltaList.hxx>
#include <climits>
#ifndef WIN32
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();
(*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
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
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
}
// 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);
}
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<std::string> aSubs = subDocuments(true);
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);
}
#include <TDF_Reference.hxx>
#include <TDF_ChildIDIterator.hxx>
#include <TDF_LabelMapHasher.hxx>
+#include <TDF_LabelMap.hxx>
+#include <TDF_ListIteratorOfLabelList.hxx>
static const int TAG_OBJECTS = 2; // tag of the objects sub-tree (features, results)
{
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();
}
}
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<Model_Document>(myDoc).get();
if (!anOwner) // this may happen on creation of document: nothing there, so nothing to synchronize
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<FeaturePtr> aNewFeatures, aKeptFeatures;
TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
} 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);
}
}
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();
}
#include <TDocStd_Document.hxx>
#include <NCollection_DataMap.hxx>
#include <TDF_Label.hxx>
+#include <TDF_LabelList.hxx>
#include <map>
#include <set>
#include <vector>
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();
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);
}
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;
}