X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_Document.cpp;h=ee8cebc14c9d0274a1dd486a1638fca540450c17;hb=f367061802012d6909c2619ef6b6c4cba86fc503;hp=b6221cc4c38004413759c2e6f404f4babe9e3bb5;hpb=3c18b31a7fe7f55e86e3c3c647c3b651333c150a;p=modules%2Fshaper.git diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index b6221cc4c..ee8cebc14 100644 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -75,7 +75,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 +84,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 +166,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 +178,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 +246,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()); } @@ -340,7 +346,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"))); @@ -370,7 +376,7 @@ bool Model_Document::finishOperation() if (!aResult && !myTransactions.empty() /* it can be for just created part document */) 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(); @@ -397,7 +403,8 @@ void Model_Document::abortOperation() myDoc->Undo(); myDoc->ClearRedos(); } - synchronizeFeatures(true, false); // references were not changed since transaction start + // references were not changed since transaction start + synchronizeFeatures(true, false, isRoot()); // abort for all subs const std::set aSubs = subDocuments(true); std::set::iterator aSubIter = aSubs.begin(); @@ -405,7 +412,7 @@ void Model_Document::abortOperation() subDoc(*aSubIter)->abortOperation(); } -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 ; @@ -445,8 +452,6 @@ void Model_Document::undoInternal(const bool theWithSubs, const bool theSynchron 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); @@ -454,6 +459,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() @@ -463,7 +471,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); @@ -484,23 +492,28 @@ void Model_Document::redo() 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--) { - aResult.push_back(aTrIter->myId); + if (aSkipCurrent == 0) aResult.push_back(aTrIter->myId); + else aSkipCurrent--; } return aResult; } @@ -545,8 +558,12 @@ FeaturePtr Model_Document::addFeature(std::string theID) FeaturePtr aFeature = ModelAPI_Session::get()->createFeature(theID); if (!aFeature) return aFeature; - std::shared_ptr aDocToAdd = std::dynamic_pointer_cast( - aFeature->documentToAdd()); + Model_Document* aDocToAdd; + if (aFeature->documentToAdd().get()) { // use the customized document to add + aDocToAdd = std::dynamic_pointer_cast(aFeature->documentToAdd()).get(); + } 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 @@ -574,10 +591,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; @@ -682,6 +699,22 @@ void Model_Document::removeFeature(FeaturePtr theFeature/*, const bool theCheck* } } +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); + } +} + FeaturePtr Model_Document::feature(TDF_Label& theLabel) const { if (myObjs.IsBound(theLabel)) @@ -797,6 +830,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; @@ -890,19 +954,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()) { @@ -911,8 +982,8 @@ void Model_Document::synchronizeFeatures(const bool theMarkUpdated, const bool t 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()); + TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(aLabIter.Value())->Get()) + .ToCString()); 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(); @@ -924,18 +995,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()) { @@ -956,23 +1025,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(); } @@ -984,11 +1050,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; } @@ -1028,7 +1096,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++) { @@ -1075,7 +1144,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()); } }