X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FModel%2FModel_Document.cpp;h=266622522498c4edf7359632df35d05102a8a126;hb=6b4c275bd0ec90bbd4f34614ece1535a6ce2bbe7;hp=d33caaae8109707c31480b20d5ef28a1aa43813f;hpb=37bf139347283d16d59b08079d52be5f6f29a38c;p=modules%2Fshaper.git diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index d33caaae8..266622522 100644 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -5,103 +5,158 @@ #include #include #include +#include #include #include -#include #include #include +#include #include #include #include +#include +#include +#include #include +#ifndef WIN32 +#include +#endif + +#ifdef WIN32 +# define _separator_ '\\' +#else +# define _separator_ '/' +#endif 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 (Root for Model_DatasMgr) -static const int TAG_HISTORY = 3; // tag of the history sub-tree (Root for Model_History) +static const int TAG_OBJECTS = 2; // tag of the objects sub-tree (features) +static const int TAG_HISTORY = 3; // tag of the history sub-tree (python dump) using namespace std; +/// 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) +{ + TCollection_ExtendedString aPath ((const Standard_CString)theFileName); + aPath += _separator_; + aPath += theID.c_str(); + aPath += ".cbf"; // standard binary file extension + return aPath; +} + bool Model_Document::load(const char* theFileName) { - bool myIsError = Standard_False; - /* - TCollection_ExtendedString aPath ((const Standard_CString)theFileName); - PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1; - try - { - Handle(TDocStd_Document) aDoc = this; - aStatus = Model_Application::GetApplication()->Open(aPath, aDoc); - } - catch (Standard_Failure) - {} - myIsError = aStatus != PCDM_RS_OK; - if (myIsError) - { - switch (aStatus) - { - case PCDM_RS_UnknownDocument: cout<<"OCAFApp_Appl_RUnknownDocument"<rootDocument().get()) { + anApp->setLoadPath(theFileName); + } + TCollection_ExtendedString aPath (DocFileName(theFileName, myID)); + PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1; + try + { + aStatus = anApp->Open(aPath, myDoc); + } + catch (Standard_Failure) + { + Handle(Standard_Failure) aFail = Standard_Failure::Caught(); + Events_Error::send(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) { + myDoc->SetUndoLimit(UNDO_LIMIT); + synchronizeFeatures(); + } + return !isError; } bool Model_Document::save(const char* theFileName) { - bool myIsError = true; - /* - TCollection_ExtendedString aPath ((const Standard_CString)theFileName); - PCDM_StoreStatus aStatus; - try { - Handle(TDocStd_Document) aDoc = this; - aStatus = Model_Application::GetApplication()->SaveAs (aDoc, aPath); - } - catch (Standard_Failure) { - Handle(Standard_Failure) aFail = Standard_Failure::Caught(); - cout<<"OCAFApp_Engine:save Error: "<GetMessageString()<rootDocument().get()) { +#ifdef WIN32 + CreateDirectory(theFileName, NULL); +#else + mkdir(theFileName, 0x1ff); +#endif + } + // filename in the dir is id of document inside of the given directory + TCollection_ExtendedString aPath(DocFileName(theFileName, myID)); + PCDM_StoreStatus aStatus; + try { + aStatus = Model_Application::getApplication()->SaveAs(myDoc, aPath); + } + catch (Standard_Failure) { + Handle(Standard_Failure) aFail = Standard_Failure::Caught(); + Events_Error::send(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; + } + } + 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); + } + return isDone; } void Model_Document::close() @@ -118,6 +173,10 @@ void Model_Document::close() void Model_Document::startOperation() { + // check is it nested or not + if (myDoc->HasOpenCommand()) { + myNestedStart = myTransactionsAfterSave; + } // new command for this myDoc->NewCommand(); // new command for all subs @@ -128,6 +187,8 @@ void Model_Document::startOperation() void Model_Document::finishOperation() { + if (myNestedStart > myTransactionsAfterSave) // this nested transaction is owervritten + myNestedStart = 0; // returns false if delta is empty and no transaction was made myIsEmptyTr[myTransactionsAfterSave] = !myDoc->CommitCommand(); myTransactionsAfterSave++; @@ -140,6 +201,7 @@ void Model_Document::finishOperation() void Model_Document::abortOperation() { myDoc->AbortCommand(); + synchronizeFeatures(); // abort for all subs set::iterator aSubIter = mySubs.begin(); for(; aSubIter != mySubs.end(); aSubIter++) @@ -160,7 +222,7 @@ bool Model_Document::isModified() bool Model_Document::canUndo() { - if (myDoc->GetAvailableUndos() > 0) + if (myDoc->GetAvailableUndos() > 0 && myNestedStart != myTransactionsAfterSave) return true; // check other subs contains operation that can be undoed set::iterator aSubIter = mySubs.begin(); @@ -208,7 +270,8 @@ void Model_Document::redo() boost::shared_ptr Model_Document::addFeature(string theID) { - boost::shared_ptr aFeature = ModelAPI_PluginManager::get()->createFeature(theID); + boost::shared_ptr aFeature = + ModelAPI_PluginManager::get()->createFeature(theID); if (aFeature) { boost::dynamic_pointer_cast(aFeature->documentToAdd())->addFeature(aFeature); } else { @@ -217,56 +280,76 @@ boost::shared_ptr Model_Document::addFeature(string theID) return aFeature; } +/// Appenad to the array of references a new referenced label +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++) { + aNewArray->SetValue(a, aRefs->Value(a)); + } + aNewArray->SetValue(aRefs->Upper() + 1, theReferenced); + aRefs->SetInternalArray(aNewArray); + } +} + void Model_Document::addFeature(const boost::shared_ptr theFeature) { - const std::string& aGroup = theFeature->getGroup(); - TDF_Label aGroupLab = groupLabel(aGroup); - TDF_Label anObjLab = aGroupLab.NewChild(); + boost::shared_ptr aThis = + Model_Application::getApplication()->getDocument(myID); + TDF_Label aFeaturesLab = groupLabel(FEATURES_GROUP); + TDF_Label aFeatureLab = aFeaturesLab.NewChild(); + + // organize feature and data objects boost::shared_ptr aData(new Model_Data); - aData->setLabel(anObjLab); - boost::shared_ptr aThis = Model_Application::getApplication()->getDocument(myID); - aData->setDocument(aThis); + aData->setFeature(theFeature); + aData->setLabel(aFeatureLab); + theFeature->setDoc(aThis); theFeature->setData(aData); setUniqueName(theFeature); theFeature->initAttributes(); + // keep the feature ID to restore document later correctly - TDataStd_Comment::Set(anObjLab, theFeature->getKind().c_str()); - // put index of the feature in the group in the tree - TDataStd_Integer::Set(anObjLab, myFeatures[aGroup].size()); - myFeatures[aGroup].push_back(theFeature); + TDataStd_Comment::Set(aFeatureLab, theFeature->getKind().c_str()); + myFeatures.push_back(theFeature); + // store feature in the history of features array + if (theFeature->isInHistory()) { + AddToRefArray(aFeaturesLab, aFeatureLab); + } + // add featue to the group + const std::string& aGroup = theFeature->getGroup(); + TDF_Label aGroupLab = groupLabel(aGroup); + AddToRefArray(aGroupLab, aFeatureLab); + // new name of this feature object by default equal to name of feature + TDF_Label anObjLab = aGroupLab.NewChild(); + TCollection_ExtendedString aName(theFeature->data()->getName().c_str()); + TDataStd_Name::Set(anObjLab, aName); + TDF_Label aGrLabChild = aGroupLab.FindChild(1); + AddToRefArray(aGrLabChild, anObjLab); // reference to names is on the first sub // event: feature is added static Events_ID anEvent = Events_Loop::eventByName(EVENT_FEATURE_CREATED); - ModelAPI_FeatureUpdatedMessage aMsg(aThis, theFeature, anEvent); + Model_FeatureUpdatedMessage aMsg(theFeature, anEvent); Events_Loop::loop()->send(aMsg); } boost::shared_ptr Model_Document::feature(TDF_Label& theLabel) { - Handle(TDataStd_Integer) aFeatureIndex; - if (theLabel.FindAttribute(TDataStd_Integer::GetID(), aFeatureIndex)) { - Handle(TDataStd_Comment) aGroupID; - if (theLabel.Father().FindAttribute(TDataStd_Comment::GetID(), aGroupID)) { - string aGroup = TCollection_AsciiString(aGroupID->Get()).ToCString(); - return myFeatures[aGroup][aFeatureIndex->Get()]; - } + // iterate all features, may be optimized later by keeping labels-map + vector >::iterator aFIter = myFeatures.begin(); + for(; aFIter != myFeatures.end(); aFIter++) { + boost::shared_ptr aData = + boost::dynamic_pointer_cast((*aFIter)->data()); + if (aData->label().IsEqual(theLabel)) + return *aFIter; } return boost::shared_ptr(); // not found } -int Model_Document::featureIndex(boost::shared_ptr theFeature) -{ - if (theFeature->data()->document().get() != this) { - return theFeature->data()->document()->featureIndex(theFeature); - } - boost::shared_ptr aData = boost::dynamic_pointer_cast(theFeature->data()); - Handle(TDataStd_Integer) aFeatureIndex; - if (aData->label().FindAttribute(TDataStd_Integer::GetID(), aFeatureIndex)) { - return aFeatureIndex->Get(); - } - return -1; // not found -} - boost::shared_ptr Model_Document::subDocument(string theDocID) { // just store sub-document identifier here to manage it later @@ -275,27 +358,39 @@ boost::shared_ptr Model_Document::subDocument(string theDocID return Model_Application::getApplication()->getDocument(theDocID); } -boost::shared_ptr Model_Document::featuresIterator(const string theGroup) +boost::shared_ptr Model_Document::feature( + const string& theGroupID, const int theIndex) { - boost::shared_ptr aThis(Model_Application::getApplication()->getDocument(myID)); - // create an empty iterator for not existing group - // (to avoidance of attributes management outside the transaction) - if (myGroups.find(theGroup) == myGroups.end()) - return boost::shared_ptr(new Model_Iterator()); - return boost::shared_ptr(new Model_Iterator(aThis, groupLabel(theGroup))); -} + TDF_Label aGroupLab = groupLabel(theGroupID); + Handle(TDataStd_ReferenceArray) aRefs; + if (aGroupLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) { + if (aRefs->Lower() <= theIndex && aRefs->Upper() >= theIndex) { + TDF_Label aFeatureLab = aRefs->Value(theIndex); + boost::shared_ptr aFeature = feature(aFeatureLab); + + if (theGroupID == FEATURES_GROUP) { // just returns the feature from the history + return aFeature; + } else { // create a new object from the group to return it + Handle(TDataStd_Name) aName; // name of the object + if (aGroupLab.FindChild(1).FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) + aRefs->Value(theIndex).FindAttribute(TDataStd_Name::GetID(), aName); + boost::shared_ptr anObj(new Model_Object(aFeature, aName)); + return anObj; + } + } + } -boost::shared_ptr Model_Document::feature(const string& theGroupID, const int theIndex) -{ - // TODO: optimize this method - boost::shared_ptr anIter = featuresIterator(theGroupID); - for(int a = 0; a != theIndex && anIter->more(); anIter->next()) a++; - return anIter->more() ? anIter->current() : boost::shared_ptr(); + // not found + return boost::shared_ptr(); } -const vector& Model_Document::getGroups() const +int Model_Document::size(const string& theGroupID) { - return myGroupsNames; + Handle(TDataStd_ReferenceArray) aRefs; + if (groupLabel(theGroupID).FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) + return aRefs->Length(); + // group is not found + return 0; } Model_Document::Model_Document(const std::string theID) @@ -303,32 +398,35 @@ Model_Document::Model_Document(const std::string theID) { myDoc->SetUndoLimit(UNDO_LIMIT); myTransactionsAfterSave = 0; - // to avoid creation of tag outside of the transaction (by iterator, for example) - /* - if (!myDoc->Main().FindChild(TAG_OBJECTS).IsAttribute(TDF_TagSource::GetID())) - TDataStd_Comment::Set(myDoc->Main().FindChild(TAG_OBJECTS).NewChild(), ""); - */ + myNestedStart = 0; + myDoc->SetNestedTransactionMode(); + // to have something in the document and avoid empty doc open/save problem + TDataStd_Integer::Set(myDoc->Main().Father(), 0); } TDF_Label Model_Document::groupLabel(const string theGroup) { - if (myGroups.find(theGroup) == myGroups.end()) { - myGroups[theGroup] = myDoc->Main().FindChild(TAG_OBJECTS).NewChild(); - myGroupsNames.push_back(theGroup); - // set to the group label the group idntifier to restore on "open" - TDataStd_Comment::Set(myGroups[theGroup], theGroup.c_str()); - myFeatures[theGroup] = vector >(); + // 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(); } - return myGroups[theGroup]; + // create a new + TDF_Label aNew = myDoc->Main().FindChild(TAG_OBJECTS).NewChild(); + TDataStd_Comment::Set(aNew, aGroup); + return aNew; } void Model_Document::setUniqueName(boost::shared_ptr theFeature) { // first count all objects of such kind to start with index = count + 1 - int aNumObjects = 0; - boost::shared_ptr anIter = featuresIterator(theFeature->getGroup()); - for(; anIter->more(); anIter->next()) { - if (anIter->currentKind() == theFeature->getKind()) + int a, aNumObjects = 0; + int aSize = size(FEATURES_GROUP); + for(a = 0; a < aSize; a++) { + if (feature(FEATURES_GROUP, a)->getKind() == theFeature->getKind()) aNumObjects++; } // generate candidate name @@ -336,109 +434,94 @@ void Model_Document::setUniqueName(boost::shared_ptr theFeatur aNameStream<getKind()<<"_"<getGroup()); anIter->more();) { - if (anIter->currentName() == aName) { + for(a = 0; a < aSize;) { + if (feature(FEATURES_GROUP, a)->data()->getName() == aName) { aNumObjects++; stringstream aNameStream; aNameStream<getKind()<<"_"<getGroup()); - } else anIter->next(); + a = 0; + } else a++; } theFeature->data()->setName(aName); } +//! Returns the object by the feature +boost::shared_ptr Model_Document::objectByFeature( + const boost::shared_ptr theFeature) +{ + for(int a = 0; a < size(theFeature->getGroup()); a++) { + boost::shared_ptr anObj = + boost::dynamic_pointer_cast(feature(theFeature->getGroup(), a)); + if (anObj) { + return anObj; + } + } + return boost::shared_ptr(); // not found +} + void Model_Document::synchronizeFeatures() { boost::shared_ptr aThis = Model_Application::getApplication()->getDocument(myID); - // iterate groups labels - TDF_ChildIDIterator aGroupsIter(myDoc->Main().FindChild(TAG_OBJECTS), - TDataStd_Comment::GetID(), Standard_False); - vector::iterator aGroupNamesIter = myGroupsNames.begin(); - for(; aGroupsIter.More() && aGroupNamesIter != myGroupsNames.end(); - aGroupsIter.Next(), aGroupNamesIter++) { - string aGroupName = TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast( - aGroupsIter.Value())->Get()).ToCString(); - if (*aGroupNamesIter != aGroupName) - break; // all since there is a change this must be recreated from scratch - } - // delete all groups left after the data model groups iteration - while(aGroupNamesIter != myGroupsNames.end()) { - string aGroupName = *aGroupNamesIter; - myFeatures.erase(aGroupName); - myGroups.erase(aGroupName); - aGroupNamesIter = myGroupsNames.erase(aGroupNamesIter); - // say that features were deleted from group - ModelAPI_FeatureDeletedMessage aMsg(aThis, aGroupName); - Events_Loop::loop()->send(aMsg); - } - // create new groups basing on the following data model update - for(; aGroupsIter.More(); aGroupsIter.Next()) { - string aGroupName = TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast( - aGroupsIter.Value())->Get()).ToCString(); - myGroupsNames.push_back(aGroupName); - myGroups[aGroupName] = aGroupsIter.Value()->Label(); - myFeatures[aGroupName] = vector >(); - } - // update features group by group - aGroupsIter.Initialize(myDoc->Main().FindChild(TAG_OBJECTS), - TDataStd_Comment::GetID(), Standard_False); - for(; aGroupsIter.More(); aGroupsIter.Next()) { - string aGroupName = TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast( - aGroupsIter.Value())->Get()).ToCString(); - // iterate features in internal container - vector >& aFeatures = myFeatures[aGroupName]; - vector >::iterator aFIter = aFeatures.begin(); - // and in parallel iterate labels of features - TDF_ChildIDIterator aFLabIter( - aGroupsIter.Value()->Label(), TDataStd_Comment::GetID(), Standard_False); - while(aFIter != aFeatures.end() || aFLabIter.More()) { - static const int INFINITE_TAG = INT_MAX; // no label means that it exists somwhere in infinite - int aFeatureTag = INFINITE_TAG; - if (aFIter != aFeatures.end()) { // existing tag for feature - boost::shared_ptr aData = boost::dynamic_pointer_cast((*aFIter)->data()); - aFeatureTag = aData->label().Tag(); - } - int aDSTag = INFINITE_TAG; - if (aFLabIter.More()) { // next label in DS is existing - aDSTag = aFLabIter.Value()->Label().Tag(); - } - if (aDSTag > aFeatureTag) { // feature is removed - aFIter = aFeatures.erase(aFIter); - // event: model is updated - ModelAPI_FeatureDeletedMessage aMsg(aThis, aGroupName); - Events_Loop::loop()->send(aMsg); - } else if (aDSTag < aFeatureTag) { // a new feature is inserted - // create a feature - boost::shared_ptr aFeature = ModelAPI_PluginManager::get()->createFeature( - TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast( - aFLabIter.Value())->Get()).ToCString()); - - boost::shared_ptr aData(new Model_Data); - TDF_Label aLab = aFLabIter.Value()->Label(); - aData->setLabel(aLab); - aData->setDocument(Model_Application::getApplication()->getDocument(myID)); - aFeature->setData(aData); - aFeature->initAttributes(); - // event: model is updated - static Events_ID anEvent = Events_Loop::eventByName(EVENT_FEATURE_CREATED); - ModelAPI_FeatureUpdatedMessage aMsg(aThis, aFeature, anEvent); - Events_Loop::loop()->send(aMsg); - - if (aFIter == aFeatures.end()) { - aFeatures.push_back(aFeature); - aFIter = aFeatures.end(); - } else { - aFIter++; - aFeatures.insert(aFIter, aFeature); - } - // feature for this label is added, so go to the next label - aFLabIter.Next(); - } else { // nothing is changed, both iterators are incremented + // update features + vector >::iterator aFIter = myFeatures.begin(); + // and in parallel iterate labels of features + TDF_ChildIDIterator aFLabIter(groupLabel(FEATURES_GROUP), TDataStd_Comment::GetID()); + while(aFIter != myFeatures.end() || aFLabIter.More()) { + static const int INFINITE_TAG = INT_MAX; // no label means that it exists somwhere in infinite + int aFeatureTag = INFINITE_TAG; + if (aFIter != myFeatures.end()) { // existing tag for feature + boost::shared_ptr aData = boost::dynamic_pointer_cast((*aFIter)->data()); + aFeatureTag = aData->label().Tag(); + } + int aDSTag = INFINITE_TAG; + if (aFLabIter.More()) { // next label in DS is existing + aDSTag = aFLabIter.Value()->Label().Tag(); + } + if (aDSTag > aFeatureTag) { // feature is removed + Model_FeatureDeletedMessage aMsg1(aThis, FEATURES_GROUP); + Model_FeatureDeletedMessage aMsg2(aThis, (*aFIter)->getGroup()); + aFIter = myFeatures.erase(aFIter); + // event: model is updated + Events_Loop::loop()->send(aMsg1); + Events_Loop::loop()->send(aMsg2); + } else if (aDSTag < aFeatureTag) { // a new feature is inserted + // create a feature + boost::shared_ptr aFeature = ModelAPI_PluginManager::get()->createFeature( + TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast( + aFLabIter.Value())->Get()).ToCString()); + + if (aFIter == myFeatures.end()) { // must be before "setData" to redo the sketch line correctly + myFeatures.push_back(aFeature); + aFIter = myFeatures.end(); + } else { aFIter++; - aFLabIter.Next(); + myFeatures.insert(aFIter, aFeature); + } + boost::shared_ptr aData(new Model_Data); + TDF_Label aLab = aFLabIter.Value()->Label(); + aData->setLabel(aLab); + aData->setFeature(aFeature); + aFeature->setDoc(aThis); + aFeature->setData(aData); + aFeature->initAttributes(); + + // event: model is updated + static Events_ID anEvent = Events_Loop::eventByName(EVENT_FEATURE_CREATED); + Model_FeatureUpdatedMessage aMsg1(aFeature, anEvent); + Events_Loop::loop()->send(aMsg1); + boost::shared_ptr anObj = objectByFeature(aFeature); + if (anObj) { + Model_FeatureUpdatedMessage aMsg2(anObj, anEvent); + Events_Loop::loop()->send(aMsg2); } + + // feature for this label is added, so go to the next label + aFLabIter.Next(); + } else { // nothing is changed, both iterators are incremented + aFIter++; + aFLabIter.Next(); } } }