Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/SuperOrxoBros_HS18/src/modules/notifications/NotificationQueue.cc @ 12177

Last change on this file since 12177 was 12177, checked in by siramesh, 5 years ago

Super Orxo Bros Final (Sidharth Ramesh, Nisa Balta, Jeff Ren)

File size: 15.9 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/XMLPort.h"
41#include "util/SubString.h"
42
43namespace orxonox
44{
45
46    RegisterClass(NotificationQueue);
47
48    /**
49    @brief
50        Default constructor. Registers and initializes the object.
51    */
52    NotificationQueue::NotificationQueue(Context* context) : BaseObject(context), Synchronisable(context), registered_(false)
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);
62
63        this->registerVariables();
64    }
65
66    /**
67    @brief
68        Destructor.
69    */
70    NotificationQueue::~NotificationQueue()
71    {
72        this->targets_.clear();
73
74        if(this->isRegistered()) // If the NotificationQueue is registered.
75        {
76            this->clear(true);
77
78            // Unregister with the NotificationManager.
79            NotificationManager::getInstance().unregisterQueue(this);
80        }
81    }
82
83    /**
84    @brief
85        Is called when the name of the NotificationQueue has changed.
86        Clears and re-creates the NotificationQueue.
87    */
88    void NotificationQueue::changedName(void)
89    {
90        SUPER(NotificationQueue, changedName);
91
92        if(this->isRegistered())
93            this->clear();
94
95        this->create();
96
97        this->targetsChanged();
98        this->maxSizeChanged();
99        this->displayTimeChanged();
100    }
101
102    /**
103    @brief
104        Creates the NotificationQueue.
105    */
106    void NotificationQueue::create(void)
107    {
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;
114            orxout(internal_error, context::notifications) << "NotificationQueue '" << this->getName() << "' could not be registered." << endl;
115            return;
116        }
117
118        orxout(internal_info, context::notifications) << "NotificationQueue '" << this->getName() << "' created." << endl;
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    {
129        this->tickTime_ += dt; // Add the time interval that has passed to the time counter.
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.
131        {
132            this->timeLimit_.time = std::time(0)-this->displayTime_; // Container containing the current time.
133
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.
136            while(it != this->ordering_.upper_bound(&this->timeLimit_))
137            {
138                this->remove(it); // Remove the Notifications that have expired.
139                it = this->ordering_.begin();
140            }
141
142            this->tickTime_ = this->tickTime_ - (int)this->tickTime_; // Reset time counter.
143        }
144    }
145
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    }
154
155
156    /**
157    @brief
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
171        Updates the NotificationQueue.
172        Updates by clearing the queue and requesting all relevant Notifications from the NotificationManager and inserting them into the queue.
173        This is called by the NotificationManager when the Notifications have changed so much, that the NotificationQueue may have to re-initialize his operations.
174    */
175    void NotificationQueue::update(void)
176    {
177        this->clear();
178
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.
181        if(this->displayTime_ == INF)
182            NotificationManager::getInstance().getNewestNotifications(this, notifications, this->getMaxSize());
183        else
184            NotificationManager::getInstance().getNotifications(this, notifications, this->displayTime_);
185
186        if(!notifications->empty())
187        {
188            // Add all Notifications that have been created after this NotificationQueue was created.
189            for(const auto& mapEntry : *notifications)
190            {
191                if(mapEntry.first >= this->creationTime_)
192                    this->push(mapEntry.second, mapEntry.first);
193            }
194        }
195
196        delete notifications;
197
198        orxout(verbose, context::notifications) << "NotificationQueue '" << this->getName() << "' updated." << endl;
199    }
200
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)
210    {
211        assert(notification);
212
213        this->push(notification, time);
214
215        orxout(verbose, context::notifications) << "NotificationQueue '" << this->getName() << "' updated. A new Notification has been added." << endl;
216    }
217
218    /**
219    @brief
220        Adds (pushes) a Notification to the NotificationQueue.
221        It inserts it into the storage containers, creates a corresponding container and pushes the notification message to the GUI.
222    @param notification
223        The Notification to be pushed.
224    @param time
225        The time when the Notification has been sent.
226    */
227    void NotificationQueue::push(Notification* notification, const std::time_t & time)
228    {
229        assert(notification);
230
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
245        // Inform that a Notification was pushed.
246        this->notificationPushed(notification);
247
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;
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
262        // Iterate through all suspects and remove the container as soon as we find it.
263        for(std::multiset<NotificationContainer*, NotificationContainerCompare>::iterator it = iterators.first; it != iterators.second; it++)
264        {
265            if(container == *it)
266            {
267                orxout(verbose_more, context::notifications) << "Notification \"" << (*it)->notification->getMessage() << "\" popped from NotificationQueue '" << this->getName() << "'" << endl;
268                this->ordering_.erase(it);
269                break;
270            }
271        }
272        this->notifications_.pop_back();
273
274        this->size_--;
275
276        delete container;
277
278        // Inform that a Notification was popped.
279        this->notificationPopped();
280    }
281
282    /**
283    @brief
284        Removes the Notification that is stored in the input NotificationContainer.
285    @param containerIterator
286        An iterator to the NotificationContainer to be removed.
287    */
288    void NotificationQueue::remove(const std::multiset<NotificationContainer*, NotificationContainerCompare>::iterator& containerIterator)
289    {
290        std::vector<NotificationContainer*>::iterator it = std::find(this->notifications_.begin(), this->notifications_.end(), *containerIterator);
291        // Get the index at which the Notification is.
292        std::vector<NotificationContainer*>::difference_type index = it - this->notifications_.begin ();
293
294        orxout(verbose_more, context::notifications) << "Notification \"" << (*it)->notification->getMessage() << "\" removed from NotificationQueue '" << this->getName() << "'" << endl;
295
296        delete *containerIterator;
297
298        this->ordering_.erase(containerIterator);
299        this->notifications_.erase(it);
300
301        this->size_--;
302
303        // TODO: index automatically cast?
304        // Inform that a Notification was removed.
305        this->notificationRemoved(index);
306    }
307
308    /**
309    @brief
310        Clears the NotificationQueue by removing all NotificationContainers.
311    @param noGraphics
312        If this is set to true the GUI is not informed of the clearing of the NotificationQueue. This is needed only internally.
313    */
314    void NotificationQueue::clear(bool noGraphics)
315    {
316        orxout(verbose, context::notifications) << "Clearing NotificationQueue " << this->getName() << "." << endl;
317        this->ordering_.clear();
318        // Delete all NotificationContainers in the list.
319        for(NotificationContainer* notification : this->notifications_)
320            delete notification;
321
322        this->notifications_.clear();
323        this->size_ = 0;
324    }
325
326    /**
327    @brief
328        Sets the name of the NotificationQueue.
329    @param name
330        The name to be set.
331    */
332    void NotificationQueue::setName(const std::string& name)
333    {
334        this->name_ = name;
335    }
336
337    /**
338    @brief
339        Sets the maximum number of displayed Notifications.
340    @param size
341        The size to be set.
342    */
343    void NotificationQueue::setMaxSize(unsigned int size)
344    {
345        if(this->maxSize_ == size)
346            return;
347
348        if(size == 0)
349        {
350            orxout(internal_warning, context::notifications) << "Trying to set maximal size of NotificationQueue '" << this->getName() << "' to 0. Ignoring..." << endl;
351            return;
352        }
353
354        this->maxSize_ = size;
355        this->maxSizeChanged();
356    }
357
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())
365            this->update();
366    }
367
368    /**
369    @brief
370        Sets the maximum number of seconds a Notification is displayed.
371    @param time
372        The number of seconds a Notification is displayed.
373    */
374    void NotificationQueue::setDisplayTime(int time)
375    {
376        if(this->displayTime_ == time)
377            return;
378
379        if(time != NotificationQueue::INF && time <= 0)
380        {
381            orxout(internal_warning, context::notifications) << "Trying to set display time of NotificationQueue '" << this->getName() << "' to non-positive value. Ignoring..." << endl;
382        }
383
384        this->displayTime_ = time;
385        this->displayTimeChanged();
386    }
387
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())
395            this->update();
396    }
397
398    /**
399    @brief
400        Produces all targets of the NotificationQueue concatenated as string, with commas (',') as separators.
401    @return
402        Returns the targets as a string.
403    */
404    const std::string& NotificationQueue::getTargets(void) const
405    {
406        std::stringstream stream;
407        bool first = true;
408        // Iterate through the set of targets.
409        for(const std::string& target : this->targets_)
410        {
411            if(!first)
412                stream << ", ";
413            else
414                first = false;
415            stream << target;
416        }
417
418        return *(new std::string(stream.str()));
419    }
420
421    /**
422    @brief
423        Sets the targets of the NotificationQueue.
424        The targets are the senders whose Notifications are displayed in this queue.
425    @param targets
426        Accepts a string of targets, each separated by commas (','), spaces are ignored.
427    */
428    void NotificationQueue::setTargets(const std::string & targets)
429    {
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
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())
447        {
448            NotificationManager::getInstance().unregisterQueue(this);
449            NotificationManager::getInstance().registerQueue(this);
450        }
451    }
452
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
466}
467
Note: See TracBrowser for help on using the repository browser.