Salome HOME
Allow arc parameters to be recalculated by sketch solver
[modules/shaper.git] / src / Events / Events_Loop.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        Events_Loop.hxx
4 // Created:     Thu Mar 13 2014
5 // Author:      Mikhail PONIKAROV
6
7 #include <Events_Loop.h>
8 #include <Events_MessageGroup.h>
9
10 #include <string>
11 #include <cstring>
12
13 Events_Loop* Events_Loop::loop()
14 {
15   // initialized on initialization of the application
16   static Events_Loop MAIN_LOOP;
17   return &MAIN_LOOP;
18 }
19
20 Events_ID Events_Loop::eventByName(const char* theName)
21 {
22   ///! All events created in this session, uniquely identified by the text and char pointer
23   static std::map<std::string, char*> CREATED_EVENTS;
24   char* aResult;
25   std::string aName(theName);
26   std::map<std::string, char*>::iterator aFound = CREATED_EVENTS.find(aName);
27   if (aFound == CREATED_EVENTS.end()) {  //not created yet
28 #ifdef WIN32
29     aResult = _strdup(theName);  // copy to make unique internal pointer
30 #else
31     aResult = strdup(theName);  // copy to make unique internal pointer
32 #endif
33     CREATED_EVENTS[aName] = aResult;
34   } else
35     aResult = aFound->second;
36
37   return Events_ID(aResult);
38 }
39
40 void Events_Loop::sendProcessEvent(const std::shared_ptr<Events_Message>& theMessage,
41   std::list<Events_Listener*>& theListeners, const bool theFlushedNow)
42 {
43   std::list<Events_Listener*>::iterator aL = theListeners.begin();
44   for (; aL != theListeners.end(); aL++) {
45     if (theFlushedNow && (*aL)->groupMessages()) {
46       (*aL)->groupWhileFlush(theMessage);
47     } else {
48       (*aL)->processEvent(theMessage);
49     }
50   }
51 }
52
53 void Events_Loop::send(const std::shared_ptr<Events_Message>& theMessage, bool isGroup)
54 {
55   if (myImmediateListeners.find(theMessage->eventID().eventText()) != myImmediateListeners.end()) {
56     myImmediateListeners[theMessage->eventID().eventText()]->processEvent(theMessage);
57   }
58   // if it is grouped message, just accumulate it
59   bool isFlushedNow = myFlushed.find(theMessage->eventID().myID) != myFlushed.end();
60   if (isGroup && !isFlushedNow) {
61     std::shared_ptr<Events_MessageGroup> aGroup =
62       std::dynamic_pointer_cast<Events_MessageGroup>(theMessage);
63     if (aGroup) {
64       std::map<char*, std::shared_ptr<Events_Message> >::iterator aMyGroup = myGroups.find(
65           aGroup->eventID().eventText());
66       if (aMyGroup == myGroups.end()) {  // create a new group of messages for accumulation
67         myGroups[aGroup->eventID().eventText()] = aGroup->newEmpty();
68         aMyGroup = myGroups.find(aGroup->eventID().eventText());
69       }
70       std::shared_ptr<Events_MessageGroup> aStored =
71         std::dynamic_pointer_cast<Events_MessageGroup>(aMyGroup->second);
72       aStored->Join(aGroup);
73       return;
74     }
75   }
76   // send
77   std::map<char*, std::map<void*, std::list<Events_Listener*> > >::iterator aFindID =
78     myListeners.find(theMessage->eventID().eventText());
79   if (aFindID != myListeners.end()) {
80     std::map<void*, std::list<Events_Listener*> >::iterator aFindSender = aFindID->second.find(
81         theMessage->sender());
82     if (aFindSender != aFindID->second.end()) {
83       sendProcessEvent(theMessage, aFindSender->second, isFlushedNow && isGroup);
84     }
85     if (theMessage->sender()) {  // also call for NULL senders registered
86       aFindSender = aFindID->second.find(NULL);
87       if (aFindSender != aFindID->second.end()) {
88         sendProcessEvent(theMessage, aFindSender->second, isFlushedNow && isGroup);
89       }
90     }
91   }
92 }
93
94 void Events_Loop::registerListener(Events_Listener* theListener, const Events_ID theID,
95                                    void* theSender, bool theImmediate)
96 {
97   if (theImmediate) { // just register as an immediate
98     myImmediateListeners[theID.eventText()] = theListener;
99     return;
100   }
101   std::map<char*, std::map<void*, std::list<Events_Listener*> > >::iterator aFindID =
102     myListeners.find(theID.eventText());
103   if (aFindID == myListeners.end()) {  // create container associated with ID
104     myListeners[theID.eventText()] = std::map<void*, std::list<Events_Listener*> >();
105     aFindID = myListeners.find(theID.eventText());
106   }
107
108   std::map<void*, std::list<Events_Listener*> >::iterator aFindSender =
109     aFindID->second.find(theSender);
110   if (aFindSender == aFindID->second.end()) {  // create container associated with sender
111     aFindID->second[theSender] = std::list<Events_Listener*>();
112     aFindSender = aFindID->second.find(theSender);
113   }
114   // check that listener was not registered wit hsuch parameters before
115   std::list<Events_Listener*>& aListeners = aFindSender->second;
116   for (std::list<Events_Listener*>::iterator aL = aListeners.begin(); aL != aListeners.end(); aL++)
117     if (*aL == theListener)
118       return;  // avoid duplicates
119
120   aListeners.push_back(theListener);
121 }
122
123 void Events_Loop::removeListener(Events_Listener* theListener)
124 {
125   // remove the listener in myListeners map
126   std::map<char*, std::map<void*, std::list<Events_Listener*> > >::const_reverse_iterator
127                                                           anIt = myListeners.rbegin();
128   while(anIt != myListeners.rend()) {
129     std::map<void*, std::list<Events_Listener*> > aLMap = anIt->second;
130     std::map<void*, std::list<Events_Listener*> >::const_reverse_iterator aLIt = aLMap.rbegin();
131     while (aLIt != aLMap.rend()) {
132       std::list<Events_Listener*> aListeners = aLIt->second;
133       std::list<Events_Listener*>::const_reverse_iterator aLsIt = aListeners.rbegin();
134       for (; aLsIt != aListeners.rend(); aLsIt++) {
135         if (*aLsIt == theListener) {
136           aListeners.remove(theListener);
137           aLMap[aLIt->first] = aListeners;
138           myListeners[anIt->first] = aLMap;
139           break;
140         }
141       }
142       if (aListeners.empty()) {
143         aLMap.erase(aLIt->first);
144         myListeners[anIt->first] = aLMap;
145         if (aLMap.empty())
146           break; // avoid incrementation of the iterator if the the container is empty
147       }
148       aLIt++;
149     }
150     if (anIt->second.empty()) {
151       myListeners.erase(anIt->first);
152       if (myListeners.empty())
153         break; // avoid incrementation of the iterator if the the container is empty
154     }
155     anIt++;
156   }
157
158   // remove the listener in myImmediateListeners map
159   std::map<char*, Events_Listener*>::const_reverse_iterator anImIt = myImmediateListeners.rbegin();
160   while(anImIt != myImmediateListeners.rend()) {
161     if (anImIt->second == theListener) {
162       myImmediateListeners.erase(anImIt->first);
163       if (myImmediateListeners.empty())
164         break; // avoid incrementation of the iterator if the the container is empty
165     }
166     anImIt++;
167   }
168 }
169
170 void Events_Loop::flush(const Events_ID& theID)
171 {
172   if (!myFlushActive)
173     return;
174   bool hasEventsToFlush = !myGroups.empty();
175   std::map<char*, std::shared_ptr<Events_Message> >::iterator aMyGroup;
176   for(aMyGroup = myGroups.find(theID.eventText());
177     aMyGroup != myGroups.end(); aMyGroup = myGroups.find(theID.eventText()))
178   {  // really sends
179     bool aWasFlushed = myFlushed.find(theID.myID) != myFlushed.end();
180     if (!aWasFlushed)
181       myFlushed.insert(theID.myID);
182     std::shared_ptr<Events_Message> aGroup = aMyGroup->second;
183     myGroups.erase(aMyGroup);
184     send(aGroup, false);
185
186     if (!aWasFlushed) {
187       // TODO: Stabilization fix. Check later.
188       if(myFlushed.find(theID.myID) != myFlushed.end()) {
189         myFlushed.erase(myFlushed.find(theID.myID));
190       } else {
191         bool aProblem = true;
192       }
193     }
194     // send accumulated messages to "groupListeners"
195     std::map<char*, std::map<void*, std::list<Events_Listener*> > >::iterator aFindID =
196       myListeners.find(theID.eventText());
197     if (aFindID != myListeners.end()) {
198       std::map<void*, std::list<Events_Listener*> >::iterator aFindSender =
199         aFindID->second.begin();
200       for(; aFindSender != aFindID->second.end(); aFindSender++) {
201         std::list<Events_Listener*>::iterator aListener = aFindSender->second.begin();
202         for(; aListener != aFindSender->second.end(); aListener++) {
203           if ((*aListener)->groupMessages()) {
204             (*aListener)->flushGrouped(theID);
205           }
206         }
207       }
208     }
209   }
210   if (hasEventsToFlush && myGroups.empty()) {
211     // no more messages left in the queue, so, finalize the sketch processing
212     static Events_ID anID = Events_Loop::eventByName("SketchPrepared");
213     std::shared_ptr<Events_Message> aMsg(new Events_Message(anID, this));
214     Events_Loop::loop()->send(aMsg, false);
215   }
216 }
217
218 void Events_Loop::eraseMessages(const Events_ID& theID)
219 {
220   std::map<char*, std::shared_ptr<Events_Message> >::iterator aMyGroup =
221     myGroups.find(theID.eventText());
222   if (aMyGroup != myGroups.end()) {
223     myGroups.erase(aMyGroup);
224   }
225 }
226
227
228 bool Events_Loop::activateFlushes(const bool theActivate)
229 {
230   bool isActive = myFlushActive;
231   myFlushActive = theActivate;
232   return isActive;
233 }
234
235 void Events_Loop::clear(const Events_ID& theID)
236 {
237   std::map<char*, std::shared_ptr<Events_Message>>::iterator aMyGroup =
238     myGroups.find(theID.eventText());
239   if (aMyGroup != myGroups.end()) {  // really sends
240     myGroups.erase(aMyGroup);
241   }
242 }
243
244 void Events_Loop::autoFlush(const Events_ID& theID, const bool theAuto)
245 {
246   if (theAuto)
247     myFlushed.insert(theID.myID);
248   else
249     myFlushed.erase(myFlushed.find(theID.myID));
250 }
251
252 bool Events_Loop::isFlushed(const Events_ID& theID)
253 {
254   return myFlushed.find(theID.myID) != myFlushed.end();
255 }
256
257 void Events_Loop::setFlushed(const Events_ID& theID, const bool theValue)
258 {
259   if (theValue)
260     myFlushed.insert(theID.myID);
261   else
262     myFlushed.erase(myFlushed.find(theID.myID));
263 }