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
44namespace KParts
45{
46 class Part;
47}
48
49#ifndef KDE_NO_DEPRECATED
50namespace 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