Salome HOME
updated copyright message
[modules/shaper.git] / src / Model / Model_Session.cpp
index 567dba4d4afcb617c8ae88f13f6dbbe2a600bf0a..b80cdd8eaf92737a34e09d233bece4bb6f4f0dc6 100644 (file)
@@ -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 <Model_Session.h>
 #include <ModelAPI_Feature.h>
 #include <ModelAPI_Plugin.h>
 #include <Model_Data.h>
-#include <Model_Document.h>
 #include <Model_Objects.h>
 #include <Model_Application.h>
 #include <Model_Events.h>
 #include <Model_Validator.h>
+#include <Model_FiltersFactory.h>
 #include <ModelAPI_Events.h>
 #include <Events_Loop.h>
 #include <Events_InfoMessage.h>
 #include <Config_ValidatorMessage.h>
 #include <Config_ModuleReader.h>
 #include <Config_ValidatorReader.h>
+#include <Config_PluginMessage.h>
+
+#include <ModelAPI_CompositeFeature.h>
 #include <ModelAPI_ResultPart.h>
 #include <ModelAPI_Tools.h>
 
+#include <TDF_ChildIDIterator.hxx>
 #include <TDF_CopyTool.hxx>
 #include <TDF_DataSet.hxx>
 #include <TDF_RelocationTable.hxx>
 #include <TDF_ClosureTool.hxx>
 
-using namespace std;
+#include <TNaming_Builder.hxx>
+#include <TNaming_Iterator.hxx>
+#include <TNaming_NamedShape.hxx>
+
+#include <TopoDS_Shape.hxx>
 
 static Model_Session* myImpl = new Model_Session();
 
-// t oredirect all calls to the root document
+// tredirect all calls to the root document
 #define ROOT_DOC std::dynamic_pointer_cast<Model_Document>(moduleDocument())
 
 bool Model_Session::load(const char* theFileName)
 {
+  myIsLoading = true;
   bool aRes = ROOT_DOC->load(theFileName, "root", ROOT_DOC);
+  myIsLoading = false;
   return aRes;
 }
 
@@ -50,11 +73,16 @@ bool Model_Session::save(const char* theFileName, std::list<std::string>& 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<Events_Message> 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<Events_Message> aStartedMsg
@@ -72,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);
 }
@@ -83,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;
@@ -144,7 +180,40 @@ std::list<std::string> Model_Session::redoList()
   return ROOT_DOC->redoList();
 }
 
-FeaturePtr Model_Session::createFeature(string theFeatureID, Model_Document* theDocOwner)
+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) {
     return myImpl->createFeature(theFeatureID, theDocOwner);
@@ -157,26 +226,20 @@ FeaturePtr Model_Session::createFeature(string theFeatureID, Model_Document* the
     std::pair<std::string, std::string>& 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",
@@ -191,14 +254,21 @@ std::shared_ptr<ModelAPI_Document> Model_Session::moduleDocument()
   Handle(Model_Application) anApp = Model_Application::getApplication();
   bool aFirstCall = !anApp->hasRoot();
   if (aFirstCall) {
-    // to be sure that plugins are loaded, 
+    // 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);
+    if (!myCurrentDoc || !Model_Application::getApplication()->hasDocument(myCurrentDoc->id())) {
+      myCurrentDoc = moduleDocument();
+      static std::shared_ptr<Events_Message> aMsg(
+        new Events_Message(Events_Loop::eventByName(EVENT_DOCUMENT_CHANGED)));
+      Events_Loop::loop()->send(aMsg);
+    }
   }
   return anApp->rootDocument();
 }
@@ -216,8 +286,9 @@ bool Model_Session::hasModuleDocument()
 
 std::shared_ptr<ModelAPI_Document> 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;
 }
 
