Mercurial > projects > qtd
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, |