]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Merge branch 'master' of newgeom:newgeom
authornds <natalia.donis@opencascade.com>
Thu, 22 May 2014 14:32:07 +0000 (18:32 +0400)
committernds <natalia.donis@opencascade.com>
Thu, 22 May 2014 14:32:07 +0000 (18:32 +0400)
Conflicts:
src/PartSet/PartSet_OperationEditLine.cpp

26 files changed:
src/Events/CMakeLists.txt
src/Events/Events_Loop.cpp
src/Events/Events_Loop.h
src/Events/Events_MessageGroup.h [new file with mode: 0644]
src/Model/Model_Data.cpp
src/Model/Model_Document.cpp
src/Model/Model_Events.cpp
src/Model/Model_Events.h
src/Model/Model_Object.cpp
src/Model/Model_PluginManager.cpp
src/Model/Model_PluginManager.h
src/ModuleBase/CMakeLists.txt
src/ModuleBase/ModuleBase_Operation.cpp
src/ModuleBase/ModuleBase_Operation.h
src/ModuleBase/ModuleBase_WidgetPoint2D.cpp
src/PartSet/PartSet_Listener.cpp
src/PartSet/PartSet_OperationEditLine.cpp
src/PartSet/PartSet_OperationEditLine.h
src/PartSet/PartSet_OperationSketch.cpp
src/PartSet/PartSet_OperationSketchBase.cpp
src/PartSet/PartSet_OperationSketchBase.h
src/PartSet/PartSet_OperationSketchLine.cpp
src/PartSet/PartSet_OperationSketchLine.h
src/SketchSolver/SketchSolver_ConstraintManager.cpp
src/XGUI/XGUI_DocumentDataModel.cpp
src/XGUI/XGUI_Workshop.cpp

index 89a27f31c8a51a7bfc3b92920942925b95d0a7c2..af4155f4268119e19d78b8f3a0241823fb22e9de 100644 (file)
@@ -3,6 +3,7 @@ INCLUDE(Common)
 SET(PROJECT_HEADERS
     Events.h
     Events_Message.h
+    Events_MessageGroup.h 
     Events_Listener.h
     Events_Loop.h
     Events_Error.h
index 6c8bb476070ed381339cef59b6a08774678a1f95..40917a64f710c5b7d7c815fb3e8f62313ed0bd0d 100644 (file)
@@ -3,6 +3,7 @@
 // Author:     Mikhail PONIKAROV
 
 #include <Events_Loop.h>
+#include <Events_MessageGroup.h>
 
 #include <string>
 #include <cstring>
@@ -32,9 +33,24 @@ Events_ID Events_Loop::eventByName(const char* theName)
   return Events_ID(aResult);
 }
 
-void Events_Loop::send(Events_Message& theMessage)
+void Events_Loop::send(Events_Message& theMessage, bool isGroup)
 {
-  // TO DO: make it in thread and wit husage of semaphores
+  // if it is grouped message, just accumulate it
+  if (isGroup) {
+    Events_MessageGroup* aGroup = dynamic_cast<Events_MessageGroup*>(&theMessage);
+    if (aGroup) {
+      std::map<char*, Events_MessageGroup*>::iterator aMyGroup = 
+        myGroups.find(aGroup->eventID().eventText());
+      if (aMyGroup == myGroups.end()) { // create a new group of messages for accumulation
+        myGroups[aGroup->eventID().eventText()] = aGroup->newEmpty();
+        aMyGroup = myGroups.find(aGroup->eventID().eventText());
+      }
+      aMyGroup->second->Join(*aGroup);
+      return;
+    }
+  }
+
+  // TO DO: make it in thread and with usage of semaphores
 
   map<char*, map<void*, list<Events_Listener*> > >::iterator aFindID = myListeners.find(
       theMessage.eventID().eventText());
@@ -80,3 +96,15 @@ void Events_Loop::registerListener(Events_Listener* theListener, const Events_ID
 
   aListeners.push_back(theListener);
 }
+
+void Events_Loop::flush(const Events_ID& theID)
+{
+  std::map<char*, Events_MessageGroup*>::iterator aMyGroup = 
+    myGroups.find(theID.eventText());
+  if (aMyGroup != myGroups.end()) { // really sends
+    Events_MessageGroup* aGroup = aMyGroup->second;
+    myGroups.erase(aMyGroup);
+    send(*aGroup, false);
+    delete aGroup;
+  }
+}
index 893ecb1994de3a38eb47581ffd950b128ff32c0b..d19dd4d4a39cee1fa832018961e49ea5b8702309 100644 (file)
@@ -11,6 +11,8 @@
 #include <map>
 #include <list>
 
+class Events_MessageGroup;
+
 /**\class Events_Lopp
  * \ingroup EventsLoop
  * \brief Base class that manages the receiving and sending of all
  * control back immideately.
  */
 class Events_Loop {
+  /// map from event ID to sender pointer to listeners that must be called for this
   std::map<char*, std::map<void*, std::list<Events_Listener*> > >
-    myListeners; ///< map from event ID to sender pointer to listeners that must be called for this
+    myListeners;
+
+  /// map from event ID to groupped messages (accumulated on flush)
+  std::map<char*, Events_MessageGroup*> myGroups;
 
   //! The empty constructor, will be called at startup of the application, only once
   Events_Loop() {};
@@ -35,12 +41,16 @@ public:
   EVENTS_EXPORT static Events_ID eventByName(const char* theName);
 
   //! Allows to send an event
-  EVENTS_EXPORT void send(Events_Message& theMessage);
+  //! \param isGroup is true for grouping messages if possible
+  EVENTS_EXPORT void send(Events_Message& theMessage, bool isGroup = true);
 
   //! Registers (or adds if such listener is already registered) a listener 
   //! that will be called on the event and from the defined sender
   EVENTS_EXPORT void registerListener(Events_Listener* theListener, const Events_ID theID, 
     void* theSender = 0);
+
+  //! Initializes sending of a group-message by the given ID
+  EVENTS_EXPORT void flush(const Events_ID& theID);
 };
 
 #endif
diff --git a/src/Events/Events_MessageGroup.h b/src/Events/Events_MessageGroup.h
new file mode 100644 (file)
index 0000000..b95f64d
--- /dev/null
@@ -0,0 +1,33 @@
+// File:       Events_MessageGroup.hxx
+// Created:    Thu Mar 13 2014
+// Author:     Mikhail PONIKAROV
+
+#ifndef Events_MessageGroup_HeaderFile
+#define Events_MessageGroup_HeaderFile
+
+#include <Events_Message.h>
+
+/**\class Events_Message
+ * \ingroup EventsLoop
+ * \brief Message that allows to group messages and send them later as a group of messages.
+ *
+ * Loop detects such messages and accumulates them without sending. On "flush" loop sends it
+ * as a group-message.
+ */
+class EVENTS_EXPORT Events_MessageGroup : public Events_Message {
+
+public:
+
+  //! Creates the message
+  Events_MessageGroup(const Events_ID theID, const void* theSender = 0)
+    : Events_Message(theID, theSender) {}
+  //! do nothing in the destructor yet
+  virtual ~Events_MessageGroup() {}
+
+  //! Creates a new empty group (to store it in the loop before flush)
+  virtual Events_MessageGroup* newEmpty() = 0;
+  //! Allows to join the given message with the current one
+  virtual void Join(Events_MessageGroup& theJoined) = 0;
+};
+
+#endif
index e6c5c02f2e7311aefacbe361f9733014634c9cc4..03effc8e3c9058cfb99083ea373862931075cde2 100644 (file)
@@ -12,6 +12,8 @@
 #include <GeomData_Point2D.h>
 #include <GeomData_Dir.h>
 #include <TDataStd_Name.hxx>
+#include "Model_Events.h"
+#include <Events_Loop.h>
 
 using namespace std;
 
@@ -35,6 +37,9 @@ string Model_Data::getName()
 void Model_Data::setName(string theName)
 {
   TDataStd_Name::Set(myLab, theName.c_str());
+  static Events_ID anEvent = Events_Loop::eventByName(EVENT_FEATURE_UPDATED);
+  Model_FeatureUpdatedMessage aMsg(myFeature, anEvent);
+  Events_Loop::loop()->send(aMsg, false);
 }
 
 void Model_Data::addAttribute(string theID, string theAttrType)
index 37f1a8673a860b8e35152136df6729f400b62037..806709ff24003c099fe34a4a2aa76840acbe7ac2 100644 (file)
@@ -179,7 +179,7 @@ void Model_Document::startOperation()
     myNestedStart = myTransactionsAfterSave;
   }
   // new command for this