@@ -250,7 +321,7 @@ void Model_Session::setActiveDocument(
     std::shared_ptr<ModelAPI_Document> 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
@@ -262,13 +333,13 @@ 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<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(theDoc);
       if (aDoc.get()) {
         bool aWasChecked = myCheckTransactions;
         setCheckTransactions(false);
         TDF_LabelList anEmptyUpdated;
-        aDoc->objects()->synchronizeFeatures(anEmptyUpdated, true, true, true);
+        aDoc->objects()->synchronizeFeatures(anEmptyUpdated, true, true, false, true);
         if (aWasChecked)
             setCheckTransactions(true);
       }
@@ -276,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
@@ -292,12 +363,12 @@ void Model_Session::setActiveDocument(
 
 std::list<std::shared_ptr<ModelAPI_Document> > Model_Session::allOpenedDocuments()
 {
-  list<std::shared_ptr<ModelAPI_Document> > aResult;
+  std::list<std::shared_ptr<ModelAPI_Document> > aResult;
   aResult.push_back(moduleDocument());
   // add subs recursively
-  list<std::shared_ptr<ModelAPI_Document> >::iterator aDoc = aResult.begin();
-  for(; aDoc != aResult.end(); aDoc++) {
-    DocumentPtr anAPIDoc = *aDoc;
+  std::list<std::shared_ptr<ModelAPI_Document> >::iterator aDocIt = aResult.begin();
+  for(; aDocIt != aResult.end(); aDocIt++) {
+    DocumentPtr anAPIDoc = *aDocIt;
     std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(anAPIDoc);
     if (aDoc) {
       const std::set<int> aSubs = aDoc->subDocuments();
@@ -310,9 +381,9 @@ std::list<std::shared_ptr<ModelAPI_Document> > 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<ModelAPI_Document> Model_Session::copy(
@@ -326,12 +397,56 @@ std::shared_ptr<ModelAPI_Document> Model_Session::copy(
   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);
 
+  // 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<std::pair<TopoDS_Shape, TopoDS_Shape> > aShapePairs; // to store old and new shapes
+    for(TNaming_Iterator anIter(aNamedShape); anIter.More(); anIter.Next()) {
+      aShapePairs.push_back(
+        std::pair<TopoDS_Shape, TopoDS_Shape>(anIter.OldShape(), anIter.NewShape()));
+    }
+
+    // Add in reverse order.
+    TDF_Label aLabel = aNamedShape->Label();
+    TNaming_Builder aBuilder(aLabel);
+    for(std::list<std::pair<TopoDS_Shape, TopoDS_Shape> >::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);
+  aNew->objects()->synchronizeFeatures(anEmptyUpdated, true, true, true, true);
   return aNew;
 }
 
@@ -339,26 +454,28 @@ Model_Session::Model_Session()
 {
   myPluginsInfoLoaded = false;
   myCheckTransactions = true;
-  myOperationAttachedToNext = false;
+  myIsLoading = false;
   ModelAPI_Session::setSession(std::shared_ptr<ModelAPI_Session>(this));
   // register the configuration reading listener
   Events_Loop* aLoop = Events_Loop::loop();
-  static const Events_ID kFeatureEvent = 
+  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 std::shared_ptr<Events_Message>& theMessage)
 {
-  static const Events_ID kFeatureEvent = 
+  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<Config_FeatureMessage> aMsg = 
+    const std::shared_ptr<Config_FeatureMessage> aMsg =
       std::dynamic_pointer_cast<Config_FeatureMessage>(theMessage);
     if (aMsg) {
 
@@ -368,7 +485,7 @@ void Model_Session::processEvent(const std::shared_ptr<Events_Message>& theMessa
           aMsg->pluginLibrary(), aMsg->documentKind());
       }
     } else {
-      const std::shared_ptr<Config_AttributeMessage> aMsgAttr = 
+      const std::shared_ptr<Config_AttributeMessage> aMsgAttr =
         std::dynamic_pointer_cast<Config_AttributeMessage>(theMessage);
       if (aMsgAttr) {
 
@@ -378,16 +495,23 @@ void Model_Session::processEvent(const std::shared_ptr<Events_Message>& theMessa
         if(aMsgAttr->isConcealment()) {
           validators()->registerConcealment(aMsgAttr->featureId(), aMsgAttr->attributeId());
         }
+        if(aMsgAttr->isMainArgument()) {
+          validators()->registerMainArgument(aMsgAttr->featureId(), aMsgAttr->attributeId());
+        }
         const std::list<std::pair<std::string, std::string> >& 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) {
-    std::shared_ptr<Config_ValidatorMessage> aMsg = 
+    std::shared_ptr<Config_ValidatorMessage> aMsg =
       std::dynamic_pointer_cast<Config_ValidatorMessage>(theMessage);
     if (aMsg) {
       if (aMsg->attributeId().empty()) {  // feature validator
@@ -397,17 +521,56 @@ void Model_Session::processEvent(const std::shared_ptr<Events_Message>& theMessa
                                       aMsg->parameters());
       }
     }
+  } else if (theMessage->eventID() == kPluginEvent) { // plugin is started to load
+    std::shared_ptr<Config_PluginMessage> aMsg =
+      std::dynamic_pointer_cast<Config_PluginMessage>(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<ModelAPI_ObjectDeletedMessage> aDeleted =
+          std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
+        std::list<std::shared_ptr<ModelAPI_Document> > allOpened =
+          Model_Session::allOpenedDocuments();
+        std::list<std::pair<std::shared_ptr<ModelAPI_Document>, std::string>>::const_iterator
+          aGIter = aDeleted->groups().cbegin();
+        for (; !aIsActual && aGIter != aDeleted->groups().cend(); aGIter++) {
+          std::list<std::shared_ptr<ModelAPI_Document> >::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<ModelAPI_ObjectDeletedMessage> aDeleted =
         std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
-      if (aDeleted && 
-          aDeleted->groups().find(ModelAPI_ResultPart::group()) != aDeleted->groups().end())
+
+      std::list<std::pair<std::shared_ptr<ModelAPI_Document>, 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;
@@ -424,7 +587,8 @@ void Model_Session::processEvent(const std::shared_ptr<Events_Message>& theMessa
           }
         }
         if (!aFound) { // if not, the part was removed, so activate the module document
-          setActiveDocument(moduleDocument());
+          if (myCurrentDoc.get())
+            setActiveDocument(moduleDocument());
         }
       }
     }
@@ -435,7 +599,6 @@ void Model_Session::LoadPluginsInfo()
 {
   if (myPluginsInfoLoaded)  // nothing to do
     return;
-
   // 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<Events_Listener*>(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<Events_Message> 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<Events_Message> 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