X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_Document.cpp;h=557ee00e59e6fc53e2e96ee73eccc9793c3df541;hb=2f89053146098946372bae4d1a3fe2e5272ab9e2;hp=8b792974cea3f10c2ac8c2efb494ce8231b7ea5c;hpb=730e32c2a13c666f4d76808b4904c5727e3d11af;p=modules%2Fshaper.git diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index 8b792974c..557ee00e5 100644 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -1,3 +1,5 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + // File: Model_Document.cxx // Created: 28 Feb 2014 // Author: Mikhail PONIKAROV @@ -10,12 +12,13 @@ #include #include #include +#include +#include #include #include #include #include -#include #include #include #include @@ -23,6 +26,8 @@ #include #include #include +#include +#include #include #ifndef WIN32 @@ -49,11 +54,11 @@ Model_Document::Model_Document(const std::string theID, const std::string theKin : myID(theID), myKind(theKind), myDoc(new TDocStd_Document("BinOcaf")) // binary OCAF format { - myDoc->SetUndoLimit(UNDO_LIMIT); - myTransactionsAfterSave = 0; + myDoc->SetUndoLimit(UNDO_LIMIT); + myTransactionsCounter = 0; + myTransactionSave = 0; myNestedNum = -1; myExecuteFeatures = true; - //myDoc->SetNestedTransactionMode(); // to have something in the document and avoid empty doc open/save problem // in transaction for nesting correct working myDoc->NewCommand(); @@ -146,7 +151,11 @@ bool Model_Document::load(const char* theFileName) } if (!isError) { myDoc->SetUndoLimit(UNDO_LIMIT); - synchronizeFeatures(); + // 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); } return !isError; } @@ -154,6 +163,7 @@ bool Model_Document::load(const char* theFileName) bool Model_Document::save(const char* theFileName, std::list& theResults) { // 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()) { #ifdef WIN32 CreateDirectory(theFileName, NULL); @@ -165,7 +175,7 @@ bool Model_Document::save(const char* theFileName, std::list& theRe TCollection_ExtendedString aPath(DocFileName(theFileName, myID)); PCDM_StoreStatus aStatus; try { - aStatus = Model_Application::getApplication()->SaveAs(myDoc, aPath); + aStatus = anApp->SaveAs(myDoc, aPath); } catch (Standard_Failure) { Handle(Standard_Failure) aFail = Standard_Failure::Caught(); Events_Error::send( @@ -187,34 +197,81 @@ bool Model_Document::save(const char* theFileName, std::list& theRe break; } } - myTransactionsAfterSave = 0; + myTransactionSave = myTransactionsCounter; if (isDone) { // save also sub-documents if any theResults.push_back(TCollection_AsciiString(aPath).ToCString()); std::set::iterator aSubIter = mySubs.begin(); for (; aSubIter != mySubs.end() && isDone; aSubIter++) { isDone = subDoc(*aSubIter)->save(theFileName, theResults); } + if (isDone) { // also try to copy the not-activated sub-documents + // they are not in mySubs but as ResultParts + int aPartsNum = size(ModelAPI_ResultPart::group()); + for(int aPart = 0; aPart < aPartsNum; aPart++) { + ResultPartPtr aPartRes = std::dynamic_pointer_cast + (object(ModelAPI_ResultPart::group(), aPart)); + if (aPartRes) { + std::string aDocName = aPartRes->data()->name(); + if (!aDocName.empty() && mySubs.find(aDocName) == mySubs.end()) { + // just copy file + TCollection_AsciiString aSubPath(DocFileName(anApp->loadPath().c_str(), aDocName)); + OSD_Path aPath(aSubPath); + OSD_File aFile(aPath); + if (aFile.Exists()) { + TCollection_AsciiString aDestinationDir(DocFileName(theFileName, aDocName)); + OSD_Path aDestination(aDestinationDir); + aFile.Copy(aDestination); + } else { + Events_Error::send( + std::string("Can not open file ") + aSubPath.ToCString() + " for saving"); + } + } + } + } + } } return isDone; } -void Model_Document::close() +void Model_Document::close(const bool theForever) { - boost::shared_ptr aPM = Model_Session::get(); + std::shared_ptr aPM = Model_Session::get(); if (this != aPM->moduleDocument().get() && this == aPM->activeDocument().get()) { aPM->setActiveDocument(aPM->moduleDocument()); } // close all subs std::set::iterator aSubIter = mySubs.begin(); for (; aSubIter != mySubs.end(); aSubIter++) - subDoc(*aSubIter)->close(); + subDoc(*aSubIter)->close(theForever); mySubs.clear(); - // close this - /* do not close because it can be undoed - if (myDoc->CanClose() == CDM_CCS_OK) - myDoc->Close(); - Model_Application::getApplication()->deleteDocument(myID); - */ + + // close for thid document needs no transaction in this document + std::static_pointer_cast(Model_Session::get())->setCheckTransactions(false); + + // delete all features of this document + std::shared_ptr aThis = + Model_Application::getApplication()->getDocument(myID); + Events_Loop* aLoop = Events_Loop::loop(); + NCollection_DataMap::Iterator aFeaturesIter(myObjs); + for(; aFeaturesIter.More(); aFeaturesIter.Next()) { + FeaturePtr aFeature = aFeaturesIter.Value(); + static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); + ModelAPI_EventCreator::get()->sendDeleted(aThis, ModelAPI_Feature::group()); + ModelAPI_EventCreator::get()->sendUpdated(aFeature, EVENT_DISP); + aFeature->eraseResults(); + aFeature->erase(); + } + myObjs.Clear(); + aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED)); + aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); + + // close all only if it is really asked, otherwise it can be undoed/redoed + if (theForever) { + if (myDoc->CanClose() == CDM_CCS_OK) + myDoc->Close(); + } + + std::static_pointer_cast(Model_Session::get())->setCheckTransactions(true); } void Model_Document::startOperation() @@ -224,8 +281,8 @@ void Model_Document::startOperation() myNestedNum = 0; myDoc->InitDeltaCompaction(); } - myIsEmptyTr[myTransactionsAfterSave] = !myDoc->CommitCommand(); - myTransactionsAfterSave++; + myIsEmptyTr[myTransactionsCounter] = !myDoc->CommitCommand(); + myTransactionsCounter++; myDoc->OpenCommand(); } else { // start the simple command myDoc->NewCommand(); @@ -240,39 +297,60 @@ bool Model_Document::compactNested() { bool allWasEmpty = true; while (myNestedNum != -1) { - myTransactionsAfterSave--; - if (!myIsEmptyTr[myTransactionsAfterSave]) { + myTransactionsCounter--; + if (!myIsEmptyTr[myTransactionsCounter]) { allWasEmpty = false; } - myIsEmptyTr.erase(myTransactionsAfterSave); + myIsEmptyTr.erase(myTransactionsCounter); myNestedNum--; } - myIsEmptyTr[myTransactionsAfterSave] = allWasEmpty; - myTransactionsAfterSave++; - myDoc->PerformDeltaCompaction(); + myIsEmptyTr[myTransactionsCounter] = allWasEmpty; + myTransactionsCounter++; + if (allWasEmpty) { + // Issue 151: if everything is empty, it is a problem for OCCT to work with it, + // just commit the empty that returns nothing + myDoc->CommitCommand(); + } else { + myDoc->PerformDeltaCompaction(); + } return !allWasEmpty; } void Model_Document::finishOperation() { - // finish for all subs first: to avoid nested finishing and "isOperation" calls problems inside - std::set::iterator aSubIter = mySubs.begin(); - for (; aSubIter != mySubs.end(); aSubIter++) - subDoc(*aSubIter)->finishOperation(); - // just to be sure that everybody knows that changes were performed if (!myDoc->HasOpenCommand() && myNestedNum != -1) - boost::static_pointer_cast(Model_Session::get()) + std::static_pointer_cast(Model_Session::get()) ->setCheckTransactions(false); // for nested transaction commit + synchronizeBackRefs(); Events_Loop* aLoop = Events_Loop::loop(); aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED)); 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)); aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED)); + // 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 + Events_Loop::loop()->autoFlush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); + static std::shared_ptr aFinishMsg + (new Events_Message(Events_Loop::eventByName("FinishOperation"))); + Events_Loop::loop()->send(aFinishMsg); + Events_Loop::loop()->autoFlush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED), false); + } + // to avoid "updated" message appearance by updater + //aLoop->clear(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); + if (!myDoc->HasOpenCommand() && myNestedNum != -1) - boost::static_pointer_cast(Model_Session::get()) + std::static_pointer_cast(Model_Session::get()) ->setCheckTransactions(true); // for nested transaction commit + // finish for all subs first: to avoid nested finishing and "isOperation" calls problems inside + std::set::iterator aSubIter = mySubs.begin(); + for (; aSubIter != mySubs.end(); aSubIter++) + subDoc(*aSubIter)->finishOperation(); + if (myNestedNum != -1) // this nested transaction is owervritten myNestedNum++; if (!myDoc->HasOpenCommand()) { @@ -282,10 +360,9 @@ void Model_Document::finishOperation() } } else { // returns false if delta is empty and no transaction was made - myIsEmptyTr[myTransactionsAfterSave] = !myDoc->CommitCommand(); // && (myNestedNum == -1); - myTransactionsAfterSave++; + myIsEmptyTr[myTransactionsCounter] = !myDoc->CommitCommand(); // && (myNestedNum == -1); + myTransactionsCounter++; } - } void Model_Document::abortOperation() @@ -293,18 +370,17 @@ void Model_Document::abortOperation() if (myNestedNum > 0 && !myDoc->HasOpenCommand()) { // abort all what was done in nested // first compact all nested if (compactNested()) { - // for nested it is undo and clear redos - myDoc->Undo(); + myDoc->Undo(); // undo only compacted, if not: do not undo the empty transaction } myDoc->ClearRedos(); - myTransactionsAfterSave--; - myIsEmptyTr.erase(myTransactionsAfterSave); + myTransactionsCounter--; + myIsEmptyTr.erase(myTransactionsCounter); } else { if (myNestedNum == 0) // abort only high-level myNestedNum = -1; myDoc->AbortCommand(); } - synchronizeFeatures(true); + synchronizeFeatures(true, false); // references were not changed since transaction start // abort for all subs std::set::iterator aSubIter = mySubs.begin(); for (; aSubIter != mySubs.end(); aSubIter++) @@ -320,13 +396,13 @@ bool Model_Document::isOperation() bool Model_Document::isModified() { // is modified if at least one operation was commited and not undoed - return myTransactionsAfterSave > 0 || isOperation(); + return myTransactionsCounter != myTransactionSave || isOperation(); } bool Model_Document::canUndo() { if (myDoc->GetAvailableUndos() > 0 && myNestedNum != 0 - && myTransactionsAfterSave != 0 /* for omitting the first useless transaction */) + && myTransactionsCounter != 0 /* for omitting the first useless transaction */) return true; // check other subs contains operation that can be undoed std::set::iterator aSubIter = mySubs.begin(); @@ -338,12 +414,12 @@ bool Model_Document::canUndo() void Model_Document::undo() { - myTransactionsAfterSave--; + myTransactionsCounter--; if (myNestedNum > 0) myNestedNum--; - if (!myIsEmptyTr[myTransactionsAfterSave]) + if (!myIsEmptyTr[myTransactionsCounter]) myDoc->Undo(); - synchronizeFeatures(true); + synchronizeFeatures(true, true); // undo for all subs std::set::iterator aSubIter = mySubs.begin(); for (; aSubIter != mySubs.end(); aSubIter++) @@ -366,10 +442,10 @@ void Model_Document::redo() { if (myNestedNum != -1) myNestedNum++; - if (!myIsEmptyTr[myTransactionsAfterSave]) + if (!myIsEmptyTr[myTransactionsCounter]) myDoc->Redo(); - myTransactionsAfterSave++; - synchronizeFeatures(true); + myTransactionsCounter++; + synchronizeFeatures(true, true); // redo for all subs std::set::iterator aSubIter = mySubs.begin(); for (; aSubIter != mySubs.end(); aSubIter++) @@ -399,7 +475,9 @@ FeaturePtr Model_Document::addFeature(std::string theID) TDF_Label anEmptyLab; FeaturePtr anEmptyFeature; FeaturePtr aFeature = ModelAPI_Session::get()->createFeature(theID); - boost::shared_ptr aDocToAdd = boost::dynamic_pointer_cast( + if (!aFeature) + return aFeature; + std::shared_ptr aDocToAdd = std::dynamic_pointer_cast( aFeature->documentToAdd()); if (aFeature) { TDF_Label aFeatureLab; @@ -465,48 +543,34 @@ void Model_Document::removeFeature(FeaturePtr theFeature, const bool 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++) { - if (myConcealedResults.find(*aResIter) != myConcealedResults.end()) { - Events_Error::send("Feature '" + theFeature->data()->name() + "' is used and can not be deleted"); - return; - } - } - NCollection_DataMap::Iterator anObjIter(myObjs); - for(; anObjIter.More(); anObjIter.Next()) { - DataPtr aData = anObjIter.Value()->data(); - if (aData->referencesTo(theFeature)) { - Events_Error::send("Feature '" + theFeature->data()->name() + "' is used and can not be deleted"); + 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; } } } - boost::shared_ptr aData = boost::static_pointer_cast(theFeature->data()); - TDF_Label aFeatureLabel = aData->label().Father(); - if (myObjs.IsBound(aFeatureLabel)) - myObjs.UnBind(aFeatureLabel); - else - return; // not found feature => do not remove - // erase fields - theFeature->erase(); - // erase all attributes under the label of feature - aFeatureLabel.ForgetAllAttributes(); - // remove it from the references array - RemoveFromRefArray(featuresLabel(), aFeatureLabel); - + std::shared_ptr aData = std::static_pointer_cast(theFeature->data()); + if (aData) { + TDF_Label aFeatureLabel = aData->label().Father(); + if (myObjs.IsBound(aFeatureLabel)) + myObjs.UnBind(aFeatureLabel); + else + return; // not found feature => do not remove + // erase fields + theFeature->erase(); + // 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()); - /* this is in "erase" - // results of this feature must be redisplayed - static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY); - const std::list >& aResults = theFeature->results(); - std::list >::const_iterator aRIter = aResults.begin(); - for (; aRIter != aResults.cend(); aRIter++) { - boost::shared_ptr aRes = *aRIter; - aRes->setData(boost::shared_ptr()); // deleted flag - ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP); - ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), aRes->groupName()); - } - */ } FeaturePtr Model_Document::feature(TDF_Label& theLabel) @@ -525,10 +589,10 @@ ObjectPtr Model_Document::object(TDF_Label theLabel) TDF_Label aFeatureLabel = theLabel.Father().Father(); // let's suppose it is result aFeature = feature(aFeatureLabel); if (aFeature) { - const std::list >& aResults = aFeature->results(); - std::list >::const_iterator aRIter = aResults.cbegin(); + const std::list >& aResults = aFeature->results(); + std::list >::const_iterator aRIter = aResults.cbegin(); for (; aRIter != aResults.cend(); aRIter++) { - boost::shared_ptr aResData = boost::dynamic_pointer_cast( + std::shared_ptr aResData = std::dynamic_pointer_cast( (*aRIter)->data()); if (aResData->label().Father().IsEqual(theLabel)) return *aRIter; @@ -537,7 +601,7 @@ ObjectPtr Model_Document::object(TDF_Label theLabel) return FeaturePtr(); // not found } -boost::shared_ptr Model_Document::subDocument(std::string theDocID) +std::shared_ptr Model_Document::subDocument(std::string theDocID) { // just store sub-document identifier here to manage it later if (mySubs.find(theDocID) == mySubs.end()) @@ -545,12 +609,12 @@ boost::shared_ptr Model_Document::subDocument(std::string the return Model_Application::getApplication()->getDocument(theDocID); } -boost::shared_ptr Model_Document::subDoc(std::string theDocID) +std::shared_ptr Model_Document::subDoc(std::string theDocID) { // just store sub-document identifier here to manage it later if (mySubs.find(theDocID) == mySubs.end()) mySubs.insert(theDocID); - return boost::dynamic_pointer_cast( + return std::dynamic_pointer_cast( Model_Application::getApplication()->getDocument(theDocID)); } @@ -584,13 +648,13 @@ ObjectPtr Model_Document::object(const std::string& theGroupID, const int theInd 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(); + const std::list >& aResults = aFeature->results(); + std::list >::const_iterator aRIter = aResults.begin(); for (; aRIter != aResults.cend(); aRIter++) { if ((*aRIter)->groupName() != theGroupID) continue; - bool isIn = theHidden; + bool isIn = theHidden && (*aRIter)->isInHistory(); if (!isIn && (*aRIter)->isInHistory()) { // check that there is nobody references this result - isIn = myConcealedResults.find(*aRIter) == myConcealedResults.end(); + isIn = !(*aRIter)->isConcealed(); } if (isIn) { if (anIndex == theIndex) @@ -621,13 +685,15 @@ int Model_Document::size(const std::string& theGroupID, const bool theHidden) 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(); + if (!aFeature) // may be on close + continue; + const std::list >& aResults = aFeature->results(); + std::list >::const_iterator aRIter = aResults.begin(); for (; aRIter != aResults.cend(); aRIter++) { if ((*aRIter)->groupName() != theGroupID) continue; bool isIn = theHidden; if (!isIn && (*aRIter)->isInHistory()) { // check that there is nobody references this result - isIn = myConcealedResults.find(*aRIter) == myConcealedResults.end(); + isIn = !(*aRIter)->isConcealed(); } if (isIn) aResult++; @@ -662,12 +728,12 @@ void Model_Document::setUniqueName(FeaturePtr theFeature) // check this is unique, if not, increase index by 1 for (aFIter.Initialize(myObjs); aFIter.More();) { FeaturePtr aFeature = aFIter.Value(); - bool isSameName = aFeature->isInHistory() && aFeature->data()->name() == aName; + bool isSameName = aFeature->data()->name() == aName; if (!isSameName) { // check also results to avoid same results names (actual for Parts) - const std::list >& aResults = aFeature->results(); - std::list >::const_iterator aRIter = aResults.begin(); + const std::list >& aResults = aFeature->results(); + std::list >::const_iterator aRIter = aResults.begin(); for (; aRIter != aResults.cend(); aRIter++) { - isSameName = (*aRIter)->isInHistory() && (*aRIter)->data()->name() == aName; + isSameName = (*aRIter)->data()->name() == aName; } } if (isSameName) { @@ -685,26 +751,26 @@ void Model_Document::setUniqueName(FeaturePtr theFeature) void Model_Document::initData(ObjectPtr theObj, TDF_Label theLab, const int theTag) { - boost::shared_ptr aThis = Model_Application::getApplication()->getDocument( + std::shared_ptr aThis = Model_Application::getApplication()->getDocument( myID); - boost::shared_ptr aData(new Model_Data); + std::shared_ptr aData(new Model_Data); aData->setLabel(theLab.FindChild(theTag)); aData->setObject(theObj); theObj->setDoc(aThis); theObj->setData(aData); - FeaturePtr aFeature = boost::dynamic_pointer_cast(theObj); + FeaturePtr aFeature = std::dynamic_pointer_cast(theObj); if (aFeature) { setUniqueName(aFeature); // must be before "initAttributes" because duplicate part uses name aFeature->initAttributes(); } } -void Model_Document::synchronizeFeatures(const bool theMarkUpdated) +void Model_Document::synchronizeFeatures(const bool theMarkUpdated, const bool theUpdateReferences) { - boost::shared_ptr aThis = + std::shared_ptr aThis = Model_Application::getApplication()->getDocument(myID); // after all updates, sends a message that groups of features were created or updated - boost::static_pointer_cast(Model_Session::get()) + std::static_pointer_cast(Model_Session::get()) ->setCheckTransactions(false); Events_Loop* aLoop = Events_Loop::loop(); aLoop->activateFlushes(false); @@ -714,42 +780,44 @@ void Model_Document::synchronizeFeatures(const bool theMarkUpdated) TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID()); for (; aLabIter.More(); aLabIter.Next()) { TDF_Label aFeatureLabel = aLabIter.Value()->Label(); + FeaturePtr aFeature; if (!myObjs.IsBound(aFeatureLabel)) { // a new feature is inserted // create a feature - FeaturePtr aNewObj = ModelAPI_Session::get()->createFeature( + aFeature = ModelAPI_Session::get()->createFeature( TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(aLabIter.Value())->Get()) .ToCString()); - if (!aNewObj) { // somethig is wrong, most probably, the opened document has invalid structure + 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(); continue; } // this must be before "setData" to redo the sketch line correctly - myObjs.Bind(aFeatureLabel, aNewObj); - aNewFeatures.insert(aNewObj); - initData(aNewObj, aFeatureLabel, TAG_FEATURE_ARGUMENTS); + myObjs.Bind(aFeatureLabel, aFeature); + aNewFeatures.insert(aFeature); + initData(aFeature, aFeatureLabel, TAG_FEATURE_ARGUMENTS); // event: model is updated static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED); - ModelAPI_EventCreator::get()->sendUpdated(aNewObj, anEvent); - - // update results of the appeared feature - updateResults(aNewObj); + ModelAPI_EventCreator::get()->sendUpdated(aFeature, anEvent); } else { // nothing is changed, both iterators are incremented - FeaturePtr aFeature = myObjs.Find(aFeatureLabel); + 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); } + } + } + // update results of thefeatures (after features created because they may be connected, like sketch and sub elements) + TDF_ChildIDIterator aLabIter2(featuresLabel(), TDataStd_Comment::GetID()); + for (; aLabIter2.More(); aLabIter2.Next()) { + TDF_Label aFeatureLabel = aLabIter2.Value()->Label(); + if (myObjs.IsBound(aFeatureLabel)) { // a new feature is inserted + FeaturePtr aFeature = myObjs.Find(aFeatureLabel); updateResults(aFeature); } } - // execute new features to restore results: after features creation to make all references valid - /*std::set::iterator aNewIter = aNewFeatures.begin(); - for(; aNewIter != aNewFeatures.end(); aNewIter++) { - (*aNewIter)->execute(); - }*/ + // check all features are checked: if not => it was removed NCollection_DataMap::Iterator aFIter(myObjs); while (aFIter.More()) { @@ -762,16 +830,8 @@ void Model_Document::synchronizeFeatures(const bool theMarkUpdated) //} // 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(); - /* - for (; aRIter != aResults.cend(); aRIter++) { - boost::shared_ptr aRes = *aRIter; - //aRes->setData(boost::shared_ptr()); // deleted flag - ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP); - ModelAPI_EventCreator::get()->sendDeleted(aThis, aRes->groupName()); - } - */ + 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(); @@ -783,33 +843,102 @@ void Model_Document::synchronizeFeatures(const bool theMarkUpdated) aFIter.Next(); } + if (theUpdateReferences) { + synchronizeBackRefs(); + } + myExecuteFeatures = false; aLoop->activateFlushes(true); aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED)); aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED)); - if (theMarkUpdated) { - aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); - } + aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); - boost::static_pointer_cast(Model_Session::get()) + aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TOHIDE)); + std::static_pointer_cast(Model_Session::get()) ->setCheckTransactions(true); myExecuteFeatures = true; } +void Model_Document::synchronizeBackRefs() +{ + std::shared_ptr aThis = + Model_Application::getApplication()->getDocument(myID); + // keeps the concealed flags of result to catch the change and create created/deleted events + std::list > aConcealed; + // first cycle: erase all data about back-references + NCollection_DataMap::Iterator aFeatures(myObjs); + for(; aFeatures.More(); aFeatures.Next()) { + FeaturePtr aFeature = aFeatures.Value(); + std::shared_ptr aFData = + std::dynamic_pointer_cast(aFeature->data()); + if (aFData) { + aFData->eraseBackReferences(); + } + const std::list >& aResults = aFeature->results(); + std::list >::const_iterator aRIter = aResults.begin(); + for (; aRIter != aResults.cend(); aRIter++) { + std::shared_ptr aResData = + std::dynamic_pointer_cast((*aRIter)->data()); + if (aResData) { + aConcealed.push_back(std::pair(*aRIter, (*aRIter)->isConcealed())); + aResData->eraseBackReferences(); + } + } + } + + // second cycle: set new back-references: only features may have reference, iterate only them + ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators(); + for(aFeatures.Initialize(myObjs); aFeatures.More(); aFeatures.Next()) { + FeaturePtr aFeature = aFeatures.Value(); + std::shared_ptr aFData = + std::dynamic_pointer_cast(aFeature->data()); + if (aFData) { + std::list > > aRefs; + aFData->referencesToObjects(aRefs); + std::list > >::iterator aRefsIter = aRefs.begin(); + for(; aRefsIter != aRefs.end(); aRefsIter++) { + std::list::iterator aRefTo = aRefsIter->second.begin(); + for(; aRefTo != aRefsIter->second.end(); aRefTo++) { + if (*aRefTo) { + std::shared_ptr aRefData = + std::dynamic_pointer_cast((*aRefTo)->data()); + aRefData->addBackReference(aFeature, aRefsIter->first); // here the Concealed flag is updated + } + } + } + } + } + std::list >::iterator aCIter = aConcealed.begin(); + for(; aCIter != aConcealed.end(); aCIter++) { + if (aCIter->first->isConcealed() != aCIter->second) { // somethign is changed => produce event + if (aCIter->second) { // was concealed become not => creation event + static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED); + ModelAPI_EventCreator::get()->sendUpdated(aCIter->first, anEvent); + } else { // was not concealed become concealed => delete event + ModelAPI_EventCreator::get()->sendDeleted(aThis, aCIter->first->groupName()); + // redisplay for the viewer (it must be disappeared also) + static Events_ID EVENT_DISP = + Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY); + ModelAPI_EventCreator::get()->sendUpdated(aCIter->first, EVENT_DISP); + } + } + } +} + TDF_Label Model_Document::resultLabel( - const boost::shared_ptr& theFeatureData, const int theResultIndex) + const std::shared_ptr& theFeatureData, const int theResultIndex) { - const boost::shared_ptr& aData = - boost::dynamic_pointer_cast(theFeatureData); + const std::shared_ptr& aData = + std::dynamic_pointer_cast(theFeatureData); return aData->label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theResultIndex + 1); } -void Model_Document::storeResult(boost::shared_ptr theFeatureData, - boost::shared_ptr theResult, +void Model_Document::storeResult(std::shared_ptr theFeatureData, + std::shared_ptr theResult, const int theResultIndex) { - boost::shared_ptr aThis = + std::shared_ptr aThis = Model_Application::getApplication()->getDocument(myID); theResult->setDoc(aThis); initData(theResult, resultLabel(theFeatureData, theResultIndex), TAG_FEATURE_ARGUMENTS); @@ -818,65 +947,78 @@ void Model_Document::storeResult(boost::shared_ptr theFeatureData } } -static const Standard_GUID ID_CONSTRUCTION("b59fa408-8ab1-42b8-980c-af5adeebe7e4"); -static const Standard_GUID ID_BODY("c1148e9a-9b17-4e9c-9160-18e918fd0013"); -static const Standard_GUID ID_PART("1b3319b9-3e0a-4298-a1dc-3fb5aaf9be59"); +std::shared_ptr Model_Document::createConstruction( + const std::shared_ptr& theFeatureData, const int theIndex) +{ + TDF_Label aLab = resultLabel(theFeatureData, theIndex); + TDataStd_Comment::Set(aLab, ModelAPI_ResultConstruction::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_ResultConstruction); + storeResult(theFeatureData, aResult, theIndex); + } + return aResult; +} -boost::shared_ptr Model_Document::createConstruction( - const boost::shared_ptr& theFeatureData, const int theIndex) +std::shared_ptr Model_Document::createBody( + const std::shared_ptr& theFeatureData, const int theIndex) { TDF_Label aLab = resultLabel(theFeatureData, theIndex); - TDataStd_UAttribute::Set(aLab, ID_CONSTRUCTION); + TDataStd_Comment::Set(aLab, ModelAPI_ResultBody::group().c_str()); ObjectPtr anOldObject = object(aLab); - boost::shared_ptr aResult; + std::shared_ptr aResult; if (anOldObject) { - aResult = boost::dynamic_pointer_cast(anOldObject); + aResult = std::dynamic_pointer_cast(anOldObject); } if (!aResult) { - aResult = boost::shared_ptr(new Model_ResultConstruction); + aResult = std::shared_ptr(new Model_ResultBody); storeResult(theFeatureData, aResult, theIndex); } return aResult; } -boost::shared_ptr Model_Document::createBody( - const boost::shared_ptr& theFeatureData, const int theIndex) +std::shared_ptr Model_Document::createPart( + const std::shared_ptr& theFeatureData, const int theIndex) { TDF_Label aLab = resultLabel(theFeatureData, theIndex); - TDataStd_UAttribute::Set(aLab, ID_BODY); + TDataStd_Comment::Set(aLab, ModelAPI_ResultPart::group().c_str()); ObjectPtr anOldObject = object(aLab); - boost::shared_ptr aResult; + std::shared_ptr aResult; if (anOldObject) { - aResult = boost::dynamic_pointer_cast(anOldObject); + aResult = std::dynamic_pointer_cast(anOldObject); } if (!aResult) { - aResult = boost::shared_ptr(new Model_ResultBody); + aResult = std::shared_ptr(new Model_ResultPart); storeResult(theFeatureData, aResult, theIndex); } return aResult; } -boost::shared_ptr Model_Document::createPart( - const boost::shared_ptr& theFeatureData, const int theIndex) +std::shared_ptr Model_Document::createGroup( + const std::shared_ptr& theFeatureData, const int theIndex) { TDF_Label aLab = resultLabel(theFeatureData, theIndex); - TDataStd_UAttribute::Set(aLab, ID_PART); + TDataStd_Comment::Set(aLab, ModelAPI_ResultGroup::group().c_str()); ObjectPtr anOldObject = object(aLab); - boost::shared_ptr aResult; + std::shared_ptr aResult; if (anOldObject) { - aResult = boost::dynamic_pointer_cast(anOldObject); + aResult = std::dynamic_pointer_cast(anOldObject); } if (!aResult) { - aResult = boost::shared_ptr(new Model_ResultPart); + aResult = std::shared_ptr(new Model_ResultGroup(theFeatureData)); storeResult(theFeatureData, aResult, theIndex); } return aResult; } -boost::shared_ptr Model_Document::feature( - const boost::shared_ptr& theResult) +std::shared_ptr Model_Document::feature( + const std::shared_ptr& theResult) { - boost::shared_ptr aData = boost::dynamic_pointer_cast(theResult->data()); + std::shared_ptr aData = std::dynamic_pointer_cast(theResult->data()); if (aData) { TDF_Label aFeatureLab = aData->label().Father().Father().Father(); return feature(aFeatureLab); @@ -887,11 +1029,11 @@ boost::shared_ptr Model_Document::feature( void Model_Document::updateResults(FeaturePtr theFeature) { // for not persistent is will be done by parametric updater automatically - if (!theFeature->isPersistentResult()) return; + //if (!theFeature->isPersistentResult()) return; // check the existing results and remove them if there is nothing on the label std::list::const_iterator aResIter = theFeature->results().cbegin(); while(aResIter != theFeature->results().cend()) { - ResultBodyPtr aBody = boost::dynamic_pointer_cast(*aResIter); + ResultPtr aBody = std::dynamic_pointer_cast(*aResIter); if (aBody) { if (!aBody->data()->isValid()) { // found a disappeared result => remove it @@ -903,6 +1045,9 @@ void Model_Document::updateResults(FeaturePtr theFeature) } aResIter++; } + // it may be on undo + if (!theFeature->data() || !theFeature->data()->isValid()) + return; // check that results are presented on all labels int aResSize = theFeature->results().size(); TDF_ChildIterator aLabIter(resultLabel(theFeature->data(), 0).Father()); @@ -912,12 +1057,21 @@ void Model_Document::updateResults(FeaturePtr theFeature) ResultPtr aNewBody; if (aResSize <= aResIndex) { TDF_Label anArgLab = aLabIter.Value(); - if (anArgLab.IsAttribute(ID_BODY)) { - aNewBody = createBody(theFeature->data(), aResIndex); - } else if (anArgLab.IsAttribute(ID_PART)) { - aNewBody = createPart(theFeature->data(), aResIndex); - } else if (!anArgLab.IsAttribute(ID_CONSTRUCTION) && anArgLab.FindChild(1).HasAttribute()) { - Events_Error::send("Unknown type of result is found in the document"); + Handle(TDataStd_Comment) aGroup; + if (anArgLab.FindAttribute(TDataStd_Comment::GetID(), aGroup)) { + if (aGroup->Get() == ModelAPI_ResultBody::group().c_str()) { + aNewBody = createBody(theFeature->data(), aResIndex); + } else if (aGroup->Get() == ModelAPI_ResultPart::group().c_str()) { + aNewBody = createPart(theFeature->data(), aResIndex); + } else if (aGroup->Get() == ModelAPI_ResultConstruction::group().c_str()) { + theFeature->execute(); // construction shapes are needed for sketch solver + break; + } else if (aGroup->Get() == ModelAPI_ResultGroup::group().c_str()) { + aNewBody = createGroup(theFeature->data(), aResIndex); + } else { + Events_Error::send(std::string("Unknown type of result is found in the document:") + + TCollection_AsciiString(aGroup->Get()).ToCString()); + } } if (aNewBody) { theFeature->setResult(aNewBody, aResIndex); @@ -926,48 +1080,6 @@ void Model_Document::updateResults(FeaturePtr theFeature) } } -void Model_Document::objectIsReferenced(const ObjectPtr& theObject) -{ - // only bodies are concealed now - ResultBodyPtr aResult = boost::dynamic_pointer_cast(theObject); - if (aResult) { - if (myConcealedResults.find(aResult) != myConcealedResults.end()) { - Events_Error::send(std::string("The object '") + aResult->data()->name() + - "' is already referenced"); - } else { - myConcealedResults.insert(aResult); - boost::shared_ptr aThis = - Model_Application::getApplication()->getDocument(myID); - ModelAPI_EventCreator::get()->sendDeleted(aThis, ModelAPI_ResultBody::group()); - - static Events_Loop* aLoop = Events_Loop::loop(); - static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); - static const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get(); - aECreator->sendUpdated(aResult, EVENT_DISP); - } - } -} - -void Model_Document::objectIsNotReferenced(const ObjectPtr& theObject) -{ - // only bodies are concealed now - ResultBodyPtr aResult = boost::dynamic_pointer_cast(theObject); - if (aResult) { - std::set::iterator aFind = myConcealedResults.find(aResult); - if (aFind != myConcealedResults.end()) { - ResultPtr aFeature = *aFind; - myConcealedResults.erase(aFind); - boost::shared_ptr aThis = - Model_Application::getApplication()->getDocument(myID); - static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED); - ModelAPI_EventCreator::get()->sendUpdated(aFeature, anEvent, false); - } else { - Events_Error::send(std::string("The object '") + aResult->data()->name() + - "' was not referenced '"); - } - } -} - Standard_Integer HashCode(const TDF_Label& theLab, const Standard_Integer theUpper) { return TDF_LabelMapHasher::HashCode(theLab, theUpper);