Salome HOME
Implementation of mechanism of grouping of messages
authormpv <mikhail.ponikarov@opencascade.com>
Thu, 22 May 2014 08:43:09 +0000 (12:43 +0400)
committermpv <mikhail.ponikarov@opencascade.com>
Thu, 22 May 2014 08:43:09 +0000 (12:43 +0400)
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_Document.cpp
src/Model/Model_Events.cpp
src/Model/Model_Events.h

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..e8d6a716a780abab0f0a0c38e91d6af64f6fadb1 100644 (file)
@@ -3,6 +3,7 @@
 // Author:     Mikhail PONIKAROV
 
 #include <Events_Loop.h>
+#include <Events_MessageGroup.h>
 
 #include <string>
 #include <cstring>
@@ -34,7 +35,20 @@ Events_ID Events_Loop::eventByName(const char* theName)
 
 void Events_Loop::send(Events_Message& theMessage)
 {
-  // TO DO: make it in thread and wit husage of semaphores
+  // if it is grouped message, just accumulate it
+  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 +94,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;
+    send(*aGroup);
+    myGroups.erase(aMyGroup);
+    delete aGroup;
+  }
+}
index 893ecb1994de3a38eb47581ffd950b128ff32c0b..f5721c8b45de9a430690f0c076ce1639fc92448f 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() {};
@@ -41,6 +47,9 @@ public:
   //! 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 37f1a8673a860b8e35152136df6729f400b62037..67953331d65992b1c1d0d991b1cddd0586b43307 100644 (file)
@@ -593,4 +593,7 @@ void Model_Document::synchronizeFeatures()
       aFLabIter.Next();
     }
   }
+  // after all updates, sends a message that groups of features were created or updated
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_CREATED));
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_DELETED));
 }
index cbf4859979003d74a98e762ac767ca08f87ef000..76655e1eec43a70b28f347420a9983c2883bcbfe 100644 (file)
@@ -5,38 +5,46 @@
 #include <Model_Events.h>
 #include <Events_Loop.h>
 
-Model_FeatureDeletedMessage::Model_FeatureDeletedMessage(
-  const boost::shared_ptr<ModelAPI_Document>& theDoc, const std::string& theGroup)
-  : Events_Message(messageId(), 0), myDoc(theDoc), myGroup(theGroup)
-
-{
+// UPDATED methods
+Events_MessageGroup* Model_FeatureUpdatedMessage::newEmpty() {
+  boost::shared_ptr<ModelAPI_Feature> anEmptyFeature;
+  return new Model_FeatureUpdatedMessage(anEmptyFeature, eventID());
 }
 
-const Events_ID Model_FeatureDeletedMessage::messageId()
+void Model_FeatureUpdatedMessage::Join(Events_MessageGroup& theJoined)
 {
-  static Events_ID MY_ID = Events_Loop::eventByName(EVENT_FEATURE_DELETED);
-  return MY_ID;
+  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);
+  }
 }
 
-Model_FeaturesMovedMessage::Model_FeaturesMovedMessage()
-: Events_Message(messageId(), 0)
-{
+// DELETED methods
+Events_MessageGroup* Model_FeatureDeletedMessage::newEmpty() {
+  return new Model_FeatureDeletedMessage(myDoc, "");
 }
 
-const Events_ID Model_FeaturesMovedMessage::messageId()
+Model_FeatureDeletedMessage::Model_FeatureDeletedMessage(
+  const boost::shared_ptr<ModelAPI_Document>& theDoc, const std::string& theGroup)
+  : Events_MessageGroup(messageId(), 0), myDoc(theDoc)
+
 {
-  static Events_ID MY_ID = Events_Loop::eventByName(EVENT_FEATURES_MOVED);
-  return MY_ID;
+  if (!theGroup.empty())
+    myGroups.insert(theGroup);
 }
 
-void Model_FeaturesMovedMessage::setFeatures(
-                                const std::list<boost::shared_ptr<ModelAPI_Feature> >& theFeatures)
+const Events_ID Model_FeatureDeletedMessage::messageId()
 {
-  myFeatures = theFeatures;  
+  static Events_ID MY_ID = Events_Loop::eventByName(EVENT_FEATURE_DELETED);
+  return MY_ID;
 }
 
-const std::list<boost::shared_ptr<ModelAPI_Feature> >& Model_FeaturesMovedMessage::features() const
+void Model_FeatureDeletedMessage::Join(Events_MessageGroup& theJoined)
 {
-  return myFeatures;
+  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);
+  }
 }
-
index c9c60b65ffd77a2be6b9fb3a2e4dc1c5a832da55..0e750f5a6f29dad229606a22b9eb4070e32bff07 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;
@@ -24,24 +24,29 @@ 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";
 
-/// 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();
+  //! Allows to join the given message with the current one
+  virtual void Join(Events_MessageGroup& theJoined);
 };
 
 /// 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 +59,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