0a743324efe2ee0033250536a6113380e88d00ae
[profile/ivi/qtbase.git] / src / corelib / tools / qlocale_mac.mm
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 QtCore 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 "qlocale_p.h"
43
44 #include "qstringlist.h"
45 #include "qvariant.h"
46 #include "qdatetime.h"
47
48 #if !defined(QWS) && defined(Q_OS_MAC)
49 #   include "private/qcore_mac_p.h"
50 #   include <CoreFoundation/CoreFoundation.h>
51 #endif
52
53 QT_BEGIN_NAMESPACE
54
55 /******************************************************************************
56 ** Wrappers for Mac locale system functions
57 */
58
59 static QByteArray envVarLocale()
60 {
61     static QByteArray lang = 0;
62 #ifdef Q_OS_UNIX
63     lang = qgetenv("LC_ALL");
64     if (lang.isEmpty())
65         lang = qgetenv("LC_NUMERIC");
66     if (lang.isEmpty())
67 #endif
68         lang = qgetenv("LANG");
69     return lang;
70 }
71
72 static QByteArray getMacLocaleName()
73 {
74     QByteArray result = envVarLocale();
75
76     QString lang, script, cntry;
77     if (result.isEmpty()
78         || (result != "C" && !qt_splitLocaleName(QString::fromLocal8Bit(result), lang, script, cntry))) {
79         QCFType<CFLocaleRef> l = CFLocaleCopyCurrent();
80         CFStringRef locale = CFLocaleGetIdentifier(l);
81         result = QCFString::toQString(locale).toUtf8();
82     }
83     return result;
84 }
85
86 static QString macMonthName(int month, bool short_format)
87 {
88     month -= 1;
89     if (month < 0 || month > 11)
90         return QString();
91
92     QCFType<CFDateFormatterRef> formatter
93         = CFDateFormatterCreate(0, QCFType<CFLocaleRef>(CFLocaleCopyCurrent()),
94                                 kCFDateFormatterNoStyle,  kCFDateFormatterNoStyle);
95     QCFType<CFArrayRef> values
96         = static_cast<CFArrayRef>(CFDateFormatterCopyProperty(formatter,
97                                   short_format ? kCFDateFormatterShortMonthSymbols
98                                                : kCFDateFormatterMonthSymbols));
99     if (values != 0) {
100         CFStringRef cfstring = static_cast<CFStringRef>(CFArrayGetValueAtIndex(values, month));
101         return QCFString::toQString(cfstring);
102     }
103     return QString();
104 }
105
106 static QString macDayName(int day, bool short_format)
107 {
108     if (day < 1 || day > 7)
109         return QString();
110
111     QCFType<CFDateFormatterRef> formatter
112         = CFDateFormatterCreate(0, QCFType<CFLocaleRef>(CFLocaleCopyCurrent()),
113                                 kCFDateFormatterNoStyle,  kCFDateFormatterNoStyle);
114     QCFType<CFArrayRef> values = static_cast<CFArrayRef>(CFDateFormatterCopyProperty(formatter,
115                                             short_format ? kCFDateFormatterShortWeekdaySymbols
116                                                          : kCFDateFormatterWeekdaySymbols));
117     if (values != 0) {
118         CFStringRef cfstring = static_cast<CFStringRef>(CFArrayGetValueAtIndex(values, day % 7));
119         return QCFString::toQString(cfstring);
120     }
121     return QString();
122 }
123
124 static QString macDateToString(const QDate &date, bool short_format)
125 {
126     CFGregorianDate macGDate;
127     macGDate.year = date.year();
128     macGDate.month = date.month();
129     macGDate.day = date.day();
130     macGDate.hour = 0;
131     macGDate.minute = 0;
132     macGDate.second = 0.0;
133     QCFType<CFDateRef> myDate
134         = CFDateCreate(0, CFGregorianDateGetAbsoluteTime(macGDate,
135                                                          QCFType<CFTimeZoneRef>(CFTimeZoneCopyDefault())));
136     QCFType<CFLocaleRef> mylocale = CFLocaleCopyCurrent();
137     CFDateFormatterStyle style = short_format ? kCFDateFormatterShortStyle : kCFDateFormatterLongStyle;
138     QCFType<CFDateFormatterRef> myFormatter
139         = CFDateFormatterCreate(kCFAllocatorDefault,
140                                 mylocale, style,
141                                 kCFDateFormatterNoStyle);
142     return QCFString(CFDateFormatterCreateStringWithDate(0, myFormatter, myDate));
143 }
144
145 static QString macTimeToString(const QTime &time, bool short_format)
146 {
147     CFGregorianDate macGDate;
148     // Assume this is local time and the current date
149     QDate dt = QDate::currentDate();
150     macGDate.year = dt.year();
151     macGDate.month = dt.month();
152     macGDate.day = dt.day();
153     macGDate.hour = time.hour();
154     macGDate.minute = time.minute();
155     macGDate.second = time.second();
156     QCFType<CFDateRef> myDate
157         = CFDateCreate(0, CFGregorianDateGetAbsoluteTime(macGDate,
158                                                          QCFType<CFTimeZoneRef>(CFTimeZoneCopyDefault())));
159
160     QCFType<CFLocaleRef> mylocale = CFLocaleCopyCurrent();
161     CFDateFormatterStyle style = short_format ? kCFDateFormatterShortStyle :  kCFDateFormatterLongStyle;
162     QCFType<CFDateFormatterRef> myFormatter = CFDateFormatterCreate(kCFAllocatorDefault,
163                                                                     mylocale,
164                                                                     kCFDateFormatterNoStyle,
165                                                                     style);
166     return QCFString(CFDateFormatterCreateStringWithDate(0, myFormatter, myDate));
167 }
168
169 static QString macToQtFormat(const QString &sys_fmt)
170 {
171     QString result;
172     int i = 0;
173
174     while (i < sys_fmt.size()) {
175         if (sys_fmt.at(i).unicode() == '\'') {
176             QString text = qt_readEscapedFormatString(sys_fmt, &i);
177             if (text == QLatin1String("'"))
178                 result += QLatin1String("''");
179             else
180                 result += QLatin1Char('\'') + text + QLatin1Char('\'');
181             continue;
182         }
183
184         QChar c = sys_fmt.at(i);
185         int repeat = qt_repeatCount(sys_fmt, i);
186
187         switch (c.unicode()) {
188             case 'G': // Qt doesn't support these :(
189             case 'Y':
190             case 'D':
191             case 'F':
192             case 'w':
193             case 'W':
194             case 'g':
195                 break;
196
197             case 'u': // extended year - use 'y'
198                 if (repeat < 4)
199                     result += QLatin1String("yy");
200                 else
201                     result += QLatin1String("yyyy");
202                 break;
203             case 'S': // fractional second
204                 if (repeat < 3)
205                     result += QLatin1Char('z');
206                 else
207                     result += QLatin1String("zzz");
208                 break;
209             case 'E':
210                 if (repeat <= 3)
211                     result += QLatin1String("ddd");
212                 else
213                     result += QLatin1String("dddd");
214                 break;
215             case 'e':
216                 if (repeat >= 2)
217                     result += QLatin1String("dd");
218                 else
219                     result += QLatin1Char('d');
220                 break;
221             case 'a':
222                 result += QLatin1String("AP");
223                 break;
224             case 'k':
225                 result += QString(repeat, QLatin1Char('H'));
226                 break;
227             case 'K':
228                 result += QString(repeat, QLatin1Char('h'));
229                 break;
230             case 'z':
231             case 'Z':
232             case 'v':
233                 result += QLatin1Char('t');
234                 break;
235             default:
236                 result += QString(repeat, c);
237                 break;
238         }
239
240         i += repeat;
241     }
242
243     return result;
244 }
245
246 QString getMacDateFormat(CFDateFormatterStyle style)
247 {
248     QCFType<CFLocaleRef> l = CFLocaleCopyCurrent();
249     QCFType<CFDateFormatterRef> formatter = CFDateFormatterCreate(kCFAllocatorDefault,
250                                                                   l, style, kCFDateFormatterNoStyle);
251     return macToQtFormat(QCFString::toQString(CFDateFormatterGetFormat(formatter)));
252 }
253
254 static QString getMacTimeFormat(CFDateFormatterStyle style)
255 {
256     QCFType<CFLocaleRef> l = CFLocaleCopyCurrent();
257     QCFType<CFDateFormatterRef> formatter = CFDateFormatterCreate(kCFAllocatorDefault,
258                                                                   l, kCFDateFormatterNoStyle, style);
259     return macToQtFormat(QCFString::toQString(CFDateFormatterGetFormat(formatter)));
260 }
261
262 static QString getCFLocaleValue(CFStringRef key)
263 {
264     QCFType<CFLocaleRef> locale = CFLocaleCopyCurrent();
265     CFTypeRef value = CFLocaleGetValue(locale, key);
266     return QCFString::toQString(CFStringRef(static_cast<CFTypeRef>(value)));
267 }
268
269 static QLocale::MeasurementSystem macMeasurementSystem()
270 {
271     QCFType<CFLocaleRef> locale = CFLocaleCopyCurrent();
272     CFStringRef system = static_cast<CFStringRef>(CFLocaleGetValue(locale, kCFLocaleMeasurementSystem));
273     if (QCFString::toQString(system) == QLatin1String("Metric")) {
274         return QLocale::MetricSystem;
275     } else {
276         return QLocale::ImperialSystem;
277     }
278 }
279
280
281 static quint8 macFirstDayOfWeek()
282 {
283     QCFType<CFCalendarRef> calendar = CFCalendarCopyCurrent();
284     quint8 day = static_cast<quint8>(CFCalendarGetFirstWeekday(calendar))-1;
285     if (day == 0)
286         day = 7;
287     return day;
288 }
289
290 static QString macCurrencySymbol(QLocale::CurrencySymbolFormat format)
291 {
292     QCFType<CFLocaleRef> locale = CFLocaleCopyCurrent();
293     switch (format) {
294     case QLocale::CurrencyIsoCode:
295         return QCFString::toQString(static_cast<CFStringRef>(CFLocaleGetValue(locale, kCFLocaleCurrencyCode)));
296     case QLocale::CurrencySymbol:
297         return QCFString::toQString(static_cast<CFStringRef>(CFLocaleGetValue(locale, kCFLocaleCurrencySymbol)));
298     case QLocale::CurrencyDisplayName: {
299         CFStringRef code = static_cast<CFStringRef>(CFLocaleGetValue(locale, kCFLocaleCurrencyCode));
300         QCFType<CFStringRef> value = CFLocaleCopyDisplayNameForPropertyValue(locale, kCFLocaleCurrencyCode, code);
301         return QCFString::toQString(value);
302     }
303     default:
304         break;
305     }
306     return QString();
307 }
308
309 #ifndef QT_NO_SYSTEMLOCALE
310 static QString macFormatCurrency(const QSystemLocale::CurrencyToStringArgument &arg)
311 {
312     QCFType<CFNumberRef> value;
313     switch (arg.value.type()) {
314     case QVariant::Int:
315     case QVariant::UInt: {
316         int v = arg.value.toInt();
317         value = CFNumberCreate(NULL, kCFNumberIntType, &v);
318         break;
319     }
320     case QVariant::Double: {
321         double v = arg.value.toDouble();
322         value = CFNumberCreate(NULL, kCFNumberDoubleType, &v);
323         break;
324     }
325     case QVariant::LongLong:
326     case QVariant::ULongLong: {
327         qint64 v = arg.value.toLongLong();
328         value = CFNumberCreate(NULL, kCFNumberLongLongType, &v);
329         break;
330     }
331     default:
332         return QString();
333     }
334
335     QCFType<CFLocaleRef> locale = CFLocaleCopyCurrent();
336     QCFType<CFNumberFormatterRef> currencyFormatter =
337             CFNumberFormatterCreate(NULL, locale, kCFNumberFormatterCurrencyStyle);
338     if (!arg.symbol.isEmpty()) {
339         CFNumberFormatterSetProperty(currencyFormatter, kCFNumberFormatterCurrencySymbol,
340                                      QCFString::toCFStringRef(arg.symbol));
341     }
342     QCFType<CFStringRef> result = CFNumberFormatterCreateStringWithNumber(NULL, currencyFormatter, value);
343     return QCFString::toQString(result);
344 }
345
346 static QVariant macQuoteString(QSystemLocale::QueryType type, const QStringRef &str)
347 {
348 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
349     if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_6)
350         return QVariant();
351
352     QString begin, end;
353     QCFType<CFLocaleRef> locale = CFLocaleCopyCurrent();
354     switch (type) {
355     case QSystemLocale::StringToStandardQuotation:
356         begin = QCFString::toQString(static_cast<CFStringRef>(CFLocaleGetValue(locale, kCFLocaleQuotationBeginDelimiterKey)));
357         end = QCFString::toQString(static_cast<CFStringRef>(CFLocaleGetValue(locale, kCFLocaleQuotationEndDelimiterKey)));
358         return QString(begin % str % end);
359     case QSystemLocale::StringToAlternateQuotation:
360         begin = QCFString::toQString(static_cast<CFStringRef>(CFLocaleGetValue(locale, kCFLocaleAlternateQuotationBeginDelimiterKey)));
361         end = QCFString::toQString(static_cast<CFStringRef>(CFLocaleGetValue(locale, kCFLocaleAlternateQuotationEndDelimiterKey)));
362         return QString(begin % str % end);
363      default:
364         break;
365     }
366 #endif
367     return QVariant();
368 }
369 #endif //QT_NO_SYSTEMLOCALE
370
371 #ifndef QT_NO_SYSTEMLOCALE
372
373 QLocale QSystemLocale::fallbackUiLocale() const
374 {
375     return QLocale(QString::fromUtf8(getMacLocaleName().constData()));
376 }
377
378 QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const
379 {
380     switch(type) {
381 //     case Name:
382 //         return getMacLocaleName();
383     case DecimalPoint: {
384         QString value = getCFLocaleValue(kCFLocaleDecimalSeparator);
385         return value.isEmpty() ? QVariant() : value;
386     }
387     case GroupSeparator: {
388         QString value = getCFLocaleValue(kCFLocaleGroupingSeparator);
389         return value.isEmpty() ? QVariant() : value;
390     }
391     case DateFormatLong:
392     case DateFormatShort:
393         return getMacDateFormat(type == DateFormatShort
394                                 ? kCFDateFormatterShortStyle
395                                 : kCFDateFormatterLongStyle);
396     case TimeFormatLong:
397     case TimeFormatShort:
398         return getMacTimeFormat(type == TimeFormatShort
399                                 ? kCFDateFormatterShortStyle
400                                 : kCFDateFormatterLongStyle);
401     case DayNameLong:
402     case DayNameShort:
403         return macDayName(in.toInt(), (type == DayNameShort));
404     case MonthNameLong:
405     case MonthNameShort:
406         return macMonthName(in.toInt(), (type == MonthNameShort));
407     case DateToStringShort:
408     case DateToStringLong:
409         return macDateToString(in.toDate(), (type == DateToStringShort));
410     case TimeToStringShort:
411     case TimeToStringLong:
412         return macTimeToString(in.toTime(), (type == TimeToStringShort));
413
414     case NegativeSign:
415     case PositiveSign:
416     case ZeroDigit:
417         break;
418
419     case MeasurementSystem:
420         return QVariant(static_cast<int>(macMeasurementSystem()));
421
422     case AMText:
423     case PMText: {
424         QCFType<CFLocaleRef> locale = CFLocaleCopyCurrent();
425         QCFType<CFDateFormatterRef> formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterLongStyle, kCFDateFormatterLongStyle);
426         QCFType<CFStringRef> value = static_cast<CFStringRef>(CFDateFormatterCopyProperty(formatter,
427             (type == AMText ? kCFDateFormatterAMSymbol : kCFDateFormatterPMSymbol)));
428         return QCFString::toQString(value);
429     }
430     case FirstDayOfWeek:
431         return QVariant(macFirstDayOfWeek());
432     case CurrencySymbol:
433         return QVariant(macCurrencySymbol(QLocale::CurrencySymbolFormat(in.toUInt())));
434     case CurrencyToString:
435         return macFormatCurrency(in.value<QSystemLocale::CurrencyToStringArgument>());
436     case UILanguages: {
437         QCFType<CFArrayRef> languages = (CFArrayRef)CFPreferencesCopyValue(
438                  CFSTR("AppleLanguages"),
439                  kCFPreferencesAnyApplication,
440                  kCFPreferencesCurrentUser,
441                  kCFPreferencesAnyHost);
442         const int cnt = CFArrayGetCount(languages);
443         QStringList result;
444         result.reserve(cnt);
445         for (int i = 0; i < cnt; ++i) {
446             const QString lang = QCFString::toQString(
447                         static_cast<CFStringRef>(CFArrayGetValueAtIndex(languages, i)));
448             result.append(lang);
449         }
450         return QVariant(result);
451     }
452     case StringToStandardQuotation:
453     case StringToAlternateQuotation:
454         return macQuoteString(type, in.value<QStringRef>());
455     default:
456         break;
457     }
458     return QVariant();
459 }
460
461 #endif // QT_NO_SYSTEMLOCALE
462
463 QT_END_NAMESPACE