Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/tutoriallevel2/src/modules/notifications/NotificationManager.cc @ 8371

Last change on this file since 8371 was 8371, checked in by dafrick, 13 years ago

Merging tutoriallevel branch into tutoriallevel2 branch.

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