X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FModel%2FModel_Session.cpp;h=b80cdd8eaf92737a34e09d233bece4bb6f4f0dc6;hb=06e7f5859095193fc7f498bd89a7d28009794f53;hp=ee29017f4a82f52015d66d2253215adb31f3e273;hpb=d36a44bebc13ef15510f2e7693deea86418bad1c;p=modules%2Fshaper.git diff --git a/src/Model/Model_Session.cpp b/src/Model/Model_Session.cpp index ee29017f4..b80cdd8ea 100644 --- a/src/Model/Model_Session.cpp +++ b/src/Model/Model_Session.cpp @@ -1,18 +1,31 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: Model_Session.cxx -// Created: 20 Mar 2014 -// Author: Mikhail PONIKAROV +// Copyright (C) 2014-2023 CEA, EDF +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// 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 +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// #include #include #include #include -#include #include #include #include #include +#include #include #include #include @@ -21,22 +34,34 @@ #include #include #include +#include + +#include #include #include +#include #include #include #include #include +#include +#include +#include + +#include + static Model_Session* myImpl = new Model_Session(); -// t oredirect all calls to the root document +// to redirect all calls to the root document #define ROOT_DOC std::dynamic_pointer_cast(moduleDocument()) bool Model_Session::load(const char* theFileName) { + myIsLoading = true; bool aRes = ROOT_DOC->load(theFileName, "root", ROOT_DOC); + myIsLoading = false; return aRes; } @@ -48,11 +73,16 @@ bool Model_Session::save(const char* theFileName, std::list& theRes void Model_Session::closeAll() { Model_Application::getApplication()->deleteAllDocuments(); + static const Events_ID aDocsCloseEvent = Events_Loop::eventByName(EVENT_DOCUMENTS_CLOSED); + myCurrentDoc = NULL; + static std::shared_ptr aMsg(new Events_Message(aDocsCloseEvent)); + Events_Loop::loop()->send(aMsg); + Events_Loop::loop()->flush(aDocsCloseEvent); } void Model_Session::startOperation(const std::string& theId, const bool theAttachedToNested) { - myOperationAttachedToNext = theAttachedToNested; + myOperationAttachedToNext.push_back(theAttachedToNested); ROOT_DOC->startOperation(); ROOT_DOC->operationId(theId); static std::shared_ptr aStartedMsg @@ -70,9 +100,13 @@ void Model_Session::finishOperation() { setCheckTransactions(false); ROOT_DOC->finishOperation(); - if (myOperationAttachedToNext) { // twice, with nested - ROOT_DOC->finishOperation(); - myOperationAttachedToNext = false; + if (!myOperationAttachedToNext.empty()) { + while (myOperationAttachedToNext.back()) { + // with nested, the first transaction can not be attached + ROOT_DOC->finishOperation(); + myOperationAttachedToNext.pop_back(); + } + myOperationAttachedToNext.pop_back(); } setCheckTransactions(true); } @@ -81,12 +115,16 @@ void Model_Session::abortOperation() { setCheckTransactions(false); ROOT_DOC->abortOperation(); - if (myOperationAttachedToNext) { // twice, with nested - ROOT_DOC->abortOperation(); - myOperationAttachedToNext = false; + if (!myOperationAttachedToNext.empty()) { + while (myOperationAttachedToNext.back()) { + // with nested, the first transaction can not be attached + ROOT_DOC->abortOperation(); + myOperationAttachedToNext.pop_back(); + } + myOperationAttachedToNext.pop_back(); } setCheckTransactions(true); - // here the update mechanism may work after abort, so, supress the warnings about + // here the update mechanism may work after abort, so, suppress the warnings about // modifications outside of the transactions bool aWasCheck = myCheckTransactions; myCheckTransactions = false; @@ -142,6 +180,39 @@ std::list Model_Session::redoList() return ROOT_DOC->redoList(); } +void Model_Session::clearUndoRedo() +{ + return ROOT_DOC->clearUndoRedo(); +} + +bool Model_Session::checkLicense(const std::string& thePluginName) +{ + return getPlugin(thePluginName); +} + +ModelAPI_Plugin* Model_Session::getPlugin(const std::string& thePluginName) +{ + if (myPluginObjs.find(thePluginName) == myPluginObjs.end()) { + // before load the used plugins + if (myUsePlugins.find(thePluginName) != myUsePlugins.end()) { + std::string aUse = myUsePlugins[thePluginName]; + std::stringstream aUseStream(aUse); + std::string aPluginName; + while (std::getline(aUseStream, aPluginName, ',')) { + if (myPluginObjs.find(aPluginName) == myPluginObjs.end()) + getPlugin(aPluginName); + } + } + // load plugin library if not yet done + Config_ModuleReader::loadPlugin(thePluginName); + } + if (myPluginObjs.find(thePluginName) == myPluginObjs.end()) { + Events_InfoMessage("Model_Session", "Can not load plugin '%1'").arg(thePluginName).send(); + return NULL; + } + return myPluginObjs[thePluginName]; +} + FeaturePtr Model_Session::createFeature(std::string theFeatureID, Model_Document* theDocOwner) { if (this != myImpl) { @@ -155,26 +226,20 @@ FeaturePtr Model_Session::createFeature(std::string theFeatureID, Model_Document std::pair& aPlugin = myPlugins[theFeatureID]; // plugin and doc kind if (!aPlugin.second.empty() && aPlugin.second != theDocOwner->kind()) { Events_InfoMessage("Model_Session", - "Feature '%1' can be created only in document '%2' by the XML definition") - .arg(theFeatureID).arg(aPlugin.second).send(); + "Feature '%1' can be created only in document '%2' by the XML definition") + .arg(theFeatureID).arg(aPlugin.second).send(); return FeaturePtr(); } - myCurrentPluginName = aPlugin.first; - if (myPluginObjs.find(myCurrentPluginName) == myPluginObjs.end()) { - // load plugin library if not yet done - Config_ModuleReader::loadPlugin(myCurrentPluginName); - } - if (myPluginObjs.find(myCurrentPluginName) != myPluginObjs.end()) { - FeaturePtr aCreated = myPluginObjs[myCurrentPluginName]->createFeature(theFeatureID); + ModelAPI_Plugin* aPluginObj = getPlugin(aPlugin.first); + if (aPluginObj) { + FeaturePtr aCreated = aPluginObj->createFeature(theFeatureID); if (!aCreated) { - Events_InfoMessage("Model_Session", - "Can not initialize feature '%1' in plugin '%2'") - .arg(theFeatureID).arg(myCurrentPluginName).send(); + Events_InfoMessage("Model_Session", "Can not initialize feature '%1' in plugin '%2'") + .arg(theFeatureID).arg(aPlugin.first).send(); } return aCreated; } else { - Events_InfoMessage("Model_Session", - "Can not load plugin '%1'").arg(myCurrentPluginName).send(); + Events_InfoMessage("Model_Session", "Can not load plugin '%1'").arg(aPlugin.first).send(); } } else { Events_InfoMessage("Model_Session", @@ -198,6 +263,12 @@ std::shared_ptr Model_Session::moduleDocument() 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); + if (!myCurrentDoc || !Model_Application::getApplication()->hasDocument(myCurrentDoc->id())) { + myCurrentDoc = moduleDocument(); + static std::shared_ptr aMsg( + new Events_Message(Events_Loop::eventByName(EVENT_DOCUMENT_CHANGED))); + Events_Loop::loop()->send(aMsg); + } } return anApp->rootDocument(); } @@ -215,8 +286,9 @@ bool Model_Session::hasModuleDocument() std::shared_ptr Model_Session::activeDocument() { - if (!myCurrentDoc || !Model_Application::getApplication()->hasDocument(myCurrentDoc->id())) - myCurrentDoc = moduleDocument(); + if (!myCurrentDoc || !Model_Application::getApplication()->hasDocument(myCurrentDoc->id())) { + return moduleDocument(); + } return myCurrentDoc; } @@ -249,7 +321,7 @@ void Model_Session::setActiveDocument( std::shared_ptr aPrevious = myCurrentDoc; myCurrentDoc = theDoc; if (theDoc.get() && theSendSignal) { - // this must be before the synchronisation call because features in PartSet lower than this + // this must be before the synchronization call because features in PartSet lower than this // part feature must be disabled and don't recomputed anymore (issue 1156, // translation feature is failed on activation of Part 2) if (isOperation()) { // do it only in transaction, not on opening of document @@ -261,7 +333,7 @@ void Model_Session::setActiveDocument( } } } - // syncronize the document: it may be just opened or opened but removed before + // synchronize the document: it may be just opened or opened but removed before std::shared_ptr aDoc = std::dynamic_pointer_cast(theDoc); if (aDoc.get()) { bool aWasChecked = myCheckTransactions; @@ -275,7 +347,7 @@ void Model_Session::setActiveDocument( new Events_Message(Events_Loop::eventByName(EVENT_DOCUMENT_CHANGED))); Events_Loop::loop()->send(aMsg); } - // make the current state correct and synchronised in the module and sub-documents + // make the current state correct and synchronized in the module and sub-documents if (isOperation()) { // do it only in transaction, not on opening of document if (myCurrentDoc == moduleDocument()) { // make the current feature the latest in root, in previous root current become also last @@ -294,9 +366,9 @@ std::list > Model_Session::allOpenedDocuments std::list > aResult; aResult.push_back(moduleDocument()); // add subs recursively - std::list >::iterator aDoc = aResult.begin(); - for(; aDoc != aResult.end(); aDoc++) { - DocumentPtr anAPIDoc = *aDoc; + std::list >::iterator aDocIt = aResult.begin(); + for(; aDocIt != aResult.end(); aDocIt++) { + DocumentPtr anAPIDoc = *aDocIt; std::shared_ptr aDoc = std::dynamic_pointer_cast(anAPIDoc); if (aDoc) { const std::set aSubs = aDoc->subDocuments(); @@ -309,9 +381,9 @@ std::list > Model_Session::allOpenedDocuments return aResult; } -bool Model_Session::isLoadByDemand(const std::string theDocID) +bool Model_Session::isLoadByDemand(const std::wstring theDocID, const int theDocIndex) { - return Model_Application::getApplication()->isLoadByDemand(theDocID); + return Model_Application::getApplication()->isLoadByDemand(theDocID, theDocIndex); } std::shared_ptr Model_Session::copy( @@ -329,6 +401,50 @@ std::shared_ptr Model_Session::copy( aRT->SetRelocation(aSourceRoot, aTargetRoot); TDF_CopyTool::Copy(aDS, aRT); + // TODO: remove after fix in OCCT. + // All named shapes are stored in reversed order, so to fix this we reverse them back. + for(TDF_ChildIDIterator aChildIter(aTargetRoot, TNaming_NamedShape::GetID(), true); + aChildIter.More(); + aChildIter.Next()) { + Handle(TNaming_NamedShape) aNamedShape = + Handle(TNaming_NamedShape)::DownCast(aChildIter.Value()); + if (aNamedShape.IsNull()) { + continue; + } + + TopoDS_Shape aShape = aNamedShape->Get(); + if(aShape.IsNull() || aShape.ShapeType() != TopAbs_COMPOUND) { + continue; + } + + TNaming_Evolution anEvol = aNamedShape->Evolution(); + std::list > aShapePairs; // to store old and new shapes + for(TNaming_Iterator anIter(aNamedShape); anIter.More(); anIter.Next()) { + aShapePairs.push_back( + std::pair(anIter.OldShape(), anIter.NewShape())); + } + + // Add in reverse order. + TDF_Label aLabel = aNamedShape->Label(); + TNaming_Builder aBuilder(aLabel); + for(std::list >::iterator aPairsIter = + aShapePairs.begin(); + aPairsIter != aShapePairs.end(); + aPairsIter++) { + if (anEvol == TNaming_GENERATED) { + aBuilder.Generated(aPairsIter->first, aPairsIter->second); + } else if (anEvol == TNaming_MODIFY) { + aBuilder.Modify(aPairsIter->first, aPairsIter->second); + } else if (anEvol == TNaming_DELETE) { + aBuilder.Delete(aPairsIter->first); + } else if (anEvol == TNaming_PRIMITIVE) { + aBuilder.Generated(aPairsIter->second); + } else if (anEvol == TNaming_SELECTED) { + aBuilder.Select(aPairsIter->second, aPairsIter->first); + } + } + } + TDF_LabelList anEmptyUpdated; aNew->objects()->synchronizeFeatures(anEmptyUpdated, true, true, true, true); return aNew; @@ -338,7 +454,7 @@ Model_Session::Model_Session() { myPluginsInfoLoaded = false; myCheckTransactions = true; - myOperationAttachedToNext = false; + myIsLoading = false; ModelAPI_Session::setSession(std::shared_ptr(this)); // register the configuration reading listener Events_Loop* aLoop = Events_Loop::loop(); @@ -349,6 +465,7 @@ Model_Session::Model_Session() aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED), 0, true); aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED), 0, true); aLoop->registerListener(this, Events_Loop::eventByName(EVENT_VALIDATOR_LOADED)); + aLoop->registerListener(this, Events_Loop::eventByName(Config_PluginMessage::EVENT_ID())); } void Model_Session::processEvent(const std::shared_ptr& theMessage) @@ -356,6 +473,7 @@ void Model_Session::processEvent(const std::shared_ptr& theMessa static const Events_ID kFeatureEvent = Events_Loop::eventByName(Config_FeatureMessage::MODEL_EVENT()); static const Events_ID kValidatorEvent = Events_Loop::eventByName(EVENT_VALIDATOR_LOADED); + static const Events_ID kPluginEvent = Events_Loop::eventByName(Config_PluginMessage::EVENT_ID()); if (theMessage->eventID() == kFeatureEvent) { const std::shared_ptr aMsg = std::dynamic_pointer_cast(theMessage); @@ -377,10 +495,17 @@ void Model_Session::processEvent(const std::shared_ptr& theMessa if(aMsgAttr->isConcealment()) { validators()->registerConcealment(aMsgAttr->featureId(), aMsgAttr->attributeId()); } + if(aMsgAttr->isMainArgument()) { + validators()->registerMainArgument(aMsgAttr->featureId(), aMsgAttr->attributeId()); + } const std::list >& aCases = aMsgAttr->getCases(); if (!aCases.empty()) { validators()->registerCase(aMsgAttr->featureId(), aMsgAttr->attributeId(), aCases); } + if (aMsgAttr->isGeometricalSelection()) { + validators()->registerGeometricalSelection(aMsgAttr->featureId(), + aMsgAttr->attributeId()); + } } } // plugins information was started to load, so, it will be loaded @@ -396,17 +521,56 @@ void Model_Session::processEvent(const std::shared_ptr& theMessa aMsg->parameters()); } } + } else if (theMessage->eventID() == kPluginEvent) { // plugin is started to load + std::shared_ptr aMsg = + std::dynamic_pointer_cast(theMessage); + if (aMsg.get()) { + myCurrentPluginName = aMsg->pluginId(); + if (!aMsg->uses().empty()) { + myUsePlugins[myCurrentPluginName] = aMsg->uses(); + } + } } else { // create/update/delete - if (myCheckTransactions && !isOperation()) - Events_InfoMessage("Model_Session", - "Modification of data structure outside of the transaction").send(); + if (myCheckTransactions && !isOperation()) { + // check it is done in real opened document: 2958 + bool aIsActual = true; + static const Events_ID kDeletedEvent = Events_Loop::eventByName(EVENT_OBJECT_DELETED); + if (theMessage->eventID() == kDeletedEvent) { + aIsActual = false; + std::shared_ptr aDeleted = + std::dynamic_pointer_cast(theMessage); + std::list > allOpened = + Model_Session::allOpenedDocuments(); + std::list, std::string>>::const_iterator + aGIter = aDeleted->groups().cbegin(); + for (; !aIsActual && aGIter != aDeleted->groups().cend(); aGIter++) { + std::list >::iterator anOpened = allOpened.begin(); + for(; anOpened != allOpened.end(); anOpened++) { + if (aGIter->first == *anOpened) { + aIsActual = true; + break; + } + } + } + } + + if (aIsActual) + Events_InfoMessage("Model_Session", + "Modification of data structure outside of the transaction").send(); + } // if part is deleted, make the root as the current document (on undo of Parts creations) static const Events_ID kDeletedEvent = Events_Loop::eventByName(EVENT_OBJECT_DELETED); if (theMessage->eventID() == kDeletedEvent) { std::shared_ptr aDeleted = std::dynamic_pointer_cast(theMessage); - if (aDeleted && - aDeleted->groups().find(ModelAPI_ResultPart::group()) != aDeleted->groups().end()) + + std::list, std::string>>::const_iterator + aGIter = aDeleted->groups().cbegin(); + for (; aGIter != aDeleted->groups().cend(); aGIter++) { + if (aGIter->second == ModelAPI_ResultPart::group()) + break; + } + if (aGIter != aDeleted->groups().cend()) { // check that the current feature of the session is still the active Part (even disabled) bool aFound = false; @@ -435,7 +599,6 @@ void Model_Session::LoadPluginsInfo() { if (myPluginsInfoLoaded) // nothing to do return; - Config_ModuleReader::loadScript("salome.shaper.initConfig", false); // Read plugins information from XML files Config_ModuleReader aModuleReader(Config_FeatureMessage::MODEL_EVENT()); aModuleReader.readAll(); @@ -452,8 +615,7 @@ void Model_Session::registerPlugin(ModelAPI_Plugin* thePlugin) { myPluginObjs[myCurrentPluginName] = thePlugin; static Events_ID EVENT_LOAD = Events_Loop::loop()->eventByName(EVENT_PLUGIN_LOADED); - ModelAPI_EventCreator::get()->sendUpdated(ObjectPtr(), EVENT_LOAD); - Events_Loop::loop()->flush(EVENT_LOAD); + ModelAPI_EventCreator::get()->sendUpdated(ObjectPtr(), EVENT_LOAD, false); // If the plugin has an ability to process GUI events, register it Events_Listener* aListener = dynamic_cast(thePlugin); if (aListener) { @@ -470,7 +632,59 @@ ModelAPI_ValidatorsFactory* Model_Session::validators() return aFactory; } +ModelAPI_FiltersFactory* Model_Session::filters() +{ + static Model_FiltersFactory* aFactory = new Model_FiltersFactory; + return aFactory; +} + int Model_Session::transactionID() { return ROOT_DOC->transactionID(); } + +bool Model_Session::isAutoUpdateBlocked() +{ + Handle(Model_Application) anApp = Model_Application::getApplication(); + if (!anApp->hasRoot()) // when document is not yet created, do not create it by such simple call + return false; + return !ROOT_DOC->autoRecomutationState(); +} + +void Model_Session::blockAutoUpdate(const bool theBlock) +{ + bool aCurrentState = isAutoUpdateBlocked(); + if (aCurrentState != theBlock) { + // if there is no operation, start it to avoid modifications outside of transaction + bool isOperation = this->isOperation(); + if (!isOperation) + startOperation("Auto update"); + ROOT_DOC->setAutoRecomutationState(!theBlock); + static Events_Loop* aLoop = Events_Loop::loop(); + if (theBlock) { + static const Events_ID kAutoOff = aLoop->eventByName(EVENT_AUTOMATIC_RECOMPUTATION_DISABLE); + std::shared_ptr aMsg(new Events_Message(kAutoOff)); + aLoop->send(aMsg); + } else { + // if there is no operation, start it to avoid modifications outside of transaction + isOperation = this->isOperation(); + if (!isOperation) + startOperation("Auto update enabling"); + static const Events_ID kAutoOn = aLoop->eventByName(EVENT_AUTOMATIC_RECOMPUTATION_ENABLE); + std::shared_ptr aMsg(new Events_Message(kAutoOn)); + aLoop->send(aMsg); + } + if (!isOperation) { + finishOperation(); + // append this transaction to the previous one: don't need this separated operation in list + ROOT_DOC->appendTransactionToPrevious(); + } + } +} + +#ifdef TINSPECTOR +Handle(TDocStd_Application) Model_Session::application() +{ + return Model_Application::getApplication(); +} +#endif