blob: 2c15017a85892552ec2ac07b8d0902e78cddf07c [file] [log] [blame]
/*
*
* Copyright 2013 Canonical Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
#include <ctime> //TODO: switch to QTimeZone (QT 5.1)
#include <unicode/decimfmt.h>
#include <unicode/timezone.h>
#include "globalization.h"
Globalization::Globalization(Cordova *cordova):
CPlugin(cordova) {
}
void Globalization::getPreferredLanguage(int scId, int ecId) {
Q_UNUSED(ecId)
QLocale locale;
QString lang = QLocale::languageToString(locale.language());
QVariantMap obj;
obj.insert("value", lang);
this->cb(scId, obj);
}
void Globalization::getLocaleName(int scId, int ecId) {
Q_UNUSED(ecId)
QVariantMap obj;
obj.insert("value", QLocale().name());
this->cb(scId, obj);
}
void Globalization::getFirstDayOfWeek(int scId, int ecId) {
Q_UNUSED(ecId)
QLocale locale;
int res;
if (locale.firstDayOfWeek() == Qt::Sunday) {
res = 1;
} else {
res = (2 - Qt::Monday) + locale.firstDayOfWeek();
}
QVariantMap obj;
obj.insert("value", res);
this->cb(scId, obj);
}
void Globalization::isDayLightSavingsTime(int scId, int ecId, const QVariantMap &options) {
time_t time = options.find("time_t")->toLongLong() / 1000;
const tm *desc = std::localtime(&time);
if (desc->tm_isdst < 0) {
this->callback(ecId, QString("new GlobalizationError(%1, 'information is not available');").arg(Globalization::UNKNOWN_ERROR));
return;
}
this->callback(scId, QString("{dst:%1}").arg(desc->tm_isdst > 0 ? "true" : "false"));
}
QLocale::FormatType translateFormat(Globalization::Format formatLength) {
QLocale::FormatType format = QLocale::ShortFormat;
switch (formatLength) {
case Globalization::FORMAT_FULL:
case Globalization::FORMAT_LONG:
format = QLocale::ShortFormat; // TODO: Qt cant parse string produced with QLocale::LongFormat;
break;
case Globalization::FORMAT_MEDIUM:
format = QLocale::ShortFormat;
break;
case Globalization::FORMAT_SHORT:
format = QLocale::NarrowFormat;
break;
}
return format;
}
void Globalization::dateToString(int scId, int ecId, const QVariantMap &options) {
time_t time = options.find("time_t")->toLongLong() / 1000;
Globalization::Format formatLength = static_cast<Globalization::Format>(options.find("formatLength")->toInt());
Globalization::Selector selector = static_cast<Globalization::Selector>(options.find("selector")->toInt());
QLocale::FormatType format = translateFormat(formatLength);
if (time < 0) {
this->callback(ecId, QString("new GlobalizationError(%1, 'unsupported operation');").arg(Globalization::FORMATTING_ERROR));
return;
}
QLocale locale;
QString res;
QDateTime dateTime = QDateTime::fromTime_t((uint)time);
switch (selector) {
case SELECTOR_ALL:
res = locale.toString(dateTime,format);
break;
case SELECTOR_TIME:
res = locale.toString(dateTime.time(), format);
break;
case SELECTOR_DATE:
res = locale.toString(dateTime.date(), format);
break;
}
QVariantMap obj;
obj.insert("value", res);
this->cb(scId, obj);
}
void Globalization::stringToDate(int scId, int ecId, const QVariantMap &options) {
QString dateString = options.find("dateString")->toString();
Globalization::Format formatLength = static_cast<Globalization::Format>(options.find("formatLength")->toInt());
Globalization::Selector selector = static_cast<Globalization::Selector>(options.find("selector")->toInt());
QLocale::FormatType format = translateFormat(formatLength);
QLocale locale;
bool valid(true);
int year(0), month(0), day(0), hour(0), minute(0), second(0), millisecond(0);
switch (selector) {
case SELECTOR_ALL:
{
QDateTime dateTime = locale.toDateTime(dateString, format);
valid = dateTime.isValid();
QTime time = dateTime.time();
hour = time.hour(); minute = time.minute(); second = time.second(); millisecond = time.msec();
QDate date = dateTime.date();
year = date.year(); month = date.month(); day = date.day();
}
break;
case SELECTOR_TIME:
{
QTime time = locale.toTime(dateString, format);
valid = time.isValid();
hour = time.hour(); minute = time.minute(); second = time.second(); millisecond = time.msec();
}
break;
case SELECTOR_DATE:
{
QDate date = locale.toDate(dateString, format);
valid = date.isValid();
year = date.year(); month = date.month(); day = date.day();
}
break;
}
if ((format == QLocale::NarrowFormat || format == QLocale::ShortFormat) && year < 2000 && year > 1900) {
year += 100;
}
if (!valid) {
this->callback(ecId, QString("new GlobalizationError(%1, 'parsing error')").arg(Globalization::PARSING_ERROR));
} else {
QVariantMap obj;
obj.insert("year", year);
obj.insert("month", month - 1);
obj.insert("day", day);
obj.insert("hour", hour);
obj.insert("minute", minute);
obj.insert("second", second);
obj.insert("millisecond", millisecond);
this->cb(scId, obj);
}
}
void Globalization::getDateNames(int scId, int ecId, const QVariantMap &options) {
Q_UNUSED(ecId)
int type = options.find("type")->toInt();
int item = options.find("item")->toInt();
QLocale::FormatType format;
if (type == FORMAT_SHORT)
format = QLocale::ShortFormat;
else
format = QLocale::LongFormat;
QLocale locale;
QList<QString> res;
if (item == REQUEST_DAY_NAMES) {
for (int i = 1; i <= 7; i++) {
res.append(locale.dayName(i, format));
}
} else { //REQUEST_MONTH_NAMES
for (int i = 1; i <= 12; i++) {
res.append(locale.monthName(i, format));
}
}
QString result;
for (QList<QString>::iterator it = res.begin(); it != res.end(); it++) {
result += QString("'%1',").arg(*it);
}
this->callback(scId, QString("{ value: [ %1 ]}").arg(result));
}
template<class T>
static QString format(T number, Globalization::NumberType type) {
QString res;
QLocale locale;
switch (type) {
case Globalization::DECIMAL:
res = locale.toString(number);
break;
case Globalization::PERCENT:
res = locale.toString(number) + locale.percent();
break;
case Globalization::CURRENCY:
res = locale.toCurrencyString(number);
break;
};
return res;
}
void Globalization::numberToString(int scId, int ecId, const QVariantMap &options) {
Q_UNUSED(ecId)
bool isInt = options.find("isInt")->toBool();
NumberType type = static_cast<NumberType>(options.find("type")->toBool());
QString res;
if (isInt) {
long long number = options.find("number")->toLongLong();
res = format(number, type);
} else {
double number = options.find("number")->toDouble();
res = format(number, type);
}
this->callback(scId, QString("{ value: '%1' }").arg(res));
}
void Globalization::stringToNumber(int scId, int ecId, int type, QString string) {
switch ((NumberType)type) {
case Globalization::DECIMAL:
string = string.remove(QLocale().groupSeparator());
break;
case Globalization::PERCENT:
string = string.remove(QLocale().percent()).remove(QLocale().groupSeparator());
break;
case Globalization::CURRENCY:
string = string.remove(QLocale().currencySymbol()).remove(QLocale().groupSeparator());
break;
};
bool ok;
double res = QLocale().toDouble(string, &ok);
if (ok)
this->callback(scId, QString("{ value: %1 }").arg(res));
else
this->callback(ecId, QString("new GlobalizationError(%1, 'parsing error')").arg(Globalization::PARSING_ERROR));
}
static QString ustr2qstr(UnicodeString &ustr) {
std::string res;
ustr.toUTF8String(res);
return QString(res.c_str());
}
void Globalization::getNumberPattern(int scId, int ecId, int type) {
Q_UNUSED(ecId);
UErrorCode status = U_ZERO_ERROR;
icu::DecimalFormat icu(status);
icu::UnicodeString pattern;
icu.toPattern(pattern);
QLocale locale;
QVariantMap obj;
obj.insert("pattern", ustr2qstr(pattern));
switch ((NumberType)type) {
case Globalization::DECIMAL:
obj.insert("symbol", "");
break;
case Globalization::PERCENT:
obj.insert("symbol", QString(locale.percent()));
break;
case Globalization::CURRENCY:
obj.insert("symbol", QString(locale.currencySymbol()));
break;
};
obj.insert("fraction", icu.getMaximumFractionDigits());
obj.insert("rounding", icu.getRoundingIncrement());
obj.insert("positive", QString(locale.positiveSign()));
obj.insert("negative", QString(locale.negativeSign()));
obj.insert("decimal", QString(locale.decimalPoint()));
obj.insert("grouping", QString(locale.groupSeparator()));
this->cb(scId, obj);
}
static bool inDayLightSavingsTime() {
time_t now;
time(&now);
const tm *desc = std::localtime(&now);
return desc->tm_isdst > 0;
}
void Globalization::getDatePattern(int scId, int ecId, int formatLength, int selector) {
Q_UNUSED(ecId);
QLocale locale;
QVariantMap res;
QLocale::FormatType format = translateFormat((Format)formatLength);
switch ((Selector)selector) {
case Selector::SELECTOR_TIME:
res.insert("pattern", locale.timeFormat(format));
break;
case Selector::SELECTOR_DATE:
res.insert("pattern", locale.dateFormat(format));
break;
case Selector::SELECTOR_ALL:
res.insert("pattern", locale.dateTimeFormat(format));
break;
};
UnicodeString result;
QSharedPointer<TimeZone> timezone = QSharedPointer<TimeZone>(TimeZone::createDefault());
timezone->getDisplayName(inDayLightSavingsTime(), TimeZone::SHORT, result);
res.insert("timezone", ustr2qstr(result));
res.insert("utc_offset", timezone->getRawOffset() / 1000 + timezone->getDSTSavings() / 1000);
res.insert("dst_offset", timezone->getDSTSavings() / 1000);
this->cb(scId, res);
}