From: mpv Date: Thu, 13 Mar 2014 15:29:27 +0000 (+0400) Subject: Initial version of event loop functionality (not multi-threaded) X-Git-Tag: V_0.1~55^2~1 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=d91a33f738cff0ae18a67776525b5c7dd90cd2db;p=modules%2Fshaper.git Initial version of event loop functionality (not multi-threaded) --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 16974454f..d67d35f11 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,7 @@ SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMakeCommon" ${CMAKE_MODULE_PATH}) INCLUDE(Common) INCLUDE(FindQt5) +ADD_SUBDIRECTORY (src/Event) #ADD_SUBDIRECTORY (src/ModelAPI) ADD_SUBDIRECTORY (src/Model) ADD_SUBDIRECTORY (src/XGUI) diff --git a/src/Event/CMakeLists.txt b/src/Event/CMakeLists.txt new file mode 100644 index 000000000..7a8af5bc4 --- /dev/null +++ b/src/Event/CMakeLists.txt @@ -0,0 +1,23 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11) + +INCLUDE(Common) + +SET(PROJECT_HEADERS + Event.hxx + Event_Message.hxx + Event_Listener.hxx + Event_Loop.hxx +) + +SET(PROJECT_SOURCES + Event_Message.cxx + Event_Listener.cxx + Event_Loop.cxx +) + +ADD_DEFINITIONS(-DEVENT_EXPORTS) +ADD_LIBRARY(Event SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS}) +TARGET_LINK_LIBRARIES(Event ${PROJECT_LIBRARIES}) + +INCLUDE_DIRECTORIES( +) diff --git a/src/Event/Event.hxx b/src/Event/Event.hxx new file mode 100644 index 000000000..d99cd0046 --- /dev/null +++ b/src/Event/Event.hxx @@ -0,0 +1,18 @@ +#ifndef EVENT_H +#define EVENT_H + +#if defined EVENT_EXPORTS +#if defined WIN32 +#define EVENT_EXPORT __declspec( dllexport ) +#else +#define EVENT_EXPORT +#endif +#else +#if defined WIN32 +#define EVENT_EXPORT __declspec( dllimport ) +#else +#define EVENT_EXPORT +#endif +#endif + +#endif diff --git a/src/Event/Event_Listener.cxx b/src/Event/Event_Listener.cxx new file mode 100644 index 000000000..44f907552 --- /dev/null +++ b/src/Event/Event_Listener.cxx @@ -0,0 +1,5 @@ +// File: Event_Listener.cxx +// Created: Thu Mar 13 2014 +// Author: Mikhail PONIKAROV + +#include \ No newline at end of file diff --git a/src/Event/Event_Listener.hxx b/src/Event/Event_Listener.hxx new file mode 100644 index 000000000..f5d70ba65 --- /dev/null +++ b/src/Event/Event_Listener.hxx @@ -0,0 +1,25 @@ +// File: Event_Listener.hxx +// Created: Thu Mar 13 2014 +// Author: Mikhail PONIKAROV + +#ifndef Event_Listener_HeaderFile +#define Event_Listener_HeaderFile + +#include +class Event_Message; + +/**\class Event_Listener + * \ingroup EventLoop + * \brief Base interface for any event listener. + * + * If some object wants to listen some events it must inherit + * this class and register in the Loop. + */ +EVENT_EXPORT class Event_Listener { + +public: + //! This method is called by loop when the event is started to process. + virtual void ProcessEvent(const Event_Message* theMessage) = 0; +}; + +#endif diff --git a/src/Event/Event_Loop.cxx b/src/Event/Event_Loop.cxx new file mode 100644 index 000000000..b1f22b50f --- /dev/null +++ b/src/Event/Event_Loop.cxx @@ -0,0 +1,80 @@ +// File: Event_Loop.hxx +// Created: Thu Mar 13 2014 +// Author: Mikhail PONIKAROV + +#include +#include + +using namespace std; + +Event_Loop* Event_Loop::Loop() +{ + // initialized on initialization of the application + static Event_Loop MAIN_LOOP; + return &MAIN_LOOP; +} + +Event_ID Event_Loop::EventByName(const char* theName) +{ + ///! All events created in this session, uniquely identified by the text and char pointer + static map CREATED_EVENTS; + char* aResult; + string aName(theName); + map::iterator aFound = CREATED_EVENTS.find(aName); + if (aFound == CREATED_EVENTS.end()) { //not created yet + aResult = strdup(theName); // copy to make unique internal pointer + CREATED_EVENTS[aName] = aResult; + } else + aResult = aFound->second; + + return Event_ID(aResult); +} + +void Event_Loop::Send(Event_Message theMessage) +{ + // TO DO: make it in thread and wit husage of semaphores + + map > >::iterator aFindID = + myListeners.find(theMessage.ID().EventText()); + if (aFindID != myListeners.end()) { + map >::iterator aFindSender = + aFindID->second.find(theMessage.Sender()); + if (aFindSender != aFindID->second.end()) { + list& aListeners = aFindSender->second; + for(list::iterator aL = aListeners.begin(); aL != aListeners.end(); aL++) + (*aL)->ProcessEvent(&theMessage); + } + if (theMessage.Sender()) { // also call for NULL senders registered + aFindSender = aFindID->second.find(NULL); + if (aFindSender != aFindID->second.end()) { + list& aListeners = aFindSender->second; + for(list::iterator aL = aListeners.begin(); aL != aListeners.end(); aL++) + (*aL)->ProcessEvent(&theMessage); + } + } + } +} + +void Event_Loop::RegisterListener( + Event_Listener* theListener, const Event_ID theID, void* theSender) +{ + map > >::iterator aFindID = + myListeners.find(theID.EventText()); + if (aFindID == myListeners.end()) { // create container associated with ID + myListeners[theID.EventText()] = map >(); + aFindID = myListeners.find(theID.EventText()); + } + + map >::iterator aFindSender = + aFindID->second.find(theSender); + if (aFindSender == aFindID->second.end()) { // create container associated with sender + aFindID->second[theSender] = list(); + aFindSender = aFindID->second.find(theSender); + } + // check that listener was not registered wit hsuch parameters before + list& aListeners = aFindSender->second; + for(list::iterator aL = aListeners.begin(); aL != aListeners.end(); aL++) + if (*aL == theListener) return; // avoid duplicates + + aListeners.push_back(theListener); +} diff --git a/src/Event/Event_Loop.hxx b/src/Event/Event_Loop.hxx new file mode 100644 index 000000000..7b6da9549 --- /dev/null +++ b/src/Event/Event_Loop.hxx @@ -0,0 +1,46 @@ +// File: Event_Loop.hxx +// Created: Thu Mar 13 2014 +// Author: Mikhail PONIKAROV + +#ifndef Event_Loop_HeaderFile +#define Event_Loop_HeaderFile + +#include +#include + +#include +#include + +/**\class Event_Lopp + * \ingroup EventLoop + * \brief Base class that manages the receiving and sending of all + * not Qt-events in the application. + * + * One per application, initialized on start. Listeners must register in this loop + * to get events, called by senders. Sending of events is very fast (just adding to container). + * Performing of events is processed in separated thread, so, sender takes + * control back immideately. + */ +class Event_Loop { + std::map > > + myListeners; ///< map from event ID to sender pointer to listeners that must be called for this + + //! The empty constructor, will be called at startup of the application, only once + Event_Loop() {}; +public: + ///! Returns the main object of the loop, one per application. + EVENT_EXPORT static Event_Loop* Loop(); + //! Returns the unique event by the given name. Call this method only on initialization of object + //! to speedup the events processing without parsing of the string. + EVENT_EXPORT static Event_ID EventByName(const char* theName); + + //! Allows to send an event + EVENT_EXPORT void Send(Event_Message theMessage); + + //! Registers (or adds if such listener is already registered) a listener + //! that will be called on the event and from the defined sender + EVENT_EXPORT void RegisterListener(Event_Listener* theListener, const Event_ID theID, + void* theSender = 0); +}; + +#endif diff --git a/src/Event/Event_Message.cxx b/src/Event/Event_Message.cxx new file mode 100644 index 000000000..02a018ef3 --- /dev/null +++ b/src/Event/Event_Message.cxx @@ -0,0 +1,5 @@ +// File: Event_Message.cxx +// Created: Thu Mar 13 2014 +// Author: Mikhail PONIKAROV + +#include diff --git a/src/Event/Event_Message.hxx b/src/Event/Event_Message.hxx new file mode 100644 index 000000000..b9abe11ce --- /dev/null +++ b/src/Event/Event_Message.hxx @@ -0,0 +1,54 @@ +// File: Event_Message.hxx +// Created: Thu Mar 13 2014 +// Author: Mikhail PONIKAROV + +#ifndef Event_Message_HeaderFile +#define Event_Message_HeaderFile + +#include + +/**\class Event_ID + * \ingroup EventLoop + * \brief Identifier of the event kind. + * + * Each event ID is created in main Envent_Loop class + * that stores correspondance between the string-name of the + * identifier and the pointer to the static string that is really + * used as an identifier (this is usefull for debugging of the events + * with log files and in debugger). + */ +EVENT_EXPORT class Event_ID { + char* myID; ///< pointer to the text-identifier of the event, unique pointer for all events of such type + + Event_ID(char* theID) {myID = theID;} + + friend class Event_Loop; +public: + /// Returns the text-identifier of the event (for debugging reasons) + char* EventText() const {return myID;} + /// Allows to compare identifiers + bool operator==(const Event_ID& theID) const {return myID == theID.myID;} +}; + +/**\class Event_Message + * \ingroup EventLoop + * \brief Message for communication between sender and listener of event. + * Normally it is inherited by the higher-level + */ +EVENT_EXPORT class Event_Message { + Event_ID myID; ///< identifier of the event + void* mySender; ///< the sender object + +public: + + //! Creates the message + Event_Message(const Event_ID theID, const void* theSender = 0); + + //! Returns identifier of the message + const Event_ID& ID() const {return myID;} + + //! Returns sender of the message or NULL if it is anonymous message + void* Sender() {return mySender;} +}; + +#endif