X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_Session.cpp;h=8e0d971254fa9f113b3afdeced8c9d8c168e79cc;hb=33d191c57ab22ff6e84ea27e69537670d242d336;hp=37b020eeeec6be69126e17a0eefcf386887059f8;hpb=d9db5498b576854aae37ddf8c0bb6fceb264712e;p=modules%2Fshaper.git diff --git a/src/Model/Model_Session.cpp b/src/Model/Model_Session.cpp index 37b020eee..b07ca70d4 100644 --- a/src/Model/Model_Session.cpp +++ b/src/Model/Model_Session.cpp @@ -1,62 +1,128 @@ -// File: Model_Session.cxx -// Created: 20 Mar 2014 -// Author: Mikhail PONIKAROV +// Copyright (C) 2014-2019 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 +// 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 +#include #include +#include #include #include +#include +#include +#include +#include +#include + +#include #include #include #include #include -using namespace std; +#include +#include +#include + +#include static Model_Session* myImpl = new Model_Session(); -// t oredirect all calls to the root document -#define ROOT_DOC boost::dynamic_pointer_cast(moduleDocument()) +// to redirect all calls to the root document +#define ROOT_DOC std::dynamic_pointer_cast(moduleDocument()) bool Model_Session::load(const char* theFileName) { - return ROOT_DOC->load(theFileName); + 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() +{ + Model_Application::getApplication()->deleteAllDocuments(); + static const Events_ID aDocChangeEvent = Events_Loop::eventByName(EVENT_DOCUMENT_CHANGED); + static std::shared_ptr aMsg(new Events_Message(aDocChangeEvent)); + Events_Loop::loop()->send(aMsg); + Events_Loop::loop()->flush(aDocChangeEvent); } -void Model_Session::startOperation() +void Model_Session::startOperation(const std::string& theId, const bool theAttachedToNested) { + myOperationAttachedToNext = theAttachedToNested; ROOT_DOC->startOperation(); + ROOT_DOC->operationId(theId); + static std::shared_ptr aStartedMsg + (new Events_Message(Events_Loop::eventByName("StartOperation"))); + Events_Loop::loop()->send(aStartedMsg); + // remove all useless documents that has been closed: on start of operation undo/redo is cleared + // MPV: this code is dangerous now because it may close the document that is activated right now + // but not in the list of the opened documents yet (create, delete, undo, activate Part) + // later this must be updated by correct usage of uniques IDs of documents, not names of results + //std::list > aUsedDocs = allOpenedDocuments(); + //Model_Application::getApplication()->removeUselessDocuments(aUsedDocs); } void Model_Session::finishOperation() { + setCheckTransactions(false); ROOT_DOC->finishOperation(); - static boost::shared_ptr aFinishMsg - (new Events_Message(Events_Loop::eventByName("FinishOperation"))); - Events_Loop::loop()->send(aFinishMsg); + if (myOperationAttachedToNext) { // twice, with nested + ROOT_DOC->finishOperation(); + myOperationAttachedToNext = false; + } + setCheckTransactions(true); } void Model_Session::abortOperation() { + setCheckTransactions(false); ROOT_DOC->abortOperation(); - static boost::shared_ptr anAbortMsg + if (myOperationAttachedToNext) { // twice, with nested + ROOT_DOC->abortOperation(); + myOperationAttachedToNext = false; + } + setCheckTransactions(true); + // here the update mechanism may work after abort, so, suppress the warnings about + // modifications outside of the transactions + bool aWasCheck = myCheckTransactions; + myCheckTransactions = false; + static std::shared_ptr anAbortMsg (new Events_Message(Events_Loop::eventByName("AbortOperation"))); Events_Loop::loop()->send(anAbortMsg); + myCheckTransactions = true; + myCheckTransactions = aWasCheck; } bool Model_Session::isOperation() @@ -76,7 +142,9 @@ bool Model_Session::canUndo() void Model_Session::undo() { + setCheckTransactions(false); ROOT_DOC->undo(); + setCheckTransactions(true); } bool Model_Session::canRedo() @@ -86,112 +154,272 @@ bool Model_Session::canRedo() void Model_Session::redo() { + setCheckTransactions(false); ROOT_DOC->redo(); + setCheckTransactions(true); } -FeaturePtr Model_Session::createFeature(string theFeatureID) +//! Returns stack of performed operations +std::list Model_Session::undoList() +{ + return ROOT_DOC->undoList(); +} +//! Returns stack of rolled back operations +std::list Model_Session::redoList() { - if (this != myImpl) - return myImpl->createFeature(theFeatureID); + return ROOT_DOC->redoList(); +} +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) { + return myImpl->createFeature(theFeatureID, theDocOwner); + } + + // load all information about plugins, features and attributes LoadPluginsInfo(); + if (myPlugins.find(theFeatureID) != myPlugins.end()) { std::pair& aPlugin = myPlugins[theFeatureID]; // plugin and doc kind - if (!aPlugin.second.empty() && aPlugin.second != activeDocument()->kind()) { - Events_Error::send( - string("Feature '") + theFeatureID + "' can be created only in document '" - + aPlugin.second + "' by the XML definition"); + 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(); return FeaturePtr(); } - myCurrentPluginName = aPlugin.first; - if (myPluginObjs.find(myCurrentPluginName) == myPluginObjs.end()) { - // load plugin library if not yet done - Config_ModuleReader::loadLibrary(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_Error::send( - string("Can not initialize feature '") + theFeatureID + "' in plugin '" - + myCurrentPluginName + "'"); + Events_InfoMessage("Model_Session", "Can not initialize feature '%1' in plugin '%2'") + .arg(theFeatureID).arg(aPlugin.first).send(); } return aCreated; } else { - Events_Error::send(string("Can not load plugin '") + myCurrentPluginName + "'"); + Events_InfoMessage("Model_Session", "Can not load plugin '%1'").arg(aPlugin.first).send(); } } else { - Events_Error::send(string("Feature '") + theFeatureID + "' not found in any plugin"); + Events_InfoMessage("Model_Session", + "Feature '%1' not found in any plugin").arg(theFeatureID).send(); } return FeaturePtr(); // return nothing } -boost::shared_ptr Model_Session::moduleDocument() +std::shared_ptr Model_Session::moduleDocument() { - return boost::shared_ptr( - Model_Application::getApplication()->getDocument("root")); + Handle(Model_Application) anApp = Model_Application::getApplication(); + bool aFirstCall = !anApp->hasRoot(); + if (aFirstCall) { + // to be sure that plugins are loaded, + // even before the first "createFeature" call (in unit tests) + + LoadPluginsInfo(); + // creation of the root document is always outside of the transaction, so, avoid checking it + setCheckTransactions(false); + 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 anApp->rootDocument(); +} + +std::shared_ptr Model_Session::document(int theDocID) +{ + return std::shared_ptr( + Model_Application::getApplication()->document(theDocID)); } bool Model_Session::hasModuleDocument() { - return Model_Application::getApplication()->hasDocument("root"); + return Model_Application::getApplication()->hasRoot(); } -boost::shared_ptr Model_Session::activeDocument() +std::shared_ptr Model_Session::activeDocument() { if (!myCurrentDoc || !Model_Application::getApplication()->hasDocument(myCurrentDoc->id())) myCurrentDoc = moduleDocument(); return myCurrentDoc; } -void Model_Session::setActiveDocument(boost::shared_ptr theDoc) +/// makes the last feature in the document as the current +static void makeCurrentLast(std::shared_ptr theDoc) { + if (theDoc.get()) { + FeaturePtr aLast = std::dynamic_pointer_cast(theDoc)->lastFeature(); + // if last is nested into something else, make this something else as last: + // otherwise it will look like edition of sub-element, so, the main will be disabled + if (aLast.get()) { + CompositeFeaturePtr aMain = ModelAPI_Tools::compositeOwner(aLast); + while(aMain.get()) { + aLast = aMain; + aMain = ModelAPI_Tools::compositeOwner(aLast); + } + } + theDoc->setCurrentFeature(aLast, false); + } +} + +void Model_Session::setActiveDocument( + std::shared_ptr theDoc, bool theSendSignal) { if (myCurrentDoc != theDoc) { + if (myCurrentDoc.get()) + myCurrentDoc->setActive(false); + if (theDoc.get()) + theDoc->setActive(true); + + std::shared_ptr aPrevious = myCurrentDoc; myCurrentDoc = theDoc; - static boost::shared_ptr aMsg(new Events_Message(Events_Loop::eventByName("CurrentDocumentChanged"))); - Events_Loop::loop()->send(aMsg); + if (theDoc.get() && theSendSignal) { + // 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 + DocumentPtr aRoot = moduleDocument(); + if (myCurrentDoc != aRoot) { + FeaturePtr aPartFeat = ModelAPI_Tools::findPartFeature(aRoot, myCurrentDoc); + if (aPartFeat.get()) { + aRoot->setCurrentFeature(aPartFeat, false); + } + } + } + // 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; + setCheckTransactions(false); + TDF_LabelList anEmptyUpdated; + aDoc->objects()->synchronizeFeatures(anEmptyUpdated, true, true, false, true); + if (aWasChecked) + setCheckTransactions(true); + } + static std::shared_ptr aMsg( + new Events_Message(Events_Loop::eventByName(EVENT_DOCUMENT_CHANGED))); + Events_Loop::loop()->send(aMsg); + } + // 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 + makeCurrentLast(aPrevious); + makeCurrentLast(myCurrentDoc); + } else { + // make the current feature the latest in sub, root current feature becomes this sub + makeCurrentLast(myCurrentDoc); + } + } } } -std::list > Model_Session::allOpenedDocuments() +std::list > Model_Session::allOpenedDocuments() { - list > aResult; + std::list > aResult; aResult.push_back(moduleDocument()); // add subs recursively - list >::iterator aDoc = aResult.begin(); + std::list >::iterator aDoc = aResult.begin(); for(; aDoc != aResult.end(); aDoc++) { DocumentPtr anAPIDoc = *aDoc; - boost::shared_ptr aDoc = boost::dynamic_pointer_cast(anAPIDoc); + std::shared_ptr aDoc = std::dynamic_pointer_cast(anAPIDoc); if (aDoc) { - std::set::const_iterator aSubIter = aDoc->subDocuments().cbegin(); - for(; aSubIter != aDoc->subDocuments().cend(); aSubIter++) { - if (!Model_Application::getApplication()->isLoadByDemand(*aSubIter)) { - aResult.push_back(Model_Application::getApplication()->getDocument(*aSubIter)); - } + const std::set aSubs = aDoc->subDocuments(); + std::set::const_iterator aSubIter = aSubs.cbegin(); + for(; aSubIter != aSubs.cend(); aSubIter++) { + aResult.push_back(Model_Application::getApplication()->document(*aSubIter)); } } } return aResult; } -boost::shared_ptr Model_Session::copy( - boost::shared_ptr theSource, std::string theID) +bool Model_Session::isLoadByDemand(const std::string theDocID, const int theDocIndex) { - // create a new document - boost::shared_ptr aNew = boost::dynamic_pointer_cast( - Model_Application::getApplication()->getDocument(theID)); + return Model_Application::getApplication()->isLoadByDemand(theDocID, theDocIndex); +} + +std::shared_ptr Model_Session::copy( + std::shared_ptr theSource, const int theDestID) +{ + std::shared_ptr aNew = Model_Application::getApplication()->document(theDestID); // make a copy of all labels - TDF_Label aSourceRoot = boost::dynamic_pointer_cast(theSource)->document()->Main() + TDF_Label aSourceRoot = std::dynamic_pointer_cast(theSource)->document()->Main() .Father(); TDF_Label aTargetRoot = aNew->document()->Main().Father(); Handle(TDF_DataSet) aDS = new TDF_DataSet; aDS->AddLabel(aSourceRoot); TDF_ClosureTool::Closure(aDS); - Handle(TDF_RelocationTable) aRT = new TDF_RelocationTable; + Handle(TDF_RelocationTable) aRT = new TDF_RelocationTable(Standard_True); aRT->SetRelocation(aSourceRoot, aTargetRoot); TDF_CopyTool::Copy(aDS, aRT); - aNew->synchronizeFeatures(false, true); + // 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; } @@ -199,36 +427,65 @@ Model_Session::Model_Session() { myPluginsInfoLoaded = false; myCheckTransactions = true; - ModelAPI_Session::setSession(boost::shared_ptr(this)); + myOperationAttachedToNext = false; + ModelAPI_Session::setSession(std::shared_ptr(this)); // register the configuration reading listener Events_Loop* aLoop = Events_Loop::loop(); - static const Events_ID kFeatureEvent = Events_Loop::eventByName("FeatureRegisterEvent"); + static const Events_ID kFeatureEvent = + Events_Loop::eventByName(Config_FeatureMessage::MODEL_EVENT()); aLoop->registerListener(this, kFeatureEvent); aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED), 0, true); 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 boost::shared_ptr& theMessage) +void Model_Session::processEvent(const std::shared_ptr& theMessage) { - static const Events_ID kFeatureEvent = Events_Loop::eventByName("FeatureRegisterEvent"); + 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 boost::shared_ptr aMsg = - boost::dynamic_pointer_cast(theMessage); + const std::shared_ptr aMsg = + std::dynamic_pointer_cast(theMessage); if (aMsg) { - // proccess the plugin info, load plugin + + // process the plugin info, load plugin if (myPlugins.find(aMsg->id()) == myPlugins.end()) { myPlugins[aMsg->id()] = std::pair( aMsg->pluginLibrary(), aMsg->documentKind()); } + } else { + const std::shared_ptr aMsgAttr = + std::dynamic_pointer_cast(theMessage); + if (aMsgAttr) { + + if (!aMsgAttr->isObligatory()) { + validators()->registerNotObligatory(aMsgAttr->featureId(), aMsgAttr->attributeId()); + } + 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 myPluginsInfoLoaded = true; } else if (theMessage->eventID() == kValidatorEvent) { - boost::shared_ptr aMsg = - boost::dynamic_pointer_cast(theMessage); + std::shared_ptr aMsg = + std::dynamic_pointer_cast(theMessage); if (aMsg) { if (aMsg->attributeId().empty()) { // feature validator validators()->assignValidator(aMsg->validatorId(), aMsg->featureId(), aMsg->parameters()); @@ -237,9 +494,53 @@ void Model_Session::processEvent(const boost::shared_ptr& theMes 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_Error::send("Modification of data structure outside of the transaction"); + 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); + + 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; + FeaturePtr aCurrentPart = moduleDocument()->currentFeature(true); + if (aCurrentPart.get()) { + const std::list >& aResList = aCurrentPart->results(); + std::list >::const_iterator aRes = aResList.begin(); + for(; !aFound && aRes != aResList.end(); aRes++) { + ResultPartPtr aPRes = std::dynamic_pointer_cast(*aRes); + if (aPRes.get() && aPRes->isActivated() && aPRes->partDoc() == activeDocument()) { + aFound = true; + + } + } + } + if (!aFound) { // if not, the part was removed, so activate the module document + if (myCurrentDoc.get()) + setActiveDocument(moduleDocument()); + } + } + } } } @@ -247,18 +548,31 @@ void Model_Session::LoadPluginsInfo() { if (myPluginsInfoLoaded) // nothing to do return; - // Read plugins information from XML files - Config_ModuleReader aXMLReader("FeatureRegisterEvent"); - aXMLReader.readAll(); + Config_ModuleReader aModuleReader(Config_FeatureMessage::MODEL_EVENT()); + aModuleReader.readAll(); + std::set aFiles = aModuleReader.modulePluginFiles(); + std::set::iterator it = aFiles.begin(); + for ( ; it != aFiles.end(); it++ ) { + Config_ValidatorReader aValidatorReader (*it); + aValidatorReader.readAll(); + }; + } 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) { + Events_Loop* aLoop = Events_Loop::loop(); + static Events_ID aStateRequestEventId = + Events_Loop::loop()->eventByName(EVENT_FEATURE_STATE_REQUEST); + aLoop->registerListener(aListener, aStateRequestEventId); + } } ModelAPI_ValidatorsFactory* Model_Session::validators() @@ -266,3 +580,53 @@ ModelAPI_ValidatorsFactory* Model_Session::validators() static Model_ValidatorsFactory* aFactory = new Model_ValidatorsFactory; 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 + bool 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(); + } + } +}