Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

NotificationListener is new an entity which is informed of new notifications. The NotificationManager is, so far, the only NotificationListener. This means that Notifications can now be sent from within orxonox (though not libraries or external).
Also introduced notification commands to affect the NotificationQueues in more ways than just have them display messages (e.g. clearing them).
Added a message type which allows to send Notifications of different importance, allowing the NotificationQueus to display them differently.

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