Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/usability/src/modules/notifications/NotificationQueue.cc @ 8377

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

Hopefully fixing two bugs.

  • Property svn:eol-style set to native
File size: 15.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 NotificationQueue.cc
31    @brief Implementation of the NotificationQueue class.
32*/
33
34#include "NotificationQueue.h"
35
36#include <map>
37#include <sstream>
38
39#include "core/CoreIncludes.h"
40#include "core/GameMode.h"
41#include "core/GUIManager.h"
42#include "core/LuaState.h"
43#include "util/Convert.h"
44#include "util/SubString.h"
45
46#include "Notification.h"
47
48namespace orxonox
49{
50
51    /**
52    @brief
53        Constructor. Creates and initializes the object.
54    @param name
55        The name of the new NotificationQueue. It needs to be unique
56    @param senders
57        The senders that are targets of this NotificationQueue, i.e. the names of senders whose Notifications this NotificationQueue displays.
58        The senders need to be seperated by commas.
59    @param size
60        The size (the maximum number of displayed Notifications) of this NotificationQueue.
61    @param displayTime
62        The time during which a Notification is (at most) displayed.
63    */
64    NotificationQueue::NotificationQueue(const std::string& name, const std::string& senders, unsigned int size, unsigned int displayTime)
65    {
66        this->registered_ = false;
67
68        RegisterRootObject(NotificationQueue);
69
70        // Initialize.
71        this->size_ = 0;
72        this->tickTime_ = 0.0f;
73
74        // Sets the input values.
75        this->setTargets(senders);
76        this->name_ = name;
77        this->maxSize_ = size;
78        this->setDisplayTime(displayTime);
79
80        // Register the NotificationQueue with the NotificationManager.
81        bool queueRegistered = NotificationManager::getInstance().registerQueue(this);
82        this->registered_ = true;
83        if(!queueRegistered) // If the registration has failed.
84        {
85            this->registered_ = false;
86            COUT(1) << "Error: NotificationQueue '" << this->getName() << "' could not be registered." << std::endl;
87            return;
88        }
89
90        this->create(); // Creates the NotificationQueue in lua.
91
92        // Register the NotificationQueue as NotificationListener with the NotificationManager.
93        bool listenerRegistered = NotificationManager::getInstance().registerListener(this);
94        if(!listenerRegistered) // If the registration has failed.
95        {
96            this->registered_ = false;
97            // Remove the NotificationQueue in lua.
98            if(GameMode::showsGraphics())
99                GUIManager::getInstance().getLuaState()->doString("NotificationLayer.removeQueue(\"" + this->getName() +  "\")");
100            NotificationManager::getInstance().unregisterQueue(this);
101            COUT(1) << "Error: NotificationQueue '" << this->getName() << "' could not be registered." << std::endl;
102            return;
103        }
104
105        COUT(3) << "NotificationQueue '" << this->getName() << "' created." << std::endl;
106    }
107
108    /**
109    @brief
110        Destructor.
111    */
112    NotificationQueue::~NotificationQueue()
113    {
114        this->targets_.clear();
115
116        if(this->registered_) // If the NotificationQueue is registered.
117        {
118            this->clear(true);
119
120            // Unregister with the NotificationManager.
121            NotificationManager::getInstance().unregisterListener(this);
122            NotificationManager::getInstance().unregisterQueue(this);
123        }
124    }
125
126    /**
127    @brief
128        Destroys the NotificationQueue.
129        Used in lua and NotificationManager.
130    @param noGraphics
131        If this is set to true (false is default), then the queue is not removed in lua. This is used to destroy the queue, after the GUIManager has been destroyed.
132    */
133    void NotificationQueue::destroy(bool noGraphics)
134    {
135        // Remove the NotificationQueue in lua.
136        if(GameMode::showsGraphics() && !noGraphics)
137            GUIManager::getInstance().getLuaState()->doString("NotificationLayer.removeQueue(\"" + this->getName() +  "\")");
138
139        COUT(3) << "NotificationQueue '" << this->getName() << "' destroyed." << std::endl;
140
141        this->OrxonoxClass::destroy();
142    }
143
144    /**
145    @brief
146        Creates the NotificationQueue in lua.
147    */
148    void NotificationQueue::create(void)
149    {
150        if(GameMode::showsGraphics())
151            GUIManager::getInstance().getLuaState()->doString("NotificationLayer.createQueue(\"" + this->getName() +  "\", " + multi_cast<std::string>(this->getMaxSize()) + ")");
152    }
153
154    /**
155    @brief
156        Updates the queue from time to time.
157    @param dt
158        The time interval that has passed since the last tick.
159    */
160    void NotificationQueue::tick(float dt)
161    {
162        this->tickTime_ += dt; // Add the time interval that has passed to the time counter.
163        if(this->tickTime_ >= 1.0) // If the time counter is greater than 1s all Notifications that have expired are removed, if it is smaller we wait to the next tick.
164        {
165            this->timeLimit_.time = std::time(0)-this->displayTime_; // Container containig the current time.
166
167            std::multiset<NotificationContainer*, NotificationContainerCompare>::iterator it = this->ordering_.begin();
168            // Iterate through all elements whose creation time is smaller than the current time minus the display time.
169            while(it != this->ordering_.upper_bound(&this->timeLimit_))
170            {
171                this->remove(it); // Remove the Notifications that have expired.
172                it = this->ordering_.begin();
173            }
174
175            this->tickTime_ = this->tickTime_ - (int)this->tickTime_; // Reset time counter.
176        }
177    }
178
179    /**
180    @brief
181        Updates the NotificationQueue.
182        Updates by clearing the queue and requesting all relevant Notifications from the NotificationManager and inserting them into the queue.
183    */
184    void NotificationQueue::update(void)
185    {
186        this->clear();
187
188        std::multimap<std::time_t, Notification*>* notifications = new std::multimap<std::time_t, Notification*>;
189        // Get the Notifications sent in the interval from now to now minus the display time.
190        NotificationManager::getInstance().getNotifications(this, notifications, this->displayTime_);
191
192        if(!notifications->empty())
193        {
194            // Add all Notifications.
195            for(std::multimap<std::time_t, Notification*>::iterator it = notifications->begin(); it != notifications->end(); it++)
196                this->push(it->second, it->first);
197        }
198
199        delete notifications;
200
201        COUT(4) << "NotificationQueue '" << this->getName() << "' updated." << std::endl;
202    }
203
204    /**
205    @brief
206        Updates the NotificationQueue by adding an new Notification.
207    @param notification
208        Pointer to the Notification.
209    @param time
210        The time the Notification was sent.
211    */
212    void NotificationQueue::update(Notification* notification, const std::time_t & time)
213    {
214        assert(notification);
215
216        this->push(notification, time);
217
218        COUT(4) << "NotificationQueue '" << this->getName() << "' updated. A new Notification has been added." << std::endl;
219    }
220
221    /**
222    @brief
223        Adds (pushes) a Notification to the NotificationQueue.
224        It inserts it into the storage containers, creates a corresponding container and pushes the Notification message to the GUI.
225    @param notification
226        The Notification to be pushed.
227    @param time
228        The time when the Notification has been sent.
229    */
230    void NotificationQueue::push(Notification* notification, const std::time_t & time)
231    {
232        assert(notification);
233
234        NotificationContainer* container = new NotificationContainer;
235        container->notification = notification;
236        container->time = time;
237
238        // If the maximum size of the NotificationQueue has been reached the last (least recently added) Notification is removed.
239        if(this->getSize() >= this->getMaxSize())
240            this->pop();
241
242        this->size_++;
243
244        this->ordering_.insert(container);
245        // Insert the Notification at the begin of the list (vector, actually).
246        this->notifications_.insert(this->notifications_.begin(), container);
247
248        // Push the Notification to the GUI.
249        if(GameMode::showsGraphics())
250            GUIManager::getInstance().getLuaState()->doString("NotificationLayer.pushNotification(\"" + this->getName() + "\", \"" + notification->getMessage() + "\")");
251
252        COUT(5) << "Notification \"" << notification->getMessage() << "\" pushed to NotificationQueue '" << this->getName() << "'" << endl;
253    }
254
255    /**
256    @brief
257        Removes (pops) the least recently added Notification form the NotificationQueue.
258    */
259    void NotificationQueue::pop(void)
260    {
261        NotificationContainer* container = this->notifications_.back();
262        // Get all the NotificationContainers that were sent the same time the NotificationContainer we want to pop was sent.
263        std::pair<std::multiset<NotificationContainer*, NotificationContainerCompare>::iterator, std::multiset<NotificationContainer*, NotificationContainerCompare>::iterator> iterators = this->ordering_.equal_range(container);
264
265        // Iterate through all suspects and remove the container as soon as we find it.
266        for(std::multiset<NotificationContainer*, NotificationContainerCompare>::iterator it = iterators.first; it != iterators.second; it++)
267        {
268            if(container == *it)
269            {
270                COUT(5) << "Notification \"" << (*it)->notification->getMessage() << "\" popped from NotificationQueue '" << this->getName() << "'" << endl;
271                this->ordering_.erase(it);
272                break;
273            }
274        }
275        this->notifications_.pop_back();
276
277        this->size_--;
278
279        delete container;
280
281        // Pops the Notification from the GUI.
282        if(GameMode::showsGraphics())
283            GUIManager::getInstance().getLuaState()->doString("NotificationLayer.popNotification(\"" + this->getName() + "\")");
284    }
285
286    /**
287    @brief
288        Removes the Notification that is stored in the input NotificationContainer.
289    @param containerIterator
290        An iterator to the NotificationContainer to be removed.
291    */
292    void NotificationQueue::remove(const std::multiset<NotificationContainer*, NotificationContainerCompare>::iterator& containerIterator)
293    {
294        std::vector<NotificationContainer*>::iterator it = std::find(this->notifications_.begin(), this->notifications_.end(), *containerIterator);
295        // Get the index at which the Notification is.
296        std::vector<NotificationContainer*>::difference_type index = it - this->notifications_.begin ();
297
298        COUT(5) << "Notification \"" << (*it)->notification->getMessage() << "\" removed from NotificationQueue '" << this->getName() << "'" << endl;
299
300        this->ordering_.erase(containerIterator);
301        this->notifications_.erase(it);
302
303        this->size_--;
304
305        delete *containerIterator;
306
307        // Removes the Notification from the GUI.
308        if(GameMode::showsGraphics())
309            GUIManager::getInstance().getLuaState()->doString("NotificationLayer.removeNotification(\"" + this->getName() + "\", " + multi_cast<std::string>(index) + ")");
310    }
311
312    /**
313    @brief
314        Clears the NotificationQueue by removing all NotificationContainers.
315    @param noGraphics
316        If this is eset to true the GUI is not informed of the clearing of the NotificationQueue. This is needed only internally.
317    */
318    void NotificationQueue::clear(bool noGraphics)
319    {
320        COUT(4) << "Clearing NotificationQueue " << this->getName() << "." << endl;
321        this->ordering_.clear();
322        // Delete all NotificationContainers in the list.
323        for(std::vector<NotificationContainer*>::iterator it = this->notifications_.begin(); it != this->notifications_.end(); it++)
324            delete *it;
325
326        this->notifications_.clear();
327        this->size_ = 0;
328
329        // Clear the NotificationQueue in the GUI.
330        if(GameMode::showsGraphics() && !noGraphics)
331            GUIManager::getInstance().getLuaState()->doString("NotificationLayer.clearQueue(\"" + this->getName() + "\")");
332    }
333
334    /**
335    @brief
336        Sets the name of the NotificationQueue.
337    @param name
338        The name to be set.
339    */
340    void NotificationQueue::setName(const std::string& name)
341    {
342        this->name_ = name;
343    }
344
345    /**
346    @brief
347        Sets the maximum number of displayed Notifications.
348    @param size
349        The size to be set.
350    */
351    void NotificationQueue::setMaxSize(unsigned int size)
352    {
353        if(this->maxSize_ == size)
354            return;
355
356        this->maxSize_ = size;
357
358        if(this->registered_)
359            this->update();
360    }
361
362    /**
363    @brief
364        Sets the maximum number of seconds a Notification is displayed.
365    @param time
366        The number of seconds the Notifications is displayed.
367    @return
368        Returns true if successful.
369    */
370    void NotificationQueue::setDisplayTime(unsigned int time)
371    {
372        if(this->displayTime_ == time)
373            return;
374
375        this->displayTime_ = time;
376
377        if(this->registered_)
378            this->update();
379    }
380
381    /**
382    @brief
383        Produces all targets of the NotificationQueue concatinated as string, with commas (',') as seperators.
384    @return
385        Returns the targets as a string.
386    */
387    const std::string& NotificationQueue::getTargets(void) const
388    {
389        std::stringstream stream;
390        bool first = true;
391        // Iterate through the set of targets.
392        for(std::set<std::string>::const_iterator it = this->targets_.begin(); it != this->targets_.end(); it++)
393        {
394            if(!first)
395                stream << ", ";
396            else
397                first = false;
398            stream << *it;
399        }
400
401        return *(new std::string(stream.str()));
402    }
403
404    /**
405    @brief
406        Sets the targets of the NotificationQueue.
407        The targets are the senders whose Notifications are displayed in this queue.
408    @param targets
409        Accepts a string of targets, each seperated by commas (','), spaces are ignored.
410    */
411    void NotificationQueue::setTargets(const std::string & targets)
412    {
413        this->targets_.clear();
414
415        SubString string = SubString(targets, ",", " ", false);
416        for(unsigned int i = 0; i < string.size(); i++)
417            this->targets_.insert(string[i]);
418
419        if(this->registered_)
420        {
421            NotificationManager::getInstance().unregisterListener(this);
422            NotificationManager::getInstance().registerListener(this);
423        }
424    }
425
426}
427
Note: See TracBrowser for help on using the repository browser.