From 34c81262dc0b79220e6b99051ce09065bf6d83d6 Mon Sep 17 00:00:00 2001 From: Frans Englich Date: Mon, 25 May 2009 10:51:48 +0200 Subject: Factor Symbian specific code into its own file, qlocale_symbian.cpp. Reviewed-by: Miikka Heikkinen --- src/corelib/tools/qlocale.cpp | 797 +------------------------------- src/corelib/tools/qlocale_symbian.cpp | 840 ++++++++++++++++++++++++++++++++++ src/corelib/tools/tools.pri | 1 + 3 files changed, 844 insertions(+), 794 deletions(-) create mode 100644 src/corelib/tools/qlocale_symbian.cpp diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index ee3e530..4d042ae 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -78,11 +78,6 @@ QT_END_NAMESPACE #include #include -#if defined(Q_OS_SYMBIAN) -#include -#include "private/qcore_symbian_p.h" -#endif - #if defined(Q_OS_LINUX) && !defined(__UCLIBC__) # include #endif @@ -303,7 +298,7 @@ static bool splitLocaleName(const QString &name, QChar *lang_begin, QChar *cntry return lang_len == 2 || lang_len == 3; } -static void getLangAndCountry(const QString &name, QLocale::Language &lang, QLocale::Country &cntry) +void getLangAndCountry(const QString &name, QLocale::Language &lang, QLocale::Country &cntry) { lang = QLocale::C; cntry = QLocale::AnyCountry; @@ -1282,794 +1277,8 @@ QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const } return QVariant(); } -#elif defined(Q_OS_SYMBIAN) - -static TExtendedLocale _s60Locale; - -// Type definitions for runtime resolved function pointers -typedef void (*FormatFunc)(TTime&, TDes&, const TDesC&, const TLocale&); -typedef TPtrC (*FormatSpecFunc)(TExtendedLocale&); - -// Runtime resolved functions -static FormatFunc ptrTimeFormatL = NULL; -static FormatSpecFunc ptrGetTimeFormatSpec = NULL; -static FormatSpecFunc ptrGetLongDateFormatSpec = NULL; -static FormatSpecFunc ptrGetShortDateFormatSpec = NULL; - -// Default functions if functions cannot be resolved -static void defaultTimeFormatL(TTime&, TDes& des, const TDesC&, const TLocale&) -{ - des.Zero(); -} - -static TPtrC defaultFormatSpec(TExtendedLocale&) -{ - return TPtrC(KNullDesC); -} - -/*! - Definition of struct for mapping Symbian to ISO locale -*/ -struct symbianToISO { - int symbian_language; - char iso_name[8]; -}; - -/*! - Mapping from Symbian to ISO locale -*/ -static const symbianToISO symbian_to_iso_list[] = { - { ELangEnglish, "en_GB" }, - { ELangFrench, "fr_FR" }, - { ELangGerman, "de_DE" }, - { ELangSpanish, "es_ES" }, - { ELangItalian, "it_IT" }, - { ELangSwedish, "sv_SE" }, - { ELangDanish, "da_DK" }, - { ELangNorwegian, "no_NO" }, - { ELangFinnish, "fi_FI" }, - { ELangAmerican, "en_US" }, - { ELangPortuguese, "pt_PT" }, - { ELangTurkish, "tr_TR" }, - { ELangIcelandic, "is_IS" }, - { ELangRussian, "ru_RU" }, - { ELangHungarian, "hu_HU" }, - { ELangDutch, "nl_NL" }, - { ELangBelgianFlemish, "nl_BE" }, - { ELangCzech, "cs_CZ" }, - { ELangSlovak, "sk_SK" }, - { ELangPolish, "pl_PL" }, - { ELangSlovenian, "sl_SI" }, - { ELangTaiwanChinese, "zh_TW" }, - { ELangHongKongChinese, "zh_HK" }, - { ELangPrcChinese, "zh_CN" }, - { ELangJapanese, "ja_JP" }, - { ELangThai, "th_TH" }, - { ELangArabic, "ar_AE" }, - { ELangTagalog, "tl_PH" }, - { ELangBulgarian, "bg_BG" }, - { ELangCatalan, "ca_ES" }, - { ELangCroatian, "hr_HR" }, - { ELangEstonian, "et_EE" }, - { ELangFarsi, "fa_IR" }, - { ELangCanadianFrench, "fr_CA" }, - { ELangGreek, "el_GR" }, - { ELangHebrew, "he_IL" }, - { ELangHindi, "hi_IN" }, - { ELangIndonesian, "id_ID" }, - { ELangLatvian, "lv_LV" }, - { ELangLithuanian, "lt_LT" }, - { ELangMalay, "ms_MY" }, - { ELangBrazilianPortuguese, "pt_BR" }, - { ELangRomanian, "ro_RO" }, - { ELangSerbian, "sr_YU" }, - { ELangLatinAmericanSpanish, "es" }, - { ELangUkrainian, "uk_UA" }, - { ELangUrdu, "ur_PK" }, // India/Pakistan - { ELangVietnamese, "vi_VN" }, -#ifdef __E32LANG_H__ -// 5.0 - { ELangBasque, "eu_ES" }, - { ELangGalician, "gl_ES" }, -#endif -#if !defined(__SERIES60_31__) - { ELangEnglish_Apac, "en" }, - { ELangEnglish_Taiwan, "en_TW" }, - { ELangEnglish_HongKong, "en_HK" }, - { ELangEnglish_Prc, "en_CN" }, - { ELangEnglish_Japan, "en_JP"}, - { ELangEnglish_Thailand, "en_TH" }, - { ELangMalay_Apac, "ms" } -#endif -}; - -/*! - Returns ISO name corresponding to the Symbian locale code \a sys_fmt. -*/ -static QByteArray symbianLocaleName(int code) -{ - //Number of Symbian to ISO locale mappings - static const int symbian_to_iso_count - = sizeof(symbian_to_iso_list)/sizeof(symbianToISO); - - int cmp = code - symbian_to_iso_list[0].symbian_language; - if (cmp < 0) - return 0; - - if (cmp == 0) - return symbian_to_iso_list[0].iso_name; - - int begin = 0; - int end = symbian_to_iso_count; - - while (end - begin > 1) { - uint mid = (begin + end)/2; - - const symbianToISO *elt = symbian_to_iso_list + mid; - int cmp = code - elt->symbian_language; - if (cmp < 0) - end = mid; - else if (cmp > 0) - begin = mid; - else - return elt->iso_name; - } - - return 0; -} - - -// order is: normal, abbr, nmode, nmode+abbr -static const char *us_locale_dep[] = { - "MM", "dd", "yyyy", "MM", "dd", - "M", "d", "yy", "M", "d", - "MMMM", "dd", "yyyy", "MMMM", "dd", - "MMM", "d", "yy", "MMM", "d" }; - -static const char *eu_locale_dep[] = { - "dd", "MM", "yyyy", "dd", "MM", - "d", "M", "yy", "d", "M", - "dd", "MMMM", "yyyy", "dd", "MMMM", - "d", "MMM", "yy", "d", "MMM" }; - -static const char *jp_locale_dep[] = { - "yyyy", "MM", "dd", "MM", "dd", - "yy", "M", "d", "M", "d", - "yyyy", "MMMM", "dd", "MMMM", "dd", - "yy", "MMM", "d", "MMM", "d" }; - -/*! - Returns a Qt version of the given \a sys_fmt Symbian locale format string. -*/ -static QString s60ToQtFormat(const QString &sys_fmt) -{ - TLocale *locale = _s60Locale.GetLocale(); - - QString result; - QString other; - QString qtformatchars = QString::fromLatin1("adhmsyzAHM"); - - QChar c; - int i = 0; - bool open_escape = false; - bool abbrev_next = false; - bool locale_indep_ordering = false; - bool minus_mode = false; - bool plus_mode = false; - bool n_mode = false; - TTimeFormat tf = locale->TimeFormat(); - - while (i < sys_fmt.size()) { - - c = sys_fmt.at(i); - - // let formatting thru - if (c.unicode() == '%') { - // if we have gathered string, concat it - if (!other.isEmpty()) { - result += other; - other.clear(); - } - // if we have open escape, end it - if (open_escape) { - result += QLatin1Char('\''); - open_escape = false; - } - - ++i; - if (i >= sys_fmt.size()) - break; - - c = sys_fmt.at(i); - - // process specials - abbrev_next = c.unicode() == '*'; - plus_mode = c.unicode() == '+'; - minus_mode = c.unicode() == '-'; - - if (abbrev_next || plus_mode || minus_mode) { - ++i; - if (i >= sys_fmt.size()) - break; - - c = sys_fmt.at(i); - - if (plus_mode || minus_mode) { - // break on undefined plus/minus mode - if (c.unicode() != 'A' && c.unicode() != 'B') - break; - } - } - - switch (c.unicode()) { - case 'F': - // locale indep mode on - locale_indep_ordering = true; - break; - - case '/': - // date sep 0-3 - ++i; - if (i >= sys_fmt.size()) - break; - - c = sys_fmt.at(i); - if (c.isDigit() && c.digitValue() <= 3) { - TChar s = locale->DateSeparator(c.digitValue()); - TUint val = s; - // some indexes return zero for empty - if (val > 0) - result += QChar(val); - } - break; - - case 'D': - if (!locale_indep_ordering) - break; - - if (!abbrev_next) - result += QLatin1String("dd"); - else - result += QLatin1Char('d'); - - break; - - case 'M': - if (!locale_indep_ordering) - break; - - if (!n_mode) { - if (!abbrev_next) - result += QLatin1String("MM"); - else - result += QLatin1String("M"); - } else { - if (!abbrev_next) - result += QLatin1String("MMMM"); - else - result += QLatin1String("MMM"); - } - - break; - - case 'N': - n_mode = true; - - if (!locale_indep_ordering) - break; - - if (!abbrev_next) - result += QLatin1String("MMMM"); - else - result += QLatin1String("MMM"); - - break; - - case 'Y': - if (!locale_indep_ordering) - break; - - if (!abbrev_next) - result += QLatin1String("yyyy"); - else - result += QLatin1String("yy"); - - break; - - case 'E': - if (!abbrev_next) - result += QLatin1String("dddd"); - else - result += QLatin1String("ddd"); - - break; - - case ':': - // timesep 0-3 - ++i; - if (i >= sys_fmt.size()) - break; - - c = sys_fmt.at(i); - if (c.isDigit() && c.digitValue() <= 3) { - TChar s = locale->TimeSeparator(c.digitValue()); - TUint val = s; - // some indexes return zero for empty - if (val > 0) - result += QChar(val); - } - - break; - - case 'J': - if (tf == ETime24 && !abbrev_next) - result += QLatin1String("hh"); - else - result += QLatin1Char('h'); - - break; - - case 'H': - if (!abbrev_next) - result += QLatin1String("hh"); - else - result += QLatin1Char('h'); - - break; - - case 'I': - result += QLatin1Char('h'); - break; - - case 'T': - if (!abbrev_next) - result += QLatin1String("mm"); - else - result += QLatin1Char('m'); - - break; - - case 'S': - if (!abbrev_next) - result += QLatin1String("ss"); - else - result += QLatin1Char('s'); - - break; - - case 'B': - // only done for 12h clock - if (tf == ETime24) - break; - - // fallthru to A - case 'A': { - // quickie to get capitalization, can't use s60 string as is because Qt 'hh' format's am/pm logic - TAmPmName ampm = TAmPmName(); - TChar first(ampm[0]); - QString qtampm = QString::fromLatin1(first.IsUpper() ? "AP" : "ap"); - - int pos = locale->AmPmSymbolPosition(); - - if ((minus_mode && pos != ELocaleBefore) || - (plus_mode && pos != ELocaleAfter)) - break; - - if (!abbrev_next && locale->AmPmSpaceBetween()) { - if (pos == ELocaleBefore) - qtampm.append(QLatin1Char(' ')); - else - qtampm.prepend(QLatin1Char(' ')); - } - - result += qtampm; - } - break; - - case '.': { - // decimal sep - TChar s = locale->DecimalSeparator(); - TUint val = s; - if (val > 0) - result += QChar(val); - } - break; - - case 'C': - // six digits in s60, three digits in qt - if (!abbrev_next) { - result += QLatin1String("zzz"); - } else { - // next char is number from 0-6, how many digits to display - ++i; - if (i >= sys_fmt.size()) - break; - - c = sys_fmt.at(i); - - if (c.isDigit()) { - // try to match wanted digits - QChar val(c.digitValue()); - - if (val >= 3) { - result += QLatin1String("zzz"); - } else if (val > 0) { - result += QLatin1Char('z'); - } - } - } - break; - - // these cases fallthru - case '1': - case '2': - case '3': - case '4': - case '5': - - // shouldn't parse these with %F - if (locale_indep_ordering) - break; - - TDateFormat df = locale->DateFormat(); - - const char **locale_dep; - switch (df) { - default: // fallthru to american - case EDateAmerican: - locale_dep = us_locale_dep; - break; - case EDateEuropean: - locale_dep = eu_locale_dep; - break; - case EDateJapanese: - locale_dep = jp_locale_dep; - break; - } - int offset = 0; - if (abbrev_next) - offset += 5; - if (n_mode) - offset += 10; - - result += QLatin1String(locale_dep[offset + (c.digitValue()-1)]); - break; - - case '%': // fallthru percent - // any junk gets copied as is - default: - result += c; - break; - - case 'Z': // Qt doesn't support these :( - case 'X': - case 'W': - break; - } - } else { - // double any single quotes, don't begin escape - if (c.unicode() == '\'') { - // end open escape - if (open_escape) { - result += other; - other.clear(); - result += QLatin1Char('\''); - open_escape = false; - } - - other += c; - } - - // gather chars and escape them in one go if any format chars are found - if (!open_escape && qtformatchars.indexOf(c) != -1) { - result += QLatin1Char('\''); - open_escape = true; - } - other += c; - } - - ++i; - } - - if (!other.isEmpty()) - result += other; - if (open_escape) - result += QLatin1Char('\''); - - return result; -} - -/*! - Retrieves Symbian locale decimal separator. -*/ -static QString symbianDecimalPoint() -{ - TLocale *locale = _s60Locale.GetLocale(); - - TChar decPoint = locale->DecimalSeparator(); - int val = decPoint; - return QChar(val); -} - -/*! - Retrieves Symbian locale group separator. -*/ -static QString symbianGroupSeparator() -{ - TLocale *locale = _s60Locale.GetLocale(); - - TChar grpSep = locale->ThousandsSeparator(); - int val = grpSep; - return QChar(val); -} - -/*! - Retrieves Symbian locale zero digit. -*/ -static QString symbianZeroDigit() -{ - TLocale *locale = _s60Locale.GetLocale(); - - // TDigitType enumeration value returned by TLocale - // will always correspond to zero digit unicode value. - TDigitType digit = locale->DigitType(); - return QChar(digit); -} - -/*! - Retrieves a day name from Symbian locale. The \a day is an integer - from 1 to 7. When \a short_format is true the method returns - the day in short format. Otherwise it returns the day in a long format. -*/ -static QString symbianDayName(int day, bool short_format) -{ - day -= 1; - - if (day < 0 || day > 6) - return QString(); - - if (short_format) { - return qt_TDes2QStringL(TDayNameAbb(TDay(day))); - } else { - return qt_TDes2QStringL(TDayName(TDay(day))); - } -} - -/*! - Retrieves a month name from Symbian locale. The \a month is an integer - from 1 to 12. When \a short_format is true the method returns - the month in short format. Otherwise it returns the month in a long format. -*/ -static QString symbianMonthName(int month, bool short_format) -{ - month -= 1; - if (month < 0 || month > 11) - return QString(); - - if (short_format) { - return qt_TDes2QStringL(TMonthNameAbb(TMonth(month))); - } else { - return qt_TDes2QStringL(TMonthName(TMonth(month))); - } -} - -/*! - Retrieves date format from Symbian locale and - transforms it to Qt format. - - When \a short_format is true the method returns - short date format. Otherwise it returns the long format. -*/ -static QString symbianDateFormat(bool short_format) -{ - TPtrC dateFormat; - - if (short_format) { - dateFormat.Set(ptrGetShortDateFormatSpec(_s60Locale)); - } else { - dateFormat.Set(ptrGetLongDateFormatSpec(_s60Locale)); - } - - return s60ToQtFormat(qt_TDesC2QStringL(dateFormat)); -} - -/*! - Retrieves time format from Symbian locale and - transforms it to Qt format. -*/ -static QString symbianTimeFormat() -{ - return s60ToQtFormat(qt_TDesC2QStringL(ptrGetTimeFormatSpec(_s60Locale))); -} - -/*! - Returns localized string representation of given \a date - formatted with Symbian locale date format. - - If \a short_format is true the format will be a short version. - Otherwise it uses a longer version. -*/ -static QString symbianDateToString(const QDate &date, bool short_format) -{ - int month = date.month() - 1; - int day = date.day() - 1; - int year = date.year(); - - TDateTime dateTime; - dateTime.Set(year, TMonth(month), day, 0, 0, 0, 0); - - TTime timeStr(dateTime); - TBuf buffer; - - TPtrC dateFormat; - if (short_format) { - dateFormat.Set(ptrGetShortDateFormatSpec(_s60Locale)); - } else { - dateFormat.Set(ptrGetLongDateFormatSpec(_s60Locale)); - } - - TRAPD(err, ptrTimeFormatL(timeStr, buffer, dateFormat, *_s60Locale.GetLocale());) - - if (err == KErrNone) - return qt_TDes2QStringL(buffer); - else - return QString(); -} - -/*! - Returns localized string representation of given \a time - formatted with Symbian locale time format. -*/ -static QString symbianTimeToString(const QTime &time) -{ - int hour = time.hour(); - int minute = time.minute(); - int second = time.second(); - int milliseconds = 0; - - TDateTime dateTime; - dateTime.Set(0, TMonth(0), 0, hour, minute, second, milliseconds); - - TTime timeStr(dateTime); - TBuf buffer; - - TRAPD(err, ptrTimeFormatL( - timeStr, - buffer, - ptrGetTimeFormatSpec(_s60Locale), - *_s60Locale.GetLocale()); - ) - - if (err == KErrNone) - return qt_TDes2QStringL(buffer); - else - return QString(); -} - -/*! - Returns the measurement system stored in Symbian locale - - \sa QLocale::MeasurementSystem -*/ -static QLocale::MeasurementSystem symbianMeasurementSystem() -{ - TLocale *locale = _s60Locale.GetLocale(); - - TUnitsFormat unitFormat = locale->UnitsGeneral(); - if (unitFormat == EUnitsImperial) - return QLocale::ImperialSystem; - else - return QLocale::MetricSystem; -} - -QLocale QSystemLocale::fallbackLocale() const -{ - // load system data before query calls - static bool initDone = false; - if (!initDone) { - _s60Locale.LoadSystemSettings(); - - // Initialize platform version dependent function pointers - ptrTimeFormatL = reinterpret_cast - (qt_resolveS60PluginFunc(S60Plugin_TimeFormatL)); - ptrGetTimeFormatSpec = reinterpret_cast - (qt_resolveS60PluginFunc(S60Plugin_GetTimeFormatSpec)); - ptrGetLongDateFormatSpec = reinterpret_cast - (qt_resolveS60PluginFunc(S60Plugin_GetLongDateFormatSpec)); - ptrGetShortDateFormatSpec = reinterpret_cast - (qt_resolveS60PluginFunc(S60Plugin_GetShortDateFormatSpec)); - if (!ptrTimeFormatL) - ptrTimeFormatL = &defaultTimeFormatL; - if (!ptrGetTimeFormatSpec) - ptrGetTimeFormatSpec = &defaultFormatSpec; - if (!ptrGetLongDateFormatSpec) - ptrGetLongDateFormatSpec = &defaultFormatSpec; - if (!ptrGetShortDateFormatSpec) - ptrGetShortDateFormatSpec = &defaultFormatSpec; - } - - TLanguage lang = User::Language(); - QString locale = symbianLocaleName(lang); - return QLocale(locale); -} - -/*! - Generic query method for locale data. Provides indirection. - Denotes the \a type of the query - with \a in as input data depending on the query. - - \sa QSystemLocale::QueryType -*/ -QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const -{ - switch(type) { - case DecimalPoint: - return symbianDecimalPoint(); - case GroupSeparator: - return symbianGroupSeparator(); - - case ZeroDigit: - return symbianZeroDigit(); - - case DayNameLong: - case DayNameShort: - return symbianDayName(in.toInt(), (type == DayNameShort) ); - - case MonthNameLong: - case MonthNameShort: - return symbianMonthName(in.toInt(), (type == MonthNameShort) ); - - case DateFormatLong: - case DateFormatShort: - return symbianDateFormat( (type == DateFormatShort) ); - case TimeFormatLong: - case TimeFormatShort: - return symbianTimeFormat(); - case DateTimeFormatLong: - case DateTimeFormatShort: - return symbianDateFormat( (type == DateTimeFormatShort) ) + QLatin1Char(' ') + symbianTimeFormat(); - case DateToStringShort: - case DateToStringLong: - return symbianDateToString(in.toDate(), (type == DateToStringShort) ); - case TimeToStringShort: - case TimeToStringLong: - return symbianTimeToString(in.toTime()); - case DateTimeToStringShort: - case DateTimeToStringLong: { - const QDateTime dt = in.toDateTime(); - return symbianDateToString(dt.date(), (type == DateTimeToStringShort) ) - + QLatin1Char(' ') + symbianTimeToString(dt.time()); - } - case MeasurementSystem: - return static_cast(symbianMeasurementSystem()); - case LanguageId: - case CountryId: { - TLanguage language = User::Language(); - QString locale = symbianLocaleName(language); - QLocale::Language lang; - QLocale::Country cntry; - getLangAndCountry(locale, lang, cntry); - if (type == LanguageId) - return lang; - // few iso codes have no country and will use this - if (cntry == QLocale::AnyCountry) - return fallbackLocale().country(); - - return cntry; - } - case NegativeSign: - case PositiveSign: - case AMText: - case PMText: - break; - default: - break; - } - return QVariant(); -} - -#elif defined(Q_OS_UNIX) +#elif defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) static uint unixGetSystemMeasurementSystem() { @@ -2113,7 +1322,7 @@ QVariant QSystemLocale::query(QueryType type, QVariant /* in */) const } } -#else +#elif !defined(Q_OS_SYMBIAN) /*! Returns a fallback locale, that will get used for everything that diff --git a/src/corelib/tools/qlocale_symbian.cpp b/src/corelib/tools/qlocale_symbian.cpp new file mode 100644 index 0000000..b58a5d5 --- /dev/null +++ b/src/corelib/tools/qlocale_symbian.cpp @@ -0,0 +1,840 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include +#include "private/qcore_symbian_p.h" + +// Located in qlocale.cpp +extern void getLangAndCountry(const QString &name, QLocale::Language &lang, QLocale::Country &cntry); + +QT_BEGIN_NAMESPACE + +static TExtendedLocale _s60Locale; + +// Type definitions for runtime resolved function pointers +typedef void (*FormatFunc)(TTime&, TDes&, const TDesC&, const TLocale&); +typedef TPtrC (*FormatSpecFunc)(TExtendedLocale&); + +// Runtime resolved functions +static FormatFunc ptrTimeFormatL = NULL; +static FormatSpecFunc ptrGetTimeFormatSpec = NULL; +static FormatSpecFunc ptrGetLongDateFormatSpec = NULL; +static FormatSpecFunc ptrGetShortDateFormatSpec = NULL; + +// Default functions if functions cannot be resolved +static void defaultTimeFormatL(TTime&, TDes& des, const TDesC&, const TLocale&) +{ + des.Zero(); +} + +static TPtrC defaultFormatSpec(TExtendedLocale&) +{ + return TPtrC(KNullDesC); +} + +/*! + Definition of struct for mapping Symbian to ISO locale +*/ +struct symbianToISO { + int symbian_language; + char iso_name[8]; +}; + + +/*! + Mapping from Symbian to ISO locale +*/ +static const symbianToISO symbian_to_iso_list[] = { + { ELangEnglish, "en_GB" }, + { ELangFrench, "fr_FR" }, + { ELangGerman, "de_DE" }, + { ELangSpanish, "es_ES" }, + { ELangItalian, "it_IT" }, + { ELangSwedish, "sv_SE" }, + { ELangDanish, "da_DK" }, + { ELangNorwegian, "no_NO" }, + { ELangFinnish, "fi_FI" }, + { ELangAmerican, "en_US" }, + { ELangPortuguese, "pt_PT" }, + { ELangTurkish, "tr_TR" }, + { ELangIcelandic, "is_IS" }, + { ELangRussian, "ru_RU" }, + { ELangHungarian, "hu_HU" }, + { ELangDutch, "nl_NL" }, + { ELangBelgianFlemish, "nl_BE" }, + { ELangCzech, "cs_CZ" }, + { ELangSlovak, "sk_SK" }, + { ELangPolish, "pl_PL" }, + { ELangSlovenian, "sl_SI" }, + { ELangTaiwanChinese, "zh_TW" }, + { ELangHongKongChinese, "zh_HK" }, + { ELangPrcChinese, "zh_CN" }, + { ELangJapanese, "ja_JP" }, + { ELangThai, "th_TH" }, + { ELangArabic, "ar_AE" }, + { ELangTagalog, "tl_PH" }, + { ELangBulgarian, "bg_BG" }, + { ELangCatalan, "ca_ES" }, + { ELangCroatian, "hr_HR" }, + { ELangEstonian, "et_EE" }, + { ELangFarsi, "fa_IR" }, + { ELangCanadianFrench, "fr_CA" }, + { ELangGreek, "el_GR" }, + { ELangHebrew, "he_IL" }, + { ELangHindi, "hi_IN" }, + { ELangIndonesian, "id_ID" }, + { ELangLatvian, "lv_LV" }, + { ELangLithuanian, "lt_LT" }, + { ELangMalay, "ms_MY" }, + { ELangBrazilianPortuguese, "pt_BR" }, + { ELangRomanian, "ro_RO" }, + { ELangSerbian, "sr_YU" }, + { ELangLatinAmericanSpanish, "es" }, + { ELangUkrainian, "uk_UA" }, + { ELangUrdu, "ur_PK" }, // India/Pakistan + { ELangVietnamese, "vi_VN" }, +#ifdef __E32LANG_H__ +// 5.0 + { ELangBasque, "eu_ES" }, + { ELangGalician, "gl_ES" }, +#endif +#if !defined(__SERIES60_31__) + { ELangEnglish_Apac, "en" }, + { ELangEnglish_Taiwan, "en_TW" }, + { ELangEnglish_HongKong, "en_HK" }, + { ELangEnglish_Prc, "en_CN" }, + { ELangEnglish_Japan, "en_JP"}, + { ELangEnglish_Thailand, "en_TH" }, + { ELangMalay_Apac, "ms" } +#endif +}; + +/*! + Returns ISO name corresponding to the Symbian locale code \a sys_fmt. +*/ +static QByteArray symbianLocaleName(int code) +{ + //Number of Symbian to ISO locale mappings + static const int symbian_to_iso_count + = sizeof(symbian_to_iso_list)/sizeof(symbianToISO); + + int cmp = code - symbian_to_iso_list[0].symbian_language; + if (cmp < 0) + return 0; + + if (cmp == 0) + return symbian_to_iso_list[0].iso_name; + + int begin = 0; + int end = symbian_to_iso_count; + + while (end - begin > 1) { + uint mid = (begin + end)/2; + + const symbianToISO *elt = symbian_to_iso_list + mid; + int cmp = code - elt->symbian_language; + if (cmp < 0) + end = mid; + else if (cmp > 0) + begin = mid; + else + return elt->iso_name; + } + + return 0; +} + + +// order is: normal, abbr, nmode, nmode+abbr +static const char *us_locale_dep[] = { + "MM", "dd", "yyyy", "MM", "dd", + "M", "d", "yy", "M", "d", + "MMMM", "dd", "yyyy", "MMMM", "dd", + "MMM", "d", "yy", "MMM", "d" }; + +static const char *eu_locale_dep[] = { + "dd", "MM", "yyyy", "dd", "MM", + "d", "M", "yy", "d", "M", + "dd", "MMMM", "yyyy", "dd", "MMMM", + "d", "MMM", "yy", "d", "MMM" }; + +static const char *jp_locale_dep[] = { + "yyyy", "MM", "dd", "MM", "dd", + "yy", "M", "d", "M", "d", + "yyyy", "MMMM", "dd", "MMMM", "dd", + "yy", "MMM", "d", "MMM", "d" }; + +/*! + Returns a Qt version of the given \a sys_fmt Symbian locale format string. +*/ +static QString s60ToQtFormat(const QString &sys_fmt) +{ + TLocale *locale = _s60Locale.GetLocale(); + + QString result; + QString other; + QString qtformatchars = QString::fromLatin1("adhmsyzAHM"); + + QChar c; + int i = 0; + bool open_escape = false; + bool abbrev_next = false; + bool locale_indep_ordering = false; + bool minus_mode = false; + bool plus_mode = false; + bool n_mode = false; + TTimeFormat tf = locale->TimeFormat(); + + while (i < sys_fmt.size()) { + + c = sys_fmt.at(i); + + // let formatting thru + if (c.unicode() == '%') { + // if we have gathered string, concat it + if (!other.isEmpty()) { + result += other; + other.clear(); + } + // if we have open escape, end it + if (open_escape) { + result += QLatin1Char('\''); + open_escape = false; + } + + ++i; + if (i >= sys_fmt.size()) + break; + + c = sys_fmt.at(i); + + // process specials + abbrev_next = c.unicode() == '*'; + plus_mode = c.unicode() == '+'; + minus_mode = c.unicode() == '-'; + + if (abbrev_next || plus_mode || minus_mode) { + ++i; + if (i >= sys_fmt.size()) + break; + + c = sys_fmt.at(i); + + if (plus_mode || minus_mode) { + // break on undefined plus/minus mode + if (c.unicode() != 'A' && c.unicode() != 'B') + break; + } + } + + switch (c.unicode()) { + case 'F': + // locale indep mode on + locale_indep_ordering = true; + break; + + case '/': + // date sep 0-3 + ++i; + if (i >= sys_fmt.size()) + break; + + c = sys_fmt.at(i); + if (c.isDigit() && c.digitValue() <= 3) { + TChar s = locale->DateSeparator(c.digitValue()); + TUint val = s; + // some indexes return zero for empty + if (val > 0) + result += QChar(val); + } + break; + + case 'D': + if (!locale_indep_ordering) + break; + + if (!abbrev_next) + result += QLatin1String("dd"); + else + result += QLatin1Char('d'); + + break; + + case 'M': + if (!locale_indep_ordering) + break; + + if (!n_mode) { + if (!abbrev_next) + result += QLatin1String("MM"); + else + result += QLatin1String("M"); + } else { + if (!abbrev_next) + result += QLatin1String("MMMM"); + else + result += QLatin1String("MMM"); + } + + break; + + case 'N': + n_mode = true; + + if (!locale_indep_ordering) + break; + + if (!abbrev_next) + result += QLatin1String("MMMM"); + else + result += QLatin1String("MMM"); + + break; + + case 'Y': + if (!locale_indep_ordering) + break; + + if (!abbrev_next) + result += QLatin1String("yyyy"); + else + result += QLatin1String("yy"); + + break; + + case 'E': + if (!abbrev_next) + result += QLatin1String("dddd"); + else + result += QLatin1String("ddd"); + + break; + + case ':': + // timesep 0-3 + ++i; + if (i >= sys_fmt.size()) + break; + + c = sys_fmt.at(i); + if (c.isDigit() && c.digitValue() <= 3) { + TChar s = locale->TimeSeparator(c.digitValue()); + TUint val = s; + // some indexes return zero for empty + if (val > 0) + result += QChar(val); + } + + break; + + case 'J': + if (tf == ETime24 && !abbrev_next) + result += QLatin1String("hh"); + else + result += QLatin1Char('h'); + + break; + + case 'H': + if (!abbrev_next) + result += QLatin1String("hh"); + else + result += QLatin1Char('h'); + + break; + + case 'I': + result += QLatin1Char('h'); + break; + + case 'T': + if (!abbrev_next) + result += QLatin1String("mm"); + else + result += QLatin1Char('m'); + + break; + + case 'S': + if (!abbrev_next) + result += QLatin1String("ss"); + else + result += QLatin1Char('s'); + + break; + + case 'B': + // only done for 12h clock + if (tf == ETime24) + break; + + // fallthru to A + case 'A': { + // quickie to get capitalization, can't use s60 string as is because Qt 'hh' format's am/pm logic + TAmPmName ampm = TAmPmName(); + TChar first(ampm[0]); + QString qtampm = QString::fromLatin1(first.IsUpper() ? "AP" : "ap"); + + int pos = locale->AmPmSymbolPosition(); + + if ((minus_mode && pos != ELocaleBefore) || + (plus_mode && pos != ELocaleAfter)) + break; + + if (!abbrev_next && locale->AmPmSpaceBetween()) { + if (pos == ELocaleBefore) + qtampm.append(QLatin1Char(' ')); + else + qtampm.prepend(QLatin1Char(' ')); + } + + result += qtampm; + } + break; + + case '.': { + // decimal sep + TChar s = locale->DecimalSeparator(); + TUint val = s; + if (val > 0) + result += QChar(val); + } + break; + + case 'C': + // six digits in s60, three digits in qt + if (!abbrev_next) { + result += QLatin1String("zzz"); + } else { + // next char is number from 0-6, how many digits to display + ++i; + if (i >= sys_fmt.size()) + break; + + c = sys_fmt.at(i); + + if (c.isDigit()) { + // try to match wanted digits + QChar val(c.digitValue()); + + if (val >= 3) { + result += QLatin1String("zzz"); + } else if (val > 0) { + result += QLatin1Char('z'); + } + } + } + break; + + // these cases fallthru + case '1': + case '2': + case '3': + case '4': + case '5': + + // shouldn't parse these with %F + if (locale_indep_ordering) + break; + + TDateFormat df = locale->DateFormat(); + + const char **locale_dep; + switch (df) { + default: // fallthru to american + case EDateAmerican: + locale_dep = us_locale_dep; + break; + case EDateEuropean: + locale_dep = eu_locale_dep; + break; + case EDateJapanese: + locale_dep = jp_locale_dep; + break; + } + int offset = 0; + if (abbrev_next) + offset += 5; + if (n_mode) + offset += 10; + + result += QLatin1String(locale_dep[offset + (c.digitValue()-1)]); + break; + + case '%': // fallthru percent + // any junk gets copied as is + default: + result += c; + break; + + case 'Z': // Qt doesn't support these :( + case 'X': + case 'W': + break; + } + } else { + // double any single quotes, don't begin escape + if (c.unicode() == '\'') { + // end open escape + if (open_escape) { + result += other; + other.clear(); + result += QLatin1Char('\''); + open_escape = false; + } + + other += c; + } + + // gather chars and escape them in one go if any format chars are found + if (!open_escape && qtformatchars.indexOf(c) != -1) { + result += QLatin1Char('\''); + open_escape = true; + } + other += c; + } + + ++i; + } + + if (!other.isEmpty()) + result += other; + if (open_escape) + result += QLatin1Char('\''); + + return result; +} + +/*! + Retrieves Symbian locale decimal separator. +*/ +static QString symbianDecimalPoint() +{ + TLocale *locale = _s60Locale.GetLocale(); + + TChar decPoint = locale->DecimalSeparator(); + int val = decPoint; + return QChar(val); +} + +/*! + Retrieves Symbian locale group separator. +*/ +static QString symbianGroupSeparator() +{ + TLocale *locale = _s60Locale.GetLocale(); + + TChar grpSep = locale->ThousandsSeparator(); + int val = grpSep; + return QChar(val); +} + +/*! + Retrieves Symbian locale zero digit. +*/ +static QString symbianZeroDigit() +{ + TLocale *locale = _s60Locale.GetLocale(); + + // TDigitType enumeration value returned by TLocale + // will always correspond to zero digit unicode value. + TDigitType digit = locale->DigitType(); + return QChar(digit); +} + +/*! + Retrieves a day name from Symbian locale. The \a day is an integer + from 1 to 7. When \a short_format is true the method returns + the day in short format. Otherwise it returns the day in a long format. +*/ +static QString symbianDayName(int day, bool short_format) +{ + day -= 1; + + if (day < 0 || day > 6) + return QString(); + + if (short_format) { + return qt_TDes2QStringL(TDayNameAbb(TDay(day))); + } else { + return qt_TDes2QStringL(TDayName(TDay(day))); + } +} + +/*! + Retrieves a month name from Symbian locale. The \a month is an integer + from 1 to 12. When \a short_format is true the method returns + the month in short format. Otherwise it returns the month in a long format. +*/ +static QString symbianMonthName(int month, bool short_format) +{ + month -= 1; + if (month < 0 || month > 11) + return QString(); + + if (short_format) { + return qt_TDes2QStringL(TMonthNameAbb(TMonth(month))); + } else { + return qt_TDes2QStringL(TMonthName(TMonth(month))); + } +} + +/*! + Retrieves date format from Symbian locale and + transforms it to Qt format. + + When \a short_format is true the method returns + short date format. Otherwise it returns the long format. +*/ +static QString symbianDateFormat(bool short_format) +{ + TPtrC dateFormat; + + if (short_format) { + dateFormat.Set(ptrGetShortDateFormatSpec(_s60Locale)); + } else { + dateFormat.Set(ptrGetLongDateFormatSpec(_s60Locale)); + } + + return s60ToQtFormat(qt_TDesC2QStringL(dateFormat)); +} + +/*! + Retrieves time format from Symbian locale and + transforms it to Qt format. +*/ +static QString symbianTimeFormat() +{ + return s60ToQtFormat(qt_TDesC2QStringL(ptrGetTimeFormatSpec(_s60Locale))); +} + +/*! + Returns localized string representation of given \a date + formatted with Symbian locale date format. + + If \a short_format is true the format will be a short version. + Otherwise it uses a longer version. +*/ +static QString symbianDateToString(const QDate &date, bool short_format) +{ + int month = date.month() - 1; + int day = date.day() - 1; + int year = date.year(); + + TDateTime dateTime; + dateTime.Set(year, TMonth(month), day, 0, 0, 0, 0); + + TTime timeStr(dateTime); + TBuf buffer; + + TPtrC dateFormat; + if (short_format) { + dateFormat.Set(ptrGetShortDateFormatSpec(_s60Locale)); + } else { + dateFormat.Set(ptrGetLongDateFormatSpec(_s60Locale)); + } + + TRAPD(err, ptrTimeFormatL(timeStr, buffer, dateFormat, *_s60Locale.GetLocale());) + + if (err == KErrNone) + return qt_TDes2QStringL(buffer); + else + return QString(); +} + +/*! + Returns localized string representation of given \a time + formatted with Symbian locale time format. +*/ +static QString symbianTimeToString(const QTime &time) +{ + int hour = time.hour(); + int minute = time.minute(); + int second = time.second(); + int milliseconds = 0; + + TDateTime dateTime; + dateTime.Set(0, TMonth(0), 0, hour, minute, second, milliseconds); + + TTime timeStr(dateTime); + TBuf buffer; + + TRAPD(err, ptrTimeFormatL( + timeStr, + buffer, + ptrGetTimeFormatSpec(_s60Locale), + *_s60Locale.GetLocale()); + ) + + if (err == KErrNone) + return qt_TDes2QStringL(buffer); + else + return QString(); +} + +/*! + Returns the measurement system stored in Symbian locale + + \sa QLocale::MeasurementSystem +*/ +static QLocale::MeasurementSystem symbianMeasurementSystem() +{ + TLocale *locale = _s60Locale.GetLocale(); + + TUnitsFormat unitFormat = locale->UnitsGeneral(); + if (unitFormat == EUnitsImperial) + return QLocale::ImperialSystem; + else + return QLocale::MetricSystem; +} + +QLocale QSystemLocale::fallbackLocale() const +{ + // load system data before query calls + static bool initDone = false; + if (!initDone) { + _s60Locale.LoadSystemSettings(); + + // Initialize platform version dependent function pointers + ptrTimeFormatL = reinterpret_cast + (qt_resolveS60PluginFunc(S60Plugin_TimeFormatL)); + ptrGetTimeFormatSpec = reinterpret_cast + (qt_resolveS60PluginFunc(S60Plugin_GetTimeFormatSpec)); + ptrGetLongDateFormatSpec = reinterpret_cast + (qt_resolveS60PluginFunc(S60Plugin_GetLongDateFormatSpec)); + ptrGetShortDateFormatSpec = reinterpret_cast + (qt_resolveS60PluginFunc(S60Plugin_GetShortDateFormatSpec)); + if (!ptrTimeFormatL) + ptrTimeFormatL = &defaultTimeFormatL; + if (!ptrGetTimeFormatSpec) + ptrGetTimeFormatSpec = &defaultFormatSpec; + if (!ptrGetLongDateFormatSpec) + ptrGetLongDateFormatSpec = &defaultFormatSpec; + if (!ptrGetShortDateFormatSpec) + ptrGetShortDateFormatSpec = &defaultFormatSpec; + } + + TLanguage lang = User::Language(); + QString locale = symbianLocaleName(lang); + return QLocale(locale); +} + +/*! + Generic query method for locale data. Provides indirection. + Denotes the \a type of the query + with \a in as input data depending on the query. + + \sa QSystemLocale::QueryType +*/ +QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const +{ + switch(type) { + case DecimalPoint: + return symbianDecimalPoint(); + case GroupSeparator: + return symbianGroupSeparator(); + + case ZeroDigit: + return symbianZeroDigit(); + + case DayNameLong: + case DayNameShort: + return symbianDayName(in.toInt(), (type == DayNameShort) ); + + case MonthNameLong: + case MonthNameShort: + return symbianMonthName(in.toInt(), (type == MonthNameShort) ); + + case DateFormatLong: + case DateFormatShort: + return symbianDateFormat( (type == DateFormatShort) ); + case TimeFormatLong: + case TimeFormatShort: + return symbianTimeFormat(); + case DateTimeFormatLong: + case DateTimeFormatShort: + return symbianDateFormat( (type == DateTimeFormatShort) ) + QLatin1Char(' ') + symbianTimeFormat(); + case DateToStringShort: + case DateToStringLong: + return symbianDateToString(in.toDate(), (type == DateToStringShort) ); + case TimeToStringShort: + case TimeToStringLong: + return symbianTimeToString(in.toTime()); + case DateTimeToStringShort: + case DateTimeToStringLong: { + const QDateTime dt = in.toDateTime(); + return symbianDateToString(dt.date(), (type == DateTimeToStringShort) ) + + QLatin1Char(' ') + symbianTimeToString(dt.time()); + } + case MeasurementSystem: + return static_cast(symbianMeasurementSystem()); + case LanguageId: + case CountryId: { + TLanguage language = User::Language(); + QString locale = symbianLocaleName(language); + QLocale::Language lang; + QLocale::Country cntry; + getLangAndCountry(locale, lang, cntry); + if (type == LanguageId) + return lang; + // few iso codes have no country and will use this + if (cntry == QLocale::AnyCountry) + return fallbackLocale().country(); + + return cntry; + } + case NegativeSign: + case PositiveSign: + case AMText: + case PMText: + break; + default: + break; + } + return QVariant(); +} + +QT_END_NAMESPACE diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index 45e92bf..c2381ce 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -65,6 +65,7 @@ SOURCES += \ tools/qvector.cpp \ tools/qvsnprintf.cpp +symbian:SOURCES+=tools/qlocale_symbian.cpp #zlib support contains(QT_CONFIG, zlib) { -- cgit v0.12 From ea4960511135786e36480b6841ed06bdb3bbc1d6 Mon Sep 17 00:00:00 2001 From: axis Date: Mon, 25 May 2009 12:53:44 +0200 Subject: Revert "Enable symbol visibility when compiling with RVCT." This reverts commit c33abd370470a0097cc1fbb858e1218ba110e0df. We will need this patch in the end, but right now it's causing too much trouble with the compiler. To return soon! --- mkspecs/common/symbian/symbian.conf | 2 +- src/corelib/global/qglobal.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mkspecs/common/symbian/symbian.conf b/mkspecs/common/symbian/symbian.conf index 2fe93d2..968a6bc 100644 --- a/mkspecs/common/symbian/symbian.conf +++ b/mkspecs/common/symbian/symbian.conf @@ -29,7 +29,7 @@ QMAKE_CFLAGS_YACC = -Wno-unused -Wno-parentheses QMAKE_CXX = g++ QMAKE_CXXFLAGS = $$QMAKE_CFLAGS QMAKE_CXXFLAGS.CW = -QMAKE_CXXFLAGS.ARMCC = --visibility_inlines_hidden +QMAKE_CXXFLAGS.ARMCC = --no_hide_all QMAKE_CXXFLAGS_DEPS = $$QMAKE_CFLAGS_DEPS QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON QMAKE_CXXFLAGS_WARN_OFF = $$QMAKE_CFLAGS_WARN_OFF diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 15b2d53..27aaac1 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -1118,7 +1118,7 @@ class QDataStream; #ifndef Q_DECL_EXPORT # ifdef Q_OS_WIN # define Q_DECL_EXPORT __declspec(dllexport) -# elif defined(Q_CC_NOKIAX86) || defined(Q_CC_RVCT) +# elif defined(Q_CC_NOKIAX86) # define Q_DECL_EXPORT __declspec(dllexport) # elif defined(QT_VISIBILITY_AVAILABLE) # define Q_DECL_EXPORT __attribute__((visibility("default"))) @@ -1130,7 +1130,7 @@ class QDataStream; #ifndef Q_DECL_IMPORT # if defined(Q_OS_WIN) # define Q_DECL_IMPORT __declspec(dllimport) -# elif defined(Q_CC_NOKIAX86) || defined(Q_CC_RVCT) +# elif defined(Q_CC_NOKIAX86) # define Q_DECL_IMPORT __declspec(dllimport) # else # define Q_DECL_IMPORT -- cgit v0.12