Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/tutoriallevel2/src/modules/notifications/NotificationQueue.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: 14.7 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 separated 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        COUT(3) << "NotificationQueue '" << this->getName() << "' created." << std::endl;
93    }
94
95    /**
96    @brief
97        Destructor.
98    */
99    NotificationQueue::~NotificationQueue()
100    {
101        this->targets_.clear();
102
103        if(this->registered_) // If the NotificationQueue is registered.
104        {
105            this->clear(true);
106
107            // Unregister with the NotificationManager.
108            NotificationManager::getInstance().unregisterQueue(this);
109        }
110    }
111
112    /**
113    @brief
114        Destroys the NotificationQueue.
115        Used in lua and NotificationManager.
116    @param noGraphics
117        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.
118    */
119    void NotificationQueue::destroy(bool noGraphics)
120    {
121        // Remove the NotificationQueue in lua.
122        if(GameMode::showsGraphics() && !noGraphics)
123            GUIManager::getInstance().getLuaState()->doString("NotificationLayer.removeQueue(\"" + this->getName() +  "\")");
124
125        COUT(3) << "NotificationQueue '" << this->getName() << "' destroyed." << std::endl;
126
127        this->OrxonoxClass::destroy();
128    }
129
130    /**
131    @brief
132        Creates the NotificationQueue in lua.
133    */
134    void NotificationQueue::create(void)
135    {
136        if(GameMode::showsGraphics())
137            GUIManager::getInstance().getLuaState()->doString("NotificationLayer.createQueue(\"" + this->getName() +  "\", " + multi_cast<std::string>(this->getMaxSize()) + ")");
138    }
139
140    /**
141    @brief
142        Updates the queue from time to time.
143    @param dt
144        The time interval that has passed since the last tick.
145    */
146    void NotificationQueue::tick(float dt)
147    {
148        this->tickTime_ += dt; // Add the time interval that has passed to the time counter.
149        if(this->displayTime_ != INF && 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.
150        {
151            this->timeLimit_.time = std::time(0)-this->displayTime_; // Container containig the current time.
152
153            std::multiset<NotificationContainer*, NotificationContainerCompare>::iterator it = this->ordering_.begin();
154            // Iterate through all elements whose creation time is smaller than the current time minus the display time.
155            while(it != this->ordering_.upper_bound(&this->timeLimit_))
156            {
157                this->remove(it); // Remove the Notifications that have expired.
158                it = this->ordering_.begin();
159            }
160
161            this->tickTime_ = this->tickTime_ - (int)this->tickTime_; // Reset time counter.
162        }
163    }
164
165    /**
166    @brief
167        Updates the NotificationQueue.
168        Updates by clearing the queue and requesting all relevant Notifications from the NotificationManager and inserting them into the queue.
169        This is called by the NotificationManager when the Notifications have changed so much, that the NotificationQueue may have to re-initialize his operations.
170    */
171    void NotificationQueue::update(void)
172    {
173        this->clear();
174
175        std::multimap<std::time_t, Notification*>* notifications = new std::multimap<std::time_t, Notification*>;
176        // Get the Notifications sent in the interval from now to now minus the display time.
177        if(this->displayTime_ == INF)
178            NotificationManager::getInstance().getNewestNotifications(this, notifications, this->getMaxSize());
179        else
180            NotificationManager::getInstance().getNotifications(this, notifications, this->displayTime_);
181
182        if(!notifications->empty())
183        {
184            // Add all Notifications.
185            for(std::multimap<std::time_t, Notification*>::iterator it = notifications->begin(); it != notifications->end(); it++)
186                this->push(it->second, it->first);
187        }
188
189        delete notifications;
190
191        COUT(4) << "NotificationQueue '" << this->getName() << "' updated." << std::endl;
192    }
193
194    /**
195    @brief
196        Updates the NotificationQueue by adding an new Notification.
197    @param notification
198        Pointer to the Notification.
199    @param time
200        The time the Notification was sent.
201    */
202    void NotificationQueue::update(Notification* notification, const std::time_t & time)
203    {
204        assert(notification);
205
206        this->push(notification, time);
207
208        COUT(4) << "NotificationQueue '" << this->getName() << "' updated. A new Notification has been added." << std::endl;
209    }
210
211    /**
212    @brief
213        Adds (pushes) a Notification to the NotificationQueue.
214        It inserts it into the storage containers, creates a corresponding container and pushes the Notification message to the GUI.
215    @param notification
216        The Notification to be pushed.
217    @param time
218        The time when the Notification has been sent.
219    */
220    void NotificationQueue::push(Notification* notification, const std::time_t & time)
221    {
222        assert(notification);
223
224        NotificationContainer* container = new NotificationContainer;
225        container->notification = notification;
226        container->time = time;
227
228        // If the maximum size of the NotificationQueue has been reached the last (least recently added) Notification is removed.
229        if(this->getSize() >= this->getMaxSize())
230            this->pop();
231
232        this->size_++;
233
234        this->ordering_.insert(container);
235        // Insert the Notification at the begin of the list (vector, actually).
236        this->notifications_.insert(this->notifications_.begin(), container);
237
238        // Push the Notification to the GUI.
239        if(GameMode::showsGraphics())
240            GUIManager::getInstance().getLuaState()->doString("NotificationLayer.pushNotification(\"" + this->getName() + "\", \"" + notification->getMessage() + "\")");
241
242        COUT(5) << "Notification \"" << notification->getMessage() << "\" pushed to NotificationQueue '" << this->getName() << "'" << endl;
243    }
244
245    /**
246    @brief
247        Removes (pops) the least recently added Notification form the NotificationQueue.
248    */
249    void NotificationQueue::pop(void)
250    {
251        NotificationContainer* container = this->notifications_.back();
252        // Get all the NotificationContainers that were sent the same time the NotificationContainer we want to pop was sent.
253        std::pair<std::multiset<NotificationContainer*, NotificationContainerCompare>::iterator, std::multiset<NotificationContainer*, NotificationContainerCompare>::iterator> iterators = this->ordering_.equal_range(container);
254
255        // Iterate through all suspects and remove the container as soon as we find it.
256        for(std::multiset<NotificationContainer*, NotificationContainerCompare>::iterator it = iterators.first; it != iterators.second; it++)
257        {
258            if(container == *it)
259            {
260                COUT(5) << "Notification \"" << (*it)->notification->getMessage() << "\" popped from NotificationQueue '" << this->getName() << "'" << endl;
261                this->ordering_.erase(it);
262                break;
263            }
264        }
265        this->notifications_.pop_back();
266
267        this->size_--;
268
269        delete container;
270
271        // Pops the Notification from the GUI.
272        if(GameMode::showsGraphics())
273            GUIManager::getInstance().getLuaState()->doString("NotificationLayer.popNotification(\"" + this->getName() + "\")");
274    }
275
276    /**
277    @brief
278        Removes the Notification that is stored in the input NotificationContainer.
279    @param containerIterator
280        An iterator to the NotificationContainer to be removed.
281    */
282    void NotificationQueue::remove(const std::multiset<NotificationContainer*, NotificationContainerCompare>::iterator& containerIterator)
283    {
284        std::vector<NotificationContainer*>::iterator it = std::find(this->notifications_.begin(), this->notifications_.end(), *containerIterator);
285        // Get the index at which the Notification is.
286        std::vector<NotificationContainer*>::difference_type index = it - this->notifications_.begin ();
287
288        COUT(5) << "Notification \"" << (*it)->notification->getMessage() << "\" removed from NotificationQueue '" << this->getName() << "'" << endl;
289
290        this->ordering_.erase(containerIterator);
291        this->notifications_.erase(it);
292
293        this->size_--;
294
295        delete *containerIterator;
296
297        // Removes the Notification from the GUI.
298        if(GameMode::showsGraphics())
299            GUIManager::getInstance().getLuaState()->doString("NotificationLayer.removeNotification(\"" + this->getName() + "\", " + multi_cast<std::string>(index) + ")");
300    }
301
302    /**
303    @brief
304        Clears the NotificationQueue by removing all NotificationContainers.
305    @param noGraphics
306        If this is set to true the GUI is not informed of the clearing of the NotificationQueue. This is needed only internally.
307    */
308    void NotificationQueue::clear(bool noGraphics)
309    {
310        COUT(4) << "Clearing NotificationQueue " << this->getName() << "." << endl;
311        this->ordering_.clear();
312        // Delete all NotificationContainers in the list.
313        for(std::vector<NotificationContainer*>::iterator it = this->notifications_.begin(); it != this->notifications_.end(); it++)
314            delete *it;
315
316        this->notifications_.clear();
317        this->size_ = 0;
318
319        // Clear the NotificationQueue in the GUI.
320        if(GameMode::showsGraphics() && !noGraphics)
321            GUIManager::getInstance().getLuaState()->doString("NotificationLayer.clearQueue(\"" + this->getName() + "\")");
322    }
323
324    /**
325    @brief
326        Sets the name of the NotificationQueue.
327    @param name
328        The name to be set.
329    */
330    void NotificationQueue::setName(const std::string& name)
331    {
332        this->name_ = name;
333    }
334
335    /**
336    @brief
337        Sets the maximum number of displayed Notifications.
338    @param size
339        The size to be set.
340    */
341    void NotificationQueue::setMaxSize(unsigned int size)
342    {
343        if(this->maxSize_ == size)
344            return;
345
346        this->maxSize_ = size;
347
348        if(this->registered_)
349            this->update();
350    }
351
352    /**
353    @brief
354        Sets the maximum number of seconds a Notification is displayed.
355    @param time
356        The number of seconds a Notification is displayed.
357    */
358    void NotificationQueue::setDisplayTime(int time)
359    {
360        if(this->displayTime_ == time)
361            return;
362
363        this->displayTime_ = time;
364
365        if(this->registered_)
366            this->update();
367    }
368
369    /**
370    @brief
371        Produces all targets of the NotificationQueue concatenated as string, with commas (',') as separators.
372    @return
373        Returns the targets as a string.
374    */
375    const std::string& NotificationQueue::getTargets(void) const
376    {
377        std::stringstream stream;
378        bool first = true;
379        // Iterate through the set of targets.
380        for(std::set<std::string>::const_iterator it = this->targets_.begin(); it != this->targets_.end(); it++)
381        {
382            if(!first)
383                stream << ", ";
384            else
385                first = false;
386            stream << *it;
387        }
388
389        return *(new std::string(stream.str()));
390    }
391
392    /**
393    @brief
394        Sets the targets of the NotificationQueue.
395        The targets are the senders whose Notifications are displayed in this queue.
396    @param targets
397        Accepts a string of targets, each separated by commas (','), spaces are ignored.
398    */
399    void NotificationQueue::setTargets(const std::string & targets)
400    {
401        this->targets_.clear();
402
403        SubString string = SubString(targets, ",", " ", false);
404        for(unsigned int i = 0; i < string.size(); i++)
405            this->targets_.insert(string[i]);
406
407        // TODO: Why?
408        if(this->registered_)
409        {
410            NotificationManager::getInstance().unregisterQueue(this);
411            NotificationManager::getInstance().registerQueue(this);
412        }
413    }
414   
415    void NotificationQueue::tidy(void)
416    {
417        while(this->size_ > 0)
418            this->pop();
419    }
420
421}
422
Note: See TracBrowser for help on using the repository browser.