Merged in f5soh/librepilot/update_credits (pull request #529)
[librepilot.git] / ground / gcs / src / libs / aggregation / aggregate.cpp
blob0a98eb5c3da07133c8422eb707ffa32f31296b6d
1 /**
2 ******************************************************************************
4 * @file aggregate.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
7 * @brief
8 * @see The GNU Public License (GPL) Version 3
9 * @defgroup
10 * @{
12 *****************************************************************************/
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "aggregate.h"
31 #include <QtCore/QWriteLocker>
33 /*!
34 \namespace Aggregation
35 \brief The Aggregation namespace contains support for bundling related components,
36 such that each component exposes the properties and behavior of the
37 other components to the outside.
39 Components that are bundled to an Aggregate can be "cast" to each other
40 and have a coupled life cycle. See the documentation of Aggregation::Aggregate for
41 details and examples.
44 /*!
45 \class Aggregation::Aggregate
46 \mainclass
47 \threadsafe
49 \brief Defines a collection of related components that can be viewed as a unit.
51 An Aggregate is a collection of components that are handled as a unit,
52 such that each component exposes the properties and behavior of the
53 other components in the Aggregate to the outside.
54 Specifically that means:
55 \list
56 \o They can be "cast" to each other (using query and query_all methods).
57 \o Their life cycle is coupled, i.e. whenever one is deleted all of them are.
58 \endlist
59 Components can be of any QObject derived type.
61 You can use an Aggregate to simulate multiple inheritance by aggregation. Assume we have
62 \code
63 using namespace Aggregation;
64 class MyInterface : public QObject { ........ };
65 class MyInterfaceEx : public QObject { ........ };
66 [...]
67 MyInterface *object = new MyInterface; // this is single inheritance
68 \endcode
69 The query method works like a qobject_cast with normal objects:
70 \code
71 Q_ASSERT(query<MyInterface>(object) == object);
72 Q_ASSERT(query<MyInterfaceEx>(object) == 0);
73 \endcode
74 If we want 'object' to also implement the class MyInterfaceEx,
75 but don't want to or cannot use multiple inheritance, we can do it
76 at any point using an Aggregate:
77 \code
78 MyInterfaceEx *objectEx = new MyInterfaceEx;
79 Aggregate *aggregate = new Aggregate;
80 aggregate->add(object);
81 aggregate->add(objectEx);
82 \endcode
83 The Aggregate bundles the two objects together.
84 If we have any part of the collection we get all parts:
85 \code
86 Q_ASSERT(query<MyInterface>(object) == object);
87 Q_ASSERT(query<MyInterfaceEx>(object) == objectEx);
88 Q_ASSERT(query<MyInterface>(objectEx) == object);
89 Q_ASSERT(query<MyInterfaceEx>(objectEx) == objectEx);
90 \endcode
91 The following deletes all three: object, objectEx and aggregate:
92 \code
93 delete objectEx;
94 // or delete object;
95 // or delete aggregate;
96 \endcode
98 Aggregation aware code never uses qobject_cast, but always uses
99 Aggregation::query which behaves like a qobject_cast as a fallback.
103 \fn T *Aggregate::component()
105 Template method that returns the component with the given type, if there is one.
106 If there are multiple components with that type a random one is returned.
108 \sa Aggregate::components()
109 \sa Aggregate::add()
113 \fn QList<T *> Aggregate::components()
115 Template method that returns all components with the given type, if there are any.
117 \sa Aggregate::component()
118 \sa Aggregate::add()
122 \fn T *Aggregation::query<T *>(Aggregate *obj)
123 \internal
127 \fn QList<T *> Aggregation::query_all<T *>(Aggregate *obj)
128 \internal
132 \relates Aggregation::Aggregate
133 \fn T *Aggregation::query<T *>(QObject *obj)
135 Performs a dynamic cast that is aware of a possible Aggregate that \a obj
136 might belong to. If \a obj itself is of the requested type then it is simply cast
137 and returned. Otherwise, if \a obj belongs to an Aggregate all its components are
138 checked, or if it doesn't belong to an Aggregate null is returned.
140 \sa Aggregate::component()
144 \relates Aggregation::Aggregate
145 \fn QList<T *> Aggregation::query_all<T *>(QObject *obj)
147 If \a obj belongs to an Aggregate, all components that can be cast to the given
148 type are returned. Otherwise, \a obj is returned if it is of the requested type.
150 \sa Aggregate::components()
153 using namespace Aggregation;
156 \fn Aggregate *Aggregate::parentAggregate(QObject *obj)
158 Returns the Aggregate object of \a obj if there is one. Otherwise returns 0.
160 Aggregate *Aggregate::parentAggregate(QObject *obj)
162 QReadLocker locker(&lock());
164 return aggregateMap().value(obj);
167 QHash<QObject *, Aggregate *> &Aggregate::aggregateMap()
169 static QHash<QObject *, Aggregate *> map;
171 return map;
175 \fn QReadWriteLock &Aggregate::lock()
176 \internal
178 QReadWriteLock &Aggregate::lock()
180 static QReadWriteLock lock;
182 return lock;
186 \fn Aggregate::Aggregate(QObject *parent)
188 Creates a new Aggregate with the given \a parent.
189 The \a parent is passed directly passed to the QObject part
190 of the class and is not used beside that.
192 Aggregate::Aggregate(QObject *parent)
193 : QObject(parent)
195 QWriteLocker locker(&lock());
197 aggregateMap().insert(this, this);
201 \fn Aggregate::~Aggregate()
203 Deleting the aggregate automatically deletes all its components.
205 Aggregate::~Aggregate()
207 QWriteLocker locker(&lock());
209 foreach(QObject * component, m_components) {
210 disconnect(component, SIGNAL(destroyed(QObject *)), this, SLOT(deleteSelf(QObject *)));
211 aggregateMap().remove(component);
213 qDeleteAll(m_components);
214 m_components.clear();
215 aggregateMap().remove(this);
218 void Aggregate::deleteSelf(QObject *obj)
221 QWriteLocker locker(&lock());
222 aggregateMap().remove(obj);
223 m_components.removeAll(obj);
225 delete this;
229 \fn void Aggregate::add(QObject *component)
231 Adds the \a component to the aggregate.
233 \sa Aggregate::remove()
235 void Aggregate::add(QObject *component)
237 if (!component) {
238 return;
240 QWriteLocker locker(&lock());
241 Aggregate *parentAggregation = aggregateMap().value(component);
242 if (parentAggregation == this) {
243 return;
245 if (parentAggregation) {
246 parentAggregation->remove(component);
248 m_components.append(component);
249 connect(component, SIGNAL(destroyed(QObject *)), this, SLOT(deleteSelf(QObject *)));
250 aggregateMap().insert(component, this);
254 \fn void Aggregate::remove(QObject *component)
256 Removes the \a component from the aggregate.
258 \sa Aggregate::add()
260 void Aggregate::remove(QObject *component)
262 if (!component) {
263 return;
265 QWriteLocker locker(&lock());
266 aggregateMap().remove(component);
267 m_components.removeAll(component);
268 disconnect(component, SIGNAL(destroyed(QObject *)), this, SLOT(deleteSelf(QObject *)));