Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Resolving some TODOs and doing some additional cleanup. Almost done now…

  • Property svn:eol-style set to native
File size: 16.1 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::Root, false);
61
62    // Setting console command to enter the edit mode.
63    SetConsoleCommand("enterEditMode", &NotificationManager::enterEditMode);
64
65    registerStaticNetworkFunction(NotificationManager::sendNotification);
66
67    /**
68    @brief
69        Constructor. Registers the Object.
70    */
71    NotificationManager::NotificationManager()
72    {
73        RegisterRootObject(NotificationManager);
74
75        this->highestIndex_ = 0;
76
77        ModifyConsoleCommand("enterEditMode").setObject(this);
78
79        COUT(3) << "NotificatioManager created." << std::endl;
80    }
81
82    /**
83    @brief
84        Destructor.
85    */
86    NotificationManager::~NotificationManager()
87    {
88        ModifyConsoleCommand("enterEditMode").setObject(NULL);
89
90        // Destroys all Notifications.
91        for(std::multimap<std::time_t, Notification*>::iterator it = this->allNotificationsList_.begin(); it!= this->allNotificationsList_.end(); it++)
92            it->second->destroy();
93        this->allNotificationsList_.clear();
94
95        COUT(3) << "NotificationManager destroyed." << std::endl;
96    }
97
98    /**
99    @brief
100        Is called before the object is destroyed.
101    */
102    void NotificationManager::preDestroy(void)
103    {
104        // Destroys all NotificationQueues that have been registered with the NotificationManager.
105        for(std::map<const std::string, NotificationQueue*>::iterator it = this->queues_.begin(); it != this->queues_.end(); it++)
106            it->second->destroy(true);
107
108        this->queues_.clear();
109    }
110
111    /**
112    @brief
113        Sends a Notification with the specified message to the specified client from the specified sender.
114    @param message
115        The message that should be sent.
116    @param clientId
117        The id of the client the notification should be sent to.
118    @param sender
119        The sender that sent the notification.
120    @param isLocal
121        If this is set to true (false is default), then the Notification is sent to the client where this function is executed, meaning the Notification is sent locally.
122    */
123    /*static*/ void NotificationManager::sendNotification(const std::string& message, unsigned int clientId, const std::string& sender, bool isLocal)
124    {
125        // If we're in standalone mode or we're already no the right client we create and send the Notification.
126        if(GameMode::isStandalone() || isLocal || Host::getPlayerID() == clientId)
127        {
128            Notification* notification = new Notification(message, sender);
129            if(NotificationManager::getInstance().registerNotification(notification))
130                COUT(3) << "Notification \"" << notification->getMessage() << "\" sent." << std::endl;
131        }
132        // If we're on the server (and the server is not the intended recipient of the Notification) we send it over the network.
133        else if(GameMode::isServer())
134        {
135            callStaticNetworkFunction(NotificationManager::sendNotification, clientId, message, clientId, sender);
136        }
137    }
138
139    /**
140    @brief
141        Registers a Notification within the NotificationManager and makes sure that the Notification is sent to all the NotificationListeners associated with its sender.
142    @param notification
143        The Notification to be registered.
144    @return
145        Returns true if successful.
146    */
147    bool NotificationManager::registerNotification(Notification* notification)
148    {
149        assert(notification);
150
151        std::time_t time = std::time(0); // Get current time.
152
153        // Add the Notification to the list that holds all Notifications.
154        this->allNotificationsList_.insert(std::pair<std::time_t, Notification*>(time, notification));
155
156        if(notification->getSender() == NotificationManager::NONE) // If the sender has no specific name, then the Notification is only added to the list of all Notifications.
157            return true;
158
159        bool all = false;
160        if(notification->getSender() == NotificationManager::ALL) // If all are the sender, then the Notifications is added to every NotificationListener.
161            all = true;
162
163        // Insert the Notification in all NotificationListeners that have its sender as target.
164        for(std::map<NotificationListener*, unsigned int>::iterator it = this->listenerList_.begin(); it != this->listenerList_.end(); it++) // Iterate through all NotificationListeners.
165        {
166            const std::set<std::string>& set = it->first->getTargetsSet();
167            bool bAll = set.find(NotificationManager::ALL) != set.end();
168            // If either the Notification has as sender 'all', the NotificationListener displays all Notifications or the NotificationListener has the sender of the Notification as target.
169            if(all || bAll || set.find(notification->getSender()) != set.end())
170            {
171                if(!bAll)
172                    this->notificationLists_[it->second]->insert(std::pair<std::time_t, Notification*>(time, notification)); // Insert the Notification in the notifications list of the current NotificationListener.
173                it->first->update(notification, time); // Update the NotificationListener.
174            }
175        }
176
177        COUT(4) << "Notification (&" << notification << ") registered with the NotificationManager." << std::endl;
178
179        return true;
180    }
181
182    /**
183    @brief
184        Unregisters a Notification within the NotificationManager for a given NotificationListener.
185    @param notification
186        A pointer to the Notification to be unregistered.
187    @param listener
188        A pointer to the NotificationListener the Notification is unregistered for.
189    */
190    void NotificationManager::unregisterNotification(Notification* notification, NotificationListener* listener)
191    {
192        assert(notification);
193        assert(listener);
194
195        // Remove the Notification from the list of Notifications of the input NotificationListener.
196        this->removeNotification(notification, *(this->notificationLists_.find(this->listenerList_.find(listener)->second)->second));
197
198        COUT(4) << "Notification (&" << notification << ") unregistered with the NotificationManager from listener (&" << listener << ")" << std::endl;
199    }
200
201    /**
202    @brief
203        Helper method that removes an input Notification form an input map.
204    @param notification
205        A pointer to the Notification to be removed.
206    @param map
207        The map the Notification should be removed from.
208    @return
209        Returns true if successful.
210    */
211    bool NotificationManager::removeNotification(Notification* notification, std::multimap<std::time_t, Notification*>& map)
212    {
213        // Iterates through all items in the map until the Notification is found.
214        //TODO: Do more efficiently?
215        for(std::multimap<std::time_t, Notification*>::iterator it = map.begin(); it != map.end(); it++)
216        {
217            if(it->second == notification)
218            {
219                map.erase(it);
220                return true;
221            }
222        }
223        return false;
224    }
225
226    /**
227    @brief
228        Registers a NotificationListener within the NotificationManager.
229    @param listener
230        The NotificationListener to be registered.
231    @return
232        Returns true if successful.  Fales if the NotificationListener is already registered.
233    */
234    bool NotificationManager::registerListener(NotificationListener* listener)
235    {
236        assert(listener);
237
238        // If the NotificationListener is already registered.
239        if(this->listenerList_.find(listener) != this->listenerList_.end())
240            return false;
241
242        this->highestIndex_ += 1;
243        unsigned int index = this->highestIndex_; // An identifier that identifies each registered NotificationListener uniquely.
244
245        this->listenerList_[listener] = index; // Add the NotificationListener to the list of NotificationListeners.
246
247        const std::set<std::string>& set = listener->getTargetsSet();
248
249        // 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.
250        bool bAll = set.find(NotificationManager::ALL) != set.end();
251        std::multimap<std::time_t, Notification*>* map = NULL;
252        if(bAll)
253            this->notificationLists_[index] = &this->allNotificationsList_;
254        // Else a new list (resp. multimap) is created and added to the list of Notification lists for NotificationListeners.
255        else
256        {
257            this->notificationLists_[index] = new std::multimap<std::time_t, Notification*>;
258            map = this->notificationLists_[index];
259        }
260
261        // Iterate through all Notifications to determine whether any of them should belong to the newly registered NotificationListener.
262        for(std::multimap<std::time_t, Notification*>::iterator it = this->allNotificationsList_.begin(); it != this->allNotificationsList_.end(); it++)
263        {
264            if(!bAll && set.find(it->second->getSender()) != set.end()) // Checks whether the listener has the sender of the current Notification as target.
265                map->insert(std::pair<std::time_t, Notification*>(it->first, it->second));
266        }
267
268        listener->update(); // Update the listener.
269
270        COUT(4) << "NotificationListener registered with the NotificationManager." << std::endl;
271
272        return true;
273    }
274
275    /**
276    @brief
277        Unregisters a NotificationListener within the NotificationManager.
278    @param listener
279        The NotificationListener to be unregistered.
280    */
281    void NotificationManager::unregisterListener(NotificationListener* listener)
282    {
283        assert(listener);
284
285        unsigned int identifier = this->listenerList_.find(listener)->second;
286        std::multimap<std::time_t, Notification*>* map = this->notificationLists_.find(identifier)->second;
287
288        // If the map is not the map of all Notifications, make sure all Notifications are unregistered.
289        std::multimap<std::time_t, Notification*>::iterator it = map->begin();
290        if(map != &this->allNotificationsList_)
291        {
292            while(it != map->end())
293            {
294                this->unregisterNotification(it->second, listener);
295                it = map->begin();
296            }
297            delete map;
298        }
299
300        // Remove the NotificationListener from the list of NotificationListeners.
301        this->listenerList_.erase(listener);
302        // Remove the Notifications list that was associated with the input NotificationListener.
303        this->notificationLists_.erase(identifier);
304
305        COUT(4) << "NotificationListener unregistered with the NotificationManager." << std::endl;
306    }
307
308    /**
309    @brief
310        Fetches the Notifications for a specific NotificationListener in a specified timeframe and stores them in the input map.
311    @param listener
312        The NotificationListener the Notifications are fetched for.
313    @param map
314        A pointer to a multimap, in which the notifications are stored. The map needs to have been allocated.
315    @param timeFrameStart
316        The start time of the timeframe.
317    @param timeFrameEnd
318        The end time of the timeframe.
319    @return
320        Returns true if successful.
321    */
322    void NotificationManager::getNotifications(NotificationListener* listener, std::multimap<std::time_t,Notification*>* map, const std::time_t & timeFrameStart, const std::time_t & timeFrameEnd)
323    {
324        assert(listener);
325        assert(map);
326
327        std::multimap<std::time_t, Notification*>* notifications = this->notificationLists_[this->listenerList_[listener]]; // All the Notifications for the input NotificationListener.
328
329        std::multimap<std::time_t,Notification*>::iterator it, itLowest, itHighest;
330        // Iterators pointing to the bounds specified by the specified start and end times of the time frame.
331        itLowest = notifications->lower_bound(timeFrameStart);
332        itHighest = notifications->upper_bound(timeFrameEnd);
333
334        for(it = itLowest; it != itHighest; it++) // Iterate through the Notifications from the start of the time frame to the end of it.
335            map->insert(std::pair<std::time_t, Notification*>(it->first, it->second)); // Add the found Notifications to the map.
336    }
337
338    /**
339    @brief
340        Enters the edit mode of the NotificationLayer.
341    */
342    void NotificationManager::enterEditMode(void)
343    {
344        if(GameMode::showsGraphics())
345        {
346            GUIManager::getInstance().hideGUI("NotificationLayer");
347            GUIManager::getInstance().showGUI("NotificationLayer", false, false);
348            GUIManager::getInstance().getLuaState()->doString("NotificationLayer.enterEditMode()");
349        }
350    }
351
352    /**
353    @brief
354        Registers a NotificationQueue.
355        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.
356    @param queue
357        A pointer to the NotificationQueue to be registered.
358    @return
359        Returns true if successful. If e.g. the a NotificationQueue with that name already exists this returns false.
360    */
361    bool NotificationManager::registerQueue(NotificationQueue* queue)
362    {
363        return this->queues_.insert(std::pair<const std::string, NotificationQueue*>(queue->getName(), queue)).second;
364    }
365
366    /**
367    @brief
368        Unregisters a NotificationQueue.
369    @param queue
370        A pointer to the NotificationQueue to be unregistered.
371    */
372    void NotificationManager::unregisterQueue(NotificationQueue* queue)
373    {
374        this->queues_.erase(queue->getName());
375    }
376
377    /**
378    @brief
379        Loads all the NotificationQueues that should exist.
380    */
381    void NotificationManager::loadQueues(void)
382    {
383        new NotificationQueue("all");
384    }
385
386    /**
387    @brief
388        Creates a new NotificationQueue.
389        This is used in lua.
390    @param name
391        The name of the new NotificationQueue.
392    */
393    void NotificationManager::createQueue(const std::string& name)
394    {
395        new NotificationQueue(name);
396    }
397
398    /**
399    @brief
400        Get the NotificationQueue with the input name.
401    @param name
402        The name of the NotificationQueue.
403    @return
404        Returns a pointer to the NotificationQueue with the input name. Returns NULL if no NotificationQueue with such a name exists.
405    */
406    NotificationQueue* NotificationManager::getQueue(const std::string & name)
407    {
408        std::map<const std::string, NotificationQueue*>::iterator it = this->queues_.find(name);
409        // Returns NULL if no such NotificationQueue exists.
410        if(it == this->queues_.end())
411            return NULL;
412
413        return (*it).second;
414    }
415
416}
Note: See TracBrowser for help on using the repository browser.