• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDECore

klocale_kde.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (c) 1997,2001 Stephan Kulow <coolo@kde.org>
00003    Copyright (c) 1999 Preston Brown <pbrown@kde.org>
00004    Copyright (c) 1999-2002 Hans Petter Bieker <bieker@kde.org>
00005    Copyright (c) 2002 Lukas Tinkl <lukas@kde.org>
00006    Copyright (C) 2007 Bernhard Loos <nhuh.put@web.de>
00007    Copyright (C) 2009, 2010 John Layt <john@layt.net>
00008 
00009    This library is free software; you can redistribute it and/or
00010    modify it under the terms of the GNU Library General Public
00011    License as published by the Free Software Foundation; either
00012    version 2 of the License, or (at your option) any later version.
00013 
00014    This library is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017    Library General Public License for more details.
00018 
00019    You should have received a copy of the GNU Library General Public License
00020    along with this library; see the file COPYING.LIB.  If not, write to
00021    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00022    Boston, MA 02110-1301, USA.
00023 */
00024 
00025 #include "klocale_p.h"
00026 
00027 #include "config-localization.h"
00028 
00029 #include <math.h>
00030 
00031 #ifdef HAVE_SYS_TIME_H
00032 #include <sys/time.h>
00033 #endif
00034 #ifdef HAVE_TIME_H
00035 #include <time.h>
00036 #endif
00037 #if HAVE_LANGINFO_H
00038 #include <langinfo.h>
00039 #endif
00040 
00041 #include <QtCore/QTextCodec>
00042 #include <QtCore/QFile>
00043 #include <QtGui/QPrinter>
00044 #include <QtCore/QFileInfo>
00045 #include <QtCore/QRegExp>
00046 #include <QtCore/QLocale>
00047 #include <QtCore/QHash>
00048 #include <QtCore/QMutexLocker>
00049 #include <QtCore/QStringList>
00050 
00051 #include "kcatalog_p.h"
00052 #include "kglobal.h"
00053 #include "kstandarddirs.h"
00054 #include "kconfig.h"
00055 #include "kcomponentdata.h"
00056 #include "kdebug.h"
00057 #include "kdatetime.h"
00058 #include "kcalendarsystem.h"
00059 #include "kcurrencycode.h"
00060 #include "klocalizedstring.h"
00061 #include "kconfiggroup.h"
00062 #include "kcatalogname_p.h"
00063 #include "common_helpers_p.h"
00064 #include "kdayperiod_p.h"
00065 
00066 class KLocaleStaticData
00067 {
00068 public:
00069 
00070     KLocaleStaticData();
00071 
00072     QString maincatalog;
00073 
00074     // FIXME: Temporary until full language-sensitivity implemented.
00075     QHash<KLocale::DigitSet, QStringList> languagesUsingDigitSet;
00076 };
00077 
00078 KLocaleStaticData::KLocaleStaticData()
00079 {
00080     // Languages using non-Western Arabic digit sets.
00081     // FIXME: Temporary until full language-sensitivity implemented.
00082     languagesUsingDigitSet.insert(KLocale::ArabicIndicDigits, QStringList() << QString::fromLatin1("ar") << QString::fromLatin1("ps"));
00083     languagesUsingDigitSet.insert(KLocale::BengaliDigits, QStringList() << QString::fromLatin1("bn") << QString::fromLatin1("as") );
00084     languagesUsingDigitSet.insert(KLocale::DevenagariDigits, QStringList() << QString::fromLatin1("hi") << QString::fromLatin1("ne"));
00085     languagesUsingDigitSet.insert(KLocale::EasternArabicIndicDigits, QStringList() << QString::fromLatin1("fa") << QString::fromLatin1("ur"));
00086     languagesUsingDigitSet.insert(KLocale::GujaratiDigits, QStringList() << QString::fromLatin1("gu") );
00087     languagesUsingDigitSet.insert(KLocale::GurmukhiDigits, QStringList() << QString::fromLatin1("pa") );
00088     languagesUsingDigitSet.insert(KLocale::KannadaDigits, QStringList() << QString::fromLatin1("kn") );
00089     languagesUsingDigitSet.insert(KLocale::KhmerDigits, QStringList() << QString::fromLatin1("km") );
00090     languagesUsingDigitSet.insert(KLocale::MalayalamDigits, QStringList() << QString::fromLatin1("ml") );
00091     languagesUsingDigitSet.insert(KLocale::OriyaDigits, QStringList() << QString::fromLatin1("or") );
00092     languagesUsingDigitSet.insert(KLocale::TamilDigits, QStringList() << QString::fromLatin1("ta") );
00093     languagesUsingDigitSet.insert(KLocale::TeluguDigits, QStringList() << QString::fromLatin1("te") );
00094     languagesUsingDigitSet.insert(KLocale::ThaiDigits, QStringList() << QString::fromLatin1("th"));
00095 }
00096 
00097 K_GLOBAL_STATIC(KLocaleStaticData, staticData)
00098 
00099 
00100 QDebug operator<<(QDebug debug, const KCatalogName &cn)
00101 {
00102     return debug << cn.name << cn.loadCount;
00103 }
00104 
00105 KLocalePrivate::KLocalePrivate(KLocale *q_ptr)
00106                : q(q_ptr),
00107                  m_config(KSharedConfig::Ptr()),
00108                  m_country(QString()),
00109                  m_language(QString()),
00110                  m_languages(0),
00111                  m_catalogName(QString()),
00112                  m_calendar(0),
00113                  m_currency(0),
00114                  m_codecForEncoding(0)
00115 {
00116 }
00117 
00118 KLocalePrivate::KLocalePrivate(const KLocalePrivate &rhs)
00119 {
00120     copy(rhs);
00121 }
00122 
00123 KLocalePrivate &KLocalePrivate::operator=(const KLocalePrivate &rhs)
00124 {
00125     copy(rhs);
00126     return *this;
00127 }
00128 
00129 KConfig *KLocalePrivate::config()
00130 {
00131     if (m_config != KSharedConfig::Ptr()) {
00132         return m_config.data();
00133     } else {
00134         return KGlobal::config().data();
00135     }
00136 }
00137 
00138 void KLocalePrivate::copy(const KLocalePrivate &rhs)
00139 {
00140     // Parent KLocale
00141     q = 0;
00142 
00143     // Config
00144     m_config = rhs.m_config;
00145 
00146     // Country settings
00147     m_country = rhs.m_country;
00148     m_countryDivisionCode = rhs.m_countryDivisionCode;
00149 
00150     // Language settings
00151     m_language = rhs.m_language;
00152     m_languages = 0;
00153     m_languageList = rhs.m_languageList;
00154     m_languageSensitiveDigits = rhs.m_languageSensitiveDigits;
00155     m_nounDeclension = rhs.m_nounDeclension;
00156 
00157     // Catalog settings
00158     m_catalogName = rhs.m_catalogName;
00159     m_catalogNames = rhs.m_catalogNames;
00160     m_catalogs = rhs.m_catalogs;
00161     m_numberOfSysCatalogs = rhs.m_numberOfSysCatalogs;
00162     m_useTranscript = rhs.m_useTranscript;
00163 
00164     // Calendar settings
00165     m_calendarSystem = rhs.m_calendarSystem;
00166     m_calendar = 0;
00167     m_weekStartDay = rhs.m_weekStartDay;
00168     m_workingWeekStartDay = rhs.m_workingWeekStartDay;
00169     m_workingWeekEndDay = rhs.m_workingWeekEndDay;
00170     m_weekDayOfPray = rhs.m_weekDayOfPray;
00171 
00172     // Date/Time settings
00173     m_dateFormat = rhs.m_dateFormat;
00174     m_dateFormatShort = rhs.m_dateFormatShort;
00175     m_timeFormat = rhs.m_timeFormat;
00176     m_dateTimeDigitSet = rhs.m_dateTimeDigitSet;
00177     m_dateMonthNamePossessive = rhs.m_dateMonthNamePossessive;
00178     m_dayPeriods = rhs.m_dayPeriods;
00179     m_weekNumberSystem = rhs.m_weekNumberSystem;
00180 
00181     // Number settings
00182     m_decimalPlaces = rhs.m_decimalPlaces;
00183     m_decimalSymbol = rhs.m_decimalSymbol;
00184     m_thousandsSeparator = rhs.m_thousandsSeparator;
00185     m_numericDigitGrouping = rhs.m_numericDigitGrouping;
00186     m_positiveSign = rhs.m_positiveSign;
00187     m_negativeSign = rhs.m_negativeSign;
00188     m_digitSet = rhs.m_digitSet;
00189 
00190     // Currency settings
00191     m_currencyCode = rhs.m_currencyCode;
00192     m_currency = 0;
00193     m_currencyCodeList = rhs.m_currencyCodeList;
00194 
00195     // Money settings
00196     m_currencySymbol = rhs.m_currencySymbol;
00197     m_monetaryDecimalSymbol = rhs.m_monetaryDecimalSymbol;
00198     m_monetaryThousandsSeparator = rhs.m_monetaryThousandsSeparator;
00199     m_monetaryDigitGrouping = rhs.m_monetaryDigitGrouping;
00200     m_monetaryDecimalPlaces = rhs.m_monetaryDecimalPlaces;
00201     m_positiveMonetarySignPosition = rhs.m_positiveMonetarySignPosition;
00202     m_negativeMonetarySignPosition = rhs.m_negativeMonetarySignPosition;
00203     m_positivePrefixCurrencySymbol = rhs.m_positivePrefixCurrencySymbol;
00204     m_negativePrefixCurrencySymbol = rhs.m_negativePrefixCurrencySymbol;
00205     m_monetaryDigitSet = rhs.m_monetaryDigitSet;
00206 
00207     // Units settings
00208     m_binaryUnitDialect = rhs.m_binaryUnitDialect;
00209     m_byteSizeFmt = rhs.m_byteSizeFmt;
00210     m_pageSize = rhs.m_pageSize;
00211     m_measureSystem = rhs.m_measureSystem;
00212 
00213     // Encoding settings
00214     m_encoding = rhs.m_encoding;
00215     m_codecForEncoding = rhs.m_codecForEncoding;
00216     m_utf8FileEncoding = rhs.m_utf8FileEncoding;
00217 }
00218 
00219 KLocalePrivate::~KLocalePrivate()
00220 {
00221     delete m_currency;
00222     delete m_calendar;
00223     delete m_languages;
00224 }
00225 
00226 // init only called from platform specific constructor, so set everything up
00227 // Will be given a persistantConfig or a tempConfig or neither, but never both
00228 void KLocalePrivate::init(const QString& catalogName, const QString &language, const QString &country,
00229                           KSharedConfig::Ptr persistantConfig, KConfig *tempConfig)
00230 {
00231     m_catalogName = catalogName;
00232 
00233     // Only keep the persistant config if it is not the global
00234     if (persistantConfig != KSharedConfig::Ptr() && persistantConfig != KGlobal::config()) {
00235         m_config = persistantConfig;
00236     }
00237 
00238     KConfigGroup cg;
00239     bool useEnvironmentVariables;
00240 
00241     // We can't read the formats from the config until we know what locale to read in, but we need
00242     // to read the config to find out the locale.  The Country and Language settings should never
00243     // be localized in the config, so we can read a temp copy of them to get us started.
00244 
00245     // If no config given, use the global config and include envvars, otherwise use only the config.
00246     if (m_config != KSharedConfig::Ptr()) {
00247         cg = m_config->group(QLatin1String("Locale"));
00248         useEnvironmentVariables = false;
00249     } else if (tempConfig == 0 || tempConfig == KGlobal::config().data()) {
00250         cg = KGlobal::config()->group(QLatin1String("Locale"));
00251         useEnvironmentVariables = true;
00252     } else {
00253         cg = tempConfig->group(QLatin1String("Locale"));
00254         useEnvironmentVariables = false;
00255     }
00256 
00257     initEncoding();
00258     initFileNameEncoding();
00259     initCountry(country, cg.readEntry(QLatin1String("Country")));
00260     initLanguageList(language, cg.readEntry(QLatin1String("Language")), useEnvironmentVariables);
00261     // Now that we have a language, we can set up the config which uses it to setLocale()
00262     initConfig(tempConfig);
00263     initMainCatalogs();
00264     initFormat();
00265 }
00266 
00267 // Init the config, this is called during construction and by later setCountry/setLanguage calls.
00268 // You _must_ have the m_language set to a valid language or en_US before calling this so a
00269 // setLocale can be applied to the config
00270 void KLocalePrivate::initConfig(KConfig *config)
00271 {
00272     // * If we were constructed with a KSharedConfig it means the user gave it to us
00273     //   to use for the life of the KLocale, so just keep using it after a setLocale
00274     // * If passed in KConfig is null or the global config then use the global, but
00275     //   do the setLocale first.
00276     // * If we have a KConfig we need to use that, but due to keeping old behaviour
00277     //   of not requiring access to it for life we can't keep a reference so instead
00278     //   take a copy and use that, but do setLocale first.
00279 
00280     if (m_config != KSharedConfig::Ptr()) {
00281         m_config->setLocale(m_language);
00282     } else {
00283         // If no config given then use the global
00284         if (config == 0 || config == KGlobal::config().data()) {
00285             KGlobal::config()->setLocale(m_language);
00286         } else {
00287             config->setLocale(m_language);
00288             m_config = KSharedConfig::openConfig();
00289             config->copyTo(QString(), m_config.data());
00290             m_config->markAsClean();
00291         }
00292     }
00293 }
00294 
00295 void KLocalePrivate::initMainCatalogs()
00296 {
00297     KLocaleStaticData *s = staticData;
00298     QMutexLocker lock(kLocaleMutex());
00299 
00300     if (!s->maincatalog.isEmpty()) {
00301         // If setMainCatalog was called, then we use that
00302         // (e.g. korgac calls setMainCatalog("korganizer") to use korganizer.po)
00303         m_catalogName = s->maincatalog;
00304     }
00305 
00306     if (m_catalogName.isEmpty()) {
00307         kDebug(173) << "KLocale instance created called without valid "
00308                     << "catalog! Give an argument or call setMainCatalog "
00309                     << "before init" << endl;
00310     } else {
00311         // do not use insertCatalog here, that would already trigger updateCatalogs
00312         m_catalogNames.append(KCatalogName(m_catalogName));   // application catalog
00313 
00314         // catalogs from which each application can draw translations
00315         const int numberOfCatalogs = m_catalogNames.size();
00316         m_catalogNames.append(KCatalogName(QString::fromLatin1("libphonon")));
00317         m_catalogNames.append(KCatalogName(QString::fromLatin1("kio4")));
00318         m_catalogNames.append(KCatalogName(QString::fromLatin1("kdelibs4")));
00319         m_catalogNames.append(KCatalogName(QString::fromLatin1("kdeqt")));
00320         m_catalogNames.append(KCatalogName(QString::fromLatin1("solid_qt")));
00321         m_catalogNames.append(KCatalogName(QString::fromLatin1("kdecalendarsystems")));
00322         m_numberOfSysCatalogs = m_catalogNames.size() - numberOfCatalogs;
00323 
00324         updateCatalogs(); // evaluate this for all languages
00325     }
00326 }
00327 
00328 void KLocalePrivate::getLanguagesFromVariable(QStringList &list, const char *variable, bool isLanguageList)
00329 {
00330     QByteArray var(qgetenv(variable));
00331     if (!var.isEmpty()) {
00332         QString value = QFile::decodeName(var);
00333         if (isLanguageList) {
00334             list += value.split(QLatin1Char(':'));
00335         } else {
00336             // Process the value to create possible combinations.
00337             QString lang, ctry, modf, cset;
00338             KLocale::splitLocale(value, lang, ctry, modf, cset);
00339 
00340             if (!ctry.isEmpty() && !modf.isEmpty()) {
00341                 list += lang + QLatin1Char('_') + ctry + QLatin1Char('@') + modf;
00342             }
00343             // NOTE: The priority is tricky in case both ctry and modf are present.
00344             // Should really lang@modf be of higher priority than lang_ctry?
00345             // For at least one case (Serbian language), it is better this way.
00346             if (!modf.isEmpty()) {
00347                 list += lang + QLatin1Char('@') + modf;
00348             }
00349             if (!ctry.isEmpty()) {
00350                 list += lang + QLatin1Char('_') + ctry;
00351             }
00352             list += lang;
00353         }
00354     }
00355 }
00356 
00357 // init the country at construction only, will ensure we always have a country set
00358 void KLocalePrivate::initCountry(const QString &country, const QString &configCountry)
00359 {
00360     // Cache the valid countries list and add the default C as it is valid to use
00361     QStringList validCountries = allCountriesList();
00362     validCountries.append( defaultCountry() );
00363 
00364     // First check if the constructor passed in a value and if so if it is valid
00365     QString putativeCountry = country;
00366 
00367     if ( putativeCountry.isEmpty() || !validCountries.contains( putativeCountry, Qt::CaseInsensitive ) ) {
00368 
00369         // If the requested country is not valid, try the country as set in the config:
00370         putativeCountry = configCountry;
00371 
00372         if ( putativeCountry.isEmpty() || !validCountries.contains( putativeCountry, Qt::CaseInsensitive ) ) {
00373 
00374             // If the config country is not valid try the current host system country
00375             putativeCountry = systemCountry();
00376 
00377             if ( putativeCountry.isEmpty() || !validCountries.contains( putativeCountry, Qt::CaseInsensitive ) ) {
00378                 // Only if no other option, resort to the default C
00379                 putativeCountry = defaultCountry();
00380             }
00381         }
00382     }
00383 
00384     // Always save as lowercase, unless it's C when we want it uppercase
00385     if ( putativeCountry.toLower() == defaultCountry().toLower() ) {
00386         m_country = defaultCountry();
00387     } else {
00388         m_country = putativeCountry.toLower();
00389     }
00390 }
00391 
00392 QString KLocalePrivate::systemCountry() const
00393 {
00394     // Use QLocale for now as it supposedly provides a sensible default most times,
00395     // e.g. if locale is only "de" it is assumed to mean country of "DE"
00396     QString systemCountry, s1, s2, s3;
00397     splitLocale( QLocale::system().name(), s1, systemCountry, s2, s3 );
00398     return systemCountry.toLower();
00399 }
00400 
00401 void KLocalePrivate::initLanguageList(const QString &language, const QString &configLanguages,
00402                                       bool useEnvironmentVariables)
00403 {
00404     m_language = language;
00405 
00406     // Collect possible languages by decreasing priority.
00407     // The priority is as follows:
00408     // - the internally set language, if any
00409     // - KDE_LANG environment variable (can be a list)
00410     // - KDE configuration (can be a list)
00411     // - environment variables considered by gettext(3)
00412     // The environment variables are not considered if useEnvironmentVariables is false.
00413     QStringList list;
00414     if (!m_language.isEmpty()) {
00415         list += m_language;
00416     }
00417 
00418     // If the Locale object was created with a specific config file, then do not use the
00419     // environmental variables.  If the locale object was created with the global config, then
00420     // do use the environmental variables.
00421     if (useEnvironmentVariables) {
00422         // KDE_LANG contains list of language codes, not locale string.
00423         getLanguagesFromVariable(list, "KDE_LANG", true);
00424     }
00425 
00426     if (!configLanguages.isEmpty()) {
00427         list += configLanguages.split(QLatin1Char(':'));
00428     }
00429 
00430     if (useEnvironmentVariables) {
00431         // Collect languages by same order of priority as for gettext(3).
00432         // LANGUAGE contains list of language codes, not locale string.
00433         getLanguagesFromVariable(list, "LANGUAGE", true);
00434         getLanguagesFromVariable(list, "LC_ALL");
00435         getLanguagesFromVariable(list, "LC_MESSAGES");
00436         getLanguagesFromVariable(list, "LANG");
00437     }
00438 
00439     // fall back to the system language
00440     list += systemLanguageList();
00441 
00442     // Send the list to filter for really present languages on the system.
00443     setLanguage(list);
00444 }
00445 
00446 QStringList KLocalePrivate::systemLanguageList() const
00447 {
00448     return QStringList();
00449 }
00450 
00451 void KLocalePrivate::initFormat()
00452 {
00453     KConfigGroup cg(config(), "Locale");
00454 
00455     KConfig entryFile(KStandardDirs::locate("locale", QString::fromLatin1("l10n/%1/entry.desktop").arg(m_country)));
00456     entryFile.setLocale(m_language);
00457     KConfigGroup entry(&entryFile, "KCM Locale");
00458 
00459     //One-time conversion in 4.4 from FracDigits to DecimalPlaces and MonetaryDecimalPlaces
00460     //If user has personal setting for FracDigits then use it for both Decimal Places
00461     //TODO: Possible to do with kconf_update
00462     if (cg.hasKey("FracDigits")) {
00463         QString fracDigits = cg.readEntry("FracDigits", "");
00464         if (!fracDigits.isEmpty()) {
00465             cg.writeEntry("DecimalPlaces", fracDigits);
00466             cg.writeEntry("MonetaryDecimalPlaces", fracDigits);
00467         }
00468         cg.deleteEntry("FracDigits");
00469         cg.config()->sync();
00470     }
00471 
00472     // Numeric
00473 #define readConfigEntry(key, default, save) \
00474         save = entry.readEntry(key, default); \
00475         save = cg.readEntry(key, save);
00476 
00477 #define readConfigNumEntry(key, default, save, type) \
00478         save = (type)entry.readEntry(key, int(default)); \
00479         save = (type)cg.readEntry(key, int(save));
00480 
00481     // Country settings
00482     readConfigEntry("CountryDivisionCode", QString(), m_countryDivisionCode);
00483 
00484     // Numeric formats
00485     readConfigNumEntry("DecimalPlaces", 2, m_decimalPlaces, int);
00486 
00487     readConfigEntry("DecimalSymbol", ".", m_decimalSymbol);
00488     readConfigEntry("ThousandsSeparator", ",", m_thousandsSeparator);
00489     m_thousandsSeparator.remove(QString::fromLatin1("$0"));
00490     QString digitGroupFormat;
00491     readConfigEntry("DigitGroupFormat", "3", digitGroupFormat);
00492     m_numericDigitGrouping = digitGroupFormatToList(digitGroupFormat);
00493 
00494     readConfigEntry("PositiveSign", "", m_positiveSign);
00495     readConfigEntry("NegativeSign", "-", m_negativeSign);
00496 
00497     readConfigNumEntry("DigitSet", KLocale::ArabicDigits, m_digitSet, KLocale::DigitSet);
00498     // FIXME: Temporary until full language-sensitivity implemented.
00499     readConfigEntry("LanguageSensitiveDigits", true, m_languageSensitiveDigits);
00500 
00501     // Currency
00502     readConfigEntry("CurrencyCode", "USD", m_currencyCode);
00503     initCurrency();
00504     readConfigEntry("CurrencySymbol", m_currency->defaultSymbol(), m_currencySymbol);
00505     readConfigEntry("CurrencyCodesInUse", QStringList(m_currencyCode), m_currencyCodeList);
00506 
00507     // Monetary formats
00508     readConfigNumEntry("MonetaryDecimalPlaces", m_currency->decimalPlaces(), m_monetaryDecimalPlaces, int);
00509 
00510     readConfigEntry("MonetaryDecimalSymbol", ".", m_monetaryDecimalSymbol);
00511     readConfigEntry("MonetaryThousandsSeparator", ",", m_monetaryThousandsSeparator);
00512     m_monetaryThousandsSeparator.remove(QString::fromLatin1("$0"));
00513     readConfigEntry("MonetaryDigitGroupFormat", "3", digitGroupFormat);
00514     m_monetaryDigitGrouping = digitGroupFormatToList(digitGroupFormat);
00515 
00516     readConfigEntry("PositivePrefixCurrencySymbol", true, m_positivePrefixCurrencySymbol);
00517     readConfigEntry("NegativePrefixCurrencySymbol", true, m_negativePrefixCurrencySymbol);
00518     readConfigNumEntry("PositiveMonetarySignPosition", KLocale::BeforeQuantityMoney,
00519                        m_positiveMonetarySignPosition, KLocale::SignPosition);
00520     readConfigNumEntry("NegativeMonetarySignPosition", KLocale::ParensAround,
00521                        m_negativeMonetarySignPosition, KLocale::SignPosition);
00522 
00523     readConfigNumEntry("MonetaryDigitSet", KLocale::ArabicDigits,
00524                        m_monetaryDigitSet, KLocale::DigitSet);
00525     readConfigNumEntry("BinaryUnitDialect", KLocale::IECBinaryDialect,
00526                        m_binaryUnitDialect, KLocale::BinaryUnitDialect);
00527 
00528     // Date and time
00529     readConfigEntry("TimeFormat", "%H:%M:%S", m_timeFormat);
00530     readConfigEntry("DateFormat", "%A %d %B %Y", m_dateFormat);
00531     readConfigEntry("DateFormatShort", "%Y-%m-%d", m_dateFormatShort);
00532     readConfigNumEntry("WeekStartDay", 1, m_weekStartDay, int);                //default to Monday
00533     readConfigNumEntry("WorkingWeekStartDay", 1, m_workingWeekStartDay, int);  //default to Monday
00534     readConfigNumEntry("WorkingWeekEndDay", 5, m_workingWeekEndDay, int);      //default to Friday
00535     readConfigNumEntry("WeekDayOfPray", 7, m_weekDayOfPray, int);              //default to Sunday
00536     readConfigNumEntry("DateTimeDigitSet", KLocale::ArabicDigits,
00537                        m_dateTimeDigitSet, KLocale::DigitSet);
00538     readConfigNumEntry("WeekNumberSystem", KLocale::IsoWeekNumber,
00539                        m_weekNumberSystem, KLocale::WeekNumberSystem);
00540 
00541     // other
00542 #ifndef QT_NO_PRINTER
00543     readConfigNumEntry("PageSize", QPrinter::A4, m_pageSize, QPrinter::PageSize);
00544 #endif
00545     readConfigNumEntry("MeasureSystem", KLocale::Metric, m_measureSystem, KLocale::MeasureSystem);
00546     QString calendarType;
00547     readConfigEntry("CalendarSystem", "gregorian", calendarType);
00548     setCalendar(calendarType);
00549 
00550     readConfigEntry("Transcript", true, m_useTranscript);
00551 
00552     //Grammatical
00553     //Precedence here is l10n / i18n / config file
00554     KConfig langCfg(KStandardDirs::locate("locale", QString::fromLatin1("%1/entry.desktop").arg(m_language)));
00555     KConfigGroup lang(&langCfg, "KCM Locale");
00556 #define read3ConfigBoolEntry(key, default, save) \
00557         save = entry.readEntry(key, default); \
00558         save = lang.readEntry(key, save); \
00559         save = cg.readEntry(key, save);
00560 
00561     read3ConfigBoolEntry("NounDeclension", false, m_nounDeclension);
00562     read3ConfigBoolEntry("DateMonthNamePossessive", false, m_dateMonthNamePossessive);
00563 
00564     initDayPeriods(cg);
00565 }
00566 
00567 void KLocalePrivate::initDayPeriods(const KConfigGroup &cg)
00568 {
00569     // Prefer any l10n file value for country/language,
00570     // otherwise default to language only value which will be filled in later when i18n available
00571 
00572     //Day Period are stored in config as one QStringList entry per Day Period
00573     //PeriodCode,LongName,ShortName,NarrowName,StartTime,EndTime,Offset,OffsetIfZero
00574     //where start and end time are in the format HH:MM:SS.MMM
00575 
00576     m_dayPeriods.clear();
00577     QString periodKey = QString::fromLatin1("DayPeriod1");
00578     int i = 1;
00579     while (cg.hasKey(periodKey)) {
00580         QStringList period = cg.readEntry(periodKey, QStringList());
00581         if (period.count() == 8) {
00582             m_dayPeriods.append(KDayPeriod(period[0], period[1], period[2], period[3],
00583                                            QTime::fromString(period[4], QString::fromLatin1("HH:mm:ss.zzz")),
00584                                            QTime::fromString(period[5], QString::fromLatin1("HH:mm:ss.zzz")),
00585                                            period[6].toInt(), period[7].toInt()));
00586         }
00587         i = i + 1;
00588         periodKey = QString::fromLatin1("DayPeriod%1").arg(i);
00589     }
00590 }
00591 
00592 bool KLocalePrivate::setCountry(const QString &country, KConfig *newConfig)
00593 {
00594     // Cache the valid countries list and add the default C as it is valid to use
00595     QStringList validCountries = allCountriesList();
00596     validCountries.append(defaultCountry());
00597 
00598     QString putativeCountry = country;
00599 
00600     if (putativeCountry.isEmpty()) {
00601         // An empty string means to use the system country
00602         putativeCountry = systemCountry();
00603         if (putativeCountry.isEmpty() || !validCountries.contains(putativeCountry, Qt::CaseInsensitive)) {
00604             // If the system country is not valid, use the default
00605             putativeCountry = defaultCountry();
00606         }
00607     } else if (!validCountries.contains(putativeCountry, Qt::CaseInsensitive)) {
00608         return false;
00609     }
00610 
00611     // Always save as lowercase, unless it's C when we want it uppercase
00612     if (putativeCountry.toLower() == defaultCountry().toLower()) {
00613         m_country = defaultCountry();
00614     } else {
00615         m_country = putativeCountry.toLower();
00616     }
00617 
00618     // Get rid of the old config, start again with the new
00619     m_config = KSharedConfig::Ptr();
00620     initConfig(newConfig);
00621 
00622     // Init all the settings
00623     initFormat();
00624 
00625     return true;
00626 }
00627 
00628 bool KLocalePrivate::setCountryDivisionCode(const QString &countryDivisionCode)
00629 {
00630     m_countryDivisionCode = countryDivisionCode;
00631     return true;
00632 }
00633 
00634 bool KLocalePrivate::setLanguage(const QString &language, KConfig *config)
00635 {
00636     QMutexLocker lock(kLocaleMutex());
00637     m_languageList.removeAll(language);
00638     m_languageList.prepend(language);   // let us consider this language to be the most important one
00639 
00640     m_language = language; // remember main language for shortcut evaluation
00641 
00642     // important when called from the outside and harmless when called before
00643     // populating the catalog name list
00644     updateCatalogs();
00645 
00646     // Get rid of the old config, start again with the new
00647     m_config = KSharedConfig::Ptr();
00648     initConfig(config);
00649 
00650     // Init the new format settings
00651     initFormat();
00652 
00653     // Maybe the mo-files for this language are empty, but in principle we can speak all languages
00654     return true;
00655 }
00656 
00657 // KDE5 Unlike the other setLanguage call this does not reparse the config so the localized config
00658 // settings for the new primary language will _not_ be loaded.  In KDE5 always keep the original
00659 // config so this can be reparsed when required.
00660 bool KLocalePrivate::setLanguage(const QStringList &languages)
00661 {
00662     QMutexLocker lock(kLocaleMutex());
00663     // This list might contain
00664     // 1) some empty strings that we have to eliminate
00665     // 2) duplicate entries like in de:fr:de, where we have to keep the first occurrence of a
00666     //    language in order to preserve the order of precenence of the user
00667     // 3) languages into which the application is not translated. For those languages we should not
00668     //    even load kdelibs.mo or kio.po. these languages have to be dropped. Otherwise we get
00669     //    strange side effects, e.g. with Hebrew: the right/left switch for languages that write
00670     //    from right to left (like Hebrew or Arabic) is set in kdelibs.mo. If you only have
00671     //    kdelibs.mo but nothing from appname.mo, you get a mostly English app with layout from
00672     //    right to left. That was considered to be a bug by the Hebrew translators.
00673     QStringList list;
00674     foreach(const QString &language, languages) {
00675         if (!language.isEmpty() && !list.contains(language) && isApplicationTranslatedInto(language)) {
00676             list.append(language);
00677         }
00678     }
00679 
00680     if (!list.contains(KLocale::defaultLanguage())) {
00681         // English should always be added as final possibility; this is important
00682         // for proper initialization of message text post-processors which are
00683         // needed for English too, like semantic to visual formatting, etc.
00684         list.append(KLocale::defaultLanguage());
00685     }
00686 
00687     m_language = list.first(); // keep this for shortcut evaluations
00688 
00689     m_languageList = list; // keep this new list of languages to use
00690 
00691     // important when called from the outside and harmless when called before populating the
00692     // catalog name list
00693     updateCatalogs();
00694 
00695     return true; // we found something. Maybe it's only English, but we found something
00696 }
00697 
00698 void KLocalePrivate::initCurrency()
00699 {
00700     if (m_currencyCode.isEmpty() || !KCurrencyCode::isValid(m_currencyCode)) {
00701         m_currencyCode = KLocale::defaultCurrencyCode();
00702     }
00703 
00704     if (!m_currency || m_currencyCode != m_currency->isoCurrencyCode() || !m_currency->isValid()) {
00705         delete m_currency;
00706         m_currency = new KCurrencyCode(m_currencyCode, m_language);
00707     }
00708 }
00709 
00710 void KLocalePrivate::setCurrencyCode(const QString &newCurrencyCode)
00711 {
00712     if (!newCurrencyCode.isEmpty() && newCurrencyCode != m_currency->isoCurrencyCode() &&
00713         KCurrencyCode::isValid(newCurrencyCode)) {
00714         m_currencyCode = newCurrencyCode;
00715         initCurrency();
00716     }
00717 }
00718 
00719 bool KLocalePrivate::isApplicationTranslatedInto(const QString &lang)
00720 {
00721     if (lang.isEmpty()) {
00722         return false;
00723     }
00724 
00725     if (lang == KLocale::defaultLanguage()) {
00726         // default language is always "installed"
00727         return true;
00728     }
00729 
00730     if (m_catalogName.isEmpty()) {
00731         kDebug() << "no appName!";
00732         return false;
00733     }
00734 
00735     if (!KCatalog::catalogLocaleDir(m_catalogName, lang).isEmpty()) {
00736         return true;
00737     }
00738     return false;
00739 }
00740 
00741 void KLocalePrivate::splitLocale(const QString &aLocale, QString &language, QString &country,
00742                                  QString &modifier, QString &charset)
00743 {
00744     QString locale = aLocale;
00745 
00746     language.clear();
00747     country.clear();
00748     modifier.clear();
00749     charset.clear();
00750 
00751     // In case there are several concatenated locale specifications,
00752     // truncate all but first.
00753     int f = locale.indexOf(QLatin1Char(':'));
00754     if (f >= 0) {
00755         locale.truncate(f);
00756     }
00757 
00758     f = locale.indexOf(QLatin1Char('.'));
00759     if (f >= 0) {
00760         charset = locale.mid(f + 1);
00761         locale.truncate(f);
00762     }
00763 
00764     f = locale.indexOf(QLatin1Char('@'));
00765     if (f >= 0) {
00766         modifier = locale.mid(f + 1);
00767         locale.truncate(f);
00768     }
00769 
00770     f = locale.indexOf(QLatin1Char('_'));
00771     if (f >= 0) {
00772         country = locale.mid(f + 1);
00773         locale.truncate(f);
00774     }
00775 
00776     language = locale;
00777 }
00778 
00779 QString KLocalePrivate::language() const
00780 {
00781     return m_language;
00782 }
00783 
00784 QString KLocalePrivate::country() const
00785 {
00786     return m_country;
00787 }
00788 
00789 QString KLocalePrivate::countryDivisionCode() const
00790 {
00791     if (m_countryDivisionCode.isEmpty()) {
00792         return country().toUpper();
00793     } else {
00794         return m_countryDivisionCode;
00795     }
00796 }
00797 
00798 KCurrencyCode *KLocalePrivate::currency()
00799 {
00800     if (!m_currency) {
00801         initCurrency();
00802     }
00803     return m_currency;
00804 }
00805 
00806 QString KLocalePrivate::currencyCode() const
00807 {
00808     return m_currencyCode;
00809 }
00810 
00811 void KLocalePrivate::insertCatalog(const QString &catalog)
00812 {
00813     QMutexLocker lock(kLocaleMutex());
00814     int pos = m_catalogNames.indexOf(KCatalogName(catalog));
00815     if (pos != -1) {
00816         ++m_catalogNames[pos].loadCount;
00817         return;
00818     }
00819 
00820     // Insert new catalog just before system catalogs, to preserve the
00821     // lowest priority of system catalogs.
00822     m_catalogNames.insert(m_catalogNames.size() - m_numberOfSysCatalogs, KCatalogName(catalog));
00823     updateCatalogs(); // evaluate the changed list and generate the necessary KCatalog objects
00824 }
00825 
00826 void KLocalePrivate::updateCatalogs()
00827 {
00828     // some changes have occurred. Maybe we have learned or forgotten some languages.
00829     // Maybe the language precedence has changed.
00830     // Maybe we have learned or forgotten some catalog names.
00831 
00832     QList<KCatalog> newCatalogs;
00833 
00834     // now iterate over all languages and all wanted catalog names and append or create them in the
00835     // right order the sequence must be e.g. nds/appname nds/kdelibs nds/kio de/appname de/kdelibs
00836     // de/kio etc. and not nds/appname de/appname nds/kdelibs de/kdelibs etc. Otherwise we would be
00837     // in trouble with a language sequende nds,<default>,de. In this case <default> must hide
00838     // everything after itself in the language list.
00839     foreach(const QString &lang, m_languageList) {
00840         if (lang == KLocale::defaultLanguage()) {
00841             // Default language has no catalogs (messages from the code),
00842             // so loading catalogs for languages below the default
00843             // would later confuse the fallback resolution.
00844             break;
00845         }
00846         foreach(const KCatalogName &name, m_catalogNames) {
00847             // create and add catalog for this name and language if it exists
00848             if (! KCatalog::catalogLocaleDir(name.name, lang).isEmpty()) {
00849                 newCatalogs.append(KCatalog(name.name, lang));
00850                 //kDebug(173) << "Catalog: " << name << ":" << lang;
00851             }
00852         }
00853     }
00854 
00855     // notify KLocalizedString of catalog update.
00856     m_catalogs = newCatalogs;
00857     KLocalizedString::notifyCatalogsUpdated(m_languageList, m_catalogNames);
00858 }
00859 
00860 void KLocalePrivate::removeCatalog(const QString &catalog)
00861 {
00862     QMutexLocker lock(kLocaleMutex());
00863     int pos = m_catalogNames.indexOf(KCatalogName(catalog));
00864     if (pos == -1) {
00865         return;
00866     }
00867     if (--m_catalogNames[pos].loadCount > 0) {
00868         return;
00869     }
00870     m_catalogNames.removeAt(pos);
00871     if (KGlobal::hasMainComponent()) {
00872         // walk through the KCatalog instances and weed out everything we no longer need
00873         updateCatalogs();
00874     }
00875 }
00876 
00877 void KLocalePrivate::setActiveCatalog(const QString &catalog)
00878 {
00879     QMutexLocker lock(kLocaleMutex());
00880     int pos = m_catalogNames.indexOf(KCatalogName(catalog));
00881     if (pos == -1) {
00882         return;
00883     }
00884     m_catalogNames.move(pos, 0);
00885     // walk through the KCatalog instances and adapt to the new order
00886     updateCatalogs();
00887 }
00888 
00889 void KLocalePrivate::translateRawFrom(const char *catname, const char *msgctxt, const char *msgid, const char *msgid_plural,
00890                                       unsigned long n, QString *language, QString *translation) const
00891 {
00892     if (!msgid || !msgid[0]) {
00893         kDebug(173) << "KLocale: trying to look up \"\" in catalog. "
00894         << "Fix the program" << endl;
00895         language->clear();
00896         translation->clear();
00897         return;
00898     }
00899     if (msgctxt && !msgctxt[0]) {
00900         kDebug(173) << "KLocale: trying to use \"\" as context to message. "
00901         << "Fix the program" << endl;
00902     }
00903     if (msgid_plural && !msgid_plural[0]) {
00904         kDebug(173) << "KLocale: trying to use \"\" as plural message. "
00905         << "Fix the program" << endl;
00906     }
00907 
00908     QMutexLocker locker(kLocaleMutex());
00909     // determine the fallback string
00910     QString fallback;
00911     if (msgid_plural == NULL) {
00912         fallback = QString::fromUtf8(msgid);
00913     } else {
00914         if (n == 1) {
00915             fallback = QString::fromUtf8(msgid);
00916         } else {
00917             fallback = QString::fromUtf8(msgid_plural);
00918         }
00919     }
00920     if (language) {
00921         *language = KLocale::defaultLanguage();
00922     }
00923     if (translation) {
00924         *translation = fallback;
00925     }
00926 
00927     // shortcut evaluation if default language is main language: do not consult the catalogs
00928     if (useDefaultLanguage()) {
00929         return;
00930     }
00931 
00932     const QList<KCatalog> catalogList = m_catalogs;
00933     QString catNameDecoded;
00934     if (catname != NULL) {
00935         catNameDecoded = QString::fromUtf8(catname);
00936     }
00937     for (QList<KCatalog>::ConstIterator it = catalogList.constBegin(); it != catalogList.constEnd();
00938          ++it) {
00939         // shortcut evaluation: once we have arrived at default language, we cannot consult
00940         // the catalog as it will not have an assiciated mo-file. For this default language we can
00941         // immediately pick the fallback string.
00942         if ((*it).language() == KLocale::defaultLanguage()) {
00943             return;
00944         }
00945 
00946         if (catNameDecoded.isEmpty() || catNameDecoded == (*it).name()) {
00947             QString text;
00948             if (msgctxt != NULL && msgid_plural != NULL) {
00949                 text = (*it).translateStrict(msgctxt, msgid, msgid_plural, n);
00950             } else if (msgid_plural != NULL) {
00951                 text = (*it).translateStrict(msgid, msgid_plural, n);
00952             } else if (msgctxt != NULL) {
00953                 text = (*it).translateStrict(msgctxt, msgid);
00954             } else {
00955                 text = (*it).translateStrict(msgid);
00956             }
00957 
00958             if (!text.isEmpty()) {
00959                 // we found it
00960                 if (language) {
00961                     *language = (*it).language();
00962                 }
00963                 if (translation) {
00964                     *translation = text;
00965                 }
00966                 return;
00967             }
00968         }
00969     }
00970 }
00971 
00972 QString KLocalePrivate::translateQt(const char *context, const char *sourceText, const char *comment) const
00973 {
00974     // Qt's context is normally the name of the class of the method which makes
00975     // the tr(sourceText) call. However, it can also be manually supplied via
00976     // translate(context, sourceText) call.
00977     //
00978     // Qt's sourceText is the actual message displayed to the user.
00979     //
00980     // Qt's comment is an optional argument of tr() and translate(), like
00981     // tr(sourceText, comment) and translate(context, sourceText, comment).
00982     //
00983     // We handle this in the following way:
00984     //
00985     // If the comment is given, then it is considered gettext's msgctxt, so a
00986     // context call is made.
00987     //
00988     // If the comment is not given, but context is given, then we treat it as
00989     // msgctxt only if it was manually supplied (the one in translate()) -- but
00990     // we don't know this, so we first try a context call, and if translation
00991     // is not found, we fallback to ordinary call.
00992     //
00993     // If neither comment nor context are given, it's just an ordinary call
00994     // on sourceText.
00995 
00996     if (!sourceText || !sourceText[0]) {
00997         kDebug(173) << "KLocale: trying to look up \"\" in catalog. "
00998         << "Fix the program" << endl;
00999         return QString();
01000     }
01001 
01002     if (useDefaultLanguage()) {
01003         return QString();
01004     }
01005 
01006     QString translation;
01007     QString language;
01008 
01009     // NOTE: Condition (language != defaultLanguage()) means that translation
01010     // was found, otherwise we got the original string back as translation.
01011 
01012     if (comment && comment[0]) {
01013         // Comment given, go for context call.
01014         translateRawFrom(0, comment, sourceText, 0, 0, &language, &translation);
01015     } else {
01016         // Comment not given, go for try-fallback with context.
01017         if (context && context[0]) {
01018             translateRawFrom(0, context, sourceText, 0, 0, &language, &translation);
01019         }
01020         if (language.isEmpty() || language == defaultLanguage()) {
01021             translateRawFrom(0, 0, sourceText, 0, 0, &language, &translation);
01022         }
01023     }
01024 
01025     if (language != defaultLanguage()) {
01026         return translation;
01027     }
01028 
01029     // No proper translation found, return empty according to Qt's expectation.
01030     return QString();
01031 }
01032 
01033 QList<KLocale::DigitSet> KLocalePrivate::allDigitSetsList() const
01034 {
01035     QList<KLocale::DigitSet> digitSets;
01036     digitSets.append(KLocale::ArabicDigits);
01037     digitSets.append(KLocale::ArabicIndicDigits);
01038     digitSets.append(KLocale::BengaliDigits);
01039     digitSets.append(KLocale::DevenagariDigits);
01040     digitSets.append(KLocale::EasternArabicIndicDigits);
01041     digitSets.append(KLocale::GujaratiDigits);
01042     digitSets.append(KLocale::GurmukhiDigits);
01043     digitSets.append(KLocale::KannadaDigits);
01044     digitSets.append(KLocale::KhmerDigits);
01045     digitSets.append(KLocale::MalayalamDigits);
01046     digitSets.append(KLocale::OriyaDigits);
01047     digitSets.append(KLocale::TamilDigits);
01048     digitSets.append(KLocale::TeluguDigits);
01049     digitSets.append(KLocale::ThaiDigits);
01050     qSort(digitSets);
01051     return digitSets;
01052 }
01053 
01054 QString KLocalePrivate::digitSetString(KLocale::DigitSet digitSet)
01055 {
01056     switch (digitSet) {
01057     case KLocale::ArabicIndicDigits:
01058         return QString::fromUtf8("٠١٢٣٤٥٦٧٨٩");
01059     case KLocale::BengaliDigits:
01060         return QString::fromUtf8("০১২৩৪৫৬৭৮৯");
01061     case KLocale::DevenagariDigits:
01062         return QString::fromUtf8("०१२३४५६७८९");
01063     case KLocale::EasternArabicIndicDigits:
01064         return QString::fromUtf8("۰۱۲۳۴۵۶۷۸۹");
01065     case KLocale::GujaratiDigits:
01066         return QString::fromUtf8("૦૧૨૩૪૫૬૭૮૯");
01067     case KLocale::GurmukhiDigits:
01068         return QString::fromUtf8("੦੧੨੩੪੫੬੭੮੯");
01069     case KLocale::KannadaDigits:
01070         return QString::fromUtf8("೦೧೨೩೪೫೬೭೮೯");
01071     case KLocale::KhmerDigits:
01072         return QString::fromUtf8("០១២៣៤៥៦៧៨៩");
01073     case KLocale::MalayalamDigits:
01074         return QString::fromUtf8("൦൧൨൩൪൫൬൭൮൯");
01075     case KLocale::OriyaDigits:
01076         return QString::fromUtf8("୦୧୨୩୪୫୬୭୮୯");
01077     case KLocale::TamilDigits:
01078         return QString::fromUtf8("௦௧௨௩௪௫௬௭௮");
01079     case KLocale::TeluguDigits:
01080         return QString::fromUtf8("౦౧౨౩౪౫౬౭౯");
01081     case KLocale::ThaiDigits:
01082         return QString::fromUtf8("๐๑๒๓๔๕๖๗๘๙");
01083     default:
01084         return QString::fromUtf8("0123456789");
01085     }
01086 }
01087 
01088 QString KLocalePrivate::digitSetToName(KLocale::DigitSet digitSet, bool withDigits) const
01089 {
01090     QString name;
01091     switch (digitSet) {
01092     case KLocale::ArabicIndicDigits:
01093         name = i18nc("digit set", "Arabic-Indic");
01094         break;
01095     case KLocale::BengaliDigits:
01096         name = i18nc("digit set", "Bengali");
01097         break;
01098     case KLocale::DevenagariDigits:
01099         name = i18nc("digit set", "Devanagari");
01100         break;
01101     case KLocale::EasternArabicIndicDigits:
01102         name = i18nc("digit set", "Eastern Arabic-Indic");
01103         break;
01104     case KLocale::GujaratiDigits:
01105         name = i18nc("digit set", "Gujarati");
01106         break;
01107     case KLocale::GurmukhiDigits:
01108         name = i18nc("digit set", "Gurmukhi");
01109         break;
01110     case KLocale::KannadaDigits:
01111         name = i18nc("digit set", "Kannada");
01112         break;
01113     case KLocale::KhmerDigits:
01114         name = i18nc("digit set", "Khmer");
01115         break;
01116     case KLocale::MalayalamDigits:
01117         name = i18nc("digit set", "Malayalam");
01118         break;
01119     case KLocale::OriyaDigits:
01120         name = i18nc("digit set", "Oriya");
01121         break;
01122     case KLocale::TamilDigits:
01123         name = i18nc("digit set", "Tamil");
01124         break;
01125     case KLocale::TeluguDigits:
01126         name = i18nc("digit set", "Telugu");
01127         break;
01128     case KLocale::ThaiDigits:
01129         name = i18nc("digit set", "Thai");
01130         break;
01131     default:
01132         name = i18nc("digit set", "Arabic");
01133     }
01134     if (withDigits) {
01135         QString digits = digitSetString(digitSet);
01136         QString nameWithDigits = i18nc("name of digit set with digit string, "
01137                                        "e.g. 'Arabic (0123456789)'", "%1 (%2)", name, digits);
01138         return nameWithDigits;
01139     } else {
01140         return name;
01141     }
01142 }
01143 
01144 QString KLocalePrivate::convertDigits(const QString &str, KLocale::DigitSet digitSet, bool ignoreContext) const
01145 {
01146     if (!ignoreContext) {
01147         // Fall back to Western Arabic digits if requested digit set
01148         // is not appropriate for current application language.
01149         // FIXME: Temporary until full language-sensitivity implemented.
01150         KLocaleStaticData *s = staticData;
01151         if (m_languageSensitiveDigits && !s->languagesUsingDigitSet[digitSet].contains(m_language)) {
01152             digitSet = KLocale::ArabicDigits;
01153         }
01154     }
01155 
01156     QString nstr;
01157     QString digitDraw = digitSetString(digitSet);
01158     foreach(const QChar &c, str) {
01159         if (c.isDigit()) {
01160             nstr += digitDraw[c.digitValue()];
01161         } else {
01162             nstr += c;
01163         }
01164     }
01165     return nstr;
01166 }
01167 
01168 QString KLocalePrivate::toArabicDigits(const QString &str)
01169 {
01170     QString nstr;
01171     foreach(const QChar &c, str) {
01172         if (c.isDigit()) {
01173             nstr += QChar('0' + c.digitValue());
01174         } else {
01175             nstr += c;
01176         }
01177     }
01178     return nstr;
01179 }
01180 
01181 bool KLocalePrivate::nounDeclension() const
01182 {
01183     return m_nounDeclension;
01184 }
01185 
01186 bool KLocalePrivate::dateMonthNamePossessive() const
01187 {
01188     return m_dateMonthNamePossessive;
01189 }
01190 
01191 int KLocalePrivate::weekStartDay() const
01192 {
01193     return m_weekStartDay;
01194 }
01195 
01196 int KLocalePrivate::workingWeekStartDay() const
01197 {
01198     return m_workingWeekStartDay;
01199 }
01200 
01201 int KLocalePrivate::workingWeekEndDay() const
01202 {
01203     return m_workingWeekEndDay;
01204 }
01205 
01206 int KLocalePrivate::weekDayOfPray() const
01207 {
01208     return m_weekDayOfPray;
01209 }
01210 
01211 int KLocalePrivate::decimalPlaces() const
01212 {
01213     return m_decimalPlaces;
01214 }
01215 
01216 QString KLocalePrivate::decimalSymbol() const
01217 {
01218     return m_decimalSymbol;
01219 }
01220 
01221 QString KLocalePrivate::thousandsSeparator() const
01222 {
01223     return m_thousandsSeparator;
01224 }
01225 
01226 QList<int> KLocalePrivate::numericDigitGrouping() const
01227 {
01228     return m_numericDigitGrouping;
01229 }
01230 
01231 QString KLocalePrivate::currencySymbol() const
01232 {
01233     return m_currencySymbol;
01234 }
01235 
01236 QString KLocalePrivate::monetaryDecimalSymbol() const
01237 {
01238     return m_monetaryDecimalSymbol;
01239 }
01240 
01241 QString KLocalePrivate::monetaryThousandsSeparator() const
01242 {
01243     return m_monetaryThousandsSeparator;
01244 }
01245 
01246 QList<int> KLocalePrivate::monetaryDigitGrouping() const
01247 {
01248     return m_monetaryDigitGrouping;
01249 }
01250 
01251 QString KLocalePrivate::positiveSign() const
01252 {
01253     return m_positiveSign;
01254 }
01255 
01256 QString KLocalePrivate::negativeSign() const
01257 {
01258     return m_negativeSign;
01259 }
01260 
01261 /* Just copy to keep the diff looking clean, delete later
01262 int KLocale::fracDigits() const
01263 {
01264     return monetaryDecimalPlaces();
01265 }
01266 */
01267 
01268 int KLocalePrivate::monetaryDecimalPlaces() const
01269 {
01270     return m_monetaryDecimalPlaces;
01271 }
01272 
01273 bool KLocalePrivate::positivePrefixCurrencySymbol() const
01274 {
01275     return m_positivePrefixCurrencySymbol;
01276 }
01277 
01278 bool KLocalePrivate::negativePrefixCurrencySymbol() const
01279 {
01280     return m_negativePrefixCurrencySymbol;
01281 }
01282 
01283 KLocale::SignPosition KLocalePrivate::positiveMonetarySignPosition() const
01284 {
01285     return m_positiveMonetarySignPosition;
01286 }
01287 
01288 KLocale::SignPosition KLocalePrivate::negativeMonetarySignPosition() const
01289 {
01290     return m_negativeMonetarySignPosition;
01291 }
01292 
01293 static inline void put_it_in(QChar *buffer, int &index, const QString &s)
01294 {
01295     for (int l = 0; l < s.length(); l++) {
01296         buffer[index++] = s.at(l);
01297     }
01298 }
01299 
01300 static inline void put_it_in(QChar *buffer, int &index, int number)
01301 {
01302     buffer[index++] = number / 10 + '0';
01303     buffer[index++] = number % 10 + '0';
01304 }
01305 
01306 // Convert POSIX Digit Group Format string into a Qlist<int>, e.g. "3;2" converts to (3,2)
01307 QList<int> KLocalePrivate::digitGroupFormatToList(const QString &digitGroupFormat) const
01308 {
01309     QList<int> groupList;
01310     QStringList stringList = digitGroupFormat.split(QLatin1Char(';'));
01311     foreach(const QString &size, stringList) {
01312         groupList.append(size.toInt());
01313     }
01314     return groupList;
01315 }
01316 
01317 // Inserts all required occurrences of the group separator into a number string.
01318 QString KLocalePrivate::formatDigitGroup(const QString &number, const QString &groupSeparator, const QString &decimalSeperator, QList<int> groupList) const
01319 {
01320     if (groupList.isEmpty() || groupSeparator.isEmpty()) {
01321         return number;
01322     }
01323 
01324     QString num = number;
01325     int groupCount = groupList.count();
01326     int groupAt = 0;
01327     int groupSize = groupList.at(groupAt);
01328     int pos = num.indexOf(decimalSeperator);
01329     if (pos == -1) {
01330         pos = num.length();
01331     }
01332     pos = pos - groupSize;
01333 
01334     while (pos > 0 && groupSize > 0) {
01335         num.insert(pos, groupSeparator);
01336         if (groupAt + 1 < groupCount) {
01337             ++groupAt;
01338             groupSize = groupList.at(groupAt);
01339         }
01340         pos = pos - groupSize;
01341     }
01342 
01343     return num;
01344 }
01345 
01346 // Strips all occurrences of the group separator from a number, returns ok if the separators were all in the valid positions
01347 QString KLocalePrivate::parseDigitGroup(const QString &number, const QString &groupSeparator, const QString &decimalSeparator, QList<int> groupList, bool *ok) const
01348 {
01349     QString num = number;
01350     bool valid = true;
01351 
01352     if (!groupSeparator.isEmpty()) {
01353         if (!groupList.isEmpty()) {
01354             int separatorSize = groupSeparator.length();
01355             int groupCount = groupList.count();
01356             int groupAt = 0;
01357             int groupSize = groupList.at(groupAt);
01358             int pos = number.indexOf(decimalSeparator);
01359             if (pos == -1) {
01360                 pos = number.length();
01361             }
01362             pos = pos - groupSize - separatorSize;
01363 
01364             while (pos > 0 && valid && groupSize > 0) {
01365                 if (num.mid(pos, separatorSize) == groupSeparator) {
01366                     num.remove(pos, separatorSize);
01367                     if (groupAt + 1 < groupCount) {
01368                         ++groupAt;
01369                         groupSize = groupList.at(groupAt);
01370                     }
01371                     pos = pos - groupSize - separatorSize;
01372                 } else {
01373                     valid = false;
01374                 }
01375             }
01376         }
01377 
01378         if (num.contains(groupSeparator)) {
01379             valid = false;
01380             num = num.remove(groupSeparator);
01381         }
01382     }
01383 
01384     if (ok) {
01385         *ok = valid;
01386     }
01387 
01388     return num;
01389 }
01390 
01391 QString KLocalePrivate::formatMoney(double num, const QString &symbol, int precision) const
01392 {
01393     // some defaults
01394     QString currencyString = symbol;
01395     if (symbol.isNull()) {
01396         currencyString = currencySymbol();
01397     }
01398     if (precision < 0) {
01399         precision = monetaryDecimalPlaces();
01400     }
01401 
01402     // the number itself
01403     bool neg = num < 0;
01404     QString res = QString::number(neg ? -num : num, 'f', precision);
01405 
01406     // Replace dot with locale decimal separator
01407     res.replace(QLatin1Char('.'), monetaryDecimalSymbol());
01408 
01409     // Insert the thousand separators
01410     res = formatDigitGroup(res, monetaryThousandsSeparator(), monetaryDecimalSymbol(), monetaryDigitGrouping());
01411 
01412     // set some variables we need later
01413     int signpos = neg
01414                   ? negativeMonetarySignPosition()
01415                   : positiveMonetarySignPosition();
01416     QString sign = neg
01417                    ? negativeSign()
01418                    : positiveSign();
01419 
01420     switch (signpos) {
01421     case KLocale::ParensAround:
01422         res.prepend(QLatin1Char('('));
01423         res.append(QLatin1Char(')'));
01424         break;
01425     case KLocale::BeforeQuantityMoney:
01426         res.prepend(sign);
01427         break;
01428     case KLocale::AfterQuantityMoney:
01429         res.append(sign);
01430         break;
01431     case KLocale::BeforeMoney:
01432         currencyString.prepend(sign);
01433         break;
01434     case KLocale::AfterMoney:
01435         currencyString.append(sign);
01436         break;
01437     }
01438 
01439     if (neg ? negativePrefixCurrencySymbol() :
01440             positivePrefixCurrencySymbol()) {
01441         res.prepend(QLatin1Char(' '));
01442         res.prepend(currencyString);
01443     } else {
01444         res.append(QLatin1Char(' '));
01445         res.append(currencyString);
01446     }
01447 
01448     // Convert to target digit set.
01449     res = convertDigits(res, m_monetaryDigitSet);
01450 
01451     return res;
01452 }
01453 
01454 
01455 QString KLocalePrivate::formatNumber(double num, int precision) const
01456 {
01457     if (precision < 0) {
01458         precision = decimalPlaces();
01459     }
01460     // no need to round since QString::number does this for us
01461     return formatNumber(QString::number(num, 'f', precision), false, 0);
01462 }
01463 
01464 QString KLocalePrivate::formatLong(long num) const
01465 {
01466     return formatNumber((double)num, 0);
01467 }
01468 
01469 // increase the digit at 'position' by one
01470 static void _inc_by_one(QString &str, int position)
01471 {
01472     for (int i = position; i >= 0; i--) {
01473         char last_char = str[i].toLatin1();
01474         switch (last_char) {
01475         case '0':
01476             str[i] = '1';
01477             break;
01478         case '1':
01479             str[i] = '2';
01480             break;
01481         case '2':
01482             str[i] = '3';
01483             break;
01484         case '3':
01485             str[i] = '4';
01486             break;
01487         case '4':
01488             str[i] = '5';
01489             break;
01490         case '5':
01491             str[i] = '6';
01492             break;
01493         case '6':
01494             str[i] = '7';
01495             break;
01496         case '7':
01497             str[i] = '8';
01498             break;
01499         case '8':
01500             str[i] = '9';
01501             break;
01502         case '9':
01503             str[i] = '0';
01504             if (i == 0) str.prepend(QLatin1Char('1'));
01505             continue;
01506         case '.':
01507             continue;
01508         }
01509         break;
01510     }
01511 }
01512 
01513 // Cut off if more digits in fractional part than 'precision'
01514 static void _round(QString &str, int precision)
01515 {
01516     int decimalSymbolPos = str.indexOf(QLatin1Char('.'));
01517 
01518     if (decimalSymbolPos == -1) {
01519         if (precision == 0)  return;
01520         else if (precision > 0) { // add dot if missing (and needed)
01521             str.append(QLatin1Char('.'));
01522             decimalSymbolPos = str.length() - 1;
01523         }
01524     }
01525     // fill up with more than enough zeroes (in case fractional part too short)
01526     str.reserve(str.length() + precision);
01527     for (int i = 0; i < precision; ++i)
01528         str.append(QLatin1Char('0'));
01529 
01530     // Now decide whether to round up or down
01531     char last_char = str[decimalSymbolPos + precision + 1].toLatin1();
01532     switch (last_char) {
01533     case '0':
01534     case '1':
01535     case '2':
01536     case '3':
01537     case '4':
01538         // nothing to do, rounding down
01539         break;
01540     case '5':
01541     case '6':
01542     case '7':
01543     case '8':
01544     case '9':
01545         _inc_by_one(str, decimalSymbolPos + precision);
01546         break;
01547     default:
01548         break;
01549     }
01550 
01551     decimalSymbolPos = str.indexOf(QLatin1Char('.'));
01552     str.truncate(decimalSymbolPos + precision + 1);
01553 
01554     // if precision == 0 delete also '.'
01555     if (precision == 0) {
01556         str = str.left(decimalSymbolPos);
01557     }
01558 
01559     str.squeeze();
01560 }
01561 
01562 QString KLocalePrivate::formatNumber(const QString &numStr, bool round, int precision) const
01563 {
01564     QString tmpString = numStr;
01565 
01566     if (precision < 0) {
01567         precision = decimalPlaces();
01568     }
01569 
01570     // Skip the sign (for now)
01571     const bool neg = (tmpString[0] == QLatin1Char('-'));
01572     if (neg || tmpString[0] == QLatin1Char('+')) {
01573         tmpString.remove(0, 1);
01574     }
01575 
01576     //kDebug(173)<<"tmpString:"<<tmpString;
01577 
01578     // Split off exponential part (including 'e'-symbol)
01579     const int expPos = tmpString.indexOf(QLatin1Char('e')); // -1 if not found
01580     QString mantString = tmpString.left(expPos); // entire string if no 'e' found
01581     QString expString;
01582     if (expPos > -1) {
01583         expString = tmpString.mid(expPos); // includes the 'e', or empty if no 'e'
01584         if (expString.length() == 1) {
01585             expString.clear();
01586         }
01587     }
01588 
01589     //kDebug(173)<<"mantString:"<<mantString;
01590     //kDebug(173)<<"expString:"<<expString;
01591     if (mantString.isEmpty() || !mantString[0].isDigit()) {// invalid number
01592         mantString = QLatin1Char('0');
01593     }
01594 
01595     if (round) {
01596         _round(mantString, precision);
01597     }
01598 
01599     // Replace dot with locale decimal separator
01600     mantString.replace(QLatin1Char('.'), decimalSymbol());
01601 
01602     // Insert the thousand separators
01603     mantString = formatDigitGroup(mantString, thousandsSeparator(), decimalSymbol(), numericDigitGrouping());
01604 
01605     // How can we know where we should put the sign?
01606     mantString.prepend(neg ? negativeSign() : positiveSign());
01607 
01608     // Convert to target digit set.
01609     if (digitSet() != KLocale::ArabicDigits) {
01610         mantString = convertDigits(mantString, digitSet());
01611         expString = convertDigits(expString, digitSet());
01612     }
01613 
01614     return mantString + expString;
01615 }
01616 
01617 // Returns a list of already translated units to use later in formatByteSize
01618 // and friends.  Account for every unit in KLocale::BinarySizeUnits
01619 QList<QString> KLocalePrivate::dialectUnitsList(KLocale::BinaryUnitDialect dialect)
01620 {
01621     QList<QString> binaryUnits;
01622     QString s; // Used in CACHE_BYTE_FMT macro defined shortly
01623 
01624     // Adds a given translation to the binaryUnits list.
01625 #define CACHE_BYTE_FMT(ctxt_text) \
01626         translateRawFrom(0, ctxt_text, 0, 0, 0, &s); \
01627         binaryUnits.append(s);
01628 
01629     // Do not remove i18n: comments below, they are used by the
01630     // translators.
01631 
01632     // This prefix is shared by all current dialects.
01633     // i18n: Dumb message, avoid any markup or scripting.
01634     CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in bytes", "%1 B"));
01635 
01636     switch (dialect) {
01637     case KLocale::MetricBinaryDialect:
01638         // i18n: Dumb message, avoid any markup or scripting.
01639         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 1000 bytes", "%1 kB"));
01640         // i18n: Dumb message, avoid any markup or scripting.
01641         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 10^6 bytes", "%1 MB"));
01642         // i18n: Dumb message, avoid any markup or scripting.
01643         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 10^9 bytes", "%1 GB"));
01644         // i18n: Dumb message, avoid any markup or scripting.
01645         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 10^12 bytes", "%1 TB"));
01646         // i18n: Dumb message, avoid any markup or scripting.
01647         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 10^15 bytes", "%1 PB"));
01648         // i18n: Dumb message, avoid any markup or scripting.
01649         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 10^18 bytes", "%1 EB"));
01650         // i18n: Dumb message, avoid any markup or scripting.
01651         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 10^21 bytes", "%1 ZB"));
01652         // i18n: Dumb message, avoid any markup or scripting.
01653         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 10^24 bytes", "%1 YB"));
01654         break;
01655 
01656     case KLocale::JEDECBinaryDialect:
01657         // i18n: Dumb message, avoid any markup or scripting.
01658         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("memory size in 1024 bytes", "%1 KB"));
01659         // i18n: Dumb message, avoid any markup or scripting.
01660         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("memory size in 2^20 bytes", "%1 MB"));
01661         // i18n: Dumb message, avoid any markup or scripting.
01662         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("memory size in 2^30 bytes", "%1 GB"));
01663         // i18n: Dumb message, avoid any markup or scripting.
01664         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("memory size in 2^40 bytes", "%1 TB"));
01665         // i18n: Dumb message, avoid any markup or scripting.
01666         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("memory size in 2^50 bytes", "%1 PB"));
01667         // i18n: Dumb message, avoid any markup or scripting.
01668         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("memory size in 2^60 bytes", "%1 EB"));
01669         // i18n: Dumb message, avoid any markup or scripting.
01670         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("memory size in 2^70 bytes", "%1 ZB"));
01671         // i18n: Dumb message, avoid any markup or scripting.
01672         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("memory size in 2^80 bytes", "%1 YB"));
01673         break;
01674 
01675     case KLocale::IECBinaryDialect:
01676     default:
01677         // i18n: Dumb message, avoid any markup or scripting.
01678         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 1024 bytes", "%1 KiB"));
01679         // i18n: Dumb message, avoid any markup or scripting.
01680         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 2^20 bytes", "%1 MiB"));
01681         // i18n: Dumb message, avoid any markup or scripting.
01682         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 2^30 bytes", "%1 GiB"));
01683         // i18n: Dumb message, avoid any markup or scripting.
01684         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 2^40 bytes", "%1 TiB"));
01685         // i18n: Dumb message, avoid any markup or scripting.
01686         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 2^50 bytes", "%1 PiB"));
01687         // i18n: Dumb message, avoid any markup or scripting.
01688         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 2^60 bytes", "%1 EiB"));
01689         // i18n: Dumb message, avoid any markup or scripting.
01690         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 2^70 bytes", "%1 ZiB"));
01691         // i18n: Dumb message, avoid any markup or scripting.
01692         CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 2^80 bytes", "%1 YiB"));
01693         break;
01694     }
01695 
01696     return binaryUnits;
01697 }
01698 
01699 QString KLocalePrivate::formatByteSize(double size, int precision, KLocale::BinaryUnitDialect dialect,
01700                                        KLocale::BinarySizeUnits specificUnit)
01701 {
01702     // Error checking
01703     if (dialect <= KLocale::DefaultBinaryDialect || dialect > KLocale::LastBinaryDialect) {
01704         dialect = m_binaryUnitDialect;
01705     }
01706 
01707     if (specificUnit < KLocale::DefaultBinaryUnits || specificUnit > KLocale::UnitLastUnit) {
01708         specificUnit = KLocale::DefaultBinaryUnits;
01709     }
01710 
01711     // Choose appropriate units.
01712     QList<QString> dialectUnits;
01713     if (dialect == m_binaryUnitDialect) {
01714         // Cache default units for speed
01715         if (m_byteSizeFmt.size() == 0) {
01716             QMutexLocker lock(kLocaleMutex());
01717 
01718             // We only cache the user's default dialect.
01719             m_byteSizeFmt = dialectUnitsList(m_binaryUnitDialect);
01720         }
01721 
01722         dialectUnits = m_byteSizeFmt;
01723     } else {
01724         dialectUnits = dialectUnitsList(dialect);
01725     }
01726 
01727     int unit = 0; // Selects what unit to use from cached list
01728     double multiplier = 1024.0;
01729 
01730     if (dialect == KLocale::MetricBinaryDialect) {
01731         multiplier = 1000.0;
01732     }
01733 
01734     // If a specific unit conversion is given, use it directly.  Otherwise
01735     // search until the result is in [0, multiplier) (or out of our range).
01736     if (specificUnit == KLocale::DefaultBinaryUnits) {
01737         while (size >= multiplier && unit < (int) KLocale::UnitYottaByte) {
01738             size /= multiplier;
01739             unit++;
01740         }
01741     } else {
01742         // A specific unit is in use
01743         unit = static_cast<int>(specificUnit);
01744         if (unit > 0) {
01745             size /= pow(multiplier, unit);
01746         }
01747     }
01748 
01749     if (unit == 0) {
01750         // Bytes, no rounding
01751         return dialectUnits[unit].arg(formatNumber(size, 0));
01752     }
01753 
01754     return dialectUnits[unit].arg(formatNumber(size, precision));
01755 }
01756 
01757 QString KLocalePrivate::formatByteSize(double size)
01758 {
01759     return formatByteSize(size, 1);
01760 }
01761 
01762 KLocale::BinaryUnitDialect KLocalePrivate::binaryUnitDialect() const
01763 {
01764     return m_binaryUnitDialect;
01765 }
01766 
01767 void KLocalePrivate::setBinaryUnitDialect(KLocale::BinaryUnitDialect newDialect)
01768 {
01769     if (newDialect > KLocale::DefaultBinaryDialect && newDialect <= KLocale::LastBinaryDialect) {
01770         QMutexLocker lock(kLocaleMutex());
01771         m_binaryUnitDialect = newDialect;
01772         m_byteSizeFmt.clear(); // Reset cached translations.
01773     }
01774 }
01775 
01776 QString KLocalePrivate::formatDuration(unsigned long mSec) const
01777 {
01778     if (mSec >= 24*3600000) {
01779         return i18nc("@item:intext %1 is a real number, e.g. 1.23 days", "%1 days",
01780                      formatNumber(mSec / (24 * 3600000.0), 2));
01781     } else if (mSec >= 3600000) {
01782         return i18nc("@item:intext %1 is a real number, e.g. 1.23 hours", "%1 hours",
01783                      formatNumber(mSec / 3600000.0, 2));
01784     } else if (mSec >= 60000) {
01785         return i18nc("@item:intext %1 is a real number, e.g. 1.23 minutes", "%1 minutes",
01786                      formatNumber(mSec / 60000.0, 2));
01787     } else if (mSec >= 1000) {
01788         return i18nc("@item:intext %1 is a real number, e.g. 1.23 seconds", "%1 seconds",
01789                      formatNumber(mSec / 1000.0, 2));
01790     }
01791     return i18ncp("@item:intext", "%1 millisecond", "%1 milliseconds", mSec);
01792 }
01793 
01794 QString KLocalePrivate::formatSingleDuration(KLocalePrivate::DurationType durationType, int n)
01795 {
01796     switch (durationType) {
01797     case KLocalePrivate::DaysDurationType:
01798         return i18ncp("@item:intext", "1 day", "%1 days", n);
01799     case KLocalePrivate::HoursDurationType:
01800         return i18ncp("@item:intext", "1 hour", "%1 hours", n);
01801     case KLocalePrivate::MinutesDurationType:
01802         return i18ncp("@item:intext", "1 minute", "%1 minutes", n);
01803     case KLocalePrivate::SecondsDurationType:
01804         return i18ncp("@item:intext", "1 second", "%1 seconds", n);
01805     }
01806     return QString();
01807 }
01808 
01809 QString KLocalePrivate::prettyFormatDuration(unsigned long mSec) const
01810 {
01811     unsigned long ms = mSec;
01812     int days = ms / (24 * 3600000);
01813     ms = ms % (24 * 3600000);
01814     int hours = ms / 3600000;
01815     ms = ms % 3600000;
01816     int minutes = ms / 60000;
01817     ms = ms % 60000;
01818     int seconds = qRound(ms / 1000.0);
01819 
01820     // Handle correctly problematic case #1 (look at KLocaleTest::prettyFormatDuration()
01821     // at klocaletest.cpp)
01822     if (seconds == 60) {
01823         return prettyFormatDuration(mSec - ms + 60000);
01824     }
01825 
01826     if (days && hours) {
01827         return i18nc("@item:intext days and hours. This uses the previous item:intext messages. If this does not fit the grammar of your language please contact the i18n team to solve the problem",
01828                      "%1 and %2", formatSingleDuration(KLocalePrivate::DaysDurationType, days),
01829                      formatSingleDuration(KLocalePrivate::HoursDurationType, hours));
01830     } else if (days) {
01831         return formatSingleDuration(KLocalePrivate::DaysDurationType, days);
01832     } else if (hours && minutes) {
01833         return i18nc("@item:intext hours and minutes. This uses the previous item:intext messages. If this does not fit the grammar of your language please contact the i18n team to solve the problem",
01834                      "%1 and %2",
01835                      formatSingleDuration(KLocalePrivate::HoursDurationType, hours),
01836                      formatSingleDuration(KLocalePrivate::MinutesDurationType, minutes));
01837     } else if (hours) {
01838         return formatSingleDuration(KLocalePrivate::HoursDurationType, hours);
01839     } else if (minutes && seconds) {
01840         return i18nc("@item:intext minutes and seconds. This uses the previous item:intext messages. If this does not fit the grammar of your language please contact the i18n team to solve the problem",
01841                      "%1 and %2",
01842                      formatSingleDuration(KLocalePrivate::MinutesDurationType, minutes),
01843                      formatSingleDuration(KLocalePrivate::SecondsDurationType, seconds));
01844     } else if (minutes) {
01845         return formatSingleDuration(KLocalePrivate::MinutesDurationType, minutes);
01846     } else {
01847         return formatSingleDuration(KLocalePrivate::SecondsDurationType, seconds);
01848     }
01849 }
01850 
01851 QString KLocalePrivate::formatDate(const QDate &date, KLocale::DateFormat format)
01852 {
01853     return calendar()->formatDate(date, format);
01854 }
01855 
01856 void KLocalePrivate::setMainCatalog(const char *catalog)
01857 {
01858     KLocaleStaticData *s = staticData;
01859     s->maincatalog = QString::fromUtf8(catalog);
01860 }
01861 
01862 double KLocalePrivate::readNumber(const QString &_str, bool * ok) const
01863 {
01864     QString str = _str.trimmed();
01865     bool neg = false;
01866 
01867     // Check negative or positive signs
01868     // Assumes blank sign is positive even if pos sign set, unless already taken by negative
01869     if (!negativeSign().isEmpty() && str.indexOf(negativeSign()) == 0) {
01870         neg = true;
01871         str.remove(0, negativeSign().length());
01872         str = str.trimmed();
01873     } else if (!positiveSign().isEmpty() && str.indexOf(positiveSign()) == 0) {
01874         neg = false;
01875         str.remove(0, positiveSign().length());
01876         str = str.trimmed();
01877     } else if (negativeSign().isEmpty() && str[0].isDigit()) {
01878         neg = true;
01879     }
01880 
01881     /* will hold the scientific notation portion of the number.
01882        Example, with 2.34E+23, exponentialPart == "E+23"
01883     */
01884     QString exponentialPart;
01885     int EPos;
01886 
01887     EPos = str.indexOf(QLatin1Char('E'), 0, Qt::CaseInsensitive);
01888 
01889     if (EPos != -1) {
01890         exponentialPart = str.mid(EPos);
01891         str = str.left(EPos);
01892         str = str.trimmed();
01893     }
01894 
01895     // Remove group separators
01896     bool groupOk = true;
01897     str = parseDigitGroup(str, thousandsSeparator(), decimalSymbol(), numericDigitGrouping(), &groupOk);
01898 
01899     if (!groupOk) {
01900         if (ok) {
01901             *ok = false;
01902         }
01903         return 0.0;
01904     }
01905 
01906     int pos = str.indexOf(decimalSymbol());
01907     QString major;
01908     QString minor;
01909     if (pos == -1) {
01910         major = str;
01911     } else {
01912         major = str.left(pos);
01913         minor = str.mid(pos + decimalSymbol().length());
01914     }
01915 
01916     // Check the major and minor parts are only digits
01917     bool digitTest = true;
01918     foreach (const QChar &ch, major) {
01919         if (!ch.isDigit()) {
01920             digitTest = false;
01921             break;
01922         }
01923     }
01924     foreach (const QChar &ch, minor) {
01925         if (!ch.isDigit()) {
01926             digitTest = false;
01927             break;
01928         }
01929     }
01930     if (!digitTest) {
01931         if (ok) {
01932             *ok = false;
01933         }
01934         return 0.0;
01935     }
01936 
01937     QString tot;
01938     if (neg) {
01939         tot = QLatin1Char('-');
01940     }
01941     tot += major + QLatin1Char('.') + minor + exponentialPart;
01942     tot = toArabicDigits(tot);
01943     return tot.toDouble(ok);
01944 }
01945 
01946 double KLocalePrivate::readMoney(const QString &_str, bool *ok) const
01947 {
01948     QString str = _str.trimmed();
01949     bool neg = false;
01950     bool currencyFound = false;
01951     QString symbol = currencySymbol();
01952 
01953     // First try removing currency symbol from either end
01954     int pos = str.indexOf(symbol);
01955     if (pos == 0 || pos == (int) str.length() - symbol.length()) {
01956         str.remove(pos, symbol.length());
01957         str = str.trimmed();
01958         currencyFound = true;
01959     }
01960     if (str.isEmpty()) {
01961         if (ok) {
01962             *ok = false;
01963         }
01964         return 0;
01965     }
01966 
01967     // Then try removing sign from either end (with a special case for parenthesis)
01968     if (str[0] == QLatin1Char('(') && str[str.length()-1] == QLatin1Char(')')) {
01969         if (positiveMonetarySignPosition() != KLocale::ParensAround) {
01970             neg = true;
01971         }
01972         str.remove(str.length() - 1, 1);
01973         str.remove(0, 1);
01974         str = str.trimmed();
01975     } else {
01976         int len = 0;
01977         QString sign;
01978         int negLen = negativeSign().length();
01979         QString negSign = negativeSign();
01980         if (!negSign.isEmpty() && (str.left(negLen) == negSign || str.right(negSign.length()) == negSign)) {
01981             neg = true;
01982             len = negLen;
01983             sign = negSign;
01984         } else {
01985             int posLen = positiveSign().length();
01986             QString posSign = positiveSign();
01987             if (!posSign.isEmpty() && (str.left(posLen) == posSign || str.right(posSign.length()) == posSign)) {
01988                 len = posLen;
01989                 sign = posSign;
01990             } else if (negSign.isEmpty() && str[0].isDigit() && str[str.length() - 1].isDigit()){
01991                 neg = true;
01992             }
01993         }
01994         if (!sign.isEmpty()) {
01995             if (str.left(len) == sign) {
01996                 str.remove(0, len);
01997             } else {
01998                 str.remove(str.length() - len, len);
01999             }
02000             str = str.trimmed();
02001         }
02002     }
02003 
02004     // Finally try again for the currency symbol, if we didn't find
02005     // it already (because of the negative sign being in the way).
02006     if (!currencyFound) {
02007         pos = str.indexOf(symbol);
02008         if (pos == 0 || pos == (int) str.length() - symbol.length()) {
02009             str.remove(pos, symbol.length());
02010             str = str.trimmed();
02011         }
02012     }
02013 
02014     // Remove group separators
02015     bool groupOk = true;
02016     str = parseDigitGroup(str, monetaryThousandsSeparator(), monetaryDecimalSymbol(), monetaryDigitGrouping(), &groupOk);
02017 
02018     if (!groupOk) {
02019         if (ok) {
02020             *ok = false;
02021         }
02022         return 0.0;
02023     }
02024 
02025     // And parse the rest as a number
02026     pos = str.indexOf(monetaryDecimalSymbol());
02027     QString major;
02028     QString minor;
02029     if (pos == -1) {
02030         major = str;
02031     } else {
02032         major = str.left(pos);
02033         minor = str.mid(pos + monetaryDecimalSymbol().length());
02034     }
02035 
02036     // Check the major and minor parts are only digits
02037     bool digitTest = true;
02038     foreach (const QChar &ch, major) {
02039         if (!ch.isDigit()) {
02040             digitTest = false;
02041             break;
02042         }
02043     }
02044     foreach (const QChar &ch, minor) {
02045         if (!ch.isDigit()) {
02046             digitTest = false;
02047             break;
02048         }
02049     }
02050     if (!digitTest) {
02051         if (ok) {
02052             *ok = false;
02053         }
02054         return 0.0;
02055     }
02056 
02057     QString tot;
02058     if (neg) {
02059         tot = QLatin1Char('-');
02060     }
02061     tot += major + QLatin1Char('.') + minor;
02062     tot = toArabicDigits(tot);
02063     return tot.toDouble(ok);
02064 }
02065 
02072 static int readInt(const QString &str, int &pos)
02073 {
02074     if (!str.at(pos).isDigit()) {
02075         return -1;
02076     }
02077     int result = 0;
02078     for (; str.length() > pos && str.at(pos).isDigit(); ++pos) {
02079         result *= 10;
02080         result += str.at(pos).digitValue();
02081     }
02082 
02083     return result;
02084 }
02085 
02086 QDate KLocalePrivate::readDate(const QString &intstr, bool *ok)
02087 {
02088     return calendar()->readDate(intstr, ok);
02089 }
02090 
02091 QDate KLocalePrivate::readDate(const QString &intstr, KLocale::ReadDateFlags flags, bool *ok)
02092 {
02093     return calendar()->readDate(intstr, flags, ok);
02094 }
02095 
02096 QDate KLocalePrivate::readDate(const QString &intstr, const QString &fmt, bool *ok)
02097 {
02098     return calendar()->readDate(intstr, fmt, ok);
02099 }
02100 
02101 QTime KLocalePrivate::readTime(const QString &intstr, bool *ok) const
02102 {
02103     QTime time = readLocaleTime(intstr, ok, KLocale::TimeDefault, KLocale::ProcessStrict);
02104     if (time.isValid()) {
02105         return time;
02106     }
02107     return readLocaleTime(intstr, ok, KLocale::TimeWithoutSeconds, KLocale::ProcessStrict);
02108 }
02109 
02110 QTime KLocalePrivate::readTime(const QString &intstr, KLocale::ReadTimeFlags flags, bool *ok) const
02111 {
02112     return readLocaleTime(intstr, ok, (flags == KLocale::WithSeconds) ? KLocale::TimeDefault : KLocale::TimeWithoutSeconds,
02113                           KLocale::ProcessStrict);
02114 }
02115 
02116 // remove the first occurrence of the 2-character string
02117 // strip2char from inout and if found, also remove one preceding
02118 // punctuation character and arbitrary number of spaces.
02119 static void stripStringAndPreceedingSeparator(QString &inout, const QLatin1String &strip2char)
02120 {
02121     int remPos = inout.indexOf(strip2char);
02122     if (remPos == -1) {
02123         return;
02124     }
02125     int endPos = remPos + 2;
02126     int curPos = remPos - 1;
02127     while (curPos >= 0 && inout.at(curPos).isSpace()) {
02128         curPos--;
02129     }
02130     // remove the separator sign before the seconds
02131     // and assume that works everywhere
02132     if (curPos >= 0 && inout.at(curPos).isPunct() && inout.at(curPos) != QLatin1Char('%')) {
02133         curPos--;
02134     }
02135     while (curPos >= 0 && inout.at(curPos).isSpace()) {
02136         curPos--;
02137     }
02138 
02139     remPos = qMax(curPos + 1, 0);
02140     inout.remove(remPos, endPos - remPos);
02141 }
02142 
02143 // remove the first occurrence of the 2-character string
02144 // strip2char from inout and if found, also remove one
02145 // succeeding punctuation character and arbitrary number of spaces.
02146 static void stripStringAndSucceedingSeparator(QString &inout, const QLatin1String &strip2char)
02147 {
02148     int remPos = inout.indexOf(strip2char);
02149     if (remPos == -1) {
02150         return;
02151     }
02152     int curPos = remPos + 2;
02153     while (curPos < inout.size() &&
02154            (inout.at(curPos).isSpace() ||
02155             (inout.at(curPos).isPunct() && inout.at(curPos) != QLatin1Char('%')))) {
02156         curPos++;
02157     }
02158     inout.remove(remPos, curPos - remPos);
02159 }
02160 
02161 // remove the first occurrence of "%p" from the inout.
02162 static void stripAmPmFormat(QString &inout)
02163 {
02164     // NOTE: this function assumes that %p - if it's present -
02165     //       is either the first or the last element of the format
02166     //       string. Either a succeeding or a preceding
02167     //       punctuation symbol is stripped.
02168     int length = inout.size();
02169     int ppos = inout.indexOf(QLatin1String("%p"));
02170     if (ppos == -1) {
02171         return;
02172     } else if (ppos == 0) {
02173         // first element, eat succeeding punctuation and spaces
02174         ppos = 2;
02175         while (ppos < length && (inout.at(ppos).isSpace() || inout.at(ppos).isPunct()) &&
02176                 inout.at(ppos) != QLatin1Char('%')) {
02177             ppos++;
02178         }
02179         inout = inout.mid(ppos);
02180     } else {
02181         stripStringAndPreceedingSeparator(inout, QLatin1String("%p"));
02182     }
02183 }
02184 
02185 QTime KLocalePrivate::readLocaleTime(const QString &intstr, bool *ok, KLocale::TimeFormatOptions options,
02186                                      KLocale::TimeProcessingOptions processing) const
02187 {
02188     QString str(intstr.simplified().toLower());
02189     QString format(timeFormat().simplified());
02190 
02191     int hour = -1;
02192     int minute = -1;
02193     int second = -1;
02194     bool useDayPeriod = false;
02195     KDayPeriod dayPeriod = dayPeriodForTime(QTime(0,0,0));
02196     int strpos = 0;
02197     int formatpos = 0;
02198     bool error = false;
02199 
02200     bool excludeSecs = ((options & KLocale::TimeWithoutSeconds) == KLocale::TimeWithoutSeconds);
02201     bool isDuration = ((options & KLocale::TimeDuration) == KLocale::TimeDuration);
02202     bool noAmPm = ((options & KLocale::TimeWithoutAmPm) == KLocale::TimeWithoutAmPm);
02203     bool foldHours = ((options & KLocale::TimeFoldHours) == KLocale::TimeFoldHours);
02204     bool strict = ((processing & KLocale::ProcessStrict) == KLocale::ProcessStrict);
02205 
02206     // if seconds aren't needed, strip them from the timeFormat
02207     if (excludeSecs) {
02208         stripStringAndPreceedingSeparator(format, QLatin1String("%S"));
02209         second = 0; // seconds are always 0
02210     }
02211 
02212     // if hours are folded, strip them from the timeFormat
02213     if (foldHours) {
02214         stripStringAndSucceedingSeparator(format, QLatin1String("%H"));
02215         stripStringAndSucceedingSeparator(format, QLatin1String("%k"));
02216         stripStringAndSucceedingSeparator(format, QLatin1String("%I"));
02217         stripStringAndSucceedingSeparator(format, QLatin1String("%l"));
02218     }
02219 
02220     // if am/pm isn't needed, strip it from the timeFormat
02221     if (noAmPm) {
02222         stripAmPmFormat(format);
02223     }
02224 
02225     while (!error && (format.length() > formatpos || str.length() > strpos)) {
02226         if (!(format.length() > formatpos && str.length() > strpos)) {
02227             error = true;
02228             break;
02229         }
02230 
02231         QChar c = format.at(formatpos++);
02232         if (c.isSpace()) {
02233             if (strict) { // strict processing: space is needed
02234                 if (!str.at(strpos).isSpace()) {
02235                     error = true;
02236                     break;
02237                 }
02238                 strpos++;
02239             } else { // lax processing: space in str not needed
02240                 // 1 space maximum as str is simplified
02241                 if (str.at(strpos).isSpace()) {
02242                     strpos++;
02243                 }
02244             }
02245             continue;
02246         }
02247 
02248         if (c != QLatin1Char('%')) {
02249             if (c != str.at(strpos++)) {
02250                 error = true;
02251                 break;
02252             }
02253             continue;
02254         }
02255 
02256         c = format.at(formatpos++);
02257         switch (c.unicode()) {
02258 
02259         case 'p': // Day Period, normally AM/PM
02260         case 'P': // Lowercase Day Period, normally am/pm
02261         {
02262             error = true;
02263             foreach (const KDayPeriod &testDayPeriod, dayPeriods()) {
02264                 QString dayPeriodText = testDayPeriod.periodName(KLocale::ShortName);
02265                 int len = dayPeriodText.length();
02266                 if (str.mid(strpos, len) == dayPeriodText.toLower()) {
02267                     dayPeriod = testDayPeriod;
02268                     strpos += len;
02269                     error = false;
02270                     useDayPeriod = true;
02271                     break;
02272                 }
02273             }
02274             break;
02275         }
02276 
02277         case 'k':  // 24h Hours Short Number
02278         case 'H':  // 24h Hours Long Number
02279             useDayPeriod = false;
02280             hour = readInt(str, strpos);
02281             break;
02282 
02283         case 'l': // 12h Hours Short Number
02284         case 'I': // 12h Hours Long Number
02285             useDayPeriod = !isDuration;
02286             hour = readInt(str, strpos);
02287             break;
02288 
02289         case 'M':
02290             minute = readInt(str, strpos);
02291             // minutes can be bigger than 59 if hours are folded
02292             if (foldHours) {
02293                 // if hours are folded, make sure minutes doesn't get bigger than 59.
02294                 hour = minute / 60;
02295                 minute = minute % 60;
02296             }
02297             break;
02298 
02299         case 'S':
02300             second = readInt(str, strpos);
02301             break;
02302         }
02303 
02304         // NOTE: if anything is performed inside this loop, be sure to
02305         //       check for error!
02306     }
02307 
02308     QTime returnTime;
02309     if (!error) {
02310         if (useDayPeriod) {
02311             returnTime = dayPeriod.time(hour, minute, second);
02312         } else {
02313             returnTime = QTime(hour, minute, second);
02314         }
02315     }
02316     if (ok) {
02317         *ok = returnTime.isValid();
02318     }
02319     return returnTime;
02320 }
02321 
02322 QString KLocalePrivate::formatTime(const QTime &time, bool includeSecs, bool isDuration) const
02323 {
02324     KLocale::TimeFormatOptions options = KLocale::TimeDefault;
02325     if (!includeSecs) {
02326         options |= KLocale::TimeWithoutSeconds;
02327     }
02328     if (isDuration) {
02329         options |= KLocale::TimeDuration;
02330     }
02331     return formatLocaleTime(time, options);
02332 }
02333 
02334 QString KLocalePrivate::formatLocaleTime(const QTime &time, KLocale::TimeFormatOptions options) const
02335 {
02336     QString rst(timeFormat());
02337 
02338     bool excludeSecs = ((options & KLocale::TimeWithoutSeconds) == KLocale::TimeWithoutSeconds);
02339     bool isDuration = ((options & KLocale::TimeDuration) == KLocale::TimeDuration);
02340     bool noAmPm = ((options & KLocale::TimeWithoutAmPm) == KLocale::TimeWithoutAmPm);
02341     bool foldHours = ((options & KLocale::TimeFoldHours) == KLocale::TimeFoldHours);
02342 
02343     // if seconds aren't needed, strip them from the timeFormat
02344     if (excludeSecs) {
02345         stripStringAndPreceedingSeparator(rst, QLatin1String("%S"));
02346     }
02347 
02348     // if hours should be folded, strip all hour symbols from the timeFormat
02349     if (foldHours) {
02350         stripStringAndSucceedingSeparator(rst, QLatin1String("%H"));
02351         stripStringAndSucceedingSeparator(rst, QLatin1String("%k"));
02352         stripStringAndSucceedingSeparator(rst, QLatin1String("%I"));
02353         stripStringAndSucceedingSeparator(rst, QLatin1String("%l"));
02354     }
02355 
02356     // if am/pm isn't needed, strip it from the timeFormat
02357     if (noAmPm) {
02358         stripAmPmFormat(rst);
02359     }
02360 
02361     // only "pm/am" and %M here can grow, the rest shrinks, but
02362     // I'm rather safe than sorry
02363     QChar *buffer = new QChar[rst.length() * 3 / 2 + 32];
02364 
02365     int index = 0;
02366     bool escape = false;
02367     int number = 0;
02368 
02369     for (int format_index = 0; format_index < rst.length(); format_index++) {
02370         if (!escape) {
02371             if (rst.at(format_index).unicode() == '%') {
02372                 escape = true;
02373             } else {
02374                 buffer[index++] = rst.at(format_index);
02375             }
02376         } else {
02377             switch (rst.at(format_index).unicode()) {
02378             case '%':
02379                 buffer[index++] = QLatin1Char('%');
02380                 break;
02381             case 'H':
02382                 put_it_in(buffer, index, time.hour());
02383                 break;
02384             case 'I':
02385                 if (isDuration) {
02386                     put_it_in(buffer, index, time.hour());
02387                 } else {
02388                     put_it_in(buffer, index, dayPeriodForTime(time).hourInPeriod(time));
02389                 }
02390                 break;
02391             case 'M':
02392                 if (foldHours) {
02393                     put_it_in(buffer, index, QString::number(time.hour() * 60 + time.minute()));
02394                 } else {
02395                     put_it_in(buffer, index, time.minute());
02396                 }
02397                 break;
02398             case 'S':
02399                 put_it_in(buffer, index, time.second());
02400                 break;
02401             case 'k':
02402             case 'l':
02403                 // to share the code
02404                 if (!isDuration && rst.at(format_index).unicode() == 'l') {
02405                     number = dayPeriodForTime(time).hourInPeriod(time);
02406                 } else {
02407                     number = time.hour();
02408                 }
02409                 if (number / 10) {
02410                     buffer[index++] = number / 10 + '0';
02411                 }
02412                 buffer[index++] = number % 10 + '0';
02413                 break;
02414             case 'p':
02415             {
02416                 put_it_in(buffer, index, dayPeriodForTime(time).periodName(KLocale::ShortName));
02417                 break;
02418             }
02419             default:
02420                 buffer[index++] = rst.at(format_index);
02421                 break;
02422             }
02423             escape = false;
02424         }
02425     }
02426     QString ret(buffer, index);
02427     delete [] buffer;
02428     ret = convertDigits(ret, dateTimeDigitSet());
02429     return ret.trimmed();
02430 }
02431 
02432 bool KLocalePrivate::use12Clock() const
02433 {
02434     if ((timeFormat().contains(QString::fromLatin1("%I")) > 0) ||
02435         (timeFormat().contains(QString::fromLatin1("%l")) > 0)) {
02436         return true;
02437     } else {
02438         return false;
02439     }
02440 }
02441 
02442 void KLocalePrivate::setDayPeriods(const QList<KDayPeriod> &dayPeriods)
02443 {
02444     if (dayPeriods.count() > 0) {
02445         foreach (const KDayPeriod &dayPeriod, dayPeriods) {
02446             if (!dayPeriod.isValid()) {
02447                 return;
02448             }
02449         }
02450         m_dayPeriods = dayPeriods;
02451     }
02452 }
02453 
02454 QList<KDayPeriod> KLocalePrivate::dayPeriods() const
02455 {
02456     // If no Day Periods currently loaded then it means there were no country specific ones defined
02457     // in the country l10n file, so default to standard AM/PM translations for the users language.
02458     // Note we couldn't do this in initDayPeriods() as i18n isn't available until we have a
02459     // valid loacle constructed.
02460     if (m_dayPeriods.isEmpty()) {
02461         m_dayPeriods.append(KDayPeriod(QString::fromLatin1("am"),
02462                                        i18nc( "Before Noon KLocale::LongName", "Ante Meridiem" ),
02463                                        i18nc( "Before Noon KLocale::ShortName", "AM" ),
02464                                        i18nc( "Before Noon KLocale::NarrowName", "A" ),
02465                                        QTime( 0, 0, 0 ), QTime( 11, 59, 59, 999 ), 0, 12 ));
02466         m_dayPeriods.append(KDayPeriod(QString::fromLatin1("pm"),
02467                                        i18nc( "After Noon KLocale::LongName", "Post Meridiem" ),
02468                                        i18nc( "After Noon KLocale::ShortName", "PM" ),
02469                                        i18nc( "After Noon KLocale::NarrowName", "P" ),
02470                                        QTime( 12, 0, 0 ), QTime( 23, 59, 59, 999 ), 0, 12 ));
02471     }
02472     return m_dayPeriods;
02473 }
02474 
02475 KDayPeriod KLocalePrivate::dayPeriodForTime(const QTime &time) const
02476 {
02477     if (time.isValid()) {
02478         foreach (const KDayPeriod &dayPeriod, dayPeriods()) {
02479             if (dayPeriod.isValid(time)) {
02480                 return dayPeriod;
02481             }
02482         }
02483     }
02484     return KDayPeriod();
02485 }
02486 
02487 QStringList KLocalePrivate::languageList() const
02488 {
02489     return m_languageList;
02490 }
02491 
02492 QStringList KLocalePrivate::currencyCodeList() const
02493 {
02494     return m_currencyCodeList;
02495 }
02496 
02497 QString KLocalePrivate::formatDateTime(const KLocale *locale, const QDateTime &dateTime, KLocale::DateFormat format,
02498                                        bool includeSeconds, int daysTo, int secsTo)
02499 {
02500     // Have to do Fancy Date formatting here rather than using normal KCalendarSystem::formatDate()
02501     // as daysTo is relative to the time spec which formatDate doesn't know about.  Needs to be
02502     // kept in sync with Fancy Date code in KCalendarSystem::formatDate().  Fix in KDE5.
02503 
02504     // Only do Fancy if less than an hour into the future or less than a week in the past
02505     if ((daysTo == 0 && secsTo > 3600) ||  daysTo < 0 || daysTo > 6) {
02506         if (format == KLocale::FancyShortDate) {
02507             format = KLocale::ShortDate;
02508         } else if (format == KLocale::FancyLongDate) {
02509             format = KLocale::LongDate;
02510         }
02511     }
02512 
02513     QString dateStr;
02514     if (format == KLocale::FancyShortDate || format == KLocale::FancyLongDate) {
02515         switch (daysTo) {
02516         case 0:
02517             dateStr = i18n("Today");
02518             break;
02519         case 1:
02520             dateStr = i18n("Yesterday");
02521             break;
02522         default:
02523             dateStr = locale->calendar()->weekDayName(dateTime.date());
02524         }
02525     } else {
02526         dateStr = locale->formatDate(dateTime.date(), format);
02527     }
02528 
02529     KLocale::TimeFormatOption timeFormat;
02530     if (includeSeconds) {
02531         timeFormat = KLocale::TimeDefault;
02532     } else {
02533         timeFormat = KLocale::TimeWithoutSeconds;
02534     }
02535 
02536     return i18nc("concatenation of dates and time", "%1 %2", dateStr,
02537                  locale->formatLocaleTime(dateTime.time(), timeFormat));
02538 }
02539 
02540 QString KLocalePrivate::formatDateTime(const QDateTime &dateTime, KLocale::DateFormat format, bool includeSeconds) const
02541 {
02542     QDateTime now = QDateTime::currentDateTime();
02543     int daysTo = dateTime.date().daysTo(now.date());
02544     int secsTo = now.secsTo(dateTime);
02545     return KLocalePrivate::formatDateTime(q, dateTime, format, includeSeconds, daysTo, secsTo);
02546 }
02547 
02548 QString KLocalePrivate::formatDateTime(const KDateTime &dateTime, KLocale::DateFormat format,
02549                                        KLocale::DateTimeFormatOptions options)
02550 {
02551     QString dt;
02552 
02553     if (dateTime.isDateOnly()) {
02554         dt = formatDate(dateTime.date(), format);
02555     } else {
02556         KDateTime now = KDateTime::currentDateTime(dateTime.timeSpec());
02557         int daysTo = dateTime.date().daysTo(now.date());
02558         int secsTo = now.secsTo(dateTime);
02559         dt = KLocalePrivate::formatDateTime(q, dateTime.dateTime(), format, (options & KLocale::Seconds), daysTo, secsTo);
02560     }
02561 
02562     if (options & KLocale::TimeZone) {
02563         QString tz;
02564         switch (dateTime.timeType()) {
02565         case KDateTime::OffsetFromUTC:
02566             tz = i18n(dateTime.toString(QString::fromLatin1("%z")).toUtf8());
02567             break;
02568         case KDateTime::UTC:
02569         case KDateTime::TimeZone:
02570             tz = i18n(dateTime.toString(QString::fromLatin1((format == KLocale::ShortDate) ? "%Z" : "%:Z")).toUtf8());
02571             break;
02572         case KDateTime::ClockTime:
02573         default:
02574             break;
02575         }
02576         return i18nc("concatenation of date/time and time zone", "%1 %2", dt, tz);
02577     }
02578 
02579     return dt;
02580 }
02581 
02582 QString KLocalePrivate::langLookup(const QString &fname, const char *rtype)
02583 {
02584     QStringList search;
02585 
02586     // assemble the local search paths
02587     const QStringList localDoc = KGlobal::dirs()->resourceDirs(rtype);
02588 
02589     // look up the different languages
02590     for (int id = localDoc.count() - 1; id >= 0; --id) {
02591         QStringList langs = KGlobal::locale()->languageList();
02592         // FIXME: KDE 4.5, change such that English is not assumed.
02593         langs.replaceInStrings(QLatin1String("en_US"), QLatin1String("en"));
02594         langs.append(QLatin1String("en"));
02595         Q_FOREACH(const QString &lang, langs)
02596             search.append(QString::fromLatin1("%1%2/%3").arg(localDoc[id]).arg(lang).arg(fname));
02597     }
02598 
02599     // try to locate the file
02600     Q_FOREACH(const QString &file, search) {
02601         kDebug(173) << "Looking for help in: " << file;
02602 
02603         QFileInfo info(file);
02604         if (info.exists() && info.isFile() && info.isReadable())
02605             return file;
02606     }
02607 
02608     return QString();
02609 }
02610 
02611 bool KLocalePrivate::useDefaultLanguage() const
02612 {
02613     return language() == KLocale::defaultLanguage();
02614 }
02615 
02616 void KLocalePrivate::initEncoding()
02617 {
02618     m_codecForEncoding = 0;
02619 
02620     // This all made more sense when we still had the EncodingEnum config key.
02621 
02622     QByteArray codeset = systemCodeset();
02623 
02624     if (!codeset.isEmpty()) {
02625         QTextCodec* codec = QTextCodec::codecForName(codeset);
02626         if (codec) {
02627             setEncoding(codec->mibEnum());
02628         }
02629     } else {
02630         setEncoding(QTextCodec::codecForLocale()->mibEnum());
02631     }
02632 
02633     if (!m_codecForEncoding) {
02634         kWarning() << "Cannot resolve system encoding, defaulting to ISO 8859-1.";
02635         const int mibDefault = 4; // ISO 8859-1
02636         setEncoding(mibDefault);
02637     }
02638 
02639     Q_ASSERT(m_codecForEncoding);
02640 }
02641 
02642 QByteArray KLocalePrivate::systemCodeset() const
02643 {
02644     QByteArray codeset;
02645 #if HAVE_LANGINFO_H
02646     // Qt since 4.2 always returns 'System' as codecForLocale and KDE (for example
02647     // KEncodingFileDialog) expects real encoding name. So on systems that have langinfo.h use
02648     // nl_langinfo instead, just like Qt compiled without iconv does. Windows already has its own
02649     // workaround
02650 
02651     codeset = nl_langinfo(CODESET);
02652 
02653     if ((codeset == "ANSI_X3.4-1968") || (codeset == "US-ASCII")) {
02654         // means ascii, "C"; QTextCodec doesn't know, so avoid warning
02655         codeset = "ISO-8859-1";
02656     }
02657 #endif
02658     return codeset;
02659 }
02660 
02661 void KLocalePrivate::initFileNameEncoding()
02662 {
02663     // If the following environment variable is set, assume all filenames
02664     // are in UTF-8 regardless of the current C locale.
02665     m_utf8FileEncoding = !qgetenv("KDE_UTF8_FILENAMES").isEmpty();
02666     if (m_utf8FileEncoding) {
02667         QFile::setEncodingFunction(KLocalePrivate::encodeFileNameUTF8);
02668         QFile::setDecodingFunction(KLocalePrivate::decodeFileNameUTF8);
02669     }
02670     // Otherwise, stay with QFile's default filename encoding functions
02671     // which, on Unix platforms, use the locale's codec.
02672 }
02673 
02674 QByteArray KLocalePrivate::encodeFileNameUTF8(const QString & fileName)
02675 {
02676     return fileName.toUtf8();
02677 }
02678 
02679 QString KLocalePrivate::decodeFileNameUTF8(const QByteArray &localFileName)
02680 {
02681     return QString::fromUtf8(localFileName);
02682 }
02683 
02684 void KLocalePrivate::setDateFormat(const QString &format)
02685 {
02686     m_dateFormat = format.trimmed();
02687 }
02688 
02689 void KLocalePrivate::setDateFormatShort(const QString &format)
02690 {
02691     m_dateFormatShort = format.trimmed();
02692 }
02693 
02694 void KLocalePrivate::setDateMonthNamePossessive(bool possessive)
02695 {
02696     m_dateMonthNamePossessive = possessive;
02697 }
02698 
02699 void KLocalePrivate::setTimeFormat(const QString &format)
02700 {
02701     m_timeFormat = format.trimmed();
02702 }
02703 
02704 void KLocalePrivate::setWeekStartDay(int day)
02705 {
02706     if (day >= 1 && day <= calendar()->daysInWeek(QDate())) {
02707         m_weekStartDay = day;
02708     }
02709 }
02710 
02711 void KLocalePrivate::setWorkingWeekStartDay(int day)
02712 {
02713     if (day >= 1 && day <= calendar()->daysInWeek(QDate())) {
02714         m_workingWeekStartDay = day;
02715     }
02716 }
02717 
02718 void KLocalePrivate::setWorkingWeekEndDay(int day)
02719 {
02720     if (day >= 1 && day <= calendar()->daysInWeek(QDate())) {
02721         m_workingWeekEndDay = day;
02722     }
02723 }
02724 
02725 void KLocalePrivate::setWeekDayOfPray(int day)
02726 {
02727     if (day >= 0 && day <= calendar()->daysInWeek(QDate())) { // 0 = None
02728         m_weekDayOfPray = day;
02729     }
02730 }
02731 
02732 QString KLocalePrivate::dateFormat() const
02733 {
02734     return m_dateFormat;
02735 }
02736 
02737 QString KLocalePrivate::dateFormatShort() const
02738 {
02739     return m_dateFormatShort;
02740 }
02741 
02742 QString KLocalePrivate::timeFormat() const
02743 {
02744     return m_timeFormat;
02745 }
02746 
02747 void KLocalePrivate::setDecimalPlaces(int digits)
02748 {
02749     m_decimalPlaces = digits;
02750 }
02751 
02752 void KLocalePrivate::setDecimalSymbol(const QString &symbol)
02753 {
02754     m_decimalSymbol = symbol.trimmed();
02755 }
02756 
02757 void KLocalePrivate::setThousandsSeparator(const QString &separator)
02758 {
02759     // allow spaces here
02760     m_thousandsSeparator = separator;
02761 }
02762 
02763 void KLocalePrivate::setNumericDigitGrouping(QList<int> groupList)
02764 {
02765     m_numericDigitGrouping = groupList;
02766 }
02767 
02768 void KLocalePrivate::setPositiveSign(const QString &sign)
02769 {
02770     m_positiveSign = sign.trimmed();
02771 }
02772 
02773 void KLocalePrivate::setNegativeSign(const QString &sign)
02774 {
02775     m_negativeSign = sign.trimmed();
02776 }
02777 
02778 void KLocalePrivate::setPositiveMonetarySignPosition(KLocale::SignPosition signpos)
02779 {
02780     m_positiveMonetarySignPosition = signpos;
02781 }
02782 
02783 void KLocalePrivate::setNegativeMonetarySignPosition(KLocale::SignPosition signpos)
02784 {
02785     m_negativeMonetarySignPosition = signpos;
02786 }
02787 
02788 void KLocalePrivate::setPositivePrefixCurrencySymbol(bool prefix)
02789 {
02790     m_positivePrefixCurrencySymbol = prefix;
02791 }
02792 
02793 void KLocalePrivate::setNegativePrefixCurrencySymbol(bool prefix)
02794 {
02795     m_negativePrefixCurrencySymbol = prefix;
02796 }
02797 
02798 void KLocalePrivate::setMonetaryDecimalPlaces(int digits)
02799 {
02800     m_monetaryDecimalPlaces = digits;
02801 }
02802 
02803 void KLocalePrivate::setMonetaryThousandsSeparator(const QString &separator)
02804 {
02805     // allow spaces here
02806     m_monetaryThousandsSeparator = separator;
02807 }
02808 
02809 void KLocalePrivate::setMonetaryDigitGrouping(QList<int> groupList)
02810 {
02811     m_monetaryDigitGrouping = groupList;
02812 }
02813 
02814 void KLocalePrivate::setMonetaryDecimalSymbol(const QString &symbol)
02815 {
02816     m_monetaryDecimalSymbol = symbol.trimmed();
02817 }
02818 
02819 void KLocalePrivate::setCurrencySymbol(const QString & symbol)
02820 {
02821     m_currencySymbol = symbol.trimmed();
02822 }
02823 
02824 int KLocalePrivate::pageSize() const
02825 {
02826     return m_pageSize;
02827 }
02828 
02829 void KLocalePrivate::setPageSize(int size)
02830 {
02831     // #### check if it's in range??
02832     m_pageSize = size;
02833 }
02834 
02835 KLocale::MeasureSystem KLocalePrivate::measureSystem() const
02836 {
02837     return m_measureSystem;
02838 }
02839 
02840 void KLocalePrivate::setMeasureSystem(KLocale::MeasureSystem value)
02841 {
02842     m_measureSystem = value;
02843 }
02844 
02845 QString KLocalePrivate::defaultLanguage()
02846 {
02847     static const QString en_US = QString::fromLatin1("en_US");
02848     return en_US;
02849 }
02850 
02851 QString KLocalePrivate::defaultCountry()
02852 {
02853     return QString::fromLatin1("C");
02854 }
02855 
02856 QString KLocalePrivate::defaultCurrencyCode()
02857 {
02858     return QString::fromLatin1("USD");
02859 }
02860 
02861 bool KLocalePrivate::useTranscript() const
02862 {
02863     return m_useTranscript;
02864 }
02865 
02866 const QByteArray KLocalePrivate::encoding()
02867 {
02868     return codecForEncoding()->name();
02869 }
02870 
02871 int KLocalePrivate::encodingMib() const
02872 {
02873     return codecForEncoding()->mibEnum();
02874 }
02875 
02876 int KLocalePrivate::fileEncodingMib() const
02877 {
02878     if (m_utf8FileEncoding) {
02879         return 106;
02880     }
02881     return codecForEncoding()->mibEnum();
02882 }
02883 
02884 QTextCodec *KLocalePrivate::codecForEncoding() const
02885 {
02886     return m_codecForEncoding;
02887 }
02888 
02889 bool KLocalePrivate::setEncoding(int mibEnum)
02890 {
02891     QTextCodec * codec = QTextCodec::codecForMib(mibEnum);
02892     if (codec) {
02893         m_codecForEncoding = codec;
02894     }
02895 
02896     return codec != 0;
02897 }
02898 
02899 QStringList KLocalePrivate::allLanguagesList()
02900 {
02901     if (!m_languages) {
02902         m_languages = new KConfig(QLatin1String("all_languages"), KConfig::NoGlobals, "locale");
02903     }
02904     return m_languages->groupList();
02905 }
02906 
02907 QStringList KLocalePrivate::installedLanguages()
02908 {
02909     QStringList languages;
02910     QStringList paths = KGlobal::dirs()->findAllResources("locale", QLatin1String("*/entry.desktop"));
02911     foreach (const QString &path, paths) {
02912         QString part = path.left(path.length() - 14);
02913         languages.append(part.mid(part.lastIndexOf(QLatin1Char('/')) + 1));
02914     }
02915     languages.sort();
02916     return languages;
02917 }
02918 
02919 QString KLocalePrivate::languageCodeToName(const QString &language)
02920 {
02921     if (!m_languages) {
02922         m_languages = new KConfig(QLatin1String("all_languages"), KConfig::NoGlobals, "locale");
02923     }
02924 
02925     KConfigGroup cg(m_languages, language);
02926     return cg.readEntry("Name");
02927 }
02928 
02929 QStringList KLocalePrivate::allCountriesList() const
02930 {
02931     QStringList countries;
02932     const QStringList paths = KGlobal::dirs()->findAllResources("locale", QLatin1String("l10n/*/entry.desktop"));
02933     for (QStringList::ConstIterator it = paths.begin(); it != paths.end(); ++it) {
02934         QString code = (*it).mid((*it).length() - 16, 2);
02935         if (code != QLatin1String("/C")) {
02936             countries.append(code);
02937         }
02938     }
02939     return countries;
02940 }
02941 
02942 QString KLocalePrivate::countryCodeToName(const QString &country) const
02943 {
02944     QString countryName;
02945     QString entryFile = KStandardDirs::locate("locale", QString::fromLatin1("l10n/") + country.toLower() + QLatin1String("/entry.desktop"));
02946     if (!entryFile.isEmpty()) {
02947         KConfig cfg(entryFile);
02948         KConfigGroup cg(&cfg, "KCM Locale");
02949         countryName = cg.readEntry("Name");
02950     }
02951     return countryName;
02952 }
02953 
02954 KLocale::CalendarSystem KLocalePrivate::calendarTypeToCalendarSystem(const QString &calendarType) const
02955 {
02956     if (calendarType == QLatin1String("coptic")) {
02957         return KLocale::CopticCalendar;
02958     } else if (calendarType == QLatin1String("ethiopian")) {
02959         return KLocale::EthiopianCalendar;
02960     } else if (calendarType == QLatin1String("gregorian")) {
02961         return KLocale::QDateCalendar;
02962     } else if (calendarType == QLatin1String("gregorian-proleptic")) {
02963         return KLocale::GregorianCalendar;
02964     } else if (calendarType == QLatin1String("hebrew")) {
02965         return KLocale::HebrewCalendar;
02966     } else if (calendarType == QLatin1String("hijri")) {
02967         return KLocale::IslamicCivilCalendar;
02968     } else if (calendarType == QLatin1String("indian-national")) {
02969         return KLocale::IndianNationalCalendar;
02970     } else if (calendarType == QLatin1String("jalali")) {
02971         return KLocale::JalaliCalendar;
02972     } else if (calendarType == QLatin1String("japanese")) {
02973         return KLocale::JapaneseCalendar;
02974     } else if (calendarType == QLatin1String("julian")) {
02975         return KLocale::JulianCalendar;
02976     } else if (calendarType == QLatin1String("minguo")) {
02977         return KLocale::MinguoCalendar;
02978     } else if (calendarType == QLatin1String("thai")) {
02979         return KLocale::ThaiCalendar;
02980     } else {
02981         return KLocale::QDateCalendar;
02982     }
02983 }
02984 
02985 QString KLocalePrivate::calendarSystemToCalendarType(KLocale::CalendarSystem calendarSystem) const
02986 {
02987     switch (calendarSystem) {
02988     case KLocale::QDateCalendar:
02989         return QLatin1String("gregorian");
02990     case KLocale::CopticCalendar:
02991         return QLatin1String("coptic");
02992     case KLocale::EthiopianCalendar:
02993         return QLatin1String("ethiopian");
02994     case KLocale::GregorianCalendar:
02995         return QLatin1String("gregorian-proleptic");
02996     case KLocale::HebrewCalendar:
02997         return QLatin1String("hebrew");
02998     case KLocale::IslamicCivilCalendar:
02999         return QLatin1String("hijri");
03000     case KLocale::IndianNationalCalendar:
03001         return QLatin1String("indian-national");
03002     case KLocale::JalaliCalendar:
03003         return QLatin1String("jalali");
03004     case KLocale::JapaneseCalendar:
03005         return QLatin1String("japanese");
03006     case KLocale::JulianCalendar:
03007         return QLatin1String("julian");
03008     case KLocale::MinguoCalendar:
03009         return QLatin1String("minguo");
03010     case KLocale::ThaiCalendar:
03011         return QLatin1String("thai");
03012     default:
03013         return QLatin1String("gregorian");
03014     }
03015 }
03016 
03017 void KLocalePrivate::setCalendar(const QString &calendarType)
03018 {
03019     setCalendarSystem(calendarTypeToCalendarSystem(calendarType));
03020 }
03021 
03022 void KLocalePrivate::setCalendarSystem(KLocale::CalendarSystem calendarSystem)
03023 {
03024     m_calendarSystem = calendarSystem;
03025     delete m_calendar;
03026     m_calendar = 0;
03027 }
03028 
03029 QString KLocalePrivate::calendarType() const
03030 {
03031     return calendarSystemToCalendarType(m_calendarSystem);
03032 }
03033 
03034 KLocale::CalendarSystem KLocalePrivate::calendarSystem() const
03035 {
03036     return m_calendarSystem;
03037 }
03038 
03039 const KCalendarSystem * KLocalePrivate::calendar()
03040 {
03041     if (!m_calendar) {
03042         m_calendar = KCalendarSystem::create(m_calendarSystem, m_config, q);
03043     }
03044 
03045     return m_calendar;
03046 }
03047 
03048 void KLocalePrivate::setWeekNumberSystem(KLocale::WeekNumberSystem weekNumberSystem)
03049 {
03050     m_weekNumberSystem = weekNumberSystem;
03051 }
03052 
03053 KLocale::WeekNumberSystem KLocalePrivate::weekNumberSystem()
03054 {
03055     return m_weekNumberSystem;
03056 }
03057 
03058 void KLocalePrivate::copyCatalogsTo(KLocale *locale)
03059 {
03060     QMutexLocker lock(kLocaleMutex());
03061     locale->d->m_catalogNames = m_catalogNames;
03062     locale->d->updateCatalogs();
03063 }
03064 
03065 QString KLocalePrivate::localizedFilePath(const QString &filePath) const
03066 {
03067     // Stop here if the default language is primary.
03068     if (useDefaultLanguage()) {
03069         return filePath;
03070     }
03071 
03072     // Check if l10n sudir is present, stop if not.
03073     QFileInfo fileInfo(filePath);
03074     QString locDirPath = fileInfo.path() + QLatin1String("/l10n");
03075     QFileInfo locDirInfo(locDirPath);
03076     if (!locDirInfo.isDir()) {
03077         return filePath;
03078     }
03079 
03080     // Go through possible localized paths by priority of languages,
03081     // return first that exists.
03082     QString fileName = fileInfo.fileName();
03083     foreach(const QString &lang, languageList()) {
03084         // Stop when the default language is reached.
03085         if (lang == KLocale::defaultLanguage()) {
03086             return filePath;
03087         }
03088         QString locFilePath = locDirPath + QLatin1Char('/') + lang + QLatin1Char('/') + fileName;
03089         QFileInfo locFileInfo(locFilePath);
03090         if (locFileInfo.isFile() && locFileInfo.isReadable()) {
03091             return locFilePath;
03092         }
03093     }
03094 
03095     return filePath;
03096 }
03097 
03098 QString KLocalePrivate::removeAcceleratorMarker(const QString &label) const
03099 {
03100     return ::removeAcceleratorMarker(label);
03101 }
03102 
03103 void KLocalePrivate::setDigitSet(KLocale::DigitSet digitSet)
03104 {
03105     m_digitSet = digitSet;
03106 }
03107 
03108 KLocale::DigitSet KLocalePrivate::digitSet() const
03109 {
03110     return m_digitSet;
03111 }
03112 
03113 void KLocalePrivate::setMonetaryDigitSet(KLocale::DigitSet digitSet)
03114 {
03115     m_monetaryDigitSet = digitSet;
03116 }
03117 
03118 KLocale::DigitSet KLocalePrivate::monetaryDigitSet() const
03119 {
03120     return m_monetaryDigitSet;
03121 }
03122 
03123 void KLocalePrivate::setDateTimeDigitSet(KLocale::DigitSet digitSet)
03124 {
03125     m_dateTimeDigitSet = digitSet;
03126 }
03127 
03128 KLocale::DigitSet KLocalePrivate::dateTimeDigitSet() const
03129 {
03130     return m_dateTimeDigitSet;
03131 }
03132 
03133 Q_GLOBAL_STATIC_WITH_ARGS(QMutex, s_kLocaleMutex, (QMutex::Recursive))
03134 
03135 QMutex *kLocaleMutex()
03136 {
03137     return s_kLocaleMutex();
03138 }

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal