Update copyright year in license headers.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / v8 / qdeclarativebuiltinfunctions.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdeclarativebuiltinfunctions_p.h"
43
44 #include <QtDeclarative/qdeclarativecomponent.h>
45 #include <private/qdeclarativeengine_p.h>
46 #include <private/qdeclarativecomponent_p.h>
47 #include <private/qdeclarativestringconverters_p.h>
48 #include <private/qdeclarativelocale_p.h>
49 #include <private/qv8engine_p.h>
50
51 #include <private/qv8profilerservice_p.h>
52 #include <private/qdeclarativedebugtrace_p.h>
53
54 #include <QtCore/qstring.h>
55 #include <QtCore/qdatetime.h>
56 #include <QtCore/qcryptographichash.h>
57 #include <QtCore/qrect.h>
58 #include <QtCore/qsize.h>
59 #include <QtCore/qpoint.h>
60 #include <QtCore/qurl.h>
61 #include <QtCore/qfile.h>
62 #include <QtCore/qcoreapplication.h>
63
64 #include <QtGui/qcolor.h>
65 #include <QtGui/qvector3d.h>
66 #include <QtGui/qvector4d.h>
67 #include <QtGui/qdesktopservices.h>
68 #include <QtGui/qfontdatabase.h>
69
70 QT_BEGIN_NAMESPACE
71
72 // send more information such as file, line etc for console APIs
73 DEFINE_BOOL_CONFIG_OPTION(qmlConsoleExtended, QML_CONSOLE_EXTENDED)
74
75 namespace QDeclarativeBuiltinFunctions {
76
77 enum ConsoleLogTypes {
78     Log,
79     Warn,
80     Error
81 };
82
83 v8::Handle<v8::Value> console(ConsoleLogTypes logType, const v8::Arguments &args)
84 {
85     v8::HandleScope handleScope;
86
87     QString result;
88     for (int i = 0; i < args.Length(); ++i) {
89         if (i != 0)
90             result.append(QLatin1Char(' '));
91
92         v8::Local<v8::Value> value = args[i];
93         //Check for Object Type
94         if (value->IsObject() && !value->IsFunction()
95                 && !value->IsArray() && !value->IsDate()
96                 && !value->IsRegExp()) {
97             result.append(QLatin1String("Object"));
98         } else {
99             v8::Local<v8::String> jsstr = value->ToString();
100             QString tmp = V8ENGINE()->toString(jsstr);
101             if (value->IsArray())
102                 result.append(QString::fromLatin1("[%1]").arg(tmp));
103             else
104                 result.append(tmp);
105         }
106     }
107
108     if (qmlConsoleExtended()) {
109         int line = -1;
110         QString scriptName;
111         //get only current frame
112         v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(1);
113         if (stackTrace->GetFrameCount()) {
114             v8::Local<v8::StackFrame> currentStackFrame = stackTrace->GetFrame(0);
115             line = currentStackFrame->GetLineNumber();
116             scriptName = V8ENGINE()->toString(currentStackFrame->GetScriptName());
117         }
118
119         result = QString(QLatin1String("%1 (%2:%3)")).arg(result).arg(scriptName).arg(line);
120     }
121
122     switch (logType) {
123     case Log:
124         qDebug("%s", qPrintable(result));
125         break;
126     case Warn:
127         qWarning("%s", qPrintable(result));
128         break;
129     case Error:
130         qCritical("%s", qPrintable(result));
131         break;
132     default:
133         break;
134     }
135
136     return v8::Undefined();
137 }
138
139 v8::Handle<v8::Value> gc(const v8::Arguments &args)
140 {
141     Q_UNUSED(args);
142     QV8Engine::gc();
143     return v8::Undefined();
144 }
145
146 v8::Handle<v8::Value> consoleError(const v8::Arguments &args)
147 {
148     return console(Error, args);
149 }
150
151 v8::Handle<v8::Value> consoleLog(const v8::Arguments &args)
152 {
153     //console.log
154     //console.debug
155     //print
156     return console(Log, args);
157 }
158
159 v8::Handle<v8::Value> consoleProfile(const v8::Arguments &args)
160 {
161     //DeclarativeDebugTrace cannot handle nested profiling
162     //although v8 can handle several profiling at once,
163     //we do not allow that. Hence, we pass an empty(default) title
164     Q_UNUSED(args);
165     QString title;
166
167     if (QDeclarativeDebugTrace::startProfiling()) {
168         QV8ProfilerService::instance()->startProfiling(title);
169         qDebug("Profiling started.");
170     } else {
171         qWarning("Profiling is already in progress. First, end current profiling session.");
172     }
173
174     return v8::Undefined();
175 }
176
177 v8::Handle<v8::Value> consoleProfileEnd(const v8::Arguments &args)
178 {
179     //DeclarativeDebugTrace cannot handle nested profiling
180     //although v8 can handle several profiling at once,
181     //we do not allow that. Hence, we pass an empty(default) title
182     Q_UNUSED(args);
183     QString title;
184
185     if (QDeclarativeDebugTrace::stopProfiling()) {
186         QV8ProfilerService *profiler = QV8ProfilerService::instance();
187         profiler->stopProfiling(title);
188         QDeclarativeDebugTrace::sendProfilingData();
189         profiler->sendProfilingData();
190         qDebug("Profiling ended.");
191     } else {
192         qWarning("Profiling was not started.");
193     }
194
195     return v8::Undefined();
196 }
197
198 v8::Handle<v8::Value> consoleTime(const v8::Arguments &args)
199 {
200     if (args.Length() != 1)
201         V8THROW_ERROR("console.time(): Invalid arguments");
202     QString name = V8ENGINE()->toString(args[0]);
203     V8ENGINE()->startTimer(name);
204     return v8::Undefined();
205 }
206
207 v8::Handle<v8::Value> consoleTimeEnd(const v8::Arguments &args)
208 {
209     if (args.Length() != 1)
210         V8THROW_ERROR("console.time(): Invalid arguments");
211     QString name = V8ENGINE()->toString(args[0]);
212     bool wasRunning;
213     qint64 elapsed = V8ENGINE()->stopTimer(name, &wasRunning);
214     if (wasRunning) {
215         qDebug("%s: %llims", qPrintable(name), elapsed);
216     }
217     return v8::Undefined();
218 }
219
220 v8::Handle<v8::Value> consoleTrace(const v8::Arguments &args)
221 {
222     if (args.Length() != 0)
223         V8THROW_ERROR("console.trace(): Invalid arguments");
224
225     //The v8 default is currently 10 stack frames.
226     v8::Handle<v8::StackTrace> stackTrace =
227         v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
228     int stackCount = stackTrace->GetFrameCount();
229
230     for (int i = 0; i < stackCount; i++) {
231         v8::Local<v8::StackFrame> frame = stackTrace->GetFrame(i);
232         v8::String::Utf8Value func_name(frame->GetFunctionName());
233         v8::String::Utf8Value script_name(frame->GetScriptName());
234         int lineNumber = frame->GetLineNumber();
235         int columnNumber = frame->GetColumn();
236         qDebug("%s (%s:%d:%d)\n", *func_name, *script_name, lineNumber, columnNumber);
237     }
238     return v8::Undefined();
239 }
240
241 v8::Handle<v8::Value> consoleWarn(const v8::Arguments &args)
242 {
243     return console(Warn, args);
244 }
245
246 v8::Handle<v8::Value> stringArg(const v8::Arguments &args)
247 {
248     QString value = V8ENGINE()->toString(args.This()->ToString());
249     if (args.Length() != 1)
250         V8THROW_ERROR("String.arg(): Invalid arguments");
251
252     v8::Handle<v8::Value> arg = args[0];
253     if (arg->IsUint32())
254         return V8ENGINE()->toString(value.arg(arg->Uint32Value()));
255     else if (arg->IsInt32())
256         return V8ENGINE()->toString(value.arg(arg->Int32Value()));
257     else if (arg->IsNumber())
258         return V8ENGINE()->toString(value.arg(arg->NumberValue()));
259     else if (arg->IsBoolean())
260         return V8ENGINE()->toString(value.arg(arg->BooleanValue()));
261
262     return V8ENGINE()->toString(value.arg(V8ENGINE()->toString(arg)));
263 }
264
265 /*!
266 \qmlmethod bool Qt::isQtObject(object)
267 Returns true if \c object is a valid reference to a Qt or QML object, otherwise false.
268 */
269 v8::Handle<v8::Value> isQtObject(const v8::Arguments &args)
270 {
271     if (args.Length() == 0)
272         return v8::Boolean::New(false);
273
274     return v8::Boolean::New(0 != V8ENGINE()->toQObject(args[0]));
275 }
276
277 /*!
278 \qmlmethod color Qt::rgba(real red, real green, real blue, real alpha)
279
280 Returns a color with the specified \c red, \c green, \c blue and \c alpha components.
281 All components should be in the range 0-1 inclusive.
282 */
283 v8::Handle<v8::Value> rgba(const v8::Arguments &args)
284 {
285     int argCount = args.Length();
286     if (argCount < 3 || argCount > 4)
287         V8THROW_ERROR("Qt.rgba(): Invalid arguments");
288
289     double r = args[0]->NumberValue();
290     double g = args[1]->NumberValue();
291     double b = args[2]->NumberValue();
292     double a = (argCount == 4) ? args[3]->NumberValue() : 1;
293
294     if (r < 0.0) r=0.0;
295     if (r > 1.0) r=1.0;
296     if (g < 0.0) g=0.0;
297     if (g > 1.0) g=1.0;
298     if (b < 0.0) b=0.0;
299     if (b > 1.0) b=1.0;
300     if (a < 0.0) a=0.0;
301     if (a > 1.0) a=1.0;
302
303     return V8ENGINE()->fromVariant(QVariant::fromValue(QColor::fromRgbF(r, g, b, a)));
304 }
305
306 /*!
307 \qmlmethod color Qt::hsla(real hue, real saturation, real lightness, real alpha)
308
309 Returns a color with the specified \c hue, \c saturation, \c lightness and \c alpha components.
310 All components should be in the range 0-1 inclusive.
311 */
312 v8::Handle<v8::Value> hsla(const v8::Arguments &args)
313 {
314     int argCount = args.Length();
315     if (argCount < 3 || argCount > 4)
316         V8THROW_ERROR("Qt.hsla(): Invalid arguments");
317
318     double h = args[0]->NumberValue();
319     double s = args[1]->NumberValue();
320     double l = args[2]->NumberValue();
321     double a = (argCount == 4) ? args[3]->NumberValue() : 1;
322
323     if (h < 0.0) h=0.0;
324     if (h > 1.0) h=1.0;
325     if (s < 0.0) s=0.0;
326     if (s > 1.0) s=1.0;
327     if (l < 0.0) l=0.0;
328     if (l > 1.0) l=1.0;
329     if (a < 0.0) a=0.0;
330     if (a > 1.0) a=1.0;
331
332     return V8ENGINE()->fromVariant(QVariant::fromValue(QColor::fromHslF(h, s, l, a)));
333 }
334
335 /*!
336 \qmlmethod rect Qt::rect(int x, int y, int width, int height)
337
338 Returns a \c rect with the top-left corner at \c x, \c y and the specified \c width and \c height.
339
340 The returned object has \c x, \c y, \c width and \c height attributes with the given values.
341 */
342 v8::Handle<v8::Value> rect(const v8::Arguments &args)
343 {
344     if (args.Length() != 4)
345         V8THROW_ERROR("Qt.rect(): Invalid arguments");
346
347     double x = args[0]->NumberValue();
348     double y = args[1]->NumberValue();
349     double w = args[2]->NumberValue();
350     double h = args[3]->NumberValue();
351
352     return V8ENGINE()->fromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
353 }
354
355 /*!
356 \qmlmethod point Qt::point(int x, int y)
357 Returns a Point with the specified \c x and \c y coordinates.
358 */
359 v8::Handle<v8::Value> point(const v8::Arguments &args)
360 {
361     if (args.Length() != 2)
362         V8THROW_ERROR("Qt.point(): Invalid arguments");
363
364     double x = args[0]->ToNumber()->Value();
365     double y = args[1]->ToNumber()->Value();
366
367     return V8ENGINE()->fromVariant(QVariant::fromValue(QPointF(x, y)));
368 }
369
370 /*!
371 \qmlmethod Qt::size(int width, int height)
372 Returns a Size with the specified \c width and \c height.
373 */
374 v8::Handle<v8::Value> size(const v8::Arguments &args)
375 {
376     if (args.Length() != 2)
377         V8THROW_ERROR("Qt.size(): Invalid arguments");
378
379     double w = args[0]->ToNumber()->Value();
380     double h = args[1]->ToNumber()->Value();
381
382     return V8ENGINE()->fromVariant(QVariant::fromValue(QSizeF(w, h)));
383 }
384
385 /*!
386 \qmlmethod Qt::vector3d(real x, real y, real z)
387 Returns a Vector3D with the specified \c x, \c y and \c z.
388 */
389 v8::Handle<v8::Value> vector3d(const v8::Arguments &args)
390 {
391     if (args.Length() != 3)
392         V8THROW_ERROR("Qt.vector(): Invalid arguments");
393
394     double x = args[0]->ToNumber()->Value();
395     double y = args[1]->ToNumber()->Value();
396     double z = args[2]->ToNumber()->Value();
397
398     return V8ENGINE()->fromVariant(QVariant::fromValue(QVector3D(x, y, z)));
399 }
400
401 /*!
402 \qmlmethod Qt::vector4d(real x, real y, real z, real w)
403 Returns a Vector4D with the specified \c x, \c y, \c z and \c w.
404 */
405 v8::Handle<v8::Value> vector4d(const v8::Arguments &args)
406 {
407     if (args.Length() != 4)
408         V8THROW_ERROR("Qt.vector4d(): Invalid arguments");
409
410     double x = args[0]->NumberValue();
411     double y = args[1]->NumberValue();
412     double z = args[2]->NumberValue();
413     double w = args[3]->NumberValue();
414
415     return V8ENGINE()->fromVariant(QVariant::fromValue(QVector4D(x, y, z, w)));
416 }
417
418 /*!
419 \qmlmethod color Qt::lighter(color baseColor, real factor)
420 Returns a color lighter than \c baseColor by the \c factor provided.
421
422 If the factor is greater than 1.0, this functions returns a lighter color.
423 Setting factor to 1.5 returns a color that is 50% brighter. If the factor is less than 1.0,
424 the return color is darker, but we recommend using the Qt.darker() function for this purpose.
425 If the factor is 0 or negative, the return value is unspecified.
426
427 The function converts the current RGB color to HSV, multiplies the value (V) component
428 by factor and converts the color back to RGB.
429
430 If \c factor is not supplied, returns a color 50% lighter than \c baseColor (factor 1.5).
431 */
432 v8::Handle<v8::Value> lighter(const v8::Arguments &args)
433 {
434     if (args.Length() != 1 && args.Length() != 2)
435         V8THROW_ERROR("Qt.lighter(): Invalid arguments");
436
437     QColor color;
438     QVariant v = V8ENGINE()->toVariant(args[0], -1);
439     if (v.userType() == QVariant::Color) {
440         color = v.value<QColor>();
441     } else if (v.userType() == QVariant::String) {
442         bool ok = false;
443         color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
444         if (!ok) {
445             return v8::Null();
446         }
447     } else {
448         return v8::Null();
449     }
450
451     qreal factor = 1.5;
452     if (args.Length() == 2)
453         factor = args[1]->ToNumber()->Value();
454
455     color = color.lighter(int(qRound(factor*100.)));
456     return V8ENGINE()->fromVariant(QVariant::fromValue(color));
457 }
458
459 /*!
460 \qmlmethod color Qt::darker(color baseColor, real factor)
461 Returns a color darker than \c baseColor by the \c factor provided.
462
463 If the factor is greater than 1.0, this function returns a darker color.
464 Setting factor to 3.0 returns a color that has one-third the brightness.
465 If the factor is less than 1.0, the return color is lighter, but we recommend using
466 the Qt.lighter() function for this purpose. If the factor is 0 or negative, the return
467 value is unspecified.
468
469 The function converts the current RGB color to HSV, divides the value (V) component
470 by factor and converts the color back to RGB.
471
472 If \c factor is not supplied, returns a color 50% darker than \c baseColor (factor 2.0).
473 */
474 v8::Handle<v8::Value> darker(const v8::Arguments &args)
475 {
476     if (args.Length() != 1 && args.Length() != 2)
477         V8THROW_ERROR("Qt.darker(): Invalid arguments");
478
479     QColor color;
480     QVariant v = V8ENGINE()->toVariant(args[0], -1);
481     if (v.userType() == QVariant::Color) {
482         color = v.value<QColor>();
483     } else if (v.userType() == QVariant::String) {
484         bool ok = false;
485         color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
486         if (!ok) {
487             return v8::Null();
488         }
489     } else {
490         return v8::Null();
491     }
492
493     qreal factor = 2.0;
494     if (args.Length() == 2)
495         factor = args[1]->ToNumber()->Value();
496
497     color = color.darker(int(qRound(factor*100.)));
498     return V8ENGINE()->fromVariant(QVariant::fromValue(color));
499 }
500
501 /*!
502     \qmlmethod color Qt::tint(color baseColor, color tintColor)
503     This function allows tinting one color with another.
504
505     The tint color should usually be mostly transparent, or you will not be
506     able to see the underlying color. The below example provides a slight red
507     tint by having the tint color be pure red which is only 1/16th opaque.
508
509     \qml
510     Item {
511         Rectangle {
512             x: 0; width: 80; height: 80
513             color: "lightsteelblue"
514         }
515         Rectangle {
516             x: 100; width: 80; height: 80
517             color: Qt.tint("lightsteelblue", "#10FF0000")
518         }
519     }
520     \endqml
521     \image declarative-rect_tint.png
522
523     Tint is most useful when a subtle change is intended to be conveyed due to some event; you can then use tinting to more effectively tune the visible color.
524 */
525 v8::Handle<v8::Value> tint(const v8::Arguments &args)
526 {
527     if (args.Length() != 2)
528         V8THROW_ERROR("Qt.tint(): Invalid arguments");
529
530     // base color
531     QColor color;
532     QVariant v = V8ENGINE()->toVariant(args[0], -1);
533     if (v.userType() == QVariant::Color) {
534         color = v.value<QColor>();
535     } else if (v.userType() == QVariant::String) {
536         bool ok = false;
537         color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
538         if (!ok) {
539             return v8::Null();
540         }
541     } else {
542         return v8::Null();
543     }
544
545     // tint color
546     QColor tintColor;
547     v = V8ENGINE()->toVariant(args[1], -1);
548     if (v.userType() == QVariant::Color) {
549         tintColor = v.value<QColor>();
550     } else if (v.userType() == QVariant::String) {
551         bool ok = false;
552         tintColor = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
553         if (!ok) {
554             return v8::Null();
555         }
556     } else {
557         return v8::Null();
558     }
559
560     // tint the base color and return the final color
561     QColor finalColor;
562     int a = tintColor.alpha();
563     if (a == 0xFF)
564         finalColor = tintColor;
565     else if (a == 0x00)
566         finalColor = color;
567     else {
568         qreal a = tintColor.alphaF();
569         qreal inv_a = 1.0 - a;
570
571         finalColor.setRgbF(tintColor.redF() * a + color.redF() * inv_a,
572                            tintColor.greenF() * a + color.greenF() * inv_a,
573                            tintColor.blueF() * a + color.blueF() * inv_a,
574                            a + inv_a * color.alphaF());
575     }
576
577     return V8ENGINE()->fromVariant(QVariant::fromValue(finalColor));
578 }
579
580 /*!
581 \qmlmethod string Qt::formatDate(datetime date, variant format)
582
583 Returns a string representation of \c date, optionally formatted according
584 to \c format.
585
586 The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
587 property, a QDate, or QDateTime value. The \a format parameter may be any of
588 the possible format values as described for
589 \l{QML:Qt::formatDateTime()}{Qt.formatDateTime()}.
590
591 If \a format is not specified, \a date is formatted using
592 \l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
593
594 \sa Locale
595 */
596 v8::Handle<v8::Value> formatDate(const v8::Arguments &args)
597 {
598     if (args.Length() < 1 || args.Length() > 2)
599         V8THROW_ERROR("Qt.formatDate(): Invalid arguments");
600
601     Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
602     QDate date = V8ENGINE()->toVariant(args[0], -1).toDateTime().date();
603     QString formattedDate;
604     if (args.Length() == 2) {
605         if (args[1]->IsString()) {
606             QString format = V8ENGINE()->toVariant(args[1], -1).toString();
607             formattedDate = date.toString(format);
608         } else if (args[1]->IsNumber()) {
609             quint32 intFormat = args[1]->ToNumber()->Value();
610             Qt::DateFormat format = Qt::DateFormat(intFormat);
611             formattedDate = date.toString(format);
612         } else {
613             V8THROW_ERROR("Qt.formatDate(): Invalid date format");
614         }
615     } else {
616          formattedDate = date.toString(enumFormat);
617     }
618
619     return V8ENGINE()->fromVariant(QVariant::fromValue(formattedDate));
620 }
621
622 /*!
623 \qmlmethod string Qt::formatTime(datetime time, variant format)
624
625 Returns a string representation of \c time, optionally formatted according to
626 \c format.
627
628 The \a time parameter may be a JavaScript \c Date object, a QTime, or QDateTime
629 value. The \a format parameter may be any of the possible format values as
630 described for \l{QML:Qt::formatDateTime()}{Qt.formatDateTime()}.
631
632 If \a format is not specified, \a time is formatted using
633 \l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
634
635 \sa Locale
636 */
637 v8::Handle<v8::Value> formatTime(const v8::Arguments &args)
638 {
639     if (args.Length() < 1 || args.Length() > 2)
640         V8THROW_ERROR("Qt.formatTime(): Invalid arguments");
641
642     QVariant argVariant = V8ENGINE()->toVariant(args[0], -1);
643     QTime time;
644     if (args[0]->IsDate() || (argVariant.type() == QVariant::String))
645         time = argVariant.toDateTime().time();
646     else // if (argVariant.type() == QVariant::Time), or invalid.
647         time = argVariant.toTime();
648
649     Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
650     QString formattedTime;
651     if (args.Length() == 2) {
652         if (args[1]->IsString()) {
653             QString format = V8ENGINE()->toVariant(args[1], -1).toString();
654             formattedTime = time.toString(format);
655         } else if (args[1]->IsNumber()) {
656             quint32 intFormat = args[1]->ToNumber()->Value();
657             Qt::DateFormat format = Qt::DateFormat(intFormat);
658             formattedTime = time.toString(format);
659         } else {
660             V8THROW_ERROR("Qt.formatTime(): Invalid time format");
661         }
662     } else {
663          formattedTime = time.toString(enumFormat);
664     }
665
666     return V8ENGINE()->fromVariant(QVariant::fromValue(formattedTime));
667 }
668
669 /*!
670 \qmlmethod string Qt::formatDateTime(datetime dateTime, variant format)
671
672 Returns a string representation of \c datetime, optionally formatted according to
673 \c format.
674
675 The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
676 property, a QDate, QTime, or QDateTime value.
677
678 If \a format is not provided, \a dateTime is formatted using
679 \l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}. Otherwise,
680 \a format should be either:
681
682 \list
683 \o One of the Qt::DateFormat enumeration values, such as
684    \c Qt.DefaultLocaleShortDate or \c Qt.ISODate
685 \o A string that specifies the format of the returned string, as detailed below.
686 \endlist
687
688 If \a format specifies a format string, it should use the following expressions
689 to specify the date:
690
691     \table
692     \header \i Expression \i Output
693     \row \i d \i the day as number without a leading zero (1 to 31)
694     \row \i dd \i the day as number with a leading zero (01 to 31)
695     \row \i ddd
696             \i the abbreviated localized day name (e.g. 'Mon' to 'Sun').
697             Uses QDate::shortDayName().
698     \row \i dddd
699             \i the long localized day name (e.g. 'Monday' to 'Qt::Sunday').
700             Uses QDate::longDayName().
701     \row \i M \i the month as number without a leading zero (1-12)
702     \row \i MM \i the month as number with a leading zero (01-12)
703     \row \i MMM
704             \i the abbreviated localized month name (e.g. 'Jan' to 'Dec').
705             Uses QDate::shortMonthName().
706     \row \i MMMM
707             \i the long localized month name (e.g. 'January' to 'December').
708             Uses QDate::longMonthName().
709     \row \i yy \i the year as two digit number (00-99)
710     \row \i yyyy \i the year as four digit number
711     \endtable
712
713 In addition the following expressions can be used to specify the time:
714
715     \table
716     \header \i Expression \i Output
717     \row \i h
718          \i the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
719     \row \i hh
720          \i the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
721     \row \i m \i the minute without a leading zero (0 to 59)
722     \row \i mm \i the minute with a leading zero (00 to 59)
723     \row \i s \i the second without a leading zero (0 to 59)
724     \row \i ss \i the second with a leading zero (00 to 59)
725     \row \i z \i the milliseconds without leading zeroes (0 to 999)
726     \row \i zzz \i the milliseconds with leading zeroes (000 to 999)
727     \row \i AP
728             \i use AM/PM display. \e AP will be replaced by either "AM" or "PM".
729     \row \i ap
730             \i use am/pm display. \e ap will be replaced by either "am" or "pm".
731     \endtable
732
733     All other input characters will be ignored. Any sequence of characters that
734     are enclosed in single quotes will be treated as text and not be used as an
735     expression. Two consecutive single quotes ("''") are replaced by a single quote
736     in the output.
737
738 For example, if the following date/time value was specified:
739
740     \code
741     // 21 May 2001 14:13:09
742     var dateTime = new Date(2001, 5, 21, 14, 13, 09)
743     \endcode
744
745 This \a dateTime value could be passed to \c Qt.formatDateTime(),
746 \l {QML:Qt::formatDate()}{Qt.formatDate()} or \l {QML:Qt::formatTime()}{Qt.formatTime()}
747 with the \a format values below to produce the following results:
748
749     \table
750     \header \i Format \i Result
751     \row \i "dd.MM.yyyy"      \i 21.05.2001
752     \row \i "ddd MMMM d yy"   \i Tue May 21 01
753     \row \i "hh:mm:ss.zzz"    \i 14:13:09.042
754     \row \i "h:m:s ap"        \i 2:13:9 pm
755     \endtable
756
757     \sa Locale
758 */
759 v8::Handle<v8::Value> formatDateTime(const v8::Arguments &args)
760 {
761     if (args.Length() < 1 || args.Length() > 2)
762         V8THROW_ERROR("Qt.formatDateTime(): Invalid arguments");
763
764     Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
765     QDateTime dt = V8ENGINE()->toVariant(args[0], -1).toDateTime();
766     QString formattedDt;
767     if (args.Length() == 2) {
768         if (args[1]->IsString()) {
769             QString format = V8ENGINE()->toVariant(args[1], -1).toString();
770             formattedDt = dt.toString(format);
771         } else if (args[1]->IsNumber()) {
772             quint32 intFormat = args[1]->ToNumber()->Value();
773             Qt::DateFormat format = Qt::DateFormat(intFormat);
774             formattedDt = dt.toString(format);
775         } else {
776             V8THROW_ERROR("Qt.formatDateTime(): Invalid datetime format");
777         }
778     } else {
779          formattedDt = dt.toString(enumFormat);
780     }
781
782     return V8ENGINE()->fromVariant(QVariant::fromValue(formattedDt));
783 }
784
785 /*!
786 \qmlmethod bool Qt::openUrlExternally(url target)
787 Attempts to open the specified \c target url in an external application, based on the user's desktop preferences. Returns true if it succeeds, and false otherwise.
788 */
789 v8::Handle<v8::Value> openUrlExternally(const v8::Arguments &args)
790 {
791     if (args.Length() != 1)
792         return V8ENGINE()->fromVariant(false);
793
794     bool ret = false;
795 #ifndef QT_NO_DESKTOPSERVICES
796     ret = QDesktopServices::openUrl(V8ENGINE()->toVariant(resolvedUrl(args), -1).toUrl());
797 #endif
798     return V8ENGINE()->fromVariant(ret);
799 }
800
801 /*!
802   \qmlmethod url Qt::resolvedUrl(url url)
803   Returns \a url resolved relative to the URL of the caller.
804 */
805 v8::Handle<v8::Value> resolvedUrl(const v8::Arguments &args)
806 {
807     QUrl url = V8ENGINE()->toVariant(args[0], -1).toUrl();
808     QDeclarativeEngine *e = V8ENGINE()->engine();
809     QDeclarativeEnginePrivate *p = 0;
810     if (e) p = QDeclarativeEnginePrivate::get(e);
811     if (p) {
812         QDeclarativeContextData *ctxt = V8ENGINE()->callingContext();
813         if (ctxt)
814             return V8ENGINE()->toString(ctxt->resolvedUrl(url).toString());
815         else
816             return V8ENGINE()->toString(url.toString());
817     }
818
819     return V8ENGINE()->toString(e->baseUrl().resolved(url).toString());
820 }
821
822 /*!
823 \qmlmethod list<string> Qt::fontFamilies()
824 Returns a list of the font families available to the application.
825 */
826 v8::Handle<v8::Value> fontFamilies(const v8::Arguments &args)
827 {
828     if (args.Length() != 0)
829         V8THROW_ERROR("Qt.fontFamilies(): Invalid arguments");
830
831     QFontDatabase database;
832     return V8ENGINE()->fromVariant(database.families());
833 }
834
835 /*!
836 \qmlmethod string Qt::md5(data)
837 Returns a hex string of the md5 hash of \c data.
838 */
839 v8::Handle<v8::Value> md5(const v8::Arguments &args)
840 {
841     if (args.Length() != 1)
842         V8THROW_ERROR("Qt.md5(): Invalid arguments");
843
844     QByteArray data = V8ENGINE()->toString(args[0]->ToString()).toUtf8();
845     QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5);
846     return V8ENGINE()->toString(QLatin1String(result.toHex()));
847 }
848
849 /*!
850 \qmlmethod string Qt::btoa(data)
851 Binary to ASCII - this function returns a base64 encoding of \c data.
852 */
853 v8::Handle<v8::Value> btoa(const v8::Arguments &args)
854 {
855     if (args.Length() != 1)
856         V8THROW_ERROR("Qt.btoa(): Invalid arguments");
857
858     QByteArray data = V8ENGINE()->toString(args[0]->ToString()).toUtf8();
859
860     return V8ENGINE()->toString(QLatin1String(data.toBase64()));
861 }
862
863 /*!
864 \qmlmethod string Qt::atob(data)
865 ASCII to binary - this function returns a base64 decoding of \c data.
866 */
867 v8::Handle<v8::Value> atob(const v8::Arguments &args)
868 {
869     if (args.Length() != 1)
870         V8THROW_ERROR("Qt.atob(): Invalid arguments");
871
872     QByteArray data = V8ENGINE()->toString(args[0]->ToString()).toUtf8();
873
874     return V8ENGINE()->toString(QLatin1String(QByteArray::fromBase64(data)));
875 }
876
877 /*!
878 \qmlmethod Qt::quit()
879 This function causes the QDeclarativeEngine::quit() signal to be emitted.
880 Within the \l {QML Viewer}, this causes the launcher application to exit;
881 to quit a C++ application when this method is called, connect the
882 QDeclarativeEngine::quit() signal to the QCoreApplication::quit() slot.
883 */
884 v8::Handle<v8::Value> quit(const v8::Arguments &args)
885 {
886     QDeclarativeEnginePrivate::get(V8ENGINE()->engine())->sendQuit();
887     return v8::Undefined();
888 }
889
890 /*!
891 \qmlmethod object Qt::createQmlObject(string qml, object parent, string filepath)
892
893 Returns a new object created from the given \a string of QML which will have the specified \a parent,
894 or \c null if there was an error in creating the object.
895
896 If \a filepath is specified, it will be used for error reporting for the created object.
897
898 Example (where \c parentItem is the id of an existing QML item):
899
900 \snippet doc/src/snippets/declarative/createQmlObject.qml 0
901
902 In the case of an error, a QtScript Error object is thrown. This object has an additional property,
903 \c qmlErrors, which is an array of the errors encountered.
904 Each object in this array has the members \c lineNumber, \c columnNumber, \c fileName and \c message.
905 For example, if the above snippet had misspelled color as 'colro' then the array would contain an object like the following:
906 { "lineNumber" : 1, "columnNumber" : 32, "fileName" : "dynamicSnippet1", "message" : "Cannot assign to non-existent property \"colro\""}.
907
908 Note that this function returns immediately, and therefore may not work if
909 the \a qml string loads new components (that is, external QML files that have not yet been loaded).
910 If this is the case, consider using \l{QML:Qt::createComponent()}{Qt.createComponent()} instead.
911
912 See \l {Dynamic Object Management in QML} for more information on using this function.
913 */
914 v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args)
915 {
916     if (args.Length() < 2 || args.Length() > 3)
917         V8THROW_ERROR("Qt.createQmlObject(): Invalid arguments");
918
919     struct Error {
920         static v8::Local<v8::Value> create(QV8Engine *engine, const QList<QDeclarativeError> &errors) {
921             QString errorstr = QLatin1String("Qt.createQmlObject(): failed to create object: ");
922
923             v8::Local<v8::Array> qmlerrors = v8::Array::New(errors.count());
924             for (int ii = 0; ii < errors.count(); ++ii) {
925                 const QDeclarativeError &error = errors.at(ii);
926                 errorstr += QLatin1String("\n    ") + error.toString();
927                 v8::Local<v8::Object> qmlerror = v8::Object::New();
928                 qmlerror->Set(v8::String::New("lineNumber"), v8::Integer::New(error.line()));
929                 qmlerror->Set(v8::String::New("columnNumber"), v8::Integer::New(error.line()));
930                 qmlerror->Set(v8::String::New("fileName"), engine->toString(error.url().toString()));
931                 qmlerror->Set(v8::String::New("message"), engine->toString(error.description()));
932                 qmlerrors->Set(ii, qmlerror);
933             }
934
935             v8::Local<v8::Value> error = v8::Exception::Error(engine->toString(errorstr));
936             v8::Local<v8::Object> errorObject = error->ToObject();
937             errorObject->Set(v8::String::New("qmlErrors"), qmlerrors);
938             return error;
939         }
940     };
941
942     QV8Engine *v8engine = V8ENGINE();
943     QDeclarativeEngine *engine = v8engine->engine();
944
945     QDeclarativeContextData *context = v8engine->callingContext();
946     QDeclarativeContext *effectiveContext = 0;
947     if (context->isPragmaLibraryContext)
948         effectiveContext = engine->rootContext();
949     else
950         effectiveContext = context->asQDeclarativeContext();
951     Q_ASSERT(context && effectiveContext);
952
953     QString qml = v8engine->toString(args[0]->ToString());
954     if (qml.isEmpty())
955         return v8::Null();
956
957     QUrl url;
958     if (args.Length() > 2)
959         url = QUrl(v8engine->toString(args[2]->ToString()));
960     else
961         url = QUrl(QLatin1String("inline"));
962
963     if (url.isValid() && url.isRelative())
964         url = context->resolvedUrl(url);
965
966     QObject *parentArg = v8engine->toQObject(args[1]);
967     if (!parentArg)
968         V8THROW_ERROR("Qt.createQmlObject(): Missing parent object");
969
970     QDeclarativeComponent component(engine);
971     component.setData(qml.toUtf8(), url);
972
973     if (component.isError()) {
974         v8::ThrowException(Error::create(v8engine, component.errors()));
975         return v8::Undefined();
976     }
977
978     if (!component.isReady())
979         V8THROW_ERROR("Qt.createQmlObject(): Component is not ready");
980
981     QObject *obj = component.beginCreate(effectiveContext);
982     if (obj)
983         QDeclarativeData::get(obj, true)->setImplicitDestructible();
984     component.completeCreate();
985
986     if (component.isError()) {
987         v8::ThrowException(Error::create(v8engine, component.errors()));
988         return v8::Undefined();
989     }
990
991     Q_ASSERT(obj);
992
993     obj->setParent(parentArg);
994
995     QList<QDeclarativePrivate::AutoParentFunction> functions = QDeclarativeMetaType::parentFunctions();
996     for (int ii = 0; ii < functions.count(); ++ii) {
997         if (QDeclarativePrivate::Parented == functions.at(ii)(obj, parentArg))
998             break;
999     }
1000
1001     return v8engine->newQObject(obj);
1002 }
1003
1004 /*!
1005 \qmlmethod object Qt::createComponent(url)
1006
1007 Returns a \l Component object created using the QML file at the specified \a url,
1008 or \c null if an empty string was given.
1009
1010 The returned component's \l Component::status property indicates whether the
1011 component was successfully created. If the status is \c Component.Error,
1012 see \l Component::errorString() for an error description.
1013
1014 Call \l {Component::createObject()}{Component.createObject()} on the returned
1015 component to create an object instance of the component.
1016
1017 For example:
1018
1019 \snippet doc/src/snippets/declarative/createComponent-simple.qml 0
1020
1021 See \l {Dynamic Object Management in QML} for more information on using this function.
1022
1023 To create a QML object from an arbitrary string of QML (instead of a file),
1024 use \l{QML:Qt::createQmlObject()}{Qt.createQmlObject()}.
1025 */
1026 v8::Handle<v8::Value> createComponent(const v8::Arguments &args)
1027 {
1028     if (args.Length() != 1)
1029         V8THROW_ERROR("Qt.createComponent(): Invalid arguments");
1030
1031     QV8Engine *v8engine = V8ENGINE();
1032     QDeclarativeEngine *engine = v8engine->engine();
1033
1034     QDeclarativeContextData *context = v8engine->callingContext();
1035     QDeclarativeContextData *effectiveContext = context;
1036     if (context->isPragmaLibraryContext)
1037         effectiveContext = 0;
1038     Q_ASSERT(context);
1039
1040     QString arg = v8engine->toString(args[0]->ToString());
1041     if (arg.isEmpty())
1042         return v8::Null();
1043
1044     QUrl url = context->resolvedUrl(QUrl(arg));
1045     QDeclarativeComponent *c = new QDeclarativeComponent(engine, url, engine);
1046     QDeclarativeComponentPrivate::get(c)->creationContext = effectiveContext;
1047     QDeclarativeData::get(c, true)->setImplicitDestructible();
1048     return v8engine->newQObject(c);
1049 }
1050
1051 v8::Handle<v8::Value> qsTranslate(const v8::Arguments &args)
1052 {
1053     if (args.Length() < 2)
1054         V8THROW_ERROR("qsTranslate() requires at least two arguments");
1055     if (!args[0]->IsString())
1056         V8THROW_ERROR("qsTranslate(): first argument (context) must be a string");
1057     if (!args[1]->IsString())
1058         V8THROW_ERROR("qsTranslate(): second argument (text) must be a string");
1059     if ((args.Length() > 2) && !args[2]->IsString())
1060         V8THROW_ERROR("qsTranslate(): third argument (comment) must be a string");
1061     if ((args.Length() > 3) && !args[3]->IsString())
1062         V8THROW_ERROR("qsTranslate(): fourth argument (encoding) must be a string");
1063
1064     QV8Engine *v8engine = V8ENGINE();
1065     QString context = v8engine->toString(args[0]);
1066     QString text = v8engine->toString(args[1]);
1067     QString comment;
1068     if (args.Length() > 2) comment = v8engine->toString(args[2]);
1069
1070     QCoreApplication::Encoding encoding = QCoreApplication::UnicodeUTF8;
1071     if (args.Length() > 3) {
1072         QString encStr = v8engine->toString(args[3]);
1073         if (encStr == QLatin1String("CodecForTr")) {
1074             encoding = QCoreApplication::CodecForTr;
1075         } else if (encStr == QLatin1String("UnicodeUTF8")) {
1076             encoding = QCoreApplication::UnicodeUTF8;
1077         } else {
1078             QString msg = QString::fromLatin1("qsTranslate(): invalid encoding '%0'").arg(encStr);
1079             V8THROW_ERROR((uint16_t *)msg.constData());
1080         }
1081     }
1082
1083     int n = -1;
1084     if (args.Length() > 4)
1085         n = args[4]->Int32Value();
1086
1087     QString result = QCoreApplication::translate(context.toUtf8().constData(),
1088                                                  text.toUtf8().constData(),
1089                                                  comment.toUtf8().constData(),
1090                                                  encoding, n);
1091
1092     return v8engine->toString(result);
1093 }
1094
1095 v8::Handle<v8::Value> qsTranslateNoOp(const v8::Arguments &args)
1096 {
1097     if (args.Length() < 2)
1098         return v8::Undefined();
1099     return args[1];
1100 }
1101
1102 v8::Handle<v8::Value> qsTr(const v8::Arguments &args)
1103 {
1104     if (args.Length() < 1)
1105         V8THROW_ERROR("qsTr() requires at least one argument");
1106     if (!args[0]->IsString())
1107         V8THROW_ERROR("qsTr(): first argument (text) must be a string");
1108     if ((args.Length() > 1) && !args[1]->IsString())
1109         V8THROW_ERROR("qsTr(): second argument (comment) must be a string");
1110     if ((args.Length() > 2) && !args[2]->IsNumber())
1111         V8THROW_ERROR("qsTr(): third argument (n) must be a number");
1112
1113     QV8Engine *v8engine = V8ENGINE();
1114     QDeclarativeContextData *ctxt = v8engine->callingContext();
1115
1116     QString path = ctxt->url.toString();
1117     int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1118     QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) : QString();
1119
1120     QString text = v8engine->toString(args[0]);
1121     QString comment;
1122     if (args.Length() > 1)
1123         comment = v8engine->toString(args[1]);
1124     int n = -1;
1125     if (args.Length() > 2)
1126         n = args[2]->Int32Value();
1127
1128     QString result = QCoreApplication::translate(context.toUtf8().constData(), text.toUtf8().constData(),
1129                                                  comment.toUtf8().constData(), QCoreApplication::UnicodeUTF8, n);
1130
1131     return v8engine->toString(result);
1132 }
1133
1134 v8::Handle<v8::Value> qsTrNoOp(const v8::Arguments &args)
1135 {
1136     if (args.Length() < 1)
1137         return v8::Undefined();
1138     return args[0];
1139 }
1140
1141 v8::Handle<v8::Value> qsTrId(const v8::Arguments &args)
1142 {
1143     if (args.Length() < 1)
1144         V8THROW_ERROR("qsTrId() requires at least one argument");
1145     if (!args[0]->IsString())
1146         V8THROW_TYPE("qsTrId(): first argument (id) must be a string");
1147     if (args.Length() > 1 && !args[1]->IsNumber())
1148         V8THROW_TYPE("qsTrId(): second argument (n) must be a number");
1149
1150     int n = -1;
1151     if (args.Length() > 1)
1152         n = args[1]->Int32Value();
1153
1154     QV8Engine *v8engine = V8ENGINE();
1155     return v8engine->toString(qtTrId(v8engine->toString(args[0]).toUtf8().constData(), n));
1156 }
1157
1158 v8::Handle<v8::Value> qsTrIdNoOp(const v8::Arguments &args)
1159 {
1160     if (args.Length() < 1)
1161         return v8::Undefined();
1162     return args[0];
1163 }
1164
1165
1166 /*!
1167     \qmlmethod Qt::locale(name)
1168
1169     Returns a JS object representing the locale with the specified
1170     name, which has the format "language[_territory][.codeset][@modifier]"
1171     or "C", where:
1172
1173     \list
1174     \o language is a lowercase, two-letter, ISO 639 language code,
1175     \o territory is an uppercase, two-letter, ISO 3166 country code,
1176     \o and codeset and modifier are ignored.
1177     \endlist
1178
1179     If the string violates the locale format, or language is not a
1180     valid ISO 369 code, the "C" locale is used instead. If country
1181     is not present, or is not a valid ISO 3166 code, the most
1182     appropriate country is chosen for the specified language.
1183
1184     \sa QtQuick2::Locale
1185 */
1186 v8::Handle<v8::Value> locale(const v8::Arguments &args)
1187 {
1188     QString code;
1189     if (args.Length() > 1)
1190         V8THROW_ERROR("locale() requires 0 or 1 argument");
1191     if (args.Length() == 1 && !args[0]->IsString())
1192         V8THROW_TYPE("locale(): argument (locale code) must be a string");
1193
1194     QV8Engine *v8engine = V8ENGINE();
1195     if (args.Length() == 1)
1196         code = v8engine->toString(args[0]);
1197
1198     return QDeclarativeLocale::locale(v8engine, code);
1199 }
1200
1201 } // namespace QDeclarativeBuiltinFunctions
1202
1203 QT_END_NAMESPACE