Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/modules/notifications/NotificationQueue.cc @ 11483

Last change on this file since 11483 was 11099, checked in by muemart, 9 years ago

Fix loads of doxygen warnings and other documentation issues

  • Property svn:eol-style set to native
File size: 15.9 KB
RevLine 
[2280]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
[2911]29/**
[7403]30    @file NotificationQueue.cc
[2911]31    @brief Implementation of the NotificationQueue class.
32*/
33
[2280]34#include "NotificationQueue.h"
35
[7403]36#include <map>
37#include <sstream>
38
39#include "core/CoreIncludes.h"
[8706]40#include "core/XMLPort.h"
[7403]41#include "util/SubString.h"
[2280]42
[2435]43namespace orxonox
44{
[2910]45
[9667]46    RegisterClass(NotificationQueue);
[9253]47
[2911]48    /**
49    @brief
[8706]50        Default constructor. Registers and initializes the object.
51    */
[9667]52    NotificationQueue::NotificationQueue(Context* context) : BaseObject(context), Synchronisable(context), registered_(false)
[8706]53    {
54        RegisterObject(NotificationQueue);
55
56        this->size_ = 0;
57        this->tickTime_ = 0.0f;
58        this->maxSize_ = NotificationQueue::DEFAULT_SIZE;
59        this->displayTime_ = NotificationQueue::DEFAULT_DISPLAY_TIME;
60
61        this->creationTime_ = std::time(0);
[9253]62
[8706]63        this->registerVariables();
64    }
65
66    /**
67    @brief
[7403]68        Destructor.
[2911]69    */
[7403]70    NotificationQueue::~NotificationQueue()
[2911]71    {
[7403]72        this->targets_.clear();
[2911]73
[8706]74        if(this->isRegistered()) // If the NotificationQueue is registered.
[7403]75        {
[7488]76            this->clear(true);
[2911]77
[7403]78            // Unregister with the NotificationManager.
79            NotificationManager::getInstance().unregisterQueue(this);
[7488]80        }
81    }
[7403]82
[7488]83    /**
84    @brief
[8706]85        Is called when the name of the NotificationQueue has changed.
86        Clears and re-creates the NotificationQueue.
[7488]87    */
[8706]88    void NotificationQueue::changedName(void)
[7488]89    {
[8706]90        SUPER(NotificationQueue, changedName);
[7488]91
[8706]92        if(this->isRegistered())
93            this->clear();
[9253]94
[8706]95        this->create();
[8079]96
[8706]97        this->targetsChanged();
98        this->maxSizeChanged();
99        this->displayTimeChanged();
[2911]100    }
101
102    /**
103    @brief
[8706]104        Creates the NotificationQueue.
[2911]105    */
[7403]106    void NotificationQueue::create(void)
[2911]107    {
[8706]108        // Register the NotificationQueue with the NotificationManager.
109        bool queueRegistered = NotificationManager::getInstance().registerQueue(this);
110        this->registered_ = true;
111        if(!queueRegistered) // If the registration has failed.
112        {
113            this->registered_ = false;
[8858]114            orxout(internal_error, context::notifications) << "NotificationQueue '" << this->getName() << "' could not be registered." << endl;
[8706]115            return;
116        }
117
[8858]118        orxout(internal_info, context::notifications) << "NotificationQueue '" << this->getName() << "' created." << endl;
[2911]119    }
120
121    /**
122    @brief
123        Updates the queue from time to time.
124    @param dt
125        The time interval that has passed since the last tick.
126    */
127    void NotificationQueue::tick(float dt)
128    {
[7403]129        this->tickTime_ += dt; // Add the time interval that has passed to the time counter.
[8706]130        if(this->displayTime_ != INF && this->tickTime_ >= 1.0) // If the time counter is greater than 1 s all Notifications that have expired are removed, if it is smaller we wait to the next tick.
[2910]131        {
[8706]132            this->timeLimit_.time = std::time(0)-this->displayTime_; // Container containing the current time.
[2911]133
[7403]134            std::multiset<NotificationContainer*, NotificationContainerCompare>::iterator it = this->ordering_.begin();
135            // Iterate through all elements whose creation time is smaller than the current time minus the display time.
[7410]136            while(it != this->ordering_.upper_bound(&this->timeLimit_))
[2911]137            {
[8079]138                this->remove(it); // Remove the Notifications that have expired.
139                it = this->ordering_.begin();
[2911]140            }
141
[7403]142            this->tickTime_ = this->tickTime_ - (int)this->tickTime_; // Reset time counter.
[2910]143        }
[2911]144    }
145
[8706]146    void NotificationQueue::XMLPort(Element& xmlelement, XMLPort::Mode mode)
147    {
148        SUPER(NotificationQueue, XMLPort, xmlelement, mode);
149
150        XMLPortParam(NotificationQueue, "targets", setTargets, getTargets, xmlelement, mode).defaultValues(NotificationListener::ALL);
151        XMLPortParam(NotificationQueue, "size", setMaxSize, getMaxSize, xmlelement, mode);
152        XMLPortParam(NotificationQueue, "displayTime", setDisplayTime, getDisplayTime, xmlelement, mode);
153    }
[9253]154
155
[2911]156    /**
157    @brief
[8706]158        Registers Variables to be Synchronised.
159        Registers Variables which have to be synchronised to the network system.
160      */
161    void NotificationQueue::registerVariables()
162    {
163        registerVariable( this->name_, VariableDirection::ToClient, new NetworkCallback<NotificationQueue>(this, &NotificationQueue::changedName));
164        registerVariable( this->maxSize_, VariableDirection::ToClient, new NetworkCallback<NotificationQueue>(this, &NotificationQueue::maxSizeChanged));
165        registerVariable( this->targets_, VariableDirection::ToClient, new NetworkCallback<NotificationQueue>(this, &NotificationQueue::targetsChanged));
166        registerVariable( this->displayTime_, VariableDirection::ToClient, new NetworkCallback<NotificationQueue>(this, &NotificationQueue::displayTimeChanged));
167    }
168
169    /**
170    @brief
[2911]171        Updates the NotificationQueue.
[7403]172        Updates by clearing the queue and requesting all relevant Notifications from the NotificationManager and inserting them into the queue.
[8706]173        This is called by the NotificationManager when the Notifications have changed so much, that the NotificationQueue may have to re-initialize his operations.
[2911]174    */
175    void NotificationQueue::update(void)
176    {
177        this->clear();
178
[7403]179        std::multimap<std::time_t, Notification*>* notifications = new std::multimap<std::time_t, Notification*>;
180        // Get the Notifications sent in the interval from now to now minus the display time.
[8706]181        if(this->displayTime_ == INF)
182            NotificationManager::getInstance().getNewestNotifications(this, notifications, this->getMaxSize());
183        else
184            NotificationManager::getInstance().getNotifications(this, notifications, this->displayTime_);
[2910]185
[7403]186        if(!notifications->empty())
[2911]187        {
[8706]188            // Add all Notifications that have been created after this NotificationQueue was created.
[11071]189            for(const auto& mapEntry : *notifications)
[8706]190            {
[11071]191                if(mapEntry.first >= this->creationTime_)
192                    this->push(mapEntry.second, mapEntry.first);
[8706]193            }
[2911]194        }
195
196        delete notifications;
197
[8858]198        orxout(verbose, context::notifications) << "NotificationQueue '" << this->getName() << "' updated." << endl;
[2280]199    }
[2910]200
[2911]201    /**
202    @brief
203        Updates the NotificationQueue by adding an new Notification.
204    @param notification
205        Pointer to the Notification.
206    @param time
207        The time the Notification was sent.
208    */
209    void NotificationQueue::update(Notification* notification, const std::time_t & time)
[2280]210    {
[7489]211        assert(notification);
212
[7403]213        this->push(notification, time);
[2910]214
[8858]215        orxout(verbose, context::notifications) << "NotificationQueue '" << this->getName() << "' updated. A new Notification has been added." << endl;
[2280]216    }
[2910]217
[2911]218    /**
219    @brief
[7403]220        Adds (pushes) a Notification to the NotificationQueue.
[8706]221        It inserts it into the storage containers, creates a corresponding container and pushes the notification message to the GUI.
[7403]222    @param notification
223        The Notification to be pushed.
224    @param time
225        The time when the Notification has been sent.
[2911]226    */
[7403]227    void NotificationQueue::push(Notification* notification, const std::time_t & time)
[2280]228    {
[7489]229        assert(notification);
230
[7403]231        NotificationContainer* container = new NotificationContainer;
232        container->notification = notification;
233        container->time = time;
234
235        // If the maximum size of the NotificationQueue has been reached the last (least recently added) Notification is removed.
236        if(this->getSize() >= this->getMaxSize())
237            this->pop();
238
239        this->size_++;
240
241        this->ordering_.insert(container);
242        // Insert the Notification at the begin of the list (vector, actually).
243        this->notifications_.insert(this->notifications_.begin(), container);
244
[8706]245        // Inform that a Notification was pushed.
246        this->notificationPushed(notification);
[8079]247
[8858]248        orxout(verbose_more, context::notifications) << "Notification \"" << notification->getMessage() << "\" pushed to NotificationQueue '" << this->getName() << "'" << endl;
249        orxout(internal_info, context::notifications) << "NotificationQueue \"" << this->getName() << "\": " << notification->getMessage() << endl;
[2911]250    }
[2500]251
[2911]252    /**
253    @brief
[7403]254        Removes (pops) the least recently added Notification form the NotificationQueue.
[2911]255    */
[7403]256    void NotificationQueue::pop(void)
[2911]257    {
[7403]258        NotificationContainer* container = this->notifications_.back();
[7412]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);
[8079]261
[7489]262        // Iterate through all suspects and remove the container as soon as we find it.
[7412]263        for(std::multiset<NotificationContainer*, NotificationContainerCompare>::iterator it = iterators.first; it != iterators.second; it++)
264        {
265            if(container == *it)
266            {
[8858]267                orxout(verbose_more, context::notifications) << "Notification \"" << (*it)->notification->getMessage() << "\" popped from NotificationQueue '" << this->getName() << "'" << endl;
[7412]268                this->ordering_.erase(it);
269                break;
270            }
271        }
[7403]272        this->notifications_.pop_back();
[2910]273
[7403]274        this->size_--;
275
276        delete container;
277
[8706]278        // Inform that a Notification was popped.
279        this->notificationPopped();
[2911]280    }
[2910]281
[2911]282    /**
283    @brief
[7403]284        Removes the Notification that is stored in the input NotificationContainer.
[7412]285    @param containerIterator
286        An iterator to the NotificationContainer to be removed.
[2911]287    */
[7412]288    void NotificationQueue::remove(const std::multiset<NotificationContainer*, NotificationContainerCompare>::iterator& containerIterator)
[2911]289    {
[7412]290        std::vector<NotificationContainer*>::iterator it = std::find(this->notifications_.begin(), this->notifications_.end(), *containerIterator);
[7403]291        // Get the index at which the Notification is.
292        std::vector<NotificationContainer*>::difference_type index = it - this->notifications_.begin ();
[8079]293
[8858]294        orxout(verbose_more, context::notifications) << "Notification \"" << (*it)->notification->getMessage() << "\" removed from NotificationQueue '" << this->getName() << "'" << endl;
[8079]295
[9253]296        delete *containerIterator;
297
[7412]298        this->ordering_.erase(containerIterator);
[7403]299        this->notifications_.erase(it);
[2911]300
[7403]301        this->size_--;
302
[8706]303        // TODO: index automatically cast?
304        // Inform that a Notification was removed.
305        this->notificationRemoved(index);
[2909]306    }
[2500]307
[2911]308    /**
309    @brief
[7403]310        Clears the NotificationQueue by removing all NotificationContainers.
[7488]311    @param noGraphics
[8706]312        If this is set to true the GUI is not informed of the clearing of the NotificationQueue. This is needed only internally.
[2911]313    */
[7488]314    void NotificationQueue::clear(bool noGraphics)
[2280]315    {
[8858]316        orxout(verbose, context::notifications) << "Clearing NotificationQueue " << this->getName() << "." << endl;
[7403]317        this->ordering_.clear();
318        // Delete all NotificationContainers in the list.
[11071]319        for(NotificationContainer* notification : this->notifications_)
320            delete notification;
[2911]321
[7403]322        this->notifications_.clear();
323        this->size_ = 0;
[2346]324    }
[2500]325
[2911]326    /**
327    @brief
[7403]328        Sets the name of the NotificationQueue.
329    @param name
330        The name to be set.
[2911]331    */
[7403]332    void NotificationQueue::setName(const std::string& name)
[2280]333    {
[7403]334        this->name_ = name;
[2280]335    }
[2500]336
[2911]337    /**
338    @brief
[7403]339        Sets the maximum number of displayed Notifications.
340    @param size
341        The size to be set.
[2911]342    */
[7403]343    void NotificationQueue::setMaxSize(unsigned int size)
[2280]344    {
[7403]345        if(this->maxSize_ == size)
346            return;
[2911]347
[8706]348        if(size == 0)
349        {
[8858]350            orxout(internal_warning, context::notifications) << "Trying to set maximal size of NotificationQueue '" << this->getName() << "' to 0. Ignoring..." << endl;
[8706]351            return;
352        }
[9253]353
[7403]354        this->maxSize_ = size;
[8706]355        this->maxSizeChanged();
356    }
[7403]357
[8706]358    /**
359    @brief
360        Is called when the maximum number of displayed Notifications has changed.
361    */
362    void NotificationQueue::maxSizeChanged(void)
363    {
364        if(this->isRegistered())
[7403]365            this->update();
[2911]366    }
367
368    /**
369    @brief
[7403]370        Sets the maximum number of seconds a Notification is displayed.
[2911]371    @param time
[8706]372        The number of seconds a Notification is displayed.
[2911]373    */
[8706]374    void NotificationQueue::setDisplayTime(int time)
[2911]375    {
[7403]376        if(this->displayTime_ == time)
377            return;
[2911]378
[8706]379        if(time != NotificationQueue::INF && time <= 0)
380        {
[8858]381            orxout(internal_warning, context::notifications) << "Trying to set display time of NotificationQueue '" << this->getName() << "' to non-positive value. Ignoring..." << endl;
[8706]382        }
[9253]383
[7403]384        this->displayTime_ = time;
[8706]385        this->displayTimeChanged();
386    }
[2911]387
[8706]388    /**
389    @brief
390        Is called when the maximum number of seconds a Notification is displayed has changed.
391    */
392    void NotificationQueue::displayTimeChanged(void)
393    {
394        if(this->isRegistered())
[7403]395            this->update();
[2911]396    }
397
398    /**
399    @brief
[8706]400        Produces all targets of the NotificationQueue concatenated as string, with commas (',') as separators.
[2911]401    @return
[7403]402        Returns the targets as a string.
[2911]403    */
[7403]404    const std::string& NotificationQueue::getTargets(void) const
[2911]405    {
[7403]406        std::stringstream stream;
407        bool first = true;
408        // Iterate through the set of targets.
[11071]409        for(const std::string& target : this->targets_)
[7403]410        {
411            if(!first)
412                stream << ", ";
413            else
414                first = false;
[11071]415            stream << target;
[7403]416        }
[2911]417
[7403]418        return *(new std::string(stream.str()));
[2911]419    }
420
421    /**
422    @brief
[7403]423        Sets the targets of the NotificationQueue.
424        The targets are the senders whose Notifications are displayed in this queue.
425    @param targets
[8706]426        Accepts a string of targets, each separated by commas (','), spaces are ignored.
[2911]427    */
[7403]428    void NotificationQueue::setTargets(const std::string & targets)
[2911]429    {
[7403]430        this->targets_.clear();
431
432        SubString string = SubString(targets, ",", " ", false);
433        for(unsigned int i = 0; i < string.size(); i++)
434            this->targets_.insert(string[i]);
435
[8706]436        this->targetsChanged();
437    }
438
439    /**
440    @brief
441        Is called when the NotificationQueue's targets have changed.
442    */
443    void NotificationQueue::targetsChanged(void)
444    {
445        // TODO: Why?
446        if(this->isRegistered())
[2911]447        {
[8706]448            NotificationManager::getInstance().unregisterQueue(this);
449            NotificationManager::getInstance().registerQueue(this);
[2911]450        }
451    }
452
[8706]453    /**
454    @brief
455        Pops all Notifications from the NotificationQueue.
456    @return
457        Returns true if successful, false if not.
458    */
459    bool NotificationQueue::tidy(void)
460    {
461        while(this->size_ > 0)
462            this->pop();
463        return true;
464    }
465
[2280]466}
[7403]467
Note: See TracBrowser for help on using the repository browser.