KJsEmbed

variant_binding.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 2005, 2006 Ian Reinhart Geiser <[email protected]>
3  Copyright (C) 2005, 2006 Matt Broadstone <[email protected]>
4  Copyright (C) 2005, 2006 Richard J. Moore <[email protected]>
5  Copyright (C) 2005, 2006 Erik L. Bunce <[email protected]>
6  Copyright (C) 2007, 2008 Sebastian Sauer <[email protected]>
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Library General Public
10  License as published by the Free Software Foundation; either
11  version 2 of the License, or (at your option) any later version.
12 
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Library General Public License for more details.
17 
18  You should have received a copy of the GNU Library General Public License
19  along with this library; see the file COPYING.LIB. If not, write to
20  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  Boston, MA 02110-1301, USA.
22 */
23 
24 #include "variant_binding.h"
25 
26 #include <stdlib.h>
27 
28 #include <kjs/PropertyNameArray.h>
29 #include <kjs/array_instance.h>
30 
31 #include <QBitRef>
32 #include <QByteRef>
33 #include <QDebug>
34 #include <QObject>
35 #include <QWidget>
36 
37 #include "kjseglobal.h"
38 #include "qobject_binding.h"
39 
40 //#define KJSEMBED_VARIANT_DEBUG
41 
42 using namespace KJSEmbed;
43 
44 const KJS::ClassInfo VariantBinding::info = { "VariantBinding", nullptr, nullptr, nullptr };
45 
47  : ProxyBinding(exec), m_value(value)
48 {
49  StaticBinding::publish(exec, this, VariantFactory::methods());
50 }
51 
52 void *VariantBinding::pointer()
53 {
54  return m_value.data();
55 }
56 
57 KJS::UString VariantBinding::toString(KJS::ExecState *) const
58 {
59  return toUString(m_value.toString());
60 }
61 
62 KJS::UString VariantBinding::className() const
63 {
64  return m_value.typeName();
65 }
66 
68 {
69  return m_value;
70 }
71 
73 {
74  m_value = val;
75 }
76 
77 QGenericArgument VariantBinding::arg(const char *type) const
78 {
79  const void *p = m_value.constData();
80  //qDebug("Ptr %0x", p );
81  //qDebug() << p;
82  return QGenericArgument(type, p);
83 }
84 
85 KJS::JSValue *callName(KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args)
86 {
87  Q_UNUSED(args);
88  KJSEmbed::VariantBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::VariantBinding>(exec, self);
89  return imp ? KJS::jsString(imp->variant().typeName()) : KJS::jsNull();
90 }
91 
92 KJS::JSValue *callCast(KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args)
93 {
94  KJSEmbed::VariantBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::VariantBinding>(exec, self);
95  if (imp) {
96  QVariant val = imp->variant();
97  QVariant::Type type = QVariant::nameToType(args[0]->toString(exec).ascii());
98  KJS::JSValue *returnValue = KJS::jsBoolean(val.convert(type));
99  imp->setValue(val);
100  return returnValue;
101  }
102  return KJS::jsNull();
103 }
104 
105 KJS::JSValue *callToString(KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args)
106 {
107  Q_UNUSED(args);
108  KJSEmbed::VariantBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::VariantBinding>(exec, self);
109  if (imp) {
110  //qDebug("Call value to string");
111  QVariant val = imp->variant();
112  QString stringVal = val.toString();
113  if (!stringVal.isEmpty()) {
114  return KJS::jsString(val.toString());
115  }
116  return KJS::jsString(val.typeName());
117  }
118  return KJS::jsNull();
119 }
120 
121 const Method VariantFactory::VariantMethods[] = {
122  {"cast", 1, KJS::DontDelete | KJS::ReadOnly | KJS::DontEnum, &callCast },
123  {"toString", 0, KJS::DontDelete | KJS::ReadOnly | KJS::DontEnum, &callToString },
124  {nullptr, 0, 0, nullptr }
125 };
126 
127 enum JavaScriptArrayType { None, List, Map };
128 
129 JavaScriptArrayType checkArray(KJS::ExecState *exec, KJS::JSValue *val)
130 {
131  KJS::JSObject *obj = val->toObject(exec);
132  if (toQString(obj->className()) == "Array") {
133  if (!obj->hasProperty(exec, KJS::Identifier("length"))) {
134  return Map;
135  }
136  KJS::JSValue *jslen = obj->get(exec, KJS::Identifier("length"));
137  const int len = jslen->toNumber(exec);
138  if (len > 0) {
139  QByteArray buff;
140  buff.setNum(len - 1);
141  if (!obj->hasProperty(exec, KJS::Identifier(buff.data()))) {
142  return Map;
143  }
144  }
145  return List;
146  } else {
147  return None;
148  }
149 }
150 
151 QMap<QString, QVariant> KJSEmbed::convertArrayToMap(KJS::ExecState *exec, KJS::JSValue *value)
152 {
153  QMap<QString, QVariant> returnMap;
154  KJS::JSObject *obj = value->toObject(exec);
155  KJS::PropertyNameArray lst;
156  obj->getPropertyNames(exec, lst);
157  KJS::PropertyNameArrayIterator idx = lst.begin();
158  for (; idx != lst.end(); idx++) {
159  KJS::Identifier id = *idx;
160  KJS::JSValue *val = obj->get(exec, id);
161  returnMap[toQString(id)] = convertToVariant(exec, val);
162  }
163  return returnMap;
164 }
165 
166 QList<QVariant> KJSEmbed::convertArrayToList(KJS::ExecState *exec, KJS::JSValue *value)
167 {
168  QList<QVariant> returnList;
169  /*
170  KJS::JSObject *obj = value->toObject( exec );
171  if ( toQString(obj->className() == "Array" )
172  {
173  int length = int(obj->get( exec, KJS::Identifier( "length" ) )->toInteger( exec ) );
174  for ( int index = 0; index < length; ++index )
175  {
176  QByteArray buff;
177  buff.setNum(index);
178  KJS::JSValue *val = obj->get(exec, KJS::Identifier( buff.data() ) );
179  if( val )
180  returnList += convertToVariant(exec, val );
181  else
182  returnList += QVariant();
183  }
184  }
185  */
186  KJS::ArrayInstance *arrayImp = extractBindingImp<KJS::ArrayInstance>(exec, value);
187  if (arrayImp) {
188  const unsigned numItems = arrayImp->getLength();
189  for (unsigned i = 0; i < numItems; ++i) {
190  returnList.append(convertToVariant(exec, arrayImp->getItem(i)));
191  }
192  }
193  return returnList;
194 }
195 
196 QStringList KJSEmbed::convertArrayToStringList(KJS::ExecState *exec, KJS::JSValue *value)
197 {
198  QStringList returnList;
199  /*
200  KJS::JSObject *obj = value->toObject( exec );
201  if ( toQString(obj->className()) == "Array" )
202  {
203  int length = int( obj->get( exec, KJS::Identifier( "length" ) )->toInteger( exec ) );
204  for ( int index = 0; index < length; ++index )
205  {
206  QByteArray buff;
207  buff.setNum(index);
208  KJS::JSValue *val = obj->get(exec, KJS::Identifier( buff.data() ) );
209  if( val )
210  returnList += convertToVariant(exec, val ).value<QString>();
211  else
212  returnList += QString();
213  }
214  }
215  */
216  KJS::ArrayInstance *arrayImp = extractBindingImp<KJS::ArrayInstance>(exec, value);
217  if (arrayImp) {
218  const unsigned numItems = arrayImp->getLength();
219  for (unsigned i = 0; i < numItems; ++i) {
220  returnList.append(convertToVariant(exec, arrayImp->getItem(i)).toString());
221  }
222  }
223  return returnList;
224 }
225 
226 QDateTime convertDateToDateTime(KJS::ExecState *exec, KJS::JSValue *value)
227 {
228  KJS::List args;
229  QDateTime returnDateTime;
230  KJS::JSObject *obj = value->toObject(exec);
231  if (toQString(obj->className()) == "Date") {
232  int seconds = int(obj->get(exec, KJS::Identifier("getSeconds"))->toObject(exec)->call(exec, obj, args)->toInteger(exec));
233  int minutes = int(obj->get(exec, KJS::Identifier("getMinutes"))->toObject(exec)->call(exec, obj, args)->toInteger(exec));
234  int hours = int(obj->get(exec, KJS::Identifier("getHours"))->toObject(exec)->call(exec, obj, args)->toInteger(exec));
235  int month = int(obj->get(exec, KJS::Identifier("getMonth"))->toObject(exec)->call(exec, obj, args)->toInteger(exec));
236  int day = int(obj->get(exec, KJS::Identifier("getDate"))->toObject(exec)->call(exec, obj, args)->toInteger(exec));
237  int year = int(obj->get(exec, KJS::Identifier("getFullYear"))->toObject(exec)->call(exec, obj, args)->toInteger(exec));
238  returnDateTime.setDate(QDate(year, month + 1, day));
239  returnDateTime.setTime(QTime(hours, minutes, seconds));
240  } else {
241  // Throw error
242  }
243 
244  return returnDateTime;
245 }
246 
247 QVariant KJSEmbed::convertToVariant(KJS::ExecState *exec, KJS::JSValue *value)
248 {
249 #ifdef KJSEMBED_VARIANT_DEBUG
250  qDebug() << "KJSEmbed::convertToVariant";
251 #endif
252 
253  QVariant returnValue;
254  switch (value->type()) {
255  case KJS::UndefinedType:
256  case KJS::NullType:
257  break;
258  case KJS::StringType:
259  returnValue = toQString(value->toString(exec));
260  break;
261  case KJS::NumberType:
262  returnValue = value->toNumber(exec);
263  break;
264  case KJS::BooleanType:
265  returnValue = value->toBoolean(exec);
266  break;
267  case KJS::ObjectType: {
268  KJS::JSObject *obj = value->toObject(exec);
269  //qDebug() << "Object type: " << toQString(obj->className());
270  if (toQString(obj->className()) == "Array") {
271  if (checkArray(exec, value) == List) {
272  returnValue = convertArrayToList(exec, value);
273  } else {
274  returnValue = convertArrayToMap(exec, value);
275  }
276  } else if (toQString(obj->className()) == "Date") {
277  returnValue = convertDateToDateTime(exec, value);
278  } else {
279  returnValue = extractVariant(exec, value);
280  }
281  //if( returnValue.isNull() ) returnValue = toQString(value->toString(exec));
282  } break;
283  default:
284  returnValue = extractVariant(exec, value);
285  //if( returnValue.isNull() ) returnValue = toQString(value->toString(exec));
286  break;
287  }
288  return returnValue;
289 }
290 
291 KJS::JSValue *KJSEmbed::convertToValue(KJS::ExecState *exec, const QVariant &value)
292 {
293 #ifdef KJSEMBED_VARIANT_DEBUG
294  qDebug() << "KJSEmbed::convertToValue typeid=" << value.type() << "typename=" << value.typeName() << "toString=" << value.toString();
295 #endif
296 
297  KJS::JSValue *returnValue;
298  switch (value.type()) {
299  case QVariant::Invalid:
300  returnValue = KJS::jsNull();
301  break;
302  case QVariant::Int:
303  returnValue = KJS::jsNumber(value.value<int>());
304  break;
305  case QVariant::UInt:
306  returnValue = KJS::jsNumber(value.value<unsigned int>());
307  break;
308  case QVariant::LongLong:
309  returnValue = KJS::jsNumber(value.value<qlonglong>());
310  break;
311  case QVariant::ULongLong:
312  returnValue = KJS::jsNumber(value.value<qulonglong>());
313  break;
314  case QVariant::Double:
315  returnValue = KJS::jsNumber(value.value<double>());
316  break;
317  case QVariant::Bool:
318  returnValue = KJS::jsBoolean(value.value<bool>());
319  break;
320  case QVariant::ByteArray:
321  returnValue = KJS::jsString(QString(value.value<QByteArray>()));
322  break;
323  case QVariant::String:
324  returnValue = KJS::jsString(value.value<QString>());
325  break;
326  case QVariant::StringList: {
327  KJS::List items;
328  QStringList lst = value.value<QStringList>();
329  QStringList::Iterator idx = lst.begin();
330  for (; idx != lst.end(); ++idx) {
331  items.append(KJS::jsString((*idx)));
332  }
333  returnValue = exec->lexicalInterpreter()->builtinArray()->construct(exec, items);
334  break;
335  }
336  case QVariant::Date: // fall through
337  case QVariant::DateTime: // fall through
338  case QVariant::Time: {
340  if (value.type() == QVariant::Date) {
341  dt.setDate(value.toDate());
342  } else if (value.type() == QVariant::Time) {
343  dt.setTime(value.toTime());
344  } else {
345  dt = value.toDateTime();
346  }
347 
348  KJS::List items;
349  items.append(KJS::jsNumber(dt.date().year()));
350  items.append(KJS::jsNumber(dt.date().month() - 1));
351  items.append(KJS::jsNumber(dt.date().day()));
352  items.append(KJS::jsNumber(dt.time().hour()));
353  items.append(KJS::jsNumber(dt.time().minute()));
354  items.append(KJS::jsNumber(dt.time().second()));
355  items.append(KJS::jsNumber(dt.time().msec()));
356  returnValue = exec->lexicalInterpreter()->builtinDate()->construct(exec, items);
357  break;
358  }
359  case QVariant::List: {
360  KJS::List items;
361  QList<QVariant> lst = value.toList();
362  foreach (const QVariant &item, lst) {
363  items.append(convertToValue(exec, item));
364  }
365  returnValue = exec->lexicalInterpreter()->builtinArray()->construct(exec, items);
366  break;
367  }
368  case QVariant::Map: {
369  QMap<QString, QVariant> map = value.toMap();
370  QMap<QString, QVariant>::Iterator idx = map.begin();
371  KJS::JSObject *obj = exec->lexicalInterpreter()->builtinObject()->construct(exec, KJS::List());
372  for (; idx != map.end(); ++idx) {
373  obj->put(exec, KJS::Identifier(toUString(idx.key())), convertToValue(exec, idx.value()));
374  }
375  returnValue = obj;
376  break;
377  }
378  default: {
379  if (value.canConvert< QWidget * >()) {
380  QWidget *widget = qvariant_cast< QWidget * >(value);
381  returnValue = widget ? createQObject(exec, widget, KJSEmbed::ObjectBinding::CPPOwned) : KJS::jsNull();
382  } else if (value.canConvert< QObject * >()) {
383  QObject *object = qvariant_cast< QObject * >(value);
384  returnValue = object ? createQObject(exec, object, KJSEmbed::ObjectBinding::CPPOwned) : KJS::jsNull();
385  } else {
386  returnValue = createVariant(exec, value.typeName(), value);
387  if (returnValue->isNull()) {
388  returnValue = KJS::jsString(value.value<QString>());
389  }
390  }
391  break;
392  }
393  }
394  return returnValue;
395 }
396 
397 QVariant KJSEmbed::extractVariant(KJS::ExecState *exec, KJS::JSValue *value)
398 {
399 #ifdef KJSEMBED_VARIANT_DEBUG
400  qDebug() << "KJSEmbed::extractVariant";
401 #endif
402 
403  KJSEmbed::VariantBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::VariantBinding>(exec, value);
404  if (imp) {
405  return imp->variant();
406  }
407  if (value->type() == KJS::StringType) {
408  return QVariant(toQString(value->toString(exec)));
409  }
410  if (value->type() == KJS::NumberType) {
411  return QVariant(value->toNumber(exec));
412  }
413  if (value->type() == KJS::BooleanType) {
414  return QVariant(value->toBoolean(exec));
415  }
416 
417  KJS::JSObject *obj = value->toObject(exec);
418  if (obj) {
419  if (QObjectBinding *objImp = KJSEmbed::extractBindingImp<QObjectBinding>(exec, value)) {
420  QVariant v;
421  if (QObject *qobj = objImp->qobject<QObject>()) {
422  v.setValue(qobj);
423  }
424  return v;
425  }
426  if (toQString(obj->className()) == "Array") {
427  return convertArrayToList(exec, value);
428  }
429  }
430  return QVariant();
431 }
432 
void append(const T &value)
void append(JSValue *val)
int month() const const
QDateTime currentDateTime()
T value() const const
QTime time() const const
int year() const const
Implement QString-KJS::UString conversion methods.
QVariant::Type nameToType(const char *name)
QByteArray & setNum(short n, int base)
VariantBinding(KJS::ExecState *exec, const QVariant &value)
Create a new binding implementation with a QVariant to wrap.
QDate toDate() const const
void setValue(const T &value)
void setDate(const QDate &date)
JSObject * builtinObject() const
QVariant::Type type() const const
bool isEmpty() const const
JSObject * builtinDate() const
int msec() const const
static void publish(KJS::ExecState *exec, KJS::JSObject *object, const Method *methods)
Publishes an array of Methods to an object.
int hour() const const
QMap< QString, QVariant > toMap() const const
QVariant based binding.
bool canConvert(int targetTypeId) const const
Interpreter * lexicalInterpreter() const
typedef Iterator
QDateTime toDateTime() const const
Method structure.
int second() const const
JSObject * builtinArray() const
QTime toTime() const const
void setValue(const QVariant &val)
Set the internal value of the QVariant.
QDate date() const const
QVariant variant() const
Return the wrapped QVariant.
QList< QVariant > toList() const const
QList::iterator begin()
QList::iterator end()
const char * typeName() const const
QGenericArgument arg(const char *type) const
Constructs a QGenericArgument that is used with QMetaObject::invokeMember.
int minute() const const
void setTime(const QTime &time)
char * data()
QString toString() const const
int day() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Dec 10 2023 03:59:19 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.