From 88fefbc68ddcbe99e718a07c5f25e5d28c839439 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 10 Nov 2011 18:33:27 +1000 Subject: Qt.locale() and JS locale type extension. Task-number: QTBUG-17129 Change-Id: I69cbbe858735b750b4e37ce489f2fa1ad5d8b5d3 Reviewed-by: Martin Jones --- doc/src/declarative/qdeclarativei18n.qdoc | 16 +- doc/src/declarative/qmldate.qdoc | 149 +++ doc/src/declarative/qmlnumber.qdoc | 105 ++ doc/src/qtquick1/declarativeui.qdoc | 2 +- doc/src/qtquick1/qdeclarativei18n.qdoc | 2 +- examples/declarative/locale/locale.qml | 132 +++ src/declarative/qml/qdeclarativeengine.cpp | 2 + src/declarative/qml/qdeclarativeengine_p.h | 3 +- src/declarative/qml/qdeclarativelocale.cpp | 1095 ++++++++++++++++++++ src/declarative/qml/qdeclarativelocale_p.h | 132 +++ src/declarative/qml/qml.pri | 4 +- .../qml/v8/qdeclarativebuiltinfunctions.cpp | 43 + .../qml/v8/qdeclarativebuiltinfunctions_p.h | 1 + src/declarative/qml/v8/qjsengine.cpp | 3 +- src/declarative/qml/v8/qjsengine.h | 4 +- src/declarative/qml/v8/qjsengine_p.h | 57 + src/declarative/qml/v8/qv8engine.cpp | 8 + src/declarative/qml/v8/qv8engine_p.h | 6 +- src/declarative/qml/v8/script.pri | 1 + tests/auto/declarative/declarative.pro | 1 + .../declarative/qdeclarativelocale/data/date.qml | 45 + .../qdeclarativelocale/data/functions.qml | 65 ++ .../declarative/qdeclarativelocale/data/number.qml | 30 + .../qdeclarativelocale/data/properties.qml | 26 + .../qdeclarativelocale/qdeclarativelocale.pro | 13 + .../qdeclarativelocale/tst_qdeclarativelocale.cpp | 1090 +++++++++++++++++++ 26 files changed, 3024 insertions(+), 11 deletions(-) create mode 100644 doc/src/declarative/qmldate.qdoc create mode 100644 doc/src/declarative/qmlnumber.qdoc create mode 100644 examples/declarative/locale/locale.qml create mode 100644 src/declarative/qml/qdeclarativelocale.cpp create mode 100644 src/declarative/qml/qdeclarativelocale_p.h create mode 100644 src/declarative/qml/v8/qjsengine_p.h create mode 100644 tests/auto/declarative/qdeclarativelocale/data/date.qml create mode 100644 tests/auto/declarative/qdeclarativelocale/data/functions.qml create mode 100644 tests/auto/declarative/qdeclarativelocale/data/number.qml create mode 100644 tests/auto/declarative/qdeclarativelocale/data/properties.qml create mode 100644 tests/auto/declarative/qdeclarativelocale/qdeclarativelocale.pro create mode 100644 tests/auto/declarative/qdeclarativelocale/tst_qdeclarativelocale.cpp diff --git a/doc/src/declarative/qdeclarativei18n.qdoc b/doc/src/declarative/qdeclarativei18n.qdoc index 00422002c3..79a935657d 100644 --- a/doc/src/declarative/qdeclarativei18n.qdoc +++ b/doc/src/declarative/qdeclarativei18n.qdoc @@ -34,6 +34,7 @@ \nextpage {QML Features} \title QML Internationalization +\section1 Translation Strings in QML can be marked for translation using the qsTr(), qsTranslate(), QT_TR_NOOP(), and QT_TRANSLATE_NOOP() functions. @@ -55,14 +56,14 @@ capabilities are described more fully in: You can test a translation with the \l {QML Viewer} using the -translation option. -\section1 Example +\section2 Example First we create a simple QML file with text to be translated. The string that needs to be translated is enclosed in a call to \c qsTr(). hello.qml: \qml -import QtQuick 1.0 +import QtQuick 2.0 Rectangle { width: 200; height: 200 @@ -83,6 +84,15 @@ Finally, we can test the translation: qmlviewer -translation hello.qm hello.qml \endcode - You can see a complete example and source code in the \l{declarative/i18n}{QML Internationalization example}. + +\section1 Localization + +Localization is the process of adapting to local conventions, +for example presenting dates and times using the locally preferred formats. + +Qt Quick supports localization via the \l {QtQuick2::Locale}{Locale} object and extensions to the +ECMAScript \l {QtQuick2::Date}{Date} and \l {QtQuick2::Number}{Number} types. + + */ diff --git a/doc/src/declarative/qmldate.qdoc b/doc/src/declarative/qmldate.qdoc new file mode 100644 index 0000000000..c0552aad40 --- /dev/null +++ b/doc/src/declarative/qmldate.qdoc @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms +** and conditions contained in a signed written agreement between you +** and Nokia. +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \qmlclass Date + \inqmlmodule QtQuick 2 + \brief The Date object provides date functions + + The QML Date object extends the JS Date object with + locale aware functions. + + Functions that accept a locale format may be either an enumeration + value: + \table + \row \i Locale.LongFormat \i The long version of day and month names; for example, returning "January" as a month name. + \row \i Locale.ShortFormat \i The short version of day and month names; for example, returning "Jan" as a month name. + \row \i Locale.NarrowFormat \i A special version of day and month names for use when space is limited; + for example, returning "J" as a month name. Note that the narrow format might contain + the same text for different months and days or it can even be an empty string if the + locale doesn't support narrow names, so you should avoid using it for date formatting. + Also, for the system locale this format is the same as ShortFormat. + \endtable + + or a string specifying the format: + \table + \header \i Expression \i Output + \row \i d \i the day as number without a leading zero (1 to 31) + \row \i dd \i the day as number with a leading zero (01 to 31) + \row \i ddd + \i the abbreviated localized day name (e.g. 'Mon' to 'Sun'). + \row \i dddd + \i the long localized day name (e.g. 'Monday' to 'Sunday'). + \row \i M \i the month as number without a leading zero (1 to 12) + \row \i MM \i the month as number with a leading zero (01 to 12) + \row \i MMM + \i the abbreviated localized month name (e.g. 'Jan' to 'Dec'). + \row \i MMMM + \i the long localized month name (e.g. 'January' to 'December'). + \row \i yy \i the year as two digit number (00 to 99) + \row \i yyyy \i the year as four digit number. If the year is negative, + a minus sign is prepended in addition. + \endtable + + All other input characters will be ignored. Any sequence of characters that + are enclosed in singlequotes will be treated as text and not be used as an + expression. Two consecutive singlequotes ("''") are replaced by a singlequote + in the output. + + Example format strings (assuming that the Date is the 20 July + 1969): + + \table + \header \o Format \o Result + \row \o dd.MM.yyyy \o 20.07.1969 + \row \o ddd MMMM d yy \o Sun July 20 69 + \row \o 'The day is' dddd \o The day is Sunday + \endtable + + \sa {QtQuick2::Locale}{Locale} +*/ + +/*! + \qmlmethod string Date::toLocaleString(locale,format) + + Converts the Date to a string containing the date and time + suitable for the specified \a locale + in the specified \a format. + + If the format is not specified Locale.LongFormat will be used. + + If \a locale is not specified, the default locale will be used. + + The following example shows the current date and time formatted + for the German locale: + \code + import QtQuick 2.0 + + Text { + text: "The date is: " + Date().toLocaleString(Qt.locale("de_DE")) + } + \endcode +*/ + +/*! + \qmlmethod string Date::toLocaleDateString(locale,format) + + Converts the Date to a string containing the date suitable for the specified \a locale + in the specified \a format. + + If the format is not specified Locale.LongFormat will be used. + + If \a locale is not specified, the default locale will be used. + + The following example shows the current date formatted + for the German locale: + \code + import QtQuick 2.0 + + Text { + text: "The date is: " + Date().toLocaleDateString(Qt.locale("de_DE")) + } + \endcode +*/ + +/*! + \qmlmethod string Date::toLocaleTimeString(locale,format) + + Converts the Date to a string containing the time suitable for the specified \a locale + in the specified \a format. + + If the format is not specified Locale.LongFormat will be used. + + If \a locale is not specified, the default locale will be used. + + The following example shows the current time formatted + for the German locale: + \code + import QtQuick 2.0 + + Text { + text: "The date is: " + Date().toLocaleTimeString(Qt.locale("de_DE")) + } + \endcode +*/ + diff --git a/doc/src/declarative/qmlnumber.qdoc b/doc/src/declarative/qmlnumber.qdoc new file mode 100644 index 0000000000..0b4341d76b --- /dev/null +++ b/doc/src/declarative/qmlnumber.qdoc @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms +** and conditions contained in a signed written agreement between you +** and Nokia. +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \qmlclass Number + \inqmlmodule QtQuick 2 + \brief The Number object provides represents a number value + + The QML Number object extends the JS Number object with + locale aware functions. + + \sa {QtQuick2::Locale}{Locale} +*/ + +/*! + \qmlmethod string Number::toLocaleString(locale,format,precision) + + Converts the Number to a string suitable for the specified \a locale + in the specified \a format, with the specified \a precision. + + Valid formats are: + \list + \o 'f' Decimal floating point, e.g. 248.65 + \o 'e' Scientific notation using e character, e.g. 2.4865e+2 + \o 'E' Scientific notation using E character, e.g. 2.4865E+2 + \o 'g' Use the shorter of e or f + \o 'G' Use the shorter of E or f + \endlist + + If precision is not specified, the precision will be 2. + + If the format is not specified 'f' will be used. + + If \a locale is not specified, the default locale will be used. + + The following example shows a number formatted for the German locale: + \code + import QtQuick 2.0 + + Text { + text: "The value is: " + Number(4742378.423).toLocaleString(Qt.locale("de_DE")) + } + \endcode + + You can apply toLocaleString() directly to constants, provided the decimal + is included in the constant, e.g. + \code + 123.0.toLocaleString(Qt.locale("de_DE")) // OK + 123..toLocaleString(Qt.locale("de_DE")) // OK + 123.toLocaleString(Qt.locale("de_DE")) // fails + \endcode +*/ + +/*! + \qmlmethod string Number::toLocaleCurrencyString(locale,symbol) + + Converts the Number to a currency using the currency and conventions of the specified + \a locale. If \a symbol is specified it will be used as the currency + symbol. + + \sa Locale::currencySymbol() +*/ + +/*! + \qmlmethod string Number::fromLocaleString(locale,number) + + Returns a Number by parsing \a number using the conventions of the supplied \a locale. + + If \a locale is not supplied the default locale will be used. + + For example, using the German locale: + \code + var german = Qt.locale("de_DE"); + var d; + d = Number.fromLocaleString(german, "1234,56) // d == 1234.56 + d = Number.fromLocaleString(german, "1.234,56") // d == 1234.56 + d = Number.fromLocaleString(german, "1234.56") // throws exception + d = Number.fromLocaleString(german, "1.234") // d == 1234.0 + \endcode +*/ + diff --git a/doc/src/qtquick1/declarativeui.qdoc b/doc/src/qtquick1/declarativeui.qdoc index 41dedecb8e..e1d5755b47 100644 --- a/doc/src/qtquick1/declarativeui.qdoc +++ b/doc/src/qtquick1/declarativeui.qdoc @@ -77,7 +77,7 @@ Qt applications. \o \l{Integrating QML Code with Existing Qt UI Code} \o \l{Dynamic Object Management in QML}{Dynamic Object Management} \o \l{Network Transparency}{Loading Resources in QML} -\o \l{QML Internationalization}{Internationalization} +\o \l{QML Internationalization}{Qt Quick 1 Internationalization} \endlist \section1 QML Add-Ons diff --git a/doc/src/qtquick1/qdeclarativei18n.qdoc b/doc/src/qtquick1/qdeclarativei18n.qdoc index 76892173ff..e985abe61d 100644 --- a/doc/src/qtquick1/qdeclarativei18n.qdoc +++ b/doc/src/qtquick1/qdeclarativei18n.qdoc @@ -32,7 +32,7 @@ \contentspage QML Features \previouspage {Network Transparency}{Loading Resources in QML} \nextpage {QML Features} -\title QML Internationalization +\title Qt Quick 1 Internationalization Strings in QML can be marked for translation using the qsTr(), qsTranslate(), diff --git a/examples/declarative/locale/locale.qml b/examples/declarative/locale/locale.qml new file mode 100644 index 0000000000..4d56ecff0b --- /dev/null +++ b/examples/declarative/locale/locale.qml @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + id: root + width: 320 + height: 480 + color: "lightgray" + + property string locale: view.currentItem.locale + + Text { + id: title + text: "Select locale:" + } + + Rectangle { + id: chooser + anchors.top: title.bottom + anchors.topMargin: 5 + width: parent.width-10 + x: 5 + height: parent.height/2 - 10 + color: "#40300030" + ListView { + id: view + clip: true + focus: true + anchors.fill: parent + model: [ + "en_US", + "en_GB", + "fi_FI", + "de_DE", + "ar_SA", + "hi_IN", + "zh_CN", + "th_TH", + "fr_FR", + "nb_NO", + "sv_SE" + ] + delegate: Text { + property string locale: modelData + height: 30 + width: view.width + text: Qt.locale(modelData).name + " ("+ Qt.locale(modelData).nativeCountryName + "/" + Qt.locale(modelData).nativeLanguageName + ")" + MouseArea { + anchors.fill: parent + onClicked: view.currentIndex = index + } + } + highlight: Rectangle { + height: 30 + color: "#60300030" + } + } + } + + Rectangle { + color: "white" + anchors.top: chooser.bottom + anchors.topMargin: 5 + anchors.bottom: parent.bottom + anchors.bottomMargin: 5 + x: 5; width: parent.width - 10 + + Column { + anchors.fill: parent + spacing: 5 + Text { + property var date: new Date() + text: "Date: " + date.toLocaleDateString(Qt.locale(root.locale)) + } + Text { + property var date: new Date() + text: "Time: " + date.toLocaleTimeString(Qt.locale(root.locale)) + } + Text { + property var dow: Qt.locale(root.locale).firstDayOfWeek + text: "First day of week: " + Qt.locale(root.locale).standaloneDayName(dow) + } + Text { + property var num: 10023823 + text: "Number: " + num.toLocaleString(Qt.locale(root.locale)) + } + Text { + property var num: 10023823 + text: "Currency: " + num.toLocaleCurrencyString(Qt.locale(root.locale)) + } + } + } +} diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 1323669fc7..ef638b4e44 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -85,6 +85,7 @@ #include #include #include +#include #ifdef Q_OS_WIN // for %APPDATA% #include @@ -174,6 +175,7 @@ void QDeclarativeEnginePrivate::defineModule() { registerBaseTypes("QtQuick", 2, 0); qmlRegisterType(); + qmlRegisterUncreatableType("QtQuick",2,0,"Locale",QDeclarativeEngine::tr("Locale cannot be instantiated. Use Qt.locale()")); } /*! diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h index a678a4588c..14ee62872d 100644 --- a/src/declarative/qml/qdeclarativeengine_p.h +++ b/src/declarative/qml/qdeclarativeengine_p.h @@ -81,6 +81,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -119,7 +120,7 @@ public: QDeclarativeJavaScriptExpressionGuard *next; }; -class Q_DECLARATIVE_EXPORT QDeclarativeEnginePrivate : public QObjectPrivate +class Q_DECLARATIVE_EXPORT QDeclarativeEnginePrivate : public QJSEnginePrivate { Q_DECLARE_PUBLIC(QDeclarativeEngine) public: diff --git a/src/declarative/qml/qdeclarativelocale.cpp b/src/declarative/qml/qdeclarativelocale.cpp new file mode 100644 index 0000000000..bbde2d801c --- /dev/null +++ b/src/declarative/qml/qdeclarativelocale.cpp @@ -0,0 +1,1095 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativelocale_p.h" +#include "qdeclarativeengine_p.h" +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QV8LocaleDataResource : public QV8ObjectResource +{ + V8_RESOURCE_TYPE(LocaleDataType) +public: + QV8LocaleDataResource(QV8Engine *e) : QV8ObjectResource(e) {} + QLocale locale; +}; + +#define GET_LOCALE_DATA_RESOURCE(OBJECT) \ +QV8LocaleDataResource *r = v8_resource_cast(OBJECT); \ +if (!r) \ + V8THROW_ERROR("Not a valid Locale object") + +static bool isLocaleObject(v8::Handle val) +{ + if (!val->IsObject()) + return false; + + v8::Handle localeObj = val->ToObject(); + return localeObj->Has(v8::String::New("nativeLanguageName")); //XXX detect locale object properly +} + +//-------------- +// Date extension + +static const char *dateToLocaleStringFunction = + "(function(toLocaleStringFunc) { " + " var orig_toLocaleString;" + " orig_toLocaleString = Date.prototype.toLocaleString;" + " Date.prototype.toLocaleString = (function() {" + " var val = toLocaleStringFunc.apply(this, arguments);" + " if (val == undefined) val = orig_toLocaleString.call(this);" + " return val;" + " })" + "})"; + +static const char *dateToLocaleTimeStringFunction = + "(function(toLocaleTimeStringFunc) { " + " var orig_toLocaleTimeString;" + " orig_toLocaleTimeString = Date.prototype.toLocaleTimeString;" + " Date.prototype.toLocaleTimeString = (function() {" + " var val = toLocaleTimeStringFunc.apply(this, arguments);" + " if (val == undefined) val = orig_toLocaleTimeString.call(this);" + " return val;" + " })" + "})"; + +static const char *dateToLocaleDateStringFunction = + "(function(toLocaleDateStringFunc) { " + " var orig_toLocaleDateString;" + " orig_toLocaleDateString = Date.prototype.toLocaleDateString;" + " Date.prototype.toLocaleDateString = (function() {" + " var val = toLocaleDateStringFunc.apply(this, arguments);" + " if (val == undefined) val = orig_toLocaleDateString.call(this);" + " return val;" + " })" + "})"; + + +static const char *dateFromLocaleStringFunction = + "(function(fromLocaleStringFunc) { " + " Date.fromLocaleString = (function() {" + " return fromLocaleStringFunc.apply(null, arguments);" + " })" + "})"; + +static const char *dateFromLocaleTimeStringFunction = + "(function(fromLocaleTimeStringFunc) { " + " Date.fromLocaleTimeString = (function() {" + " return fromLocaleTimeStringFunc.apply(null, arguments);" + " })" + "})"; + +static const char *dateFromLocaleDateStringFunction = + "(function(fromLocaleDateStringFunc) { " + " Date.fromLocaleDateString = (function() {" + " return fromLocaleDateStringFunc.apply(null, arguments);" + " })" + "})"; + + +static void registerFunction(QV8Engine *engine, const char *script, v8::InvocationCallback func) +{ + v8::Local registerScript = v8::Script::New(v8::String::New(script), 0, 0, v8::Handle(), v8::Script::NativeMode); + v8::Local result = registerScript->Run(); + Q_ASSERT(result->IsFunction()); + v8::Local registerFunc = v8::Local::Cast(result); + v8::Handle args = V8FUNCTION(func, engine); + registerFunc->Call(v8::Local::Cast(registerFunc), 1, &args); +} + +void QDeclarativeDateExtension::registerExtension(QV8Engine *engine) +{ + registerFunction(engine, dateToLocaleStringFunction, toLocaleString); + registerFunction(engine, dateToLocaleTimeStringFunction, toLocaleTimeString); + registerFunction(engine, dateToLocaleDateStringFunction, toLocaleDateString); + registerFunction(engine, dateFromLocaleStringFunction, fromLocaleString); + registerFunction(engine, dateFromLocaleTimeStringFunction, fromLocaleTimeString); + registerFunction(engine, dateFromLocaleDateStringFunction, fromLocaleDateString); +} + +v8::Handle QDeclarativeDateExtension::toLocaleString(const v8::Arguments& args) +{ + if (args.Length() > 2) + return v8::Undefined(); + + if (!args.This()->IsDate()) + return v8::Undefined(); + + QDateTime dt = QV8Engine::qtDateTimeFromJsDate(v8::Handle::Cast(args.This())->NumberValue()); + + if (args.Length() == 0) { + // Use QLocale for standard toLocaleString() function + QLocale locale; + return QJSConverter::toString(locale.toString(dt)); + } + + if (!isLocaleObject(args[0])) + return v8::Undefined(); // Use the default Date toLocaleString() + + GET_LOCALE_DATA_RESOURCE(args[0]->ToObject()); + + QLocale::FormatType enumFormat = QLocale::LongFormat; + QString formattedDt; + if (args.Length() == 2) { + if (args[1]->IsString()) { + QString format = r->engine->toVariant(args[1], -1).toString(); + formattedDt = r->locale.toString(dt, format); + } else if (args[1]->IsNumber()) { + quint32 intFormat = args[1]->ToNumber()->Value(); + QLocale::FormatType format = QLocale::FormatType(intFormat); + formattedDt = r->locale.toString(dt, format); + } else { + V8THROW_ERROR("Locale: Date.toLocaleString(): Invalid datetime format"); + } + } else { + formattedDt = r->locale.toString(dt, enumFormat); + } + + return r->engine->toString(formattedDt); +} + +v8::Handle QDeclarativeDateExtension::toLocaleTimeString(const v8::Arguments& args) +{ + if (args.Length() > 2) + return v8::Undefined(); + + if (!args.This()->IsDate()) + return v8::Undefined(); + + QDateTime dt = QV8Engine::qtDateTimeFromJsDate(v8::Handle::Cast(args.This())->NumberValue()); + QTime time = dt.time(); + + if (args.Length() == 0) { + // Use QLocale for standard toLocaleString() function + QLocale locale; + return QJSConverter::toString(locale.toString(time)); + } + + if (!isLocaleObject(args[0])) + return v8::Undefined(); // Use the default Date toLocaleTimeString() + + GET_LOCALE_DATA_RESOURCE(args[0]->ToObject()); + + QLocale::FormatType enumFormat = QLocale::LongFormat; + QString formattedTime; + if (args.Length() == 2) { + if (args[1]->IsString()) { + QString format = r->engine->toVariant(args[1], -1).toString(); + formattedTime = r->locale.toString(time, format); + } else if (args[1]->IsNumber()) { + quint32 intFormat = args[1]->ToNumber()->Value(); + QLocale::FormatType format = QLocale::FormatType(intFormat); + formattedTime = r->locale.toString(time, format); + } else { + V8THROW_ERROR("Locale: Date.toLocaleTimeString(): Invalid time format"); + } + } else { + formattedTime = r->locale.toString(time, enumFormat); + } + + return r->engine->toString(formattedTime); +} + +v8::Handle QDeclarativeDateExtension::toLocaleDateString(const v8::Arguments& args) +{ + if (args.Length() > 2) + return v8::Undefined(); + + if (!args.This()->IsDate()) + return v8::Undefined(); + + QDateTime dt = QV8Engine::qtDateTimeFromJsDate(v8::Handle::Cast(args.This())->NumberValue()); + QDate date = dt.date(); + + if (args.Length() == 0) { + // Use QLocale for standard toLocaleString() function + QLocale locale; + return QJSConverter::toString(locale.toString(date)); + } + + if (!isLocaleObject(args[0])) + return v8::Undefined(); // Use the default Date toLocaleDateString() + + GET_LOCALE_DATA_RESOURCE(args[0]->ToObject()); + + QLocale::FormatType enumFormat = QLocale::LongFormat; + QString formattedDate; + if (args.Length() == 2) { + if (args[1]->IsString()) { + QString format = r->engine->toVariant(args[1], -1).toString(); + formattedDate = r->locale.toString(date, format); + } else if (args[1]->IsNumber()) { + quint32 intFormat = args[1]->ToNumber()->Value(); + QLocale::FormatType format = QLocale::FormatType(intFormat); + formattedDate = r->locale.toString(date, format); + } else { + V8THROW_ERROR("Locale: Date.loLocaleDateString(): Invalid date format"); + } + } else { + formattedDate = r->locale.toString(date, enumFormat); + } + + return r->engine->toString(formattedDate); +} + +v8::Handle QDeclarativeDateExtension::fromLocaleString(const v8::Arguments& args) +{ + if (args.Length() == 1 && args[0]->IsString()) { + QLocale locale; + QString dateString = QJSConverter::toString(args[0]->ToString()); + QDateTime dt = locale.toDateTime(dateString); + return QJSConverter::toDateTime(dt); + } + + if (args.Length() < 1 || args.Length() > 3 || !isLocaleObject(args[0])) + V8THROW_ERROR("Locale: Date.fromLocaleString(): Invalid arguments"); + + GET_LOCALE_DATA_RESOURCE(args[0]->ToObject()); + + QLocale::FormatType enumFormat = QLocale::LongFormat; + QDateTime dt; + QString dateString = r->engine->toString(args[1]->ToString()); + if (args.Length() == 3) { + if (args[2]->IsString()) { + QString format = r->engine->toString(args[2]->ToString()); + dt = r->locale.toDateTime(dateString, format); + } else if (args[2]->IsNumber()) { + quint32 intFormat = args[2]->ToNumber()->Value(); + QLocale::FormatType format = QLocale::FormatType(intFormat); + dt = r->locale.toDateTime(dateString, format); + } else { + V8THROW_ERROR("Locale: Date.fromLocaleString(): Invalid datetime format"); + } + } else { + dt = r->locale.toDateTime(dateString, enumFormat); + } + + return QJSConverter::toDateTime(dt); +} + +v8::Handle QDeclarativeDateExtension::fromLocaleTimeString(const v8::Arguments& args) +{ + if (args.Length() == 1 && args[0]->IsString()) { + QLocale locale; + QString timeString = QJSConverter::toString(args[0]->ToString()); + QTime time = locale.toTime(timeString); + QDateTime dt = QDateTime::currentDateTime(); + dt.setTime(time); + return QJSConverter::toDateTime(dt); + } + + if (args.Length() < 1 || args.Length() > 3 || !isLocaleObject(args[0])) + V8THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid arguments"); + + GET_LOCALE_DATA_RESOURCE(args[0]->ToObject()); + + QLocale::FormatType enumFormat = QLocale::LongFormat; + QTime tm; + QString dateString = r->engine->toString(args[1]->ToString()); + if (args.Length() == 3) { + if (args[2]->IsString()) { + QString format = r->engine->toString(args[2]->ToString()); + tm = r->locale.toTime(dateString, format); + } else if (args[2]->IsNumber()) { + quint32 intFormat = args[2]->ToNumber()->Value(); + QLocale::FormatType format = QLocale::FormatType(intFormat); + tm = r->locale.toTime(dateString, format); + } else { + V8THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid datetime format"); + } + } else { + tm = r->locale.toTime(dateString, enumFormat); + } + + QDateTime dt = QDateTime::currentDateTime(); + dt.setTime(tm); + + return QJSConverter::toDateTime(dt); +} + +v8::Handle QDeclarativeDateExtension::fromLocaleDateString(const v8::Arguments& args) +{ + if (args.Length() == 1 && args[0]->IsString()) { + QLocale locale; + QString dateString = QJSConverter::toString(args[0]->ToString()); + QDate date = locale.toDate(dateString); + return QJSConverter::toDateTime(QDateTime(date)); + } + + if (args.Length() < 1 || args.Length() > 3 || !isLocaleObject(args[0])) + V8THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid arguments"); + + GET_LOCALE_DATA_RESOURCE(args[0]->ToObject()); + + QLocale::FormatType enumFormat = QLocale::LongFormat; + QDate dt; + QString dateString = r->engine->toString(args[1]->ToString()); + if (args.Length() == 3) { + if (args[2]->IsString()) { + QString format = r->engine->toString(args[2]->ToString()); + dt = r->locale.toDate(dateString, format); + } else if (args[2]->IsNumber()) { + quint32 intFormat = args[2]->ToNumber()->Value(); + QLocale::FormatType format = QLocale::FormatType(intFormat); + dt = r->locale.toDate(dateString, format); + } else { + V8THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid datetime format"); + } + } else { + dt = r->locale.toDate(dateString, enumFormat); + } + + return QJSConverter::toDateTime(QDateTime(dt)); +} + +//----------------- +// Number extension + +static const char *numberToLocaleStringFunction = + "(function(toLocaleStringFunc) { " + " var orig_toLocaleString;" + " orig_toLocaleString = Number.prototype.toLocaleString;" + " Number.prototype.toLocaleString = (function() {" + " var val = toLocaleStringFunc.apply(this, arguments);" + " if (val == undefined) val = orig_toLocaleString.call(this);" + " return val;" + " })" + "})"; + +static const char *numberToLocaleCurrencyStringFunction = + "(function(toLocaleCurrencyStringFunc) { " + " Number.prototype.toLocaleCurrencyString = (function() {" + " return toLocaleCurrencyStringFunc.apply(this, arguments);" + " })" + "})"; + +static const char *numberFromLocaleStringFunction = + "(function(fromLocaleStringFunc) { " + " Number.fromLocaleString = (function() {" + " return fromLocaleStringFunc.apply(null, arguments);" + " })" + "})"; + + +void QDeclarativeNumberExtension::registerExtension(QV8Engine *engine) +{ + registerFunction(engine, numberToLocaleStringFunction, toLocaleString); + registerFunction(engine, numberToLocaleCurrencyStringFunction, toLocaleCurrencyString); + registerFunction(engine, numberFromLocaleStringFunction, fromLocaleString); +} + +v8::Handle QDeclarativeNumberExtension::toLocaleString(const v8::Arguments& args) +{ + if (args.Length() > 3) + V8THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments"); + + double number = args.This()->ToNumber()->Value(); + + if (args.Length() == 0) { + // Use QLocale for standard toLocaleString() function + QLocale locale; + return QJSConverter::toString(locale.toString(number)); + } + + if (!isLocaleObject(args[0])) + return v8::Undefined(); // Use the default Number toLocaleString() + + GET_LOCALE_DATA_RESOURCE(args[0]->ToObject()); + + uint16_t format = 'f'; + if (args.Length() > 1) { + if (!args[1]->IsString()) + V8THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments"); + v8::Local fs = args[1]->ToString(); + if (!fs.IsEmpty() && fs->Length()) + format = fs->GetCharacter(0); + } + int prec = 2; + if (args.Length() > 2) { + if (!args[2]->IsNumber()) + V8THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments"); + prec = args[2]->IntegerValue(); + } + + return r->engine->toString(r->locale.toString(number, (char)format, prec)); +} + +v8::Handle QDeclarativeNumberExtension::toLocaleCurrencyString(const v8::Arguments& args) +{ + if (args.Length() > 2) + V8THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments"); + + double number = args.This()->ToNumber()->Value(); + + if (args.Length() == 0) { + // Use QLocale for standard toLocaleString() function + QLocale locale; + return QJSConverter::toString(locale.toString(number)); + } + + if (!isLocaleObject(args[0])) + V8THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments"); + + GET_LOCALE_DATA_RESOURCE(args[0]->ToObject()); + + QString symbol; + if (args.Length() > 1) { + if (!args[1]->IsString()) + V8THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments"); + symbol = r->engine->toString(args[1]->ToString()); + } + + return r->engine->toString(r->locale.toCurrencyString(number, symbol)); +} + +v8::Handle QDeclarativeNumberExtension::fromLocaleString(const v8::Arguments& args) +{ + if (args.Length() < 1 || args.Length() > 2) + V8THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments"); + + int numberIdx = 0; + QLocale locale; + + if (args.Length() == 2) { + if (!isLocaleObject(args[0])) + V8THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments"); + + GET_LOCALE_DATA_RESOURCE(args[0]->ToObject()); + locale = r->locale; + + numberIdx = 1; + } + + v8::Local ns = args[numberIdx]->ToString(); + if (ns.IsEmpty() || ns->Length() == 0) + return v8::Number::New(Q_QNAN); + + bool ok = false; + double val = locale.toDouble(QJSConverter::toString(ns), &ok); + + if (!ok) + V8THROW_ERROR("Locale: Number.fromLocaleString(): Invalid format") + + return v8::Number::New(val); +} + +//-------------- +// Locale object + +static v8::Handle locale_get_firstDayOfWeek(v8::Local, const v8::AccessorInfo &info) +{ + GET_LOCALE_DATA_RESOURCE(info.This()); + return v8::Integer::New(r->locale.firstDayOfWeek()); +} + +static v8::Handle locale_get_measurementSystem(v8::Local, const v8::AccessorInfo &info) +{ + GET_LOCALE_DATA_RESOURCE(info.This()); + return v8::Integer::New(r->locale.measurementSystem()); +} + +static v8::Handle locale_get_textDirection(v8::Local, const v8::AccessorInfo &info) +{ + GET_LOCALE_DATA_RESOURCE(info.This()); + return v8::Integer::New(r->locale.textDirection()); +} + +static v8::Handle locale_get_weekDays(v8::Local, const v8::AccessorInfo &info) +{ + GET_LOCALE_DATA_RESOURCE(info.This()); + + QList days = r->locale.weekdays(); + + v8::Handle result = v8::Array::New(days.size()); + for (int i = 0; i < days.size(); ++i) { + int day = days.at(i); + if (day == 7) // JS Date days in range 0(Sunday) to 6(Saturday) + day = 0; + result->Set(i, v8::Integer::New(day)); + } + + return result; +} + +static v8::Handle locale_currencySymbol(const v8::Arguments &args) +{ + GET_LOCALE_DATA_RESOURCE(args.This()); + + if (args.Length() > 1) + V8THROW_ERROR("Locale: currencySymbol(): Invalid arguments"); + + QLocale::CurrencySymbolFormat format = QLocale::CurrencySymbol; + if (args.Length() == 1) { + quint32 intFormat = args[0]->ToNumber()->Value(); + format = QLocale::CurrencySymbolFormat(intFormat); + } + + return r->engine->toString(r->locale.currencySymbol(format)); +} + +#define LOCALE_FORMAT(FUNC) \ +static v8::Handle locale_ ##FUNC (const v8::Arguments &args) { \ + GET_LOCALE_DATA_RESOURCE(args.This());\ + if (args.Length() > 1) \ + V8THROW_ERROR("Locale: " #FUNC "(): Invalid arguments"); \ + QLocale::FormatType format = QLocale::LongFormat;\ + if (args.Length() == 1) { \ + quint32 intFormat = args[0]->Uint32Value(); \ + format = QLocale::FormatType(intFormat); \ + } \ + return r->engine->toString(r->locale. FUNC (format)); \ +} + +LOCALE_FORMAT(dateTimeFormat) +LOCALE_FORMAT(timeFormat) +LOCALE_FORMAT(dateFormat) + +// +1 added to idx because JS is 0-based, whereas QLocale months begin at 1. +#define LOCALE_FORMATTED_MONTHNAME(VARIABLE) \ +static v8::Handle locale_ ## VARIABLE (const v8::Arguments &args) {\ + GET_LOCALE_DATA_RESOURCE(args.This()); \ + if (args.Length() < 1 || args.Length() > 2) \ + V8THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \ + QLocale::FormatType enumFormat = QLocale::LongFormat; \ + int idx = args[0]->IntegerValue() + 1; \ + if (idx < 1 || idx > 12) \ + V8THROW_ERROR("Locale: Invalid month"); \ + QString name; \ + if (args.Length() == 2) { \ + if (args[1]->IsNumber()) { \ + quint32 intFormat = args[1]->IntegerValue(); \ + QLocale::FormatType format = QLocale::FormatType(intFormat); \ + name = r->locale. VARIABLE(idx, format); \ + } else { \ + V8THROW_ERROR("Locale: Invalid datetime format"); \ + } \ + } else { \ + name = r->locale. VARIABLE(idx, enumFormat); \ + } \ + return r->engine->toString(name); \ +} + +// 0 -> 7 as Qt::Sunday is 7, but Sunday is 0 in JS Date +#define LOCALE_FORMATTED_DAYNAME(VARIABLE) \ +static v8::Handle locale_ ## VARIABLE (const v8::Arguments &args) {\ + GET_LOCALE_DATA_RESOURCE(args.This()); \ + if (args.Length() < 1 || args.Length() > 2) \ + V8THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \ + QLocale::FormatType enumFormat = QLocale::LongFormat; \ + int idx = args[0]->IntegerValue(); \ + if (idx < 0 || idx > 7) \ + V8THROW_ERROR("Locale: Invalid day"); \ + if (idx == 0) idx = 7; \ + QString name; \ + if (args.Length() == 2) { \ + if (args[1]->IsNumber()) { \ + quint32 intFormat = args[1]->ToNumber()->Value(); \ + QLocale::FormatType format = QLocale::FormatType(intFormat); \ + name = r->locale. VARIABLE(idx, format); \ + } else { \ + V8THROW_ERROR("Locale: Invalid datetime format"); \ + } \ + } else { \ + name = r->locale. VARIABLE(idx, enumFormat); \ + } \ + return r->engine->toString(name); \ +} + + +#define LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(FT, VARIABLE, ENGINE) \ + FT->PrototypeTemplate()->Set(v8::String::New( #VARIABLE ), V8FUNCTION(locale_ ## VARIABLE, ENGINE)); + +LOCALE_FORMATTED_MONTHNAME(monthName) +LOCALE_FORMATTED_MONTHNAME(standaloneMonthName) +LOCALE_FORMATTED_DAYNAME(dayName) +LOCALE_FORMATTED_DAYNAME(standaloneDayName) + +#define LOCALE_STRING_PROPERTY(VARIABLE) static v8::Handle locale_get_ ## VARIABLE (v8::Local, const v8::AccessorInfo &info) \ +{ \ + GET_LOCALE_DATA_RESOURCE(info.This()); \ + return r->engine->toString(r->locale. VARIABLE());\ +} + +#define LOCALE_REGISTER_STRING_ACCESSOR(FT, VARIABLE) \ + FT ->PrototypeTemplate()->SetAccessor( v8::String::New( #VARIABLE ), locale_get_ ## VARIABLE ) + + +LOCALE_STRING_PROPERTY(name) +LOCALE_STRING_PROPERTY(nativeLanguageName) +LOCALE_STRING_PROPERTY(nativeCountryName) +LOCALE_STRING_PROPERTY(decimalPoint) +LOCALE_STRING_PROPERTY(groupSeparator) +LOCALE_STRING_PROPERTY(percent) +LOCALE_STRING_PROPERTY(zeroDigit) +LOCALE_STRING_PROPERTY(negativeSign) +LOCALE_STRING_PROPERTY(positiveSign) +LOCALE_STRING_PROPERTY(exponential) +LOCALE_STRING_PROPERTY(amText) +LOCALE_STRING_PROPERTY(pmText) + +class QV8LocaleDataDeletable : public QV8Engine::Deletable +{ +public: + QV8LocaleDataDeletable(QV8Engine *engine); + ~QV8LocaleDataDeletable(); + + v8::Persistent constructor; +}; + +QV8LocaleDataDeletable::QV8LocaleDataDeletable(QV8Engine *engine) +{ + v8::HandleScope handle_scope; + v8::Context::Scope scope(engine->context()); + + v8::Local ft = v8::FunctionTemplate::New(); + ft->InstanceTemplate()->SetHasExternalResource(true); + + LOCALE_REGISTER_STRING_ACCESSOR(ft, name); + LOCALE_REGISTER_STRING_ACCESSOR(ft, nativeLanguageName); + LOCALE_REGISTER_STRING_ACCESSOR(ft, nativeCountryName); + LOCALE_REGISTER_STRING_ACCESSOR(ft, decimalPoint); + LOCALE_REGISTER_STRING_ACCESSOR(ft, groupSeparator); + LOCALE_REGISTER_STRING_ACCESSOR(ft, percent); + LOCALE_REGISTER_STRING_ACCESSOR(ft, zeroDigit); + LOCALE_REGISTER_STRING_ACCESSOR(ft, negativeSign); + LOCALE_REGISTER_STRING_ACCESSOR(ft, positiveSign); + LOCALE_REGISTER_STRING_ACCESSOR(ft, exponential); + LOCALE_REGISTER_STRING_ACCESSOR(ft, amText); + LOCALE_REGISTER_STRING_ACCESSOR(ft, pmText); + + ft->PrototypeTemplate()->Set(v8::String::New("currencySymbol"), V8FUNCTION(locale_currencySymbol, engine)); + + ft->PrototypeTemplate()->Set(v8::String::New("dateTimeFormat"), V8FUNCTION(locale_dateTimeFormat, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("dateFormat"), V8FUNCTION(locale_dateFormat, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("timeFormat"), V8FUNCTION(locale_timeFormat, engine)); + + LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(ft, monthName, engine); + LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(ft, standaloneMonthName, engine); + LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(ft, dayName, engine); + LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(ft, standaloneDayName, engine); + + ft->PrototypeTemplate()->SetAccessor(v8::String::New("firstDayOfWeek"), locale_get_firstDayOfWeek); + ft->PrototypeTemplate()->SetAccessor(v8::String::New("weekDays"), locale_get_weekDays); + ft->PrototypeTemplate()->SetAccessor(v8::String::New("measurementSystem"), locale_get_measurementSystem); + ft->PrototypeTemplate()->SetAccessor(v8::String::New("textDirection"), locale_get_textDirection); + + constructor = qPersistentNew(ft->GetFunction()); +} + +QV8LocaleDataDeletable::~QV8LocaleDataDeletable() +{ + qPersistentDispose(constructor); +} + +V8_DEFINE_EXTENSION(QV8LocaleDataDeletable, localeV8Data); + +class QV8LocaleData { +public: + QV8LocaleData(QV8Engine*,const QLocale &); + ~QV8LocaleData(); + QDeclarativeV8Handle v8Value(); +private: + v8::Persistent m_v8Value; +}; + +QV8LocaleData::QV8LocaleData(QV8Engine *engine, const QLocale &locale) +{ + if (!engine) + return; + + QV8LocaleDataDeletable *d = localeV8Data(engine); + m_v8Value = qPersistentNew(d->constructor->NewInstance()); + QV8LocaleDataResource *r = new QV8LocaleDataResource(engine); + r->locale = locale; + m_v8Value->SetExternalResource(r); +} + +QV8LocaleData::~QV8LocaleData() +{ + qPersistentDispose(m_v8Value); +} + +QDeclarativeV8Handle QV8LocaleData::v8Value() +{ + return QDeclarativeV8Handle::fromHandle(m_v8Value); +} + +/*! + \qmlclass Locale QDeclarativeLocale + \inqmlmodule QtQuick 2 + \brief The Locale object provides locale specific properties and formatted data. + + The Locale object is created via the \l{QML:Qt::locale()}{Qt.locale()} function. It cannot be created + directly. + + The \l{QML:Qt::locale()}{Qt.locale()} function returns a JS Locale object representing the + locale with the specified name, which has the format + "language[_territory][.codeset][@modifier]" or "C". + + Locale supports the concept of a default locale, which is + determined from the system's locale settings at application + startup. If no parameter is passed to Qt.locale() the default + locale object is returned. + + The Locale object provides a number of functions and properties + providing data for the specified locale. + + The Locale object may also be passed to the \l Date and \l Number toLocaleString() + and fromLocaleString() methods in order to convert to/from strings using + the specified locale. + + This example shows the current date formatted for the German locale: + + \code + import QtQuick 2.0 + + Text { + text: "The date is: " + Date().toLocaleString(Qt.locale("de_DE")) + } + \endcode + + The following example displays the specified number + in the correct format for the default locale: + + \code + import QtQuick 2.0 + + Text { + text: "The value is: " + Number(23443.34).toLocaleString(Qt.locale()) + } + \endcode + + QtQuick Locale's data is based on Common Locale Data Repository v1.8.1. + + The double-to-string and string-to-double conversion functions are + covered by the following licenses: + + \legalese + Copyright (c) 1991 by AT&T. + + Permission to use, copy, modify, and distribute this software for any + purpose without fee is hereby granted, provided that this entire notice + is included in all copies of any software which is or includes a copy + or modification of this software and in all copies of the supporting + documentation for such software. + + THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR AT&T MAKES ANY + REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + + This product includes software developed by the University of + California, Berkeley and its contributors. + + \sa {QtQuick2::Date}{Date} {QtQuick2::Number}{Number} +*/ + +QDeclarativeLocale::QDeclarativeLocale() +{ +} + +QDeclarativeLocale::~QDeclarativeLocale() +{ +} + +v8::Handle QDeclarativeLocale::locale(QV8Engine *v8engine, const QString &locale) +{ + QV8LocaleDataDeletable *d = localeV8Data(v8engine); + v8::Local v8Value = d->constructor->NewInstance(); + QV8LocaleDataResource *r = new QV8LocaleDataResource(v8engine); + r->locale = QLocale(locale); + v8Value->SetExternalResource(r); + + return v8Value; +} + +/*! + \enum QtQuick2::Locale::FormatType + + This enumeration describes the types of format that can be used when + converting Date objects to strings. + + \value LongFormat The long version of day and month names; for + example, returning "January" as a month name. + + \value ShortFormat The short version of day and month names; for + example, returning "Jan" as a month name. + + \value NarrowFormat A special version of day and month names for + use when space is limited; for example, returning "J" as a month + name. Note that the narrow format might contain the same text for + different months and days or it can even be an empty string if the + locale doesn't support narrow names, so you should avoid using it + for date formatting. Also, for the system locale this format is + the same as ShortFormat. +*/ + +/*! + \qmlproperty string QtQuick2::Locale::name + + Holds the language and country of this locale as a + string of the form "language_country", where + language is a lowercase, two-letter ISO 639 language code, + and country is an uppercase, two- or three-letter ISO 3166 country code. +*/ + +/*! + \qmlproperty string QtQuick2::Locale::decimalPoint + + Holds the decimal point character of this locale. +*/ + +/*! + \qmlproperty string QtQuick2::Locale::groupSeparator + + Holds the group separator character of this locale. +*/ + +/*! + \qmlproperty string QtQuick2::Locale::percent + + Holds the percent character of this locale. +*/ + + +/*! + \qmlproperty string QtQuick2::Locale::zeroDigit + + Holds Returns the zero digit character of this locale. +*/ + +/*! + \qmlproperty string QtQuick2::Locale::negativeSign + + Holds the negative sign character of this locale. +*/ + +/*! + \qmlproperty string QtQuick2::Locale::positiveSign + + Holds the positive sign character of this locale. +*/ + +/*! + \qmlproperty string QtQuick2::Locale::exponential + + Holds the exponential character of this locale. +*/ + +/*! + \qmlmethod string QtQuick2::Locale::dateTimeFormat(type) + + Returns the date time format used for the current locale. + \a type specifies the FormatType to return. + + \sa {QtQuick2::Date}{Date} +*/ + +/*! + \qmlmethod string QtQuick2::Locale::dateFormat(type) + + Returns the date format used for the current locale. + \a type specifies the FormatType to return. + + \sa {QtQuick2::Date}{Date} +*/ + +/*! + \qmlmethod string QtQuick2::Locale::timeFormat(type) + + Returns the time format used for the current locale. + \a type specifies the FormatType to return. + + \sa {QtQuick2::Date}{Date} +*/ + +/*! + \qmlmethod string QtQuick2::Locale::monthName(month, type) + + Returns the localized name of \a month (0-11), in the optional + \l FortmatType specified by \a type. + + \note the QLocale C++ API expects a range of (1-12), however Locale.monthName() + expects 0-11 as per the JS Date object. + + \sa dayName(), standaloneMonthName() +*/ + +/*! + \qmlmethod string QtQuick2::Locale::standaloneMonthName(month, type) + + Returns the localized name of \a month (0-11) that is used as a + standalone text, in the optional \l FormatType specified by \a type. + + If the locale information doesn't specify the standalone month + name then return value is the same as in monthName(). + + \note the QLocale C++ API expects a range of (1-12), however Locale.standaloneMonthName() + expects 0-11 as per the JS Date object. + + \sa monthName(), standaloneDayName() +*/ + +/*! + \qmlmethod string QtQuick2::Locale::dayName(day, type) + + Returns the localized name of the \a day (where 0 represents + Sunday, 1 represents Monday and so on), in the optional + \l FormatType specified by \a type. + + \sa monthName(), standaloneDayName() +*/ + +/*! + \qmlmethod string QtQuick2::Locale::standaloneDayName(day, type) + + Returns the localized name of the \a day (where 0 represents + Sunday, 1 represents Monday and so on) that is used as a + standalone text, in the \l FormatType specified by \a type. + + If the locale information does not specify the standalone day + name then return value is the same as in dayName(). + + \sa dayName(), standaloneMonthName() +*/ + +/*! + \qmlproperty enumeration QtQuick2::Locale::firstDayOfWeek + + Holds the first day of the week according to the current locale. + + \list + \o Locale.Sunday = 0 + \o Locale.Monday = 1 + \o Locale.Tuesday = 2 + \o Locale.Wednesday = 3 + \o Locale.Thursday = 4 + \o Locale.Friday = 5 + \o Locale.Saturday = 6 + \endlist + + \note that these values match the JS Date API which is different + from the Qt C++ API where Qt::Sunday = 7. +*/ + +/*! + \qmlproperty Array QtQuick2::Locale::weekdays + + Holds an array of days that are considered weekdays according to the current locale, + where Sunday is 0 and Saturday is 6. + + \sa firstDayOfWeek +*/ + + +/*! + \qmlproperty enumeration QtQuick2::Locale::textDirection + + Holds the text direction of the language: + \list + \o Qt.LeftToRight + \o Qt.RightToLeft + \endlist +*/ + +/*! + \qmlproperty string QtQuick2::Locale::amText + + The localized name of the "AM" suffix for times specified using the conventions of the 12-hour clock. +*/ + +/*! + \qmlproperty string QtQuick2::Locale::pmText + + The localized name of the "PM" suffix for times specified using the conventions of the 12-hour clock. +*/ + +/*! + \qmlmethod string QtQuick2::Locale::currencySymbol(format) + + Returns the currency symbol for the specified \a format: + \list + \o Locale.CurrencyIsoCode a ISO-4217 code of the currency. + \o Locale.CurrencySymbol a currency symbol. + \o Locale.CurrencyDisplayName a user readable name of the currency. + \endlist +*/ + +/*! + \qmlproperty string QtQuick2::Locale::nativeLanguageName + + Holds a native name of the language for the locale. For example + "Schwiizertüütsch" for Swiss-German locale. + + \sa nativeCountryName +*/ + +/*! + \qmlproperty string QtQuick2::Locale::nativeCountryName + + Holds a native name of the country for the locale. For example + "España" for Spanish/Spain locale. + + \sa nativeLanguageName +*/ + +/*! + \qmlproperty enumeration QtQuick2::Locale::measurementSystem + + This property defines which units are used for measurement. + + \list + \o Locale.MetricSystem This value indicates metric units, such as meters, + centimeters and millimeters. + \o Locale.ImperialSystem This value indicates imperial units, such as inches and + miles. There are several distinct imperial systems in the world; this + value stands for the official United States imperial units. + \endlist +*/ + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativelocale_p.h b/src/declarative/qml/qdeclarativelocale_p.h new file mode 100644 index 0000000000..948729da36 --- /dev/null +++ b/src/declarative/qml/qdeclarativelocale_p.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVELOCALE_H +#define QDECLARATIVELOCALE_H + +#include + +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeDateExtension +{ +public: + static void registerExtension(QV8Engine *engine); + +private: + static v8::Handle toLocaleString(const v8::Arguments& args); + static v8::Handle toLocaleTimeString(const v8::Arguments& args); + static v8::Handle toLocaleDateString(const v8::Arguments& args); + static v8::Handle fromLocaleString(const v8::Arguments& args); + static v8::Handle fromLocaleTimeString(const v8::Arguments& args); + static v8::Handle fromLocaleDateString(const v8::Arguments& args); +}; + + +class QDeclarativeNumberExtension +{ +public: + static void registerExtension(QV8Engine *engine); + +private: + static v8::Handle toLocaleString(const v8::Arguments& args); + static v8::Handle fromLocaleString(const v8::Arguments& args); + static v8::Handle toLocaleCurrencyString(const v8::Arguments& args); +}; + + +class Q_AUTOTEST_EXPORT QDeclarativeLocale +{ + Q_GADGET + Q_ENUMS(MeasurementSystem) + Q_ENUMS(FormatType) + Q_ENUMS(CurrencySymbolFormat) + Q_ENUMS(DayOfWeek) + +public: + ~QDeclarativeLocale(); + + enum MeasurementSystem { + MetricSystem = QLocale::MetricSystem, + ImperialSystem = QLocale::ImperialSystem + }; + enum FormatType { + LongFormat = QLocale::LongFormat, + ShortFormat = QLocale::ShortFormat, + NarrowFormat = QLocale::NarrowFormat + }; + enum CurrencySymbolFormat { + CurrencyIsoCode = QLocale::CurrencyIsoCode, + CurrencySymbol = QLocale::CurrencySymbol, + CurrencyDisplayName = QLocale::CurrencyDisplayName + }; + // Qt defines Sunday as 7, but JS Date assigns Sunday 0 + enum DayOfWeek { + Sunday = 0, + Monday = Qt::Monday, + Tuesday = Qt::Tuesday, + Wednesday = Qt::Wednesday, + Thursday = Qt::Thursday, + Friday = Qt::Friday, + Saturday = Qt::Saturday + }; + + static v8::Handle locale(QV8Engine *v8engine, const QString &lang); + +private: + QDeclarativeLocale(); +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index b14e547f40..a920d62a2a 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -43,6 +43,7 @@ SOURCES += \ $$PWD/qdeclarativeextensionplugin.cpp \ $$PWD/qdeclarativeimport.cpp \ $$PWD/qdeclarativelist.cpp \ + $$PWD/qdeclarativelocale.cpp \ HEADERS += \ $$PWD/qdeclarativeglobal_p.h \ @@ -104,7 +105,8 @@ HEADERS += \ $$PWD/qdeclarativeimport_p.h \ $$PWD/qdeclarativeextensionplugin.h \ $$PWD/qdeclarativenullablevalue_p_p.h \ - $$PWD/qdeclarativescriptstring_p.h + $$PWD/qdeclarativescriptstring_p.h \ + $$PWD/qdeclarativelocale_p.h \ QT += sql include(parser/parser.pri) diff --git a/src/declarative/qml/v8/qdeclarativebuiltinfunctions.cpp b/src/declarative/qml/v8/qdeclarativebuiltinfunctions.cpp index 84b42f6d7f..a822eb84ec 100644 --- a/src/declarative/qml/v8/qdeclarativebuiltinfunctions.cpp +++ b/src/declarative/qml/v8/qdeclarativebuiltinfunctions.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -521,6 +522,8 @@ the possible format values as described for If \a format is not specified, \a date is formatted using \l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}. + +\sa Locale */ v8::Handle formatDate(const v8::Arguments &args) { @@ -560,6 +563,8 @@ described for \l{QML:Qt::formatDateTime()}{Qt.formatDateTime()}. If \a format is not specified, \a time is formatted using \l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}. + +\sa Locale */ v8::Handle formatTime(const v8::Arguments &args) { @@ -680,6 +685,8 @@ with the \a format values below to produce the following results: \row \i "hh:mm:ss.zzz" \i 14:13:09.042 \row \i "h:m:s ap" \i 2:13:9 pm \endtable + + \sa Locale */ v8::Handle formatDateTime(const v8::Arguments &args) { @@ -1087,6 +1094,42 @@ v8::Handle qsTrIdNoOp(const v8::Arguments &args) return args[0]; } + +/*! + \qmlmethod Qt::locale(name) + + Returns a JS object representing the locale with the specified + name, which has the format "language[_territory][.codeset][@modifier]" + or "C", where: + + \list + \o language is a lowercase, two-letter, ISO 639 language code, + \o territory is an uppercase, two-letter, ISO 3166 country code, + \o and codeset and modifier are ignored. + \endlist + + If the string violates the locale format, or language is not a + valid ISO 369 code, the "C" locale is used instead. If country + is not present, or is not a valid ISO 3166 code, the most + appropriate country is chosen for the specified language. + + \sa QtQuick2::Locale +*/ +v8::Handle locale(const v8::Arguments &args) +{ + QString code; + if (args.Length() > 1) + V8THROW_ERROR("locale() requires 0 or 1 argument"); + if (args.Length() == 1 && !args[0]->IsString()) + V8THROW_TYPE("locale(): argument (locale code) must be a string"); + + QV8Engine *v8engine = V8ENGINE(); + if (args.Length() == 1) + code = v8engine->toString(args[0]); + + return QDeclarativeLocale::locale(v8engine, code); +} + } // namespace QDeclarativeBuiltinFunctions QT_END_NAMESPACE diff --git a/src/declarative/qml/v8/qdeclarativebuiltinfunctions_p.h b/src/declarative/qml/v8/qdeclarativebuiltinfunctions_p.h index 8810f77df4..8a4ac06f6c 100644 --- a/src/declarative/qml/v8/qdeclarativebuiltinfunctions_p.h +++ b/src/declarative/qml/v8/qdeclarativebuiltinfunctions_p.h @@ -96,6 +96,7 @@ v8::Handle qsTrNoOp(const v8::Arguments &args); v8::Handle qsTrId(const v8::Arguments &args); v8::Handle qsTrIdNoOp(const v8::Arguments &args); v8::Handle stringArg(const v8::Arguments &args); +v8::Handle locale(const v8::Arguments &args); } QT_END_NAMESPACE diff --git a/src/declarative/qml/v8/qjsengine.cpp b/src/declarative/qml/v8/qjsengine.cpp index 084640bb14..e0fc36727d 100644 --- a/src/declarative/qml/v8/qjsengine.cpp +++ b/src/declarative/qml/v8/qjsengine.cpp @@ -22,6 +22,7 @@ ****************************************************************************/ #include "qjsengine.h" +#include "qjsengine_p.h" #include "qjsvalue.h" #include "qjsvalue_p.h" #include "qscriptisolate_p.h" @@ -178,7 +179,7 @@ QJSEngine::QJSEngine(QObject *parent) { } -QJSEngine::QJSEngine(QObjectPrivate &dd, QObject *parent) +QJSEngine::QJSEngine(QJSEnginePrivate &dd, QObject *parent) : QObject(dd, parent) , d(new QV8Engine(this)) { diff --git a/src/declarative/qml/v8/qjsengine.h b/src/declarative/qml/v8/qjsengine.h index 759363ab84..c941d0c9e3 100644 --- a/src/declarative/qml/v8/qjsengine.h +++ b/src/declarative/qml/v8/qjsengine.h @@ -45,6 +45,7 @@ class QRegExp; template inline T qjsvalue_cast(const QJSValue &); +class QJSEnginePrivate; class Q_DECLARATIVE_EXPORT QJSEngine : public QObject { @@ -111,11 +112,12 @@ private: friend inline bool qjsvalue_cast_helper(const QJSValue &, int, void *); protected: - QJSEngine(QObjectPrivate &dd, QObject *parent = 0); + QJSEngine(QJSEnginePrivate &dd, QObject *parent = 0); private: QV8Engine *d; Q_DISABLE_COPY(QJSEngine) + Q_DECLARE_PRIVATE(QJSEngine) friend class QV8Engine; }; diff --git a/src/declarative/qml/v8/qjsengine_p.h b/src/declarative/qml/v8/qjsengine_p.h new file mode 100644 index 0000000000..46f8754af4 --- /dev/null +++ b/src/declarative/qml/v8/qjsengine_p.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-ONLY$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QJSENGINE_P_H +#define QJSENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include "qjsengine.h" + + +QT_BEGIN_NAMESPACE + + +class QJSEnginePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QJSEngine) + +public: + static QJSEnginePrivate* get(QJSEngine*e) { return e->d_func(); } + + QJSEnginePrivate() {} +}; + +QT_END_NAMESPACE + +#endif // QJSENGINE_P_H diff --git a/src/declarative/qml/v8/qv8engine.cpp b/src/declarative/qml/v8/qv8engine.cpp index 791c972c0b..7c4ebff7c1 100644 --- a/src/declarative/qml/v8/qv8engine.cpp +++ b/src/declarative/qml/v8/qv8engine.cpp @@ -47,6 +47,7 @@ #include "qv8gccallback_p.h" #include "qv8sequencewrapper_p.h" #include "qv8include_p.h" +#include "qjsengine_p.h" #include "../../../3rdparty/javascriptcore/DateMath.h" #include @@ -55,6 +56,7 @@ #include #include #include +#include #include "qscript_impl_p.h" #include "qv8domerrors_p.h" @@ -113,6 +115,7 @@ static bool ObjectComparisonCallback(v8::Local lhs, v8::Local value, int typeHint) case QV8ObjectResource::ListModelType: case QV8ObjectResource::Context2DType: case QV8ObjectResource::ParticleDataType: + case QV8ObjectResource::LocaleDataType: return QVariant(); case QV8ObjectResource::TypeType: return m_typeWrapper.toVariant(r); @@ -565,6 +569,7 @@ void QV8Engine::initializeGlobal(v8::Handle global) qt->Set(v8::String::New("btoa"), V8FUNCTION(btoa, this)); qt->Set(v8::String::New("atob"), V8FUNCTION(atob, this)); qt->Set(v8::String::New("resolvedUrl"), V8FUNCTION(resolvedUrl, this)); + qt->Set(v8::String::New("locale"), V8FUNCTION(locale, this)); if (m_engine) { qt->Set(v8::String::New("application"), newQObject(new QDeclarativeApplication(m_engine))); @@ -604,6 +609,9 @@ void QV8Engine::initializeGlobal(v8::Handle global) #undef STRING_ARG } + QDeclarativeDateExtension::registerExtension(this); + QDeclarativeNumberExtension::registerExtension(this); + qt_add_domexceptions(this); m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(this); m_sqlDatabaseData = qt_add_qmlsqldatabase(this); diff --git a/src/declarative/qml/v8/qv8engine_p.h b/src/declarative/qml/v8/qv8engine_p.h index 7b85cfcc31..acf7ec816a 100644 --- a/src/declarative/qml/v8/qv8engine_p.h +++ b/src/declarative/qml/v8/qv8engine_p.h @@ -139,7 +139,7 @@ public: ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType, ListModelType, Context2DType, Context2DStyleType, Context2DPixelArrayType, ParticleDataType, SignalHandlerType, IncubatorType, VisualDataItemType, - SequenceType }; + SequenceType, LocaleDataType }; virtual ResourceType resourceType() const = 0; QV8Engine *engine; @@ -412,6 +412,9 @@ public: QObject *qtObjectFromJS(v8::Handle value); QSet visitedConversionObjects; + + static QDateTime qtDateTimeFromJsDate(double jsDate); + protected: QJSEngine* q; QDeclarativeEngine *m_engine; @@ -449,7 +452,6 @@ protected: void initializeGlobal(v8::Handle); double qtDateTimeToJsDate(const QDateTime &dt); - QDateTime qtDateTimeFromJsDate(double jsDate); private: typedef QScriptIntrusiveList ValueList; diff --git a/src/declarative/qml/v8/script.pri b/src/declarative/qml/v8/script.pri index 587ab6f42d..3439413f5e 100644 --- a/src/declarative/qml/v8/script.pri +++ b/src/declarative/qml/v8/script.pri @@ -5,6 +5,7 @@ SOURCES += \ HEADERS += \ $$PWD/qjsengine.h \ + $$PWD/qjsengine_p.h \ $$PWD/qjsvalue.h \ $$PWD/qjsvalue_p.h \ $$PWD/qjsvalueiterator.h \ diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro index 7cb9d33576..0d19af9a6c 100644 --- a/tests/auto/declarative/declarative.pro +++ b/tests/auto/declarative/declarative.pro @@ -22,6 +22,7 @@ PUBLICTESTS += \ qdeclarativeqt \ qdeclarativetranslation \ qdeclarativexmlhttprequest \ + qdeclarativelocale \ qjsvalue \ qjsvalueiterator \ qjsengine \ diff --git a/tests/auto/declarative/qdeclarativelocale/data/date.qml b/tests/auto/declarative/qdeclarativelocale/data/date.qml new file mode 100644 index 0000000000..3f58497d22 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelocale/data/date.qml @@ -0,0 +1,45 @@ +import QtQuick 2.0 + +QtObject { + property var locale: Qt.locale() + + function setLocale(l) { + locale = Qt.locale(l) + } + + function toLocaleString(fmt) { + var d = new Date(2011, 9, 7, 18, 53, 48, 345); + if (fmt < 0) + return d.toLocaleString(locale); + else + return d.toLocaleString(locale, fmt); + } + + function toLocaleDateString(fmt) { + var d = new Date(2011, 9, 7, 18, 53, 48, 345); + if (fmt < 0) + return d.toLocaleDateString(locale); + else + return d.toLocaleDateString(locale, fmt); + } + + function toLocaleTimeString(fmt) { + var d = new Date(2011, 9, 7, 18, 53, 48, 345); + if (fmt < 0) + return d.toLocaleTimeString(locale); + else + return d.toLocaleTimeString(locale, fmt); + } + + function fromLocaleString(d,fmt) { + return Date.fromLocaleString(locale, d, fmt) + } + + function fromLocaleDateString(d,fmt) { + return Date.fromLocaleDateString(locale, d, fmt) + } + + function fromLocaleTimeString(d,fmt) { + return Date.fromLocaleTimeString(locale, d, fmt) + } +} diff --git a/tests/auto/declarative/qdeclarativelocale/data/functions.qml b/tests/auto/declarative/qdeclarativelocale/data/functions.qml new file mode 100644 index 0000000000..5fef6a26fb --- /dev/null +++ b/tests/auto/declarative/qdeclarativelocale/data/functions.qml @@ -0,0 +1,65 @@ +import QtQuick 2.0 + +QtObject { + property var locale: Qt.locale() + + function setLocale(l) { + locale = Qt.locale(l) + } + + function currencySymbol(type) { + if (type < 0) + return locale.currencySymbol() + else + return locale.currencySymbol(type) + } + + function monthName(month,type) { + if (type < 0) + return locale.monthName(month) + else + return locale.monthName(month, type) + } + + function standaloneMonthName(month,type) { + if (type < 0) + return locale.standaloneMonthName(month) + else + return locale.standaloneMonthName(month, type) + } + + function dayName(month,type) { + if (type < 0) + return locale.dayName(month) + else + return locale.dayName(month, type) + } + + function standaloneDayName(month,type) { + if (type < 0) + return locale.standaloneDayName(month) + else + return locale.standaloneDayName(month, type) + } + + function dateTimeFormat(fmt) { + if (fmt < 0) + return locale.dateTimeFormat() + else + return locale.dateTimeFormat(fmt) + } + + function dateFormat(fmt) { + if (fmt < 0) + return locale.dateFormat() + else + return locale.dateFormat(fmt) + } + + function timeFormat(fmt) { + if (fmt < 0) + return locale.timeFormat() + else + return locale.timeFormat(fmt) + } +} diff --git a/tests/auto/declarative/qdeclarativelocale/data/number.qml b/tests/auto/declarative/qdeclarativelocale/data/number.qml new file mode 100644 index 0000000000..51a6c15dce --- /dev/null +++ b/tests/auto/declarative/qdeclarativelocale/data/number.qml @@ -0,0 +1,30 @@ +import QtQuick 2.0 + +QtObject { + property var locale: Qt.locale() + + function setLocale(l) { + locale = Qt.locale(l) + } + + function toLocaleString(n,fmt,prec) { + if (prec < 0) + return n.toLocaleString(locale, fmt); + else + return n.toLocaleString(locale, fmt, prec); + } + + function toLocaleCurrencyString(n,symbol) { + if (symbol.length == 0) + return n.toLocaleCurrencyString(locale); + else + return n.toLocaleCurrencyString(locale, symbol); + } + + function fromLocaleString(n) { + return Number.fromLocaleString(locale, n) + } + + property var const1: 1234.56.toLocaleString(locale); + property var const2: 1234..toLocaleString(locale); +} diff --git a/tests/auto/declarative/qdeclarativelocale/data/properties.qml b/tests/auto/declarative/qdeclarativelocale/data/properties.qml new file mode 100644 index 0000000000..1d2968b419 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelocale/data/properties.qml @@ -0,0 +1,26 @@ +import QtQuick 2.0 + +QtObject { + property var locale: Qt.locale() + + function setLocale(l) { + locale = Qt.locale(l); + } + + property var name: locale.name + property var amText: locale.amText + property var pmText: locale.pmText + property var nativeLanguageName: locale.nativeLanguageName + property var nativeCountryName: locale.nativeCountryName + property var decimalPoint: locale.decimalPoint + property var groupSeparator: locale.groupSeparator + property var percent: locale.percent + property var zeroDigit: locale.zeroDigit + property var negativeSign: locale.negativeSign + property var positiveSign: locale.positiveSign + property var exponential: locale.exponential + property var firstDayOfWeek: locale.firstDayOfWeek + property var measurementSystem: locale.measurementSystem + property var textDirection: locale.textDirection + property var weekDays: locale.weekDays +} diff --git a/tests/auto/declarative/qdeclarativelocale/qdeclarativelocale.pro b/tests/auto/declarative/qdeclarativelocale/qdeclarativelocale.pro new file mode 100644 index 0000000000..05ce0fec6a --- /dev/null +++ b/tests/auto/declarative/qdeclarativelocale/qdeclarativelocale.pro @@ -0,0 +1,13 @@ +CONFIG += testcase +TARGET = tst_qdeclarativelocale +macx:CONFIG -= app_bundle + +SOURCES += tst_qdeclarativelocale.cpp + +testDataFiles.files = data +testDataFiles.path = . +DEPLOYMENT += testDataFiles + +CONFIG += parallel_test + +QT += declarative testlib diff --git a/tests/auto/declarative/qdeclarativelocale/tst_qdeclarativelocale.cpp b/tests/auto/declarative/qdeclarativelocale/tst_qdeclarativelocale.cpp new file mode 100644 index 0000000000..54139a2671 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelocale/tst_qdeclarativelocale.cpp @@ -0,0 +1,1090 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include + +#include +#include +#include +#include +#include +#include "../shared/util.h" + +class tst_qdeclarativelocale : public QObject +{ + Q_OBJECT +public: + tst_qdeclarativelocale() { } + +private slots: + void properties_data(); + void properties(); + void currencySymbol_data(); + void currencySymbol(); + void monthName_data(); + void monthName(); + void standaloneMonthName_data(); + void standaloneMonthName(); + void dayName_data(); + void dayName(); + void standaloneDayName_data(); + void standaloneDayName(); + void weekDays_data(); + void weekDays(); + void dateFormat_data(); + void dateFormat(); + void dateTimeFormat_data(); + void dateTimeFormat(); + void timeFormat_data(); + void timeFormat(); + + void dateToLocaleString_data(); + void dateToLocaleString(); + void dateToLocaleStringFormatted_data(); + void dateToLocaleStringFormatted(); + void dateToLocaleDateString_data(); + void dateToLocaleDateString(); + void dateToLocaleDateStringFormatted_data(); + void dateToLocaleDateStringFormatted(); + void dateToLocaleTimeString_data(); + void dateToLocaleTimeString(); + void dateToLocaleTimeStringFormatted_data(); + void dateToLocaleTimeStringFormatted(); + void dateFromLocaleString_data(); + void dateFromLocaleString(); + void dateFromLocaleDateString_data(); + void dateFromLocaleDateString(); + void dateFromLocaleTimeString_data(); + void dateFromLocaleTimeString(); + + void numberToLocaleString_data(); + void numberToLocaleString(); + void numberToLocaleCurrencyString_data(); + void numberToLocaleCurrencyString(); + void numberFromLocaleString_data(); + void numberFromLocaleString(); + void numberConstToLocaleString(); + +private: + void addPropertyData(const QString &l); + QVariant getProperty(QObject *obj, const QString &locale, const QString &property); + void addCurrencySymbolData(const QString &locale); + void addStandardFormatData(); + void addFormatNameData(const QString &locale); + void addDateTimeFormatData(const QString &l); + void addDateFormatData(const QString &l); + void addTimeFormatData(const QString &l); + QDeclarativeEngine engine; +}; + +#define LOCALE_PROP(type,prop) { #prop, QVariant(type(qlocale.prop())) } + +void tst_qdeclarativelocale::addPropertyData(const QString &l) +{ + QLocale qlocale(l); + + struct { + const char *name; + QVariant value; + } + values[] = { + LOCALE_PROP(QString,name), + LOCALE_PROP(QString,amText), + LOCALE_PROP(QString,pmText), + LOCALE_PROP(QString,nativeLanguageName), + LOCALE_PROP(QString,nativeCountryName), + LOCALE_PROP(QString,decimalPoint), + LOCALE_PROP(QString,groupSeparator), + LOCALE_PROP(QString,percent), + LOCALE_PROP(QString,zeroDigit), + LOCALE_PROP(QString,negativeSign), + LOCALE_PROP(QString,positiveSign), + LOCALE_PROP(QString,exponential), + LOCALE_PROP(int,firstDayOfWeek), + LOCALE_PROP(int,measurementSystem), + LOCALE_PROP(int,textDirection), + { 0, QVariant() } + }; + + int i = 0; + while (values[i].name) { + QByteArray n = l.toLatin1() + ':' + values[i].name; + QTest::newRow(n.constData()) << l << QByteArray(values[i].name) << values[i].value; + ++i; + } +} + +void tst_qdeclarativelocale::properties_data() +{ + QTest::addColumn("locale"); + QTest::addColumn("property"); + QTest::addColumn("value"); + + addPropertyData("en_US"); + addPropertyData("de_DE"); + addPropertyData("ar_SA"); + addPropertyData("hi_IN"); + addPropertyData("zh_CN"); + addPropertyData("th_TH"); +} + +void tst_qdeclarativelocale::properties() +{ + QFETCH(QString, locale); + QFETCH(QByteArray, property); + QFETCH(QVariant, value); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("properties.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QCOMPARE(obj->property(property), value); + + delete obj; +} + +void tst_qdeclarativelocale::addCurrencySymbolData(const QString &l) +{ + QByteArray locale = l.toLatin1(); + QTest::newRow(locale.constData()) << l << -1; + QByteArray t(locale); + t += " CurrencyIsoCode"; + QTest::newRow(t.constData()) << l << (int)QLocale::CurrencyIsoCode; + t = locale + " CurrencySymbol"; + QTest::newRow(t.constData()) << l << (int)QLocale::CurrencySymbol; + t = locale + " CurrencyDisplayName"; + QTest::newRow(t.constData()) << l << (int)QLocale::CurrencyDisplayName; +} + +void tst_qdeclarativelocale::currencySymbol_data() +{ + QTest::addColumn("locale"); + QTest::addColumn("param"); + + addCurrencySymbolData("en_US"); + addCurrencySymbolData("de_DE"); + addCurrencySymbolData("ar_SA"); + addCurrencySymbolData("hi_IN"); + addCurrencySymbolData("zh_CN"); + addCurrencySymbolData("th_TH"); +} + +void tst_qdeclarativelocale::currencySymbol() +{ + QFETCH(QString, locale); + QFETCH(int, param); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("functions.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QLocale l(locale); + QVariant val; + QLocale::CurrencySymbolFormat format = QLocale::CurrencySymbol; + + if (param >= 0) + format = QLocale::CurrencySymbolFormat(param); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QMetaObject::invokeMethod(obj, "currencySymbol", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(int(format)))); + + QCOMPARE(val.toString(), l.currencySymbol(format)); + + delete obj; +} + +void tst_qdeclarativelocale::addFormatNameData(const QString &l) +{ + QByteArray locale = l.toLatin1(); + QTest::newRow(locale.constData()) << l << -1; + QByteArray t(locale); + t += " LongFormat"; + QTest::newRow(t.constData()) << l << (int)QLocale::LongFormat; + t = locale + " ShortFormat"; + QTest::newRow(t.constData()) << l << (int)QLocale::ShortFormat; + t = locale + " NarrowFormat"; + QTest::newRow(t.constData()) << l << (int)QLocale::NarrowFormat; +} + +void tst_qdeclarativelocale::addStandardFormatData() +{ + QTest::addColumn("locale"); + QTest::addColumn("param"); + + addFormatNameData("en_US"); + addFormatNameData("de_DE"); + addFormatNameData("ar_SA"); + addFormatNameData("hi_IN"); + addFormatNameData("zh_CN"); + addFormatNameData("th_TH"); +} + +void tst_qdeclarativelocale::monthName_data() +{ + addStandardFormatData(); +} + +void tst_qdeclarativelocale::monthName() +{ + QFETCH(QString, locale); + QFETCH(int, param); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("functions.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QLocale l(locale); + QVariant val; + QLocale::FormatType format = QLocale::LongFormat; + if (param >= 0) + format = QLocale::FormatType(param); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + for (int i = 0; i <= 11; ++i) { + QMetaObject::invokeMethod(obj, "monthName", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(i)), + Q_ARG(QVariant, QVariant(int(format)))); + + // QLocale January == 1, JS Date January == 0 + QCOMPARE(val.toString(), l.monthName(i+1, format)); + } + + delete obj; +} + +void tst_qdeclarativelocale::standaloneMonthName_data() +{ + addStandardFormatData(); +} + +void tst_qdeclarativelocale::standaloneMonthName() +{ + QFETCH(QString, locale); + QFETCH(int, param); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("functions.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QLocale l(locale); + QVariant val; + QLocale::FormatType format = QLocale::LongFormat; + if (param >= 0) + format = QLocale::FormatType(param); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + for (int i = 0; i <= 11; ++i) { + QMetaObject::invokeMethod(obj, "standaloneMonthName", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(i)), + Q_ARG(QVariant, QVariant(int(format)))); + + // QLocale January == 1, JS Date January == 0 + QCOMPARE(val.toString(), l.standaloneMonthName(i+1, format)); + } + + delete obj; +} + +void tst_qdeclarativelocale::dayName_data() +{ + addStandardFormatData(); +} + +void tst_qdeclarativelocale::dayName() +{ + QFETCH(QString, locale); + QFETCH(int, param); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("functions.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QLocale l(locale); + QVariant val; + QLocale::FormatType format = QLocale::LongFormat; + if (param >= 0) + format = QLocale::FormatType(param); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + for (int i = 1; i <= 7; ++i) { + QMetaObject::invokeMethod(obj, "dayName", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(i)), + Q_ARG(QVariant, QVariant(int(format)))); + + QCOMPARE(val.toString(), l.dayName(i, format)); + } + + delete obj; +} + +void tst_qdeclarativelocale::standaloneDayName_data() +{ + addStandardFormatData(); +} + +void tst_qdeclarativelocale::standaloneDayName() +{ + QFETCH(QString, locale); + QFETCH(int, param); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("functions.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QLocale l(locale); + QVariant val; + QLocale::FormatType format = param < 0 ? QLocale::LongFormat : QLocale::FormatType(param); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + for (int i = 1; i <= 7; ++i) { + QMetaObject::invokeMethod(obj, "standaloneDayName", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(i)), + Q_ARG(QVariant, QVariant(int(format)))); + + QCOMPARE(val.toString(), l.standaloneDayName(i, format)); + } + + delete obj; +} + +void tst_qdeclarativelocale::weekDays_data() +{ + QTest::addColumn("locale"); + + QTest::newRow("en_US") << "en_US"; + QTest::newRow("de_DE") << "de_DE"; + QTest::newRow("ar_SA") << "ar_SA"; + QTest::newRow("hi_IN") << "hi_IN"; + QTest::newRow("zh_CN") << "zh_CN"; + QTest::newRow("th_TH") << "th_TH"; +} + +void tst_qdeclarativelocale::weekDays() +{ + QFETCH(QString, locale); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("properties.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QVariant val = obj->property("weekDays"); + QVERIFY(val.type() == QVariant::List); + + QList qmlDays = val.toList(); + QList days = QLocale(locale).weekdays(); + + QVERIFY(days.count() == qmlDays.count()); + + for (int i = 0; i < days.count(); ++i) { + int day = int(days.at(i)); + if (day == 7) // JS Date days in range 0(Sunday) to 6(Saturday) + day = 0; + QCOMPARE(day, qmlDays.at(i).toInt()); + } + + delete obj; +} + + +void tst_qdeclarativelocale::dateTimeFormat_data() +{ + addStandardFormatData(); +} + +void tst_qdeclarativelocale::dateTimeFormat() +{ + QFETCH(QString, locale); + QFETCH(int, param); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("functions.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QLocale l(locale); + QVariant val; + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QLocale::FormatType format = param < 0 ? QLocale::LongFormat : QLocale::FormatType(param); + QMetaObject::invokeMethod(obj, "dateTimeFormat", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(param))); + + QCOMPARE(val.toString(), l.dateTimeFormat(format)); +} + +void tst_qdeclarativelocale::dateFormat_data() +{ + addStandardFormatData(); +} + +void tst_qdeclarativelocale::dateFormat() +{ + QFETCH(QString, locale); + QFETCH(int, param); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("functions.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QLocale l(locale); + QVariant val; + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QLocale::FormatType format = param < 0 ? QLocale::LongFormat : QLocale::FormatType(param); + QMetaObject::invokeMethod(obj, "dateFormat", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(param))); + + QCOMPARE(val.toString(), l.dateFormat(format)); +} + +void tst_qdeclarativelocale::timeFormat_data() +{ + addStandardFormatData(); +} + +void tst_qdeclarativelocale::timeFormat() +{ + QFETCH(QString, locale); + QFETCH(int, param); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("functions.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QLocale l(locale); + QVariant val; + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QLocale::FormatType format = param < 0 ? QLocale::LongFormat : QLocale::FormatType(param); + QMetaObject::invokeMethod(obj, "timeFormat", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(param))); + + QCOMPARE(val.toString(), l.timeFormat(format)); +} + +void tst_qdeclarativelocale::dateToLocaleString_data() +{ + addStandardFormatData(); +} + +void tst_qdeclarativelocale::dateToLocaleString() +{ + QFETCH(QString, locale); + QFETCH(int, param); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("date.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QDateTime dt; + dt.setDate(QDate(2011, 10, 7)); // weirdly, JS Date month range is 0-11 + dt.setTime(QTime(18, 53, 48, 345)); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QLocale::FormatType format = param < 0 ? QLocale::LongFormat : QLocale::FormatType(param); + + QVariant val; + QMetaObject::invokeMethod(obj, "toLocaleString", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(param))); + + QLocale l(locale); + QCOMPARE(val.toString(), l.toString(dt, format)); +} + +void tst_qdeclarativelocale::addDateTimeFormatData(const QString &l) +{ + const char *formats[] = { + "hh:mm dd.MM.yyyy", + "h:m:sap ddd MMMM d yy", + "'The date and time is: 'H:mm:ss:zzz dd/MM/yy", + "MMM d yyyy HH:mm t", + 0 + }; + QByteArray locale = l.toLatin1(); + int i = 0; + while (formats[i]) { + QByteArray t(locale); + t += " "; + t += formats[i]; + QTest::newRow(t.constData()) << l << QString(formats[i]); + ++i; + } +} + +void tst_qdeclarativelocale::dateToLocaleStringFormatted_data() +{ + QTest::addColumn("locale"); + QTest::addColumn("format"); + + addDateTimeFormatData("en_US"); + addDateTimeFormatData("de_DE"); + addDateTimeFormatData("ar_SA"); + addDateTimeFormatData("hi_IN"); + addDateTimeFormatData("zh_CN"); + addDateTimeFormatData("th_TH"); +} + +void tst_qdeclarativelocale::dateToLocaleStringFormatted() +{ + QFETCH(QString, locale); + QFETCH(QString, format); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("date.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QDateTime dt; + dt.setDate(QDate(2011, 10, 7)); // weirdly, JS Date month range is 0-11 + dt.setTime(QTime(18, 53, 48, 345)); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QVariant val; + QMetaObject::invokeMethod(obj, "toLocaleString", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(format))); + + QLocale l(locale); + QCOMPARE(val.toString(), l.toString(dt, format)); +} + +void tst_qdeclarativelocale::dateToLocaleDateString_data() +{ + addStandardFormatData(); +} + +void tst_qdeclarativelocale::dateToLocaleDateString() +{ + QFETCH(QString, locale); + QFETCH(int, param); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("date.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QDateTime dt; + dt.setDate(QDate(2011, 10, 7)); // weirdly, JS Date month range is 0-11 + dt.setTime(QTime(18, 53, 48, 345)); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QLocale::FormatType format = param < 0 ? QLocale::LongFormat : QLocale::FormatType(param); + + QVariant val; + QMetaObject::invokeMethod(obj, "toLocaleDateString", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(param))); + + QLocale l(locale); + QCOMPARE(val.toString(), l.toString(dt.date(), format)); +} + +void tst_qdeclarativelocale::addDateFormatData(const QString &l) +{ + const char *formats[] = { + "dd.MM.yyyy", + "ddd MMMM d yy", + "'The date is: 'dd/MM/yy", + "MMM d yyyy", + 0 + }; + QByteArray locale = l.toLatin1(); + int i = 0; + while (formats[i]) { + QByteArray t(locale); + t += " "; + t += formats[i]; + QTest::newRow(t.constData()) << l << QString(formats[i]); + ++i; + } +} + +void tst_qdeclarativelocale::dateToLocaleDateStringFormatted_data() +{ + QTest::addColumn("locale"); + QTest::addColumn("format"); + + addDateFormatData("en_US"); + addDateFormatData("de_DE"); + addDateFormatData("ar_SA"); + addDateFormatData("hi_IN"); + addDateFormatData("zh_CN"); + addDateFormatData("th_TH"); +} + +void tst_qdeclarativelocale::dateToLocaleDateStringFormatted() +{ + QFETCH(QString, locale); + QFETCH(QString, format); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("date.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QDateTime dt; + dt.setDate(QDate(2011, 10, 7)); // weirdly, JS Date month range is 0-11 + dt.setTime(QTime(18, 53, 48, 345)); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QVariant val; + QMetaObject::invokeMethod(obj, "toLocaleString", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(format))); + + QLocale l(locale); + QCOMPARE(val.toString(), l.toString(dt.date(), format)); +} + +void tst_qdeclarativelocale::dateToLocaleTimeString_data() +{ + addStandardFormatData(); +} + +void tst_qdeclarativelocale::dateToLocaleTimeString() +{ + QFETCH(QString, locale); + QFETCH(int, param); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("date.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QDateTime dt; + dt.setDate(QDate(2011, 10, 7)); // weirdly, JS Date month range is 0-11 + dt.setTime(QTime(18, 53, 48, 345)); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QLocale::FormatType format = param < 0 ? QLocale::LongFormat : QLocale::FormatType(param); + + QVariant val; + QMetaObject::invokeMethod(obj, "toLocaleTimeString", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(param))); + + QLocale l(locale); + QCOMPARE(val.toString(), l.toString(dt.time(), format)); +} + +void tst_qdeclarativelocale::addTimeFormatData(const QString &l) +{ + const char *formats[] = { + "hh:mm", + "h:m:sap", + "'The time is: 'H:mm:ss:zzz", + "HH:mm t", + 0 + }; + QByteArray locale = l.toLatin1(); + int i = 0; + while (formats[i]) { + QByteArray t(locale); + t += " "; + t += formats[i]; + QTest::newRow(t.constData()) << l << QString(formats[i]); + ++i; + } +} + +void tst_qdeclarativelocale::dateToLocaleTimeStringFormatted_data() +{ + QTest::addColumn("locale"); + QTest::addColumn("format"); + + addTimeFormatData("en_US"); + addTimeFormatData("de_DE"); + addTimeFormatData("ar_SA"); + addTimeFormatData("hi_IN"); + addTimeFormatData("zh_CN"); + addTimeFormatData("th_TH"); +} + +void tst_qdeclarativelocale::dateToLocaleTimeStringFormatted() +{ + QFETCH(QString, locale); + QFETCH(QString, format); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("date.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QDateTime dt; + dt.setDate(QDate(2011, 10, 7)); // weirdly, JS Date month range is 0-11 + dt.setTime(QTime(18, 53, 48, 345)); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QVariant val; + QMetaObject::invokeMethod(obj, "toLocaleString", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(format))); + + QLocale l(locale); + QCOMPARE(val.toString(), l.toString(dt.time(), format)); +} + +void tst_qdeclarativelocale::dateFromLocaleString_data() +{ + QTest::addColumn("locale"); + QTest::addColumn("format"); + + QTest::newRow("en_US 1") << "en_US" << "dddd, MMMM d, yyyy h:mm:ss AP"; + QTest::newRow("en_US long") << "en_US" << QLocale("en_US").dateTimeFormat(); + QTest::newRow("en_US short") << "en_US" << QLocale("en_US").dateTimeFormat(QLocale::ShortFormat); + QTest::newRow("de_DE long") << "de_DE" << QLocale("de_DE").dateTimeFormat(); + QTest::newRow("de_DE short") << "de_DE" << QLocale("de_DE").dateTimeFormat(QLocale::ShortFormat); + QTest::newRow("ar_SA long") << "ar_SA" << QLocale("ar_SA").dateTimeFormat(); + QTest::newRow("ar_SA short") << "ar_SA" << QLocale("ar_SA").dateTimeFormat(QLocale::ShortFormat); + QTest::newRow("zh_CN long") << "zh_CN" << QLocale("zh_CN").dateTimeFormat(); + QTest::newRow("zh_CN short") << "zh_CN" << QLocale("zh_CN").dateTimeFormat(QLocale::ShortFormat); +} + +void tst_qdeclarativelocale::dateFromLocaleString() +{ + QFETCH(QString, locale); + QFETCH(QString, format); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("date.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QDateTime dt; + dt.setDate(QDate(2011, 10, 7)); + dt.setTime(QTime(18, 53, 48, 345)); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QLocale l(locale); + QVariant val; + QMetaObject::invokeMethod(obj, "fromLocaleString", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(l.toString(dt, format))), + Q_ARG(QVariant, QVariant(format))); + + QDateTime pd = l.toDateTime(l.toString(dt, format), format); + QCOMPARE(val.toDateTime(), pd); +} + +void tst_qdeclarativelocale::dateFromLocaleDateString_data() +{ + QTest::addColumn("locale"); + QTest::addColumn("format"); + + QTest::newRow("en_US 1") << "en_US" << "dddd, MMMM d, yyyy h:mm:ss AP"; + QTest::newRow("en_US long") << "en_US" << QLocale("en_US").dateTimeFormat(); + QTest::newRow("en_US short") << "en_US" << QLocale("en_US").dateTimeFormat(QLocale::ShortFormat); + QTest::newRow("de_DE long") << "de_DE" << QLocale("de_DE").dateTimeFormat(); + QTest::newRow("de_DE short") << "de_DE" << QLocale("de_DE").dateTimeFormat(QLocale::ShortFormat); + QTest::newRow("ar_SA long") << "ar_SA" << QLocale("ar_SA").dateTimeFormat(); + QTest::newRow("ar_SA short") << "ar_SA" << QLocale("ar_SA").dateTimeFormat(QLocale::ShortFormat); + QTest::newRow("zh_CN long") << "zh_CN" << QLocale("zh_CN").dateTimeFormat(); + QTest::newRow("zh_CN short") << "zh_CN" << QLocale("zh_CN").dateTimeFormat(QLocale::ShortFormat); +} + +void tst_qdeclarativelocale::dateFromLocaleDateString() +{ + QFETCH(QString, locale); + QFETCH(QString, format); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("date.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QDateTime dt; + dt.setDate(QDate(2011, 10, 7)); + dt.setTime(QTime(18, 53, 48, 345)); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QLocale l(locale); + QVariant val; + QMetaObject::invokeMethod(obj, "fromLocaleDateString", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(l.toString(dt, format))), + Q_ARG(QVariant, QVariant(format))); + + QDate pd = l.toDate(l.toString(dt, format), format); + QCOMPARE(val.toDate(), pd); +} + +void tst_qdeclarativelocale::dateFromLocaleTimeString_data() +{ + QTest::addColumn("locale"); + QTest::addColumn("format"); + + QTest::newRow("en_US 1") << "en_US" << "dddd, MMMM d, yyyy h:mm:ss AP"; + QTest::newRow("en_US long") << "en_US" << QLocale("en_US").dateTimeFormat(); + QTest::newRow("en_US short") << "en_US" << QLocale("en_US").dateTimeFormat(QLocale::ShortFormat); + QTest::newRow("de_DE long") << "de_DE" << QLocale("de_DE").dateTimeFormat(); + QTest::newRow("de_DE short") << "de_DE" << QLocale("de_DE").dateTimeFormat(QLocale::ShortFormat); + QTest::newRow("ar_SA long") << "ar_SA" << QLocale("ar_SA").dateTimeFormat(); + QTest::newRow("ar_SA short") << "ar_SA" << QLocale("ar_SA").dateTimeFormat(QLocale::ShortFormat); + QTest::newRow("zh_CN long") << "zh_CN" << QLocale("zh_CN").dateTimeFormat(); + QTest::newRow("zh_CN short") << "zh_CN" << QLocale("zh_CN").dateTimeFormat(QLocale::ShortFormat); +} + +void tst_qdeclarativelocale::dateFromLocaleTimeString() +{ + QFETCH(QString, locale); + QFETCH(QString, format); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("date.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QDateTime dt; + dt.setDate(QDate(2011, 10, 7)); + dt.setTime(QTime(18, 53, 48, 345)); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QLocale l(locale); + QVariant val; + QMetaObject::invokeMethod(obj, "fromLocaleTimeString", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(l.toString(dt, format))), + Q_ARG(QVariant, QVariant(format))); + + QTime pd = l.toTime(l.toString(dt, format), format); + QCOMPARE(val.toTime(), pd); +} + +void tst_qdeclarativelocale::numberToLocaleString_data() +{ + QTest::addColumn("locale"); + QTest::addColumn("format"); + QTest::addColumn("prec"); + + QTest::newRow("en_US 1") << "en_US" << 'f' << 2; + QTest::newRow("en_US 2") << "en_US" << 'g' << 3; + QTest::newRow("en_US 3") << "en_US" << 'f' << 0; + QTest::newRow("en_US 4") << "en_US" << 'f' << -1; + QTest::newRow("de_DE 1") << "de_DE" << 'f' << 2; + QTest::newRow("de_DE 2") << "de_DE" << 'g' << 3; + QTest::newRow("ar_SA 1") << "ar_SA" << 'f' << 2; + QTest::newRow("ar_SA 2") << "ar_SA" << 'g' << 3; +} + +void tst_qdeclarativelocale::numberToLocaleString() +{ + QFETCH(QString, locale); + QFETCH(char, format); + QFETCH(int, prec); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("number.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + double number = 2344423.3289; + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QLocale l(locale); + QVariant val; + QMetaObject::invokeMethod(obj, "toLocaleString", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(number)), + Q_ARG(QVariant, QVariant(QString(format))), + Q_ARG(QVariant, QVariant(prec))); + + if (prec < 0) prec = 2; + QCOMPARE(val.toString(), l.toString(number, format, prec)); +} + +void tst_qdeclarativelocale::numberToLocaleCurrencyString_data() +{ + QTest::addColumn("locale"); + QTest::addColumn("symbol"); + + QTest::newRow("en_US 1") << "en_US" << QString(); + QTest::newRow("en_US 2") << "en_US" << "USD"; + QTest::newRow("de_DE") << "de_DE" << QString(); + QTest::newRow("ar_SA") << "ar_SA" << QString(); + QTest::newRow("hi_IN") << "hi_IN" << QString(); + QTest::newRow("zh_CN") << "zh_CN" << QString(); + QTest::newRow("th_TH") << "th_TH" << QString(); +} + +void tst_qdeclarativelocale::numberToLocaleCurrencyString() +{ + QFETCH(QString, locale); + QFETCH(QString, symbol); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("number.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + double number = 2344423.3289; + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QLocale l(locale); + QVariant val; + QMetaObject::invokeMethod(obj, "toLocaleCurrencyString", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(number)), + Q_ARG(QVariant, QVariant(symbol))); + + QCOMPARE(val.toString(), l.toCurrencyString(number, symbol)); +} + +void tst_qdeclarativelocale::numberFromLocaleString_data() +{ + QTest::addColumn("locale"); + QTest::addColumn("number"); + + QTest::newRow("en_US 1") << "en_US" << 1234567.2345; + QTest::newRow("en_US 2") << "en_US" << 0.234; + QTest::newRow("en_US 3") << "en_US" << 234.0; + QTest::newRow("de_DE") << "de_DE" << 1234567.2345; + QTest::newRow("ar_SA") << "ar_SA" << 1234567.2345; + QTest::newRow("hi_IN") << "hi_IN" << 1234567.2345; + QTest::newRow("zh_CN") << "zh_CN" << 1234567.2345; + QTest::newRow("th_TH") << "th_TH" << 1234567.2345; +} + +void tst_qdeclarativelocale::numberFromLocaleString() +{ + QFETCH(QString, locale); + QFETCH(double, number); + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("number.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QLocale l(locale); + QString strNumber = l.toString(number, 'f'); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant(locale))); + + QVariant val; + QMetaObject::invokeMethod(obj, "fromLocaleString", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, val), + Q_ARG(QVariant, QVariant(strNumber))); + + QCOMPARE(val.toDouble(), l.toDouble(strNumber)); +} + +void tst_qdeclarativelocale::numberConstToLocaleString() +{ + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("number.qml"))); + + QObject *obj = c.create(); + QVERIFY(obj); + + QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection, + Q_ARG(QVariant, QVariant("en_US"))); + + QLocale l("en_US"); + QCOMPARE(obj->property("const1").toString(), l.toString(1234.56, 'f', 2)); + QCOMPARE(obj->property("const2").toString(), l.toString(1234., 'f', 2)); +} + +QTEST_MAIN(tst_qdeclarativelocale) + +#include "tst_qdeclarativelocale.moc" -- cgit v1.2.3