Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation3/src/modules/questsystem/notifications/NotificationQueue.cc @ 7038

Last change on this file since 7038 was 6945, checked in by dafrick, 15 years ago

A lot of cleanup, mostly increasing output levels, which means, that the console is no longer cluttered by lots and lots of Quest-stuff (the log file still is, but that should be ok…).
Also some possible bugs (or let's say pitfalls) removed, which have been around for a long time and didn't cause any problems so far. Now they never will.
Also, regarding my previous commit. Quests seem tu work just fine, even the second time the level is loaded, which is awesome.

Ergo: Questsystem/Notificationsystem segfault upon loading a level with Quests/Notifications in it twice is now officially resolved.

  • Property svn:eol-style set to native
File size: 14.5 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
31    @brief Implementation of the NotificationQueue class.
32*/
33
34#include "NotificationQueue.h"
35
36#include <sstream>
37
38#include "core/CoreIncludes.h"
39#include "core/XMLPort.h"
40#include "NotificationOverlay.h"
41#include "NotificationManager.h"
42
43namespace orxonox
44{
45
46    CreateFactory(NotificationQueue);
47
48    const std::string NotificationQueue::DEFAULT_FONT("VeraMono");
49    const Vector2 NotificationQueue::DEFAULT_POSITION(0.0,0.0);
50    const float NotificationQueue::DEFAULT_FONT_SIZE = 0.025f;
51
52    /**
53    @brief
54        Constructor. Creates and initializes the object.
55    */
56    NotificationQueue::NotificationQueue(BaseObject* creator) : OverlayGroup(creator)
57    {
58        this->registered_ = false;
59       
60        RegisterObject(NotificationQueue);
61        this->initialize();
62    }
63
64    /**
65    @brief
66        Destructor.
67    */
68    NotificationQueue::~NotificationQueue()
69    {
70        this->targets_.clear();
71        this->clear();
72
73        if(this->registered_)
74            NotificationManager::getInstance().unregisterListener(this);
75    }
76
77    /**
78    @brief
79        Initializes the object.
80        Registers the object, initializes variables, sets default values and registers the queue with the NotificationManager.
81    */
82    void NotificationQueue::initialize(void)
83    {
84        this->size_ = 0;
85        this->tickTime_ = 0.0;
86
87        NotificationManager::getInstance().registerListener(this);
88        this->registered_ = true;
89    }
90
91    /**
92    @brief
93        Sets the defaults.
94    */
95    void NotificationQueue::setDefaults(void)
96    {
97        this->setMaxSize(DEFAULT_SIZE);
98        this->setNotificationLength(DEFAULT_LENGTH);
99        this->setDisplayTime(DEFAULT_DISPLAY_TIME);
100        this->setPosition(DEFAULT_POSITION);
101
102        this->setTargets(NotificationManager::ALL);
103
104        this->setFontSize(DEFAULT_FONT_SIZE);
105        this->setFont(DEFAULT_FONT);
106    }
107
108    /**
109    @brief
110        Method for creating a NotificationQueue object through XML.
111    */
112    void NotificationQueue::XMLPort(Element& xmlElement, XMLPort::Mode mode)
113    {
114        SUPER(NotificationQueue, XMLPort, xmlElement, mode);
115
116        this->setDefaults();
117
118        XMLPortParam(NotificationQueue, "maxSize", setMaxSize, getMaxSize, xmlElement, mode);
119        XMLPortParam(NotificationQueue, "notificationLength", setNotificationLength, getNotificationLength, xmlElement, mode);
120        XMLPortParam(NotificationQueue, "displayTime", setDisplayTime, getDisplayTime, xmlElement, mode);
121        XMLPortParam(NotificationQueue, "targets", setTargets, getTargets, xmlElement, mode);
122        XMLPortParam(NotificationQueue, "font", setFont, getFont, xmlElement, mode);
123        XMLPortParam(NotificationQueue, "fontSize", setFontSize, getFontSize, xmlElement, mode);
124        XMLPortParam(NotificationQueue, "position", setPosition, getPosition, xmlElement, mode);
125
126        COUT(3) << "NotificationQueue '" << this->getName() << "' created." << std::endl;
127    }
128
129    /**
130    @brief
131        Updates the queue from time to time.
132    @param dt
133        The time interval that has passed since the last tick.
134    */
135    void NotificationQueue::tick(float dt)
136    {
137        this->tickTime_ += dt; //!< Add the time interval that has passed to the time counter.
138        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.
139        {
140            this->timeLimit_.time = std::time(0)-this->displayTime_; //!< Container containig the current time.
141
142            std::multiset<NotificationOverlayContainer*, NotificationOverlayContainerCompare>::iterator it;
143            it = this->containers_.begin();
144            while(it != this->containers_.upper_bound(&this->timeLimit_)) //!< Iterate through all elements whose creation time is smaller than the current time minus the display time.
145            {
146                this->removeContainer(*it);
147                this->scroll(Vector2(0.0f,-(1.1f*this->getFontSize())));
148                it = this->containers_.begin(); //TODO: Needed?
149            }
150
151            this->tickTime_ = 0.0f; //!< Reset time counter.
152        }
153    }
154
155    /**
156    @brief
157        Updates the NotificationQueue.
158        Updates by clearing the queue and requesting all relevant Notifications from the NotificationManager and inserting the in the queue.
159    */
160    void NotificationQueue::update(void)
161    {
162        this->clear();
163
164        std::multimap<std::time_t,Notification*>* notifications = new std::multimap<std::time_t,Notification*>;
165        if(!NotificationManager::getInstance().getNotifications(this, notifications, this->displayTime_)) //!< Get the Notifications sent in the interval form now to minus the display time.
166        {
167            COUT(1) << "NotificationQueue update failed due to undetermined cause." << std::endl;
168            return;
169        }
170
171        if(notifications->empty())
172            return;
173
174        for(std::multimap<std::time_t,Notification*>::iterator it = notifications->begin(); it != notifications->end(); it++) //!> Add all Notifications.
175        {
176            this->addNotification(it->second, it->first);
177        }
178
179        delete notifications;
180
181        COUT(4) << "NotificationQueue '" << this->getName() << "' updated." << std::endl;
182    }
183
184    /**
185    @brief
186        Updates the NotificationQueue by adding an new Notification.
187    @param notification
188        Pointer to the Notification.
189    @param time
190        The time the Notification was sent.
191    */
192    void NotificationQueue::update(Notification* notification, const std::time_t & time)
193    {
194        this->addNotification(notification, time);
195
196        std::multiset<NotificationOverlayContainer*, NotificationOverlayContainerCompare>::iterator it;
197        while(this->getSize() > this->getMaxSize())
198        {
199            it = this->containers_.begin();
200            this->removeContainer(*it);
201            this->scroll(Vector2(0.0f,-(1.1f*this->getFontSize())));
202        }
203
204        COUT(4) << "NotificationQueue '" << this->getName() << "' updated. A new Notifications has been added." << std::endl;
205    }
206
207    /**
208    @brief
209        Sets the maximum number of displayed Notifications.
210    @param size
211        The size to be set.
212    @return
213        Returns true if successful.
214    */
215    bool NotificationQueue::setMaxSize(int size)
216    {
217        if(size < 0)
218            return false;
219        this->maxSize_ = size;
220        this->update();
221        return true;
222    }
223
224    /**
225    @brief
226        Sets the maximum number of characters a Notification message displayed by this queue is allowed to have.
227    @param length
228        The length to be set.
229    @return
230        Returns true if successful.
231    */
232    bool NotificationQueue::setNotificationLength(int length)
233    {
234        if(length < 0)
235            return false;
236        this->notificationLength_ = length;
237        this->update();
238        return true;
239    }
240
241    /**
242    @brief
243        Sets the maximum number of seconds a Notification is displayed.
244    @param time
245        The number of seconds the Notifications is displayed.
246    @return
247        Returns true if successful.
248    */
249    bool NotificationQueue::setDisplayTime(int time)
250    {
251        if(time < 0)
252            return false;
253        this->displayTime_ = time;
254        this->update();
255        return true;
256    }
257
258    /**
259    @brief
260        Produces all targets concatinated as string, with kommas (',') as seperators.
261    @param string
262        Pointer to a string which will be used by the method to fill with the concatination of the targets.
263    @return
264        Returns true if successful.
265    */
266    bool NotificationQueue::getTargets(std::string* string) const
267    {
268        if(string == NULL)
269        {
270            COUT(4) << "Input string must have memory allocated." << std::endl;
271            return false;
272        }
273        string->clear();
274        bool first = true;
275        for(std::set<std::string>::const_iterator it = this->targets_.begin(); it != this->targets_.end(); it++) //!< Iterate through the set of targets.
276        {
277            if(!first)
278            {
279                *string += ',';
280            }
281            else
282            {
283                first = false;
284            }
285            *string += *it;
286        }
287
288        return true;
289    }
290
291    /**
292    @brief
293        Sets the targets of the queue.
294        The targets are the senders whose Notifications are displayed in this queue.
295    @param targets
296        Accepts a string of targets, each seperated by commas (','), spaces are ignored.
297    @return
298        Returns true if successful.
299    */
300    bool NotificationQueue::setTargets(const std::string & targets)
301    {
302        this->targets_.clear();
303
304        std::string* pTemp;
305        unsigned int index = 0;
306        while( index < targets.size() ) //!< Go through the string, character by character until the end is reached.
307        {
308            pTemp = new std::string();
309            while(index < targets.size() && targets[index] != ',' && targets[index] != ' ')
310            {
311                *pTemp += targets[index];
312                index++;
313            }
314            index++;
315            this->targets_.insert(*pTemp);
316        }
317
318        return true;
319    }
320
321    /**
322    @brief
323        Sets the font size.
324    @param size
325        The font size.
326    @return
327        Returns true if successful.
328    */
329    bool NotificationQueue::setFontSize(float size)
330    {
331        if(size <= 0)
332            return false;
333        this->fontSize_ = size;
334        for (std::map<Notification*, NotificationOverlayContainer*>::iterator it = this->overlays_.begin(); it != this->overlays_.end(); it++) //!< Set the font size for each overlay.
335        {
336            it->second->overlay->setFontSize(size);
337        }
338        return true;
339    }
340
341    /**
342    @brief
343        Sets the font.
344    @param font
345        The font.
346    @return
347        Returns true if successful.
348    */
349    bool NotificationQueue::setFont(const std::string & font)
350    {
351        this->font_ = font;
352        for (std::map<Notification*, NotificationOverlayContainer*>::iterator it = this->overlays_.begin(); it != this->overlays_.end(); it++) //!< Set the font for each overlay.
353        {
354            it->second->overlay->setFont(font);
355        }
356        return true;
357    }
358
359    /**
360    @brief
361        Scrolls the NotificationQueue, meaning all NotificationOverlays are moved the input vector.
362    @param pos
363        The vector the NotificationQueue is scrolled.
364    */
365    void NotificationQueue::scroll(const Vector2 pos)
366    {
367        for (std::map<Notification*, NotificationOverlayContainer*>::iterator it = this->overlays_.begin(); it != this->overlays_.end(); ++it) //!< Scroll each overlay.
368        {
369            it->second->overlay->scroll(pos);
370        }
371    }
372
373    /**
374    @brief
375        Aligns all the Notifications to the position of the NotificationQueue.
376    */
377    void NotificationQueue::positionChanged(void)
378    {
379        int counter = 0;
380        for (std::multiset<NotificationOverlayContainer*, NotificationOverlayContainerCompare>::iterator it = this->containers_.begin(); it != this->containers_.end(); it++) //!< Set the position for each overlay.
381        {
382            (*it)->overlay->setPosition(this->getPosition());
383            (*it)->overlay->scroll(Vector2(0.0f,(1.1f*this->getFontSize())*counter));
384            counter++;
385        }
386    }
387
388    /**
389    @brief
390        Adds a Notification, to the queue.
391        It inserts it into the storage containers, creates an corresponding overlay and a container.
392    @param notification
393        The Notification.
394    @param time
395        The time.
396    */
397    void NotificationQueue::addNotification(Notification* notification, const std::time_t & time)
398    {
399        NotificationOverlayContainer* container = new NotificationOverlayContainer;
400        container->overlay = new NotificationOverlay(this, notification);
401        container->notification = notification;
402        container->time = time;
403        std::string timeString = std::ctime(&time);
404        timeString.erase(timeString.length()-1);
405        std::ostringstream stream;
406        stream << reinterpret_cast<unsigned long>(notification);
407        const std::string& addressString = stream.str();
408        container->name = "NotificationOverlay(" + timeString + ")&" + addressString;
409
410        this->containers_.insert(container);
411        this->overlays_[notification] = container;
412        this->addElement(container->overlay);
413        this->size_= this->size_+1;
414
415        container->overlay->scroll(Vector2(0.0f,(1.1f*this->getFontSize())*(this->getSize()-1)));
416    }
417
418    /**
419    @brief
420        Removes a container from the queue.
421    @param container
422        A pointer to the container.
423    @return
424        Returns true if successful.
425    */
426    bool NotificationQueue::removeContainer(NotificationOverlayContainer* container)
427    {
428        if(this->size_ == 0) //!< You cannot remove anything if the queue is empty.
429            return false;
430
431        // Unregister the NotificationQueue with the NotificationManager.
432        NotificationManager::getInstance().unregisterNotification(container->notification, this);
433       
434        this->removeElement(container->overlay);
435        this->containers_.erase(container);
436        this->overlays_.erase(container->notification);
437        container->overlay->destroy();
438        delete container;
439        this->size_= this->size_-1;
440
441        return true;
442    }
443
444    /**
445    @brief
446        Clears the queue by removing all containers.
447    */
448    void NotificationQueue::clear(void)
449    {
450        std::multiset<NotificationOverlayContainer*, NotificationOverlayContainerCompare>::iterator it = this->containers_.begin();
451        while(it != this->containers_.end())
452        {
453            this->removeContainer(*it);
454            it = this->containers_.begin();
455        }
456    }
457
458}
Note: See TracBrowser for help on using the repository browser.