Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation/src/modules/notifications/NotificationQueue.cc @ 8661

Last change on this file since 8661 was 8656, checked in by dafrick, 14 years ago

Adding network callbacks. Still doesn't work yet, though.

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