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