2 ******************************************************************************
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
8 * @see The GNU Public License (GPL) Version 3
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
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>
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
45 \class Aggregation::Aggregate
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:
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.
59 Components can be of any QObject derived type.
61 You can use an Aggregate to simulate multiple inheritance by aggregation. Assume we have
63 using namespace Aggregation;
64 class MyInterface : public QObject { ........ };
65 class MyInterfaceEx : public QObject { ........ };
67 MyInterface *object = new MyInterface; // this is single inheritance
69 The query method works like a qobject_cast with normal objects:
71 Q_ASSERT(query<MyInterface>(object) == object);
72 Q_ASSERT(query<MyInterfaceEx>(object) == 0);
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:
78 MyInterfaceEx *objectEx = new MyInterfaceEx;
79 Aggregate *aggregate = new Aggregate;
80 aggregate->add(object);
81 aggregate->add(objectEx);
83 The Aggregate bundles the two objects together.
84 If we have any part of the collection we get all parts:
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);
91 The following deletes all three: object, objectEx and aggregate:
95 // or delete aggregate;
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()
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()
122 \fn T *Aggregation::query<T *>(Aggregate *obj)
127 \fn QList<T *> Aggregation::query_all<T *>(Aggregate *obj)
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
;
175 \fn QReadWriteLock &Aggregate::lock()
178 QReadWriteLock
&Aggregate::lock()
180 static QReadWriteLock 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
)
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
);
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
)
240 QWriteLocker
locker(&lock());
241 Aggregate
*parentAggregation
= aggregateMap().value(component
);
242 if (parentAggregation
== this) {
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.
260 void Aggregate::remove(QObject
*component
)
265 QWriteLocker
locker(&lock());
266 aggregateMap().remove(component
);
267 m_components
.removeAll(component
);
268 disconnect(component
, SIGNAL(destroyed(QObject
*)), this, SLOT(deleteSelf(QObject
*)));