-  myDoc->NewCommand();
+  myDoc->OpenCommand();
   // new command for all subs
   set<string>::iterator aSubIter = mySubs.begin();
   for(; aSubIter != mySubs.end(); aSubIter++)
@@ -593,4 +593,11 @@ void Model_Document::synchronizeFeatures()
       aFLabIter.Next();
     }
   }
+  // after all updates, sends a message that groups of features were created or updated
+  boost::static_pointer_cast<Model_PluginManager>(Model_PluginManager::get())->
+    setCheckTransactions(false);
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_CREATED));
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_DELETED));
+  boost::static_pointer_cast<Model_PluginManager>(Model_PluginManager::get())->
+    setCheckTransactions(true);
 }
index cbf4859979003d74a98e762ac767ca08f87ef000..35606208d18dee1cb3b0fbaf6e0b11963c80839a 100644 (file)
@@ -5,11 +5,18 @@
 #include <Model_Events.h>
 #include <Events_Loop.h>
 
+// DELETED methods
+Events_MessageGroup* Model_FeatureDeletedMessage::newEmpty() {
+  return new Model_FeatureDeletedMessage(myDoc, "");
+}
+
 Model_FeatureDeletedMessage::Model_FeatureDeletedMessage(
   const boost::shared_ptr<ModelAPI_Document>& theDoc, const std::string& theGroup)
-  : Events_Message(messageId(), 0), myDoc(theDoc), myGroup(theGroup)
+  : Events_MessageGroup(messageId(), 0), myDoc(theDoc)
 
 {
+  if (!theGroup.empty())
+    myGroups.insert(theGroup);
 }
 
 const Events_ID Model_FeatureDeletedMessage::messageId()
@@ -18,25 +25,11 @@ const Events_ID Model_FeatureDeletedMessage::messageId()
   return MY_ID;
 }
 
-Model_FeaturesMovedMessage::Model_FeaturesMovedMessage()
-: Events_Message(messageId(), 0)
+void Model_FeatureDeletedMessage::Join(Events_MessageGroup& theJoined)
 {
+  Model_FeatureDeletedMessage* aJoined = dynamic_cast<Model_FeatureDeletedMessage*>(&theJoined);
+  std::set<std::string>::iterator aGIter = aJoined->myGroups.begin();
+  for(; aGIter != aJoined->myGroups.end(); aGIter++) {
+    myGroups.insert(*aGIter);
+  }
 }
-
-const Events_ID Model_FeaturesMovedMessage::messageId()
-{
-  static Events_ID MY_ID = Events_Loop::eventByName(EVENT_FEATURES_MOVED);
-  return MY_ID;
-}
-
-void Model_FeaturesMovedMessage::setFeatures(
-                                const std::list<boost::shared_ptr<ModelAPI_Feature> >& theFeatures)
-{
-  myFeatures = theFeatures;  
-}
-
-const std::list<boost::shared_ptr<ModelAPI_Feature> >& Model_FeaturesMovedMessage::features() const
-{
-  return myFeatures;
-}
-
index c9c60b65ffd77a2be6b9fb3a2e4dc1c5a832da55..6f8631fb38b833911a7a52d91afef6aa37d4a330 100644 (file)
@@ -6,11 +6,11 @@
 #define Model_Events_HeaderFile
 
 #include <Model.h>
-#include <Events_Message.h>
+#include <Events_MessageGroup.h>
 #include <Events_Loop.h>
 #include <boost/shared_ptr.hpp>
 #include <string>
-#include <list>
+#include <set>
 
 class ModelAPI_Feature;
 class ModelAPI_Document;
@@ -22,26 +22,41 @@ static const char * EVENT_FEATURE_UPDATED = "FeatureUpdated";
 /// Event ID that data of feature is deleted (comes with Model_FeatureDeletedMessage)
 static const char * EVENT_FEATURE_DELETED = "FeatureDeleted";
 /// Event ID that data of feature is updated (comes with Model_FeaturesMovedMessage)
-static const char * EVENT_FEATURES_MOVED = "FeaturesMoved";
+static const char * EVENT_FEATURE_MOVED = "FeaturesMoved";
 
-/// Message that feature was changed (used for Object Browser update)
-class Model_FeatureUpdatedMessage : public Events_Message {
-  boost::shared_ptr<ModelAPI_Feature> myFeature; ///< which feature is changed
+/// Message that feature was changed (used for Object Browser update): moved, updated and deleted
+class Model_FeatureUpdatedMessage : public Events_MessageGroup {
+  std::set<boost::shared_ptr<ModelAPI_Feature> > myFeatures; ///< which feature is changed
 public:
   /// sender is not important, all information is located in the feature
   Model_FeatureUpdatedMessage(
     const boost::shared_ptr<ModelAPI_Feature>& theFeature,
-    const Events_ID& theEvent) : Events_Message(theEvent, 0), myFeature(theFeature)
-  {}
+    const Events_ID& theEvent) : Events_MessageGroup(theEvent, 0)
+  {if (theFeature) myFeatures.insert(theFeature);}
 
   /// Returns the feature that has been updated
-  boost::shared_ptr<ModelAPI_Feature> feature() const {return myFeature;}
+  std::set<boost::shared_ptr<ModelAPI_Feature> > features() const {return myFeatures;}
+
+  //! Creates a new empty group (to store it in the loop before flush)
+  virtual Events_MessageGroup* newEmpty() {
+    boost::shared_ptr<ModelAPI_Feature> anEmptyFeature;
+    return new Model_FeatureUpdatedMessage(anEmptyFeature, eventID());
+  }
+
+  //! Allows to join the given message with the current one
+  virtual void Join(Events_MessageGroup& theJoined) {
+    Model_FeatureUpdatedMessage* aJoined = dynamic_cast<Model_FeatureUpdatedMessage*>(&theJoined);
+    std::set<boost::shared_ptr<ModelAPI_Feature> >::iterator aFIter = aJoined->myFeatures.begin();
+    for(; aFIter != aJoined->myFeatures.end(); aFIter++) {
+      myFeatures.insert(*aFIter);
+    }
+  }
 };
 
 /// Message that feature was deleted (used for Object Browser update)
-class Model_FeatureDeletedMessage : public Events_Message {
+class Model_FeatureDeletedMessage : public Events_MessageGroup {
   boost::shared_ptr<ModelAPI_Document> myDoc; ///< document owner of the feature
-  std::string myGroup; ///< group identifier that contained the deleted feature
+  std::set<std::string> myGroups; ///< group identifiers that contained the deleted feature
 public:
   /// creates a message by initialization of fields
   Model_FeatureDeletedMessage(const boost::shared_ptr<ModelAPI_Document>& theDoc,
@@ -54,24 +69,13 @@ public:
   boost::shared_ptr<ModelAPI_Document> document() const {return myDoc;}
 
   /// Returns the group where the feature was deleted
-  const std::string& group() const {return myGroup;}
-};
-
-/// Message that features were moved (used for the feature preview update)
-class Model_FeaturesMovedMessage : public Events_Message {
-  std::list<boost::shared_ptr<ModelAPI_Feature> > myFeatures; ///< which features are moved
-public:
-  /// creates a message by initialization of fields
-  MODEL_EXPORT Model_FeaturesMovedMessage();
-
-  /// Returns the ID of this message (EVENT_FEATURES_MOVED)
-  static const Events_ID messageId();
+  const std::set<std::string >& groups() const {return myGroups;}
 
-  /// Sets a list of features
-  MODEL_EXPORT void setFeatures(const std::list<boost::shared_ptr<ModelAPI_Feature> >& theFeatures);
+  //! Creates a new empty group (to store it in the loop before flush)
+  virtual Events_MessageGroup* newEmpty();
 
-  /// Returns a list of features
-  MODEL_EXPORT const std::list<boost::shared_ptr<ModelAPI_Feature> >& features() const;
+  //! Allows to join the given message with the current one
+  virtual void Join(Events_MessageGroup& theJoined);
 };
 
 #endif
index 9b39c6d2f2d02c339f0c1cc00860fea09ce82a00..c8a852b511c0eb5e2edefbd9811b426d2b4cda35 100644 (file)
@@ -4,6 +4,8 @@
 
 #include "Model_Object.h"
 #include <TCollection_AsciiString.hxx>
+#include "Model_Events.h"
+#include <Events_Loop.h>
 
 boost::shared_ptr<ModelAPI_Feature> Model_Object::featureRef()
 {
@@ -17,7 +19,12 @@ std::string Model_Object::getName()
 
 void Model_Object::setName(std::string theName)
 {
-  myName->Set(theName.c_str());
+  if (myName->Get() != theName.c_str()) {
+    myName->Set(theName.c_str());
+    static Events_ID anEvent = Events_Loop::eventByName(EVENT_FEATURE_UPDATED);
+    Model_FeatureUpdatedMessage aMsg(boost::shared_ptr<ModelAPI_Object>(this), anEvent);
+    Events_Loop::loop()->send(aMsg, false);
+  }
 }
 
 Model_Object::Model_Object(boost::shared_ptr<ModelAPI_Feature> theRef,
index 7a0a20d0a009958e1b4e4b1073aaefdbe5d00bf8..1a6cef9d82964e297c036547464e3240ac0bdeec 100644 (file)
@@ -8,6 +8,7 @@
 #include <Model_Data.h>
 #include <Model_Document.h>
 #include <Model_Application.h>
+#include <Model_Events.h>
 #include <Events_Loop.h>
 #include <Events_Error.h>
 #include <Config_FeatureMessage.h>
@@ -97,27 +98,35 @@ boost::shared_ptr<ModelAPI_Document> Model_PluginManager::copy(
 Model_PluginManager::Model_PluginManager()
 {
   myPluginsInfoLoaded = false;
-  //TODO(sbh): Implement static method to extract event id [SEID]
-  static Events_ID aFeatureEvent = Events_Loop::eventByName("FeatureRegisterEvent");
-
+  myCheckTransactions = true;
   ModelAPI_PluginManager::SetPluginManager(boost::shared_ptr<ModelAPI_PluginManager>(this));
   // register the configuration reading listener
   Events_Loop* aLoop = Events_Loop::loop();
-  aLoop->registerListener(this, aFeatureEvent);
+  static Events_ID FeatureEvent = Events_Loop::eventByName("FeatureRegisterEvent");
+  aLoop->registerListener(this, FeatureEvent);
+  aLoop->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_CREATED));
+  aLoop->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
+  aLoop->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_DELETED));
 }
 
 void Model_PluginManager::processEvent(const Events_Message* theMessage)
 {
-  const Config_FeatureMessage* aMsg =
-    dynamic_cast<const Config_FeatureMessage*>(theMessage);
-  if (aMsg) {
-    // proccess the plugin info, load plugin
-    if (myPlugins.find(aMsg->id()) == myPlugins.end()) {
-      myPlugins[aMsg->id()] = aMsg->pluginLibrary();
+  static Events_ID FeatureEvent = Events_Loop::eventByName("FeatureRegisterEvent");
+  if (theMessage->eventID() == FeatureEvent) {
+    const Config_FeatureMessage* aMsg =
+      dynamic_cast<const Config_FeatureMessage*>(theMessage);
+    if (aMsg) {
+      // proccess the plugin info, load plugin
+      if (myPlugins.find(aMsg->id()) == myPlugins.end()) {
+        myPlugins[aMsg->id()] = aMsg->pluginLibrary();
+      }
     }
+    // plugins information was started to load, so, it will be loaded
+    myPluginsInfoLoaded = true;
+  } else { // create/update/delete
+    if (myCheckTransactions && !rootDocument()->isOperation())
+      Events_Error::send("Modification of data structure outside of the transaction");
   }
-  // plugins information was started to load, so, it will be loaded
-  myPluginsInfoLoaded = true;
 }
 
 void Model_PluginManager::LoadPluginsInfo()
index aa230700a1dc5d44e33bd8020402a25ad5971a8a..4efef6a4cd5034c79e8ff69a405cc49b852ceb33 100644 (file)
@@ -26,6 +26,7 @@ class Model_PluginManager : public ModelAPI_PluginManager, public Events_Listene
   std::map<std::string, ModelAPI_Plugin*> myPluginObjs; ///< instances of the already plugins
   std::string myCurrentPluginName; ///< name of the plugin that must be loaded currently
   boost::shared_ptr<ModelAPI_Document> myCurrentDoc; ///< current working document
+  bool myCheckTransactions; ///< if true, generates error if document is updated outside of transaction
 public:
   /// Returns the root document of the application (that may contains sub-documents)
   MODEL_EXPORT virtual boost::shared_ptr<ModelAPI_Document> rootDocument();
@@ -51,6 +52,8 @@ public:
   MODEL_EXPORT virtual boost::shared_ptr<ModelAPI_Document> copy(
     boost::shared_ptr<ModelAPI_Document> theSource, std::string theID);
 
+  void setCheckTransactions(const bool theCheck) {myCheckTransactions = theCheck;}
+
   /// Is called only once, on startup of the application
   Model_PluginManager();
 
index b154decb009ed0e9e21ba1c885e7f0bfdeb7f47e..82f7214d88e005c820d1fda431e71c81f9b8eb81 100644 (file)
@@ -41,6 +41,8 @@ SOURCE_GROUP ("Generated Files" FILES ${PROJECT_AUTOMOC} ${PROJECT_COMPILED_RESO
 
 INCLUDE_DIRECTORIES(
     ${PROJECT_SOURCE_DIR}/src/Config
+    ${CMAKE_SOURCE_DIR}/src/Events
+    ${CMAKE_SOURCE_DIR}/src/Model
     ${CMAKE_SOURCE_DIR}/src/ModelAPI
     ${CMAKE_SOURCE_DIR}/src/GeomDataAPI
 )
index e742c055393a02e4d1d582406fbc71b82bc2d27a..a513205e17f29df06e41ea74e03e741b441eb308 100644 (file)
@@ -15,6 +15,9 @@
 #include <ModelAPI_Feature.h>
 #include <ModelAPI_Data.h>
 #include <ModelAPI_Document.h>
+#include <Model_Events.h>
+
+#include <Events_Loop.h>
 
 #ifdef _DEBUG
 #include <QDebug>
@@ -47,6 +50,7 @@ void ModuleBase_Operation::storeReal(double theValue)
   boost::shared_ptr<ModelAPI_Data> aData = myFeature->data();
   boost::shared_ptr<ModelAPI_AttributeDouble> aReal = aData->real(anId.toStdString());
   aReal->setValue(theValue);
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
 }
 
 void ModuleBase_Operation::storeCustomValue()
@@ -84,13 +88,26 @@ void ModuleBase_Operation::commitOperation()
   if (myFeature) myFeature->execute();
 }
 
-boost::shared_ptr<ModelAPI_Feature> ModuleBase_Operation::createFeature()
+void ModuleBase_Operation::flushUpdated()
+{
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
+}
+
+void ModuleBase_Operation::flushCreated()
+{
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_CREATED));
+}
+
+boost::shared_ptr<ModelAPI_Feature> ModuleBase_Operation::createFeature(const bool theFlushMessage)
 {
   boost::shared_ptr<ModelAPI_Document> aDoc = document();
   boost::shared_ptr<ModelAPI_Feature> aFeature = aDoc->addFeature(
                                            getDescription()->operationId().toStdString());
   if (aFeature) // TODO: generate an error if feature was not created
     aFeature->execute();
+
+  if (theFlushMessage)
+    flushCreated();
   return aFeature;
 }
 
index 43c225dd147802f48e5fc3c3bd22209d596f567a..e992762aba096e6b98ef741925fabaf23d94ff21 100644 (file)
@@ -70,9 +70,15 @@ protected:
   /// Virtual method called when operation committed (see commit() method for more description)
   virtual void commitOperation();
 
+  /// Send update message by loop
+  void flushUpdated();
+  /// Send created message by loop
+  void flushCreated();
+
   /// Creates an operation new feature
+  /// \param theFlushMessage the flag whether the create message should be flushed
   /// \returns the created feature
-  virtual boost::shared_ptr<ModelAPI_Feature> createFeature();
+  virtual boost::shared_ptr<ModelAPI_Feature> createFeature(const bool theFlushMessage = true);
 
   /// Returns the operation feature
   /// \return the feature
index d0ce1b11e50e5d7266f83a467664d6049494a1a0..4d99d01be7fccfd41897cc5c04ea5d594e8f1548 100644 (file)
@@ -6,6 +6,9 @@
 
 #include <Config_Keywords.h>
 
+#include <Events_Loop.h>
+#include <Model_Events.h>
+
 #include <ModelAPI_Feature.h>
 #include <ModelAPI_Data.h>
 #include <GeomDataAPI_Point2D.h>
@@ -68,6 +71,8 @@ bool ModuleBase_WidgetPoint2D::storeValue(boost::shared_ptr<ModelAPI_Feature> th
 
   bool isBlocked = this->blockSignals(true);
   aPoint->setValue(myXSpin->value(), myYSpin->value());
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
+
   this->blockSignals(isBlocked);
   return true;
 }
index 06af416d2126fd71e46db484992169a55ae4e3f5..355142a31449d3cf0eff57d1dad009b7f04e57f9 100644 (file)
@@ -37,24 +37,34 @@ void PartSet_Listener::processEvent(const Events_Message* theMessage)
   if (aType == EVENT_FEATURE_UPDATED ||
       aType == EVENT_FEATURE_CREATED)
   {
-    const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
-    boost::shared_ptr<ModelAPI_Feature> aFeature = aUpdMsg->feature();
-    if (myModule->workshop()->displayer()->IsVisible(aFeature) ||
-        aType == EVENT_FEATURE_CREATED) {
-      myModule->visualizePreview(aFeature, true, false);
-      myModule->activateFeature(aFeature, true);
-      myModule->workshop()->displayer()->UpdateViewer();
+    const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>
+                                                                                    (theMessage);
+    std::set<boost::shared_ptr<ModelAPI_Feature> > aFeatures = aUpdMsg->features();
+    std::set<boost::shared_ptr<ModelAPI_Feature> >::const_iterator anIt = aFeatures.begin(),
+                                                                   aLast = aFeatures.end();
+    for (; anIt != aLast; anIt++) {
+      boost::shared_ptr<ModelAPI_Feature> aFeature = *anIt;
+      if (myModule->workshop()->displayer()->IsVisible(aFeature) ||
+          aType == EVENT_FEATURE_CREATED) {
+        myModule->visualizePreview(aFeature, true, false);
+        myModule->activateFeature(aFeature, true);
+      }
     }
+    myModule->workshop()->displayer()->UpdateViewer();
   }
   if (aType == EVENT_FEATURE_DELETED)
   {
     const Model_FeatureDeletedMessage* aDelMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
     boost::shared_ptr<ModelAPI_Document> aDoc = aDelMsg->document();
 
-    std::string aGroup = aDelMsg->group();
-    if (aDelMsg->group().compare("Sketch") == 0) { // Update only Sketch group
-      myModule->workshop()->displayer()->EraseDeletedFeatures();
-      myModule->updateCurrentPreview(aGroup);
+    std::set<std::string> aGroups = aDelMsg->groups();
+    std::set<std::string>::const_iterator anIt = aGroups.begin(), aLast = aGroups.end();
+    for (; anIt != aLast; anIt++) {
+      std::string aGroup = *anIt;
+      if (aGroup.compare("Sketch") == 0) { // Update only Sketch group
+        myModule->workshop()->displayer()->EraseDeletedFeatures();
+        myModule->updateCurrentPreview(aGroup);
+      }
     }
   }
 }
index 561ae86e3a5718fa351629d7897f0c2a9c966ba1..d630bb2c3c914dcd9847677b2cc1a13d82fac739 100644 (file)
@@ -7,6 +7,7 @@
 #include <PartSet_OperationSketch.h>
 
 #include <ModuleBase_OperationDescription.h>
+#include <Model_Events.h>
 
 #include <XGUI_ViewerPrs.h>
 
@@ -134,6 +135,7 @@ void PartSet_OperationEditLine::mouseMoved(QMouseEvent* theEvent, Handle(V3d_Vie
       moveLinePoint(aFeature, aDeltaX, aDeltaY, LINE_ATTR_END);
     }
   }
+  flushUpdated();
   sendFeatures();
 
   myCurPoint.setPoint(aPoint);
@@ -190,7 +192,7 @@ void PartSet_OperationEditLine::blockSelection(bool isBlocked, const bool isRest
   }
 }
 
-boost::shared_ptr<ModelAPI_Feature> PartSet_OperationEditLine::createFeature()
+boost::shared_ptr<ModelAPI_Feature> PartSet_OperationEditLine::createFeature(const bool /*theFlushMessage*/)
 {
   // do nothing in order to do not create a new feature
   return boost::shared_ptr<ModelAPI_Feature>();
@@ -212,17 +214,18 @@ void PartSet_OperationEditLine::moveLinePoint(boost::shared_ptr<ModelAPI_Feature
 
 void PartSet_OperationEditLine::sendFeatures()
 {
+  static Events_ID anEvent = Events_Loop::eventByName(EVENT_FEATURE_MOVED);
+
   std::list<boost::shared_ptr<ModelAPI_Feature> > aFeatures;
   std::list<XGUI_ViewerPrs>::const_iterator anIt = myFeatures.begin(), aLast = myFeatures.end();
   for (; anIt != aLast; anIt++) {
     boost::shared_ptr<ModelAPI_Feature> aFeature = (*anIt).feature();
-    if (!aFeature || aFeature == feature())
+    if (!aFeature)
       continue;
-  }
 
-  static Events_ID aModuleEvent = Events_Loop::eventByName("PartSetEditEvent");
-  Model_FeaturesMovedMessage aMessage;
-  aMessage.setFeatures(aFeatures);
-  Events_Loop::loop()->send(aMessage);
+    Model_FeatureUpdatedMessage aMessage(aFeature, anEvent);
+    Events_Loop::loop()->send(aMessage);
+  }
+  Events_Loop::loop()->flush(anEvent);
 }
 
index 8f0b62361174db341d136997d8c33436728cb377..219d23b2c9eb4aec94114620833bd5edb4e9f2aa 100644 (file)
@@ -114,8 +114,9 @@ protected:
 
   /// Creates an operation new feature
   /// Returns NULL feature. This is an operation of edition, not creation.
+  /// \param theFlushMessage the flag whether the create message should be flushed
   /// \returns the created feature
-  virtual boost::shared_ptr<ModelAPI_Feature> createFeature();
+  virtual boost::shared_ptr<ModelAPI_Feature> createFeature(const bool theFlushMessage = true);
 
 protected:
   /// Emits a signal about the selection blocking. Emits a signal to change the selection.
index e818e5ec12df7737cb10b06b00fe0675ac2ab4df..e57a113b73ebc39cc1a6cd82a708afc48c8c795d 100644 (file)
@@ -160,6 +160,9 @@ void PartSet_OperationSketch::setSketchPlane(const TopoDS_Shape& theShape)
     boost::dynamic_pointer_cast<GeomDataAPI_Dir>(aData->attribute(SKETCH_ATTR_DIRY));
   aDirY->setValue(aC, anA, aB);
   boost::shared_ptr<GeomAPI_Dir> aDir = aPlane->direction();
+
+  flushUpdated();
+
   emit featureConstructed(feature(), FM_Hide);
   emit closeLocalContext();
   emit planeSelected(aDir->x(), aDir->y(), aDir->z());
index c83897545d3d663f6a66c6bc1e4d5a734db5506a..acf76c60a094e134b5a9691c7e1be72ad383cbbe 100644 (file)
@@ -54,9 +54,9 @@ std::list<int> PartSet_OperationSketchBase::getSelectionModes(boost::shared_ptr<
   aModes.push_back(TopAbs_EDGE);
   return aModes;
 }
-boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchBase::createFeature()
+boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchBase::createFeature(const bool theFlushMessage)
 {
-  boost::shared_ptr<ModelAPI_Feature> aFeature = ModuleBase_Operation::createFeature();
+  boost::shared_ptr<ModelAPI_Feature> aFeature = ModuleBase_Operation::createFeature(theFlushMessage);
   if (aFeature)
     emit featureConstructed(aFeature, FM_Activation);
   return aFeature;
index 53916ee6f8dc2321caf2fb15506a15fb5686f661..5aa07c3f002c0ab90f8171e5d701c8fe629262ae 100644 (file)
@@ -124,8 +124,9 @@ protected:
   /// Creates an operation new feature
   /// In addition to the default realization it appends the created line feature to
   /// the sketch feature
+  /// \param theFlushMessage the flag whether the create message should be flushed
   /// \returns the created feature
-  virtual boost::shared_ptr<ModelAPI_Feature> createFeature();
+  virtual boost::shared_ptr<ModelAPI_Feature> createFeature(const bool theFlushMessage = true);
 };
 
 #endif
index 4ccf1c16cfee09af1bcbd49a082dc99959226af7..33e03c5e2c4d4c841b9148252902ee0834c3a0a2 100644 (file)
@@ -144,11 +144,15 @@ void PartSet_OperationSketchLine::mouseReleased(QMouseEvent* theEvent, Handle(V3
     case SM_FirstPoint: {
       setLinePoint(feature(), aX, anY, LINE_ATTR_START);
       setLinePoint(feature(), aX, anY, LINE_ATTR_END);
+      flushUpdated();
+
       myPointSelectionMode = SM_SecondPoint;
     }
     break;
     case SM_SecondPoint: {
       setLinePoint(feature(), aX, anY, LINE_ATTR_END);
+      flushUpdated();
+
       myPointSelectionMode = SM_DonePoint;
     }
     break;
@@ -167,12 +171,14 @@ void PartSet_OperationSketchLine::mouseMoved(QMouseEvent* theEvent, Handle(V3d_V
       PartSet_Tools::ConvertTo2D(aPoint, sketch(), theView, aX, anY);
       setLinePoint(feature(), aX, anY, LINE_ATTR_START);
       setLinePoint(feature(), aX, anY, LINE_ATTR_END);
+      flushUpdated();
     }
     break;
     case SM_SecondPoint:
     {
       gp_Pnt aPoint = PartSet_Tools::ConvertClickToPoint(theEvent->pos(), theView);
       setLinePoint(aPoint, theView, LINE_ATTR_END);
+      flushUpdated();
     }
     break;
     case SM_DonePoint:
@@ -233,9 +239,9 @@ void PartSet_OperationSketchLine::stopOperation()
   emit multiSelectionEnabled(true);
 }
 
-boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchLine::createFeature()
+boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchLine::createFeature(const bool theFlushMessage)
 {
-  boost::shared_ptr<ModelAPI_Feature> aNewFeature = ModuleBase_Operation::createFeature();
+  boost::shared_ptr<ModelAPI_Feature> aNewFeature = ModuleBase_Operation::createFeature(false);
   if (sketch()) {
     boost::shared_ptr<SketchPlugin_Feature> aFeature = 
                            boost::dynamic_pointer_cast<SketchPlugin_Feature>(sketch());
@@ -253,6 +259,8 @@ boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchLine::createFeature()
   }
 
   emit featureConstructed(aNewFeature, FM_Activation);
+  if (theFlushMessage)
+    flushCreated();
   return aNewFeature;
 }
 
index 0d556d2c06103b69e30d2549f715820993960049..db20415c74cb86f54548866d6b52f83077734eb7 100644 (file)
@@ -89,8 +89,9 @@ protected:
   /// Creates an operation new feature
   /// In addition to the default realization it appends the created line feature to
   /// the sketch feature
+  /// \param theFlushMessage the flag whether the create message should be flushed
   /// \returns the created feature
-  virtual boost::shared_ptr<ModelAPI_Feature> createFeature();
+  virtual boost::shared_ptr<ModelAPI_Feature> createFeature(const bool theFlushMessage = true);
 
   /// Creates a constraint on two points
   /// \param thePoint1 the first point
index 4a47879faab6da65aadfed7598a0fe0620468d31..7caf4342ca625a72908582d28b85248bada6a7bb 100644 (file)
@@ -12,6 +12,7 @@
 #include <ModelAPI_AttributeRefList.h>
 #include <ModelAPI_Data.h>
 #include <Model_Events.h>
+
 #include <SketchPlugin_Constraint.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
 #include <SketchPlugin_Line.h>
@@ -21,6 +22,8 @@
 #include <math.h>
 #include <assert.h>
 
+#include <set>
+
 /// Tolerance for value of parameters
 const double tolerance = 1.e-10;
 
@@ -61,7 +64,7 @@ SketchSolver_ConstraintManager::SketchSolver_ConstraintManager()
   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_CREATED));
   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_DELETED));
