Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ai/src/modules/notifications/NotificationQueue.cc @ 8143

Last change on this file since 8143 was 7489, checked in by dafrick, 14 years ago

Mostly more documentation.

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