]> git.saurik.com Git - apple/javascriptcore.git/blob - bindings/qt/qt_runtime.cpp
113f0c52d3ea5bde65cbb44cc1b4f0c95b3c03c6
[apple/javascriptcore.git] / bindings / qt / qt_runtime.cpp
1 /*
2 * Copyright (C) 2006 Trolltech ASA
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 */
19
20 #include "config.h"
21 #include "qt_runtime.h"
22 #include "qt_instance.h"
23 #include "object.h"
24 #include "array_instance.h"
25 #include "date_object.h"
26 #include "DateMath.h"
27 #include "regexp_object.h"
28 #include <runtime_object.h>
29 #include <runtime_array.h>
30 #include <function.h>
31 #include "PropertyNameArray.h"
32 #include "qmetatype.h"
33 #include "qmetaobject.h"
34 #include "qobject.h"
35 #include "qstringlist.h"
36 #include "qdebug.h"
37 #include "qvarlengtharray.h"
38 #include "qdatetime.h"
39 #include <limits.h>
40
41 // QtScript has these
42 Q_DECLARE_METATYPE(QObjectList);
43 Q_DECLARE_METATYPE(QList<int>);
44 Q_DECLARE_METATYPE(QVariant);
45
46
47 namespace KJS {
48 namespace Bindings {
49
50 // Debugging
51 //#define QTWK_RUNTIME_CONVERSION_DEBUG
52 //#define QTWK_RUNTIME_MATCH_DEBUG
53
54 class QWKNoDebug
55 {
56 public:
57 inline QWKNoDebug(){}
58 inline ~QWKNoDebug(){}
59
60 template<typename T>
61 inline QWKNoDebug &operator<<(const T &) { return *this; }
62 };
63
64 #ifdef QTWK_RUNTIME_CONVERSION_DEBUG
65 #define qConvDebug() qDebug()
66 #else
67 #define qConvDebug() QWKNoDebug()
68 #endif
69
70 #ifdef QTWK_RUNTIME_MATCH_DEBUG
71 #define qMatchDebug() qDebug()
72 #else
73 #define qMatchDebug() QWKNoDebug()
74 #endif
75
76 typedef enum {
77 Variant,
78 Number,
79 Boolean,
80 String,
81 Date,
82 RegExp,
83 Array,
84 QObj,
85 Object,
86 Null
87 } JSRealType;
88
89 static JSRealType valueRealType(ExecState* exec, JSValue* val)
90 {
91 if (val->isNumber())
92 return Number;
93 else if (val->isString())
94 return String;
95 else if (val->isBoolean())
96 return Boolean;
97 else if (val->isNull())
98 return Null;
99 else if (val->isObject()) {
100 JSObject *object = val->toObject(exec);
101 if (object->inherits(&ArrayInstance::info))
102 return Array;
103 else if (object->inherits(&DateInstance::info))
104 return Date;
105 else if (object->inherits(&RegExpImp::info))
106 return RegExp;
107 else if (object->inherits(&RuntimeObjectImp::info))
108 return QObj;
109 return Object;
110 }
111
112 return String; // I don't know.
113 }
114
115 QVariant convertValueToQVariant(ExecState* exec, JSValue* value, QMetaType::Type hint, int *distance)
116 {
117 // check magic pointer values before dereferencing value
118 if (value == jsNaN() || value == jsUndefined()) {
119 if (distance)
120 *distance = -1;
121 return QVariant();
122 }
123
124 JSLock lock;
125 JSRealType type = valueRealType(exec, value);
126 if (hint == QMetaType::Void) {
127 switch(type) {
128 case Number:
129 hint = QMetaType::Double;
130 break;
131 case Boolean:
132 hint = QMetaType::Bool;
133 break;
134 case String:
135 default:
136 hint = QMetaType::QString;
137 break;
138 case Date:
139 hint = QMetaType::QDateTime;
140 break;
141 case RegExp:
142 hint = QMetaType::QRegExp;
143 break;
144 case QObj:
145 hint = QMetaType::QObjectStar;
146 break;
147 case Array:
148 hint = QMetaType::QVariantList;
149 break;
150 }
151 }
152
153 if (value == jsNull()
154 && hint != QMetaType::QObjectStar
155 && hint != QMetaType::VoidStar) {
156 if (distance)
157 *distance = -1;
158 return QVariant();
159 }
160
161 QVariant ret;
162 int dist = -1;
163 switch (hint) {
164 case QMetaType::Bool:
165 ret = QVariant(value->toBoolean(exec));
166 if (type == Boolean)
167 dist = 0;
168 else
169 dist = 10;
170 break;
171
172 case QMetaType::Int:
173 case QMetaType::UInt:
174 case QMetaType::Long:
175 case QMetaType::ULong:
176 case QMetaType::LongLong:
177 case QMetaType::ULongLong:
178 case QMetaType::Short:
179 case QMetaType::UShort:
180 case QMetaType::Float:
181 case QMetaType::Double:
182 ret = QVariant(value->toNumber(exec));
183 ret.convert((QVariant::Type)hint);
184 if (type == Number) {
185 switch (hint) {
186 case QMetaType::Double:
187 dist = 0;
188 break;
189 case QMetaType::Float:
190 dist = 1;
191 break;
192 case QMetaType::LongLong:
193 case QMetaType::ULongLong:
194 dist = 2;
195 break;
196 case QMetaType::Long:
197 case QMetaType::ULong:
198 dist = 3;
199 break;
200 case QMetaType::Int:
201 case QMetaType::UInt:
202 dist = 4;
203 break;
204 case QMetaType::Short:
205 case QMetaType::UShort:
206 dist = 5;
207 break;
208 break;
209 default:
210 dist = 10;
211 break;
212 }
213 } else {
214 dist = 10;
215 }
216 break;
217
218 case QMetaType::QChar:
219 if (type == Number || type == Boolean) {
220 ret = QVariant(QChar((ushort)value->toNumber(exec)));
221 if (type == Boolean)
222 dist = 3;
223 else
224 dist = 6;
225 } else {
226 UString str = value->toString(exec);
227 ret = QVariant(QChar(str.size() ? *(const ushort*)str.rep()->data() : 0));
228 if (type == String)
229 dist = 3;
230 else
231 dist = 10;
232 }
233 break;
234
235 case QMetaType::QString: {
236 UString ustring = value->toString(exec);
237 ret = QVariant(QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size()));
238 if (type == String)
239 dist = 0;
240 else
241 dist = 10;
242 break;
243 }
244
245 case QMetaType::QVariantMap:
246 if (type == Object || type == Array) {
247 // Enumerate the contents of the object
248 JSObject* object = value->toObject(exec);
249
250 PropertyNameArray properties;
251 object->getPropertyNames(exec, properties);
252 PropertyNameArray::const_iterator it = properties.begin();
253
254 QVariantMap result;
255 int objdist = 0;
256 while(it != properties.end()) {
257 if (object->propertyIsEnumerable(exec, *it)) {
258 JSValue* val = object->get(exec, *it);
259 QVariant v = convertValueToQVariant(exec, val, QMetaType::Void, &objdist);
260 if (objdist >= 0) {
261 UString ustring = (*it).ustring();
262 QString id = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
263 result.insert(id, v);
264 }
265 }
266 ++it;
267 }
268 dist = 1;
269 ret = QVariant(result);
270 }
271 break;
272
273 case QMetaType::QVariantList:
274 if (type == Array) {
275 JSObject* object = value->toObject(exec);
276 ArrayInstance* array = static_cast<ArrayInstance*>(object);
277
278 QVariantList result;
279 int len = array->getLength();
280 int objdist = 0;
281 for (int i = 0; i < len; ++i) {
282 JSValue *val = array->getItem(i);
283 result.append(convertValueToQVariant(exec, val, QMetaType::Void, &objdist));
284 if (objdist == -1)
285 break; // Failed converting a list entry, so fail the array
286 }
287 if (objdist != -1) {
288 dist = 5;
289 ret = QVariant(result);
290 }
291 } else {
292 // Make a single length array
293 QVariantList result;
294 int objdist;
295 result.append(convertValueToQVariant(exec, value, QMetaType::Void, &objdist));
296 if (objdist != -1) {
297 ret = QVariant(result);
298 dist = 10;
299 }
300 }
301 break;
302
303 case QMetaType::QStringList: {
304 if (type == Array) {
305 JSObject* object = value->toObject(exec);
306 ArrayInstance* array = static_cast<ArrayInstance*>(object);
307
308 QStringList result;
309 int len = array->getLength();
310 for (int i = 0; i < len; ++i) {
311 JSValue* val = array->getItem(i);
312 UString ustring = val->toString(exec);
313 QString qstring = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
314
315 result.append(qstring);
316 }
317 dist = 5;
318 ret = QVariant(result);
319 } else {
320 // Make a single length array
321 UString ustring = value->toString(exec);
322 QString qstring = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
323 QStringList result;
324 result.append(qstring);
325 ret = QVariant(result);
326 dist = 10;
327 }
328 break;
329 }
330
331 case QMetaType::QByteArray: {
332 UString ustring = value->toString(exec);
333 ret = QVariant(QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size()).toLatin1());
334 if (type == String)
335 dist = 5;
336 else
337 dist = 10;
338 break;
339 }
340
341 case QMetaType::QDateTime:
342 case QMetaType::QDate:
343 case QMetaType::QTime:
344 if (type == Date) {
345 JSObject* object = value->toObject(exec);
346 DateInstance* date = static_cast<DateInstance*>(object);
347 GregorianDateTime gdt;
348 date->getUTCTime(gdt);
349 if (hint == QMetaType::QDateTime) {
350 ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
351 dist = 0;
352 } else if (hint == QMetaType::QDate) {
353 ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
354 dist = 1;
355 } else {
356 ret = QTime(gdt.hour + 1900, gdt.minute, gdt.second);
357 dist = 2;
358 }
359 } else if (type == Number) {
360 double b = value->toNumber(exec);
361 GregorianDateTime gdt;
362 msToGregorianDateTime(b, true, gdt);
363 if (hint == QMetaType::QDateTime) {
364 ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
365 dist = 6;
366 } else if (hint == QMetaType::QDate) {
367 ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
368 dist = 8;
369 } else {
370 ret = QTime(gdt.hour, gdt.minute, gdt.second);
371 dist = 10;
372 }
373 } else if (type == String) {
374 UString ustring = value->toString(exec);
375 QString qstring = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
376
377 if (hint == QMetaType::QDateTime) {
378 QDateTime dt = QDateTime::fromString(qstring, Qt::ISODate);
379 if (!dt.isValid())
380 dt = QDateTime::fromString(qstring, Qt::TextDate);
381 if (!dt.isValid())
382 dt = QDateTime::fromString(qstring, Qt::SystemLocaleDate);
383 if (!dt.isValid())
384 dt = QDateTime::fromString(qstring, Qt::LocaleDate);
385 if (dt.isValid()) {
386 ret = dt;
387 dist = 2;
388 }
389 } else if (hint == QMetaType::QDate) {
390 QDate dt = QDate::fromString(qstring, Qt::ISODate);
391 if (!dt.isValid())
392 dt = QDate::fromString(qstring, Qt::TextDate);
393 if (!dt.isValid())
394 dt = QDate::fromString(qstring, Qt::SystemLocaleDate);
395 if (!dt.isValid())
396 dt = QDate::fromString(qstring, Qt::LocaleDate);
397 if (dt.isValid()) {
398 ret = dt;
399 dist = 3;
400 }
401 } else {
402 QTime dt = QTime::fromString(qstring, Qt::ISODate);
403 if (!dt.isValid())
404 dt = QTime::fromString(qstring, Qt::TextDate);
405 if (!dt.isValid())
406 dt = QTime::fromString(qstring, Qt::SystemLocaleDate);
407 if (!dt.isValid())
408 dt = QTime::fromString(qstring, Qt::LocaleDate);
409 if (dt.isValid()) {
410 ret = dt;
411 dist = 3;
412 }
413 }
414 }
415 break;
416
417 case QMetaType::QRegExp:
418 if (type == RegExp) {
419 /* JSObject *object = value->toObject(exec);
420 RegExpImp *re = static_cast<RegExpImp*>(object);
421 */
422 // Attempt to convert.. a bit risky
423 UString ustring = value->toString(exec);
424 QString qstring = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
425
426 // this is of the form '/xxxxxx/i'
427 int firstSlash = qstring.indexOf('/');
428 int lastSlash = qstring.lastIndexOf('/');
429 if (firstSlash >=0 && lastSlash > firstSlash) {
430 QRegExp realRe;
431
432 realRe.setPattern(qstring.mid(firstSlash + 1, lastSlash - firstSlash - 1));
433
434 if (qstring.mid(lastSlash + 1).contains('i'))
435 realRe.setCaseSensitivity(Qt::CaseInsensitive);
436
437 ret = qVariantFromValue(realRe);
438 dist = 0;
439 } else {
440 qConvDebug() << "couldn't parse a JS regexp";
441 }
442 } else if (type == String) {
443 UString ustring = value->toString(exec);
444 QString qstring = QString::fromUtf16((const ushort*)ustring.rep()->data(),ustring.size());
445
446 QRegExp re(qstring);
447 if (re.isValid()) {
448 ret = qVariantFromValue(re);
449 dist = 10;
450 }
451 }
452 break;
453
454 case QMetaType::QObjectStar:
455 if (type == QObj) {
456 JSObject* object = value->toObject(exec);
457 QtInstance* qtinst = static_cast<QtInstance*>(Instance::getInstance(object, Instance::QtLanguage));
458 if (qtinst) {
459 if (qtinst->getObject()) {
460 qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
461 ret = qVariantFromValue(qtinst->getObject());
462 qConvDebug() << ret;
463 dist = 0;
464 } else {
465 qConvDebug() << "can't convert deleted qobject";
466 }
467 } else {
468 qConvDebug() << "wasn't a qtinstance";
469 }
470 } else if (type == Null) {
471 QObject* nullobj = 0;
472 ret = qVariantFromValue(nullobj);
473 dist = 0;
474 } else {
475 qConvDebug() << "previous type was not an object:" << type;
476 }
477 break;
478
479 case QMetaType::VoidStar:
480 if (type == QObj) {
481 JSObject* object = value->toObject(exec);
482 QtInstance* qtinst = static_cast<QtInstance*>(Instance::getInstance(object, Instance::QtLanguage));
483 if (qtinst) {
484 if (qtinst->getObject()) {
485 qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
486 ret = qVariantFromValue((void *)qtinst->getObject());
487 qConvDebug() << ret;
488 dist = 0;
489 } else {
490 qConvDebug() << "can't convert deleted qobject";
491 }
492 } else {
493 qConvDebug() << "wasn't a qtinstance";
494 }
495 } else if (type == Null) {
496 ret = qVariantFromValue((void*)0);
497 dist = 0;
498 } else if (type == Number) {
499 // I don't think that converting a double to a pointer is a wise
500 // move. Except maybe 0.
501 qConvDebug() << "got number for void * - not converting, seems unsafe:" << value->toNumber(exec);
502 } else {
503 qConvDebug() << "void* - unhandled type" << type;
504 }
505 break;
506
507 default:
508 // Non const type ids
509 if (hint == (QMetaType::Type) qMetaTypeId<QObjectList>())
510 {
511 if (type == Array) {
512 JSObject* object = value->toObject(exec);
513 ArrayInstance* array = static_cast<ArrayInstance *>(object);
514
515 QObjectList result;
516 int len = array->getLength();
517 for (int i = 0; i < len; ++i) {
518 JSValue *val = array->getItem(i);
519 int itemdist = -1;
520 QVariant item = convertValueToQVariant(exec, val, QMetaType::QObjectStar, &itemdist);
521 if (itemdist >= 0)
522 result.append(item.value<QObject*>());
523 else
524 break;
525 }
526 // If we didn't fail conversion
527 if (result.count() == len) {
528 dist = 5;
529 ret = QVariant::fromValue(result);
530 } else {
531 qConvDebug() << "type conversion failed (wanted" << len << ", got " << result.count() << ")";
532 }
533 } else {
534 // Make a single length array
535 QObjectList result;
536 int itemdist = -1;
537 QVariant item = convertValueToQVariant(exec, value, QMetaType::QObjectStar, &itemdist);
538 if (itemdist >= 0) {
539 result.append(item.value<QObject*>());
540 dist = 10;
541 ret = QVariant::fromValue(result);
542 }
543 }
544 break;
545 } else if (hint == (QMetaType::Type) qMetaTypeId<QList<int> >()) {
546 if (type == Array) {
547 JSObject* object = value->toObject(exec);
548 ArrayInstance* array = static_cast<ArrayInstance *>(object);
549
550 QList<int> result;
551 int len = array->getLength();
552 for (int i = 0; i < len; ++i) {
553 JSValue* val = array->getItem(i);
554 int itemdist = -1;
555 QVariant item = convertValueToQVariant(exec, val, QMetaType::Int, &itemdist);
556 if (itemdist >= 0)
557 result.append(item.value<int>());
558 else
559 break;
560 }
561 // If we didn't fail conversion
562 if (result.count() == len) {
563 dist = 5;
564 ret = QVariant::fromValue(result);
565 } else {
566 qConvDebug() << "type conversion failed (wanted" << len << ", got " << result.count() << ")";
567 }
568 } else {
569 // Make a single length array
570 QList<int> result;
571 int itemdist = -1;
572 QVariant item = convertValueToQVariant(exec, value, QMetaType::Int, &itemdist);
573 if (itemdist >= 0) {
574 result.append(item.value<int>());
575 dist = 10;
576 ret = QVariant::fromValue(result);
577 }
578 }
579 break;
580 } else if (hint == (QMetaType::Type) qMetaTypeId<QVariant>()) {
581 // Well.. we can do anything... just recurse with the autodetect flag
582 ret = convertValueToQVariant(exec, value, QMetaType::Void, distance);
583 dist = 10;
584 break;
585 }
586
587 dist = 10;
588 break;
589 }
590
591 if (!ret.isValid())
592 dist = -1;
593 if (distance)
594 *distance = dist;
595
596 return ret;
597 }
598
599 JSValue* convertQVariantToValue(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& variant)
600 {
601 // Variants with QObject * can be isNull but not a null pointer
602 // An empty QString variant is also null
603 QMetaType::Type type = (QMetaType::Type) variant.userType();
604 if (variant.isNull() &&
605 type != QMetaType::QObjectStar &&
606 type != QMetaType::VoidStar &&
607 type != QMetaType::QWidgetStar &&
608 type != QMetaType::QString) {
609 return jsNull();
610 }
611
612 JSLock lock;
613
614 if (type == QMetaType::Bool)
615 return jsBoolean(variant.toBool());
616
617 if (type == QMetaType::Int ||
618 type == QMetaType::UInt ||
619 type == QMetaType::Long ||
620 type == QMetaType::ULong ||
621 type == QMetaType::LongLong ||
622 type == QMetaType::ULongLong ||
623 type == QMetaType::Short ||
624 type == QMetaType::UShort ||
625 type == QMetaType::Float ||
626 type == QMetaType::Double)
627 return jsNumber(variant.toDouble());
628
629 if (type == QMetaType::QRegExp) {
630 QRegExp re = variant.value<QRegExp>();
631
632 if (re.isValid()) {
633 RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->lexicalGlobalObject()->regExpConstructor());
634 List args;
635 UString uflags;
636
637 if (re.caseSensitivity() == Qt::CaseInsensitive)
638 uflags = "i"; // ### Can't do g or m
639 UString ustring((KJS::UChar*)re.pattern().utf16(), re.pattern().length());
640 args.append(jsString(ustring));
641 args.append(jsString(uflags));
642 return regExpObj->construct(exec, args);
643 }
644 }
645
646 if (type == QMetaType::QDateTime ||
647 type == QMetaType::QDate ||
648 type == QMetaType::QTime) {
649 DateObjectImp *dateObj = static_cast<DateObjectImp*>(exec->lexicalGlobalObject()->dateConstructor());
650 List args;
651
652 QDate date = QDate::currentDate();
653 QTime time(0,0,0); // midnight
654
655 if (type == QMetaType::QDate)
656 date = variant.value<QDate>();
657 else if (type == QMetaType::QTime)
658 time = variant.value<QTime>();
659 else {
660 QDateTime dt = variant.value<QDateTime>().toLocalTime();
661 date = dt.date();
662 time = dt.time();
663 }
664
665 // Dates specified this way are in local time (we convert DateTimes above)
666 args.append(jsNumber(date.year()));
667 args.append(jsNumber(date.month() - 1));
668 args.append(jsNumber(date.day()));
669 args.append(jsNumber(time.hour()));
670 args.append(jsNumber(time.minute()));
671 args.append(jsNumber(time.second()));
672 args.append(jsNumber(time.msec()));
673 return dateObj->construct(exec, args);
674 }
675
676 if (type == QMetaType::QByteArray) {
677 QByteArray ba = variant.value<QByteArray>();
678 UString ustring(ba.constData());
679 return jsString(ustring);
680 }
681
682 if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
683 QObject* obj = variant.value<QObject*>();
684 return Instance::createRuntimeObject(Instance::QtLanguage, obj, root);
685 }
686
687 if (type == QMetaType::QVariantMap) {
688 // create a new object, and stuff properties into it
689 JSObject* ret = new JSObject(exec->lexicalGlobalObject()->objectPrototype());
690 QVariantMap map = variant.value<QVariantMap>();
691 QVariantMap::const_iterator i = map.constBegin();
692 while (i != map.constEnd()) {
693 QString s = i.key();
694 JSValue* val = convertQVariantToValue(exec, root, i.value());
695 if (val)
696 ret->put(exec, Identifier((const UChar *)s.constData(), s.length()), val);
697 // ### error case?
698 ++i;
699 }
700
701 return ret;
702 }
703
704 // List types
705 if (type == QMetaType::QVariantList) {
706 QVariantList vl = variant.toList();
707 return new RuntimeArray(exec, new QtArray<QVariant>(vl, QMetaType::Void, root));
708 } else if (type == QMetaType::QStringList) {
709 QStringList sl = variant.value<QStringList>();
710 return new RuntimeArray(exec, new QtArray<QString>(sl, QMetaType::QString, root));
711 } else if (type == (QMetaType::Type) qMetaTypeId<QObjectList>()) {
712 QObjectList ol= variant.value<QObjectList>();
713 return new RuntimeArray(exec, new QtArray<QObject*>(ol, QMetaType::QObjectStar, root));
714 } else if (type == (QMetaType::Type)qMetaTypeId<QList<int> >()) {
715 QList<int> il= variant.value<QList<int> >();
716 return new RuntimeArray(exec, new QtArray<int>(il, QMetaType::Int, root));
717 }
718
719 if (type == (QMetaType::Type)qMetaTypeId<QVariant>()) {
720 QVariant real = variant.value<QVariant>();
721 qConvDebug() << "real variant is:" << real;
722 return convertQVariantToValue(exec, root, real);
723 }
724
725 qConvDebug() << "fallback path for" << variant << variant.userType();
726
727 QString string = variant.toString();
728 UString ustring((KJS::UChar*)string.utf16(), string.length());
729 return jsString(ustring);
730 }
731
732 // ===============
733
734 // Qt-like macros
735 #define QW_D(Class) Class##Data* d = d_func()
736 #define QW_DS(Class,Instance) Class##Data* d = Instance->d_func()
737
738 QtRuntimeMethod::QtRuntimeMethod(QtRuntimeMethodData* dd, ExecState *exec, const Identifier &ident, PassRefPtr<QtInstance> inst)
739 : InternalFunctionImp (static_cast<FunctionPrototype*>(exec->lexicalGlobalObject()->functionPrototype()), ident)
740 , d_ptr(dd)
741 {
742 QW_D(QtRuntimeMethod);
743 d->m_instance = inst;
744 }
745
746 QtRuntimeMethod::~QtRuntimeMethod()
747 {
748 delete d_ptr;
749 }
750
751 CodeType QtRuntimeMethod::codeType() const
752 {
753 return FunctionCode;
754 }
755
756 Completion QtRuntimeMethod::execute(ExecState*)
757 {
758 return Completion(Normal, jsUndefined());
759 }
760
761 // ===============
762
763 QtRuntimeMethodData::~QtRuntimeMethodData()
764 {
765 }
766
767 QtRuntimeMetaMethodData::~QtRuntimeMetaMethodData()
768 {
769
770 }
771
772 QtRuntimeConnectionMethodData::~QtRuntimeConnectionMethodData()
773 {
774
775 }
776
777 // ===============
778
779 // Type conversion metadata (from QtScript originally)
780 class QtMethodMatchType
781 {
782 public:
783 enum Kind {
784 Invalid,
785 Variant,
786 MetaType,
787 Unresolved,
788 MetaEnum
789 };
790
791
792 QtMethodMatchType()
793 : m_kind(Invalid) { }
794
795 Kind kind() const
796 { return m_kind; }
797
798 QMetaType::Type typeId() const;
799
800 bool isValid() const
801 { return (m_kind != Invalid); }
802
803 bool isVariant() const
804 { return (m_kind == Variant); }
805
806 bool isMetaType() const
807 { return (m_kind == MetaType); }
808
809 bool isUnresolved() const
810 { return (m_kind == Unresolved); }
811
812 bool isMetaEnum() const
813 { return (m_kind == MetaEnum); }
814
815 QByteArray name() const;
816
817 int enumeratorIndex() const
818 { Q_ASSERT(isMetaEnum()); return m_typeId; }
819
820 static QtMethodMatchType variant()
821 { return QtMethodMatchType(Variant); }
822
823 static QtMethodMatchType metaType(int typeId, const QByteArray &name)
824 { return QtMethodMatchType(MetaType, typeId, name); }
825
826 static QtMethodMatchType metaEnum(int enumIndex, const QByteArray &name)
827 { return QtMethodMatchType(MetaEnum, enumIndex, name); }
828
829 static QtMethodMatchType unresolved(const QByteArray &name)
830 { return QtMethodMatchType(Unresolved, /*typeId=*/0, name); }
831
832 private:
833 QtMethodMatchType(Kind kind, int typeId = 0, const QByteArray &name = QByteArray())
834 : m_kind(kind), m_typeId(typeId), m_name(name) { }
835
836 Kind m_kind;
837 int m_typeId;
838 QByteArray m_name;
839 };
840
841 QMetaType::Type QtMethodMatchType::typeId() const
842 {
843 if (isVariant())
844 return (QMetaType::Type) QMetaType::type("QVariant");
845 return (QMetaType::Type) (isMetaEnum() ? QMetaType::Int : m_typeId);
846 }
847
848 QByteArray QtMethodMatchType::name() const
849 {
850 if (!m_name.isEmpty())
851 return m_name;
852 else if (m_kind == Variant)
853 return "QVariant";
854 return QByteArray();
855 }
856
857 struct QtMethodMatchData
858 {
859 int matchDistance;
860 int index;
861 QVector<QtMethodMatchType> types;
862 QVarLengthArray<QVariant, 10> args;
863
864 QtMethodMatchData(int dist, int idx, QVector<QtMethodMatchType> typs,
865 const QVarLengthArray<QVariant, 10> &as)
866 : matchDistance(dist), index(idx), types(typs), args(as) { }
867 QtMethodMatchData()
868 : index(-1) { }
869
870 bool isValid() const
871 { return (index != -1); }
872
873 int firstUnresolvedIndex() const
874 {
875 for (int i=0; i < types.count(); i++) {
876 if (types.at(i).isUnresolved())
877 return i;
878 }
879 return -1;
880 }
881 };
882
883 static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str)
884 {
885 QByteArray scope;
886 QByteArray name;
887 int scopeIdx = str.indexOf("::");
888 if (scopeIdx != -1) {
889 scope = str.left(scopeIdx);
890 name = str.mid(scopeIdx + 2);
891 } else {
892 name = str;
893 }
894 for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
895 QMetaEnum m = meta->enumerator(i);
896 if ((m.name() == name)/* && (scope.isEmpty() || (m.scope() == scope))*/)
897 return i;
898 }
899 return -1;
900 }
901
902 // Helper function for resolving methods
903 // Largely based on code in QtScript for compatibility reasons
904 static int findMethodIndex(ExecState* exec,
905 const QMetaObject* meta,
906 const QByteArray& signature,
907 bool allowPrivate,
908 const List& jsArgs,
909 QVarLengthArray<QVariant, 10> &vars,
910 void** vvars,
911 JSObject **pError)
912 {
913 QList<int> matchingIndices;
914
915 bool overloads = !signature.contains('(');
916
917 int count = meta->methodCount();
918 for (int i = count - 1; i >= 0; --i) {
919 const QMetaMethod m = meta->method(i);
920
921 // Don't choose private methods
922 if (m.access() == QMetaMethod::Private && !allowPrivate)
923 continue;
924
925 // try and find all matching named methods
926 if (m.signature() == signature)
927 matchingIndices.append(i);
928 else if (overloads) {
929 QByteArray rawsignature = m.signature();
930 rawsignature.truncate(rawsignature.indexOf('('));
931 if (rawsignature == signature)
932 matchingIndices.append(i);
933 }
934 }
935
936 int chosenIndex = -1;
937 *pError = 0;
938 QVector<QtMethodMatchType> chosenTypes;
939
940 QVarLengthArray<QVariant, 10> args;
941 QVector<QtMethodMatchData> candidates;
942 QVector<QtMethodMatchData> unresolved;
943 QVector<int> tooFewArgs;
944 QVector<int> conversionFailed;
945
946 foreach(int index, matchingIndices) {
947 QMetaMethod method = meta->method(index);
948
949 QVector<QtMethodMatchType> types;
950 bool unresolvedTypes = false;
951
952 // resolve return type
953 QByteArray returnTypeName = method.typeName();
954 int rtype = QMetaType::type(returnTypeName);
955 if ((rtype == 0) && !returnTypeName.isEmpty()) {
956 if (returnTypeName == "QVariant") {
957 types.append(QtMethodMatchType::variant());
958 } else if (returnTypeName.endsWith('*')) {
959 types.append(QtMethodMatchType::metaType(QMetaType::VoidStar, returnTypeName));
960 } else {
961 int enumIndex = indexOfMetaEnum(meta, returnTypeName);
962 if (enumIndex != -1)
963 types.append(QtMethodMatchType::metaEnum(enumIndex, returnTypeName));
964 else {
965 unresolvedTypes = true;
966 types.append(QtMethodMatchType::unresolved(returnTypeName));
967 }
968 }
969 } else {
970 if (returnTypeName == "QVariant")
971 types.append(QtMethodMatchType::variant());
972 else
973 types.append(QtMethodMatchType::metaType(rtype, returnTypeName));
974 }
975
976 // resolve argument types
977 QList<QByteArray> parameterTypeNames = method.parameterTypes();
978 for (int i = 0; i < parameterTypeNames.count(); ++i) {
979 QByteArray argTypeName = parameterTypeNames.at(i);
980 int atype = QMetaType::type(argTypeName);
981 if (atype == 0) {
982 if (argTypeName == "QVariant") {
983 types.append(QtMethodMatchType::variant());
984 } else {
985 int enumIndex = indexOfMetaEnum(meta, argTypeName);
986 if (enumIndex != -1)
987 types.append(QtMethodMatchType::metaEnum(enumIndex, argTypeName));
988 else {
989 unresolvedTypes = true;
990 types.append(QtMethodMatchType::unresolved(argTypeName));
991 }
992 }
993 } else {
994 if (argTypeName == "QVariant")
995 types.append(QtMethodMatchType::variant());
996 else
997 types.append(QtMethodMatchType::metaType(atype, argTypeName));
998 }
999 }
1000
1001 if (jsArgs.size() < (types.count() - 1)) {
1002 qMatchDebug() << "Match:too few args for" << method.signature();
1003 tooFewArgs.append(index);
1004 continue;
1005 }
1006
1007 if (unresolvedTypes) {
1008 qMatchDebug() << "Match:unresolved arg types for" << method.signature();
1009 // remember it so we can give an error message later, if necessary
1010 unresolved.append(QtMethodMatchData(/*matchDistance=*/INT_MAX, index,
1011 types, QVarLengthArray<QVariant, 10>()));
1012 continue;
1013 }
1014
1015 // Now convert arguments
1016 if (args.count() != types.count())
1017 args.resize(types.count());
1018
1019 QtMethodMatchType retType = types[0];
1020 args[0] = QVariant(retType.typeId(), (void *)0); // the return value
1021
1022 bool converted = true;
1023 int matchDistance = 0;
1024 for (int i = 0; converted && i < types.count() - 1; ++i) {
1025 JSValue* arg = i < jsArgs.size() ? jsArgs[i] : jsUndefined();
1026
1027 int argdistance = -1;
1028 QVariant v = convertValueToQVariant(exec, arg, types.at(i+1).typeId(), &argdistance);
1029 if (argdistance >= 0) {
1030 matchDistance += argdistance;
1031 args[i+1] = v;
1032 } else {
1033 qMatchDebug() << "failed to convert argument " << i << "type" << types.at(i+1).typeId() << QMetaType::typeName(types.at(i+1).typeId());
1034 converted = false;
1035 }
1036 }
1037
1038 qMatchDebug() << "Match: " << method.signature() << (converted ? "converted":"failed to convert") << "distance " << matchDistance;
1039
1040 if (converted) {
1041 if ((jsArgs.size() == types.count() - 1)
1042 && (matchDistance == 0)) {
1043 // perfect match, use this one
1044 chosenIndex = index;
1045 break;
1046 } else {
1047 QtMethodMatchData metaArgs(matchDistance, index, types, args);
1048 if (candidates.isEmpty()) {
1049 candidates.append(metaArgs);
1050 } else {
1051 QtMethodMatchData otherArgs = candidates.at(0);
1052 if ((args.count() > otherArgs.args.count())
1053 || ((args.count() == otherArgs.args.count())
1054 && (matchDistance <= otherArgs.matchDistance))) {
1055 candidates.prepend(metaArgs);
1056 } else {
1057 candidates.append(metaArgs);
1058 }
1059 }
1060 }
1061 } else {
1062 conversionFailed.append(index);
1063 }
1064
1065 if (!overloads)
1066 break;
1067 }
1068
1069 if (chosenIndex == -1 && candidates.count() == 0) {
1070 // No valid functions at all - format an error message
1071 if (!conversionFailed.isEmpty()) {
1072 QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n")
1073 .arg(QLatin1String(signature));
1074 for (int i = 0; i < conversionFailed.size(); ++i) {
1075 if (i > 0)
1076 message += QLatin1String("\n");
1077 QMetaMethod mtd = meta->method(conversionFailed.at(i));
1078 message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
1079 }
1080 *pError = throwError(exec, TypeError, message.toLatin1().constData());
1081 } else if (!unresolved.isEmpty()) {
1082 QtMethodMatchData argsInstance = unresolved.first();
1083 int unresolvedIndex = argsInstance.firstUnresolvedIndex();
1084 Q_ASSERT(unresolvedIndex != -1);
1085 QtMethodMatchType unresolvedType = argsInstance.types.at(unresolvedIndex);
1086 QString message = QString::fromLatin1("cannot call %0(): unknown type `%1'")
1087 .arg(QString::fromLatin1(signature))
1088 .arg(QLatin1String(unresolvedType.name()));
1089 *pError = throwError(exec, TypeError, message.toLatin1().constData());
1090 } else {
1091 QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n")
1092 .arg(QLatin1String(signature));
1093 for (int i = 0; i < tooFewArgs.size(); ++i) {
1094 if (i > 0)
1095 message += QLatin1String("\n");
1096 QMetaMethod mtd = meta->method(tooFewArgs.at(i));
1097 message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
1098 }
1099 *pError = throwError(exec, SyntaxError, message.toLatin1().constData());
1100 }
1101 }
1102
1103 if (chosenIndex == -1 && candidates.count() > 0) {
1104 QtMethodMatchData metaArgs = candidates.at(0);
1105 if ((candidates.size() > 1)
1106 && (metaArgs.args.count() == candidates.at(1).args.count())
1107 && (metaArgs.matchDistance == candidates.at(1).matchDistance)) {
1108 // ambiguous call
1109 QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n")
1110 .arg(QLatin1String(signature));
1111 for (int i = 0; i < candidates.size(); ++i) {
1112 if (i > 0)
1113 message += QLatin1String("\n");
1114 QMetaMethod mtd = meta->method(candidates.at(i).index);
1115 message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
1116 }
1117 *pError = throwError(exec, TypeError, message.toLatin1().constData());
1118 } else {
1119 chosenIndex = metaArgs.index;
1120 args = metaArgs.args;
1121 }
1122 }
1123
1124 if (chosenIndex != -1) {
1125 /* Copy the stuff over */
1126 int i;
1127 vars.resize(args.count());
1128 for (i=0; i < args.count(); i++) {
1129 vars[i] = args[i];
1130 vvars[i] = vars[i].data();
1131 }
1132 }
1133
1134 return chosenIndex;
1135 }
1136
1137 // Signals are not fuzzy matched as much as methods
1138 static int findSignalIndex(const QMetaObject* meta, int initialIndex, QByteArray signature)
1139 {
1140 int index = initialIndex;
1141 QMetaMethod method = meta->method(index);
1142 bool overloads = !signature.contains('(');
1143 if (overloads && (method.attributes() & QMetaMethod::Cloned)) {
1144 // find the most general method
1145 do {
1146 method = meta->method(--index);
1147 } while (method.attributes() & QMetaMethod::Cloned);
1148 }
1149 return index;
1150 }
1151
1152 QtRuntimeMetaMethod::QtRuntimeMetaMethod(ExecState* exec, const Identifier& ident, PassRefPtr<QtInstance> inst, int index, const QByteArray& signature, bool allowPrivate)
1153 : QtRuntimeMethod (new QtRuntimeMetaMethodData(), exec, ident, inst)
1154 {
1155 QW_D(QtRuntimeMetaMethod);
1156 d->m_signature = signature;
1157 d->m_index = index;
1158 d->m_connect = 0;
1159 d->m_disconnect = 0;
1160 d->m_allowPrivate = allowPrivate;
1161 }
1162
1163 void QtRuntimeMetaMethod::mark()
1164 {
1165 QtRuntimeMethod::mark();
1166 QW_D(QtRuntimeMetaMethod);
1167 if (d->m_connect)
1168 d->m_connect->mark();
1169 if (d->m_disconnect)
1170 d->m_disconnect->mark();
1171 }
1172
1173 JSValue* QtRuntimeMetaMethod::callAsFunction(ExecState* exec, JSObject*, const List& args)
1174 {
1175 QW_D(QtRuntimeMetaMethod);
1176
1177 // We're limited to 10 args
1178 if (args.size() > 10)
1179 return jsUndefined();
1180
1181 // We have to pick a method that matches..
1182 JSLock lock;
1183
1184 QObject *obj = d->m_instance->getObject();
1185 if (obj) {
1186 QVarLengthArray<QVariant, 10> vargs;
1187 void *qargs[11];
1188
1189 int methodIndex;
1190 JSObject* errorObj = 0;
1191 if ((methodIndex = findMethodIndex(exec, obj->metaObject(), d->m_signature, d->m_allowPrivate, args, vargs, (void **)qargs, &errorObj)) != -1) {
1192 if (obj->qt_metacall(QMetaObject::InvokeMetaMethod, methodIndex, qargs) >= 0)
1193 return jsUndefined();
1194
1195 if (vargs[0].isValid())
1196 return convertQVariantToValue(exec, d->m_instance->rootObject(), vargs[0]);
1197 }
1198
1199 if (errorObj)
1200 return errorObj;
1201 } else {
1202 return throwError(exec, GeneralError, "cannot call function of deleted QObject");
1203 }
1204
1205 // void functions return undefined
1206 return jsUndefined();
1207 }
1208
1209 bool QtRuntimeMetaMethod::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
1210 {
1211 if (propertyName == "connect") {
1212 slot.setCustom(this, connectGetter);
1213 return true;
1214 } else if (propertyName == "disconnect") {
1215 slot.setCustom(this, disconnectGetter);
1216 return true;
1217 } else if (propertyName == exec->propertyNames().length) {
1218 slot.setCustom(this, lengthGetter);
1219 return true;
1220 }
1221
1222 return QtRuntimeMethod::getOwnPropertySlot(exec, propertyName, slot);
1223 }
1224
1225 JSValue *QtRuntimeMetaMethod::lengthGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot&)
1226 {
1227 // QtScript always returns 0
1228 return jsNumber(0);
1229 }
1230
1231 JSValue *QtRuntimeMetaMethod::connectGetter(ExecState* exec, JSObject*, const Identifier& ident, const PropertySlot& slot)
1232 {
1233 QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(slot.slotBase());
1234 QW_DS(QtRuntimeMetaMethod, thisObj);
1235
1236 if (!d->m_connect)
1237 d->m_connect = new QtRuntimeConnectionMethod(exec, ident, true, d->m_instance, d->m_index, d->m_signature);
1238 return d->m_connect;
1239 }
1240
1241 JSValue* QtRuntimeMetaMethod::disconnectGetter(ExecState* exec, JSObject*, const Identifier& ident, const PropertySlot& slot)
1242 {
1243 QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(slot.slotBase());
1244 QW_DS(QtRuntimeMetaMethod, thisObj);
1245
1246 if (!d->m_disconnect)
1247 d->m_disconnect = new QtRuntimeConnectionMethod(exec, ident, false, d->m_instance, d->m_index, d->m_signature);
1248 return d->m_disconnect;
1249 }
1250
1251 // ===============
1252
1253 QMultiMap<QObject*, QtConnectionObject*> QtRuntimeConnectionMethod::connections;
1254
1255 QtRuntimeConnectionMethod::QtRuntimeConnectionMethod(ExecState* exec, const Identifier& ident, bool isConnect, PassRefPtr<QtInstance> inst, int index, const QByteArray& signature)
1256 : QtRuntimeMethod (new QtRuntimeConnectionMethodData(), exec, ident, inst)
1257 {
1258 QW_D(QtRuntimeConnectionMethod);
1259
1260 d->m_signature = signature;
1261 d->m_index = index;
1262 d->m_isConnect = isConnect;
1263 }
1264
1265 JSValue *QtRuntimeConnectionMethod::callAsFunction(ExecState* exec, JSObject*, const List& args)
1266 {
1267 QW_D(QtRuntimeConnectionMethod);
1268
1269 JSLock lock;
1270
1271 QObject* sender = d->m_instance->getObject();
1272
1273 if (sender) {
1274
1275 JSObject* thisObject = exec->lexicalGlobalObject();
1276 JSObject* funcObject = 0;
1277
1278 // QtScript checks signalness first, arguments second
1279 int signalIndex = -1;
1280
1281 // Make sure the initial index is a signal
1282 QMetaMethod m = sender->metaObject()->method(d->m_index);
1283 if (m.methodType() == QMetaMethod::Signal)
1284 signalIndex = findSignalIndex(sender->metaObject(), d->m_index, d->m_signature);
1285
1286 if (signalIndex != -1) {
1287 if (args.size() == 1) {
1288 funcObject = args[0]->toObject(exec);
1289 if (!funcObject->implementsCall()) {
1290 if (d->m_isConnect)
1291 return throwError(exec, TypeError, "QtMetaMethod.connect: target is not a function");
1292 else
1293 return throwError(exec, TypeError, "QtMetaMethod.disconnect: target is not a function");
1294 }
1295 } else if (args.size() >= 2) {
1296 if (args[0]->type() == ObjectType) {
1297 thisObject = args[0]->toObject(exec);
1298
1299 // Get the actual function to call
1300 JSObject *asObj = args[1]->toObject(exec);
1301 if (asObj->implementsCall()) {
1302 // Function version
1303 funcObject = asObj;
1304 } else {
1305 // Convert it to a string
1306 UString funcName = args[1]->toString(exec);
1307 Identifier funcIdent(funcName);
1308
1309 // ### DropAllLocks
1310 // This is resolved at this point in QtScript
1311 JSValue* val = thisObject->get(exec, funcIdent);
1312 JSObject* asFuncObj = val->toObject(exec);
1313
1314 if (asFuncObj->implementsCall()) {
1315 funcObject = asFuncObj;
1316 } else {
1317 if (d->m_isConnect)
1318 return throwError(exec, TypeError, "QtMetaMethod.connect: target is not a function");
1319 else
1320 return throwError(exec, TypeError, "QtMetaMethod.disconnect: target is not a function");
1321 }
1322 }
1323 } else {
1324 if (d->m_isConnect)
1325 return throwError(exec, TypeError, "QtMetaMethod.connect: thisObject is not an object");
1326 else
1327 return throwError(exec, TypeError, "QtMetaMethod.disconnect: thisObject is not an object");
1328 }
1329 } else {
1330 if (d->m_isConnect)
1331 return throwError(exec, GeneralError, "QtMetaMethod.connect: no arguments given");
1332 else
1333 return throwError(exec, GeneralError, "QtMetaMethod.disconnect: no arguments given");
1334 }
1335
1336 if (d->m_isConnect) {
1337 // to connect, we need:
1338 // target object [from ctor]
1339 // target signal index etc. [from ctor]
1340 // receiver function [from arguments]
1341 // receiver this object [from arguments]
1342
1343 QtConnectionObject* conn = new QtConnectionObject(d->m_instance, signalIndex, thisObject, funcObject);
1344 bool ok = QMetaObject::connect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
1345 if (!ok) {
1346 delete conn;
1347 QString msg = QString("QtMetaMethod.connect: failed to connect to %1::%2()")
1348 .arg(sender->metaObject()->className())
1349 .arg(QLatin1String(d->m_signature));
1350 return throwError(exec, GeneralError, msg.toLatin1().constData());
1351 }
1352 else {
1353 // Store connection
1354 connections.insert(sender, conn);
1355 }
1356 } else {
1357 // Now to find our previous connection object. Hmm.
1358 QList<QtConnectionObject*> conns = connections.values(sender);
1359 bool ret = false;
1360
1361 foreach(QtConnectionObject* conn, conns) {
1362 // Is this the right connection?
1363 if (conn->match(sender, signalIndex, thisObject, funcObject)) {
1364 // Yep, disconnect it
1365 QMetaObject::disconnect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
1366 delete conn; // this will also remove it from the map
1367 ret = true;
1368 break;
1369 }
1370 }
1371
1372 if (!ret) {
1373 QString msg = QString("QtMetaMethod.disconnect: failed to disconnect from %1::%2()")
1374 .arg(sender->metaObject()->className())
1375 .arg(QLatin1String(d->m_signature));
1376 return throwError(exec, GeneralError, msg.toLatin1().constData());
1377 }
1378 }
1379 } else {
1380 QString msg = QString("QtMetaMethod.%1: %2::%3() is not a signal")
1381 .arg(d->m_isConnect ? "connect": "disconnect")
1382 .arg(sender->metaObject()->className())
1383 .arg(QLatin1String(d->m_signature));
1384 return throwError(exec, TypeError, msg.toLatin1().constData());
1385 }
1386 } else {
1387 return throwError(exec, GeneralError, "cannot call function of deleted QObject");
1388 }
1389
1390 return jsUndefined();
1391 }
1392
1393 bool QtRuntimeConnectionMethod::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
1394 {
1395 if (propertyName == exec->propertyNames().length) {
1396 slot.setCustom(this, lengthGetter);
1397 return true;
1398 }
1399
1400 return QtRuntimeMethod::getOwnPropertySlot(exec, propertyName, slot);
1401 }
1402
1403 JSValue *QtRuntimeConnectionMethod::lengthGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot&)
1404 {
1405 // we have one formal argument, and one optional
1406 return jsNumber(1);
1407 }
1408
1409 // ===============
1410
1411 QtConnectionObject::QtConnectionObject(PassRefPtr<QtInstance> instance, int signalIndex, JSObject* thisObject, JSObject* funcObject)
1412 : m_instance(instance)
1413 , m_signalIndex(signalIndex)
1414 , m_originalObject(m_instance->getObject())
1415 , m_thisObject(thisObject)
1416 , m_funcObject(funcObject)
1417 {
1418 setParent(m_originalObject);
1419 ASSERT(JSLock::currentThreadIsHoldingLock()); // so our ProtectedPtrs are safe
1420 }
1421
1422 QtConnectionObject::~QtConnectionObject()
1423 {
1424 // Remove us from the map of active connections
1425 QtRuntimeConnectionMethod::connections.remove(m_originalObject, this);
1426 }
1427
1428 static const uint qt_meta_data_QtConnectionObject[] = {
1429
1430 // content:
1431 1, // revision
1432 0, // classname
1433 0, 0, // classinfo
1434 1, 10, // methods
1435 0, 0, // properties
1436 0, 0, // enums/sets
1437
1438 // slots: signature, parameters, type, tag, flags
1439 28, 27, 27, 27, 0x0a,
1440
1441 0 // eod
1442 };
1443
1444 static const char qt_meta_stringdata_QtConnectionObject[] = {
1445 "KJS::Bindings::QtConnectionObject\0\0execute()\0"
1446 };
1447
1448 const QMetaObject QtConnectionObject::staticMetaObject = {
1449 { &QObject::staticMetaObject, qt_meta_stringdata_QtConnectionObject,
1450 qt_meta_data_QtConnectionObject, 0 }
1451 };
1452
1453 const QMetaObject *QtConnectionObject::metaObject() const
1454 {
1455 return &staticMetaObject;
1456 }
1457
1458 void *QtConnectionObject::qt_metacast(const char *_clname)
1459 {
1460 if (!_clname) return 0;
1461 if (!strcmp(_clname, qt_meta_stringdata_QtConnectionObject))
1462 return static_cast<void*>(const_cast<QtConnectionObject*>(this));
1463 return QObject::qt_metacast(_clname);
1464 }
1465
1466 int QtConnectionObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
1467 {
1468 _id = QObject::qt_metacall(_c, _id, _a);
1469 if (_id < 0)
1470 return _id;
1471 if (_c == QMetaObject::InvokeMetaMethod) {
1472 switch (_id) {
1473 case 0: execute(_a); break;
1474 }
1475 _id -= 1;
1476 }
1477 return _id;
1478 }
1479
1480 void QtConnectionObject::execute(void **argv)
1481 {
1482 QObject* obj = m_instance->getObject();
1483 if (obj) {
1484 const QMetaObject* meta = obj->metaObject();
1485 const QMetaMethod method = meta->method(m_signalIndex);
1486
1487 QList<QByteArray> parameterTypes = method.parameterTypes();
1488
1489 int argc = parameterTypes.count();
1490
1491 JSLock lock;
1492
1493 // ### Should the Interpreter/ExecState come from somewhere else?
1494 RefPtr<RootObject> ro = m_instance->rootObject();
1495 if (ro) {
1496 JSGlobalObject* globalobj = ro->globalObject();
1497 if (globalobj) {
1498 ExecState* exec = globalobj->globalExec();
1499 if (exec) {
1500 // Build the argument list (up to the formal argument length of the slot)
1501 List l;
1502 // ### DropAllLocks?
1503 int funcArgC = m_funcObject->get(exec, exec->propertyNames().length)->toInt32(exec);
1504 int argTotal = qMax(funcArgC, argc);
1505 for(int i=0; i < argTotal; i++) {
1506 if (i < argc) {
1507 int argType = QMetaType::type(parameterTypes.at(i));
1508 l.append(convertQVariantToValue(exec, ro, QVariant(argType, argv[i+1])));
1509 } else {
1510 l.append(jsUndefined());
1511 }
1512 }
1513 // Stuff in the __qt_sender property, if we can
1514 if (m_funcObject->inherits(&FunctionImp::info)) {
1515 FunctionImp* fimp = static_cast<FunctionImp*>(m_funcObject.get());
1516
1517 JSObject* qt_sender = Instance::createRuntimeObject(Instance::QtLanguage, sender(), ro);
1518 JSObject* wrapper = new JSObject();
1519 wrapper->put(exec, "__qt_sender__", qt_sender);
1520 ScopeChain oldsc = fimp->scope();
1521 ScopeChain sc = oldsc;
1522 sc.push(wrapper);
1523 fimp->setScope(sc);
1524 fimp->call(exec, m_thisObject, l);
1525 fimp->setScope(oldsc);
1526 } else
1527 m_funcObject->call(exec, m_thisObject, l);
1528 }
1529 }
1530 }
1531 } else {
1532 // A strange place to be - a deleted object emitted a signal here.
1533 qWarning() << "sender deleted, cannot deliver signal";
1534 }
1535 }
1536
1537 bool QtConnectionObject::match(QObject* sender, int signalIndex, JSObject* thisObject, JSObject *funcObject)
1538 {
1539 if (m_originalObject == sender && m_signalIndex == signalIndex
1540 && thisObject == (JSObject*)m_thisObject && funcObject == (JSObject*)m_funcObject)
1541 return true;
1542 return false;
1543 }
1544
1545 // ===============
1546
1547 template <typename T> QtArray<T>::QtArray(QList<T> list, QMetaType::Type type, PassRefPtr<RootObject> rootObject)
1548 : Array(rootObject)
1549 , m_list(list)
1550 , m_type(type)
1551 {
1552 m_length = m_list.count();
1553 }
1554
1555 template <typename T> QtArray<T>::~QtArray ()
1556 {
1557 }
1558
1559 template <typename T> RootObject* QtArray<T>::rootObject() const
1560 {
1561 return _rootObject && _rootObject->isValid() ? _rootObject.get() : 0;
1562 }
1563
1564 template <typename T> void QtArray<T>::setValueAt(ExecState *exec, unsigned int index, JSValue *aValue) const
1565 {
1566 // QtScript sets the value, but doesn't forward it to the original source
1567 // (e.g. if you do 'object.intList[5] = 6', the object is not updated, but the
1568 // copy of the list is).
1569 int dist = -1;
1570 QVariant val = convertValueToQVariant(exec, aValue, m_type, &dist);
1571
1572 if (dist >= 0) {
1573 m_list[index] = val.value<T>();
1574 }
1575 }
1576
1577
1578 template <typename T> JSValue* QtArray<T>::valueAt(ExecState *exec, unsigned int index) const
1579 {
1580 if (index < m_length) {
1581 T val = m_list.at(index);
1582 return convertQVariantToValue(exec, rootObject(), QVariant::fromValue(val));
1583 }
1584
1585 return jsUndefined();
1586 }
1587
1588 // ===============
1589
1590 } }