-  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURES_MOVED));
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_MOVED));
 }
 
 SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
@@ -72,37 +75,58 @@ SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
 void SketchSolver_ConstraintManager::processEvent(const Events_Message* theMessage)
 {
   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED) ||
-      theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED))
+      theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED) || 
+      theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_MOVED))
   {
-    const Model_FeatureUpdatedMessage* aUpdateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
+    const Model_FeatureUpdatedMessage* anUpdateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
+    std::set< boost::shared_ptr<ModelAPI_Feature> > aFeatures = anUpdateMsg->features();
 
-    // Only sketches and constraints can be added by Create event
-    const std::string& aFeatureKind = aUpdateMsg->feature()->getKind();
-    if (aFeatureKind.compare("Sketch") == 0)
-    {
-      boost::shared_ptr<SketchPlugin_Feature> aSketch =
-        boost::dynamic_pointer_cast<SketchPlugin_Feature>(aUpdateMsg->feature());
-      changeWorkplane(aSketch);
-      return ;
-    }
-    boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
-      boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aUpdateMsg->feature());
-    if (aConstraint)
-      changeConstraint(aConstraint);
-    else
+    bool isModifiedEvt = theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_MOVED);
+    if (!isModifiedEvt)
     {
-      // Sketch plugin features can be only updated
-      boost::shared_ptr<SketchPlugin_Feature> aFeature =
-        boost::dynamic_pointer_cast<SketchPlugin_Feature>(aUpdateMsg->feature());
-      if (aFeature)
-        updateEntity(aFeature);
+      std::set< boost::shared_ptr<ModelAPI_Feature> >::iterator aFeatIter;
+      for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++)
+      {
+        // Only sketches and constraints can be added by Create event
+        const std::string& aFeatureKind = (*aFeatIter)->getKind();
+        if (aFeatureKind.compare("Sketch") == 0)
+        {
+          boost::shared_ptr<SketchPlugin_Feature> aSketch =
+            boost::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
+          if (aSketch)
+            changeWorkplane(aSketch);
+          return ;
+        }
+        boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
+          boost::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFeatIter);
+        if (aConstraint)
+          changeConstraint(aConstraint);
+        else
+        {
+          // Sketch plugin features can be only updated
+          boost::shared_ptr<SketchPlugin_Feature> aFeature =
+            boost::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
+          if (aFeature)
+            updateEntity(aFeature);
+        }
+      }
     }
