Implement strict mode for qmldir modules
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmllocale.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqmllocale_p.h"
43 #include "qqmlengine_p.h"
44 #include <private/qqmlcontext_p.h>
45 #include <private/qjsconverter_impl_p.h>
46 #include <QtCore/qnumeric.h>
47 #include <QtCore/qdatetime.h>
48
49 #include <private/qlocale_p.h>
50 #include <private/qlocale_data_p.h>
51
52 QT_BEGIN_NAMESPACE
53
54 class QV8LocaleDataResource : public QV8ObjectResource
55 {
56     V8_RESOURCE_TYPE(LocaleDataType)
57 public:
58     QV8LocaleDataResource(QV8Engine *e) : QV8ObjectResource(e) {}
59     QLocale locale;
60 };
61
62 #define GET_LOCALE_DATA_RESOURCE(OBJECT) \
63 QV8LocaleDataResource *r = v8_resource_cast<QV8LocaleDataResource>(OBJECT); \
64 if (!r) \
65     V8THROW_ERROR("Not a valid Locale object")
66
67 static bool isLocaleObject(v8::Handle<v8::Value> val)
68 {
69     if (!val->IsObject())
70         return false;
71
72     v8::Handle<v8::Object> localeObj = val->ToObject();
73     return localeObj->Has(v8::String::New("nativeLanguageName")); //XXX detect locale object properly
74 }
75
76 //--------------
77 // Date extension
78
79 static const char *dateToLocaleStringFunction =
80         "(function(toLocaleStringFunc) { "
81         "  var orig_toLocaleString;"
82         "  orig_toLocaleString = Date.prototype.toLocaleString;"
83         "  Date.prototype.toLocaleString = (function() {"
84         "    var val = toLocaleStringFunc.apply(this, arguments);"
85         "    if (val == undefined) val = orig_toLocaleString.call(this);"
86         "    return val;"
87         "  })"
88         "})";
89
90 static const char *dateToLocaleTimeStringFunction =
91         "(function(toLocaleTimeStringFunc) { "
92         "  var orig_toLocaleTimeString;"
93         "  orig_toLocaleTimeString = Date.prototype.toLocaleTimeString;"
94         "  Date.prototype.toLocaleTimeString = (function() {"
95         "    var val = toLocaleTimeStringFunc.apply(this, arguments);"
96         "    if (val == undefined) val = orig_toLocaleTimeString.call(this);"
97         "    return val;"
98         "  })"
99         "})";
100
101 static const char *dateToLocaleDateStringFunction =
102         "(function(toLocaleDateStringFunc) { "
103         "  var orig_toLocaleDateString;"
104         "  orig_toLocaleDateString = Date.prototype.toLocaleDateString;"
105         "  Date.prototype.toLocaleDateString = (function() {"
106         "    var val = toLocaleDateStringFunc.apply(this, arguments);"
107         "    if (val == undefined) val = orig_toLocaleDateString.call(this);"
108         "    return val;"
109         "  })"
110         "})";
111
112
113 static const char *dateFromLocaleStringFunction =
114         "(function(fromLocaleStringFunc) { "
115         "  Date.fromLocaleString = (function() {"
116         "    return fromLocaleStringFunc.apply(null, arguments);"
117         "  })"
118         "})";
119
120 static const char *dateFromLocaleTimeStringFunction =
121         "(function(fromLocaleTimeStringFunc) { "
122         "  Date.fromLocaleTimeString = (function() {"
123         "    return fromLocaleTimeStringFunc.apply(null, arguments);"
124         "  })"
125         "})";
126
127 static const char *dateFromLocaleDateStringFunction =
128         "(function(fromLocaleDateStringFunc) { "
129         "  Date.fromLocaleDateString = (function() {"
130         "    return fromLocaleDateStringFunc.apply(null, arguments);"
131         "  })"
132         "})";
133
134 static const char *dateTimeZoneUpdatedFunction =
135         "(function(timeZoneUpdatedFunc) { "
136         "  Date.timeZoneUpdated = (function() {"
137         "    return timeZoneUpdatedFunc.apply(null, arguments);"
138         "  })"
139         "})";
140
141
142 static void registerFunction(QV8Engine *engine, const char *script, v8::InvocationCallback func)
143 {
144     v8::Local<v8::Script> registerScript = v8::Script::New(v8::String::New(script), 0, 0, v8::Handle<v8::String>(), v8::Script::NativeMode);
145     v8::Local<v8::Value> result = registerScript->Run();
146     Q_ASSERT(result->IsFunction());
147     v8::Local<v8::Function> registerFunc = v8::Local<v8::Function>::Cast(result);
148     v8::Handle<v8::Value> args = V8FUNCTION(func, engine);
149     registerFunc->Call(v8::Local<v8::Object>::Cast(registerFunc), 1, &args);
150 }
151
152 void QQmlDateExtension::registerExtension(QV8Engine *engine)
153 {
154     registerFunction(engine, dateToLocaleStringFunction, toLocaleString);
155     registerFunction(engine, dateToLocaleTimeStringFunction, toLocaleTimeString);
156     registerFunction(engine, dateToLocaleDateStringFunction, toLocaleDateString);
157     registerFunction(engine, dateFromLocaleStringFunction, fromLocaleString);
158     registerFunction(engine, dateFromLocaleTimeStringFunction, fromLocaleTimeString);
159     registerFunction(engine, dateFromLocaleDateStringFunction, fromLocaleDateString);
160     registerFunction(engine, dateTimeZoneUpdatedFunction, timeZoneUpdated);
161 }
162
163 v8::Handle<v8::Value> QQmlDateExtension::toLocaleString(const v8::Arguments& args)
164 {
165     if (args.Length() > 2)
166         return v8::Undefined();
167
168     if (!args.This()->IsDate())
169         return v8::Undefined();
170
171     QDateTime dt = QV8Engine::qtDateTimeFromJsDate(v8::Handle<v8::Date>::Cast(args.This())->NumberValue());
172
173     if (args.Length() == 0) {
174         // Use QLocale for standard toLocaleString() function
175         QLocale locale;
176         return QJSConverter::toString(locale.toString(dt));
177     }
178
179     if (!isLocaleObject(args[0]))
180         return v8::Undefined(); // Use the default Date toLocaleString()
181
182     GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
183
184     QLocale::FormatType enumFormat = QLocale::LongFormat;
185     QString formattedDt;
186     if (args.Length() == 2) {
187         if (args[1]->IsString()) {
188             QString format = r->engine->toVariant(args[1], -1).toString();
189             formattedDt = r->locale.toString(dt, format);
190         } else if (args[1]->IsNumber()) {
191             quint32 intFormat = args[1]->ToNumber()->Value();
192             QLocale::FormatType format = QLocale::FormatType(intFormat);
193             formattedDt = r->locale.toString(dt, format);
194         } else {
195             V8THROW_ERROR("Locale: Date.toLocaleString(): Invalid datetime format");
196         }
197     } else {
198          formattedDt = r->locale.toString(dt, enumFormat);
199     }
200
201     return r->engine->toString(formattedDt);
202 }
203
204 v8::Handle<v8::Value> QQmlDateExtension::toLocaleTimeString(const v8::Arguments& args)
205 {
206     if (args.Length() > 2)
207         return v8::Undefined();
208
209     if (!args.This()->IsDate())
210         return v8::Undefined();
211
212     QDateTime dt = QV8Engine::qtDateTimeFromJsDate(v8::Handle<v8::Date>::Cast(args.This())->NumberValue());
213     QTime time = dt.time();
214
215     if (args.Length() == 0) {
216         // Use QLocale for standard toLocaleString() function
217         QLocale locale;
218         return QJSConverter::toString(locale.toString(time));
219     }
220
221     if (!isLocaleObject(args[0]))
222         return v8::Undefined(); // Use the default Date toLocaleTimeString()
223
224     GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
225
226     QLocale::FormatType enumFormat = QLocale::LongFormat;
227     QString formattedTime;
228     if (args.Length() == 2) {
229         if (args[1]->IsString()) {
230             QString format = r->engine->toVariant(args[1], -1).toString();
231             formattedTime = r->locale.toString(time, format);
232         } else if (args[1]->IsNumber()) {
233             quint32 intFormat = args[1]->ToNumber()->Value();
234             QLocale::FormatType format = QLocale::FormatType(intFormat);
235             formattedTime = r->locale.toString(time, format);
236         } else {
237             V8THROW_ERROR("Locale: Date.toLocaleTimeString(): Invalid time format");
238         }
239     } else {
240          formattedTime = r->locale.toString(time, enumFormat);
241     }
242
243     return r->engine->toString(formattedTime);
244 }
245
246 v8::Handle<v8::Value> QQmlDateExtension::toLocaleDateString(const v8::Arguments& args)
247 {
248     if (args.Length() > 2)
249         return v8::Undefined();
250
251     if (!args.This()->IsDate())
252         return v8::Undefined();
253
254     QDateTime dt = QV8Engine::qtDateTimeFromJsDate(v8::Handle<v8::Date>::Cast(args.This())->NumberValue());
255     QDate date = dt.date();
256
257     if (args.Length() == 0) {
258         // Use QLocale for standard toLocaleString() function
259         QLocale locale;
260         return QJSConverter::toString(locale.toString(date));
261     }
262
263     if (!isLocaleObject(args[0]))
264         return v8::Undefined(); // Use the default Date toLocaleDateString()
265
266     GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
267
268     QLocale::FormatType enumFormat = QLocale::LongFormat;
269     QString formattedDate;
270     if (args.Length() == 2) {
271         if (args[1]->IsString()) {
272             QString format = r->engine->toVariant(args[1], -1).toString();
273             formattedDate = r->locale.toString(date, format);
274         } else if (args[1]->IsNumber()) {
275             quint32 intFormat = args[1]->ToNumber()->Value();
276             QLocale::FormatType format = QLocale::FormatType(intFormat);
277             formattedDate = r->locale.toString(date, format);
278         } else {
279             V8THROW_ERROR("Locale: Date.loLocaleDateString(): Invalid date format");
280         }
281     } else {
282          formattedDate = r->locale.toString(date, enumFormat);
283     }
284
285     return r->engine->toString(formattedDate);
286 }
287
288 v8::Handle<v8::Value> QQmlDateExtension::fromLocaleString(const v8::Arguments& args)
289 {
290     if (args.Length() == 1 && args[0]->IsString()) {
291         QLocale locale;
292         QString dateString = QJSConverter::toString(args[0]->ToString());
293         QDateTime dt = locale.toDateTime(dateString);
294         return QJSConverter::toDateTime(dt);
295     }
296
297     if (args.Length() < 1 || args.Length() > 3 || !isLocaleObject(args[0]))
298         V8THROW_ERROR("Locale: Date.fromLocaleString(): Invalid arguments");
299
300     GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
301
302     QLocale::FormatType enumFormat = QLocale::LongFormat;
303     QDateTime dt;
304     QString dateString = r->engine->toString(args[1]->ToString());
305     if (args.Length() == 3) {
306         if (args[2]->IsString()) {
307             QString format = r->engine->toString(args[2]->ToString());
308             dt = r->locale.toDateTime(dateString, format);
309         } else if (args[2]->IsNumber()) {
310             quint32 intFormat = args[2]->ToNumber()->Value();
311             QLocale::FormatType format = QLocale::FormatType(intFormat);
312             dt = r->locale.toDateTime(dateString, format);
313         } else {
314             V8THROW_ERROR("Locale: Date.fromLocaleString(): Invalid datetime format");
315         }
316     } else {
317         dt = r->locale.toDateTime(dateString, enumFormat);
318     }
319
320     return QJSConverter::toDateTime(dt);
321 }
322
323 v8::Handle<v8::Value> QQmlDateExtension::fromLocaleTimeString(const v8::Arguments& args)
324 {
325     if (args.Length() == 1 && args[0]->IsString()) {
326         QLocale locale;
327         QString timeString = QJSConverter::toString(args[0]->ToString());
328         QTime time = locale.toTime(timeString);
329         QDateTime dt = QDateTime::currentDateTime();
330         dt.setTime(time);
331         return QJSConverter::toDateTime(dt);
332     }
333
334     if (args.Length() < 1 || args.Length() > 3 || !isLocaleObject(args[0]))
335         V8THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid arguments");
336
337     GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
338
339     QLocale::FormatType enumFormat = QLocale::LongFormat;
340     QTime tm;
341     QString dateString = r->engine->toString(args[1]->ToString());
342     if (args.Length() == 3) {
343         if (args[2]->IsString()) {
344             QString format = r->engine->toString(args[2]->ToString());
345             tm = r->locale.toTime(dateString, format);
346         } else if (args[2]->IsNumber()) {
347             quint32 intFormat = args[2]->ToNumber()->Value();
348             QLocale::FormatType format = QLocale::FormatType(intFormat);
349             tm = r->locale.toTime(dateString, format);
350         } else {
351             V8THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid datetime format");
352         }
353     } else {
354         tm = r->locale.toTime(dateString, enumFormat);
355     }
356
357     QDateTime dt = QDateTime::currentDateTime();
358     dt.setTime(tm);
359
360     return QJSConverter::toDateTime(dt);
361 }
362
363 v8::Handle<v8::Value> QQmlDateExtension::fromLocaleDateString(const v8::Arguments& args)
364 {
365     if (args.Length() == 1 && args[0]->IsString()) {
366         QLocale locale;
367         QString dateString = QJSConverter::toString(args[0]->ToString());
368         QDate date = locale.toDate(dateString);
369         return QJSConverter::toDateTime(QDateTime(date));
370     }
371
372     if (args.Length() < 1 || args.Length() > 3 || !isLocaleObject(args[0]))
373         V8THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid arguments");
374
375     GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
376
377     QLocale::FormatType enumFormat = QLocale::LongFormat;
378     QDate dt;
379     QString dateString = r->engine->toString(args[1]->ToString());
380     if (args.Length() == 3) {
381         if (args[2]->IsString()) {
382             QString format = r->engine->toString(args[2]->ToString());
383             dt = r->locale.toDate(dateString, format);
384         } else if (args[2]->IsNumber()) {
385             quint32 intFormat = args[2]->ToNumber()->Value();
386             QLocale::FormatType format = QLocale::FormatType(intFormat);
387             dt = r->locale.toDate(dateString, format);
388         } else {
389             V8THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid datetime format");
390         }
391     } else {
392         dt = r->locale.toDate(dateString, enumFormat);
393     }
394
395     return QJSConverter::toDateTime(QDateTime(dt));
396 }
397
398 v8::Handle<v8::Value> QQmlDateExtension::timeZoneUpdated(const v8::Arguments& args)
399 {
400     if (args.Length() != 0)
401         V8THROW_ERROR("Locale: Date.timeZoneUpdated(): Invalid arguments");
402
403     v8::Date::DateTimeConfigurationChangeNotification();
404
405     return v8::Undefined();
406 }
407
408 //-----------------
409 // Number extension
410
411 static const char *numberToLocaleStringFunction =
412         "(function(toLocaleStringFunc) { "
413         "  var orig_toLocaleString;"
414         "  orig_toLocaleString = Number.prototype.toLocaleString;"
415         "  Number.prototype.toLocaleString = (function() {"
416         "    var val = toLocaleStringFunc.apply(this, arguments);"
417         "    if (val == undefined) val = orig_toLocaleString.call(this);"
418         "    return val;"
419         "  })"
420         "})";
421
422 static const char *numberToLocaleCurrencyStringFunction =
423         "(function(toLocaleCurrencyStringFunc) { "
424         "  Number.prototype.toLocaleCurrencyString = (function() {"
425         "    return toLocaleCurrencyStringFunc.apply(this, arguments);"
426         "  })"
427         "})";
428
429 static const char *numberFromLocaleStringFunction =
430         "(function(fromLocaleStringFunc) { "
431         "  Number.fromLocaleString = (function() {"
432         "    return fromLocaleStringFunc.apply(null, arguments);"
433         "  })"
434         "})";
435
436
437 void QQmlNumberExtension::registerExtension(QV8Engine *engine)
438 {
439     registerFunction(engine, numberToLocaleStringFunction, toLocaleString);
440     registerFunction(engine, numberToLocaleCurrencyStringFunction, toLocaleCurrencyString);
441     registerFunction(engine, numberFromLocaleStringFunction, fromLocaleString);
442 }
443
444 v8::Handle<v8::Value> QQmlNumberExtension::toLocaleString(const v8::Arguments& args)
445 {
446     if (args.Length() > 3)
447         V8THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
448
449     double number = args.This()->ToNumber()->Value();
450
451     if (args.Length() == 0) {
452         // Use QLocale for standard toLocaleString() function
453         QLocale locale;
454         return QJSConverter::toString(locale.toString(number));
455     }
456
457     if (!isLocaleObject(args[0]))
458         return v8::Undefined(); // Use the default Number toLocaleString()
459
460     GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
461
462     uint16_t format = 'f';
463     if (args.Length() > 1) {
464         if (!args[1]->IsString())
465             V8THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
466         v8::Local<v8::String> fs = args[1]->ToString();
467         if (!fs.IsEmpty() && fs->Length())
468             format = fs->GetCharacter(0);
469     }
470     int prec = 2;
471     if (args.Length() > 2) {
472         if (!args[2]->IsNumber())
473             V8THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
474          prec = args[2]->IntegerValue();
475     }
476
477     return r->engine->toString(r->locale.toString(number, (char)format, prec));
478 }
479
480 v8::Handle<v8::Value> QQmlNumberExtension::toLocaleCurrencyString(const v8::Arguments& args)
481 {
482     if (args.Length() > 2)
483         V8THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
484
485     double number = args.This()->ToNumber()->Value();
486
487     if (args.Length() == 0) {
488         // Use QLocale for standard toLocaleString() function
489         QLocale locale;
490         return QJSConverter::toString(locale.toString(number));
491     }
492
493     if (!isLocaleObject(args[0]))
494         V8THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
495
496     GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
497
498     QString symbol;
499     if (args.Length() > 1) {
500         if (!args[1]->IsString())
501             V8THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
502         symbol = r->engine->toString(args[1]->ToString());
503     }
504
505     return r->engine->toString(r->locale.toCurrencyString(number, symbol));
506 }
507
508 v8::Handle<v8::Value> QQmlNumberExtension::fromLocaleString(const v8::Arguments& args)
509 {
510     if (args.Length() < 1 || args.Length() > 2)
511         V8THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
512
513     int numberIdx = 0;
514     QLocale locale;
515
516     if (args.Length() == 2) {
517         if (!isLocaleObject(args[0]))
518             V8THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
519
520         GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
521         locale = r->locale;
522
523         numberIdx = 1;
524     }
525
526     v8::Local<v8::String> ns = args[numberIdx]->ToString();
527     if (ns.IsEmpty() || ns->Length() == 0)
528         return v8::Number::New(Q_QNAN);
529
530     bool ok = false;
531     double val = locale.toDouble(QJSConverter::toString(ns), &ok);
532
533     if (!ok)
534         V8THROW_ERROR("Locale: Number.fromLocaleString(): Invalid format")
535
536     return v8::Number::New(val);
537 }
538
539 //--------------
540 // Locale object
541
542 static v8::Handle<v8::Value> locale_get_firstDayOfWeek(v8::Local<v8::String>, const v8::AccessorInfo &info)
543 {
544     GET_LOCALE_DATA_RESOURCE(info.This());
545     int fdow = int(r->locale.firstDayOfWeek());
546     if (fdow == 7)
547         fdow = 0; // Qt::Sunday = 7, but Sunday is 0 in JS Date
548     return v8::Integer::New(fdow);
549 }
550
551 static v8::Handle<v8::Value> locale_get_measurementSystem(v8::Local<v8::String>, const v8::AccessorInfo &info)
552 {
553     GET_LOCALE_DATA_RESOURCE(info.This());
554     return v8::Integer::New(r->locale.measurementSystem());
555 }
556
557 static v8::Handle<v8::Value> locale_get_textDirection(v8::Local<v8::String>, const v8::AccessorInfo &info)
558 {
559     GET_LOCALE_DATA_RESOURCE(info.This());
560     return v8::Integer::New(r->locale.textDirection());
561 }
562
563 static v8::Handle<v8::Value> locale_get_weekDays(v8::Local<v8::String>, const v8::AccessorInfo &info)
564 {
565     GET_LOCALE_DATA_RESOURCE(info.This());
566
567     QList<Qt::DayOfWeek> days = r->locale.weekdays();
568
569     v8::Handle<v8::Array> result = v8::Array::New(days.size());
570     for (int i = 0; i < days.size(); ++i) {
571         int day = days.at(i);
572         if (day == 7) // JS Date days in range 0(Sunday) to 6(Saturday)
573             day = 0;
574         result->Set(i, v8::Integer::New(day));
575     }
576
577     return result;
578 }
579
580 static v8::Handle<v8::Value> locale_get_uiLanguages(v8::Local<v8::String>, const v8::AccessorInfo &info)
581 {
582     GET_LOCALE_DATA_RESOURCE(info.This());
583
584     QStringList langs = r->locale.uiLanguages();
585     v8::Handle<v8::Array> result = v8::Array::New(langs.size());
586     for (int i = 0; i < langs.size(); ++i) {
587         result->Set(i, r->engine->toString(langs.at(i)));
588     }
589
590     return result;
591 }
592
593 static v8::Handle<v8::Value> locale_currencySymbol(const v8::Arguments &args)
594 {
595     GET_LOCALE_DATA_RESOURCE(args.This());
596
597     if (args.Length() > 1)
598         V8THROW_ERROR("Locale: currencySymbol(): Invalid arguments");
599
600     QLocale::CurrencySymbolFormat format = QLocale::CurrencySymbol;
601     if (args.Length() == 1) {
602         quint32 intFormat = args[0]->ToNumber()->Value();
603         format = QLocale::CurrencySymbolFormat(intFormat);
604     }
605
606     return r->engine->toString(r->locale.currencySymbol(format));
607 }
608
609 #define LOCALE_FORMAT(FUNC) \
610 static v8::Handle<v8::Value> locale_ ##FUNC (const v8::Arguments &args) { \
611     GET_LOCALE_DATA_RESOURCE(args.This());\
612     if (args.Length() > 1) \
613         V8THROW_ERROR("Locale: " #FUNC "(): Invalid arguments"); \
614     QLocale::FormatType format = QLocale::LongFormat;\
615     if (args.Length() == 1) { \
616         quint32 intFormat = args[0]->Uint32Value(); \
617         format = QLocale::FormatType(intFormat); \
618     } \
619     return r->engine->toString(r->locale. FUNC (format)); \
620 }
621
622 LOCALE_FORMAT(dateTimeFormat)
623 LOCALE_FORMAT(timeFormat)
624 LOCALE_FORMAT(dateFormat)
625
626 // +1 added to idx because JS is 0-based, whereas QLocale months begin at 1.
627 #define LOCALE_FORMATTED_MONTHNAME(VARIABLE) \
628 static v8::Handle<v8::Value> locale_ ## VARIABLE (const v8::Arguments &args) {\
629     GET_LOCALE_DATA_RESOURCE(args.This()); \
630     if (args.Length() < 1 || args.Length() > 2) \
631         V8THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
632     QLocale::FormatType enumFormat = QLocale::LongFormat; \
633     int idx = args[0]->IntegerValue() + 1; \
634     if (idx < 1 || idx > 12) \
635         V8THROW_ERROR("Locale: Invalid month"); \
636     QString name; \
637     if (args.Length() == 2) { \
638         if (args[1]->IsNumber()) { \
639             quint32 intFormat = args[1]->IntegerValue(); \
640             QLocale::FormatType format = QLocale::FormatType(intFormat); \
641             name = r->locale. VARIABLE(idx, format); \
642         } else { \
643             V8THROW_ERROR("Locale: Invalid datetime format"); \
644         } \
645     } else { \
646         name = r->locale. VARIABLE(idx, enumFormat); \
647     } \
648     return r->engine->toString(name); \
649 }
650
651 // 0 -> 7 as Qt::Sunday is 7, but Sunday is 0 in JS Date
652 #define LOCALE_FORMATTED_DAYNAME(VARIABLE) \
653 static v8::Handle<v8::Value> locale_ ## VARIABLE (const v8::Arguments &args) {\
654     GET_LOCALE_DATA_RESOURCE(args.This()); \
655     if (args.Length() < 1 || args.Length() > 2) \
656         V8THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
657     QLocale::FormatType enumFormat = QLocale::LongFormat; \
658     int idx = args[0]->IntegerValue(); \
659     if (idx < 0 || idx > 7) \
660         V8THROW_ERROR("Locale: Invalid day"); \
661     if (idx == 0) idx = 7; \
662     QString name; \
663     if (args.Length() == 2) { \
664         if (args[1]->IsNumber()) { \
665             quint32 intFormat = args[1]->ToNumber()->Value(); \
666             QLocale::FormatType format = QLocale::FormatType(intFormat); \
667             name = r->locale. VARIABLE(idx, format); \
668         } else { \
669             V8THROW_ERROR("Locale: Invalid datetime format"); \
670         } \
671     } else { \
672         name = r->locale. VARIABLE(idx, enumFormat); \
673     } \
674     return r->engine->toString(name); \
675 }
676
677
678 #define LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(FT, VARIABLE, ENGINE) \
679     FT->PrototypeTemplate()->Set(v8::String::New( #VARIABLE ), V8FUNCTION(locale_ ## VARIABLE, ENGINE));
680
681 LOCALE_FORMATTED_MONTHNAME(monthName)
682 LOCALE_FORMATTED_MONTHNAME(standaloneMonthName)
683 LOCALE_FORMATTED_DAYNAME(dayName)
684 LOCALE_FORMATTED_DAYNAME(standaloneDayName)
685
686 #define LOCALE_STRING_PROPERTY(VARIABLE) static v8::Handle<v8::Value> locale_get_ ## VARIABLE (v8::Local<v8::String>, const v8::AccessorInfo &info) \
687 { \
688     GET_LOCALE_DATA_RESOURCE(info.This()); \
689     return r->engine->toString(r->locale. VARIABLE());\
690 }
691
692 #define LOCALE_REGISTER_STRING_ACCESSOR(FT, VARIABLE) \
693     FT ->PrototypeTemplate()->SetAccessor( v8::String::New( #VARIABLE ), locale_get_ ## VARIABLE )
694
695
696 LOCALE_STRING_PROPERTY(name)
697 LOCALE_STRING_PROPERTY(nativeLanguageName)
698 LOCALE_STRING_PROPERTY(nativeCountryName)
699 LOCALE_STRING_PROPERTY(decimalPoint)
700 LOCALE_STRING_PROPERTY(groupSeparator)
701 LOCALE_STRING_PROPERTY(percent)
702 LOCALE_STRING_PROPERTY(zeroDigit)
703 LOCALE_STRING_PROPERTY(negativeSign)
704 LOCALE_STRING_PROPERTY(positiveSign)
705 LOCALE_STRING_PROPERTY(exponential)
706 LOCALE_STRING_PROPERTY(amText)
707 LOCALE_STRING_PROPERTY(pmText)
708
709 class QV8LocaleDataDeletable : public QV8Engine::Deletable
710 {
711 public:
712     QV8LocaleDataDeletable(QV8Engine *engine);
713     ~QV8LocaleDataDeletable();
714
715     v8::Persistent<v8::Function> constructor;
716 };
717
718 QV8LocaleDataDeletable::QV8LocaleDataDeletable(QV8Engine *engine)
719 {
720     v8::HandleScope handle_scope;
721     v8::Context::Scope scope(engine->context());
722
723     v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
724     ft->InstanceTemplate()->SetHasExternalResource(true);
725
726     LOCALE_REGISTER_STRING_ACCESSOR(ft, name);
727     LOCALE_REGISTER_STRING_ACCESSOR(ft, nativeLanguageName);
728     LOCALE_REGISTER_STRING_ACCESSOR(ft, nativeCountryName);
729     LOCALE_REGISTER_STRING_ACCESSOR(ft, decimalPoint);
730     LOCALE_REGISTER_STRING_ACCESSOR(ft, groupSeparator);
731     LOCALE_REGISTER_STRING_ACCESSOR(ft, percent);
732     LOCALE_REGISTER_STRING_ACCESSOR(ft, zeroDigit);
733     LOCALE_REGISTER_STRING_ACCESSOR(ft, negativeSign);
734     LOCALE_REGISTER_STRING_ACCESSOR(ft, positiveSign);
735     LOCALE_REGISTER_STRING_ACCESSOR(ft, exponential);
736     LOCALE_REGISTER_STRING_ACCESSOR(ft, amText);
737     LOCALE_REGISTER_STRING_ACCESSOR(ft, pmText);
738
739     ft->PrototypeTemplate()->Set(v8::String::New("currencySymbol"), V8FUNCTION(locale_currencySymbol, engine));
740
741     ft->PrototypeTemplate()->Set(v8::String::New("dateTimeFormat"), V8FUNCTION(locale_dateTimeFormat, engine));
742     ft->PrototypeTemplate()->Set(v8::String::New("dateFormat"), V8FUNCTION(locale_dateFormat, engine));
743     ft->PrototypeTemplate()->Set(v8::String::New("timeFormat"), V8FUNCTION(locale_timeFormat, engine));
744
745     LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(ft, monthName, engine);
746     LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(ft, standaloneMonthName, engine);
747     LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(ft, dayName, engine);
748     LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(ft, standaloneDayName, engine);
749
750     ft->PrototypeTemplate()->SetAccessor(v8::String::New("firstDayOfWeek"), locale_get_firstDayOfWeek);
751     ft->PrototypeTemplate()->SetAccessor(v8::String::New("weekDays"), locale_get_weekDays);
752     ft->PrototypeTemplate()->SetAccessor(v8::String::New("measurementSystem"), locale_get_measurementSystem);
753     ft->PrototypeTemplate()->SetAccessor(v8::String::New("textDirection"), locale_get_textDirection);
754     ft->PrototypeTemplate()->SetAccessor(v8::String::New("uiLanguages"), locale_get_uiLanguages);
755
756     constructor = qPersistentNew(ft->GetFunction());
757 }
758
759 QV8LocaleDataDeletable::~QV8LocaleDataDeletable()
760 {
761     qPersistentDispose(constructor);
762 }
763
764 V8_DEFINE_EXTENSION(QV8LocaleDataDeletable, localeV8Data);
765
766 /*!
767     \qmltype Locale
768     \instantiates QQmlLocale
769     \inqmlmodule QtQuick 2
770     \brief Provides locale specific properties and formatted data
771
772     The Locale object may only be created via the \l{QML:Qt::locale()}{Qt.locale()} function.
773     It cannot be created directly.
774
775     The \l{QML:Qt::locale()}{Qt.locale()} function returns a JS Locale object representing the
776     locale with the specified name, which has the format
777     "language[_territory][.codeset][@modifier]" or "C".
778
779     Locale supports the concept of a default locale, which is
780     determined from the system's locale settings at application
781     startup.  If no parameter is passed to Qt.locale() the default
782     locale object is returned.
783
784     The Locale object provides a number of functions and properties
785     providing data for the specified locale.
786
787     The Locale object may also be passed to the \l Date and \l Number toLocaleString()
788     and fromLocaleString() methods in order to convert to/from strings using
789     the specified locale.
790
791     This example shows the current date formatted for the German locale:
792
793     \code
794     import QtQuick 2.0
795
796     Text {
797         text: "The date is: " + Date().toLocaleString(Qt.locale("de_DE"))
798     }
799     \endcode
800
801     The following example displays the specified number
802     in the correct format for the default locale:
803
804     \code
805     import QtQuick 2.0
806
807     Text {
808         text: "The value is: " + Number(23443.34).toLocaleString(Qt.locale())
809     }
810     \endcode
811
812     QtQuick Locale's data is based on Common Locale Data Repository v1.8.1.
813
814     The double-to-string and string-to-double conversion functions are
815     covered by the following licenses:
816
817     \legalese
818     Copyright (c) 1991 by AT&T.
819
820     Permission to use, copy, modify, and distribute this software for any
821     purpose without fee is hereby granted, provided that this entire notice
822     is included in all copies of any software which is or includes a copy
823     or modification of this software and in all copies of the supporting
824     documentation for such software.
825
826     THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
827     WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR AT&T MAKES ANY
828     REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
829     OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
830
831     This product includes software developed by the University of
832     California, Berkeley and its contributors.
833
834     \sa {QtQuick2::Date}{Date}, {QtQuick2::Number}{Number}
835 */
836
837 QQmlLocale::QQmlLocale()
838 {
839 }
840
841 QQmlLocale::~QQmlLocale()
842 {
843 }
844
845 v8::Handle<v8::Value> QQmlLocale::locale(QV8Engine *v8engine, const QString &locale)
846 {
847     QV8LocaleDataDeletable *d = localeV8Data(v8engine);
848     v8::Local<v8::Object> v8Value = d->constructor->NewInstance();
849     QV8LocaleDataResource *r = new QV8LocaleDataResource(v8engine);
850     if (locale.isEmpty())
851         r->locale = QLocale();
852     else
853         r->locale = QLocale(locale);
854     v8Value->SetExternalResource(r);
855
856     return v8Value;
857 }
858
859 static const char *localeCompareFunction =
860     "(function(localeCompareFunc) { "
861     "  var orig_localeCompare;"
862     "  orig_localeCompare = String.prototype.localeCompare;"
863     "  String.prototype.localeCompare = (function() {"
864     "    var val = localeCompareFunc.apply(this, arguments);"
865     "    if (val == undefined) val = orig_localeCompare.call(this);"
866     "    return val;"
867     "  })"
868     "})";
869
870 void QQmlLocale::registerStringLocaleCompare(QV8Engine *engine)
871 {
872     registerFunction(engine, localeCompareFunction, localeCompare);
873 }
874
875 v8::Handle<v8::Value> QQmlLocale::localeCompare(const v8::Arguments &args)
876 {
877     if (args.Length() != 1 || (!args[0]->IsString() && !args[0]->IsStringObject()))
878         return v8::Undefined();
879
880     if (!args.This()->IsString() && !args.This()->IsStringObject())
881         return v8::Undefined();
882
883     QString thisString = QJSConverter::toString(args.This()->ToString());
884     QString thatString = QJSConverter::toString(args[0]->ToString());
885
886     return v8::Integer::New(QString::localeAwareCompare(thisString, thatString));
887 }
888
889 /*!
890     \enum QtQuick2::Locale::FormatType
891
892     This enumeration describes the types of format that can be used when
893     converting Date objects to strings.
894
895     \value LongFormat The long version of day and month names; for
896     example, returning "January" as a month name.
897
898     \value ShortFormat The short version of day and month names; for
899     example, returning "Jan" as a month name.
900
901     \value NarrowFormat A special version of day and month names for
902     use when space is limited; for example, returning "J" as a month
903     name. Note that the narrow format might contain the same text for
904     different months and days or it can even be an empty string if the
905     locale doesn't support narrow names, so you should avoid using it
906     for date formatting. Also, for the system locale this format is
907     the same as ShortFormat.
908 */
909
910 /*!
911     \qmlproperty string QtQuick2::Locale::name
912
913     Holds the language and country of this locale as a
914     string of the form "language_country", where
915     language is a lowercase, two-letter ISO 639 language code,
916     and country is an uppercase, two- or three-letter ISO 3166 country code.
917 */
918
919 /*!
920     \qmlproperty string QtQuick2::Locale::decimalPoint
921
922     Holds the decimal point character of this locale.
923 */
924
925 /*!
926     \qmlproperty string QtQuick2::Locale::groupSeparator
927
928     Holds the group separator character of this locale.
929 */
930
931 /*!
932     \qmlproperty string QtQuick2::Locale::percent
933
934     Holds the percent character of this locale.
935 */
936
937
938 /*!
939     \qmlproperty string QtQuick2::Locale::zeroDigit
940
941     Holds Returns the zero digit character of this locale.
942 */
943
944 /*!
945     \qmlproperty string QtQuick2::Locale::negativeSign
946
947     Holds the negative sign character of this locale.
948 */
949
950 /*!
951     \qmlproperty string QtQuick2::Locale::positiveSign
952
953     Holds the positive sign character of this locale.
954 */
955
956 /*!
957     \qmlproperty string QtQuick2::Locale::exponential
958
959     Holds the exponential character of this locale.
960 */
961
962 /*!
963     \qmlmethod string QtQuick2::Locale::dateTimeFormat(type)
964
965     Returns the date time format used for the current locale.
966     \a type specifies the FormatType to return.
967
968     \sa {QtQuick2::Date}{Date}
969 */
970
971 /*!
972     \qmlmethod string QtQuick2::Locale::dateFormat(type)
973
974     Returns the date format used for the current locale.
975     \a type specifies the FormatType to return.
976
977     \sa {QtQuick2::Date}{Date}
978 */
979
980 /*!
981     \qmlmethod string QtQuick2::Locale::timeFormat(type)
982
983     Returns the time format used for the current locale.
984     \a type specifies the FormatType to return.
985
986     \sa {QtQuick2::Date}{Date}
987 */
988
989 /*!
990     \qmlmethod string QtQuick2::Locale::monthName(month, type)
991
992     Returns the localized name of \a month (0-11), in the optional
993     \l FortmatType specified by \a type.
994
995     \note the QLocale C++ API expects a range of (1-12), however Locale.monthName()
996     expects 0-11 as per the JS Date object.
997
998     \sa dayName(), standaloneMonthName()
999 */
1000
1001 /*!
1002     \qmlmethod string QtQuick2::Locale::standaloneMonthName(month, type)
1003
1004     Returns the localized name of \a month (0-11) that is used as a
1005     standalone text, in the optional \l FormatType specified by \a type.
1006
1007     If the locale information doesn't specify the standalone month
1008     name then return value is the same as in monthName().
1009
1010     \note the QLocale C++ API expects a range of (1-12), however Locale.standaloneMonthName()
1011     expects 0-11 as per the JS Date object.
1012
1013     \sa monthName(), standaloneDayName()
1014 */
1015
1016 /*!
1017     \qmlmethod string QtQuick2::Locale::dayName(day, type)
1018
1019     Returns the localized name of the \a day (where 0 represents
1020     Sunday, 1 represents Monday and so on), in the optional
1021     \l FormatType specified by \a type.
1022
1023     \sa monthName(), standaloneDayName()
1024 */
1025
1026 /*!
1027     \qmlmethod string QtQuick2::Locale::standaloneDayName(day, type)
1028
1029     Returns the localized name of the \a day (where 0 represents
1030     Sunday, 1 represents Monday and so on) that is used as a
1031     standalone text, in the \l FormatType specified by \a type.
1032
1033     If the locale information does not specify the standalone day
1034     name then return value is the same as in dayName().
1035
1036     \sa dayName(), standaloneMonthName()
1037 */
1038
1039 /*!
1040     \qmlproperty enumeration QtQuick2::Locale::firstDayOfWeek
1041
1042     Holds the first day of the week according to the current locale.
1043
1044     \list
1045     \li Locale.Sunday = 0
1046     \li Locale.Monday = 1
1047     \li Locale.Tuesday = 2
1048     \li Locale.Wednesday = 3
1049     \li Locale.Thursday = 4
1050     \li Locale.Friday = 5
1051     \li Locale.Saturday = 6
1052     \endlist
1053
1054     \note that these values match the JS Date API which is different
1055     from the Qt C++ API where Qt::Sunday = 7.
1056 */
1057
1058 /*!
1059     \qmlproperty Array<int> QtQuick2::Locale::weekDays
1060
1061     Holds an array of days that are considered week days according to the current locale,
1062     where Sunday is 0 and Saturday is 6.
1063
1064     \sa firstDayOfWeek
1065 */
1066
1067 /*!
1068     \qmlproperty Array<string> QtQuick2::Locale::uiLanguages
1069
1070     Returns an ordered list of locale names for translation purposes in
1071     preference order.
1072
1073     The return value represents locale names that the user expects to see the
1074     UI translation in.
1075
1076     The first item in the list is the most preferred one.
1077 */
1078
1079 /*!
1080     \qmlproperty enumeration QtQuick2::Locale::textDirection
1081
1082     Holds the text direction of the language:
1083     \list
1084     \li Qt.LeftToRight
1085     \li Qt.RightToLeft
1086     \endlist
1087 */
1088
1089 /*!
1090     \qmlproperty string QtQuick2::Locale::amText
1091
1092     The localized name of the "AM" suffix for times specified using the conventions of the 12-hour clock.
1093 */
1094
1095 /*!
1096     \qmlproperty string QtQuick2::Locale::pmText
1097
1098     The localized name of the "PM" suffix for times specified using the conventions of the 12-hour clock.
1099 */
1100
1101 /*!
1102     \qmlmethod string QtQuick2::Locale::currencySymbol(format)
1103
1104     Returns the currency symbol for the specified \a format:
1105     \list
1106     \li Locale.CurrencyIsoCode a ISO-4217 code of the currency.
1107     \li Locale.CurrencySymbol a currency symbol.
1108     \li Locale.CurrencyDisplayName a user readable name of the currency.
1109     \endlist
1110     \sa Number::toLocaleCurrencyString()
1111 */
1112
1113 /*!
1114     \qmlproperty string QtQuick2::Locale::nativeLanguageName
1115
1116     Holds a native name of the language for the locale. For example
1117     "Schwiizertüütsch" for Swiss-German locale.
1118
1119     \sa nativeCountryName
1120 */
1121
1122 /*!
1123     \qmlproperty string QtQuick2::Locale::nativeCountryName
1124
1125     Holds a native name of the country for the locale. For example
1126     "España" for Spanish/Spain locale.
1127
1128     \sa nativeLanguageName
1129 */
1130
1131 /*!
1132     \qmlproperty enumeration QtQuick2::Locale::measurementSystem
1133
1134     This property defines which units are used for measurement.
1135
1136     \list
1137     \li Locale.MetricSystem This value indicates metric units, such as meters,
1138         centimeters and millimeters.
1139     \li Locale.ImperialSystem This value indicates imperial units, such as inches and
1140         miles. There are several distinct imperial systems in the world; this
1141         value stands for the official United States imperial units.
1142     \endlist
1143 */
1144
1145 QT_END_NAMESPACE