X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_Document.cpp;h=2487b7c30f1b6d0b068a65299380202a0a5fa73b;hb=4b378265f0b502fe00e8af93ce9f2c5739acfc1c;hp=244eb0314369cb483d1403c1b5700853c66b4036;hpb=8b714c0bc3795b0a18977d2fdefbe741a8ef10c0;p=modules%2Fshaper.git diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index 244eb0314..2487b7c30 100644 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -5,11 +5,13 @@ #include #include #include -#include +#include #include #include #include #include +#include +#include #include #include @@ -20,6 +22,8 @@ #include #include #include +#include +#include #include #ifndef WIN32 @@ -32,100 +36,131 @@ # define _separator_ '/' #endif -static const int UNDO_LIMIT = 10; // number of possible undo operations +static const int UNDO_LIMIT = 10; // number of possible undo operations -static const int TAG_GENERAL = 1; // general properties tag -static const int TAG_OBJECTS = 2; // tag of the objects sub-tree (features, results) -static const int TAG_HISTORY = 3; // tag of the history sub-tree (python dump) +static const int TAG_GENERAL = 1; // general properties tag +static const int TAG_OBJECTS = 2; // tag of the objects sub-tree (features, results) +static const int TAG_HISTORY = 3; // tag of the history sub-tree (python dump) // feature sub-labels -static const int TAG_FEATURE_ARGUMENTS = 1; ///< where the arguments are located -static const int TAG_FEATURE_RESULTS = 2; ///< where the results are located +static const int TAG_FEATURE_ARGUMENTS = 1; ///< where the arguments are located +static const int TAG_FEATURE_RESULTS = 2; ///< where the results are located -using namespace std; +Model_Document::Model_Document(const std::string theID, const std::string theKind) + : myID(theID), myKind(theKind), + myDoc(new TDocStd_Document("BinOcaf")) // binary OCAF format +{ + myDoc->SetUndoLimit(UNDO_LIMIT); + myTransactionsAfterSave = 0; + myNestedNum = -1; + myExecuteFeatures = true; + // to have something in the document and avoid empty doc open/save problem + // in transaction for nesting correct working + myDoc->NewCommand(); + TDataStd_Integer::Set(myDoc->Main().Father(), 0); + myDoc->CommitCommand(); +} /// Returns the file name of this document by the nameof directory and identifuer of a document -static TCollection_ExtendedString DocFileName(const char* theFileName, const string& theID) +static TCollection_ExtendedString DocFileName(const char* theFileName, const std::string& theID) { - TCollection_ExtendedString aPath ((const Standard_CString)theFileName); + TCollection_ExtendedString aPath((const Standard_CString) theFileName); + // remove end-separators + while(aPath.Length() && (aPath.Value(aPath.Length()) == '\\' || aPath.Value(aPath.Length()) == '/')) + aPath.Remove(aPath.Length()); aPath += _separator_; aPath += theID.c_str(); - aPath += ".cbf"; // standard binary file extension + aPath += ".cbf"; // standard binary file extension return aPath; } bool Model_Document::load(const char* theFileName) { Handle(Model_Application) anApp = Model_Application::getApplication(); - if (this == Model_PluginManager::get()->rootDocument().get()) { + if (this == Model_Session::get()->moduleDocument().get()) { anApp->setLoadPath(theFileName); } - TCollection_ExtendedString aPath (DocFileName(theFileName, myID)); + TCollection_ExtendedString aPath(DocFileName(theFileName, myID)); PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1; - try - { + try { aStatus = anApp->Open(aPath, myDoc); - } - catch (Standard_Failure) - { + } catch (Standard_Failure) { Handle(Standard_Failure) aFail = Standard_Failure::Caught(); - Events_Error::send(string("Exception in opening of document: ") + aFail->GetMessageString()); + Events_Error::send( + std::string("Exception in opening of document: ") + aFail->GetMessageString()); return false; } bool isError = aStatus != PCDM_RS_OK; - if (isError) - { - switch (aStatus) - { - case PCDM_RS_UnknownDocument: - Events_Error::send(string("Can not open document: PCDM_RS_UnknownDocument")); break; - case PCDM_RS_AlreadyRetrieved: - Events_Error::send(string("Can not open document: PCDM_RS_AlreadyRetrieved")); break; - case PCDM_RS_AlreadyRetrievedAndModified: - Events_Error::send(string("Can not open document: PCDM_RS_AlreadyRetrievedAndModified")); break; - case PCDM_RS_NoDriver: - Events_Error::send(string("Can not open document: PCDM_RS_NoDriver")); break; - case PCDM_RS_UnknownFileDriver: - Events_Error::send(string("Can not open document: PCDM_RS_UnknownFileDriver")); break; - case PCDM_RS_OpenError: - Events_Error::send(string("Can not open document: PCDM_RS_OpenError")); break; - case PCDM_RS_NoVersion: - Events_Error::send(string("Can not open document: PCDM_RS_NoVersion")); break; - case PCDM_RS_NoModel: - Events_Error::send(string("Can not open document: PCDM_RS_NoModel")); break; - case PCDM_RS_NoDocument: - Events_Error::send(string("Can not open document: PCDM_RS_NoDocument")); break; - case PCDM_RS_FormatFailure: - Events_Error::send(string("Can not open document: PCDM_RS_FormatFailure")); break; - case PCDM_RS_TypeNotFoundInSchema: - Events_Error::send(string("Can not open document: PCDM_RS_TypeNotFoundInSchema")); break; - case PCDM_RS_UnrecognizedFileFormat: - Events_Error::send(string("Can not open document: PCDM_RS_UnrecognizedFileFormat")); break; - case PCDM_RS_MakeFailure: - Events_Error::send(string("Can not open document: PCDM_RS_MakeFailure")); break; - case PCDM_RS_PermissionDenied: - Events_Error::send(string("Can not open document: PCDM_RS_PermissionDenied")); break; - case PCDM_RS_DriverFailure: - Events_Error::send(string("Can not open document: PCDM_RS_DriverFailure")); break; - default: - Events_Error::send(string("Can not open document: unknown error")); break; + if (isError) { + switch (aStatus) { + case PCDM_RS_UnknownDocument: + Events_Error::send(std::string("Can not open document: unknown format")); + break; + case PCDM_RS_AlreadyRetrieved: + Events_Error::send(std::string("Can not open document: already opened")); + break; + case PCDM_RS_AlreadyRetrievedAndModified: + Events_Error::send( + std::string("Can not open document: already opened and modified")); + break; + case PCDM_RS_NoDriver: + Events_Error::send(std::string("Can not open document: driver library is not found")); + break; + case PCDM_RS_UnknownFileDriver: + Events_Error::send(std::string("Can not open document: unknown driver for opening")); + break; + case PCDM_RS_OpenError: + Events_Error::send(std::string("Can not open document: file open error")); + break; + case PCDM_RS_NoVersion: + Events_Error::send(std::string("Can not open document: invalid version")); + break; + case PCDM_RS_NoModel: + Events_Error::send(std::string("Can not open document: no data model")); + break; + case PCDM_RS_NoDocument: + Events_Error::send(std::string("Can not open document: no document inside")); + break; + case PCDM_RS_FormatFailure: + Events_Error::send(std::string("Can not open document: format failure")); + break; + case PCDM_RS_TypeNotFoundInSchema: + Events_Error::send(std::string("Can not open document: invalid object")); + break; + case PCDM_RS_UnrecognizedFileFormat: + Events_Error::send(std::string("Can not open document: unrecognized file format")); + break; + case PCDM_RS_MakeFailure: + Events_Error::send(std::string("Can not open document: make failure")); + break; + case PCDM_RS_PermissionDenied: + Events_Error::send(std::string("Can not open document: permission denied")); + break; + case PCDM_RS_DriverFailure: + Events_Error::send(std::string("Can not open document: driver failure")); + break; + default: + Events_Error::send(std::string("Can not open document: unknown error")); + break; } } 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)); + synchronizeFeatures(false, true); } return !isError; } -bool Model_Document::save(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 - if (this == Model_PluginManager::get()->rootDocument().get()) { + if (this == Model_Session::get()->moduleDocument().get()) { #ifdef WIN32 CreateDirectory(theFileName, NULL); #else - mkdir(theFileName, 0x1ff); + mkdir(theFileName, 0x1ff); #endif } // filename in the dir is id of document inside of the given directory @@ -133,96 +168,116 @@ bool Model_Document::save(const char* theFileName) PCDM_StoreStatus aStatus; try { aStatus = Model_Application::getApplication()->SaveAs(myDoc, aPath); - } - catch (Standard_Failure) { + } catch (Standard_Failure) { Handle(Standard_Failure) aFail = Standard_Failure::Caught(); - Events_Error::send(string("Exception in saving of document: ") + aFail->GetMessageString()); + Events_Error::send( + std::string("Exception in saving of document: ") + aFail->GetMessageString()); return false; } bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj; - if (!isDone) - { - switch (aStatus) - { - case PCDM_SS_DriverFailure: - Events_Error::send(string("Can not save document: PCDM_SS_DriverFailure")); - break; - case PCDM_SS_WriteFailure: - Events_Error::send(string("Can not save document: PCDM_SS_WriteFailure")); - break; - case PCDM_SS_Failure: - default: - Events_Error::send(string("Can not save document: PCDM_SS_Failure")); - break; + if (!isDone) { + switch (aStatus) { + case PCDM_SS_DriverFailure: + Events_Error::send(std::string("Can not save document: save driver-library failure")); + break; + case PCDM_SS_WriteFailure: + Events_Error::send(std::string("Can not save document: file writing failure")); + break; + case PCDM_SS_Failure: + default: + Events_Error::send(std::string("Can not save document")); + break; } } myTransactionsAfterSave = 0; - if (isDone) { // save also sub-documents if any - set::iterator aSubIter = mySubs.begin(); - for(; aSubIter != mySubs.end() && isDone; aSubIter++) - isDone = subDocument(*aSubIter)->save(theFileName); + 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); + } } return isDone; } void Model_Document::close() { - boost::shared_ptr aPM = Model_PluginManager::get(); - if (this != aPM->rootDocument().get() && - this == aPM->currentDocument().get()) { - aPM->setCurrentDocument(aPM->rootDocument()); + boost::shared_ptr aPM = Model_Session::get(); + if (this != aPM->moduleDocument().get() && this == aPM->activeDocument().get()) { + aPM->setActiveDocument(aPM->moduleDocument()); } // close all subs - set::iterator aSubIter = mySubs.begin(); - for(; aSubIter != mySubs.end(); aSubIter++) - subDocument(*aSubIter)->close(); + std::set::iterator aSubIter = mySubs.begin(); + for (; aSubIter != mySubs.end(); aSubIter++) + subDoc(*aSubIter)->close(); 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 this only if it is module document, otherwise it can be undoed + if (this == aPM->moduleDocument().get()) { + if (myDoc->CanClose() == CDM_CCS_OK) + myDoc->Close(); + Model_Application::getApplication()->deleteDocument(myID); + } } void Model_Document::startOperation() { - if (myDoc->HasOpenCommand()) { // start of nested command + if (myDoc->HasOpenCommand()) { // start of nested command if (myNestedNum == -1) { myNestedNum = 0; myDoc->InitDeltaCompaction(); } - myIsEmptyTr[myTransactionsAfterSave] = false; + myIsEmptyTr[myTransactionsAfterSave] = !myDoc->CommitCommand(); myTransactionsAfterSave++; - myDoc->NewCommand(); - } else { // start of simple command + myDoc->OpenCommand(); + } else { // start the simple command myDoc->NewCommand(); } // new command for all subs - set::iterator aSubIter = mySubs.begin(); - for(; aSubIter != mySubs.end(); aSubIter++) - subDocument(*aSubIter)->startOperation(); + std::set::iterator aSubIter = mySubs.begin(); + for (; aSubIter != mySubs.end(); aSubIter++) + subDoc(*aSubIter)->startOperation(); } -void Model_Document::compactNested() { - while(myNestedNum != -1) { +bool Model_Document::compactNested() +{ + bool allWasEmpty = true; + while (myNestedNum != -1) { myTransactionsAfterSave--; + if (!myIsEmptyTr[myTransactionsAfterSave]) { + allWasEmpty = false; + } myIsEmptyTr.erase(myTransactionsAfterSave); myNestedNum--; } - myIsEmptyTr[myTransactionsAfterSave] = false; + myIsEmptyTr[myTransactionsAfterSave] = allWasEmpty; myTransactionsAfterSave++; myDoc->PerformDeltaCompaction(); + return !allWasEmpty; } void Model_Document::finishOperation() { - // just to be sure that everybody knows that changes were performed - Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED)); - Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); - Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED)); + // 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 + // just to be sure that everybody knows that changes were performed + if (!myDoc->HasOpenCommand() && myNestedNum != -1) + boost::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)); + if (!myDoc->HasOpenCommand() && myNestedNum != -1) + boost::static_pointer_cast(Model_Session::get()) + ->setCheckTransactions(true); // for nested transaction commit + + if (myNestedNum != -1) // this nested transaction is owervritten myNestedNum++; if (!myDoc->HasOpenCommand()) { if (myNestedNum != -1) { @@ -231,58 +286,55 @@ void Model_Document::finishOperation() } } else { // returns false if delta is empty and no transaction was made - myIsEmptyTr[myTransactionsAfterSave] = !myDoc->CommitCommand() && (myNestedNum == -1); + myIsEmptyTr[myTransactionsAfterSave] = !myDoc->CommitCommand(); // && (myNestedNum == -1); myTransactionsAfterSave++; } - - // finish for all subs - set::iterator aSubIter = mySubs.begin(); - for(; aSubIter != mySubs.end(); aSubIter++) - subDocument(*aSubIter)->finishOperation(); } void Model_Document::abortOperation() { - if (myNestedNum > 0 && !myDoc->HasOpenCommand()) { // abort all what was done in nested - // first compact all nested - compactNested(); - // for nested it is undo and clear redos - myDoc->Undo(); + 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->ClearRedos(); myTransactionsAfterSave--; myIsEmptyTr.erase(myTransactionsAfterSave); } else { - if (myNestedNum == 0) // abort only high-level + 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 - set::iterator aSubIter = mySubs.begin(); - for(; aSubIter != mySubs.end(); aSubIter++) - subDocument(*aSubIter)->abortOperation(); + std::set::iterator aSubIter = mySubs.begin(); + for (; aSubIter != mySubs.end(); aSubIter++) + subDoc(*aSubIter)->abortOperation(); } bool Model_Document::isOperation() { // operation is opened for all documents: no need to check subs - return myDoc->HasOpenCommand() == Standard_True; + return myDoc->HasOpenCommand() == Standard_True ; } bool Model_Document::isModified() { // is modified if at least one operation was commited and not undoed - return myTransactionsAfterSave > 0; + return myTransactionsAfterSave > 0 || isOperation(); } bool Model_Document::canUndo() { - if (myDoc->GetAvailableUndos() > 0 && myNestedNum != 0 && myTransactionsAfterSave != 0 /* for omitting the first useless transaction */) + if (myDoc->GetAvailableUndos() > 0 && myNestedNum != 0 + && myTransactionsAfterSave != 0 /* for omitting the first useless transaction */) return true; // check other subs contains operation that can be undoed - set::iterator aSubIter = mySubs.begin(); - for(; aSubIter != mySubs.end(); aSubIter++) - if (subDocument(*aSubIter)->canUndo()) + std::set::iterator aSubIter = mySubs.begin(); + for (; aSubIter != mySubs.end(); aSubIter++) + if (subDoc(*aSubIter)->canUndo()) return true; return false; } @@ -290,14 +342,15 @@ bool Model_Document::canUndo() void Model_Document::undo() { myTransactionsAfterSave--; - if (myNestedNum > 0) myNestedNum--; + if (myNestedNum > 0) + myNestedNum--; if (!myIsEmptyTr[myTransactionsAfterSave]) myDoc->Undo(); - synchronizeFeatures(true); + synchronizeFeatures(true, true); // undo for all subs - set::iterator aSubIter = mySubs.begin(); - for(; aSubIter != mySubs.end(); aSubIter++) - subDocument(*aSubIter)->undo(); + std::set::iterator aSubIter = mySubs.begin(); + for (; aSubIter != mySubs.end(); aSubIter++) + subDoc(*aSubIter)->undo(); } bool Model_Document::canRedo() @@ -305,36 +358,38 @@ bool Model_Document::canRedo() if (myDoc->GetAvailableRedos() > 0) return true; // check other subs contains operation that can be redoed - set::iterator aSubIter = mySubs.begin(); - for(; aSubIter != mySubs.end(); aSubIter++) - if (subDocument(*aSubIter)->canRedo()) + std::set::iterator aSubIter = mySubs.begin(); + for (; aSubIter != mySubs.end(); aSubIter++) + if (subDoc(*aSubIter)->canRedo()) return true; return false; } void Model_Document::redo() { - if (myNestedNum != -1) myNestedNum++; + if (myNestedNum != -1) + myNestedNum++; if (!myIsEmptyTr[myTransactionsAfterSave]) myDoc->Redo(); myTransactionsAfterSave++; - synchronizeFeatures(true); + synchronizeFeatures(true, true); // redo for all subs - set::iterator aSubIter = mySubs.begin(); - for(; aSubIter != mySubs.end(); aSubIter++) - subDocument(*aSubIter)->redo(); + std::set::iterator aSubIter = mySubs.begin(); + for (; aSubIter != mySubs.end(); aSubIter++) + subDoc(*aSubIter)->redo(); } /// Appenad to the array of references a new referenced label -static void AddToRefArray(TDF_Label& theArrayLab, TDF_Label& theReferenced) { +static void AddToRefArray(TDF_Label& theArrayLab, TDF_Label& theReferenced) +{ Handle(TDataStd_ReferenceArray) aRefs; if (!theArrayLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) { aRefs = TDataStd_ReferenceArray::Set(theArrayLab, 0, 0); aRefs->SetValue(0, theReferenced); - } else { // extend array by one more element - Handle(TDataStd_HLabelArray1) aNewArray = - new TDataStd_HLabelArray1(aRefs->Lower(), aRefs->Upper() + 1); - for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) { + } else { // extend array by one more element + Handle(TDataStd_HLabelArray1) aNewArray = new TDataStd_HLabelArray1(aRefs->Lower(), + aRefs->Upper() + 1); + for (int a = aRefs->Lower(); a <= aRefs->Upper(); a++) { aNewArray->SetValue(a, aRefs->Value(a)); } aNewArray->SetValue(aRefs->Upper() + 1, theReferenced); @@ -342,61 +397,60 @@ static void AddToRefArray(TDF_Label& theArrayLab, TDF_Label& theReferenced) { } } - -FeaturePtr Model_Document::addFeature(string theID) +FeaturePtr Model_Document::addFeature(std::string theID) { TDF_Label anEmptyLab; FeaturePtr anEmptyFeature; - FeaturePtr aFeature = ModelAPI_PluginManager::get()->createFeature(theID); + FeaturePtr aFeature = ModelAPI_Session::get()->createFeature(theID); + if (!aFeature) + return aFeature; + boost::shared_ptr aDocToAdd = boost::dynamic_pointer_cast( + aFeature->documentToAdd()); if (aFeature) { TDF_Label aFeatureLab; - if (!aFeature->isAction()) {// do not add action to the data model - TDF_Label aFeaturesLab = groupLabel(ModelAPI_Feature::group()); + if (!aFeature->isAction()) { // do not add action to the data model + TDF_Label aFeaturesLab = aDocToAdd->featuresLabel(); aFeatureLab = aFeaturesLab.NewChild(); - initData(aFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS); + aDocToAdd->initData(aFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS); // keep the feature ID to restore document later correctly TDataStd_Comment::Set(aFeatureLab, aFeature->getKind().c_str()); - myObjs[ModelAPI_Feature::group()].push_back(aFeature); + aDocToAdd->myObjs.Bind(aFeatureLab, aFeature); // store feature in the history of features array if (aFeature->isInHistory()) { AddToRefArray(aFeaturesLab, aFeatureLab); } } - setUniqueName(aFeature); - if (!aFeature->isAction()) {// do not add action to the data model + if (!aFeature->isAction()) { // do not add action to the data model // event: feature is added static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED); ModelAPI_EventCreator::get()->sendUpdated(aFeature, anEvent); + } else { // feature must be executed + // no creation event => updater not working, problem with remove part + aFeature->execute(); } } return aFeature; } -void Model_Document::storeResult(boost::shared_ptr theFeatureData, - boost::shared_ptr theResult, const int theResultIndex) -{ - initData(theResult, boost::dynamic_pointer_cast(theFeatureData)-> - label().Father().FindChild(TAG_FEATURE_RESULTS), theResultIndex); -} - /// Appenad to the array of references a new referenced label. /// If theIndex is not -1, removes element at thisindex, not theReferenced. /// \returns the index of removed element -static int RemoveFromRefArray( - TDF_Label theArrayLab, TDF_Label theReferenced, const int theIndex = -1) { - int aResult = -1; // no returned +static int RemoveFromRefArray(TDF_Label theArrayLab, TDF_Label theReferenced, const int theIndex = + -1) +{ + int aResult = -1; // no returned Handle(TDataStd_ReferenceArray) aRefs; if (theArrayLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) { - if (aRefs->Length() == 1) { // just erase an array + if (aRefs->Length() == 1) { // just erase an array if ((theIndex == -1 && aRefs->Value(0) == theReferenced) || theIndex == 0) { theArrayLab.ForgetAttribute(TDataStd_ReferenceArray::GetID()); } aResult = 0; - } else { // reduce the array - Handle(TDataStd_HLabelArray1) aNewArray = - new TDataStd_HLabelArray1(aRefs->Lower(), aRefs->Upper() - 1); + } else { // reduce the array + Handle(TDataStd_HLabelArray1) aNewArray = new TDataStd_HLabelArray1(aRefs->Lower(), + aRefs->Upper() - 1); int aCount = aRefs->Lower(); - for(int a = aCount; a <= aRefs->Upper(); a++, aCount++) { + for (int a = aCount; a <= aRefs->Upper(); a++, aCount++) { if ((theIndex == -1 && aRefs->Value(a) == theReferenced) || theIndex == a) { aCount--; aResult = a; @@ -410,76 +464,69 @@ static int RemoveFromRefArray( return aResult; } -void Model_Document::removeFeature(FeaturePtr theFeature) +void Model_Document::removeFeature(FeaturePtr theFeature, const bool theCheck) { - boost::shared_ptr aData = boost::static_pointer_cast(theFeature->data()); - TDF_Label aFeatureLabel = aData->label().Father(); - // remove feature from the myObjects list - std::vector& aVec = myObjs[ModelAPI_Feature::group()]; - std::vector::iterator anIter = aVec.begin(); - while(anIter != aVec.end()) { - if (*anIter == theFeature) { - anIter = aVec.erase(anIter); - } else { - anIter++; + 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++) { + boost::shared_ptr aData = + boost::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(groupLabel(ModelAPI_Feature::group()), aData->label()); - + if (theFeature->isInHistory()) { + RemoveFromRefArray(featuresLabel(), aFeatureLabel); + } // event: feature is deleted ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), ModelAPI_Feature::group()); } -/// returns the object group name by the object label -static string groupName(TDF_Label theObjectLabel) { - TDF_Label aGroupLab = theObjectLabel.Father(); - Handle(TDataStd_Comment) aComment; - if (aGroupLab.FindAttribute(TDataStd_Comment::GetID(), aComment)) - return string(TCollection_AsciiString(aComment->Get()).ToCString()); - return ""; // not found +FeaturePtr Model_Document::feature(TDF_Label& theLabel) +{ + if (myObjs.IsBound(theLabel)) + return myObjs.Find(theLabel); + return FeaturePtr(); // not found } -FeaturePtr Model_Document::feature(TDF_Label& theLabel) +ObjectPtr Model_Document::object(TDF_Label theLabel) { - // iterate all features, may be optimized later by keeping labels-map - std::vector& aVec = myObjs[ModelAPI_Feature::group()]; - vector::iterator aFIter = aVec.begin(); - for(; aFIter != aVec.end(); aFIter++) { - boost::shared_ptr aData = - boost::dynamic_pointer_cast((*aFIter)->data()); - if (aData->label().IsEqual(theLabel)) - return boost::dynamic_pointer_cast(*aFIter); - } - return FeaturePtr(); // not found -} - -ObjectPtr Model_Document::object(TDF_Label& theLabel) -{ - // iterate all features, may be optimized later by keeping labels-map - std::vector& aVec = myObjs[ModelAPI_Feature::group()]; - vector::iterator aFIter = aVec.begin(); - for(; aFIter != aVec.end(); aFIter++) { - boost::shared_ptr aData = - boost::dynamic_pointer_cast((*aFIter)->data()); - if (aData->label().IsEqual(theLabel)) - return *aFIter; - list >& aResults = - boost::dynamic_pointer_cast(*aFIter)->results(); - list >::iterator aRIter = aResults.begin(); - for(; aRIter != aResults.end(); aRIter++) { - boost::shared_ptr aResData = - boost::dynamic_pointer_cast((*aRIter)->data()); - if (aResData->label().IsEqual(theLabel)) + // try feature by label + FeaturePtr aFeature = feature(theLabel); + if (aFeature) + return feature(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(); + for (; aRIter != aResults.cend(); aRIter++) { + boost::shared_ptr aResData = boost::dynamic_pointer_cast( + (*aRIter)->data()); + if (aResData->label().Father().IsEqual(theLabel)) return *aRIter; } } - return FeaturePtr(); // not found + return FeaturePtr(); // not found } -boost::shared_ptr Model_Document::subDocument(string theDocID) +boost::shared_ptr Model_Document::subDocument(std::string theDocID) { // just store sub-document identifier here to manage it later if (mySubs.find(theDocID) == mySubs.end()) @@ -487,30 +534,57 @@ boost::shared_ptr Model_Document::subDocument(string theDocID return Model_Application::getApplication()->getDocument(theDocID); } -ObjectPtr Model_Document::object(const string& theGroupID, const int theIndex) +boost::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( + Model_Application::getApplication()->getDocument(theDocID)); +} + +ObjectPtr Model_Document::object(const std::string& theGroupID, const int theIndex, + const bool theHidden) { if (theGroupID == ModelAPI_Feature::group()) { - std::map >::iterator aFind = myObjs.find(theGroupID); - if (aFind != myObjs.end()) { - int aSize = aFind->second.size(); - if (theIndex >= 0 && theIndex < aSize) - return aFind->second[theIndex]; + if (theHidden) { + int anIndex = 0; + TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID()); + for (; aLabIter.More(); aLabIter.Next()) { + if (theIndex == anIndex) { + TDF_Label aFLabel = aLabIter.Value()->Label(); + return feature(aFLabel); + } + anIndex++; + } + } else { + Handle(TDataStd_ReferenceArray) aRefs; + if (!featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) + return ObjectPtr(); + if (aRefs->Lower() > theIndex || aRefs->Upper() < theIndex) + return ObjectPtr(); + TDF_Label aFeatureLabel = aRefs->Value(theIndex); + return feature(aFeatureLabel); } } else { - // iterate all features in order to find the needed result - std::map >::iterator aFind = myObjs.find(ModelAPI_Feature::group()); - if (aFind != myObjs.end()) { - vector::iterator aFIter = aFind->second.begin(); - for(int anIndex = 0; aFIter != aFind->second.end(); aFIter++) { - const list >& aResults = - boost::dynamic_pointer_cast(*aFIter)->results(); - list >::const_iterator aRIter = aResults.begin(); - for(; aRIter != aResults.cend(); aRIter++) { - if ((*aRIter)->isInHistory() && (*aRIter)->groupName() == theGroupID) { - if (anIndex == theIndex) - return *aRIter; - anIndex++; - } + // 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) continue; + bool isIn = theHidden && (*aRIter)->isInHistory(); + if (!isIn && (*aRIter)->isInHistory()) { // check that there is nobody references this result + isIn = !(*aRIter)->isConcealed(); + } + if (isIn) { + if (anIndex == theIndex) + return *aRIter; + anIndex++; } } } @@ -519,28 +593,33 @@ ObjectPtr Model_Document::object(const string& theGroupID, const int theIndex) return ObjectPtr(); } -int Model_Document::size(const string& theGroupID) +int Model_Document::size(const std::string& theGroupID, const bool theHidden) { int aResult = 0; if (theGroupID == ModelAPI_Feature::group()) { - std::map >::iterator aFind = myObjs.find(theGroupID); - if (aFind != myObjs.end()) { - aResult = aFind->second.size(); + if (theHidden) { + return myObjs.Size(); + } else { + Handle(TDataStd_ReferenceArray) aRefs; + if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) + return aRefs->Length(); } } else { - // iterate all features in order to find the needed result - std::map >::iterator aFind = myObjs.find(ModelAPI_Feature::group()); - if (aFind != myObjs.end()) { - vector::iterator aFIter = aFind->second.begin(); - for(; aFIter != aFind->second.end(); aFIter++) { - const list >& aResults = - boost::dynamic_pointer_cast(*aFIter)->results(); - list >::const_iterator aRIter = aResults.begin(); - for(; aRIter != aResults.cend(); aRIter++) { - if ((*aRIter)->isInHistory() && (*aRIter)->groupName() == theGroupID) { - aResult++; - } + // comment must be in any feature: it is kind + 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) continue; + bool isIn = theHidden; + if (!isIn && (*aRIter)->isInHistory()) { // check that there is nobody references this result + isIn = !(*aRIter)->isConcealed(); } + if (isIn) + aResult++; } } } @@ -548,165 +627,373 @@ int Model_Document::size(const string& theGroupID) return aResult; } -Model_Document::Model_Document(const std::string theID) - : myID(theID), myDoc(new TDocStd_Document("BinOcaf")) // binary OCAF format +TDF_Label Model_Document::featuresLabel() { - myDoc->SetUndoLimit(UNDO_LIMIT); - myTransactionsAfterSave = 0; - myNestedNum = -1; - //myDoc->SetNestedTransactionMode(); - // to have something in the document and avoid empty doc open/save problem - // in transaction for nesting correct working - myDoc->NewCommand(); - TDataStd_Integer::Set(myDoc->Main().Father(), 0); - myDoc->CommitCommand(); -} - -TDF_Label Model_Document::groupLabel(const string theGroup) -{ - // searching for existing - TCollection_ExtendedString aGroup(theGroup.c_str()); - TDF_ChildIDIterator aGroupIter(myDoc->Main().FindChild(TAG_OBJECTS), TDataStd_Comment::GetID()); - for(; aGroupIter.More(); aGroupIter.Next()) { - Handle(TDataStd_Comment) aName = Handle(TDataStd_Comment)::DownCast(aGroupIter.Value()); - if (aName->Get() == aGroup) - return aGroupIter.Value()->Label(); - } - // create a new - TDF_Label aNew = myDoc->Main().FindChild(TAG_OBJECTS).NewChild(); - TDataStd_Comment::Set(aNew, aGroup); - return aNew; + return myDoc->Main().FindChild(TAG_OBJECTS); } void Model_Document::setUniqueName(FeaturePtr theFeature) { - string aName; // result + if (!theFeature->data()->name().empty()) + return; // not needed, name is already defined + std::string aName; // result // first count all objects of such kind to start with index = count + 1 - int a, aNumObjects = 0; - int aSize = size(ModelAPI_Feature::group()); - for(a = 0; a < aSize; a++) { - if (boost::dynamic_pointer_cast(object(ModelAPI_Feature::group(), a))->getKind() - == theFeature->getKind()) + int aNumObjects = 0; + NCollection_DataMap::Iterator aFIter(myObjs); + for (; aFIter.More(); aFIter.Next()) { + if (aFIter.Value()->getKind() == theFeature->getKind()) aNumObjects++; } // generate candidate name - stringstream aNameStream; - aNameStream<getKind()<<"_"<getKind() << "_" << aNumObjects + 1; aName = aNameStream.str(); // check this is unique, if not, increase index by 1 - for(a = 0; a < aSize;) { - if (boost::dynamic_pointer_cast(object(ModelAPI_Feature::group(), a)) - ->data()->name() == aName) { + for (aFIter.Initialize(myObjs); aFIter.More();) { + FeaturePtr aFeature = aFIter.Value(); + 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(); + for (; aRIter != aResults.cend(); aRIter++) { + isSameName = (*aRIter)->data()->name() == aName; + } + } + if (isSameName) { aNumObjects++; - stringstream aNameStream; - aNameStream<getKind()<<"_"<getKind() << "_" << aNumObjects + 1; aName = aNameStream.str(); // reinitialize iterator to make sure a new name is unique - a = 0; - } else a++; + aFIter.Initialize(myObjs); + } else + aFIter.Next(); } theFeature->data()->setName(aName); } -void Model_Document::initData(ObjectPtr theObj, TDF_Label& theLab, const int theTag) { - boost::shared_ptr aThis = - Model_Application::getApplication()->getDocument(myID); +void Model_Document::initData(ObjectPtr theObj, TDF_Label theLab, const int theTag) +{ + boost::shared_ptr aThis = Model_Application::getApplication()->getDocument( + myID); boost::shared_ptr aData(new Model_Data); - aData->setLabel(theLab.FindChild(theTag + 1)); + aData->setLabel(theLab.FindChild(theTag)); aData->setObject(theObj); theObj->setDoc(aThis); theObj->setData(aData); FeaturePtr aFeature = boost::dynamic_pointer_cast(theObj); - if (aFeature) aFeature->initAttributes(); + 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 = Model_Application::getApplication()->getDocument(myID); - // update all objects: iterate from the end: as they appeared in the list - map >::reverse_iterator aGroupIter = myObjs.rbegin(); - for(; aGroupIter != myObjs.rend(); aGroupIter++) { - vector::iterator anObjIter = aGroupIter->second.begin(); - // and in parallel iterate labels of features - const string& aGroupName = aGroupIter->first; - TDF_ChildIDIterator aLabIter(groupLabel(aGroupName), TDataStd_Comment::GetID()); - while(anObjIter != aGroupIter->second.end() || aLabIter.More()) { - static const int INFINITE_TAG = INT_MAX; // no label means that it exists somwhere in infinite - int aFeatureTag = INFINITE_TAG; - if (anObjIter != aGroupIter->second.end()) { // existing tag for feature - boost::shared_ptr aData = - boost::dynamic_pointer_cast((*anObjIter)->data()); - aFeatureTag = aData->label().Tag(); + // after all updates, sends a message that groups of features were created or updated + boost::static_pointer_cast(Model_Session::get()) + ->setCheckTransactions(false); + Events_Loop* aLoop = Events_Loop::loop(); + aLoop->activateFlushes(false); + + // update all objects by checking are they of labels or not + std::set aNewFeatures, aKeptFeatures; + 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 + aFeature = ModelAPI_Session::get()->createFeature( + 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(); + continue; } - int aDSTag = INFINITE_TAG; - if (aLabIter.More()) { // next label in DS is existing - aDSTag = aLabIter.Value()->Label().Tag(); + // this must be before "setData" to redo the sketch line correctly + 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(aFeature, anEvent); + + // update results of the appeared feature + updateResults(aFeature); + } 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); } - if (aDSTag > aFeatureTag) { // feature is removed - ObjectPtr anObj = *anObjIter; - anObjIter = aGroupIter->second.erase(anObjIter); - // event: model is updated - if (anObj->isInHistory()) { - ModelAPI_EventCreator::get()->sendDeleted(aThis, aGroupName); - } - ModelAPI_EventCreator::get()->sendDeleted(aThis, aGroupName); - } else if (aDSTag < aFeatureTag) { // a new feature is inserted - // create a feature - TDF_Label aLab = aLabIter.Value()->Label(); - ObjectPtr aNewObj = ModelAPI_PluginManager::get()->createFeature( - TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(aLabIter.Value())->Get()) - .ToCString()); - // this must be before "setData" to redo the sketch line correctly - if (anObjIter == aGroupIter->second.end()) { - aGroupIter->second.push_back(aNewObj); - anObjIter = aGroupIter->second.end(); - } else { - anObjIter++; - aGroupIter->second.insert(anObjIter, aNewObj); - } - initData(aNewObj, aLab, TAG_FEATURE_ARGUMENTS); + updateResults(aFeature); + } + } + // check all features are checked: if not => it was removed + 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()) { + 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); + } else + aFIter.Next(); + } - // event: model is updated - static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED); - ModelAPI_EventCreator::get()->sendUpdated(aNewObj, anEvent); - // feature for this label is added, so go to the next label - aLabIter.Next(); - } else { // nothing is changed, both iterators are incremented - if (theMarkUpdated) { - static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); - ModelAPI_EventCreator::get()->sendUpdated(*anObjIter, anEvent); + 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_TO_REDISPLAY)); + aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TOHIDE)); + boost::static_pointer_cast(Model_Session::get()) + ->setCheckTransactions(true); + myExecuteFeatures = true; +} + +void Model_Document::synchronizeBackRefs() +{ + boost::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(); + boost::shared_ptr aFData = + boost::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++) { + boost::shared_ptr aResData = + boost::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(); + boost::shared_ptr aFData = + boost::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) { + boost::shared_ptr aRefData = + boost::dynamic_pointer_cast((*aRefTo)->data()); + aRefData->addBackReference(aFeature, aRefsIter->first); // here the Concealed flag is updated + } } - anObjIter++; - aLabIter.Next(); } } } - // after all updates, sends a message that groups of features were created or updated - boost::static_pointer_cast(Model_PluginManager::get())-> - setCheckTransactions(false); - Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED)); - if (theMarkUpdated) - Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); - Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED)); - boost::static_pointer_cast(Model_PluginManager::get())-> - setCheckTransactions(true); + 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()); + } + } + } } -boost::shared_ptr Model_Document::createConstruction() +TDF_Label Model_Document::resultLabel( + const boost::shared_ptr& theFeatureData, const int theResultIndex) +{ + const boost::shared_ptr& aData = + boost::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, + const int theResultIndex) { - boost::shared_ptr aResult(new Model_ResultConstruction()); + boost::shared_ptr aThis = + Model_Application::getApplication()->getDocument(myID); + 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()); + } +} + +boost::shared_ptr Model_Document::createConstruction( + const boost::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); + boost::shared_ptr aResult; + if (anOldObject) { + aResult = boost::dynamic_pointer_cast(anOldObject); + } + if (!aResult) { + aResult = boost::shared_ptr(new Model_ResultConstruction); + storeResult(theFeatureData, aResult, theIndex); + } + return aResult; +} + +boost::shared_ptr Model_Document::createBody( + const boost::shared_ptr& theFeatureData, const int theIndex) +{ + TDF_Label aLab = resultLabel(theFeatureData, theIndex); + TDataStd_Comment::Set(aLab, ModelAPI_ResultBody::group().c_str()); + ObjectPtr anOldObject = object(aLab); + boost::shared_ptr aResult; + if (anOldObject) { + aResult = boost::dynamic_pointer_cast(anOldObject); + } + if (!aResult) { + aResult = boost::shared_ptr(new Model_ResultBody); + storeResult(theFeatureData, aResult, theIndex); + } return aResult; } -boost::shared_ptr Model_Document::createBody() +boost::shared_ptr Model_Document::createPart( + const boost::shared_ptr& theFeatureData, const int theIndex) { - boost::shared_ptr aResult(new Model_ResultBody()); + TDF_Label aLab = resultLabel(theFeatureData, theIndex); + TDataStd_Comment::Set(aLab, ModelAPI_ResultPart::group().c_str()); + ObjectPtr anOldObject = object(aLab); + boost::shared_ptr aResult; + if (anOldObject) { + aResult = boost::dynamic_pointer_cast(anOldObject); + } + if (!aResult) { + aResult = boost::shared_ptr(new Model_ResultPart); + storeResult(theFeatureData, aResult, theIndex); + } return aResult; } -boost::shared_ptr Model_Document::createPart() +boost::shared_ptr Model_Document::createGroup( + const boost::shared_ptr& theFeatureData, const int theIndex) { - boost::shared_ptr aResult(new Model_ResultPart()); + TDF_Label aLab = resultLabel(theFeatureData, theIndex); + TDataStd_Comment::Set(aLab, ModelAPI_ResultGroup::group().c_str()); + ObjectPtr anOldObject = object(aLab); + boost::shared_ptr aResult; + if (anOldObject) { + aResult = boost::dynamic_pointer_cast(anOldObject); + } + if (!aResult) { + aResult = boost::shared_ptr(new Model_ResultGroup(theFeatureData)); + storeResult(theFeatureData, aResult, theIndex); + } return aResult; } + +boost::shared_ptr Model_Document::feature( + const boost::shared_ptr& theResult) +{ + boost::shared_ptr aData = boost::dynamic_pointer_cast(theResult->data()); + if (aData) { + TDF_Label aFeatureLab = aData->label().Father().Father().Father(); + return feature(aFeatureLab); + } + return FeaturePtr(); +} + +void Model_Document::updateResults(FeaturePtr theFeature) +{ + // for not persistent is will be done by parametric updater automatically + 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); + if (aBody) { + if (!aBody->data()->isValid()) { + // found a disappeared result => remove it + theFeature->removeResult(aBody); + // start iterate from beginning because iterator is corrupted by removing + aResIter = theFeature->results().cbegin(); + continue; + } + } + aResIter++; + } + // check that results are presented on all labels + int aResSize = theFeature->results().size(); + TDF_ChildIterator aLabIter(resultLabel(theFeature->data(), 0).Father()); + for(; aLabIter.More(); aLabIter.Next()) { + // here must be GUID of the feature + int aResIndex = aLabIter.Value().Tag() - 1; + ResultPtr aNewBody; + if (aResSize <= aResIndex) { + TDF_Label anArgLab = aLabIter.Value(); + 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() && + aGroup->Get() != ModelAPI_ResultGroup::group().c_str()) { + 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); + } + } + } +} + +Standard_Integer HashCode(const TDF_Label& theLab, const Standard_Integer theUpper) +{ + return TDF_LabelMapHasher::HashCode(theLab, theUpper); + +} +Standard_Boolean IsEqual(const TDF_Label& theLab1, const TDF_Label& theLab2) +{ + return TDF_LabelMapHasher::IsEqual(theLab1, theLab2); +}