+
+    // Solve the set of constraints
+    resolveConstraints();
   }
   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_DELETED))
   {
     const Model_FeatureDeletedMessage* aDeleteMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
-
-    if (aDeleteMsg->group().compare("Sketch") == 0)
+    const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
+
+    // Find "Sketch" in groups. The constraint groups should be updated when an object removed from Sketch
+    std::set<std::string>::const_iterator aFGrIter;
+    for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
+      if (aFGrIter->compare("Sketch") == 0)
+        break;
+    
+    if (aFGrIter != aFeatureGroups.end())
     {
       std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter = myGroups.begin();
       while (aGroupIter != myGroups.end())
@@ -118,11 +142,6 @@ void SketchSolver_ConstraintManager::processEvent(const Events_Message* theMessa
       }
     }
   }
-  else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURES_MOVED))
-  {
-    // Solve the set of constraints
-    resolveConstraints();
-  }
 }
 
 bool SketchSolver_ConstraintManager::changeWorkplane(boost::shared_ptr<SketchPlugin_Feature> theSketch)
@@ -237,10 +256,16 @@ void SketchSolver_ConstraintManager::findGroups(
 boost::shared_ptr<SketchPlugin_Feature> SketchSolver_ConstraintManager::findWorkplaneForConstraint(
               boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
 {
+  // Already verified workplanes
+  std::set< boost::shared_ptr<SketchPlugin_Feature> > aVerified;
+
   std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
   {
     boost::shared_ptr<SketchPlugin_Feature> aWP = (*aGroupIter)->getWorkplane();
+    if (aVerified.find(aWP) != aVerified.end())
+      continue;
+
     boost::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures =
       boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aWP->data()->attribute(SKETCH_ATTR_FEATURES));
     std::list< boost::shared_ptr<ModelAPI_Feature> > aFeaturesList = aWPFeatures->list();
@@ -248,6 +273,7 @@ boost::shared_ptr<SketchPlugin_Feature> SketchSolver_ConstraintManager::findWork
     for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
       if (*anIter == theConstraint)
         return aWP; // workplane is found
+    aVerified.insert(aWP);
   }
 
   return boost::shared_ptr<SketchPlugin_Feature>();
@@ -258,6 +284,9 @@ void SketchSolver_ConstraintManager::resolveConstraints()
   std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
     (*aGroupIter)->resolveConstraints();
+
+  // Features may be updated => send events
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
 }
 
 
@@ -310,7 +339,19 @@ bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isInteract(
   if (myWorkplane.h != SLVS_E_UNKNOWN && myConstraints.empty())
     return true;
 
-  /// \todo Should be implemented
+  // Go through constraint entities and verify if some of them already in the group
+  for (int i = 0; i < CONSTRAINT_ATTR_SIZE; i++)
+  {
+    boost::shared_ptr<ModelAPI_AttributeRefAttr> aCAttrRef =
+      boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+        theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[i])
+      );
+    if (!aCAttrRef) continue;
+    if (myEntityMap.find(aCAttrRef->attr()) != myEntityMap.end())
+      return true;
+  }
+
+  // Entities did not found
   return false;
 }
 
