Improve documentation.
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmllocale.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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
815     \target FormatType
816     \section2 Locale String Format Types
817
818     The monthName(), standaloneMonthName(), dayName() and standaloneDayName()
819     can use the following enumeration values to specify the formatting of
820     the string representation for a Date object.
821
822     \list
823     \li Locale.LongFormat The long version of day and month names; for
824     example, returning "January" as a month name.
825     \li Locale.ShortFormat The short version of day and month names; for
826     example, returning "Jan" as a month name.
827     \li Locale.NarrowFormat A special version of day and month names for
828     use when space is limited; for example, returning "J" as a month
829     name. Note that the narrow format might contain the same text for
830     different months and days or it can even be an empty string if the
831     locale doesn't support narrow names, so you should avoid using it
832     for date formatting. Also, for the system locale this format is
833     the same as ShortFormat.
834     \endlist
835
836
837     Additionally the double-to-string and string-to-double conversion functions are
838     covered by the following licenses:
839
840     \legalese
841     Copyright (c) 1991 by AT&T.
842
843     Permission to use, copy, modify, and distribute this software for any
844     purpose without fee is hereby granted, provided that this entire notice
845     is included in all copies of any software which is or includes a copy
846     or modification of this software and in all copies of the supporting
847     documentation for such software.
848
849     THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
850     WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR AT&T MAKES ANY
851     REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
852     OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
853
854     This product includes software developed by the University of
855     California, Berkeley and its contributors.
856
857     \sa {QtQuick2::Date}{Date}, {QtQuick2::Number}{Number}
858 */
859
860 QQmlLocale::QQmlLocale()
861 {
862 }
863
864 QQmlLocale::~QQmlLocale()
865 {
866 }
867
868 v8::Handle<v8::Value> QQmlLocale::locale(QV8Engine *v8engine, const QString &locale)
869 {
870     QV8LocaleDataDeletable *d = localeV8Data(v8engine);
871     v8::Local<v8::Object> v8Value = d->constructor->NewInstance();
872     QV8LocaleDataResource *r = new QV8LocaleDataResource(v8engine);
873     if (locale.isEmpty())
874         r->locale = QLocale();
875     else
876         r->locale = QLocale(locale);
877     v8Value->SetExternalResource(r);
878
879     return v8Value;
880 }
881
882 static const char *localeCompareFunction =
883     "(function(localeCompareFunc) { "
884     "  var orig_localeCompare;"
885     "  orig_localeCompare = String.prototype.localeCompare;"
886     "  String.prototype.localeCompare = (function() {"
887     "    var val = localeCompareFunc.apply(this, arguments);"
888     "    if (val == undefined) val = orig_localeCompare.call(this);"
889     "    return val;"
890     "  })"
891     "})";
892
893 void QQmlLocale::registerStringLocaleCompare(QV8Engine *engine)
894 {
895     registerFunction(engine, localeCompareFunction, localeCompare);
896 }
897
898 v8::Handle<v8::Value> QQmlLocale::localeCompare(const v8::Arguments &args)
899 {
900     if (args.Length() != 1 || (!args[0]->IsString() && !args[0]->IsStringObject()))
901         return v8::Undefined();
902
903     if (!args.This()->IsString() && !args.This()->IsStringObject())
904         return v8::Undefined();
905
906     QString thisString = QJSConverter::toString(args.This()->ToString());
907     QString thatString = QJSConverter::toString(args[0]->ToString());
908
909     return v8::Integer::New(QString::localeAwareCompare(thisString, thatString));
910 }
911
912 /*!
913     \qmlproperty string QtQuick2::Locale::name
914
915     Holds the language and country of this locale as a
916     string of the form "language_country", where
917     language is a lowercase, two-letter ISO 639 language code,
918     and country is an uppercase, two- or three-letter ISO 3166 country code.
919 */
920
921 /*!
922     \qmlproperty string QtQuick2::Locale::decimalPoint
923
924     Holds the decimal point character of this locale.
925 */
926
927 /*!
928     \qmlproperty string QtQuick2::Locale::groupSeparator
929
930     Holds the group separator character of this locale.
931 */
932
933 /*!
934     \qmlproperty string QtQuick2::Locale::percent
935
936     Holds the percent character of this locale.
937 */
938
939
940 /*!
941     \qmlproperty string QtQuick2::Locale::zeroDigit
942
943     Holds Returns the zero digit character of this locale.
944 */
945
946 /*!
947     \qmlproperty string QtQuick2::Locale::negativeSign
948
949     Holds the negative sign character of this locale.
950 */
951
952 /*!
953     \qmlproperty string QtQuick2::Locale::positiveSign
954
955     Holds the positive sign character of this locale.
956 */
957
958 /*!
959     \qmlproperty string QtQuick2::Locale::exponential
960
961     Holds the exponential character of this locale.
962 */
963
964 /*!
965     \qmlmethod string QtQuick2::Locale::dateTimeFormat(type)
966
967     Returns the date time format used for the current locale.
968     \a type specifies the FormatType to return.
969
970     \sa {QtQuick2::Date}{Date}
971 */
972
973 /*!
974     \qmlmethod string QtQuick2::Locale::dateFormat(type)
975
976     Returns the date format used for the current locale.
977     \a type specifies the FormatType to return.
978
979     \sa {QtQuick2::Date}{Date}
980 */
981
982 /*!
983     \qmlmethod string QtQuick2::Locale::timeFormat(type)
984
985     Returns the time format used for the current locale.
986     \a type specifies the FormatType to return.
987
988     \sa {QtQuick2::Date}{Date}
989 */
990
991 /*!
992     \qmlmethod string QtQuick2::Locale::monthName(month, type)
993
994     Returns the localized name of \a month (0-11), in the optional
995     \l FormatType specified by \a type.
996
997     \note the QLocale C++ API expects a range of (1-12), however Locale.monthName()
998     expects 0-11 as per the JS Date object.
999
1000     \sa dayName(), standaloneMonthName()
1001 */
1002
1003 /*!
1004     \qmlmethod string QtQuick2::Locale::standaloneMonthName(month, type)
1005
1006     Returns the localized name of \a month (0-11) that is used as a
1007     standalone text, in the optional \l FormatType specified by \a type.
1008
1009     If the locale information doesn't specify the standalone month
1010     name then return value is the same as in monthName().
1011
1012     \note the QLocale C++ API expects a range of (1-12), however Locale.standaloneMonthName()
1013     expects 0-11 as per the JS Date object.
1014
1015     \sa monthName(), standaloneDayName()
1016 */
1017
1018 /*!
1019     \qmlmethod string QtQuick2::Locale::dayName(day, type)
1020
1021     Returns the localized name of the \a day (where 0 represents
1022     Sunday, 1 represents Monday and so on), in the optional
1023     \l FormatType specified by \a type.
1024
1025     \sa monthName(), standaloneDayName()
1026 */
1027
1028 /*!
1029     \qmlmethod string QtQuick2::Locale::standaloneDayName(day, type)
1030
1031     Returns the localized name of the \a day (where 0 represents
1032     Sunday, 1 represents Monday and so on) that is used as a
1033     standalone text, in the \l FormatType specified by \a type.
1034
1035     If the locale information does not specify the standalone day
1036     name then return value is the same as in dayName().
1037
1038     \sa dayName(), standaloneMonthName()
1039 */
1040
1041 /*!
1042     \qmlproperty enumeration QtQuick2::Locale::firstDayOfWeek
1043
1044     Holds the first day of the week according to the current locale.
1045
1046     \list
1047     \li Locale.Sunday = 0
1048     \li Locale.Monday = 1
1049     \li Locale.Tuesday = 2
1050     \li Locale.Wednesday = 3
1051     \li Locale.Thursday = 4
1052     \li Locale.Friday = 5
1053     \li Locale.Saturday = 6
1054     \endlist
1055
1056     \note that these values match the JS Date API which is different
1057     from the Qt C++ API where Qt::Sunday = 7.
1058 */
1059
1060 /*!
1061     \qmlproperty Array<int> QtQuick2::Locale::weekDays
1062
1063     Holds an array of days that are considered week days according to the current locale,
1064     where Sunday is 0 and Saturday is 6.
1065
1066     \sa firstDayOfWeek
1067 */
1068
1069 /*!
1070     \qmlproperty Array<string> QtQuick2::Locale::uiLanguages
1071
1072     Returns an ordered list of locale names for translation purposes in
1073     preference order.
1074
1075     The return value represents locale names that the user expects to see the
1076     UI translation in.
1077
1078     The first item in the list is the most preferred one.
1079 */
1080
1081 /*!
1082     \qmlproperty enumeration QtQuick2::Locale::textDirection
1083
1084     Holds the text direction of the language:
1085     \list
1086     \li Qt.LeftToRight
1087     \li Qt.RightToLeft
1088     \endlist
1089 */
1090
1091 /*!
1092     \qmlproperty string QtQuick2::Locale::amText
1093
1094     The localized name of the "AM" suffix for times specified using the conventions of the 12-hour clock.
1095 */
1096
1097 /*!
1098     \qmlproperty string QtQuick2::Locale::pmText
1099
1100     The localized name of the "PM" suffix for times specified using the conventions of the 12-hour clock.
1101 */
1102
1103 /*!
1104     \qmlmethod string QtQuick2::Locale::currencySymbol(format)
1105
1106     Returns the currency symbol for the specified \a format:
1107     \list
1108     \li Locale.CurrencyIsoCode a ISO-4217 code of the currency.
1109     \li Locale.CurrencySymbol a currency symbol.
1110     \li Locale.CurrencyDisplayName a user readable name of the currency.
1111     \endlist
1112     \sa Number::toLocaleCurrencyString()
1113 */
1114
1115 /*!
1116     \qmlproperty string QtQuick2::Locale::nativeLanguageName
1117
1118     Holds a native name of the language for the locale. For example
1119     "Schwiizertüütsch" for Swiss-German locale.
1120
1121     \sa nativeCountryName
1122 */
1123
1124 /*!
1125     \qmlproperty string QtQuick2::Locale::nativeCountryName
1126
1127     Holds a native name of the country for the locale. For example
1128     "España" for Spanish/Spain locale.
1129
1130     \sa nativeLanguageName
1131 */
1132
1133 /*!
1134     \qmlproperty enumeration QtQuick2::Locale::measurementSystem
1135
1136     This property defines which units are used for measurement.
1137
1138     \list
1139     \li Locale.MetricSystem This value indicates metric units, such as meters,
1140         centimeters and millimeters.
1141     \li Locale.ImperialSystem This value indicates imperial units, such as inches and
1142         miles. There are several distinct imperial systems in the world; this
1143         value stands for the official United States imperial units.
1144     \endlist
1145 */
1146
1147 QT_END_NAMESPACE