comparison d2/qt/core/QMetaObject.d @ 368:185df9220ea7

Fixed startsWith. Implemented meta-object members as ranges. Freed QMetaObject from stuff that belongs to MetaClass
author Max Samukha <maxter@maxter.com>
date Mon, 28 Jun 2010 21:29:32 +0300
parents f69341b40588
children 6e1857c521af
comparison
equal deleted inserted replaced
367:f69341b40588 368:185df9220ea7
12 std.typetuple, 12 std.typetuple,
13 std.traits, 13 std.traits,
14 std.c.stdlib; 14 std.c.stdlib;
15 15
16 import std.string : indexOf; 16 import std.string : indexOf;
17 17 import std.algorithm : filter;
18 class QMetaArgument : Meta 18
19 { 19 //TODO: remove
20 } 20 import std.stdio;
21 21
22 class QMetaMethod : Meta 22 class QMetaArgument : MetaBase
23 {
24 }
25
26 class QMetaMethod : MetaBase
23 { 27 {
24 alias typeof(this) This; 28 alias typeof(this) This;
25 29
26 // QMetaArgument[] arguments; 30 // QMetaArgument[] arguments;
27 string signature; 31 string signature;
28 int indexOfMethod; 32 int index;
29 33
30 this(string signature_, int indexOfMethod_) 34 this(string signature, int index)
31 { 35 {
32 signature = signature_; 36 this.signature = signature;
33 indexOfMethod = indexOfMethod_; 37 this.index = index;
38
39 int openBracket = indexOf(signature, '(');
40 name = signature[0..openBracket];
34 } 41 }
35 42
36 string args() const 43 string args() const
37 { 44 {
38 int openBracket = indexOf(signature, '('); 45 int openBracket = indexOf(signature, '(');
40 return signature[openBracket + 1 .. $-1]; 47 return signature[openBracket + 1 .. $-1];
41 else 48 else
42 return ""; 49 return "";
43 } 50 }
44 51
45 string name() const 52 static M create(alias method, M : This)(uint index)
46 {
47 int openBracket = indexOf(signature, '(');
48 return signature[0..openBracket];
49 }
50
51 // mixin(Derived) or typeof(Derived) would help a lot here
52 static create(alias method, M : This)(uint index)
53 { 53 {
54 alias ParameterTypeTuple!method Args; 54 alias ParameterTypeTuple!method Args;
55 return new M(.signature!(Args)(methodName!(method)), index); 55 return new M(.signature!(Args)(methodName!(method)), index);
56 } 56 }
57 } 57 }
58 58
59 /**
60 */
59 class QMetaSignal : QMetaMethod 61 class QMetaSignal : QMetaMethod
60 { 62 {
61 alias typeof(this) This; 63 alias typeof(this) This;
62 64
63 this(string signature_, int indexOfMethod_) 65 this(string signature, int indexOfMethod)
64 { 66 {
65 super(signature_, indexOfMethod_); 67 super(signature, indexOfMethod);
66 } 68 }
67 69
68 static This create(alias method)(uint index) 70 static This create(alias method)(uint index)
69 { 71 {
70 return typeof(super).create!(method, This)(index); 72 return typeof(super).create!(method, This)(index);
73 75
74 class QMetaSlot : QMetaMethod 76 class QMetaSlot : QMetaMethod
75 { 77 {
76 alias typeof(this) This; 78 alias typeof(this) This;
77 79
78 this(string signature_, int indexOfMethod_) 80 this(string signature, int indexOfMethod)
79 { 81 {
80 super(signature_, indexOfMethod_); 82 super(signature, indexOfMethod);
81 } 83 }
82 84
83 static This create(alias method)(uint index) 85 static This create(alias method)(uint index)
84 { 86 {
85 return typeof(super).create!(method, This)(index); 87 return typeof(super).create!(method, This)(index);
86 } 88 }
87 } 89 }
88 90
89 class MetaObject : MetaType 91 /**
90 { 92 Base class for QtD meta-classes.
91 MetaObject _base; 93 */
94 abstract class QtdMetaClass : MetaClass
95 {
96 private:
97 void* nativeId_;
98
99 public:
100
101 this() {}
102
103 /**
104 */
105 @property
106 void* nativeId()
107 {
108 return nativeId_;
109 }
110
111 void construct(T)()
112 {
113 super.construct!T();
114 nativeId_ = T.qtd_nativeStaticMetaObject();
115 }
92 } 116 }
93 117
94 struct QMetaObjectNative 118 struct QMetaObjectNative
95 { 119 {
96 QMetaObjectNative *superdata; 120 QMetaObjectNative *superdata;
97 immutable(char) *stringdata; 121 immutable(char) *stringdata;
98 const(uint) *data; 122 const(uint) *data;
99 void *extradata; 123 void *extradata;
100 } 124 }
101 125
102 class QMetaException : Exception { this(string msg) { super(msg); } } 126
103 127 /**
104 final class QMetaObject 128 */
129 final class QMetaObject : QtdMetaClass
105 { 130 {
106 alias typeof(this) This; 131 alias typeof(this) This;
107 132
108 private this() {} 133 private QObject function(void* nativeId) _createWrapper;
134
135 this() {}
109 136
110 enum Call 137 enum Call
111 { 138 {
112 InvokeMetaMethod, 139 InvokeMetaMethod,
113 ReadProperty, 140 ReadProperty,
119 QueryPropertyEditable, 146 QueryPropertyEditable,
120 QueryPropertyUser, 147 QueryPropertyUser,
121 CreateInstance 148 CreateInstance
122 } 149 }
123 150
124 private 151 alias createImpl!This create;
125 { 152
126 QMetaObjectNative* _nativeId; 153 void construct(T : QObject)()
127 QMetaObject _base; // super class 154 {
128 QMetaObject _firstDerived; // head of the linked list of derived classes 155 super.construct!T();
129 QMetaObject _next; // next sibling on this derivation level
130 QMetaMethod[] _methods;
131 ClassInfo _classInfo;
132
133 QObject function(void* nativeId) _createWrapper;
134 }
135
136 private void addDerived(QMetaObject mo)
137 {
138 mo._next = _firstDerived;
139 _firstDerived = mo;
140 }
141
142 // ctor
143 void construct(T : QObject)(void* nativeId)
144 {
145 alias BaseClassesTuple!(T)[0] Base;
146 This base;
147 static if (is(Base : QObject))
148 base = Base.staticMetaObject;
149
150 _nativeId = cast(QMetaObjectNative*)nativeId;
151 T.setStaticMetaObject(this);
152
153 if (base)
154 {
155 base.addDerived(this);
156 _base = base;
157 }
158 _classInfo = T.classinfo;
159
160 156
161 static if (isQtType!T) 157 static if (isQtType!T)
162 { 158 {
163 static if (is(T.ConcreteType)) 159 static if (is(T.ConcreteType))
164 alias T.ConcreteType Concrete; 160 alias T.ConcreteType Concrete;
169 auto obj = new Concrete(nativeId, cast(QtdObjectFlags)(QtdObjectFlags.nativeOwnership | QtdObjectFlags.dynamicEntity)); 165 auto obj = new Concrete(nativeId, cast(QtdObjectFlags)(QtdObjectFlags.nativeOwnership | QtdObjectFlags.dynamicEntity));
170 T.__createEntity(nativeId, cast(void*)obj); 166 T.__createEntity(nativeId, cast(void*)obj);
171 return obj; 167 return obj;
172 }; 168 };
173 169
174 T._populateMetaInfo; 170 T._populateMetaInfo(this);
175 } 171 }
176 // create run time meta-objects for user-defined signals and slots 172 // create run time meta-objects for user-defined signals and slots
177 else static if (is(typeof(T.methods))) 173 else static if (is(typeof(T.methods)))
178 { 174 {
179 int index = Base.staticMetaObject().methodCount(); 175 alias BaseClassesTuple!(T)[0] Base;
176 int index = meta!(Base).methodCount;
180 177
181 static if (T.signals.length) 178 static if (T.signals.length)
182 { 179 {
183 foreach (signal; T.signals) 180 foreach (signal; T.signals)
184 { 181 {
196 } 193 }
197 } 194 }
198 } 195 }
199 } 196 }
200 197
201 // new 198 /**
202 static This create(T : QObject)(void* nativeId) 199 */
203 { 200 @property
204 auto m = new This(); 201 override This next()
205 m.construct!T(nativeId); 202 {
206 return m; 203 return static_cast!This(super.next);
207 } 204 }
208 205
209 /++ 206 /**
210 +/ 207 */
211 QMetaObject base() 208 @property
212 { 209 override This firstDerived()
213 return _base; 210 {
214 } 211 return static_cast!This(super.firstDerived);
215 212 }
216 /++ 213
217 +/ 214 void addMethod(QMetaMethod method)
215 {
216 members_ ~= method;
217 }
218
219 /**
220 */
221 @property
222 override This base()
223 {
224 return super.base;
225 }
226
227 /**
228 */
229 @property
218 QMetaObjectNative* nativeId() 230 QMetaObjectNative* nativeId()
219 { 231 {
220 return _nativeId; 232 return cast(QMetaObjectNative*)super.nativeId;
221 } 233 }
222 234
223 /++ 235 M lookUpMethod(M : QMetaMethod = QMetaMethod)(string signature)
224 +/ 236 {
225 ClassInfo classInfo() 237 foreach (method; allMembers)
226 { 238 {
227 return _classInfo; 239 if (auto m = cast(M)method)
228 } 240 {
229 241 if (m.signature == signature)
230 const (QMetaMethod[]) methods() 242 return m;
231 { 243 }
232 return _methods; 244 }
233 } 245 return null;
234 246 }
235 void addMethod(QMetaMethod method_) 247
236 { 248 // TODO: probably make this return a filtering range.
237 _methods ~= method_; 249 auto lookUpMethodOverloads(M : QMetaMethod = QMetaMethod)(string name)
238 } 250 {
239 251 M[] methods;
240 QMetaMethod lookUpMethod(string slot) 252 foreach (m; allMembers)
241 { 253 {
242 foreach (method; _methods) 254 if (auto method = cast(M)m)
243 if (method.signature == slot) 255 {
244 return method; 256 if (method.name == name)
245 if (_base) 257 methods ~= method;
246 return _base.lookUpMethod(slot); 258 }
247 else 259 }
248 return null; 260 return methods;
249 } 261 }
250 262
251 QMetaSignal lookUpSignal(string signal) 263 private QMetaObject lookUpDerived(void*[] moIds)
252 {
253 foreach (method; _methods)
254 if (method.signature == signal && cast(QMetaSignal)method)
255 return cast(QMetaSignal)method;
256 if (_base)
257 return _base.lookUpSignal(signal);
258 else
259 return null;
260 }
261
262 QMetaMethod[] lookUpMethodOverloads(string methodName)
263 {
264 typeof(return) result;
265 foreach (method; _methods)
266 if (method.name == methodName)
267 result ~= method;
268 if (_base)
269 result ~= _base.lookUpMethodOverloads(methodName);
270 return result;
271 }
272
273 QMetaSignal[] lookUpSignalOverloads(string signalName)
274 {
275 typeof(return) result;
276 foreach (method; _methods)
277 if (method.name == signalName && cast(QMetaSignal)method)
278 result ~= cast(QMetaSignal)method;
279 if (_base)
280 result ~= _base.lookUpSignalOverloads(signalName);
281 return result;
282 }
283
284 private QMetaObject lookupDerived(void*[] moIds)
285 { 264 {
286 assert (moIds.length >= 1); 265 assert (moIds.length >= 1);
287 266
288 for (auto mo = _firstDerived; mo !is null; mo = mo._next) 267 for (auto mo = firstDerived; mo !is null; mo = mo.next)
289 { 268 {
290 if (mo._nativeId == moIds[0]) 269 if (mo.nativeId == moIds[0])
291 { 270 {
292 if (moIds.length == 1) // exact match found 271 if (moIds.length == 1) // exact match found
293 return mo; 272 return mo;
294 else // look deeper 273 else // look deeper
295 return mo.lookupDerived(moIds[1..$]); 274 return mo.lookUpDerived(moIds[1..$]);
296 } 275 }
297 } 276 }
298 277
299 // no initialized wrapper that matches the native object. 278 // no initialized wrapper that matches the native object.
300 // use the base class wrapper 279 // use the base class wrapper
309 { 288 {
310 result = cast(QObject)qtd_get_d_qobject(nativeObjId); 289 result = cast(QObject)qtd_get_d_qobject(nativeObjId);
311 if (!result) 290 if (!result)
312 { 291 {
313 auto moId = qtd_QObject_metaObject(nativeObjId); 292 auto moId = qtd_QObject_metaObject(nativeObjId);
314 if (_nativeId == moId) 293 auto nId = nativeId;
294 if (nId == moId)
315 result = _createWrapper(nativeObjId); 295 result = _createWrapper(nativeObjId);
316 else 296 else
317 { 297 {
318 // get native metaobjects for the entire derivation lattice 298 // get native metaobjects for the entire derivation lattice
319 // up to, but not including, the current metaobject. 299 // up to, but not including, the current metaobject.
321 301
322 for (void* tmp = moId;;) 302 for (void* tmp = moId;;)
323 { 303 {
324 tmp = qtd_QMetaObject_superClass(tmp); 304 tmp = qtd_QMetaObject_superClass(tmp);
325 assert(tmp); 305 assert(tmp);
326 if (tmp == _nativeId) 306 if (tmp == nId)
327 break; 307 break;
328 moCount++; 308 moCount++;
329 } 309 }
330 310
331 void*[] moIds = (cast(void**)alloca(moCount * (void*).sizeof))[0..moCount]; 311 void*[] moIds = (cast(void**)alloca(moCount * (void*).sizeof))[0..moCount];
332 312
333 moIds[--moCount] = moId; 313 moIds[--moCount] = moId;
334 while (moCount > 0) 314 while (moCount > 0)
335 moIds[--moCount] = moId = qtd_QMetaObject_superClass(moId); 315 moIds[--moCount] = moId = qtd_QMetaObject_superClass(moId);
336 316
337 result = lookupDerived(moIds)._createWrapper(nativeObjId); 317 result = lookUpDerived(moIds)._createWrapper(nativeObjId);
338 } 318 }
339 } 319 }
340 } 320 }
341 321
342 return result; 322 return result;
359 return qtd_QMetaObject_connect(sender.__nativeId, signal_index, receiver.__nativeId, method_index, type, types); 339 return qtd_QMetaObject_connect(sender.__nativeId, signal_index, receiver.__nativeId, method_index, type, types);
360 } 340 }
361 341
362 int indexOfMethod_Cpp(string method) 342 int indexOfMethod_Cpp(string method)
363 { 343 {
364 return qtd_QMetaObject_indexOfMethod(_nativeId, toStringz(method)); 344 return qtd_QMetaObject_indexOfMethod(nativeId, toStringz(method));
365 } 345 }
366 346
367 int methodCount() 347 int methodCount()
368 { 348 {
369 return qtd_QMetaObject_methodCount(_nativeId); 349 return qtd_QMetaObject_methodCount(nativeId);
370 } 350 }
371 351
372 static void connectImpl(QObject sender, string signalString, QObject receiver, string methodString, int type) 352 static void connectImpl(QObject sender, string signalString, QObject receiver, string methodString, int type)
373 { 353 {
374 QMetaSignal[] signals; 354 QMetaSignal[] signals;
375 QMetaMethod[] methods; 355 QMetaMethod[] methods;
376 QMetaSignal signal; 356 QMetaSignal signal;
377 QMetaMethod method; 357 QMetaMethod method;
378 358
379 if(indexOf(signalString, '(') > 0) 359 if(indexOf(signalString, '(') > 0)
380 signal = sender.metaObject.lookUpSignal(signalString); 360 signal = sender.metaObject.lookUpMethod!QMetaSignal(signalString);
381 else 361 else
382 signals = sender.metaObject.lookUpSignalOverloads(signalString); // parameters not specified. Looking for a match 362 signals = sender.metaObject.lookUpMethodOverloads!QMetaSignal(signalString); // parameters not specified. Looking for a match
383 363
384 if(indexOf(methodString, '(') > 0) 364 if(indexOf(methodString, '(') > 0)
385 method = receiver.metaObject.lookUpMethod(methodString); 365 method = receiver.metaObject.lookUpMethod(methodString);
386 else 366 else
387 methods = receiver.metaObject.lookUpMethodOverloads(methodString); // parameters not specified. Looking for a match 367 methods = receiver.metaObject.lookUpMethodOverloads(methodString); // parameters not specified. Looking for a match
388 368
389 if(!signal && !method) 369 if(!signal && !method)
390 { 370 {
391 Top: 371 Top:
392 foreach(sig; signals) 372 foreach(sig; signals)
373 {
393 foreach(meth; methods) 374 foreach(meth; methods)
375 {
394 if(startsWith(sig.args, meth.args)) 376 if(startsWith(sig.args, meth.args))
395 { 377 {
396 signal = sig; 378 signal = sig;
397 method = meth; 379 method = meth;
398 break Top; 380 break Top;
399 } 381 }
382 }
383 }
400 } 384 }
401 else if (!signal) 385 else if (!signal)
402 { 386 {
403 foreach(sig; signals) 387 foreach(sig; signals)
404 if(startsWith(sig.args, method.args)) 388 if(startsWith(sig.args, method.args))
423 { 407 {
424 success = false; 408 success = false;
425 } 409 }
426 else 410 else
427 { 411 {
428 int signalIndex = signal.indexOfMethod; 412 int signalIndex = signal.index;
429 int methodIndex = method.indexOfMethod; 413 int methodIndex = method.index;
430 414
431 success = QMetaObject.connect(sender, signalIndex, receiver, methodIndex, type); 415 success = QMetaObject.connect(sender, signalIndex, receiver, methodIndex, type);
432 } 416 }
433 417
434 if(!success) 418 if(!success)
435 throw new QMetaException("QMetaObject: Signal " ~ signalString ~ " cannot be connected to slot " ~ methodString); 419 {
420 throw new MetaException("QMetaObject: Failed to connect signal "
421 ~ sender.classinfo.name ~ "." ~ signalString ~ " to slot "
422 ~ receiver.classinfo.name ~ "." ~ methodString ~ ". Make sure the signal and slot exist and match.");
423 }
436 } 424 }
437 } 425 }
438 426
439 /** 427 /**
440 */ 428 */
441 mixin template Q_CLASSINFO(string name, string value) 429 mixin template Q_CLASSINFO(string name, string value)
442 { 430 {
443 mixin InnerAttribute!("Q_CLASSINFO", AttributeOptions.allowMultiple, name, value); 431 mixin InnerAttribute!("Q_CLASSINFO", AttributeOptions.allowMultiple, name, value);
444 } 432 }
445 433
434 /**
435 */
436 mixin template Q_PROPERTY(T, string params)
437 {
438 static assert(false, "not implemented");
439 }
440
446 version (QtdUnittest) 441 version (QtdUnittest)
447 { 442 {
443 // COMPILER BUG: cannot put this inside the unittest block as static class.
444 class QMetaObject_A : QObject
445 {
446 mixin Q_CLASSINFO!("author", "Sabrina Schweinsteiger");
447 mixin Q_CLASSINFO!("url", "http://doc.moosesoft.co.uk/1.0/");
448
449 static int slot1Called;
450
451 final
452 {
453 void signal_signal1();
454 void signal_signal2(int);
455 }
456
457
458 void slot_slot1()
459 {
460 slot1Called++;
461 }
462
463 mixin Q_OBJECT;
464 }
465
448 unittest 466 unittest
449 { 467 {
450 static class Test : QObject 468 scope a = new QMetaObject_A;
451 { 469 QObject.connect(a, "signal1", a, "slot1");
452 mixin Q_CLASSINFO!("author", "Sabrina Schweinsteiger"); 470 a.signal1();
453 mixin Q_CLASSINFO!("url", "http://doc.moosesoft.co.uk/1.0/"); 471 assert(QMetaObject_A.slot1Called == 1);
454 472
455 mixin Q_OBJECT; 473 QObject.connect(a, "signal2", a, "slot1");
456 } 474 a.signal2(42);
457 } 475 assert(QMetaObject_A.slot1Called == 2);
458 } 476 }
477 }
459 478
460 extern(C) void qtd_QMetaObject_activate_3(void* sender, void* m, int local_signal_index, void **argv); 479 extern(C) void qtd_QMetaObject_activate_3(void* sender, void* m, int local_signal_index, void **argv);
461 extern(C) void qtd_QMetaObject_activate_4(void *sender, void* m, int from_local_signal_index, int to_local_signal_index, void **argv); 480 extern(C) void qtd_QMetaObject_activate_4(void *sender, void* m, int from_local_signal_index, int to_local_signal_index, void **argv);
462 extern(C) bool qtd_QMetaObject_connect(const void* sender, int signal_index, 481 extern(C) bool qtd_QMetaObject_connect(const void* sender, int signal_index,
463 const void* receiver, int method_index, 482 const void* receiver, int method_index,