X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_Document.cpp;h=505b77f3647d91ff9dab7230d1fbf16bd047766f;hb=e8fce5fe73fee1a8ea2929934a7e6f71bd1e3eb5;hp=99a624ae09f4746f66d7ef5f9a21596db44d6cf9;hpb=d4b0a5cb916f4eccf4a0bce02e43a54c7a67cb93;p=modules%2Fshaper.git diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp old mode 100755 new mode 100644 index 99a624ae0..505b77f36 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 CEA/DEN, EDF R&D +// Copyright (C) 2014-2021 CEA/DEN, EDF R&D // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -12,10 +12,9 @@ // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // -// See http://www.salome-platform.org/ or -// email : webmaster.salome@opencascade.com +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // #include @@ -24,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +34,8 @@ #include #include +#include + #include #include #include @@ -45,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -61,17 +62,23 @@ #include #include #include -#include +#include #include #include #include #include +#include #include #include -#include +#include + +#ifdef TINSPECTOR #include +#endif + +#include #include #ifndef WIN32 @@ -102,11 +109,14 @@ static const int TAG_EXTERNAL_CONSTRUCTIONS = 5; static const Standard_GUID kEXTERNAL_SHAPE_REF("9aa5dd14-6d34-4a8d-8786-05842fd7bbbd"); Model_Document::Model_Document(const int theID, const std::string theKind) - : myID(theID), myKind(theKind), myIsActive(false), myIsSetCurrentFeature(false), - myDoc(new TDocStd_Document("BinOcaf")) // binary OCAF format + : myID(theID), + myKind(theKind), + myDoc(new TDocStd_Document("BinOcaf")), // binary OCAF format + myIsActive(false), + myIsSetCurrentFeature(false) { #ifdef TINSPECTOR - CDF_Session::CurrentSession()->Directory()->Add(myDoc); + ModelAPI_Session::get()->application()->NewDocument("BinOcaf", myDoc); #endif myObjs = new Model_Objects(myDoc->Main()); myDoc->SetUndoLimit(UNDO_LIMIT); @@ -121,6 +131,15 @@ Model_Document::Model_Document(const int theID, const std::string theKind) myDoc->CommitCommand(); } +Model_Document::~Model_Document() +{ + if (!myDoc.IsNull()) + { + myDoc->ClearUndos(); + myDoc->ClearRedos(); + } +} + void Model_Document::setThis(DocumentPtr theDoc) { myObjs->setOwner(theDoc); @@ -145,6 +164,7 @@ bool Model_Document::isRoot() const return this == Model_Session::get()->moduleDocument().get(); } +// LCOV_EXCL_START /// Makes all modification and generation naming shapes that have old shapes corresponding to /// shapes in a root document be equal to this root document static void updateShapesFromRoot(const TDF_Label theThisAccess, const TDF_Label theRootAccess) @@ -220,25 +240,23 @@ static void updateShapesFromRoot(const TDF_Label theThisAccess, const TDF_Label } } } +// LCOV_EXCL_STOP -bool Model_Document::load(const char* theDirName, const char* theFileName, DocumentPtr theThis) +static bool loadDocument(Handle(Model_Application) theApp, + Handle(TDocStd_Document)& theDoc, + const TCollection_ExtendedString& theFilename) { - Handle(Model_Application) anApp = Model_Application::getApplication(); - if (isRoot()) { - anApp->setLoadPath(theDirName); - } - TCollection_ExtendedString aPath(DocFileName(theDirName, theFileName)); - PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1; - Handle(TDocStd_Document) aLoaded; + PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus)-1; try { - aStatus = anApp->Open(aPath, aLoaded); + aStatus = theApp->Open(theFilename, theDoc); } catch (Standard_Failure const& anException) { Events_InfoMessage("Model_Document", "Exception in opening of document: %1").arg(anException.GetMessageString()).send(); return false; } - bool isError = aStatus != PCDM_RS_OK; - if (isError) { + bool isOk = aStatus == PCDM_RS_OK; + if (!isOk) { + // LCOV_EXCL_START switch (aStatus) { case PCDM_RS_UnknownDocument: Events_InfoMessage("Model_Document", "Can not open document").send(); @@ -293,10 +311,26 @@ bool Model_Document::load(const char* theDirName, const char* theFileName, Docum Events_InfoMessage("Model_Document", "Can not open document: unknown error").send(); break; } + // LCOV_EXCL_STOP } + return isOk; +} + +bool Model_Document::load(const char* theDirName, const char* theFileName, DocumentPtr theThis) +{ + Handle(Model_Application) anApp = Model_Application::getApplication(); + if (isRoot()) { + anApp->setLoadPath(theDirName); + } + TCollection_ExtendedString aPath(DocFileName(theDirName, theFileName)); + Handle(TDocStd_Document) aLoaded; + bool isOk = loadDocument(anApp, aLoaded, aPath); + std::shared_ptr aSession = std::dynamic_pointer_cast(Model_Session::get()); - if (!isError) { + if (isOk) { + // keep handle to avoid destruction of the document until myObjs works on it + Handle(TDocStd_Document) anOldDoc = myDoc; myDoc = aLoaded; myDoc->SetUndoLimit(UNDO_LIMIT); @@ -305,6 +339,9 @@ bool Model_Document::load(const char* theDirName, const char* theFileName, Docum aSession->setCheckTransactions(false); if (myObjs) delete myObjs; + anOldDoc->ClearRedos(); + anOldDoc->ClearUndos(); + anOldDoc.Nullify(); myObjs = new Model_Objects(myDoc->Main()); // synchronization is inside myObjs->setOwner(theThis); // update the current features status @@ -331,7 +368,127 @@ bool Model_Document::load(const char* theDirName, const char* theFileName, Docum } else { // open failed, but new document was created to work with it: inform the model aSession->setActiveDocument(Model_Session::get()->moduleDocument(), false); } - return !isError; + return isOk; +} + +bool Model_Document::importPart(const char* theFileName, + std::list >& theImported, + bool theCheckOnly) +{ + Handle(Model_Application) anApp = Model_Application::getApplication(); + TCollection_ExtendedString aFormat; + if (!anApp->Format(theFileName, aFormat)) + return false; + + Handle(TDocStd_Document) aTempDoc; + bool isOk = loadDocument(anApp, aTempDoc, theFileName); + + if (isOk && theCheckOnly) { + // verify all features are applicable for the current document type (e.g. PartSet) + std::shared_ptr aSession = + std::dynamic_pointer_cast(ModelAPI_Session::get()); + for (TDF_ChildIterator anIt(aTempDoc->Main()); anIt.More() && isOk; anIt.Next()) { + TDF_Label aCurrentLab = anIt.Value(); + Handle(TDataStd_Comment) aFeatureID; + TDF_Label aNewFeatuerLab; + if (aCurrentLab.FindAttribute(TDataStd_Comment::GetID(), aFeatureID)) { + TCollection_AsciiString anID(aFeatureID->Get()); + std::string aFeatureKind(anID.ToCString()); + if (aSession->myPlugins.find(aFeatureKind) != aSession->myPlugins.end()) { + std::string& aDocKind = aSession->myPlugins[aFeatureKind].second; + isOk = aDocKind.empty() || aDocKind == kind(); + } + } + } + } + + if (isOk && !theCheckOnly) { + // copy features from the temporary document to the current + Handle(TDF_RelocationTable) aRelocTable = new TDF_RelocationTable(); + // add to relocation table source root label to the destination label because + // sometimes there could be a reference to root (issue 3267 on import part + // with sketch with removed features) + aRelocTable->SetRelocation(aTempDoc->Main().Root(), myDoc->Main().Root()); + TDF_LabelList anAllNewFeatures; + // Perform the copying twice for correct references: + // 1. copy labels hierarchy and fill the relocation table + for (TDF_ChildIterator anIt(aTempDoc->Main()); anIt.More(); anIt.Next()) { + TDF_Label aCurrentLab = anIt.Value(); + Handle(TDataStd_Comment) aFeatureID; + TDF_Label aNewFeatuerLab; + if (aCurrentLab.FindAttribute(TDataStd_Comment::GetID(), aFeatureID)) { + TCollection_AsciiString anID(aFeatureID->Get()); + FeaturePtr aNewFeature = addFeature(anID.ToCString()); + std::shared_ptr aData = + std::dynamic_pointer_cast(aNewFeature->data()); + aNewFeatuerLab = aData->label().Father(); + Model_Tools::copyLabels(aCurrentLab, aNewFeatuerLab, aRelocTable); + theImported.push_back(aNewFeature); + } + anAllNewFeatures.Append(aNewFeatuerLab); + } + // 2. copy attributes + std::set aCoordinateLabels; + Model_Tools::labelsOfCoordinates(aCoordinateLabels, aRelocTable); + TDF_ListIteratorOfLabelList aNewIt(anAllNewFeatures); + for (TDF_ChildIterator anIt(aTempDoc->Main()); anIt.More(); anIt.Next()) { + TDF_Label aCurrentLab = anIt.Value(); + TDF_Label aFeatureLab = aNewIt.Value(); + if (aFeatureLab.IsNull()) + anAllNewFeatures.Remove(aNewIt); + else { + Model_Tools::copyAttrsAndKeepRefsToCoordinates( + aCurrentLab, aFeatureLab, aCoordinateLabels, aRelocTable); + aNewIt.Next(); + } + } + + myObjs->synchronizeFeatures(anAllNewFeatures, true, false, false, true); + } + + if (anApp->CanClose(aTempDoc) == CDM_CCS_OK) + anApp->Close(aTempDoc); + return isOk; +} + +static bool saveDocument(Handle(Model_Application) theApp, + Handle(TDocStd_Document) theDoc, + const TCollection_ExtendedString& theFilename) +{ + PCDM_StoreStatus aStatus; + try { + // create the directory to save the document + OSD_Path aPathToFile = UTL::Path(theFilename); + aPathToFile.SetName(""); + aPathToFile.SetExtension(""); + OSD_Directory aBaseDir(aPathToFile); + if (aPathToFile.TrekLength() != 0 && !aBaseDir.Exists()) + aBaseDir.Build(OSD_Protection()); + // save the document + aStatus = theApp->SaveAs(theDoc, theFilename); + } + catch (Standard_Failure const& anException) { + Events_InfoMessage("Model_Document", + "Exception in saving of document: %1").arg(anException.GetMessageString()).send(); + return false; + } + bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj; + if (!isDone) { + switch (aStatus) { + case PCDM_SS_DriverFailure: + Events_InfoMessage("Model_Document", + "Can not save document: save driver-library failure").send(); + break; + case PCDM_SS_WriteFailure: + Events_InfoMessage("Model_Document", "Can not save document: file writing failure").send(); + break; + case PCDM_SS_Failure: + default: + Events_InfoMessage("Model_Document", "Can not save document").send(); + break; + } + } + return isDone; } bool Model_Document::save( @@ -362,41 +519,17 @@ bool Model_Document::save( Handle(Model_Application) anApp = Model_Application::getApplication(); if (isRoot()) { #ifdef WIN32 - CreateDirectory((LPTSTR) theDirName, NULL); + size_t aDirLen = strlen(theDirName); + std::wstring aWStr(aDirLen, L'#'); + mbstowcs(&aWStr[0], theDirName, aDirLen); + CreateDirectory(aWStr.c_str(), NULL); #else mkdir(theDirName, 0x1ff); #endif } // filename in the dir is id of document inside of the given directory TCollection_ExtendedString aPath(DocFileName(theDirName, theFileName)); - PCDM_StoreStatus aStatus; - try { - aStatus = anApp->SaveAs(myDoc, aPath); - } catch (Standard_Failure const& anException) { - Events_InfoMessage("Model_Document", - "Exception in saving of document: %1").arg(anException.GetMessageString()).send(); - if (aWasCurrent.get()) { // return the current feature to the initial position - setCurrentFeature(aWasCurrent, false); - aSession->setCheckTransactions(true); - } - return false; - } - bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj; - if (!isDone) { - switch (aStatus) { - case PCDM_SS_DriverFailure: - Events_InfoMessage("Model_Document", - "Can not save document: save driver-library failure").send(); - break; - case PCDM_SS_WriteFailure: - Events_InfoMessage("Model_Document", "Can not save document: file writing failure").send(); - break; - case PCDM_SS_Failure: - default: - Events_InfoMessage("Model_Document", "Can not save document").send(); - break; - } - } + bool isDone = saveDocument(anApp, myDoc, aPath); if (aWasCurrent.get()) { // return the current feature to the initial position setCurrentFeature(aWasCurrent, false); @@ -414,12 +547,12 @@ bool Model_Document::save( ResultPartPtr aPart = std::dynamic_pointer_cast(*aPartRes); if (!aPart->isActivated()) { // copy not-activated document that is not in the memory - std::string aDocName = aPart->data()->name(); + std::string aDocName = Locale::Convert::toString(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); + OSD_Path aCopyPath(aSubPath); + OSD_File aFile(aCopyPath); if (aFile.Exists()) { TCollection_AsciiString aDestinationDir(DocFileName(theDirName, aDocName)); OSD_Path aDestination(aDestinationDir); @@ -431,14 +564,53 @@ bool Model_Document::save( } } } else { // simply save opened document + std::string aDocName = Locale::Convert::toString(aPart->data()->name()); isDone = std::dynamic_pointer_cast(aPart->partDoc())-> - save(theDirName, aPart->data()->name().c_str(), theResults); + save(theDirName, aDocName.c_str(), theResults); } } } return isDone; } +bool Model_Document::save(const char* theFilename, + const std::list& theExportFeatures) const +{ + Handle(Model_Application) anApp = Model_Application::getApplication(); + TCollection_ExtendedString aFormat; + if (!anApp->Format(theFilename, aFormat)) + return false; + + Handle(TDocStd_Document) aTempDoc = new TDocStd_Document(aFormat); + TDF_Label aMain = aTempDoc->Main(); + + Handle(TDF_RelocationTable) aRelocTable = new TDF_RelocationTable(); + std::list::const_iterator anIt = theExportFeatures.begin(); + // Perform the copying twice for correct references: + // 1. copy labels hierarchy and fill the relocation table + for (; anIt != theExportFeatures.end(); ++anIt) { + TDF_Label aFeatureLab = aMain.NewChild(); + std::shared_ptr aData = std::dynamic_pointer_cast((*anIt)->data()); + Model_Tools::copyLabels(aData->label().Father(), aFeatureLab, aRelocTable); + } + // 2. copy attributes + std::set aCoordinateLabels; + Model_Tools::labelsOfCoordinates(aCoordinateLabels, aRelocTable); + TDF_ChildIterator aChildIt(aMain); + for (anIt = theExportFeatures.begin(); anIt != theExportFeatures.end(); ++anIt) { + TDF_Label aFeatureLab = aChildIt.Value(); + std::shared_ptr aData = std::dynamic_pointer_cast((*anIt)->data()); + Model_Tools::copyAttrsAndKeepRefsToCoordinates( + aData->label().Father(), aFeatureLab, aCoordinateLabels, aRelocTable); + aChildIt.Next(); + } + + bool isDone = saveDocument(anApp, aTempDoc, theFilename); + if (aTempDoc->CanClose() == CDM_CCS_OK) + aTempDoc->Close(); + return isDone; +} + void Model_Document::close(const bool theForever) { std::shared_ptr aPM = Model_Session::get(); @@ -616,7 +788,7 @@ static bool isEmptyTransaction(const Handle(TDocStd_Document)& theDoc) { aDelta = theDoc->GetUndos().Last(); TDF_LabelList aDeltaList; aDelta->Labels(aDeltaList); // it clears list, so, use new one and then append to the result - for(TDF_ListIteratorOfLabelList aListIter(aDeltaList); aListIter.More(); aListIter.Next()) { + if (!aDeltaList.IsEmpty()) { return false; } // add also label of the modified attributes @@ -668,10 +840,10 @@ bool Model_Document::finishOperation() } myObjs->synchronizeBackRefs(); Events_Loop* aLoop = Events_Loop::loop(); - static const Events_ID kCreatedEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED); - static const Events_ID kUpdatedEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED); - static const Events_ID kRedispEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY); - static const Events_ID kDeletedEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED); + static const Events_ID kCreatedEvent = aLoop->eventByName(EVENT_OBJECT_CREATED); + static const Events_ID kUpdatedEvent = aLoop->eventByName(EVENT_OBJECT_UPDATED); + static const Events_ID kRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); + static const Events_ID kDeletedEvent = aLoop->eventByName(EVENT_OBJECT_DELETED); aLoop->flush(kCreatedEvent); aLoop->flush(kUpdatedEvent); aLoop->flush(kRedispEvent); @@ -844,7 +1016,7 @@ bool Model_Document::isOperation() const bool Model_Document::isModified() { // is modified if at least one operation was committed and not undone - return myTransactions.size() != myTransactionSave || isOperation(); + return (int)myTransactions.size() != myTransactionSave || isOperation(); } bool Model_Document::canUndo() @@ -887,9 +1059,10 @@ void Model_Document::undoInternal(const bool theWithSubs, const bool theSynchron myDoc->Undo(); } + std::set aSubs; if (theWithSubs) { // undo for all subs - const std::set aSubs = subDocuments(); + aSubs = subDocuments(); std::set::iterator aSubIter = aSubs.begin(); for (; aSubIter != aSubs.end(); aSubIter++) { if (!subDoc(*aSubIter)->myObjs) @@ -902,6 +1075,19 @@ void Model_Document::undoInternal(const bool theWithSubs, const bool theSynchron myObjs->synchronizeFeatures(aDeltaLabels, true, false, false, isRoot()); // update the current features status setCurrentFeature(currentFeature(false), false); + + if (theWithSubs) { + // undo for all subs + const std::set aNewSubs = subDocuments(); + std::set::iterator aNewSubIter = aNewSubs.begin(); + for (; aNewSubIter != aNewSubs.end(); aNewSubIter++) { + // synchronize only newly appeared documents + if (!subDoc(*aNewSubIter)->myObjs || aSubs.find(*aNewSubIter) != aSubs.end()) + continue; + TDF_LabelList anEmptyDeltas; + subDoc(*aNewSubIter)->myObjs->synchronizeFeatures(anEmptyDeltas, true, false, true, true); + } + } } } @@ -950,7 +1136,8 @@ void Model_Document::redo() // update the current features status setCurrentFeature(currentFeature(false), false); } - +// this is used for creation of undo/redo1-list by GUI +// LCOV_EXCL_START std::list Model_Document::undoList() const { std::list aResult; @@ -976,6 +1163,7 @@ std::list Model_Document::redoList() const } return aResult; } +// LCOV_EXCL_STOP void Model_Document::operationId(const std::string& theId) { @@ -986,6 +1174,8 @@ FeaturePtr Model_Document::addFeature(std::string theID, const bool theMakeCurre { std::shared_ptr aSession = std::dynamic_pointer_cast(ModelAPI_Session::get()); + if (!aSession->hasModuleDocument() || !myObjs) + return FeaturePtr(); // this may be on close of the document FeaturePtr aFeature = aSession->createFeature(theID, this); if (!aFeature) return aFeature; @@ -1018,6 +1208,15 @@ FeaturePtr Model_Document::addFeature(std::string theID, const bool theMakeCurre } } } + // #2861,3029: if the parameter is added, add it after parameters existing in the list + if (aCurrent.get() && + (aFeature->getKind() == "Parameter" || aFeature->getKind() == "ParametersMgr")) { + int anIndex = kUNDEFINED_FEATURE_INDEX; + for(FeaturePtr aNextFeat = myObjs->nextFeature(aCurrent, anIndex); + aNextFeat.get() && aNextFeat->getKind() == "Parameter"; + aNextFeat = myObjs->nextFeature(aCurrent, anIndex)) + aCurrent = aNextFeat; + } aDocToAdd->myObjs->addFeature(aFeature, aCurrent); if (!aFeature->isAction()) { // do not add action to the data model if (theMakeCurrent) // after all this feature stays in the document, so make it current @@ -1030,7 +1229,6 @@ FeaturePtr Model_Document::addFeature(std::string theID, const bool theMakeCurre return aFeature; } - void Model_Document::refsToFeature(FeaturePtr theFeature, std::set >& theRefs, const bool isSendError) { @@ -1041,7 +1239,7 @@ void Model_Document::removeFeature(FeaturePtr theFeature) { myObjs->removeFeature(theFeature); // fix for #2723: send signal that part is updated - if (!isRoot()) { + if (!isRoot() && isOperation()) { std::shared_ptr aRoot = std::dynamic_pointer_cast(ModelAPI_Session::get()->moduleDocument()); std::list allParts; @@ -1069,8 +1267,7 @@ static bool isSub(const CompositeFeaturePtr theMain, const FeaturePtr theSub) { return isSub(theMain, aParent); } - -void Model_Document::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis) +void Model_Document::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis, const bool theSplit) { bool aCurrentUp = theMoved == currentFeature(false); if (aCurrentUp) { @@ -1094,13 +1291,26 @@ void Model_Document::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis) } while (aSub.get()); } + AttributeSelectionListPtr aMovedList; + if (theMoved->getKind() == "Group") { + aMovedList = theMoved->selectionList("group_list"); + if (aMovedList.get()) + aMovedList->setMakeCopy(true); + } myObjs->moveFeature(theMoved, anAfterThisSub); + + if (theSplit) { // split the group into sub-features + theMoved->customAction("split"); + } + if (aCurrentUp) { // make the moved feature enabled or disabled due to the real status setCurrentFeature(currentFeature(false), false); } else if (theAfterThis == currentFeature(false) || anAfterThisSub == currentFeature(false)) { // must be after move to make enabled all features which are before theMoved setCurrentFeature(theMoved, true); } + if (aMovedList.get()) + aMovedList->setMakeCopy(false); } void Model_Document::updateHistory(const std::shared_ptr theObject) @@ -1145,7 +1355,7 @@ ObjectPtr Model_Document::object(const std::string& theGroupID, } std::shared_ptr Model_Document::objectByName( - const std::string& theGroupID, const std::string& theName) + const std::string& theGroupID, const std::wstring& theName) { return myObjs->objectByName(theGroupID, theName); } @@ -1230,6 +1440,18 @@ void Model_Document::setCurrentFeature( } } } + if (theVisible) { // make RemoveResults feature be active even it is performed after the current + int anIndex = kUNDEFINED_FEATURE_INDEX; + FeaturePtr aNext = + theCurrent.get() ? myObjs->nextFeature(theCurrent, anIndex, false) : myObjs->firstFeature(); + for (; aNext.get(); aNext = myObjs->nextFeature(theCurrent, anIndex, false)) { + if (aNext->isInHistory()) { + break; // next in history is not needed + } else if (aNext->getKind() == "RemoveResults"){ + theCurrent = aNext; + } + } + } if (theCurrent.get()) { std::shared_ptr aData = std::static_pointer_cast(theCurrent->data()); if (!aData.get() || !aData->isValid()) { @@ -1311,6 +1533,9 @@ void Model_Document::setCurrentFeature( myIsSetCurrentFeature = false; // unblock the flush signals and up them after this aLoop->activateFlushes(isActive); + + static Events_ID kUpdatedSel = aLoop->eventByName(EVENT_UPDATE_SELECTION); + aLoop->flush(kUpdatedSel); } void Model_Document::setCurrentFeatureUp() @@ -1435,16 +1660,6 @@ std::shared_ptr Model_Document::feature( return myObjs->feature(theResult); } -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); -} - FeaturePtr Model_Document::featureByLab(const TDF_Label& theLab) { TDF_Label aCurrentLab = theLab; while(aCurrentLab.Depth() > 3) @@ -1465,10 +1680,9 @@ ResultPtr Model_Document::resultByLab(const TDF_Label& theLab) return ResultPtr(); // not found } - -void Model_Document::addNamingName(const TDF_Label theLabel, std::string theName) +void Model_Document::addNamingName(const TDF_Label theLabel, std::wstring theName) { - std::map >::iterator aFind = myNamingNames.find(theName); + std::map >::iterator aFind = myNamingNames.find(theName); if (aFind != myNamingNames.end()) { // to avoid duplicate-labels // to keep correct order in spite of history line management @@ -1500,11 +1714,11 @@ void Model_Document::addNamingName(const TDF_Label theLabel, std::string theName myNamingNames[theName].push_back(theLabel); } -void Model_Document::changeNamingName(const std::string theOldName, - const std::string theNewName, +void Model_Document::changeNamingName(const std::wstring theOldName, + const std::wstring theNewName, const TDF_Label& theLabel) { - std::map >::iterator aFind = myNamingNames.find(theOldName); + std::map >::iterator aFind = myNamingNames.find(theOldName); if (aFind != myNamingNames.end()) { std::list::iterator aLabIter = aFind->second.begin(); for(; aLabIter != aFind->second.end(); aLabIter++) { @@ -1519,9 +1733,9 @@ void Model_Document::changeNamingName(const std::string theOldName, TDF_ChildIDIterator aChild(theLabel, TDataStd_Name::GetID()); for(; aChild.More(); aChild.Next()) { Handle(TDataStd_Name) aSubName = Handle(TDataStd_Name)::DownCast(aChild.Value()); - std::string aName = TCollection_AsciiString(aSubName->Get()).ToCString(); + std::wstring aName = Locale::Convert::toWString(aSubName->Get().ToExtString()); if (aName.find(theOldName) == 0) { // started from parent name - std::string aNewSubName = theNewName + aName.substr(theNewName.size()); + std::wstring aNewSubName = theNewName + aName.substr(theOldName.size()); changeNamingName(aName, aNewSubName, aSubName->Label()); aSubName->Set(aNewSubName.c_str()); } @@ -1532,9 +1746,55 @@ void Model_Document::changeNamingName(const std::string theOldName, } } -TDF_Label Model_Document::findNamingName(std::string theName, ResultPtr theContext) +// returns true if names consist of the same sub-elements but with different order. +// Sub-elements are separated by "-" symbol. First part must be "Face", second at the same place. +static bool IsExchangedName(const TCollection_ExtendedString& theName1, + const TCollection_ExtendedString& theName2) { - std::map >::iterator aFind = myNamingNames.find(theName); + static const TCollection_ExtendedString aSepStr("-"); + static const Standard_ExtString aSep = aSepStr.ToExtString(); + static const TCollection_ExtendedString aWireTail("_wire"); + if (theName1.Token(aSep, 1) != "Face" || theName2.Token(aSep, 1) != "Face") + return false; + if (theName1.Token(aSep, 2) != theName2.Token(aSep, 2)) + return false; + // Collect Map of the sub-elements of the first name + NCollection_Map aSubsMap; + TCollection_ExtendedString aWireSuffix; + int a = 3; + for (; true ; a++) { + TCollection_ExtendedString aToken = theName1.Token(aSep, a); + if (aToken.IsEmpty()) + break; + int aTailPos = aToken.Search(aWireTail); + if (aTailPos > 0) { + aWireSuffix = aToken.Split(aTailPos - 1); + } + aSubsMap.Add(aToken); + } + // check all subs in the second name are in the map + for (int a2 = 3; true; a2++) { + TCollection_ExtendedString aToken = theName2.Token(aSep, a2); + if (aToken.IsEmpty()) { + if (a2 != a) // number of sub-elements is not equal + return false; + break; + } + int aTailPos = aToken.Search(aWireTail); + if (aTailPos > 0) { + TCollection_ExtendedString aSuffix = aToken.Split(aTailPos - 1); + if (aWireSuffix != aSuffix) + return false; + } + if (!aSubsMap.Contains(aToken)) + return false; + } + return true; +} + +TDF_Label Model_Document::findNamingName(std::wstring theName, ResultPtr theContext) +{ + std::map >::iterator aFind = myNamingNames.find(theName); if (aFind != myNamingNames.end()) { std::list::reverse_iterator aLabIter = aFind->second.rbegin(); for(; aLabIter != aFind->second.rend(); aLabIter++) { @@ -1547,9 +1807,9 @@ TDF_Label Model_Document::findNamingName(std::string theName, ResultPtr theConte return *(aFind->second.rbegin()); // no more variants, so, return the last } // not found exact name, try to find by sub-components - std::string::size_type aSlash = theName.rfind('/'); - if (aSlash != std::string::npos) { - std::string anObjName = theName.substr(0, aSlash); + std::wstring::size_type aSlash = theName.rfind(L'/'); + if (aSlash != std::wstring::npos) { + std::wstring anObjName = theName.substr(0, aSlash); aFind = myNamingNames.find(anObjName); if (aFind != myNamingNames.end()) { TCollection_ExtendedString aSubName(theName.substr(aSlash + 1).c_str()); @@ -1563,13 +1823,19 @@ TDF_Label Model_Document::findNamingName(std::string theName, ResultPtr theConte } // copy aSubName to avoid incorrect further processing after its suffix cutting TCollection_ExtendedString aSubNameCopy(aSubName); + TDF_Label aFaceLabelWithExchangedSubs; // check also exchanged sub-elements of the name // searching sub-labels with this name TDF_ChildIDIterator aNamesIter(*aLabIter, TDataStd_Name::GetID(), Standard_True); for(; aNamesIter.More(); aNamesIter.Next()) { Handle(TDataStd_Name) aName = Handle(TDataStd_Name)::DownCast(aNamesIter.Value()); if (aName->Get() == aSubNameCopy) return aName->Label(); + if (aName->Get().Length() == aSubNameCopy.Length() && + IsExchangedName(aName->Get(), aSubNameCopy)) + aFaceLabelWithExchangedSubs = aName->Label(); } + if (!aFaceLabelWithExchangedSubs.IsNull()) + return aFaceLabelWithExchangedSubs; // If not found child label with the exact sub-name, then try to find compound with // such sub-name without suffix. Standard_Integer aSuffixPos = aSubNameCopy.SearchFromEnd('_'); @@ -1639,7 +1905,7 @@ bool Model_Document::isLaterByDep(FeaturePtr theThis, FeaturePtr theOther) { int Model_Document::numberOfNameInHistory( const ObjectPtr& theNameObject, const TDF_Label& theStartFrom) { - std::map >::iterator aFind = + std::map >::iterator aFind = myNamingNames.find(theNameObject->data()->name()); if (aFind == myNamingNames.end() || aFind->second.size() < 2) { return 1; // no need to specify the name by additional identifiers @@ -1677,10 +1943,10 @@ int Model_Document::numberOfNameInHistory( } ResultPtr Model_Document::findByName( - std::string& theName, std::string& theSubShapeName, bool& theUniqueContext) + std::wstring& theName, std::wstring& theSubShapeName, bool& theUniqueContext) { int aNumInHistory = 0; - std::string aName = theName; + std::wstring aName = theName; ResultPtr aRes = myObjs->findByName(aName); theUniqueContext = !(aRes.get() && myNamingNames.find(aName) != myNamingNames.end()); while(!aRes.get() && aName[0] == '_') { // this may be theContext with the history index @@ -1689,8 +1955,8 @@ ResultPtr Model_Document::findByName( aRes = myObjs->findByName(aName); } if (aNumInHistory) { - std::map >::iterator aFind = myNamingNames.find(aName); - if (aFind != myNamingNames.end() && aFind->second.size() > aNumInHistory) { + std::map >::iterator aFind = myNamingNames.find(aName); + if (aFind != myNamingNames.end() && (int)aFind->second.size() > aNumInHistory) { std::list::reverse_iterator aLibIt = aFind->second.rbegin(); for(; aNumInHistory != 0; aNumInHistory--) aLibIt++; @@ -1759,11 +2025,6 @@ void Model_Document::incrementTransactionID() int aNewVal = transactionID() + 1; TDataStd_Integer::Set(generalLabel().FindChild(TAG_CURRENT_TRANSACTION), aNewVal); } -void Model_Document::decrementTransactionID() -{ - int aNewVal = transactionID() - 1; - TDataStd_Integer::Set(generalLabel().FindChild(TAG_CURRENT_TRANSACTION), aNewVal); -} TDF_Label Model_Document::extConstructionsLabel() const { @@ -1785,11 +2046,6 @@ 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 = @@ -1844,7 +2100,7 @@ AttributeSelectionListPtr Model_Document::selectionInPartFeature() aData->setObject(mySelectionFeature); mySelectionFeature->setDoc(myObjs->owner()); mySelectionFeature->setData(aData); - std::string aName = id() + "_Part"; + std::wstring aName = id() + L"_Part"; mySelectionFeature->data()->setName(aName); mySelectionFeature->setDoc(myObjs->owner()); mySelectionFeature->initAttributes(); @@ -2009,6 +2265,8 @@ bool Model_Document::isLater(FeaturePtr theLater, FeaturePtr theCurrent) const return myObjs->isLater(theLater, theCurrent); } +// Object Browser nodes states +// LCOV_EXCL_START void Model_Document::storeNodesState(const std::list& theStates) { TDF_Label aLab = generalLabel().FindChild(TAG_NODES_STATE); @@ -2034,6 +2292,7 @@ void Model_Document::restoreNodesState(std::list& theStates) const } } } +// LCOV_EXCL_STOP void Model_Document::eraseAllFeatures() { @@ -2041,6 +2300,16 @@ void Model_Document::eraseAllFeatures() myObjs->eraseAllFeatures(); } +std::shared_ptr Model_Document::nextFeature( + std::shared_ptr theCurrent, const bool theReverse) const +{ + if (theCurrent.get() && myObjs) { + int anIndex = kUNDEFINED_FEATURE_INDEX; + return myObjs->nextFeature(theCurrent, anIndex, theReverse); + } + return FeaturePtr(); // nothing by default +} + void Model_Document::setExecuteFeatures(const bool theFlag) { myExecuteFeatures = theFlag; @@ -2057,6 +2326,8 @@ void Model_Document::appendTransactionToPrevious() { Transaction anAppended = myTransactions.back(); myTransactions.pop_back(); + if (!myNestedNum.empty()) + (*myNestedNum.rbegin())--; if (!myTransactions.empty()) { // if it is empty, just forget the appended myTransactions.back().myOCAFNum += anAppended.myOCAFNum; }