Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/tutoriallevel/src/modules/notifications/NotificationManager.cc @ 8748

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

Committing changes before merge.

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