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, 14 years ago

Merging tutoriallevel branch into tutoriallevel2 branch.

  • Property svn:eol-style set to native
File size: 18.7 KB
RevLine 
[2280]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
[2911]29/**
[7403]30    @file NotificationManager.cc
[2911]31    @brief Implementation of the NotificationManager class.
32*/
33
[2280]34#include "NotificationManager.h"
35
[7403]36#include "core/command/ConsoleCommand.h"
37#include "core/CoreIncludes.h"
38#include "core/GUIManager.h"
39#include "core/LuaState.h"
[7474]40#include "network/Host.h"
41#include "network/NetworkFunction.h"
[8371]42#include "util/Convert.h"
[7403]43#include "util/ScopedSingletonManager.h"
[2911]44
[5619]45#include "interfaces/NotificationListener.h"
[2280]46
[7403]47#include "Notification.h"
48#include "NotificationQueue.h"
49
50#include "ToluaBindNotifications.h"
51
[2435]52namespace orxonox
53{
[2280]54
[6417]55    const std::string NotificationManager::ALL("all");
56    const std::string NotificationManager::NONE("none");
[2911]57
[7403]58    // Register tolua_open function when loading the library.
59    DeclareToluaInterface(Notifications);
[2911]60
[7488]61    ManageScopedSingleton(NotificationManager, ScopeID::Root, false);
[7403]62
[7484]63    // Setting console command to enter the edit mode.
[7403]64    SetConsoleCommand("enterEditMode", &NotificationManager::enterEditMode);
65
[7474]66    registerStaticNetworkFunction(NotificationManager::sendNotification);
67
[2911]68    /**
69    @brief
70        Constructor. Registers the Object.
71    */
72    NotificationManager::NotificationManager()
[2280]73    {
[2911]74        RegisterRootObject(NotificationManager);
75
76        this->highestIndex_ = 0;
[7403]77
78        ModifyConsoleCommand("enterEditMode").setObject(this);
79
80        COUT(3) << "NotificatioManager created." << std::endl;
[2280]81    }
82
[2911]83    /**
84    @brief
85        Destructor.
86    */
[2280]87    NotificationManager::~NotificationManager()
88    {
[7403]89        ModifyConsoleCommand("enterEditMode").setObject(NULL);
[7163]90
[7488]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
[7403]96        COUT(3) << "NotificationManager destroyed." << std::endl;
[2280]97    }
[2501]98
[2911]99    /**
100    @brief
[7403]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.
[8079]106        std::map<const std::string, NotificationQueue*>::iterator it = this->queues_.begin();
107        while(it != this->queues_.end())
108        {
[7488]109            it->second->destroy(true);
[8079]110            it = this->queues_.begin();
111        }
[7489]112
[7403]113        this->queues_.clear();
114    }
115
[7484]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.
[7486]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.
[7484]127    */
[7486]128    /*static*/ void NotificationManager::sendNotification(const std::string& message, unsigned int clientId, const std::string& sender, bool isLocal)
[7474]129    {
[7484]130        // If we're in standalone mode or we're already no the right client we create and send the Notification.
[7486]131        if(GameMode::isStandalone() || isLocal || Host::getPlayerID() == clientId)
[7474]132        {
[7488]133            Notification* notification = new Notification(message, sender);
134            if(NotificationManager::getInstance().registerNotification(notification))
135                COUT(3) << "Notification \"" << notification->getMessage() << "\" sent." << std::endl;
[7474]136        }
[7484]137        // If we're on the server (and the server is not the intended recipient of the Notification) we send it over the network.
[7474]138        else if(GameMode::isServer())
139        {
140            callStaticNetworkFunction(NotificationManager::sendNotification, clientId, message, clientId, sender);
141        }
142    }
143
[7403]144    /**
145    @brief
[5619]146        Registers a Notification within the NotificationManager and makes sure that the Notification is sent to all the NotificationListeners associated with its sender.
[2911]147    @param notification
148        The Notification to be registered.
149    @return
150        Returns true if successful.
151    */
152    bool NotificationManager::registerNotification(Notification* notification)
153    {
[7403]154        assert(notification);
[5619]155
[7552]156        std::time_t time = std::time(0); // Get current time.
[5619]157
[7403]158        // Add the Notification to the list that holds all Notifications.
159        this->allNotificationsList_.insert(std::pair<std::time_t, Notification*>(time, notification));
[5619]160
[7403]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.
[2911]162            return true;
[5619]163
[2911]164        bool all = false;
[7403]165        if(notification->getSender() == NotificationManager::ALL) // If all are the sender, then the Notifications is added to every NotificationListener.
[2911]166            all = true;
[5619]167
[7403]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.
[2435]170        {
[7417]171            const std::set<std::string>& set = it->first->getTargetsSet();
[7403]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())
[2280]175            {
[7403]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.
[2435]179            }
180        }
[5619]181
[7403]182        COUT(4) << "Notification (&" << notification << ") registered with the NotificationManager." << std::endl;
[5619]183
[2280]184        return true;
185    }
[5619]186
[2911]187    /**
188    @brief
[7403]189        Unregisters a Notification within the NotificationManager for a given NotificationListener.
[7163]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
[7403]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));
[7163]202
[7403]203        COUT(4) << "Notification (&" << notification << ") unregistered with the NotificationManager from listener (&" << listener << ")" << std::endl;
[7163]204    }
205
206    /**
207    @brief
[7403]208        Helper method that removes an input Notification form an input map.
[7163]209    @param notification
[7403]210        A pointer to the Notification to be removed.
[7163]211    @param map
[7403]212        The map the Notification should be removed from.
[7163]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
[5619]233        Registers a NotificationListener within the NotificationManager.
234    @param listener
235        The NotificationListener to be registered.
[2911]236    @return
[7403]237        Returns true if successful.  Fales if the NotificationListener is already registered.
[2911]238    */
[5619]239    bool NotificationManager::registerListener(NotificationListener* listener)
[2280]240    {
[7403]241        assert(listener);
242
243        // If the NotificationListener is already registered.
244        if(this->listenerList_.find(listener) != this->listenerList_.end())
245            return false;
246
[2911]247        this->highestIndex_ += 1;
[7403]248        unsigned int index = this->highestIndex_; // An identifier that identifies each registered NotificationListener uniquely.
[5619]249
[7403]250        this->listenerList_[listener] = index; // Add the NotificationListener to the list of NotificationListeners.
[5619]251
[7417]252        const std::set<std::string>& set = listener->getTargetsSet();
[5619]253
[7403]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();
[7504]256        std::multimap<std::time_t, Notification*>* map = NULL;
[7403]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
[2284]261        {
[7403]262            this->notificationLists_[index] = new std::multimap<std::time_t, Notification*>;
263            map = this->notificationLists_[index];
[2284]264        }
[5619]265
[7403]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++)
[2911]268        {
[7403]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));
[2911]271        }
[2501]272
[7403]273        listener->update(); // Update the listener.
[5619]274
[7163]275        COUT(4) << "NotificationListener registered with the NotificationManager." << std::endl;
[5619]276
[2911]277        return true;
[2280]278    }
[5619]279
[2911]280    /**
281    @brief
[7403]282        Unregisters a NotificationListener within the NotificationManager.
283    @param listener
284        The NotificationListener to be unregistered.
[7163]285    */
286    void NotificationManager::unregisterListener(NotificationListener* listener)
287    {
288        assert(listener);
289
[7403]290        unsigned int identifier = this->listenerList_.find(listener)->second;
[7163]291        std::multimap<std::time_t, Notification*>* map = this->notificationLists_.find(identifier)->second;
292
[7403]293        // If the map is not the map of all Notifications, make sure all Notifications are unregistered.
[7163]294        std::multimap<std::time_t, Notification*>::iterator it = map->begin();
[7403]295        if(map != &this->allNotificationsList_)
[7163]296        {
[7403]297            while(it != map->end())
298            {
299                this->unregisterNotification(it->second, listener);
300                it = map->begin();
301            }
302            delete map;
[7163]303        }
304
[8079]305        COUT(4) << "NotificationListener '" << identifier << "' unregistered with the NotificationManager." << std::endl;
306
[7403]307        // Remove the NotificationListener from the list of NotificationListeners.
[7163]308        this->listenerList_.erase(listener);
[7403]309        // Remove the Notifications list that was associated with the input NotificationListener.
[7163]310        this->notificationLists_.erase(identifier);
311    }
312
313    /**
314    @brief
[7403]315        Fetches the Notifications for a specific NotificationListener in a specified timeframe and stores them in the input map.
[5619]316    @param listener
317        The NotificationListener the Notifications are fetched for.
[2911]318    @param map
[7403]319        A pointer to a multimap, in which the notifications are stored. The map needs to have been allocated.
[2911]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    */
[7403]327    void NotificationManager::getNotifications(NotificationListener* listener, std::multimap<std::time_t,Notification*>* map, const std::time_t & timeFrameStart, const std::time_t & timeFrameEnd)
[2346]328    {
[7403]329        assert(listener);
330        assert(map);
[2501]331
[7403]332        std::multimap<std::time_t, Notification*>* notifications = this->notificationLists_[this->listenerList_[listener]]; // All the Notifications for the input NotificationListener.
[5619]333
[2911]334        std::multimap<std::time_t,Notification*>::iterator it, itLowest, itHighest;
[7403]335        // Iterators pointing to the bounds specified by the specified start and end times of the time frame.
[2911]336        itLowest = notifications->lower_bound(timeFrameStart);
[7403]337        itHighest = notifications->upper_bound(timeFrameEnd);
[5619]338
[7403]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    }
[5619]342
[7403]343    /**
344    @brief
[8371]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
[7403]377        Enters the edit mode of the NotificationLayer.
378    */
379    void NotificationManager::enterEditMode(void)
380    {
[7489]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        }
[2346]387    }
[2280]388
[7403]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    {
[8079]400        COUT(4) << "NotificationQueue '" << queue->getName() << "' registered with the NotificationManager." << std::endl;
[7403]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    {
[8079]412        COUT(4) << "NotificationQueue '" << queue->getName() << "' unregistered with the NotificationManager." << std::endl;
[7403]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    {
[8371]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)");
[7403]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
[2280]462}
Note: See TracBrowser for help on using the repository browser.