From eacec078e7652d28974cb3b6ec166be42c75c813 Mon Sep 17 00:00:00 2001 From: mpv Date: Wed, 3 Feb 2016 12:21:45 +0300 Subject: [PATCH] Update the internal persistence mechanism of documents identification: on load/save, undo/redo of documents creation or deletion, external references between the documents --- src/Model/Model_Application.cpp | 75 +++++++++---- src/Model/Model_Application.h | 28 ++++- src/Model/Model_AttributeDocRef.cpp | 25 ++--- src/Model/Model_AttributeDocRef.h | 9 +- src/Model/Model_AttributeReference.cpp | 10 +- src/Model/Model_Document.cpp | 105 ++++++++++-------- src/Model/Model_Document.h | 30 ++--- src/Model/Model_Objects.cpp | 15 ++- src/Model/Model_Objects.h | 4 + src/Model/Model_ResultPart.cpp | 24 ++-- src/Model/Model_ResultPart.h | 1 - src/Model/Model_Session.cpp | 39 +++---- src/Model/Model_Session.h | 8 +- src/ModelAPI/ModelAPI_AttributeDocRef.h | 3 + src/ModelAPI/ModelAPI_Document.h | 7 +- src/ModelAPI/ModelAPI_Session.h | 8 +- src/ModelAPI/Test/TestDocument.py | 14 +-- src/PartSetPlugin/PartSetPlugin_Duplicate.cpp | 30 ++--- src/PartSetPlugin/PartSetPlugin_Duplicate.h | 47 ++++++-- 19 files changed, 283 insertions(+), 199 deletions(-) diff --git a/src/Model/Model_Application.cpp b/src/Model/Model_Application.cpp index 4dddb449d..24a16b9ad 100644 --- a/src/Model/Model_Application.cpp +++ b/src/Model/Model_Application.cpp @@ -23,35 +23,51 @@ Handle(Model_Application) Model_Application::getApplication() } //======================================================================= -const std::shared_ptr& Model_Application::getDocument(string theDocID) +std::shared_ptr Model_Application::document(const int theDocID) { if (myDocs.find(theDocID) != myDocs.end()) return myDocs[theDocID]; + return std::shared_ptr(); // not loaded, so return null +} +//======================================================================= +void Model_Application::createDocument(const int theDocID) +{ static const std::string thePartSetKind("PartSet"); static const std::string thePartKind("Part"); - bool isRoot = theDocID == "root"; // the document is root std::shared_ptr aNew( - new Model_Document(theDocID, isRoot ? thePartSetKind : thePartKind)); + new Model_Document(theDocID, theDocID == 0 ? thePartSetKind : thePartKind)); myDocs[theDocID] = aNew; + aNew->setThis(aNew); + static Events_ID anId = ModelAPI_DocumentCreatedMessage::eventId(); + std::shared_ptr aMessage = std::shared_ptr + (new ModelAPI_DocumentCreatedMessage(anId, this)); + aMessage->setDocument(aNew); + Events_Loop::loop()->send(aMessage); +} + +//======================================================================= +bool Model_Application::loadDocument(const std::string theDocName, const int theDocID) +{ + static const std::string thePartKind("Part"); // root document is never loaded here + std::shared_ptr aNew(new Model_Document(theDocID, thePartKind)); + myDocs[theDocID] = aNew; + + bool aRes = true; // load it if it must be loaded by demand - if (myLoadedByDemand.find(theDocID) != myLoadedByDemand.end() && !myPath.empty()) { - aNew->load(myPath.c_str(), aNew); - myLoadedByDemand.erase(theDocID); // done, don't do it anymore - } else { - aNew->setThis(aNew); - static Events_ID anId = ModelAPI_DocumentCreatedMessage::eventId(); - std::shared_ptr aMessage = std::shared_ptr - (new ModelAPI_DocumentCreatedMessage(anId, this)); - aMessage->setDocument(aNew); - Events_Loop::loop()->send(aMessage); + if (myLoadedByDemand.find(theDocName) != myLoadedByDemand.end() && !myPath.empty()) { + aRes = aNew->load(myPath.c_str(), theDocName.c_str(), aNew); + myLoadedByDemand.erase(theDocName); // done, don't do it anymore + } else { // error + aRes = false; } - return myDocs[theDocID]; + return aRes; } -void Model_Application::deleteDocument(string theDocID) +//======================================================================= +void Model_Application::deleteDocument(const int theDocID) { if (myDocs.find(theDocID) != myDocs.end()) { myDocs[theDocID]->close(true); @@ -60,22 +76,36 @@ void Model_Application::deleteDocument(string theDocID) myLoadedByDemand.clear(); } +//======================================================================= void Model_Application::deleteAllDocuments() { - std::map >::iterator aDoc = myDocs.begin(); + std::map >::iterator aDoc = myDocs.begin(); for(; aDoc != myDocs.end(); aDoc++) { - aDoc->second->close(true); + if (!aDoc->second->isOpened()) // here is main document was closed before subs and closed subs + aDoc->second->close(true); } myDocs.clear(); myLoadedByDemand.clear(); } //======================================================================= -bool Model_Application::hasDocument(std::string theDocID) +bool Model_Application::hasDocument(const int theDocID) { return myDocs.find(theDocID) != myDocs.end(); } +//======================================================================= +bool Model_Application::hasRoot() +{ + return !myDocs.empty(); +} + +//======================================================================= +std::shared_ptr Model_Application::rootDocument() +{ + return myDocs[0]; +} + //======================================================================= void Model_Application::setLoadPath(std::string thePath) { @@ -104,7 +134,7 @@ bool Model_Application::isLoadByDemand(std::string theID) void Model_Application::removeUselessDocuments( std::list > theUsedDocs) { - std::map >::iterator aDoc = myDocs.begin(); + std::map >::iterator aDoc = myDocs.begin(); while(aDoc != myDocs.end()) { bool aFound = false; std::list >::iterator aUsed = theUsedDocs.begin(); @@ -121,6 +151,13 @@ void Model_Application::removeUselessDocuments( } } +int Model_Application::generateDocumentId() +{ + int aResult = myDocs.size(); + for(; myDocs.find(aResult) != myDocs.end(); aResult++); // count until the result id is unique + return aResult; +} + //======================================================================= Model_Application::Model_Application() { diff --git a/src/Model/Model_Application.h b/src/Model/Model_Application.h index b5a2af8e0..728c2a807 100644 --- a/src/Model/Model_Application.h +++ b/src/Model/Model_Application.h @@ -34,14 +34,27 @@ public: //! Retuns the application: one per process MODEL_EXPORT static Handle_Model_Application getApplication(); - //! Returns the main document (on first call creates it) by the string identifier - MODEL_EXPORT const std::shared_ptr& getDocument(std::string theDocID); + //! Returns the document by the identifier + //! \returns false of document is not yet created/not loaded + MODEL_EXPORT std::shared_ptr document(const int theDocID); //! Returns true if document has been created - MODEL_EXPORT bool hasDocument(std::string theDocID); + MODEL_EXPORT bool hasDocument(const int theDocID); + //! Returns true if root document has been created + MODEL_EXPORT bool hasRoot(); + //! Returns root document, if created (or null otherwise) + MODEL_EXPORT std::shared_ptr rootDocument(); //! Deletes the document from the application - MODEL_EXPORT void deleteDocument(std::string theDocID); + MODEL_EXPORT void deleteDocument(const int theDocID); //! Deletes all documents existing in the application MODEL_EXPORT void deleteAllDocuments(); + //! Creates a new document an returns an id of this document + //! \param theDocID if it is zero, the root document is created + MODEL_EXPORT void createDocument(const int theDocID); + //! Loads document by the file name (if it is registered as load by demand) + //! \param theDocName name of the document file + //! \param theDocID the identifier of the loaded document (to be created) + //! \returns true if load is ok + MODEL_EXPORT bool loadDocument(const std::string theDocName, const int theDocID); //! Set path for the loaded by demand documents void setLoadPath(std::string thePath); @@ -55,6 +68,9 @@ public: //! not in the given list void removeUselessDocuments(std::list > theUsedDocs); + //! produces new unique identifier of the document + int generateDocumentId(); + public: // Redefined OCAF methods //! Return name of resource (i.e. "Standard") @@ -68,8 +84,8 @@ public: Model_Application(); private: - /// Map from string identifiers to created documents of an application - std::map > myDocs; + /// Map from identifiers to created documents of an application + std::map > myDocs; /// Path for the loaded by demand documents std::string myPath; /// Path for the loaded by demand documents diff --git a/src/Model/Model_AttributeDocRef.cpp b/src/Model/Model_AttributeDocRef.cpp index 2284226c2..5c3eaf442 100644 --- a/src/Model/Model_AttributeDocRef.cpp +++ b/src/Model/Model_AttributeDocRef.cpp @@ -13,30 +13,27 @@ using namespace std; void Model_AttributeDocRef::setValue(std::shared_ptr theDoc) { - myDoc = theDoc; - TCollection_ExtendedString aNewID(theDoc->id().c_str()); - if (!myIsInitialized || myComment->Get() != aNewID) { - myComment->Set(TCollection_ExtendedString(theDoc->id().c_str())); + if (myID->Get() != theDoc->id()) { + myID->Set(theDoc->id()); owner()->data()->sendAttributeUpdated(this); } } std::shared_ptr Model_AttributeDocRef::value() { - return myDoc; + return Model_Application::getApplication()->document(myID->Get()); +} + +int Model_AttributeDocRef::docId() +{ + return myID->Get(); } Model_AttributeDocRef::Model_AttributeDocRef(TDF_Label& theLabel) { - myIsInitialized = theLabel.FindAttribute(TDataStd_Comment::GetID(), myComment) == Standard_True; + myIsInitialized = theLabel.FindAttribute(TDataStd_Integer::GetID(), myID) == Standard_True; if (!myIsInitialized) { - // create attribute: not initialized by value yet, just empty string - myComment = TDataStd_Comment::Set(theLabel, ""); - } else { // document was already referenced: try to set it as loaded by demand - Handle(Model_Application) anApp = Model_Application::getApplication(); - string anID(TCollection_AsciiString(myComment->Get()).ToCString()); - if (!anApp->hasDocument(anID)) { - anApp->setLoadByDemand(anID); - } + int aNewID = Model_Application::getApplication()->generateDocumentId(); + myID = TDataStd_Integer::Set(theLabel, aNewID); } } diff --git a/src/Model/Model_AttributeDocRef.h b/src/Model/Model_AttributeDocRef.h index 3a4638a69..04eacc437 100644 --- a/src/Model/Model_AttributeDocRef.h +++ b/src/Model/Model_AttributeDocRef.h @@ -9,7 +9,7 @@ #include "Model.h" #include "ModelAPI_AttributeDocRef.h" -#include +#include #include /**\class Model_AttributeDocRef @@ -19,15 +19,18 @@ class Model_AttributeDocRef : public ModelAPI_AttributeDocRef { - Handle_TDataStd_Comment myComment; ///< reference to document is identified as string-id - std::shared_ptr myDoc; ///< document referenced by this attribute (if already loaded) + Handle(TDataStd_Integer) myID; ///< persistent and unique identifier of the document in the application public: + /// Defines the document referenced from this attribute MODEL_EXPORT virtual void setValue(std::shared_ptr theDoc); /// Returns document referenced from this attribute MODEL_EXPORT virtual std::shared_ptr value(); + /// Returns the persisten ID of the document + MODEL_EXPORT virtual int docId(); + protected: /// Initializes attibutes Model_AttributeDocRef(TDF_Label& theLabel); diff --git a/src/Model/Model_AttributeReference.cpp b/src/Model/Model_AttributeReference.cpp index beb04549c..40ad13ad9 100644 --- a/src/Model/Model_AttributeReference.cpp +++ b/src/Model/Model_AttributeReference.cpp @@ -46,7 +46,9 @@ void Model_AttributeReference::setValue(ObjectPtr theObject) myRef->Label().ForgetAttribute(TDataStd_AsciiString::GetID()); } else { // different document: store the document name (comment) and entry (string): external // if these attributes exist, the link is external: keep reference to access the label - TDataStd_Comment::Set(myRef->Label(), theObject->document()->id().c_str()); + std::ostringstream anIdString; // string with document Id + anIdString<document()->id(); + TDataStd_Comment::Set(myRef->Label(), anIdString.str().c_str()); TCollection_AsciiString anEntry; TDF_Tool::Entry(anObjLab, anEntry); TDataStd_AsciiString::Set(myRef->Label(), anEntry); @@ -64,9 +66,9 @@ ObjectPtr Model_AttributeReference::value() if (isInitialized()) { Handle(TDataStd_Comment) aDocID; if (myRef->Label().FindAttribute(TDataStd_Comment::GetID(), aDocID)) { // external ref - DocumentPtr aRefDoc = - ModelAPI_Session::get()->document(TCollection_AsciiString(aDocID->Get()).ToCString()); - if (aRefDoc) { + int anID = atoi(TCollection_AsciiString(aDocID->Get()).ToCString()); + DocumentPtr aRefDoc = Model_Application::getApplication()->document(anID); + if (aRefDoc.get()) { Handle(TDataStd_AsciiString) anEntry; if (myRef->Label().FindAttribute(TDataStd_AsciiString::GetID(), anEntry)) { std::shared_ptr aDR = std::dynamic_pointer_cast(aRefDoc); diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index 645291f72..280da04f2 100755 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -59,7 +59,7 @@ static const int TAG_CURRENT_FEATURE = 1; ///< where the reference to the curren static const int TAG_CURRENT_TRANSACTION = 2; ///< integer, index of the transaction static const int TAG_SELECTION_FEATURE = 3; ///< integer, tag of the selection feature label -Model_Document::Model_Document(const std::string theID, const std::string theKind) +Model_Document::Model_Document(const int theID, const std::string theKind) : myID(theID), myKind(theKind), myIsActive(false), myDoc(new TDocStd_Document("BinOcaf")) // binary OCAF format { @@ -81,10 +81,10 @@ void Model_Document::setThis(DocumentPtr theDoc) myObjs->setOwner(theDoc); } -/// 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) +/// Returns the file name of this document by the name of directory and identifier of a document +static TCollection_ExtendedString DocFileName(const char* theDirName, const std::string& theID) { - TCollection_ExtendedString aPath((const Standard_CString) theFileName); + TCollection_ExtendedString aPath((const Standard_CString) theDirName); // remove end-separators while(aPath.Length() && (aPath.Value(aPath.Length()) == '\\' || aPath.Value(aPath.Length()) == '/')) @@ -100,13 +100,13 @@ bool Model_Document::isRoot() const return this == Model_Session::get()->moduleDocument().get(); } -bool Model_Document::load(const char* theFileName, DocumentPtr theThis) +bool Model_Document::load(const char* theDirName, const char* theFileName, DocumentPtr theThis) { Handle(Model_Application) anApp = Model_Application::getApplication(); if (isRoot()) { - anApp->setLoadPath(theFileName); + anApp->setLoadPath(theDirName); } - TCollection_ExtendedString aPath(DocFileName(theFileName, myID)); + TCollection_ExtendedString aPath(DocFileName(theDirName, theFileName)); PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1; Handle(TDocStd_Document) aLoaded; try { @@ -177,7 +177,7 @@ bool Model_Document::load(const char* theFileName, DocumentPtr theThis) myDoc = aLoaded; myDoc->SetUndoLimit(UNDO_LIMIT); // to avoid the problem that feature is created in the current, not this, document - aSession->setActiveDocument(anApp->getDocument(myID), false); + aSession->setActiveDocument(anApp->document(myID), false); aSession->setCheckTransactions(false); if (myObjs) delete myObjs; @@ -189,13 +189,25 @@ bool Model_Document::load(const char* theFileName, DocumentPtr theThis) aSession->setActiveDocument(Model_Session::get()->moduleDocument(), false); // this is done in Part result "activate", so no needed here. Causes not-blue active part. // aSession->setActiveDocument(anApp->getDocument(myID), true); + + // make sub-parts as loaded by demand + std::list aPartResults; + myObjs->allResults(ModelAPI_ResultPart::group(), aPartResults); + std::list::iterator aPartRes = aPartResults.begin(); + for(; aPartRes != aPartResults.end(); aPartRes++) { + ResultPartPtr aPart = std::dynamic_pointer_cast(*aPartRes); + if (aPart.get()) + anApp->setLoadByDemand(aPart->data()->name()); + } + } else { // open failed, but new documnet was created to work with it: inform the model aSession->setActiveDocument(Model_Session::get()->moduleDocument(), false); } return !isError; } -bool Model_Document::save(const char* theFileName, std::list& theResults) +bool Model_Document::save( + const char* theDirName, const char* theFileName, std::list& theResults) { // create a directory in the root document if it is not yet exist Handle(Model_Application) anApp = Model_Application::getApplication(); @@ -207,7 +219,7 @@ bool Model_Document::save(const char* theFileName, std::list& theRe #endif } // filename in the dir is id of document inside of the given directory - TCollection_ExtendedString aPath(DocFileName(theFileName, myID)); + TCollection_ExtendedString aPath(DocFileName(theDirName, theFileName)); PCDM_StoreStatus aStatus; try { aStatus = anApp->SaveAs(myDoc, aPath); @@ -234,20 +246,22 @@ bool Model_Document::save(const char* theFileName, std::list& theRe } myTransactionSave = myTransactions.size(); if (isDone) { // save also sub-documents if any - theResults.push_back(TCollection_AsciiString(aPath).ToCString()); - const std::set aSubs = subDocuments(false); - std::set::iterator aSubIter = aSubs.begin(); - for (; aSubIter != aSubs.end() && isDone; aSubIter++) { - if (anApp->isLoadByDemand(*aSubIter)) { + // iterate all result parts to find all loaded or not yet loaded documents + std::list aPartResults; + myObjs->allResults(ModelAPI_ResultPart::group(), aPartResults); + std::list::iterator aPartRes = aPartResults.begin(); + for(; aPartRes != aPartResults.end(); aPartRes++) { + ResultPartPtr aPart = std::dynamic_pointer_cast(*aPartRes); + if (!aPart->isActivated()) { // copy not-activated document that is not in the memory - std::string aDocName = *aSubIter; + std::string aDocName = aPart->data()->name(); if (!aDocName.empty()) { // just copy file TCollection_AsciiString aSubPath(DocFileName(anApp->loadPath().c_str(), aDocName)); OSD_Path aPath(aSubPath); OSD_File aFile(aPath); if (aFile.Exists()) { - TCollection_AsciiString aDestinationDir(DocFileName(theFileName, aDocName)); + TCollection_AsciiString aDestinationDir(DocFileName(theDirName, aDocName)); OSD_Path aDestination(aDestinationDir); aFile.Copy(aDestination); theResults.push_back(aDestinationDir.ToCString()); @@ -257,7 +271,8 @@ bool Model_Document::save(const char* theFileName, std::list& theRe } } } else { // simply save opened document - isDone = subDoc(*aSubIter)->save(theFileName, theResults); + isDone = std::dynamic_pointer_cast(aPart->partDoc())-> + save(theDirName, aPart->data()->name().c_str(), theResults); } } } @@ -274,8 +289,8 @@ void Model_Document::close(const bool theForever) aPM->setActiveDocument(DocumentPtr()); } // close all subs - const std::set aSubs = subDocuments(true); - std::set::iterator aSubIter = aSubs.begin(); + const std::set aSubs = subDocuments(); + std::set::iterator aSubIter = aSubs.begin(); for (; aSubIter != aSubs.end(); aSubIter++) { std::shared_ptr aSub = subDoc(*aSubIter); if (aSub->myObjs) // if it was not closed before @@ -322,8 +337,8 @@ void Model_Document::startOperation() (*myNestedNum.rbegin())++; myRedos.clear(); // new command for all subs - const std::set aSubs = subDocuments(true); - std::set::iterator aSubIter = aSubs.begin(); + const std::set aSubs = subDocuments(); + std::set::iterator aSubIter = aSubs.begin(); for (; aSubIter != aSubs.end(); aSubIter++) subDoc(*aSubIter)->startOperation(); } @@ -499,8 +514,8 @@ bool Model_Document::finishOperation() // finish for all subs first: to avoid nested finishing and "isOperation" calls problems inside bool aResult = false; - const std::set aSubs = subDocuments(true); - std::set::iterator aSubIter = aSubs.begin(); + const std::set aSubs = subDocuments(); + std::set::iterator aSubIter = aSubs.begin(); for (; aSubIter != aSubs.end(); aSubIter++) if (subDoc(*aSubIter)->finishOperation()) aResult = true; @@ -594,8 +609,8 @@ void Model_Document::abortOperation() myDoc->ClearRedos(); } // abort for all subs, flushes will be later, in the end of root abort - const std::set aSubs = subDocuments(true); - std::set::iterator aSubIter = aSubs.begin(); + const std::set aSubs = subDocuments(); + std::set::iterator aSubIter = aSubs.begin(); for (; aSubIter != aSubs.end(); aSubIter++) subDoc(*aSubIter)->abortOperation(); // references may be changed because they are set in attributes on the fly @@ -623,8 +638,8 @@ bool Model_Document::canUndo() myTransactions.size() - aCurrentNum > 0 /* for omitting the first useless transaction */) return true; // check other subs contains operation that can be undoed - const std::set aSubs = subDocuments(true); - std::set::iterator aSubIter = aSubs.begin(); + const std::set aSubs = subDocuments(); + std::set::iterator aSubIter = aSubs.begin(); for (; aSubIter != aSubs.end(); aSubIter++) { std::shared_ptr aSub = subDoc(*aSubIter); if (aSub->myObjs) {// if it was not closed before @@ -655,8 +670,8 @@ void Model_Document::undoInternal(const bool theWithSubs, const bool theSynchron if (theWithSubs) { // undo for all subs - const std::set aSubs = subDocuments(true); - std::set::iterator aSubIter = aSubs.begin(); + const std::set aSubs = subDocuments(); + std::set::iterator aSubIter = aSubs.begin(); for (; aSubIter != aSubs.end(); aSubIter++) { if (!subDoc(*aSubIter)->myObjs) continue; @@ -681,8 +696,8 @@ bool Model_Document::canRedo() if (!myRedos.empty()) return true; // check other subs contains operation that can be redoed - const std::set aSubs = subDocuments(true); - std::set::iterator aSubIter = aSubs.begin(); + const std::set aSubs = subDocuments(); + std::set::iterator aSubIter = aSubs.begin(); for (; aSubIter != aSubs.end(); aSubIter++) { if (!subDoc(*aSubIter)->myObjs) continue; @@ -706,8 +721,8 @@ void Model_Document::redo() } // redo for all subs - const std::set aSubs = subDocuments(true); - std::set::iterator aSubIter = aSubs.begin(); + const std::set aSubs = subDocuments(); + std::set::iterator aSubIter = aSubs.begin(); for (; aSubIter != aSubs.end(); aSubIter++) subDoc(*aSubIter)->redo(); @@ -825,31 +840,26 @@ void Model_Document::updateHistory(const std::string theGroup) myObjs->updateHistory(theGroup); } -std::shared_ptr Model_Document::subDocument(std::string theDocID) +const std::set Model_Document::subDocuments() const { - return Model_Application::getApplication()->getDocument(theDocID); -} - -const std::set Model_Document::subDocuments(const bool theActivatedOnly) const -{ - std::set aResult; + std::set aResult; std::list aPartResults; myObjs->allResults(ModelAPI_ResultPart::group(), aPartResults); std::list::iterator aPartRes = aPartResults.begin(); for(; aPartRes != aPartResults.end(); aPartRes++) { ResultPartPtr aPart = std::dynamic_pointer_cast(*aPartRes); - if (aPart && (!theActivatedOnly || aPart->isActivated())) { - aResult.insert(aPart->original()->data()->name()); + if (aPart && aPart->isActivated()) { + aResult.insert(aPart->original()->partDoc()->id()); } } return aResult; } -std::shared_ptr Model_Document::subDoc(std::string theDocID) +std::shared_ptr Model_Document::subDoc(int theDocID) { // just store sub-document identifier here to manage it later return std::dynamic_pointer_cast( - Model_Application::getApplication()->getDocument(theDocID)); + Model_Application::getApplication()->document(theDocID)); } ObjectPtr Model_Document::object(const std::string& theGroupID, const int theIndex) @@ -1164,6 +1174,11 @@ std::shared_ptr Model_Document::internalFeature(const int theI return myObjs->internalFeature(theIndex); } +std::shared_ptr Model_Document::featureById(const int theId) +{ + return myObjs->featureById(theId); +} + void Model_Document::synchronizeTransactions() { Model_Document* aRoot = diff --git a/src/Model/Model_Document.h b/src/Model/Model_Document.h index 25e467e71..6f0b2bee6 100644 --- a/src/Model/Model_Document.h +++ b/src/Model/Model_Document.h @@ -36,16 +36,20 @@ class Model_Document : public ModelAPI_Document MODEL_EXPORT virtual const std::string& kind() const {return myKind;} //! Loads the OCAF document from the file. - //! \param theFileName full name of the file to load + //! \param theDirName directory of the loaded file + //! \param theFileName a name of the file to load //! \param theThis the common shared pointer to the document to manage with it later //! \returns true if file was loaded successfully - MODEL_EXPORT virtual bool load(const char* theFileName, DocumentPtr theThis); + MODEL_EXPORT virtual bool load( + const char* theDirName, const char* theFileName, DocumentPtr theThis); //! Saves the OCAF document to the file. - //! \param theFileName full name of the file to store + //! \param theDirName directory where the document will be saved + //! \param theFileName a name of the document file to store //! \param theResults the result full file names that were stored by "save" //! \returns true if file was stored successfully - MODEL_EXPORT virtual bool save(const char* theFileName, std::list& theResults); + MODEL_EXPORT virtual bool save( + const char* theDirName, const char* theFileName, std::list& theResults); //! Removes document data //! \param theForever if it is false, document is just hiden (to keep possibility make it back on Undo/Redo) @@ -104,14 +108,11 @@ class Model_Document : public ModelAPI_Document //! \returns index started from zero, or -1 if object is invisible or belongs to another document MODEL_EXPORT virtual const int index(std::shared_ptr theObject); - //! Adds a new sub-document by the identifier, or returns existing one if it is already exist - MODEL_EXPORT virtual std::shared_ptr subDocument(std::string theDocID); - //! Internal sub-document by ID - MODEL_EXPORT virtual std::shared_ptr subDoc(std::string theDocID); + MODEL_EXPORT virtual std::shared_ptr subDoc(int theDocID); ///! Returns the id of the document - MODEL_EXPORT virtual const std::string& id() const + MODEL_EXPORT virtual const int id() const { return myID; } @@ -150,6 +151,9 @@ class Model_Document : public ModelAPI_Document //! wihtout this participation MODEL_EXPORT virtual void synchronizeTransactions(); + //! Returns feature by the id of the feature (produced by the Data "featureId" method) + MODEL_EXPORT virtual std::shared_ptr featureById(const int theId); + /// Creates a construction cresults MODEL_EXPORT virtual std::shared_ptr createConstruction( @@ -210,7 +214,7 @@ class Model_Document : public ModelAPI_Document TDF_Label generalLabel() const; //! Creates new document with binary file format - Model_Document(const std::string theID, const std::string theKind); + Model_Document(const int theID, const std::string theKind); //! Returns the internal OCCT document of this interface Handle_TDocStd_Document document() @@ -222,8 +226,8 @@ class Model_Document : public ModelAPI_Document //! \returns true if resulting transaction is not empty and can be undoed void compactNested(); - //! Returns all sub documents - const std::set subDocuments(const bool theActivatedOnly) const; + //! Returns all loaded sub documents + const std::set subDocuments() const; //! The implementation of undo: with or without recoursive calls in the sub-documents void undoInternal(const bool theWithSubs, const bool theSynchronize); @@ -272,7 +276,7 @@ class Model_Document : public ModelAPI_Document friend class DFBrowser; private: - std::string myID; ///< identifier of the document in the application + int myID; ///< identifier of the document in the application std::string myKind; ///< kind of the document in the application Handle_TDocStd_Document myDoc; ///< OCAF document diff --git a/src/Model/Model_Objects.cpp b/src/Model/Model_Objects.cpp index aa8e2751c..63131d43e 100644 --- a/src/Model/Model_Objects.cpp +++ b/src/Model/Model_Objects.cpp @@ -568,12 +568,6 @@ void Model_Objects::setUniqueName(FeaturePtr theFeature) isSameName = (*aRIter)->data()->name() == aName; } } - // for new Parts create names that are not in the Postponed list - if (!isSameName && (theFeature->getKind() == "Part" || theFeature->getKind() == "Duplicate")) { - std::shared_ptr aSession = - std::dynamic_pointer_cast(Model_Session::get()); - isSameName = aSession->isLoadByDemand(aName) || aSession->hasDocument(aName); - } if (isSameName) { aNumObjects++; @@ -602,6 +596,15 @@ void Model_Objects::initData(ObjectPtr theObj, TDF_Label theLab, const int theTa theObj->initAttributes(); } +std::shared_ptr Model_Objects::featureById(const int theId) +{ + if (theId > 0) { + TDF_Label aLab = featuresLabel().FindChild(theId, Standard_False); + return feature(aLab); + } + return std::shared_ptr(); // not found +} + void Model_Objects::synchronizeFeatures( const TDF_LabelList& theUpdated, const bool theUpdateReferences, const bool theFlush) { diff --git a/src/Model/Model_Objects.h b/src/Model/Model_Objects.h index 9f947c776..740a3d542 100644 --- a/src/Model/Model_Objects.h +++ b/src/Model/Model_Objects.h @@ -95,6 +95,10 @@ class Model_Objects //! Returns the feature by zero-based index: features in the history or not std::shared_ptr internalFeature(const int theIndex); + //! Returns feature by the id of the feature (produced by the Data "featureId" method) + std::shared_ptr featureById(const int theId); + + /// Creates a construction result std::shared_ptr createConstruction( const std::shared_ptr& theFeatureData, const int theIndex = 0); diff --git a/src/Model/Model_ResultPart.cpp b/src/Model/Model_ResultPart.cpp index 772cbb384..57dcd9a78 100644 --- a/src/Model/Model_ResultPart.cpp +++ b/src/Model/Model_ResultPart.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -31,9 +32,14 @@ void Model_ResultPart::initAttributes() { // append the color attribute. It is empty, the attribute will be filled by a request - data()->addAttribute(DOC_REF(), ModelAPI_AttributeDocRef::typeId()); + AttributeDocRefPtr aDocRef = std::dynamic_pointer_cast( + data()->addAttribute(DOC_REF(), ModelAPI_AttributeDocRef::typeId())); data()->addAttribute(COLOR_ID(), ModelAPI_AttributeIntArray::typeId()); data()->addAttribute(BASE_REF_ID(), ModelAPI_AttributeReference::typeId()); + + if (aDocRef->isInitialized() && // initialized immideately means already exist and will be loaded + !Model_Application::getApplication()->hasDocument(aDocRef->docId())) + Model_Application::getApplication()->setLoadByDemand(data()->name()); } std::shared_ptr Model_ResultPart::partDoc() @@ -42,15 +48,11 @@ std::shared_ptr Model_ResultPart::partDoc() return baseRef()->partDoc(); } DocumentPtr aRes = data()->document(DOC_REF())->value(); - if (!aRes.get() && myIsInLoad) { // trying to get this document from the session - aRes = document()->subDocument(data()->name()); - } return aRes; } Model_ResultPart::Model_ResultPart() { - myIsInLoad = false; } void Model_ResultPart::activate() @@ -66,14 +68,18 @@ void Model_ResultPart::activate() bool isNewTransaction = false; SessionPtr aMgr = ModelAPI_Session::get(); if (!aDocRef->value().get()) { // create (or open) a document if it is not yet created - myIsInLoad = true; + Handle(Model_Application) anApp = Model_Application::getApplication(); if (!aMgr->isOperation()) { aMgr->startOperation("Activation"); isNewTransaction = true; } - std::shared_ptr aDoc = document()->subDocument(data()->name()); - myIsInLoad = false; - if (aDoc) { + if (anApp->isLoadByDemand(data()->name())) { + anApp->loadDocument(data()->name(), aDocRef->docId()); // if it is just ne part, load may fail + } else { + anApp->createDocument(aDocRef->docId()); + } + std::shared_ptr aDoc = aDocRef->value(); + if (aDoc.get()) { aDoc->synchronizeTransactions(); aDocRef->setValue(aDoc); } diff --git a/src/Model/Model_ResultPart.h b/src/Model/Model_ResultPart.h index 220e1b408..49adb855a 100644 --- a/src/Model/Model_ResultPart.h +++ b/src/Model/Model_ResultPart.h @@ -23,7 +23,6 @@ class Model_ResultPart : public ModelAPI_ResultPart { TopoDS_Shape myShape; ///< shape of this part created from bodies (updated only of Part deactivation) std::shared_ptr myTrsf; ///< if it is just copy of original shape, keep just transformation - bool myIsInLoad; ///< true if document of this part is in the loading process, so, it may be already received public: /// the reference to the base result document, may be null if this is the root, others make sequence of references diff --git a/src/Model/Model_Session.cpp b/src/Model/Model_Session.cpp index 1bb0cebd2..e336d1652 100644 --- a/src/Model/Model_Session.cpp +++ b/src/Model/Model_Session.cpp @@ -38,13 +38,13 @@ static Model_Session* myImpl = new Model_Session(); bool Model_Session::load(const char* theFileName) { - bool aRes = ROOT_DOC->load(theFileName, ROOT_DOC); + bool aRes = ROOT_DOC->load(theFileName, "root", ROOT_DOC); return aRes; } bool Model_Session::save(const char* theFileName, std::list& theResults) { - return ROOT_DOC->save(theFileName, theResults); + return ROOT_DOC->save(theFileName, "root", theResults); } void Model_Session::closeAll() @@ -186,34 +186,27 @@ FeaturePtr Model_Session::createFeature(string theFeatureID, Model_Document* the std::shared_ptr Model_Session::moduleDocument() { - bool aFirstCall = !Model_Application::getApplication()->hasDocument("root"); + Handle(Model_Application) anApp = Model_Application::getApplication(); + bool aFirstCall = !anApp->hasRoot(); if (aFirstCall) { // creation of the root document is always outside of the transaction, so, avoid checking it setCheckTransactions(false); - } - std::shared_ptr aDoc = std::shared_ptr( - Model_Application::getApplication()->getDocument("root")); - if (aFirstCall) { + anApp->createDocument(0); // 0 is a root ID // creation of the root document is always outside of the transaction, so, avoid checking it setCheckTransactions(true); } - return aDoc; + return anApp->rootDocument(); } -std::shared_ptr Model_Session::document(std::string theDocID) +std::shared_ptr Model_Session::document(int theDocID) { return std::shared_ptr( - Model_Application::getApplication()->getDocument(theDocID)); + Model_Application::getApplication()->document(theDocID)); } bool Model_Session::hasModuleDocument() { - return Model_Application::getApplication()->hasDocument("root"); -} - -bool Model_Session::hasDocument(std::string theDocID) -{ - return Model_Application::getApplication()->hasDocument(theDocID); + return Model_Application::getApplication()->hasRoot(); } std::shared_ptr Model_Session::activeDocument() @@ -302,12 +295,10 @@ std::list > Model_Session::allOpenedDocuments DocumentPtr anAPIDoc = *aDoc; std::shared_ptr aDoc = std::dynamic_pointer_cast(anAPIDoc); if (aDoc) { - const std::set aSubs = aDoc->subDocuments(true); - std::set::const_iterator aSubIter = aSubs.cbegin(); + const std::set aSubs = aDoc->subDocuments(); + std::set::const_iterator aSubIter = aSubs.cbegin(); for(; aSubIter != aSubs.cend(); aSubIter++) { - if (!Model_Application::getApplication()->isLoadByDemand(*aSubIter)) { - aResult.push_back(Model_Application::getApplication()->getDocument(*aSubIter)); - } + aResult.push_back(Model_Application::getApplication()->document(*aSubIter)); } } } @@ -320,11 +311,9 @@ bool Model_Session::isLoadByDemand(const std::string theDocID) } std::shared_ptr Model_Session::copy( - std::shared_ptr theSource, std::string theID) + std::shared_ptr theSource, const int theDestID) { - // create a new document - std::shared_ptr aNew = std::dynamic_pointer_cast( - Model_Application::getApplication()->getDocument(theID)); + std::shared_ptr aNew = Model_Application::getApplication()->document(theDestID); // make a copy of all labels TDF_Label aSourceRoot = std::dynamic_pointer_cast(theSource)->document()->Main() .Father(); diff --git a/src/Model/Model_Session.h b/src/Model/Model_Session.h index 04eadff1c..f31928620 100644 --- a/src/Model/Model_Session.h +++ b/src/Model/Model_Session.h @@ -80,9 +80,7 @@ class Model_Session : public ModelAPI_Session, public Events_Listener MODEL_EXPORT virtual std::shared_ptr moduleDocument(); /// Returns the document by ID, loads if not loaded yet. Returns null if no such document. - MODEL_EXPORT virtual std::shared_ptr document(std::string theDocID); - /// Return true if document with such ID has been already created - MODEL_EXPORT virtual bool hasDocument(std::string theDocID); + MODEL_EXPORT virtual std::shared_ptr document(int theDocID); /// Return true if root document has been already created MODEL_EXPORT virtual bool hasModuleDocument(); @@ -108,9 +106,9 @@ class Model_Session : public ModelAPI_Session, public Events_Listener /// Processes the configuration file reading MODEL_EXPORT virtual void processEvent(const std::shared_ptr& theMessage); - /// Copies the document to the new one with the given id + /// Copies the document to the new one MODEL_EXPORT virtual std::shared_ptr copy( - std::shared_ptr theSource, std::string theID); + std::shared_ptr theSource, const int theDestID); /// Returns the validators factory: the only one instance per application MODEL_EXPORT virtual ModelAPI_ValidatorsFactory* validators(); diff --git a/src/ModelAPI/ModelAPI_AttributeDocRef.h b/src/ModelAPI/ModelAPI_AttributeDocRef.h index 0772c9fc3..c846235dd 100644 --- a/src/ModelAPI/ModelAPI_AttributeDocRef.h +++ b/src/ModelAPI/ModelAPI_AttributeDocRef.h @@ -24,6 +24,9 @@ class ModelAPI_AttributeDocRef : public ModelAPI_Attribute /// Returns document referenced from this attribute MODELAPI_EXPORT virtual std::shared_ptr value() = 0; + /// Returns the persisten ID of the document + MODELAPI_EXPORT virtual int docId() = 0; + /// Returns the type of this class of attributes MODELAPI_EXPORT static std::string typeId() { diff --git a/src/ModelAPI/ModelAPI_Document.h b/src/ModelAPI/ModelAPI_Document.h index abf679546..8c1297359 100644 --- a/src/ModelAPI/ModelAPI_Document.h +++ b/src/ModelAPI/ModelAPI_Document.h @@ -66,11 +66,8 @@ public: virtual void moveFeature(std::shared_ptr theMoved, std::shared_ptr theAfterThis) = 0; - ///! Adds a new sub-document by the identifier, or returns existing one if it is already exist - virtual std::shared_ptr subDocument(std::string theDocID) = 0; - ///! Returns the id of the document - virtual const std::string& id() const = 0; + virtual const int id() const = 0; //! Returns the object in the group by the index (started from zero) //! \param theGroupID group that contains an object @@ -118,6 +115,8 @@ public: //! wihtout this participation virtual void synchronizeTransactions() = 0; + //! Returns feature by the id of the feature (produced by the Data "featureId" method) + virtual std::shared_ptr featureById(const int theId) = 0; //! To virtually destroy the fields of successors MODELAPI_EXPORT virtual ~ModelAPI_Document(); diff --git a/src/ModelAPI/ModelAPI_Session.h b/src/ModelAPI/ModelAPI_Session.h index df0e9c519..6d385ea5b 100644 --- a/src/ModelAPI/ModelAPI_Session.h +++ b/src/ModelAPI/ModelAPI_Session.h @@ -80,8 +80,8 @@ class MODELAPI_EXPORT ModelAPI_Session /// Returns the root document of the application (that may contains sub-documents) virtual std::shared_ptr moduleDocument() = 0; - /// Returns the document by ID, loads if not loaded yet. Returns null if no such document. - virtual std::shared_ptr document(std::string theDocID) = 0; + /// Returns the document by ID. Returns null if no such document. + virtual std::shared_ptr document(int theDocID) = 0; /// Return true if root document has been already created virtual bool hasModuleDocument() = 0; @@ -100,8 +100,8 @@ class MODELAPI_EXPORT ModelAPI_Session virtual bool isLoadByDemand(const std::string theDocID) = 0; /// Copies the document to the new one with the given id - virtual std::shared_ptr copy(std::shared_ptr theSource, - std::string theID) = 0; + virtual std::shared_ptr copy( + std::shared_ptr theSource, const int theDestID) =0; /// Returns the validators factory: the only one instance per application virtual ModelAPI_ValidatorsFactory* validators() = 0; diff --git a/src/ModelAPI/Test/TestDocument.py b/src/ModelAPI/Test/TestDocument.py index 8080f3654..14bf232bb 100644 --- a/src/ModelAPI/Test/TestDocument.py +++ b/src/ModelAPI/Test/TestDocument.py @@ -18,7 +18,7 @@ __updated__ = "2014-12-26" aSession = ModelAPI_Session.get() # TODO: enable this assertion: assert(aSession.moduleDocument()) -assert(aSession.moduleDocument().id() == "root") +assert(aSession.moduleDocument().id() == 0) assert(aSession.moduleDocument().kind() == "PartSet") assert(aSession.hasModuleDocument()) # Create a new document @@ -27,22 +27,22 @@ aSession.moduleDocument().addFeature("Part") aSession.finishOperation() assert(aSession.activeDocument()) -assert(aSession.activeDocument().id() == "Part_1") +assert(aSession.activeDocument().id() == 1) assert(aSession.activeDocument().kind() == "Part") # Activate root doc -aRootDoc = aSession.document("root") +aRootDoc = aSession.document(0) assert(aRootDoc) aSession.startOperation() aSession.setActiveDocument(aRootDoc, False) aSession.finishOperation() assert(aSession.activeDocument()) -assert(aSession.activeDocument().id() == "root") +assert(aSession.activeDocument().id() == 0) # check all opened docs allDocsList = aSession.allOpenedDocuments() assert(len(allDocsList) != 0) # Activate Part_1 doc back for further testing aSession.startOperation() -aSession.setActiveDocument(aSession.document("Part_1"), False) +aSession.setActiveDocument(aSession.document(1), False) aSession.finishOperation() #========================================================================= # Duplication of a document @@ -66,7 +66,7 @@ aPart.addFeature("Duplicate") aSession.finishOperation() assert(aSession.moduleDocument().size("Parts") == 2) aCopyOfPart = aSession.activeDocument() -assert(aCopyOfPart.id() == "Part_2") +assert(aCopyOfPart.id() == 2) assert(aCopyOfPart.kind() == "Part") assert(aCopyOfPart.size("Features") == 1) assert(aCopyOfPart != aPart) @@ -82,7 +82,7 @@ assert(aSession.moduleDocument().size("Parts") == 1) assert(aSession.activeDocument().id() == aCopyOfPart.id()) # Remove another one document aSession.startOperation() -aDoc2 = aSession.document("Part_2") +aDoc2 = aSession.document(2) aSession.setActiveDocument(aDoc2, False) aDoc2.addFeature("Remove") aSession.finishOperation() diff --git a/src/PartSetPlugin/PartSetPlugin_Duplicate.cpp b/src/PartSetPlugin/PartSetPlugin_Duplicate.cpp index 462a7366b..7b3e303d7 100644 --- a/src/PartSetPlugin/PartSetPlugin_Duplicate.cpp +++ b/src/PartSetPlugin/PartSetPlugin_Duplicate.cpp @@ -5,6 +5,7 @@ // Author: Mikhail PONIKAROV #include "PartSetPlugin_Duplicate.h" +#include "PartSetPlugin_Part.h" #include #include #include @@ -14,14 +15,8 @@ using namespace std; -PartSetPlugin_Duplicate::PartSetPlugin_Duplicate() -{ -} - -void PartSetPlugin_Duplicate::initAttributes() +void PartSetPlugin_Duplicate::execute() { - PartSetPlugin_Part::initAttributes(); - std::shared_ptr aPManager = ModelAPI_Session::get(); std::shared_ptr aRoot = aPManager->moduleDocument(); std::shared_ptr aSource; // searching for source document attribute @@ -34,21 +29,12 @@ void PartSetPlugin_Duplicate::initAttributes() aSource.reset(); } if (aSource) { + // create a new Part feature + FeaturePtr aNewPart = aRoot->addFeature(PartSetPlugin_Part::ID(), false); + aNewPart->execute(); // to make result and generate a unique name + std::shared_ptr aCopy = aPManager->copy( - aSource->data()->document(ModelAPI_ResultPart::DOC_REF())->value(), data()->name()); - } else { // invalid part copy: do nothing, keep this in empty name - data()->setName(""); + aSource->data()->document(ModelAPI_ResultPart::DOC_REF())->value(), + std::dynamic_pointer_cast(aNewPart->firstResult())->partDoc()->id()); } } - -void PartSetPlugin_Duplicate::execute() -{ - if (!data()->name().empty()) - PartSetPlugin_Part::execute(); -} - -const std::string& PartSetPlugin_Duplicate::documentToAdd() -{ - // part must be added only to the module document - return ModelAPI_Session::get()->moduleDocument()->kind(); -} diff --git a/src/PartSetPlugin/PartSetPlugin_Duplicate.h b/src/PartSetPlugin/PartSetPlugin_Duplicate.h index 408d096e8..8553448bf 100644 --- a/src/PartSetPlugin/PartSetPlugin_Duplicate.h +++ b/src/PartSetPlugin/PartSetPlugin_Duplicate.h @@ -7,33 +7,56 @@ #ifndef PartSetPlugin_Duplicate_H_ #define PartSetPlugin_Duplicate_H_ -#include "PartSetPlugin_Part.h" +#include "PartSetPlugin.h" +#include /**\class PartSetPlugin_Duplicate * \ingroup Plugins * \brief Duplicates the active part (not root). Creates a new "part" feature. */ -class PartSetPlugin_Duplicate : public PartSetPlugin_Part +class PartSetPlugin_Duplicate : public ModelAPI_Feature { public: - /// Duplicate kind + + /// Duplicate kind inline static const std::string& ID() { - static const std::string MY_DUPLICATE_KIND("Duplicate"); - return MY_DUPLICATE_KIND; + static const std::string MY_REMOVE_KIND("Duplicate"); + return MY_REMOVE_KIND; + } + /// Returns the kind of a feature + PARTSETPLUGIN_EXPORT virtual const std::string& getKind() + { + static std::string MY_KIND = PartSetPlugin_Duplicate::ID(); + return MY_KIND; } - /// Makes a new part, copy of active - PartSetPlugin_Duplicate(); - - /// Part must be added only to PartSet - PARTSETPLUGIN_EXPORT virtual const std::string& documentToAdd(); + /// Returns to which group in the document must be added feature + PARTSETPLUGIN_EXPORT virtual const std::string& getGroup() + { + static std::string MY_GROUP = "Parts"; + return MY_GROUP; + } /// Request for initialization of data model of the feature: adding all attributes - PARTSETPLUGIN_EXPORT virtual void initAttributes(); + PARTSETPLUGIN_EXPORT virtual void initAttributes() + { + } - /// doesn't call creation of new document, just does nothing if document was not copied + /// Not normal feature that stored in the tree + PARTSETPLUGIN_EXPORT virtual bool isAction() + { + return true; + } + + /// Performs the "duplicate" PARTSETPLUGIN_EXPORT virtual void execute(); + + /// Use plugin manager for features creation + PartSetPlugin_Duplicate() + { + } + }; #endif -- 2.39.2