1 | /* |
2 | * The Type2Type template and the Inheritance Detector are from |
3 | * <http://www.cuj.com/experts/1810/alexandr.htm> |
4 | * (c) Andrei Alexandrescu <andrei@metalanguage.com> and |
5 | * free for any use. |
6 | * |
7 | * The rest is: |
8 | * Copyright (C) 2001 Simon Hausmann <hausmann@kde.org> |
9 | * |
10 | * This library is free software; you can redistribute it and/or |
11 | * modify it under the terms of the GNU Library General Public |
12 | * License as published by the Free Software Foundation; either |
13 | * version 2 of the License, or (at your option) any later version. |
14 | * |
15 | * This library is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 | * Library General Public License for more details. |
19 | * |
20 | * You should have received a copy of the GNU Library General Public License |
21 | * along with this library; see the file COPYING.LIB. If not, write to |
22 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
23 | * Boston, MA 02110-1301, USA. |
24 | */ |
25 | // -*- mode: c++ -*- |
26 | // |
27 | // W A R N I N G |
28 | // ------------- |
29 | // |
30 | // This file is not part of the KDE API. It exists for the convenience |
31 | // of KGenericFactory. This header file may change from version to |
32 | // version without notice, or even be removed. |
33 | // |
34 | // We mean it. |
35 | // |
36 | |
37 | #ifndef KGENERICFACTORY_TCC |
38 | #define KGENERICFACTORY_TCC |
39 | |
40 | #include <QtCore/QMetaObject> |
41 | #include <ktypelist.h> |
42 | #include "kdebug.h" |
43 | |
44 | namespace KParts |
45 | { |
46 | class Part; |
47 | } |
48 | |
49 | #ifndef KDE_NO_DEPRECATED |
50 | namespace KDEPrivate |
51 | { |
52 | template <class Base> |
53 | struct InheritanceDetector |
54 | { |
55 | typedef char ConversionExists; |
56 | struct ConversionDoesNotExist { char bleh[ 2 ]; }; |
57 | static ConversionExists test( Base * ); |
58 | static ConversionDoesNotExist test( ... ); |
59 | }; |
60 | |
61 | /* Simon: KCC doesn't eat the generic InheritanceDetector<Base>. |
62 | Instead we have to use concrete specializations :-( |
63 | |
64 | template <class Base, class Derived> |
65 | struct InheritanceTest |
66 | { |
67 | typedef Derived * DerivedPtr; |
68 | enum { Result = sizeof( InheritanceDetector<Base>::test( DerivedPtr() ) ) == |
69 | sizeof( InheritanceDetector<Base>::ConversionExists ) }; |
70 | }; |
71 | */ |
72 | |
73 | template <class Derived> |
74 | struct QWidgetInheritanceTest |
75 | { |
76 | typedef Derived * DerivedPtr; |
77 | enum { Result = sizeof( InheritanceDetector<QWidget>::test( DerivedPtr() ) ) == |
78 | sizeof( InheritanceDetector<QWidget>::ConversionExists ) }; |
79 | }; |
80 | |
81 | template <class Derived> |
82 | struct PartInheritanceTest |
83 | { |
84 | typedef Derived * DerivedPtr; |
85 | enum { Result = sizeof( InheritanceDetector<KParts::Part>::test( DerivedPtr() ) ) == |
86 | sizeof( InheritanceDetector<KParts::Part>::ConversionExists ) }; |
87 | }; |
88 | |
89 | |
90 | template <bool condition, typename Then, typename Else> |
91 | struct If |
92 | { |
93 | typedef Else Result; |
94 | }; |
95 | |
96 | template <typename Then, typename Else> |
97 | struct If<true, Then, Else> |
98 | { |
99 | typedef Then Result; |
100 | }; |
101 | |
102 | // a small helper template, to ease the overloading done in ConcreteFactory |
103 | // to choose the right constructor for the given class. |
104 | template <class T> |
105 | struct Type2Type |
106 | { |
107 | typedef T OriginalType; |
108 | }; |
109 | |
110 | |
111 | // this template is called from the MultiFactory one. It instantiates |
112 | // the given class if the className matches. Instantiating is done by |
113 | // calling the right constructor (a parentwidget/parent |
114 | // one for Parts, a parentwidget one for widgets and last |
115 | // but not least the standard default constructor with a parent . |
116 | // the choice of the right constructor is done using an ordered inheritance |
117 | // test. |
118 | template <class Product, class ParentType = QObject> |
119 | class ConcreteFactory |
120 | { |
121 | public: |
122 | typedef typename If< PartInheritanceTest< Product >::Result, |
123 | KParts::Part, |
124 | typename If< QWidgetInheritanceTest< Product >::Result, |
125 | QWidget, QObject >::Result >::Result BaseType; |
126 | |
127 | static inline Product *create( QWidget *parentWidget, |
128 | QObject *parent, |
129 | const char *className, const QStringList &args ) |
130 | { |
131 | const QMetaObject* metaObject = &Product::staticMetaObject; |
132 | while ( metaObject ) |
133 | { |
134 | //kDebug(150) << "className=" << className << " metaObject->className()=" << metaObject->className() << endl; |
135 | if ( !qstrcmp( className, metaObject->className() ) ) |
136 | return create( parentWidget, |
137 | parent, args, Type2Type<BaseType>() ); |
138 | metaObject = metaObject->superClass(); |
139 | } |
140 | //kDebug(150) << "error, returning 0" << endl; |
141 | return 0; |
142 | } |
143 | private: |
144 | typedef typename If< QWidgetInheritanceTest<ParentType>::Result, |
145 | ParentType, QWidget >::Result WidgetParentType; |
146 | |
147 | static inline Product *create( QWidget *parentWidget, |
148 | QObject *parent, |
149 | const QStringList &args, Type2Type<KParts::Part> ) |
150 | { |
151 | //kDebug(150) << "create - 1" << endl; |
152 | return new Product( parentWidget, parent, args ); |
153 | } |
154 | |
155 | static inline Product *create( QWidget* /*parentWidget*/, |
156 | QObject *parent, |
157 | const QStringList &args, Type2Type<QWidget> ) |
158 | { |
159 | //kDebug(150) << "create - 2" << endl; |
160 | WidgetParentType *p = dynamic_cast<WidgetParentType *>( parent ); |
161 | if ( parent && !p ) |
162 | return 0; |
163 | return new Product( p, args ); |
164 | } |
165 | |
166 | static inline Product *create( QWidget* /*parentWidget*/, |
167 | QObject *parent, |
168 | const QStringList &args, Type2Type<QObject> ) |
169 | { |
170 | //kDebug(150) << "create - 3" << endl; |
171 | ParentType *p = dynamic_cast<ParentType *>( parent ); |
172 | if ( parent && !p ) |
173 | return 0; |
174 | return new Product( p, args ); |
175 | } |
176 | }; |
177 | |
178 | // this template is used to iterate through the typelist and call the |
179 | // concrete factory for each type. the specializations of this template |
180 | // are the ones actually being responsible for iterating, in fact. |
181 | template <class Product, class ParentType = QObject> |
182 | class MultiFactory |
183 | { |
184 | public: |
185 | inline static QObject *create( QWidget *parentWidget, |
186 | QObject *parent, |
187 | const char *className, |
188 | const QStringList &args ) |
189 | { |
190 | return ConcreteFactory<Product, ParentType>::create( parentWidget, |
191 | parent, className, |
192 | args ); |
193 | } |
194 | |
195 | }; |
196 | |
197 | // this specialized template we 'reach' at the end of a typelist |
198 | // (the last item in a typelist is the NullType) |
199 | template <> |
200 | class MultiFactory<KDE::NullType> |
201 | { |
202 | public: |
203 | inline static QObject *create( QWidget *, QObject *, |
204 | const char *, |
205 | const QStringList & ) |
206 | { return 0; } |
207 | }; |
208 | |
209 | // this specialized template we 'reach' at the end of a typelist |
210 | // (the last item in a typelist is the NullType) |
211 | template <> |
212 | class MultiFactory<KDE::NullType, KDE::NullType> |
213 | { |
214 | public: |
215 | inline static QObject *create( QWidget *, QObject *, |
216 | const char *, |
217 | const QStringList & ) |
218 | { return 0; } |
219 | }; |
220 | |
221 | template <class Product, class ProductListTail> |
222 | class MultiFactory< KTypeList<Product, ProductListTail>, QObject > |
223 | { |
224 | public: |
225 | inline static QObject *create( QWidget *parentWidget, |
226 | QObject *parent, |
227 | const char *className, |
228 | const QStringList &args ) |
229 | { |
230 | // try with the head of the typelist first. the head is always |
231 | // a concrete type. |
232 | QObject *object = MultiFactory<Product>::create( parentWidget, |
233 | parent, className, |
234 | args ); |
235 | |
236 | if ( !object ) |
237 | object = MultiFactory<ProductListTail>::create( parentWidget, |
238 | parent, className, |
239 | args ); |
240 | |
241 | return object; |
242 | } |
243 | }; |
244 | |
245 | template <class Product, class ProductListTail, |
246 | class ParentType, class ParentTypeListTail> |
247 | class MultiFactory< KTypeList<Product, ProductListTail>, |
248 | KTypeList<ParentType, ParentTypeListTail> > |
249 | { |
250 | public: |
251 | inline static QObject *create( QWidget *parentWidget, |
252 | QObject *parent, |
253 | const char *className, |
254 | const QStringList &args ) |
255 | { |
256 | // try with the head of the typelist first. the head is always |
257 | // a concrete type. |
258 | QObject *object = MultiFactory<Product, ParentType> |
259 | ::create( parentWidget, |
260 | parent, className, args ); |
261 | |
262 | // if that failed continue by advancing the typelist, calling this |
263 | // template specialization recursively (with T2 being a typelist) . |
264 | // at the end we reach the nulltype specialization. |
265 | if ( !object ) |
266 | object = MultiFactory<ProductListTail, ParentTypeListTail> |
267 | ::create( parentWidget, |
268 | parent, className, args ); |
269 | |
270 | return object; |
271 | } |
272 | }; |
273 | } |
274 | |
275 | #endif |
276 | |
277 | #endif |
278 | |