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