From a0c4a712263dbacd2c8d95da64e00bd213d05cbf Mon Sep 17 00:00:00 2001 From: El Mehdi Fekari Date: Fri, 8 Mar 2013 16:08:23 +0100 Subject: [PATCH] Inital port of QSystemLocale on BlackBerry 10 Change-Id: Ic177e2867d9fa3dbaec221766964ac28656a2662 Reviewed-by: Rafael Roquetto --- src/corelib/tools/qlocale_blackberry.cpp | 313 +++++++++++++++++++++++ src/corelib/tools/qlocale_blackberry.h | 99 +++++++ src/corelib/tools/qlocale_p.h | 26 -- src/corelib/tools/qlocale_unix.cpp | 101 -------- src/corelib/tools/tools.pri | 4 + 5 files changed, 416 insertions(+), 127 deletions(-) create mode 100644 src/corelib/tools/qlocale_blackberry.cpp create mode 100644 src/corelib/tools/qlocale_blackberry.h diff --git a/src/corelib/tools/qlocale_blackberry.cpp b/src/corelib/tools/qlocale_blackberry.cpp new file mode 100644 index 0000000000..01576dd732 --- /dev/null +++ b/src/corelib/tools/qlocale_blackberry.cpp @@ -0,0 +1,313 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlocale_blackberry.h" +#include "qlocale_p.h" + +#include "qdatetime.h" + +#include "qcoreapplication.h" +#include "private/qcore_unix_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_SYSTEMLOCALE + +static const char ppsUomPath[] = "/pps/services/locale/uom"; +static const char ppsRegionLocalePath[] = "/pps/services/locale/settings"; +static const char ppsLanguageLocalePath[] = "/pps/services/confstr/_CS_LOCALE"; +static const char ppsHourFormatPath[] = "/pps/system/settings"; + +static const size_t ppsBufferSize = 256; + +QBBSystemLocaleData::QBBSystemLocaleData() + : languageNotifier(0) + , regionNotifier(0) + , measurementNotifier(0) + , hourNotifier(0) + , languageFd(-1) + , regionFd(-1) + , measurementFd(-1) + , hourFd(-1) +{ + // we cannot call this directly, because by the time this constructor is + // called, the event dispatcher has not yet been created, causing the + // subsequent call to QSocketNotifier constructor to fail. + QMetaObject::invokeMethod(this, "installSocketNotifiers", Qt::QueuedConnection); + + readLangageLocale(); + readRegionLocale(); + readMeasurementSystem(); + readHourFormat(); +} + +QBBSystemLocaleData::~QBBSystemLocaleData() +{ + if (measurementFd != -1) + qt_safe_close(measurementFd); + + if (languageFd != -1) + qt_safe_close(languageFd); + + if (regionFd != -1) + qt_safe_close(regionFd); + + if (hourFd != -1) + qt_safe_close(hourFd); +} + +uint QBBSystemLocaleData::measurementSystem() +{ + return m_measurementSystem; +} + +QVariant QBBSystemLocaleData::timeFormat(QLocale::FormatType formatType) +{ + return getCorrectFormat(regionLocale().timeFormat(formatType), formatType); +} + +QVariant QBBSystemLocaleData::dateTimeFormat(QLocale::FormatType formatType) +{ + return getCorrectFormat(regionLocale().dateTimeFormat(formatType), formatType); +} + +QLocale QBBSystemLocaleData::languageLocale() +{ + if (!lc_langage.isEmpty()) + return QLocale(QLatin1String(lc_langage)); + + return QLocale::c(); +} + +QLocale QBBSystemLocaleData::regionLocale() +{ + if (!lc_region.isEmpty()) + return QLocale(QLatin1String(lc_region)); + + return QLocale::c(); +} + +void QBBSystemLocaleData::installSocketNotifiers() +{ + Q_ASSERT(!languageNotifier || !regionNotifier || !measurementNotifier || !hourNotifier); + Q_ASSERT(QCoreApplication::instance()); + + languageNotifier = new QSocketNotifier(languageFd, QSocketNotifier::Read, this); + QObject::connect(languageNotifier, SIGNAL(activated(int)), this, SLOT(readLangageLocale())); + + regionNotifier = new QSocketNotifier(regionFd, QSocketNotifier::Read, this); + QObject::connect(regionNotifier, SIGNAL(activated(int)), this, SLOT(readRegionLocale())); + + measurementNotifier = new QSocketNotifier(measurementFd, QSocketNotifier::Read, this); + QObject::connect(measurementNotifier, SIGNAL(activated(int)), this, SLOT(readMeasurementSystem())); + + hourNotifier = new QSocketNotifier(hourFd, QSocketNotifier::Read, this); + QObject::connect(hourNotifier, SIGNAL(activated(int)), this, SLOT(readHourFormat())); +} + +void QBBSystemLocaleData::readLangageLocale() +{ + lc_langage = readPpsValue(ppsLanguageLocalePath, "_CS_LOCALE", &languageFd); +} + +void QBBSystemLocaleData::readRegionLocale() +{ + lc_region = readPpsValue(ppsRegionLocalePath, "region", ®ionFd); +} + +void QBBSystemLocaleData::readMeasurementSystem() +{ + QByteArray measurement = readPpsValue(ppsUomPath, "uom", &measurementFd); + m_measurementSystem = (qstrcmp(measurement, "imperial") == 0) ? QLocale::ImperialSystem : QLocale::MetricSystem; +} + +void QBBSystemLocaleData::readHourFormat() +{ + QByteArray hourFormat = readPpsValue(ppsHourFormatPath, "hourFormat", &hourFd); + is24HourFormat = (qstrcmp(hourFormat, "24") == 0); +} + +QByteArray QBBSystemLocaleData::readPpsValue(const char *ppsPath, const char *ppsObject, int *ppsFd) +{ + QByteArray result; + if (!ppsPath || !ppsObject) + return result; + + *ppsFd = qt_safe_open(ppsPath, O_RDONLY); + if (*ppsFd == -1) { + qWarning("Failed to open Locale pps, errno=%d", errno); + return result; + } + + char buffer[ppsBufferSize]; + + int bytes = qt_safe_read(*ppsFd, buffer, ppsBufferSize - 1); + if (bytes == -1) { + qWarning("Failed to read Locale pps, errno=%d", errno); + return result; + } + // ensure data is null terminated + buffer[bytes] = '\0'; + + pps_decoder_t ppsDecoder; + pps_decoder_initialize(&ppsDecoder, 0); + if (pps_decoder_parse_pps_str(&ppsDecoder, buffer) == PPS_DECODER_OK) { + pps_decoder_push(&ppsDecoder, 0); + const char *ppsBuff; + if (pps_decoder_get_string(&ppsDecoder, ppsObject, &ppsBuff) == PPS_DECODER_OK) { + result = ppsBuff; + } else { + int val; + if (pps_decoder_get_int(&ppsDecoder, ppsObject, &val) == PPS_DECODER_OK) + result = QByteArray::number(val); + } + } + + pps_decoder_cleanup(&ppsDecoder); + + return result; +} + +QString QBBSystemLocaleData::getCorrectFormat(const QString &baseFormat, QLocale::FormatType formatType) +{ + QString format = baseFormat; + if (is24HourFormat) { + if (format.contains(QStringLiteral("AP"), Qt::CaseInsensitive)) { + format.replace(QStringLiteral("AP"), QStringLiteral(""), Qt::CaseInsensitive); + format.replace(QStringLiteral("h"), QStringLiteral("H"), Qt::CaseSensitive); + } + + } else { + + if (!format.contains(QStringLiteral("AP"), Qt::CaseInsensitive)) { + format.contains(QStringLiteral("HH"), Qt::CaseSensitive) ? + format.replace(QStringLiteral("HH"), QStringLiteral("hh"), Qt::CaseSensitive) : + format.replace(QStringLiteral("H"), QStringLiteral("h"), Qt::CaseSensitive); + + formatType == QLocale::LongFormat ? format.append(QStringLiteral(" AP t")) : format.append(QStringLiteral(" AP")); + } + } + + return format; +} + +Q_GLOBAL_STATIC(QBBSystemLocaleData, bbSysLocaleData) + +QLocale QSystemLocale::fallbackUiLocale() const +{ + return bbSysLocaleData()->languageLocale(); +} + +QVariant QSystemLocale::query(QueryType type, QVariant in) const +{ + QBBSystemLocaleData *d = bbSysLocaleData(); + + QReadLocker locker(&d->lock); + + const QLocale &lc_language = d->languageLocale(); + const QLocale &lc_region = d->regionLocale(); + + switch (type) { + case DecimalPoint: + return lc_region.decimalPoint(); + case GroupSeparator: + return lc_region.groupSeparator(); + case NegativeSign: + return lc_region.negativeSign(); + case PositiveSign: + return lc_region.positiveSign(); + case DateFormatLong: + return lc_region.dateFormat(QLocale::LongFormat); + case DateFormatShort: + return lc_region.dateFormat(QLocale::ShortFormat); + case TimeFormatLong: + return d->timeFormat(QLocale::LongFormat); + case TimeFormatShort: + return d->timeFormat(QLocale::ShortFormat); + case DateTimeFormatLong: + return d->dateTimeFormat(QLocale::LongFormat); + case DateTimeFormatShort: + return d->dateTimeFormat(QLocale::ShortFormat); + case DayNameLong: + return lc_language.dayName(in.toInt(), QLocale::LongFormat); + case DayNameShort: + return lc_language.dayName(in.toInt(), QLocale::ShortFormat); + case MonthNameLong: + return lc_language.monthName(in.toInt(), QLocale::LongFormat); + case MonthNameShort: + return lc_language.monthName(in.toInt(), QLocale::ShortFormat); + case DateToStringLong: + return lc_region.toString(in.toDate(), QLocale::LongFormat); + case DateToStringShort: + return lc_region.toString(in.toDate(), QLocale::ShortFormat); + case TimeToStringLong: + return lc_region.toString(in.toTime(), QLocale::LongFormat); + case TimeToStringShort: + return lc_region.toString(in.toTime(), QLocale::ShortFormat); + case DateTimeToStringShort: + return lc_region.toString(in.toDateTime(), d->dateTimeFormat(QLocale::ShortFormat).toString()); + case DateTimeToStringLong: + return lc_region.toString(in.toDateTime(), d->dateTimeFormat(QLocale::LongFormat).toString()); + case MeasurementSystem: + return d->measurementSystem(); + case ZeroDigit: + return lc_region.zeroDigit(); + case CountryId: + return lc_region.country(); + case LanguageId: + return lc_language.language(); + case AMText: + return lc_language.amText(); + case PMText: + return lc_language.pmText(); + default: + break; + } + return QVariant(); +} + +#endif + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qlocale_blackberry.h b/src/corelib/tools/qlocale_blackberry.h new file mode 100644 index 0000000000..8e9560d6c1 --- /dev/null +++ b/src/corelib/tools/qlocale_blackberry.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOCALE_BLACKBERRY_H +#define QLOCALE_BLACKBERRY_H + +#include "qsocketnotifier.h" +#include "qreadwritelock.h" +#include "qlocale.h" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_SYSTEMLOCALE + +class QBBSystemLocaleData : public QObject +{ + Q_OBJECT + +public: + QBBSystemLocaleData(); + virtual ~QBBSystemLocaleData(); + uint measurementSystem(); + QVariant timeFormat(QLocale::FormatType); + QVariant dateTimeFormat(QLocale::FormatType); + QLocale languageLocale(); + QLocale regionLocale(); + + QReadWriteLock lock; + +public Q_SLOTS: + void installSocketNotifiers(); + void readLangageLocale(); + void readRegionLocale(); + void readMeasurementSystem(); + void readHourFormat(); + +private: + QByteArray readPpsValue(const char* ppsPath, const char* ppsObject, int* ppsFd); + QString getCorrectFormat(const QString &baseFormat, QLocale::FormatType typeFormat); + + QByteArray lc_langage; + QByteArray lc_region; + uint m_measurementSystem; + bool is24HourFormat; + + QSocketNotifier *languageNotifier; + QSocketNotifier *regionNotifier; + QSocketNotifier *measurementNotifier; + QSocketNotifier *hourNotifier; + + int languageFd; + int regionFd; + int measurementFd; + int hourFd; +}; +#endif // QT_NO_SYSTEMLOCALE + +QT_END_NAMESPACE + +#endif // QLOCALE_BLACKBERRY_H + diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h index 3c3d7c7054..ff44dcc163 100644 --- a/src/corelib/tools/qlocale_p.h +++ b/src/corelib/tools/qlocale_p.h @@ -59,10 +59,6 @@ #include "qlocale.h" -#if defined(Q_OS_BLACKBERRY) -#include "qsocketnotifier.h" -#endif - QT_BEGIN_NAMESPACE #ifndef QT_NO_SYSTEMLOCALE @@ -377,28 +373,6 @@ inline char QLocalePrivate::digitToCLocale(QChar in) const return 0; } -#if defined(Q_OS_BLACKBERRY) -class QQNXLocaleData: public QObject -{ - Q_OBJECT -public: - QQNXLocaleData(); - virtual ~QQNXLocaleData(); - -public Q_SLOTS: - void updateMeasurementSystem(); - void installSocketNotifier(); - -private: - void initialize(); - -public: - uint ppsMeasurement; - QSocketNotifier *ppsNotifier; - int ppsFd; -}; -#endif - QString qt_readEscapedFormatString(const QString &format, int *idx); bool qt_splitLocaleName(const QString &name, QString &lang, QString &script, QString &cntry); int qt_repeatCount(const QString &s, int i); diff --git a/src/corelib/tools/qlocale_unix.cpp b/src/corelib/tools/qlocale_unix.cpp index fb9e3f1a8b..4e443cd79b 100644 --- a/src/corelib/tools/qlocale_unix.cpp +++ b/src/corelib/tools/qlocale_unix.cpp @@ -47,99 +47,8 @@ #include "qvariant.h" #include "qreadwritelock.h" -#if defined(Q_OS_BLACKBERRY) -#include -#include - -#include -#include -#include -#endif - QT_BEGIN_NAMESPACE -#if defined(Q_OS_BLACKBERRY) -static const char ppsServicePath[] = "/pps/services/locale/uom"; -static const size_t ppsBufferSize = 256; - -QQNXLocaleData::QQNXLocaleData() - :ppsNotifier(0) - ,ppsFd(-1) -{ - initialize(); - - // we cannot call this directly, because by the time this constructor is - // called, the event dispatcher has not yet been created, causing the - // subsequent call to QSocketNotifier constructor to fail. - QMetaObject::invokeMethod(this, "installSocketNotifier", Qt::QueuedConnection); -} - -QQNXLocaleData::~QQNXLocaleData() -{ - if (ppsFd != -1) - qt_safe_close(ppsFd); -} - -void QQNXLocaleData::updateMeasurementSystem() -{ - char buffer[ppsBufferSize]; - - errno = 0; - int bytes = qt_safe_read(ppsFd, buffer, ppsBufferSize - 1); - if (bytes == -1) { - qWarning("Failed to read Locale pps, errno=%d", errno); - return; - } - // ensure data is null terminated - buffer[bytes] = '\0'; - - pps_decoder_t ppsDecoder; - pps_decoder_initialize(&ppsDecoder, 0); - if (pps_decoder_parse_pps_str(&ppsDecoder, buffer) == PPS_DECODER_OK) { - pps_decoder_push(&ppsDecoder, 0); - const char *measurementBuff; - if (pps_decoder_get_string(&ppsDecoder, "uom", &measurementBuff) == PPS_DECODER_OK) { - if (qstrcmp(measurementBuff, "imperial") == 0) { - pps_decoder_cleanup(&ppsDecoder); - ppsMeasurement = QLocale::ImperialSystem; - return; - } - } - } - - pps_decoder_cleanup(&ppsDecoder); - ppsMeasurement = QLocale::MetricSystem; -} - -void QQNXLocaleData::initialize() -{ - errno = 0; - ppsFd = qt_safe_open(ppsServicePath, O_RDONLY); - if (ppsFd == -1) { - qWarning("Failed to open Locale pps, errno=%d", errno); - return; - } - - updateMeasurementSystem(); -} - -void QQNXLocaleData::installSocketNotifier() -{ - if (!QCoreApplication::instance() || ppsFd == -1) { - qWarning("QQNXLocaleData: Failed to create socket notifier, locale updates may not work."); - return; - } - - if (ppsNotifier) { - qWarning("QQNXLocaleData: socket notifier already created."); - return; - } - - ppsNotifier = new QSocketNotifier(ppsFd, QSocketNotifier::Read, this); - QObject::connect(ppsNotifier, SIGNAL(activated(int)), this, SLOT(updateMeasurementSystem())); -} -#endif - #ifndef QT_NO_SYSTEMLOCALE struct QSystemLocaleData { @@ -194,11 +103,7 @@ void QSystemLocaleData::readEnvironment() lc_messages = QLocale(QString::fromLatin1(lc_messages_var)); } - Q_GLOBAL_STATIC(QSystemLocaleData, qSystemLocaleData) -#if defined(Q_OS_BLACKBERRY) - Q_GLOBAL_STATIC(QQNXLocaleData, qqnxLocaleData) -#endif #endif @@ -230,9 +135,6 @@ QLocale QSystemLocale::fallbackUiLocale() const QVariant QSystemLocale::query(QueryType type, QVariant in) const { QSystemLocaleData *d = qSystemLocaleData(); -#if defined(Q_OS_BLACKBERRY) - QQNXLocaleData *qnxd = qqnxLocaleData(); -#endif if (type == LocaleChanged) { d->readEnvironment(); @@ -320,9 +222,6 @@ QVariant QSystemLocale::query(QueryType type, QVariant in) const return QLocale::MetricSystem; if (meas_locale.compare(QLatin1String("Other"), Qt::CaseInsensitive) == 0) return QLocale::MetricSystem; -#if defined(Q_OS_BLACKBERRY) - return qnxd->ppsMeasurement; -#endif return QVariant((int)QLocale(meas_locale).measurementSystem()); } case UILanguages: { diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index c6e12c59eb..bb152987e6 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -106,6 +106,10 @@ SOURCES += \ SOURCES += tools/qelapsedtimer_mac.cpp OBJECTIVE_SOURCES += tools/qlocale_mac.mm } +else:blackberry { + SOURCES += tools/qelapsedtimer_unix.cpp tools/qlocale_blackberry.cpp + HEADERS += tools/qlocale_blackberry.h +} else:unix:SOURCES += tools/qelapsedtimer_unix.cpp tools/qlocale_unix.cpp else:win32:SOURCES += tools/qelapsedtimer_win.cpp tools/qlocale_win.cpp else:integrity:SOURCES += tools/qelapsedtimer_unix.cpp tools/qlocale_unix.cpp