index 8b42208aee3bd78bacc9ab82b704a7228470b928..d1ca2c2ed4b895c46237f14eeb63322c674fe33b 100644 (file)
@@ -49,73 +49,80 @@ void XGUI_DocumentDataModel::processEvent(const Events_Message* theMessage)
   // Created object event *******************
   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED)) {
     const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
-    FeaturePtr aFeature = aUpdMsg->feature();
-    DocumentPtr aDoc = aFeature->document();
-
-    if (aDoc == myDocument) {  // If root objects
-      if (aFeature->getGroup().compare(PARTS_GROUP) == 0) { // Update only Parts group
-        // Add a new part
-        int aStart = myPartModels.size() + 1;
-        XGUI_PartDataModel* aModel = new XGUI_PartDataModel(myDocument, this);
-        aModel->setPartId(myPartModels.count());
-        myPartModels.append(aModel);
-        insertRow(aStart, partFolderNode());
-      } else { // Update top groups (other except parts
-        QModelIndex aIndex = myModel->findParent(aFeature);
-        int aStart = myModel->rowCount(aIndex) - 1;
-        aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
-        insertRow(aStart, aIndex);
-      }
-    } else { // if sub-objects of first level nodes
-      XGUI_PartModel* aPartModel = 0;
-      QList<XGUI_PartModel*>::const_iterator aIt;
-      for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
-        if ((*aIt)->hasDocument(aDoc)) {
-          aPartModel = (*aIt);
-          break;
+    std::set<FeaturePtr> aFeatures = aUpdMsg->features();
+
+    std::set<FeaturePtr>::const_iterator aIt;
+    for (aIt = aFeatures.begin(); aIt != aFeatures.end(); ++aIt) {
+      FeaturePtr aFeature = (*aIt);
+      DocumentPtr aDoc = aFeature->document();
+      if (aDoc == myDocument) {  // If root objects
+        if (aFeature->getGroup().compare(PARTS_GROUP) == 0) { // Update only Parts group
+          // Add a new part
+          int aStart = myPartModels.size() + 1;
+          XGUI_PartDataModel* aModel = new XGUI_PartDataModel(myDocument, this);
+          aModel->setPartId(myPartModels.count());
+          myPartModels.append(aModel);
+          insertRow(aStart, partFolderNode());
+        } else { // Update top groups (other except parts
+          QModelIndex aIndex = myModel->findParent(aFeature);
+          int aStart = myModel->rowCount(aIndex) - 1;
+          aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
+          insertRow(aStart, aIndex);
+        }
+      } else { // if sub-objects of first level nodes
+        XGUI_PartModel* aPartModel = 0;
+        QList<XGUI_PartModel*>::const_iterator aIt;
+        for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
+          if ((*aIt)->hasDocument(aDoc)) {
+            aPartModel = (*aIt);
+            break;
+          }
+        }
+        if (aPartModel) {
+          QModelIndex aIndex = aPartModel->findParent(aFeature);
+          int aStart = aPartModel->rowCount(aIndex) - 1;
+          aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
+          insertRow(aStart, aIndex);
         }
-      }
-      if (aPartModel) {
-        QModelIndex aIndex = aPartModel->findParent(aFeature);
-        int aStart = aPartModel->rowCount(aIndex) - 1;
-        aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
-        insertRow(aStart, aIndex);
       }
     }
-
   // Deleted object event ***********************
   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_DELETED)) {
     const Model_FeatureDeletedMessage* aUpdMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
     DocumentPtr aDoc = aUpdMsg->document();
-
-    if (aDoc == myDocument) {  // If root objects
-      if (aUpdMsg->group().compare(PARTS_GROUP) == 0) { // Updsate only Parts group
-        int aStart = myPartModels.size() - 1;
-        removeSubModel(aStart);
-        removeRow(aStart, partFolderNode());
-      } else { // Update top groups (other except parts
-        QModelIndex aIndex = myModel->findGroup(aUpdMsg->group());
-        int aStart = myModel->rowCount(aIndex);
-        aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
-        removeRow(aStart, aIndex);
-      }
-    } else {
-      XGUI_PartModel* aPartModel = 0;
-      QList<XGUI_PartModel*>::const_iterator aIt;
-      for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
-        if ((*aIt)->hasDocument(aDoc)) {
-          aPartModel = (*aIt);
-          break;
+    std::set<std::string> aGroups = aUpdMsg->groups();
+
+    std::set<std::string>::const_iterator aIt;
+    for (aIt = aGroups.begin(); aIt != aGroups.end(); ++aIt) {
+      std::string aGroup = (*aIt);
+      if (aDoc == myDocument) {  // If root objects
+        if (aGroup.compare(PARTS_GROUP) == 0) { // Updsate only Parts group
+          int aStart = myPartModels.size() - 1;
+          removeSubModel(aStart);
+          removeRow(aStart, partFolderNode());
+        } else { // Update top groups (other except parts
+          QModelIndex aIndex = myModel->findGroup(aGroup);
+          int aStart = myModel->rowCount(aIndex);
+          aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
+          removeRow(aStart, aIndex);
+        }
+      } else {
+        XGUI_PartModel* aPartModel = 0;
+        QList<XGUI_PartModel*>::const_iterator aIt;
+        for (aIt = myPartModels.constBegin(); aIt != myPartModels.constEnd(); ++aIt) {
+          if ((*aIt)->hasDocument(aDoc)) {
+            aPartModel = (*aIt);
+            break;
+          }
+        }
+        if (aPartModel) {
+          QModelIndex aIndex = aPartModel->findGroup(aGroup);
+          int aStart = aPartModel->rowCount(aIndex);
+          aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
+          removeRow(aStart, aIndex);
         }
-      }
-      if (aPartModel) {
-        QModelIndex aIndex = aPartModel->findGroup(aUpdMsg->group());
-        int aStart = aPartModel->rowCount(aIndex);
-        aIndex = createIndex(aIndex.row(), aIndex.column(), (void*)getModelIndex(aIndex));
-        removeRow(aStart, aIndex);
       }
     }
-
   // Deleted object event ***********************
   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED)) {
     //const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
index 9d064f210bbe9500ad01613bbf22880196a9efcd..a5d6cddab790c12b436efa0c78a10778484ca614 100644 (file)
@@ -212,8 +212,18 @@ void XGUI_Workshop::processEvent(const Events_Message* theMessage)
   // Process creation of Part
   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED)) {
     const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
-    FeaturePtr aFeature = aUpdMsg->feature();
-    if (aFeature->getKind() == "Part") {
+    std::set<FeaturePtr> aFeatures = aUpdMsg->features();
+
+    std::set<FeaturePtr>::const_iterator aIt;
+    bool aHasPart = false;
+    for (aIt = aFeatures.begin(); aIt != aFeatures.end(); ++aIt) {
+      FeaturePtr aFeature = (*aIt);
+      if (aFeature->getKind() == "Part") {
+        aHasPart = true;
+        break;
+      }
+    }
+    if (aHasPart) {
       //The created part will be created in Object Browser later and we have to activate it
       // only when it is created everywere
       QTimer::singleShot(50, this, SLOT(activateLastPart()));
@@ -234,10 +244,16 @@ void XGUI_Workshop::processEvent(const Events_Message* theMessage)
   {
     const Model_FeatureUpdatedMessage* anUpdateMsg =
         dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
-    FeaturePtr aNewFeature = anUpdateMsg->feature();
+    std::set<FeaturePtr> aFeatures = anUpdateMsg->features();
+
     FeaturePtr aCurrentFeature = myOperationMgr->currentOperation()->feature();
-    if(aNewFeature == aCurrentFeature) {
-      myPropertyPanel->updateContentWidget(aCurrentFeature);
+    std::set<FeaturePtr>::const_iterator aIt;
+    for (aIt = aFeatures.begin(); aIt != aFeatures.end(); ++aIt) {
+      FeaturePtr aNewFeature = (*aIt);
+      if(aNewFeature == aCurrentFeature) {
+        myPropertyPanel->updateContentWidget(aCurrentFeature);
+        break;
+      } 
     }
   }
   //An operation passed by message. Start it, process and commit.