Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/usability/src/modules/notifications/NotificationManager.cc @ 7987

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

Hopefully fixing two bugs.

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