Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/modules/notifications/NotificationManager.cc @ 7474

Last change on this file since 7474 was 7474, checked in by dafrick, 14 years ago

Synchronizing Notifications.
In the course of that, notifications are not longer sent by creating a Notification and the calling notification.send() bur by letting the NotificationManager handle all this: NotificationManager::getInstance().sendNotification(message)
This made QuestNotification obsolete, thus it was removde.

Also did some work on synchronizing the Script class. It should work properly most of the time, but the current solution is unreliable and unsatisfactory. So this will change as soon as I know how.

  • Property svn:eol-style set to native
File size: 14.9 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Damian 'Mozork' Frick
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @file NotificationManager.cc
31    @brief Implementation of the NotificationManager class.
32*/
33
34#include "NotificationManager.h"
35
36#include "core/command/ConsoleCommand.h"
37#include "core/CoreIncludes.h"
38#include "core/GUIManager.h"
39#include "core/LuaState.h"
40#include "network/Host.h"
41#include "network/NetworkFunction.h"
42#include "util/ScopedSingletonManager.h"
43
44#include "interfaces/NotificationListener.h"
45
46#include "Notification.h"
47#include "NotificationQueue.h"
48
49#include "ToluaBindNotifications.h"
50
51namespace orxonox
52{
53
54    const std::string NotificationManager::ALL("all");
55    const std::string NotificationManager::NONE("none");
56
57    // Register tolua_open function when loading the library.
58    DeclareToluaInterface(Notifications);
59
60    ManageScopedSingleton(NotificationManager, ScopeID::Graphics, false);
61
62    SetConsoleCommand("enterEditMode", &NotificationManager::enterEditMode);
63
64    registerStaticNetworkFunction(NotificationManager::sendNotification);
65
66    /**
67    @brief
68        Constructor. Registers the Object.
69    */
70    NotificationManager::NotificationManager()
71    {
72        RegisterRootObject(NotificationManager);
73
74        this->highestIndex_ = 0;
75
76        ModifyConsoleCommand("enterEditMode").setObject(this);
77
78        COUT(3) << "NotificatioManager created." << std::endl;
79    }
80
81    /**
82    @brief
83        Destructor.
84    */
85    NotificationManager::~NotificationManager()
86    {
87        ModifyConsoleCommand("enterEditMode").setObject(NULL);
88
89        COUT(3) << "NotificationManager destroyed." << std::endl;
90    }
91
92    /**
93    @brief
94        Is called before the object is destroyed.
95    */
96    void NotificationManager::preDestroy(void)
97    {
98        // Destroys all NotificationQueues that have been registered with the NotificationManager.
99        for(std::map<const std::string, NotificationQueue*>::iterator it = this->queues_.begin(); it != this->queues_.end(); )
100        {
101            NotificationQueue* queue = (*it).second;
102            it++;
103            queue->destroy();
104        }
105        this->queues_.clear();
106    }
107
108    /*static*/ void NotificationManager::sendNotification(const std::string& message, unsigned int clientId, const std::string& sender)
109    {
110        if(GameMode::isStandalone() || Host::getPlayerID() == clientId)
111        {
112            Notification* notification = new Notification(message);
113            notification->send(sender);
114        }
115        else if(GameMode::isServer())
116        {
117            callStaticNetworkFunction(NotificationManager::sendNotification, clientId, message, clientId, sender);
118        }
119    }
120
121    /**
122    @brief
123        Registers a Notification within the NotificationManager and makes sure that the Notification is sent to all the NotificationListeners associated with its sender.
124    @param notification
125        The Notification to be registered.
126    @return
127        Returns true if successful.
128    */
129    bool NotificationManager::registerNotification(Notification* notification)
130    {
131        assert(notification);
132
133        std::time_t time = std::time(0); //TODO: Doesn't this expire? //!< Get current time.
134
135        // Add the Notification to the list that holds all Notifications.
136        this->allNotificationsList_.insert(std::pair<std::time_t, Notification*>(time, notification));
137
138        if(notification->getSender() == NotificationManager::NONE) // If the sender has no specific name, then the Notification is only added to the list of all Notifications.
139            return true;
140
141        bool all = false;
142        if(notification->getSender() == NotificationManager::ALL) // If all are the sender, then the Notifications is added to every NotificationListener.
143            all = true;
144
145        // Insert the Notification in all NotificationListeners that have its sender as target.
146        for(std::map<NotificationListener*, unsigned int>::iterator it = this->listenerList_.begin(); it != this->listenerList_.end(); it++) // Iterate through all NotificationListeners.
147        {
148            const std::set<std::string>& set = it->first->getTargetsSet();
149            bool bAll = set.find(NotificationManager::ALL) != set.end();
150            // If either the Notification has as sender 'all', the NotificationListener displays all Notifications or the NotificationListener has the sender of the Notification as target.
151            if(all || bAll || set.find(notification->getSender()) != set.end())
152            {
153                if(!bAll)
154                    this->notificationLists_[it->second]->insert(std::pair<std::time_t, Notification*>(time, notification)); // Insert the Notification in the notifications list of the current NotificationListener.
155                it->first->update(notification, time); // Update the NotificationListener.
156            }
157        }
158
159        COUT(4) << "Notification (&" << notification << ") registered with the NotificationManager." << std::endl;
160
161        return true;
162    }
163
164    /**
165    @brief
166        Unregisters a Notification within the NotificationManager for a given NotificationListener.
167    @param notification
168        A pointer to the Notification to be unregistered.
169    @param listener
170        A pointer to the NotificationListener the Notification is unregistered for.
171    */
172    void NotificationManager::unregisterNotification(Notification* notification, NotificationListener* listener)
173    {
174        assert(notification);
175        assert(listener);
176
177        // Remove the Notification from the list of Notifications of the input NotificationListener.
178        this->removeNotification(notification, *(this->notificationLists_.find(this->listenerList_.find(listener)->second)->second));
179
180        COUT(4) << "Notification (&" << notification << ") unregistered with the NotificationManager from listener (&" << listener << ")" << std::endl;
181    }
182
183    /**
184    @brief
185        Helper method that removes an input Notification form an input map.
186    @param notification
187        A pointer to the Notification to be removed.
188    @param map
189        The map the Notification should be removed from.
190    @return
191        Returns true if successful.
192    */
193    bool NotificationManager::removeNotification(Notification* notification, std::multimap<std::time_t, Notification*>& map)
194    {
195        // Iterates through all items in the map until the Notification is found.
196        //TODO: Do more efficiently?
197        for(std::multimap<std::time_t, Notification*>::iterator it = map.begin(); it != map.end(); it++)
198        {
199            if(it->second == notification)
200            {
201                map.erase(it);
202                return true;
203            }
204        }
205        return false;
206    }
207
208    /**
209    @brief
210        Registers a NotificationListener within the NotificationManager.
211    @param listener
212        The NotificationListener to be registered.
213    @return
214        Returns true if successful.  Fales if the NotificationListener is already registered.
215    */
216    bool NotificationManager::registerListener(NotificationListener* listener)
217    {
218        assert(listener);
219
220        // If the NotificationListener is already registered.
221        if(this->listenerList_.find(listener) != this->listenerList_.end())
222            return false;
223
224        this->highestIndex_ += 1;
225        unsigned int index = this->highestIndex_; // An identifier that identifies each registered NotificationListener uniquely.
226
227        this->listenerList_[listener] = index; // Add the NotificationListener to the list of NotificationListeners.
228
229        const std::set<std::string>& set = listener->getTargetsSet();
230
231        // If all senders are the target of the NotificationListener, then the list of Notifications for that specific NotificationListener is the same as the list of all Notifications.
232        bool bAll = set.find(NotificationManager::ALL) != set.end();
233        std::multimap<std::time_t, Notification*>* map;
234        if(bAll)
235            this->notificationLists_[index] = &this->allNotificationsList_;
236        // Else a new list (resp. multimap) is created and added to the list of Notification lists for NotificationListeners.
237        else
238        {
239            this->notificationLists_[index] = new std::multimap<std::time_t, Notification*>;
240            map = this->notificationLists_[index];
241        }
242
243        // Iterate through all Notifications to determine whether any of them should belong to the newly registered NotificationListener.
244        for(std::multimap<std::time_t, Notification*>::iterator it = this->allNotificationsList_.begin(); it != this->allNotificationsList_.end(); it++)
245        {
246            if(!bAll && set.find(it->second->getSender()) != set.end()) // Checks whether the listener has the sender of the current Notification as target.
247                map->insert(std::pair<std::time_t, Notification*>(it->first, it->second));
248        }
249
250        listener->update(); // Update the listener.
251
252        COUT(4) << "NotificationListener registered with the NotificationManager." << std::endl;
253
254        return true;
255    }
256
257    /**
258    @brief
259        Unregisters a NotificationListener within the NotificationManager.
260    @param listener
261        The NotificationListener to be unregistered.
262    */
263    void NotificationManager::unregisterListener(NotificationListener* listener)
264    {
265        assert(listener);
266
267        unsigned int identifier = this->listenerList_.find(listener)->second;
268        std::multimap<std::time_t, Notification*>* map = this->notificationLists_.find(identifier)->second;
269
270        // If the map is not the map of all Notifications, make sure all Notifications are unregistered.
271        std::multimap<std::time_t, Notification*>::iterator it = map->begin();
272        if(map != &this->allNotificationsList_)
273        {
274            while(it != map->end())
275            {
276                this->unregisterNotification(it->second, listener);
277                it = map->begin();
278            }
279            delete map;
280        }
281
282        // Remove the NotificationListener from the list of NotificationListeners.
283        this->listenerList_.erase(listener);
284        // Remove the Notifications list that was associated with the input NotificationListener.
285        this->notificationLists_.erase(identifier);
286
287        COUT(4) << "NotificationListener unregistered with the NotificationManager." << std::endl;
288    }
289
290    /**
291    @brief
292        Fetches the Notifications for a specific NotificationListener in a specified timeframe and stores them in the input map.
293    @param listener
294        The NotificationListener the Notifications are fetched for.
295    @param map
296        A pointer to a multimap, in which the notifications are stored. The map needs to have been allocated.
297    @param timeFrameStart
298        The start time of the timeframe.
299    @param timeFrameEnd
300        The end time of the timeframe.
301    @return
302        Returns true if successful.
303    */
304    void NotificationManager::getNotifications(NotificationListener* listener, std::multimap<std::time_t,Notification*>* map, const std::time_t & timeFrameStart, const std::time_t & timeFrameEnd)
305    {
306        assert(listener);
307        assert(map);
308
309        std::multimap<std::time_t, Notification*>* notifications = this->notificationLists_[this->listenerList_[listener]]; // All the Notifications for the input NotificationListener.
310
311        std::multimap<std::time_t,Notification*>::iterator it, itLowest, itHighest;
312        // Iterators pointing to the bounds specified by the specified start and end times of the time frame.
313        itLowest = notifications->lower_bound(timeFrameStart);
314        itHighest = notifications->upper_bound(timeFrameEnd);
315
316        for(it = itLowest; it != itHighest; it++) // Iterate through the Notifications from the start of the time frame to the end of it.
317            map->insert(std::pair<std::time_t, Notification*>(it->first, it->second)); // Add the found Notifications to the map.
318    }
319
320    /**
321    @brief
322        Enters the edit mode of the NotificationLayer.
323    */
324    void NotificationManager::enterEditMode(void)
325    {
326        GUIManager::getInstance().hideGUI("NotificationLayer");
327        GUIManager::getInstance().showGUI("NotificationLayer", false, false);
328        GUIManager::getInstance().getLuaState()->doString("NotificationLayer.enterEditMode()");
329    }
330
331    /**
332    @brief
333        Registers a NotificationQueue.
334        This makes sure that the NotificationQueue can be attained through lua by name. It also makes sure that the NotificationQueue is destroyed upon destruction of the NotificationManager.
335    @param queue
336        A pointer to the NotificationQueue to be registered.
337    @return
338        Returns true if successful. If e.g. the a NotificationQueue with that name already exists this returns false.
339    */
340    bool NotificationManager::registerQueue(NotificationQueue* queue)
341    {
342        return this->queues_.insert(std::pair<const std::string, NotificationQueue*>(queue->getName(), queue)).second;
343    }
344
345    /**
346    @brief
347        Unregisters a NotificationQueue.
348    @param queue
349        A pointer to the NotificationQueue to be unregistered.
350    */
351    void NotificationManager::unregisterQueue(NotificationQueue* queue)
352    {
353        this->queues_.erase(queue->getName());
354    }
355
356    /**
357    @brief
358        Loads all the NotificationQueues that should exist.
359    */
360    void NotificationManager::loadQueues(void)
361    {
362        new NotificationQueue("all");
363    }
364
365    /**
366    @brief
367        Creates a new NotificationQueue.
368        This is used in lua.
369    @param name
370        The name of the new NotificationQueue.
371    */
372    void NotificationManager::createQueue(const std::string& name)
373    {
374        new NotificationQueue(name);
375    }
376
377    /**
378    @brief
379        Get the NotificationQueue with the input name.
380    @param name
381        The name of the NotificationQueue.
382    @return
383        Returns a pointer to the NotificationQueue with the input name. Returns NULL if no NotificationQueue with such a name exists.
384    */
385    NotificationQueue* NotificationManager::getQueue(const std::string & name)
386    {
387        std::map<const std::string, NotificationQueue*>::iterator it = this->queues_.find(name);
388        // Returns NULL if no such NotificationQueue exists.
389        if(it == this->queues_.end())
390            return NULL;
391
392        return (*it).second;
393    }
394
395}
Note: See TracBrowser for help on using the repository browser.