X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FModel%2FModel_Document.cpp;h=59ebd2fb0f1663417cfa9e1b17c945d973215a64;hb=27a61e1e61c970b3bfd4b863543aadeac9b65162;hp=c08c851605ba88b20bfdbc1e8fdec69826d70304;hpb=6333682060ad5116559e12d5c212f1a1f199b3a0;p=modules%2Fshaper.git diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index c08c85160..59ebd2fb0 100644 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include @@ -20,9 +20,8 @@ #include #include #include -#include - -#include +#include +#include #include #ifndef WIN32 @@ -35,102 +34,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 + +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 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(std::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(std::string("Can not open document: PCDM_RS_UnknownDocument")); break; - case PCDM_RS_AlreadyRetrieved: - Events_Error::send(std::string("Can not open document: PCDM_RS_AlreadyRetrieved")); break; - case PCDM_RS_AlreadyRetrievedAndModified: - Events_Error::send( - std::string("Can not open document: PCDM_RS_AlreadyRetrievedAndModified")); - break; - case PCDM_RS_NoDriver: - Events_Error::send(std::string("Can not open document: PCDM_RS_NoDriver")); break; - case PCDM_RS_UnknownFileDriver: - Events_Error::send(std::string("Can not open document: PCDM_RS_UnknownFileDriver")); break; - case PCDM_RS_OpenError: - Events_Error::send(std::string("Can not open document: PCDM_RS_OpenError")); break; - case PCDM_RS_NoVersion: - Events_Error::send(std::string("Can not open document: PCDM_RS_NoVersion")); break; - case PCDM_RS_NoModel: - Events_Error::send(std::string("Can not open document: PCDM_RS_NoModel")); break; - case PCDM_RS_NoDocument: - Events_Error::send(std::string("Can not open document: PCDM_RS_NoDocument")); break; - case PCDM_RS_FormatFailure: - Events_Error::send(std::string("Can not open document: PCDM_RS_FormatFailure")); break; - case PCDM_RS_TypeNotFoundInSchema: - Events_Error::send(std::string("Can not open document: PCDM_RS_TypeNotFoundInSchema")); - break; - case PCDM_RS_UnrecognizedFileFormat: - Events_Error::send(std::string("Can not open document: PCDM_RS_UnrecognizedFileFormat")); - break; - case PCDM_RS_MakeFailure: - Events_Error::send(std::string("Can not open document: PCDM_RS_MakeFailure")); break; - case PCDM_RS_PermissionDenied: - Events_Error::send(std::string("Can not open document: PCDM_RS_PermissionDenied")); break; - case PCDM_RS_DriverFailure: - Events_Error::send(std::string("Can not open document: PCDM_RS_DriverFailure")); break; - default: - Events_Error::send(std::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); + // to avoid the problem that feature is created in the current, not this, document + Model_Session::get()->setActiveDocument(anApp->getDocument(myID)); synchronizeFeatures(); } 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 @@ -138,97 +166,114 @@ 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(std::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(std::string("Can not save document: PCDM_SS_DriverFailure")); - break; - case PCDM_SS_WriteFailure: - Events_Error::send(std::string("Can not save document: PCDM_SS_WriteFailure")); - break; - case PCDM_SS_Failure: - default: - Events_Error::send(std::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 + 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 = subDocument(*aSubIter)->save(theFileName); + 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 std::set::iterator aSubIter = mySubs.begin(); - for(; aSubIter != mySubs.end(); aSubIter++) - subDocument(*aSubIter)->close(); + 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); - */ + 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 std::set::iterator aSubIter = mySubs.begin(); - for(; aSubIter != mySubs.end(); aSubIter++) - subDocument(*aSubIter)->startOperation(); + 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_TO_REDISPLAY)); - 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 + 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_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) { @@ -237,58 +282,56 @@ 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 - std::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); // abort for all subs std::set::iterator aSubIter = mySubs.begin(); - for(; aSubIter != mySubs.end(); aSubIter++) - subDocument(*aSubIter)->abortOperation(); + 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 std::set::iterator aSubIter = mySubs.begin(); - for(; aSubIter != mySubs.end(); aSubIter++) - if (subDocument(*aSubIter)->canUndo()) + for (; aSubIter != mySubs.end(); aSubIter++) + if (subDoc(*aSubIter)->canUndo()) return true; return false; } @@ -296,14 +339,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); // undo for all subs std::set::iterator aSubIter = mySubs.begin(); - for(; aSubIter != mySubs.end(); aSubIter++) - subDocument(*aSubIter)->undo(); + for (; aSubIter != mySubs.end(); aSubIter++) + subDoc(*aSubIter)->undo(); } bool Model_Document::canRedo() @@ -312,35 +356,37 @@ bool Model_Document::canRedo() return true; // check other subs contains operation that can be redoed std::set::iterator aSubIter = mySubs.begin(); - for(; aSubIter != mySubs.end(); aSubIter++) - if (subDocument(*aSubIter)->canRedo()) + 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); // redo for all subs std::set::iterator aSubIter = mySubs.begin(); - for(; aSubIter != mySubs.end(); aSubIter++) - subDocument(*aSubIter)->redo(); + 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); @@ -352,28 +398,32 @@ FeaturePtr Model_Document::addFeature(std::string theID) { TDF_Label anEmptyLab; FeaturePtr anEmptyFeature; - FeaturePtr aFeature = ModelAPI_PluginManager::get()->createFeature(theID); - boost::shared_ptr aDocToAdd = - boost::dynamic_pointer_cast(aFeature->documentToAdd()); + 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 = aDocToAdd->groupLabel(ModelAPI_Feature::group()); + if (!aFeature->isAction()) { // do not add action to the data model + TDF_Label aFeaturesLab = aDocToAdd->featuresLabel(); aFeatureLab = aFeaturesLab.NewChild(); aDocToAdd->initData(aFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS); // keep the feature ID to restore document later correctly TDataStd_Comment::Set(aFeatureLab, aFeature->getKind().c_str()); - aDocToAdd->setUniqueName(aFeature); - aDocToAdd->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); } } - 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; @@ -382,21 +432,22 @@ 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. /// \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,83 +461,82 @@ 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++) { + 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"); + 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()); + 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++) { + for (; aRIter != aResults.cend(); aRIter++) { boost::shared_ptr aRes = *aRIter; - aRes->setData(boost::shared_ptr()); // deleted flag + aRes->setData(boost::shared_ptr()); // deleted flag ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP); ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), aRes->groupName()); } -} - -/// returns the object group name by the object label -static std::string groupName(TDF_Label theObjectLabel) { - TDF_Label aGroupLab = theObjectLabel.Father(); - Handle(TDataStd_Comment) aComment; - if (aGroupLab.FindAttribute(TDataStd_Comment::GetID(), aComment)) - return std::string(TCollection_AsciiString(aComment->Get()).ToCString()); - return ""; // not found + */ } FeaturePtr Model_Document::feature(TDF_Label& theLabel) { - // iterate all features, may be optimized later by keeping labels-map - std::vector& aVec = myObjs[ModelAPI_Feature::group()]; - std::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 + if (myObjs.IsBound(theLabel)) + return myObjs.Find(theLabel); + 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()]; - std::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; - std::list >& aResults = - boost::dynamic_pointer_cast(*aFIter)->results(); - std::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(std::string theDocID) @@ -497,39 +547,57 @@ boost::shared_ptr Model_Document::subDocument(std::string the return Model_Application::getApplication()->getDocument(theDocID); } -ObjectPtr Model_Document::object(const std::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()) { - // features may be not in history but in the myObjs, so, iterate all - int anIndex = 0; - std::map >::iterator aFind = - myObjs.find(ModelAPI_Feature::group()); - if (aFind != myObjs.end()) { - std::vector::iterator aFIter = aFind->second.begin(); - for(; aFIter != aFind->second.end(); aFIter++) { - if ((*aFIter)->isInHistory()) { - if (theIndex == anIndex) - return *aFIter; - anIndex++; + 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()) { - std::vector::iterator aFIter = aFind->second.begin(); - for(int anIndex = 0; aFIter != aFind->second.end(); aFIter++) { - const std::list >& aResults = - boost::dynamic_pointer_cast(*aFIter)->results(); - std::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; + if (!isIn && (*aRIter)->isInHistory()) { // check that there is nobody references this result + isIn = myConcealedResults.find(*aRIter) == myConcealedResults.end(); + } + if (isIn) { + if (anIndex == theIndex) + return *aRIter; + anIndex++; } } } @@ -538,36 +606,33 @@ ObjectPtr Model_Document::object(const std::string& theGroupID, const int theInd return ObjectPtr(); } -int Model_Document::size(const std::string& theGroupID) +int Model_Document::size(const std::string& theGroupID, const bool theHidden) { int aResult = 0; if (theGroupID == ModelAPI_Feature::group()) { - // features may be not in history but in the myObjs, so, iterate all - std::map >::iterator aFind = - myObjs.find(ModelAPI_Feature::group()); - if (aFind != myObjs.end()) { - std::vector::iterator aFIter = aFind->second.begin(); - for(; aFIter != aFind->second.end(); aFIter++) { - if ((*aFIter)->isInHistory()) { - aResult++; - } - } + 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()) { - std::vector::iterator aFIter = aFind->second.begin(); - for(; aFIter != aFind->second.end(); aFIter++) { - const std::list >& aResults = - boost::dynamic_pointer_cast(*aFIter)->results(); - std::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 = myConcealedResults.find(*aRIter) == myConcealedResults.end(); } + if (isIn) + aResult++; } } } @@ -575,251 +640,342 @@ int Model_Document::size(const std::string& theGroupID) return aResult; } -Model_Document::Model_Document(const std::string theID) - : myID(theID), myDoc(new TDocStd_Document("BinOcaf")) // binary OCAF format -{ - 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 std::string theGroup) +TDF_Label Model_Document::featuresLabel() { - // 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) { - std::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 = myObjs.find(ModelAPI_Feature::group()) == myObjs.end() ? - 0 : myObjs[ModelAPI_Feature::group()].size(); - for(a = 0; a < aSize; a++) { - if (boost::dynamic_pointer_cast(myObjs[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 std::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;) { - FeaturePtr aFeature = - boost::dynamic_pointer_cast(myObjs[ModelAPI_Feature::group()][a]); + for (aFIter.Initialize(myObjs); aFIter.More();) { + FeaturePtr aFeature = aFIter.Value(); bool isSameName = aFeature->isInHistory() && aFeature->data()->name() == aName; - if (!isSameName) { // check also results to avoid same results names (actual for Parts) + 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++) { + for (; aRIter != aResults.cend(); aRIter++) { isSameName = (*aRIter)->isInHistory() && (*aRIter)->data()->name() == aName; } } if (isSameName) { aNumObjects++; std::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) { boost::shared_ptr aThis = Model_Application::getApplication()->getDocument(myID); - // update all objects: iterate from the end: as they appeared in the list - std::map >::reverse_iterator aGroupIter = myObjs.rbegin(); - for(; aGroupIter != myObjs.rend(); aGroupIter++) { - std::vector::iterator anObjIter = aGroupIter->second.begin(); - // and in parallel iterate labels of features+ - const std::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(); - } - int aDSTag = INFINITE_TAG; - if (aLabIter.More()) { // next label in DS is existing - aDSTag = aLabIter.Value()->Label().Tag(); - } - 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); - } - // results of this feature must be redisplayed (hided) - static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY); - const std::list >& aResults = boost::dynamic_pointer_cast(anObj)->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()); - } - } else if (aDSTag < aFeatureTag) { // a new feature is inserted - // create a feature - TDF_Label aLab = aLabIter.Value()->Label(); - ObjectPtr aNewObj = ModelAPI_PluginManager::get()->createFeature( + // 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(); + if (!myObjs.IsBound(aFeatureLabel)) { // a new feature is inserted + // create a feature + FeaturePtr aNewObj = ModelAPI_Session::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); - - // 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); - } - anObjIter++; - aLabIter.Next(); + .ToCString()); + if (!aNewObj) { // 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); + + // 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); + } else { // nothing is changed, both iterators are incremented + FeaturePtr 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); } + updateResults(aFeature); } } - // 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); + // 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()) { + 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(); + /* + 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()); + } + */ + // 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(); + } + + 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)); + boost::static_pointer_cast(Model_Session::get()) + ->setCheckTransactions(true); + myExecuteFeatures = true; +} + +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 theResult, + const int theResultIndex) { boost::shared_ptr aThis = Model_Application::getApplication()->getDocument(myID); theResult->setDoc(aThis); - initData(theResult, boost::dynamic_pointer_cast(theFeatureData)-> - label().Father().FindChild(TAG_FEATURE_RESULTS), theResultIndex); - if (theResult->data()->name().empty()) { // if was not initialized, generate event and set a name - static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED); - ModelAPI_EventCreator::get()->sendUpdated(theResult, anEvent); + 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) + const boost::shared_ptr& theFeatureData, const int theIndex) { - ObjectPtr anOldObject = object(boost::dynamic_pointer_cast(theFeatureData)-> - label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theIndex + 1)); + 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); + storeResult(theFeatureData, aResult, theIndex); } return aResult; } boost::shared_ptr Model_Document::createBody( - const boost::shared_ptr& theFeatureData, const int theIndex) + const boost::shared_ptr& theFeatureData, const int theIndex) { - ObjectPtr anOldObject = object(boost::dynamic_pointer_cast(theFeatureData)-> - label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theIndex + 1)); + 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); + storeResult(theFeatureData, aResult, theIndex); } return aResult; } boost::shared_ptr Model_Document::createPart( - const boost::shared_ptr& theFeatureData, const int theIndex) + const boost::shared_ptr& theFeatureData, const int theIndex) { - ObjectPtr anOldObject = object(boost::dynamic_pointer_cast(theFeatureData)-> - label().Father().FindChild(TAG_FEATURE_RESULTS).FindChild(theIndex + 1)); + 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); + storeResult(theFeatureData, aResult, theIndex); } return aResult; } boost::shared_ptr Model_Document::feature( - const boost::shared_ptr& theResult) -{ - // iterate all features in order to find the needed result - std::map >::iterator aFind = - myObjs.find(ModelAPI_Feature::group()); - if (aFind != myObjs.end()) { - std::vector::iterator aFIter = aFind->second.begin(); - for(; aFIter != aFind->second.end(); aFIter++) { - FeaturePtr aFeature = boost::dynamic_pointer_cast(*aFIter); - const std::list >& aResults = aFeature->results(); - std::list >::const_iterator aRIter = aResults.begin(); - for(; aRIter != aResults.cend(); aRIter++) { - if (*aRIter == theResult) { - return aFeature; + 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()) { + 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); + } } } - return FeaturePtr(); +} + +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); + +} +Standard_Boolean IsEqual(const TDF_Label& theLab1, const TDF_Label& theLab2) +{ + return TDF_LabelMapHasher::IsEqual(theLab1, theLab2); }