OSDN Git Service

d4baeeda16831066bfdf9219cfde64127af9946c
[qt-creator-jp/qt-creator-jp.git] / src / libs / aggregation / aggregate.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "aggregate.h"
35
36 #include <QtCore/QWriteLocker>
37
38 /*!
39     \namespace Aggregation
40     \brief The Aggregation namespace contains support for bundling related components,
41            such that each component exposes the properties and behavior of the
42            other components to the outside.
43
44     Components that are bundled to an Aggregate can be "cast" to each other
45     and have a coupled life cycle. See the documentation of Aggregation::Aggregate for
46     details and examples.
47 */
48
49 /*!
50     \class Aggregation::Aggregate
51     \mainclass
52     \threadsafe
53
54     \brief Defines a collection of related components that can be viewed as a unit.
55
56     An Aggregate is a collection of components that are handled as a unit,
57     such that each component exposes the properties and behavior of the
58     other components in the Aggregate to the outside.
59     Specifically that means:
60     \list
61     \o They can be "cast" to each other (using query and query_all methods).
62     \o Their life cycle is coupled, i.e. whenever one is deleted all of them are.
63     \endlist
64     Components can be of any QObject derived type.
65
66     You can use an Aggregate to simulate multiple inheritance by aggregation. Assume we have
67     \code
68         using namespace Aggregation;
69         class MyInterface : public QObject { ........ };
70         class MyInterfaceEx : public QObject { ........ };
71         [...]
72         MyInterface *object = new MyInterface; // this is single inheritance
73     \endcode
74     The query method works like a qobject_cast with normal objects:
75     \code
76         Q_ASSERT(query<MyInterface>(object) == object);
77         Q_ASSERT(query<MyInterfaceEx>(object) == 0);
78     \endcode
79     If we want 'object' to also implement the class MyInterfaceEx,
80     but don't want to or cannot use multiple inheritance, we can do it
81     at any point using an Aggregate:
82     \code
83         MyInterfaceEx *objectEx = new MyInterfaceEx;
84         Aggregate *aggregate = new Aggregate;
85         aggregate->add(object);
86         aggregate->add(objectEx);
87     \endcode
88     The Aggregate bundles the two objects together.
89     If we have any part of the collection we get all parts:
90     \code
91         Q_ASSERT(query<MyInterface>(object) == object);
92         Q_ASSERT(query<MyInterfaceEx>(object) == objectEx);
93         Q_ASSERT(query<MyInterface>(objectEx) == object);
94         Q_ASSERT(query<MyInterfaceEx>(objectEx) == objectEx);
95     \endcode
96     The following deletes all three: object, objectEx and aggregate:
97     \code
98         delete objectEx;
99         // or delete object;
100         // or delete aggregate;
101     \endcode
102
103     Aggregation aware code never uses qobject_cast, but always uses
104     Aggregation::query which behaves like a qobject_cast as a fallback.
105 */
106
107 /*!
108     \fn T *Aggregate::component()
109
110     Template method that returns the component with the given type, if there is one.
111     If there are multiple components with that type a random one is returned.
112
113     \sa Aggregate::components()
114     \sa Aggregate::add()
115 */
116
117 /*!
118     \fn QList<T *> Aggregate::components()
119
120     Template method that returns all components with the given type, if there are any.
121
122     \sa Aggregate::component()
123     \sa Aggregate::add()
124 */
125
126 /*!
127     \fn T *Aggregation::query<T *>(Aggregate *obj)
128     \internal
129 */
130
131 /*!
132     \fn QList<T *> Aggregation::query_all<T *>(Aggregate *obj)
133     \internal
134 */
135
136 /*!
137     \relates Aggregation::Aggregate
138     \fn T *Aggregation::query<T *>(QObject *obj)
139
140     Performs a dynamic cast that is aware of a possible Aggregate that \a obj
141     might belong to. If \a obj itself is of the requested type then it is simply cast
142     and returned. Otherwise, if \a obj belongs to an Aggregate all its components are
143     checked, or if it doesn't belong to an Aggregate null is returned.
144
145     \sa Aggregate::component()
146 */
147
148 /*!
149     \relates Aggregation::Aggregate
150     \fn QList<T *> Aggregation::query_all<T *>(QObject *obj)
151
152     If \a obj belongs to an Aggregate, all components that can be cast to the given
153     type are returned. Otherwise, \a obj is returned if it is of the requested type.
154
155     \sa Aggregate::components()
156 */
157
158 using namespace Aggregation;
159
160 /*!
161     \fn Aggregate *Aggregate::parentAggregate(QObject *obj)
162
163     Returns the Aggregate object of \a obj if there is one. Otherwise returns 0.
164 */
165 Aggregate *Aggregate::parentAggregate(QObject *obj)
166 {
167     QReadLocker locker(&lock());
168     return aggregateMap().value(obj);
169 }
170
171 QHash<QObject *, Aggregate *> &Aggregate::aggregateMap()
172 {
173     static QHash<QObject *, Aggregate *> map;
174     return map;
175 }
176
177 /*!
178     \fn QReadWriteLock &Aggregate::lock()
179     \internal
180 */
181 QReadWriteLock &Aggregate::lock()
182 {
183     static QReadWriteLock lock;
184     return lock;
185 }
186
187 /*!
188     \fn Aggregate::Aggregate(QObject *parent)
189
190     Creates a new Aggregate with the given \a parent.
191     The \a parent is passed directly passed to the QObject part
192     of the class and is not used beside that.
193 */
194 Aggregate::Aggregate(QObject *parent)
195     : QObject(parent)
196 {
197     QWriteLocker locker(&lock());
198     aggregateMap().insert(this, this);
199 }
200
201 /*!
202     \fn Aggregate::~Aggregate()
203
204     Deleting the aggregate automatically deletes all its components.
205 */
206 Aggregate::~Aggregate()
207 {
208     QWriteLocker locker(&lock());
209     foreach (QObject *component, m_components) {
210         disconnect(component, SIGNAL(destroyed(QObject*)), this, SLOT(deleteSelf(QObject*)));
211         aggregateMap().remove(component);
212     }
213     qDeleteAll(m_components);
214     m_components.clear();
215     aggregateMap().remove(this);
216 }
217
218 void Aggregate::deleteSelf(QObject *obj)
219 {
220     {
221         QWriteLocker locker(&lock());
222         aggregateMap().remove(obj);
223         m_components.removeAll(obj);
224     }
225     delete this;
226 }
227
228 /*!
229     \fn void Aggregate::add(QObject *component)
230
231     Adds the \a component to the aggregate.
232
233     \sa Aggregate::remove()
234 */
235 void Aggregate::add(QObject *component)
236 {
237     if (!component)
238         return;
239     {
240         QWriteLocker locker(&lock());
241         Aggregate *parentAggregation = aggregateMap().value(component);
242         if (parentAggregation == this)
243             return;
244         if (parentAggregation)
245             parentAggregation->remove(component);
246         m_components.append(component);
247         connect(component, SIGNAL(destroyed(QObject*)), this, SLOT(deleteSelf(QObject*)));
248         aggregateMap().insert(component, this);
249     }
250     emit changed();
251 }
252
253 /*!
254     \fn void Aggregate::remove(QObject *component)
255
256     Removes the \a component from the aggregate.
257
258     \sa Aggregate::add()
259 */
260 void Aggregate::remove(QObject *component)
261 {
262     if (!component)
263         return;
264     {
265         QWriteLocker locker(&lock());
266         aggregateMap().remove(component);
267         m_components.removeAll(component);
268         disconnect(component, SIGNAL(destroyed(QObject*)), this, SLOT(deleteSelf(QObject*)));
269     }
270     emit changed();
271 }