klocale.cpp Source File (kdecore Library)

| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# klocale.cpp

    00001 // -*- c-basic-offset: 2 -*-
    00002 /* This file is part of the KDE libraries
    00003    Copyright (c) 1997,2001 Stephan Kulow <coolo@kde.org>
    00004    Copyright (c) 1999 Preston Brown <pbrown@kde.org>
    00005    Copyright (c) 1999-2001 Hans Petter Bieker <bieker@kde.org>
    00006    Copyright (c) 2002 Lukas Tinkl <lukas@kde.org>
    00007
    00008    This library is free software; you can redistribute it and/or
    00009    modify it under the terms of the GNU Library General Public
    00010    License as published by the Free Software Foundation; either
    00011    version 2 of the License, or (at your option) any later version.
    00012
    00013    This library is distributed in the hope that it will be useful,
    00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00016    Library General Public License for more details.
    00017
    00018    You should have received a copy of the GNU Library General Public License
    00019    along with this library; see the file COPYING.LIB.  If not, write to
    00020    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00021    Boston, MA 02111-1307, USA.
    00022 */
    00023
    00024 #include <config.h>
    00025
    00026 #include <stdlib.h> // getenv
    00027
    00028 #include <qtextcodec.h>
    00029 #include <qfile.h>
    00030 #undef GrayScale // make --enable-final happy
    00031 #include <qprinter.h>
    00032 #include <qdatetime.h>
    00033 #include <qfileinfo.h>
    00034 #include <qregexp.h>
    00035
    00036 #include "kcatalogue.h"
    00037 #include "kglobal.h"
    00038 #include "kstandarddirs.h"
    00039 #include "ksimpleconfig.h"
    00040 #include "kinstance.h"
    00041 #include "kconfig.h"
    00042 #include "kdebug.h"
    00043 #include "klocale.h"
    00044
    00045 static const char * const SYSTEM_MESSAGES = "kdelibs";
    00046
    00047 static const char *maincatalogue = 0;
    00048
    00049 class KLocalePrivate
    00050 {
    00051 public:
    00052   int weekStartDay;
    00053   int plural_form;
    00054   bool nounDeclension;
    00055   bool dateMonthNamePossessive;
    00056   QStringList languageList;
    00057   QValueList<KCatalogue> catalogues;
    00058   QString encoding;
    00059   QTextCodec * codecForEncoding;
    00060   KConfig * config;
    00061   bool formatInited;
    00062   int /*QPrinter::PageSize*/ pageSize;
    00063   KLocale::MeasureSystem measureSystem;
    00064   QStringList langTwoAlpha;
    00065   KConfig *languages;
    00066 };
    00067
    00068 static KLocale *this_klocale = 0;
    00069
    00070 KLocale::KLocale( const QString & catalogue, KConfig * config )
    00071 {
    00072   d = new KLocalePrivate;
    00073   d->config = config;
    00074   d->languages = 0;
    00075
    00076   initCatalogue(catalogue);
    00077   initEncoding(0);
    00078   initFileNameEncoding(0);
    00079
    00080   KConfig *cfg = d->config;
    00081   this_klocale = this;
    00082   if (!cfg) cfg = KGlobal::instance()->config();
    00083   this_klocale = 0;
    00084   Q_ASSERT( cfg );
    00085
    00086   if (m_language.isEmpty())
    00087      initLanguage(cfg, config == 0);
    00088 }
    00089
    00090
    00091 QString KLocale::_initLanguage(KConfigBase *config)
    00092 {
    00093   if (this_klocale)
    00094   {
    00095      this_klocale->initLanguage((KConfig *) config, true);
    00096      return this_klocale->language();
    00097   }
    00098   return QString::null;
    00099 }
    00100
    00101
    00102 void KLocale::initCatalogue(const QString & catalogue)
    00103 {
    00104   // Use the first non-null string.
    00105   QString mainCatalogue = catalogue;
    00106   if (maincatalogue)
    00107     mainCatalogue = QString::fromLatin1(maincatalogue);
    00108
    00109   if (mainCatalogue.isEmpty()) {
    00110     kdDebug(173) << "KLocale instance created called without valid "
    00111                  << "catalogue! Give an argument or call setMainCatalogue "
    00112                  << "before init" << endl;
    00113   }
    00114   else
    00115     d->catalogues.append( KCatalogue(mainCatalogue ) );
    00116
    00117   // always include kdelibs.mo
    00118   d->catalogues.append( KCatalogue( SYSTEM_MESSAGES ) );
    00119 }
    00120
    00121 void KLocale::initLanguage(KConfig * config, bool useEnv)
    00122 {
    00123   KConfigGroupSaver saver(config, "Locale");
    00124
    00125   m_country = config->readEntry( "Country" );
    00126   if ( m_country.isEmpty() )
    00127     m_country = defaultCountry();
    00128
    00129   // Reset the list and add the new languages
    00130   QStringList languageList;
    00131   if ( useEnv )
    00132     languageList += QStringList::split
    00133       (':', QFile::decodeName( ::getenv("KDE_LANG") ));
    00134
    00135   languageList += config->readListEntry("Language", ':');
    00136
    00137   // same order as setlocale use
    00138   if ( useEnv )
    00139     {
    00140       // HPB: Only run splitLocale on the environment variables..
    00141       QStringList langs;
    00142
    00143       langs << QFile::decodeName( ::getenv("LC_ALL") );
    00144       langs << QFile::decodeName( ::getenv("LC_MESSAGES") );
    00145       langs << QFile::decodeName( ::getenv("LANG") );
    00146       langs << QFile::decodeName( ::getenv("LC_CTYPE") );
    00147
    00148       for ( QStringList::Iterator it = langs.begin();
    00149             it != langs.end();
    00150             ++it )
    00151         {
    00152           QString ln, ct, chrset;
    00153           splitLocale(*it, ln, ct, chrset);
    00154
    00155           if (!ct.isEmpty()) {
    00156             langs.insert(it, ln + '_' + ct);
    00157             if (!chrset.isEmpty())
    00158               langs.insert(it, ln + '_' + ct + '.' + chrset);
    00159           }
    00160           langs.insert(it, ln);
    00161
    00162         }
    00163
    00164       languageList += langs;
    00165     }
    00166
    00167   // now we have a language list -- let's use the first OK language
    00168   setLanguage( languageList );
    00169 }
    00170
    00171 void KLocale::doBindInit()
    00172 {
    00173   for ( QValueList<KCatalogue>::Iterator it = d->catalogues.begin();
    00174         it != d->catalogues.end();
    00175         ++it )
    00176     initCatalogue( *it );
    00177
    00178   if ( useDefaultLanguage() )
    00179     d->plural_form = -1;
    00180   else
    00181     {
    00182       QString pf = translate_priv
    00183         ( I18N_NOOP("_: Dear translator, please do not translate this string "
    00184                     "in any form, but pick the _right_ value out of "
    00185                     "NoPlural/TwoForms/French... If not sure what to do mail "
    00186                     "thd@kde.org and coolo@kde.org, they will tell you. "
    00187                     "Better leave that out if unsure, the programs will "
    00188                     "crash!!\nDefinition of PluralForm - to be set by the "
    00189                     "translator of kdelibs.po"), 0);
    00190       if ( pf.isEmpty() ) {
    00191         kdWarning(173) << "found no definition of PluralForm for " << m_language << endl;
    00192         d->plural_form = -1;
    00193       } else if ( pf == "NoPlural" )
    00194         d->plural_form = 0;
    00195       else if ( pf == "TwoForms" )
    00196         d->plural_form = 1;
    00197       else if ( pf == "French" )
    00198         d->plural_form = 2;
    00199       else if ( pf == "OneTwoRest" || pf == "Gaeilge" ) // Gaelige is the old name
    00200         d->plural_form = 3;
    00201       else if ( pf == "Russian" )
    00202         d->plural_form = 4;
    00203       else if ( pf == "Polish" )
    00204         d->plural_form = 5;
    00205       else if ( pf == "Slovenian" )
    00206         d->plural_form = 6;
    00207       else if ( pf == "Lithuanian" )
    00208         d->plural_form = 7;
    00209       else if ( pf == "Czech" )
    00210         d->plural_form = 8;
    00211       else if ( pf == "Slovak" )
    00212         d->plural_form = 9;
    00213       else if ( pf == "Maltese" )
    00214         d->plural_form = 10;
    00215       else if ( pf == "Arabic" )
    00216         d->plural_form = 11;
    00217       else if ( pf == "Balcan" )
    00218         d->plural_form = 12;
    00219       else if ( pf == "Macedonian" )
    00220         d->plural_form = 13;
    00221       else {
    00222         kdWarning(173) << "Definition of PluralForm is none of "
    00223                        << "NoPlural/"
    00224                        << "TwoForms/"
    00225                        << "French/"
    00226                        << "OneTwoRest/"
    00227                        << "Russian/"
    00228                        << "Polish/"
    00229                        << "Slovenian/"
    00230                        << "Lithuanian/"
    00231                        << "Czech/"
    00232                        << "Slovak/"
    00233                        << "Arabic/"
    00234                        << "Balcan/"
    00235                        << "Macedonian/"
    00236                        << "Maltese: " << pf << endl;
    00237         exit(1);
    00238       }
    00239     }
    00240
    00241   d->formatInited = false;
    00242 }
    00243
    00244 void KLocale::doFormatInit() const
    00245 {
    00246   if ( d->formatInited ) return;
    00247
    00248   KLocale * that = const_cast<KLocale *>(this);
    00249   that->initFormat();
    00250
    00251   d->formatInited = true;
    00252 }
    00253
    00254 void KLocale::initFormat()
    00255 {
    00256   KConfig *config = d->config;
    00257   if (!config) config = KGlobal::instance()->config();
    00258   Q_ASSERT( config );
    00259
    00260   kdDebug(173) << "KLocale::initFormat" << endl;
    00261
    00262   // make sure the config files are read using the correct locale
    00263   // ### Why not add a KConfigBase::setLocale( const KLocale * )?
    00264   // ### Then we could remove this hack
    00265   KLocale *lsave = KGlobal::_locale;
    00266   KGlobal::_locale = this;
    00267
    00268   KConfigGroupSaver saver(config, "Locale");
    00269
    00270   KSimpleConfig entry(locate("locale",
    00271                              QString::fromLatin1("l10n/%1/entry.desktop")
    00272                              .arg(m_country)), true);
    00273   entry.setGroup("KCM Locale");
    00274
    00275   // Numeric
    00276 #define readConfigEntry(key, default, save) \
    00277   save = entry.readEntry(key, QString::fromLatin1(default)); \
    00278   save = config->readEntry(key, save);
    00279
    00280 #define readConfigNumEntry(key, default, save, type) \
    00281   save = (type)entry.readNumEntry(key, default); \
    00282   save = (type)config->readNumEntry(key, save);
    00283
    00284 #define readConfigBoolEntry(key, default, save) \
    00285   save = entry.readBoolEntry(key, default); \
    00286   save = config->readBoolEntry(key, save);
    00287
    00288   readConfigEntry("DecimalSymbol", ".", m_decimalSymbol);
    00289   readConfigEntry("ThousandsSeparator", ",", m_thousandsSeparator);
    00290   m_thousandsSeparator.replace( QRegExp(QString::fromLatin1("\\$0")),
    00291                                 QString::null );
    00292   //kdDebug(173) << "m_thousandsSeparator=" << m_thousandsSeparator << endl;
    00293
    00294   readConfigEntry("PositiveSign", "", m_positiveSign);
    00295   readConfigEntry("NegativeSign", "-", m_negativeSign);
    00296
    00297   // Monetary
    00298   readConfigEntry("CurrencySymbol", "$", m_currencySymbol);
    00299   readConfigEntry("MonetaryDecimalSymbol", ".", m_monetaryDecimalSymbol);
    00300   readConfigEntry("MonetaryThousandsSeparator", ",",
    00301                   m_monetaryThousandsSeparator);
    00302   m_monetaryThousandsSeparator.replace(QRegExp(QString::fromLatin1("\\$0")),
    00303                                        QString::null);
    00304
    00305   readConfigNumEntry("FracDigits", 2, m_fracDigits, int);
    00306   readConfigBoolEntry("PositivePrefixCurrencySymbol", true,
    00307                       m_positivePrefixCurrencySymbol);
    00308   readConfigBoolEntry("NegativePrefixCurrencySymbol", true,
    00309                       m_negativePrefixCurrencySymbol);
    00310   readConfigNumEntry("PositiveMonetarySignPosition", (int)BeforeQuantityMoney,
    00311                      m_positiveMonetarySignPosition, SignPosition);
    00312   readConfigNumEntry("NegativeMonetarySignPosition", (int)ParensAround,
    00313                      m_negativeMonetarySignPosition, SignPosition);
    00314
    00315   //Grammatical
    00316   readConfigBoolEntry("NounDeclension", false, d->nounDeclension);
    00317
    00318   // Date and time
    00319   readConfigEntry("TimeFormat", "%H:%M:%S", m_timeFormat);
    00320   readConfigEntry("DateFormat", "%A %d %B %Y", m_dateFormat);
    00321   readConfigEntry("DateFormatShort", "%Y-%m-%d", m_dateFormatShort);
    00322   readConfigBoolEntry("DateMonthNamePossessive", false,
    00323                       d->dateMonthNamePossessive);
    00324   readConfigNumEntry("WeekStartDay", 1, d->weekStartDay, int);
    00325
    00326   // other
    00327   readConfigNumEntry("PageSize", (int)QPrinter::A4, d->pageSize, int);
    00328   readConfigNumEntry("MeasureSystem", (int)Metric, d->measureSystem,
    00329                      MeasureSystem);
    00330
    00331   // end of hack
    00332   KGlobal::_locale = lsave;
    00333 }
    00334
    00335 bool KLocale::setCountry(const QString & country)
    00336 {
    00337   // Check if the file exists too??
    00338   if ( country.isEmpty() )
    00339     return false;
    00340
    00341   m_country = country;
    00342
    00343   d->formatInited = false;
    00344
    00345   return true;
    00346 }
    00347
    00348 QString KLocale::catalogueFileName(const QString & language,
    00349                                    const KCatalogue & catalogue)
    00350 {
    00351   QString path = QString::fromLatin1("%1/LC_MESSAGES/%2.mo")
    00352     .arg( language )
    00353     .arg( catalogue.name() );
    00354
    00355   return locate( "locale", path );
    00356 }
    00357
    00358 bool KLocale::isLanguageInstalled(const QString & language) const
    00359 {
    00360   // Do not allow empty languages
    00361   if ( language.isEmpty() ) return false;
    00362
    00363   bool bRes = true;
    00364   if ( language != defaultLanguage() )
    00365     for ( QValueList<KCatalogue>::ConstIterator it = d->catalogues.begin();
    00366           it != d->catalogues.end() && bRes;
    00367           ++it )
    00368       {
    00369         bRes = !catalogueFileName( language, *it ).isNull();
    00370         if ( !bRes )
    00371           kdDebug(173) << "message catalogue not found: "
    00372                        << (*it).name() << endl;
    00373       }
    00374
    00375   return bRes;
    00376 }
    00377
    00378 bool KLocale::setLanguage(const QString & language)
    00379 {
    00380   bool bRes = isLanguageInstalled( language );
    00381
    00382   if ( bRes )
    00383     {
    00384       m_language = language;
    00385
    00386       doBindInit();
    00387     }
    00388
    00389   return bRes;
    00390 }
    00391
    00392 bool KLocale::setLanguage(const QStringList & languages)
    00393 {
    00394   QStringList languageList(languages);
    00395
    00396   // Remove duplicate entries in reverse so that we
    00397   // can keep user's language preference order intact. (DA)
    00398   for( QStringList::Iterator it = languageList.fromLast();
    00399          it != languageList.begin();
    00400          --it )
    00401     if ( languageList.contains(*it) > 1 || (*it).isEmpty() )
    00402       it = languageList.remove( it );
    00403
    00404   bool bRes = false;
    00405   for ( QStringList::ConstIterator it = languageList.begin();
    00406         it != languageList.end();
    00407         ++it )
    00408     if ( bRes = setLanguage( *it ) )
    00409       break;
    00410
    00411   if ( !bRes )
    00412     setLanguage(defaultLanguage());
    00413
    00414   d->languageList = languageList;
    00415   d->langTwoAlpha.clear(); // Flush cache
    00416
    00417   return bRes;
    00418 }
    00419
    00420 void KLocale::splitLocale(const QString & aStr,
    00421                           QString & language,
    00422                           QString & country,
    00423                           QString & chrset)
    00424 {
    00425   QString str = aStr;
    00426
    00427   // just in case, there is another language appended
    00428   int f = str.find(':');
    00429   if (f >= 0)
    00430     str.truncate(f);
    00431
    00432   country = QString::null;
    00433   chrset = QString::null;
    00434   language = QString::null;
    00435
    00436   f = str.find('.');
    00437   if (f >= 0)
    00438     {
    00439       chrset = str.mid(f + 1);
    00440       str.truncate(f);
    00441     }
    00442
    00443   f = str.find('_');
    00444   if (f >= 0)
    00445     {
    00446       country = str.mid(f + 1);
    00447       str.truncate(f);
    00448     }
    00449
    00450   language = str;
    00451 }
    00452
    00453 QString KLocale::language() const
    00454 {
    00455   return m_language;
    00456 }
    00457
    00458 QString KLocale::country() const
    00459 {
    00460   return m_country;
    00461 }
    00462
    00463 QString KLocale::monthName(int i, bool shortName) const
    00464 {
    00465   if ( shortName )
    00466     switch ( i )
    00467       {
    00468       case 1:   return translate("January", "Jan");
    00469       case 2:   return translate("February", "Feb");
    00470       case 3:   return translate("March", "Mar");
    00471       case 4:   return translate("April", "Apr");
    00472       case 5:   return translate("May short", "May");
    00473       case 6:   return translate("June", "Jun");
    00474       case 7:   return translate("July", "Jul");
    00475       case 8:   return translate("August", "Aug");
    00476       case 9:   return translate("September", "Sep");
    00477       case 10:  return translate("October", "Oct");
    00478       case 11:  return translate("November", "Nov");
    00479       case 12:  return translate("December", "Dec");
    00480       }
    00481   else
    00482     switch (i)
    00483       {
    00484       case 1:   return translate("January");
    00485       case 2:   return translate("February");
    00486       case 3:   return translate("March");
    00487       case 4:   return translate("April");
    00488       case 5:   return translate("May long", "May");
    00489       case 6:   return translate("June");
    00490       case 7:   return translate("July");
    00491       case 8:   return translate("August");
    00492       case 9:   return translate("September");
    00493       case 10:  return translate("October");
    00494       case 11:  return translate("November");
    00495       case 12:  return translate("December");
    00496       }
    00497
    00498   return QString::null;
    00499 }
    00500
    00501 QString KLocale::monthNamePossessive(int i, bool shortName) const
    00502 {
    00503   if ( shortName )
    00504     switch ( i )
    00505       {
    00506       case 1:   return translate("of January", "of Jan");
    00507       case 2:   return translate("of February", "of Feb");
    00508       case 3:   return translate("of March", "of Mar");
    00509       case 4:   return translate("of April", "of Apr");
    00510       case 5:   return translate("of May short", "of May");
    00511       case 6:   return translate("of June", "of Jun");
    00512       case 7:   return translate("of July", "of Jul");
    00513       case 8:   return translate("of August", "of Aug");
    00514       case 9:   return translate("of September", "of Sep");
    00515       case 10:  return translate("of October", "of Oct");
    00516       case 11:  return translate("of November", "of Nov");
    00517       case 12:  return translate("of December", "of Dec");
    00518       }
    00519   else
    00520     switch (i)
    00521       {
    00522       case 1:   return translate("of January");
    00523       case 2:   return translate("of February");
    00524       case 3:   return translate("of March");
    00525       case 4:   return translate("of April");
    00526       case 5:   return translate("of May long", "of May");
    00527       case 6:   return translate("of June");
    00528       case 7:   return translate("of July");
    00529       case 8:   return translate("of August");
    00530       case 9:   return translate("of September");
    00531       case 10:  return translate("of October");
    00532       case 11:  return translate("of November");
    00533       case 12:  return translate("of December");
    00534       }
    00535
    00536   return QString::null;
    00537 }
    00538
    00539 QString KLocale::weekDayName (int i, bool shortName) const
    00540 {
    00541   if ( shortName )
    00542     switch ( i )
    00543       {
    00544       case 1:  return translate("Monday", "Mon");
    00545       case 2:  return translate("Tuesday", "Tue");
    00546       case 3:  return translate("Wednesday", "Wed");
    00547       case 4:  return translate("Thursday", "Thu");
    00548       case 5:  return translate("Friday", "Fri");
    00549       case 6:  return translate("Saturday", "Sat");
    00550       case 7:  return translate("Sunday", "Sun");
    00551       }
    00552   else
    00553     switch ( i )
    00554       {
    00555       case 1:  return translate("Monday");
    00556       case 2:  return translate("Tuesday");
    00557       case 3:  return translate("Wednesday");
    00558       case 4:  return translate("Thursday");
    00559       case 5:  return translate("Friday");
    00560       case 6:  return translate("Saturday");
    00561       case 7:  return translate("Sunday");
    00562       }
    00563
    00564   return QString::null;
    00565 }
    00566
    00567 void KLocale::insertCatalogue( const QString & catalogue )
    00568 {
    00569   KCatalogue cat( catalogue );
    00570
    00571   initCatalogue( cat );
    00572
    00573   d->catalogues.append( cat );
    00574 }
    00575
    00576 void KLocale::removeCatalogue(const QString &catalogue)
    00577 {
    00578   for ( QValueList<KCatalogue>::Iterator it = d->catalogues.begin();
    00579         it != d->catalogues.end(); )
    00580     if ((*it).name() == catalogue) {
    00581       it = d->catalogues.remove(it);
    00582       return;
    00583     } else
    00584       ++it;
    00585 }
    00586
    00587 void KLocale::setActiveCatalogue(const QString &catalogue)
    00588 {
    00589   for ( QValueList<KCatalogue>::Iterator it = d->catalogues.begin();
    00590         it != d->catalogues.end(); ++it)
    00591     if ((*it).name() == catalogue) {
    00592       KCatalogue save = *it;
    00593       d->catalogues.remove(it);
    00594       d->catalogues.prepend(save);
    00595       return;
    00596     }
    00597 }
    00598
    00599
    00600 KLocale::~KLocale()
    00601 {
    00602   delete d->languages;
    00603   delete d;
    00604 }
    00605
    00606 QString KLocale::translate_priv(const char *msgid,
    00607                                 const char *fallback,
    00608                                 const char **translated) const
    00609 {
    00610   if (!msgid || !msgid[0])
    00611     {
    00612       kdWarning() << "KLocale: trying to look up \"\" in catalogue. "
    00613                    << "Fix the program" << endl;
    00614       return QString::null;
    00615     }
    00616
    00617   if ( useDefaultLanguage() )
    00618     return QString::fromUtf8( fallback );
    00619
    00620   for ( QValueList<KCatalogue>::ConstIterator it = d->catalogues.begin();
    00621         it != d->catalogues.end();
    00622         ++it )
    00623     {
    00624       // kdDebug(173) << "translate " << msgid << " " << (*it).name() << " " << (!KGlobal::activeInstance() ? QCString("no instance") : KGlobal::activeInstance()->instanceName()) << endl;
    00625       const char * text = (*it).translate( msgid );
    00626
    00627       if ( text )
    00628         {
    00629           // we found it
    00630           if (translated)
    00631             *translated = text;
    00632           return QString::fromUtf8( text );
    00633         }
    00634     }
    00635
    00636   // Always use UTF-8 if the string was not found
    00637   return QString::fromUtf8( fallback );
    00638 }
    00639
    00640 QString KLocale::translate(const char* msgid) const
    00641 {
    00642   return translate_priv(msgid, msgid);
    00643 }
    00644
    00645 QString KLocale::translate( const char *index, const char *fallback) const
    00646 {
    00647   if (!index || !index[0] || !fallback || !fallback[0])
    00648     {
    00649       kdDebug(173) << "KLocale: trying to look up \"\" in catalogue. "
    00650                    << "Fix the program" << endl;
    00651       return QString::null;
    00652     }
    00653
    00654   if ( useDefaultLanguage() )
    00655     return QString::fromUtf8( fallback );
    00656
    00657   char *newstring = new char[strlen(index) + strlen(fallback) + 5];
    00658   sprintf(newstring, "_: %s\n%s", index, fallback);
    00659   // as copying QString is very fast, it looks slower as it is ;/
    00660   QString r = translate_priv(newstring, fallback);
    00661   delete [] newstring;
    00662
    00663   return r;
    00664 }
    00665
    00666 QString put_n_in(const QString &orig, unsigned long n)
    00667 {
    00668   QString ret = orig;
    00669   int index = ret.find("%n");
    00670   if (index == -1)
    00671     return ret;
    00672   ret.replace(index, 2, QString::number(n));
    00673   return ret;
    00674 }
    00675
    00676 #define EXPECT_LENGTH(x) \
    00677    if (forms.count() != x) { \
    00678       kdError() << "translation of \"" << singular << "\" doesn't contain " << x << " different plural forms as expected\n"; \
    00679       return QString( "BROKEN TRANSLATION %1" ).arg( singular ); }
    00680
    00681 QString KLocale::translate( const char *singular, const char *plural,
    00682                             unsigned long n ) const
    00683 {
    00684   if (!singular || !singular[0] || !plural || !plural[0])
    00685     {
    00686       kdWarning() << "KLocale: trying to look up \"\" in catalogue. "
    00687                    << "Fix the program" << endl;
    00688       return QString::null;
    00689     }
    00690
    00691   char *newstring = new char[strlen(singular) + strlen(plural) + 6];
    00692   sprintf(newstring, "_n: %s\n%s", singular, plural);
    00693   // as copying QString is very fast, it looks slower as it is ;/
    00694   QString r = translate_priv(newstring, 0);
    00695   delete [] newstring;
    00696
    00697   if ( r.isEmpty() || useDefaultLanguage() || d->plural_form == -1) {
    00698     if ( n == 1 ) {
    00699       return put_n_in( QString::fromUtf8( singular ),  n );
    00700         } else {
    00701           QString tmp = QString::fromUtf8( plural );
    00702 #ifndef NDEBUG
    00703           if (tmp.find("%n") == -1) {
    00704                           kdWarning() << "the message for i18n should contain a '%n'! " << plural << endl;
    00705           }
    00706 #endif
    00707       return put_n_in( tmp,  n );
    00708         }
    00709   }
    00710
    00711   QStringList forms = QStringList::split( "\n", r, false );
    00712   switch ( d->plural_form ) {
    00713   case 0: // NoPlural
    00714     EXPECT_LENGTH( 1 );
    00715     return put_n_in( forms[0], n);
    00716   case 1: // TwoForms
    00717     EXPECT_LENGTH( 2 );
    00718     if ( n == 1 )
    00719       return put_n_in( forms[0], n);
    00720     else
    00721       return put_n_in( forms[1], n);
    00722   case 2: // French
    00723     EXPECT_LENGTH( 2 );
    00724     if ( n == 1 || n == 0 )
    00725       return put_n_in( forms[0], n);
    00726     else
    00727       return put_n_in( forms[1], n);
    00728   case 3: // Gaeilge
    00729     EXPECT_LENGTH( 3 );
    00730     if ( n == 1 )
    00731       return put_n_in( forms[0], n);
    00732     else if ( n == 2 )
    00733       return put_n_in( forms[1], n);
    00734     else
    00735       return put_n_in( forms[2], n);
    00736   case 4: // Russian, corrected by mok
    00737     EXPECT_LENGTH( 3 );
    00738     if ( n%10 == 1  &&  n%100 != 11)
    00739       return put_n_in( forms[0], n); // odin fail
    00740     else if (( n%10 >= 2 && n%10 <=4 ) && (n%100<10 || n%100>20))
    00741       return put_n_in( forms[1], n); // dva faila
    00742     else
    00743       return put_n_in( forms[2], n); // desyat' failov
    00744   case 5: // Polish
    00745     EXPECT_LENGTH( 3 );
    00746     if ( n == 1 )
    00747       return put_n_in( forms[0], n);
    00748     else if ( n%10 >= 2 && n%10 <=4 && (n%100<10 || n%100>=20) )
    00749       return put_n_in( forms[1], n);
    00750     else
    00751       return put_n_in( forms[2], n);
    00752   case 6: // Slovenian
    00753     EXPECT_LENGTH( 4 );
    00754     if ( n%100 == 1 )
    00755       return put_n_in( forms[1], n); // ena datoteka
    00756     else if ( n%100 == 2 )
    00757       return put_n_in( forms[2], n); // dve datoteki
    00758     else if ( n%100 == 3 || n%100 == 4 )
    00759       return put_n_in( forms[3], n); // tri datoteke
    00760     else
    00761       return put_n_in( forms[0], n); // sto datotek
    00762   case 7: // Lithuanian
    00763     EXPECT_LENGTH( 3 );
    00764     if ( n%10 == 0 || (n%100>=11 && n%100<=19) )
    00765       return put_n_in( forms[2], n);
    00766     else if ( n%10 == 1 )
    00767       return put_n_in( forms[0], n);
    00768     else
    00769       return put_n_in( forms[1], n);
    00770   case 8: // Czech
    00771     EXPECT_LENGTH( 3 );
    00772     if ( n%100 == 1 )
    00773       return put_n_in( forms[0], n);
    00774     else if (( n%100 >= 2 ) && ( n%100 <= 4 ))
    00775       return put_n_in( forms[1], n);
    00776     else
    00777       return put_n_in( forms[2], n);
    00778   case 9: // Slovak
    00779     EXPECT_LENGTH( 3 );
    00780     if ( n == 1 )
    00781       return put_n_in( forms[0], n);
    00782     else if (( n >= 2 ) && ( n <= 4 ))
    00783       return put_n_in( forms[1], n);
    00784     else
    00785       return put_n_in( forms[2], n);
    00786   case 10: // Maltese
    00787     EXPECT_LENGTH( 4 );
    00788     if ( n == 1 )
    00789       return put_n_in( forms[0], n );
    00790     else if ( ( n == 0 ) || ( n%100 > 0 && n%100 <= 10 ) )
    00791       return put_n_in( forms[1], n );
    00792     else if ( n%100 > 10 && n%100 < 20 )
    00793       return put_n_in( forms[2], n );
    00794     else
    00795       return put_n_in( forms[3], n );
    00796   case 11: // Arabic
    00797     EXPECT_LENGTH( 4 );
    00798     if (n == 1)
    00799       return put_n_in(forms[0], n);
    00800     else if (n == 2)
    00801       return put_n_in(forms[1], n);
    00802     else if ( n < 11)
    00803       return put_n_in(forms[2], n);
    00804     else
    00805       return put_n_in(forms[3], n);
    00806   case 12: // Balcan
    00807      EXPECT_LENGTH( 3 );
    00808      if (n != 11 && n % 10 == 1)
    00809         return put_n_in(forms[0], n);
    00810      else if (n / 10 != 1 && n % 10 >= 2 && n % 10 <= 4)
    00811         return put_n_in(forms[1], n);
    00812      else
    00813         return put_n_in(forms[2], n);
    00814   case 13: // Macedonian
    00815      EXPECT_LENGTH(3);
    00816      if (n % 10 == 1)
    00817         return put_n_in(forms[0], n);
    00818      else if (n % 10 == 2)
    00819         return put_n_in(forms[1], n);
    00820      else
    00821         return put_n_in(forms[2], n);
    00822   }
    00823   kdFatal() << "The function should have been returned in another way\n";
    00824
    00825   return QString::null;
    00826 }
    00827
    00828 QString KLocale::translateQt( const char *context, const char *source,
    00829                               const char *message) const
    00830 {
    00831   if (!source || !source[0]) {
    00832     kdWarning() << "KLocale: trying to look up \"\" in catalogue. "
    00833                 << "Fix the program" << endl;
    00834     return QString::null;
    00835   }
    00836
    00837   if ( useDefaultLanguage() ) {
    00838     return QString::null;
    00839   }
    00840
    00841   char *newstring = 0;
    00842   const char *translation = 0;
    00843   QString r;
    00844
    00845   if ( message && message[0]) {
    00846     char *newstring = new char[strlen(source) + strlen(message) + 5];
    00847     sprintf(newstring, "_: %s\n%s", source, message);
    00848     const char *translation = 0;
    00849     // as copying QString is very fast, it looks slower as it is ;/
    00850     r = translate_priv(newstring, source, &translation);
    00851     delete [] newstring;
    00852     if (translation)
    00853       return r;
    00854   }
    00855
    00856   if ( context && context[0] && message && message[0]) {
    00857     newstring = new char[strlen(context) + strlen(message) + 5];
    00858     sprintf(newstring, "_: %s\n%s", context, message);
    00859     // as copying QString is very fast, it looks slower as it is ;/
    00860     r = translate_priv(newstring, source, &translation);
    00861     delete [] newstring;
    00862     if (translation)
    00863       return r;
    00864   }
    00865
    00866   r = translate_priv(source, source, &translation);
    00867   if (translation)
    00868     return r;
    00869   return QString::null;
    00870 }
    00871
    00872 bool KLocale::nounDeclension() const
    00873 {
    00874   doFormatInit();
    00875   return d->nounDeclension;
    00876 }
    00877
    00878 bool KLocale::dateMonthNamePossessive() const
    00879 {
    00880   doFormatInit();
    00881   return d->dateMonthNamePossessive;
    00882 }
    00883
    00884 int KLocale::weekStartDay() const
    00885 {
    00886   doFormatInit();
    00887   return d->weekStartDay;
    00888 }
    00889
    00890 bool KLocale::weekStartsMonday() const //deprecated
    00891 {
    00892   doFormatInit();
    00893   return (d->weekStartDay==1);
    00894 }
    00895
    00896 QString KLocale::decimalSymbol() const
    00897 {
    00898   doFormatInit();
    00899   return m_decimalSymbol;
    00900 }
    00901
    00902 QString KLocale::thousandsSeparator() const
    00903 {
    00904   doFormatInit();
    00905   return m_thousandsSeparator;
    00906 }
    00907
    00908 QString KLocale::currencySymbol() const
    00909 {
    00910   doFormatInit();
    00911   return m_currencySymbol;
    00912 }
    00913
    00914 QString KLocale::monetaryDecimalSymbol() const
    00915 {
    00916   doFormatInit();
    00917   return m_monetaryDecimalSymbol;
    00918 }
    00919
    00920 QString KLocale::monetaryThousandsSeparator() const
    00921 {
    00922   doFormatInit();
    00923   return m_monetaryThousandsSeparator;
    00924 }
    00925
    00926 QString KLocale::positiveSign() const
    00927 {
    00928   doFormatInit();
    00929   return m_positiveSign;
    00930 }
    00931
    00932 QString KLocale::negativeSign() const
    00933 {
    00934   doFormatInit();
    00935   return m_negativeSign;
    00936 }
    00937
    00938 int KLocale::fracDigits() const
    00939 {
    00940   doFormatInit();
    00941   return m_fracDigits;
    00942 }
    00943
    00944 bool KLocale::positivePrefixCurrencySymbol() const
    00945 {
    00946   doFormatInit();
    00947   return m_positivePrefixCurrencySymbol;
    00948 }
    00949
    00950 bool KLocale::negativePrefixCurrencySymbol() const
    00951 {
    00952   doFormatInit();
    00953   return m_negativePrefixCurrencySymbol;
    00954 }
    00955
    00956 KLocale::SignPosition KLocale::positiveMonetarySignPosition() const
    00957 {
    00958   doFormatInit();
    00959   return m_positiveMonetarySignPosition;
    00960 }
    00961
    00962 KLocale::SignPosition KLocale::negativeMonetarySignPosition() const
    00963 {
    00964   doFormatInit();
    00965   return m_negativeMonetarySignPosition;
    00966 }
    00967
    00968 inline void put_it_in( QChar *buffer, uint& index, const QString &s )
    00969 {
    00970   for ( uint l = 0; l < s.length(); l++ )
    00971     buffer[index++] = s.at( l );
    00972 }
    00973
    00974 inline void put_it_in( QChar *buffer, uint& index, int number )
    00975 {
    00976   buffer[index++] = number / 10 + '0';
    00977   buffer[index++] = number % 10 + '0';
    00978 }
    00979
    00980 QString KLocale::formatMoney(double num,
    00981                              const QString & symbol,
    00982                              int precision) const
    00983 {
    00984   // some defaults
    00985   QString currency = symbol.isNull()
    00986     ? currencySymbol()
    00987     : symbol;
    00988   if (precision < 0) precision = fracDigits();
    00989
    00990   // the number itself
    00991   bool neg = num < 0;
    00992   QString res = QString::number(neg?-num:num, 'f', precision);
    00993   int pos = res.find('.');
    00994   if (pos == -1) pos = res.length();
    00995   else res.replace(pos, 1, monetaryDecimalSymbol());
    00996
    00997   while (0 < (pos -= 3))
    00998     res.insert(pos, monetaryThousandsSeparator()); // thousend sep
    00999
    01000   // set some variables we need later
    01001   int signpos = neg
    01002     ? negativeMonetarySignPosition()
    01003     : positiveMonetarySignPosition();
    01004   QString sign = neg
    01005     ? negativeSign()
    01006     : positiveSign();
    01007
    01008   switch (signpos)
    01009     {
    01010     case ParensAround:
    01011       res.prepend('(');
    01012       res.append (')');
    01013       break;
    01014     case BeforeQuantityMoney:
    01015       res.prepend(sign);
    01016       break;
    01017     case AfterQuantityMoney:
    01018       res.append(sign);
    01019       break;
    01020     case BeforeMoney:
    01021       currency.prepend(sign);
    01022       break;
    01023     case AfterMoney:
    01024       currency.append(sign);
    01025       break;
    01026     }
    01027
    01028   if (neg?negativePrefixCurrencySymbol():
    01029       positivePrefixCurrencySymbol())
    01030     {
    01031       res.prepend(' ');
    01032       res.prepend(currency);
    01033     } else {
    01034       res.append (' ');
    01035       res.append (currency);
    01036     }
    01037
    01038   return res;
    01039 }
    01040
    01041 QString KLocale::formatMoney(const QString &numStr) const
    01042 {
    01043   return formatMoney(numStr.toDouble());
    01044 }
    01045
    01046 QString KLocale::formatNumber(double num, int precision) const
    01047 {
    01048   bool neg = num < 0;
    01049   if (precision == -1) precision = 2;
    01050   QString res = QString::number(neg?-num:num, 'f', precision);
    01051   int pos = res.find('.');
    01052   if (pos == -1) pos = res.length();
    01053   else res.replace(pos, 1, decimalSymbol());
    01054
    01055   while (0 < (pos -= 3))
    01056     res.insert(pos, thousandsSeparator()); // thousand sep
    01057
    01058   // How can we know where we should put the sign?
    01059   res.prepend(neg?negativeSign():positiveSign());
    01060
    01061   return res;
    01062 }
    01063
    01064 QString KLocale::formatNumber(const QString &numStr) const
    01065 {
    01066   return formatNumber(numStr.toDouble());
    01067 }
    01068
    01069 QString KLocale::formatDate(const QDate &pDate, bool shortFormat) const
    01070 {
    01071   const QString rst = shortFormat?dateFormatShort():dateFormat();
    01072
    01073   // I'm rather safe than sorry
    01074   QChar *buffer = new QChar[rst.length() * 3 / 2 + 50];
    01075
    01076   unsigned int index = 0;
    01077   bool escape = false;
    01078   int number = 0;
    01079
    01080   for ( uint format_index = 0; format_index < rst.length(); ++format_index )
    01081     {
    01082       if ( !escape )
    01083         {
    01084           if ( rst.at( format_index ).unicode() == '%' )
    01085             escape = true;
    01086           else
    01087             buffer[index++] = rst.at( format_index );
    01088         }
    01089       else
    01090         {
    01091           switch ( rst.at( format_index ).unicode() )
    01092             {
    01093             case '%':
    01094               buffer[index++] = '%';
    01095               break;
    01096             case 'Y':
    01097               put_it_in( buffer, index, pDate.year() / 100 );
    01098             case 'y':
    01099               put_it_in( buffer, index, pDate.year() % 100 );
    01100               break;
    01101             case 'n':
    01102               number = pDate.month();
    01103             case 'e':
    01104               // to share the code
    01105               if ( rst.at( format_index ).unicode() == 'e' )
    01106                 number = pDate.day();
    01107               if ( number / 10 )
    01108                 buffer[index++] = number / 10 + '0';
    01109               buffer[index++] = number % 10 + '0';
    01110               break;
    01111             case 'm':
    01112               put_it_in( buffer, index, pDate.month() );
    01113               break;
    01114             case 'b':
    01115               if (d->nounDeclension && d->dateMonthNamePossessive)
    01116                 put_it_in( buffer, index, monthNamePossessive(pDate.month(), true) );
    01117               else
    01118                 put_it_in( buffer, index, monthName(pDate.month(), true) );
    01119               break;
    01120             case 'B':
    01121               if (d->nounDeclension && d->dateMonthNamePossessive)
    01122                 put_it_in( buffer, index, monthNamePossessive(pDate.month(), false) );
    01123               else
    01124                 put_it_in( buffer, index, monthName(pDate.month(), false) );
    01125               break;
    01126             case 'd':
    01127               put_it_in( buffer, index, pDate.day() );
    01128               break;
    01129             case 'a':
    01130               put_it_in( buffer, index, weekDayName(pDate.dayOfWeek(), true) );
    01131               break;
    01132             case 'A':
    01133               put_it_in( buffer, index, weekDayName(pDate.dayOfWeek(), false) );
    01134               break;
    01135             default:
    01136               buffer[index++] = rst.at( format_index );
    01137               break;
    01138             }
    01139           escape = false;
    01140         }
    01141     }
    01142   QString ret( buffer, index );
    01143   delete [] buffer;
    01144   return ret;
    01145 }
    01146
    01147 void KLocale::setMainCatalogue(const char *catalogue)
    01148 {
    01149   maincatalogue = catalogue;
    01150 }
    01151
    01152 double KLocale::readNumber(const QString &_str, bool * ok) const
    01153 {
    01154   QString str = _str.stripWhiteSpace();
    01155   bool neg = str.find(negativeSign()) == 0;
    01156   if (neg)
    01157     str.remove( 0, negativeSign().length() );
    01158
    01159   /* will hold the scientific notation portion of the number.
    01160      Example, with 2.34E+23, exponentialPart == "E+23"
    01161   */
    01162   QString exponentialPart;
    01163   int EPos;
    01164
    01165   EPos = str.find('E', 0, false);
    01166
    01167   if (EPos != -1)
    01168   {
    01169     exponentialPart = str.mid(EPos);
    01170     str = str.left(EPos);
    01171   }
    01172
    01173   int pos = str.find(decimalSymbol());
    01174   QString major;
    01175   QString minor;
    01176   if ( pos == -1 )
    01177     major = str;
    01178   else
    01179     {
    01180       major = str.left(pos);
    01181       minor = str.mid(pos + decimalSymbol().length());
    01182     }
    01183
    01184   // Remove thousand separators
    01185   int thlen = thousandsSeparator().length();
    01186   int lastpos = 0;
    01187   while ( ( pos = major.find( thousandsSeparator() ) ) > 0 )
    01188   {
    01189     // e.g. 12,,345,,678,,922 Acceptable positions (from the end) are 5, 10, 15... i.e. (3+thlen)*N
    01190     int fromEnd = major.length() - pos;
    01191     if ( fromEnd % (3+thlen) != 0 // Needs to be a multiple, otherwise it's an error
    01192         || pos - lastpos > 3 // More than 3 digits between two separators -> error
    01193         || pos == 0          // Can't start with a separator
    01194         || (lastpos>0 && pos-lastpos!=3))   // Must have exactly 3 digits between two separators
    01195     {
    01196       if (ok) *ok = false;
    01197       return 0.0;
    01198     }
    01199
    01200     lastpos = pos;
    01201     major.remove( pos, thlen );
    01202   }
    01203   if (lastpos>0 && major.length()-lastpos!=3)   // Must have exactly 3 digits after the last separator
    01204   {
    01205     if (ok) *ok = false;
    01206     return 0.0;
    01207   }
    01208
    01209   QString tot;
    01210   if (neg) tot = '-';
    01211
    01212   tot += major + '.' + minor + exponentialPart;
    01213
    01214   return tot.toDouble(ok);
    01215 }
    01216
    01217 double KLocale::readMoney(const QString &_str, bool * ok) const
    01218 {
    01219   QString str = _str.stripWhiteSpace();
    01220   bool neg = false;
    01221   bool currencyFound = false;
    01222   // First try removing currency symbol from either end
    01223   int pos = str.find(currencySymbol());
    01224   if ( pos == 0 || pos == (int) str.length()-1 )
    01225     {
    01226       str.remove(pos,currencySymbol().length());
    01227       str = str.stripWhiteSpace();
    01228       currencyFound = true;
    01229     }
    01230   if (str.isEmpty())
    01231     {
    01232       if (ok) *ok = false;
    01233       return 0;
    01234     }
    01235   // Then try removing negative sign from either end
    01236   // (with a special case for parenthesis)
    01237   if (negativeMonetarySignPosition() == ParensAround)
    01238     {
    01239       if (str[0] == '(' && str[str.length()-1] == ')')
    01240         {
    01241           neg = true;
    01242           str.remove(str.length()-1,1);
    01243           str.remove(0,1);
    01244         }
    01245     }
    01246   else
    01247     {
    01248       int i1 = str.find(negativeSign());
    01249       if ( i1 == 0 || i1 == (int) str.length()-1 )
    01250         {
    01251           neg = true;
    01252           str.remove(i1,negativeSign().length());
    01253         }
    01254     }
    01255   if (neg) str = str.stripWhiteSpace();
    01256
    01257   // Finally try again for the currency symbol, if we didn't find
    01258   // it already (because of the negative sign being in the way).
    01259   if ( !currencyFound )
    01260     {
    01261       pos = str.find(currencySymbol());
    01262       if ( pos == 0 || pos == (int) str.length()-1 )
    01263         {
    01264           str.remove(pos,currencySymbol().length());
    01265           str = str.stripWhiteSpace();
    01266         }
    01267     }
    01268
    01269   // And parse the rest as a number
    01270   pos = str.find(monetaryDecimalSymbol());
    01271   QString major;
    01272   QString minior;
    01273   if (pos == -1)
    01274     major = str;
    01275   else
    01276     {
    01277       major = str.left(pos);
    01278       minior = str.mid(pos + monetaryDecimalSymbol().length());
    01279     }
    01280
    01281
    01282   // Remove thousand separators
    01283   int thlen = monetaryThousandsSeparator().length();
    01284   int lastpos = 0;
    01285   while ( ( pos = major.find( monetaryThousandsSeparator() ) ) > 0 )
    01286   {
    01287     // e.g. 12,,345,,678,,922 Acceptable positions (from the end) are 5, 10, 15... i.e. (3+thlen)*N
    01288     int fromEnd = major.length() - pos;
    01289     if ( fromEnd % (3+thlen) != 0 // Needs to be a multiple, otherwise it's an error
    01290         || pos - lastpos > 3 // More than 3 digits between two separators -> error
    01291         || pos == 0          // Can't start with a separator
    01292         || (lastpos>0 && pos-lastpos!=3))   // Must have exactly 3 digits between two separators
    01293     {
    01294       if (ok) *ok = false;
    01295       return 0.0;
    01296     }
    01297     lastpos = pos;
    01298     major.remove( pos, thlen );
    01299   }
    01300   if (lastpos>0 && major.length()-lastpos!=3)   // Must have exactly 3 digits after the last separator
    01301   {
    01302     if (ok) *ok = false;
    01303     return 0.0;
    01304   }
    01305
    01306   QString tot;
    01307   if (neg) tot = '-';
    01308   tot += major + '.' + minior;
    01309   return tot.toDouble(ok);
    01310 }
    01311
    01318 static int readInt(const QString &str, uint &pos)
    01319 {
    01320   if (!str.at(pos).isDigit()) return -1;
    01321   int result = 0;
    01322   for (; str.length() > pos && str.at(pos).isDigit(); pos++)
    01323     {
    01324       result *= 10;
    01325       result += str.at(pos).digitValue();
    01326     }
    01327
    01328   return result;
    01329 }
    01330
    01331 QDate KLocale::readDate(const QString &intstr, bool* ok) const
    01332 {
    01333   QDate date;
    01334   date = readDate(intstr, true, ok);
    01335   if (date.isValid()) return date;
    01336   return readDate(intstr, false, ok);
    01337 }
    01338
    01339 QDate KLocale::readDate(const QString &intstr, bool shortFormat, bool* ok) const
    01340 {
    01341   QString fmt = (shortFormat ? dateFormatShort() : dateFormat()).simplifyWhiteSpace();
    01342   return readDate( intstr, fmt, ok );
    01343 }
    01344
    01345 QDate KLocale::readDate(const QString &intstr, const QString &fmt, bool* ok) const
    01346 {
    01347   //kdDebug() << "KLocale::readDate intstr=" << intstr << " fmt=" << fmt << endl;
    01348   QString str = intstr.simplifyWhiteSpace().lower();
    01349   int day = -1, month = -1;
    01350   // allow the year to be omitted if not in the format
    01351   int year = QDate::currentDate().year();
    01352   uint strpos = 0;
    01353   uint fmtpos = 0;
    01354
    01355   bool error = false;
    01356
    01357   while (fmt.length() > fmtpos && str.length() > strpos && !error)
    01358   {
    01359
    01360     QChar c = fmt.at(fmtpos++);
    01361
    01362     if (c != '%') {
    01363       if (c.isSpace() && str.at(strpos).isSpace())
    01364         strpos++;
    01365       else if (c != str.at(strpos++))
    01366         error = true;
    01367     }
    01368     else
    01369     {
    01370       int j;
    01371       // remove space at the begining
    01372       if (str.length() > strpos && str.at(strpos).isSpace())
    01373         strpos++;
    01374
    01375       c = fmt.at(fmtpos++);
    01376       switch (c)
    01377       {
    01378         case 'a':
    01379         case 'A':
    01380
    01381           error = true;
    01382           j = 1;
    01383           while (error && (j < 8)) {
    01384             QString s = weekDayName(j, c == 'a').lower();
    01385             int len = s.length();
    01386             if (str.mid(strpos, len) == s)
    01387             {
    01388               strpos += len;
    01389               error = false;
    01390             }
    01391             j++;
    01392           }
    01393           break;
    01394         case 'b':
    01395         case 'B':
    01396
    01397           error = true;
    01398           if (d->nounDeclension && d->dateMonthNamePossessive) {
    01399             j = 1;
    01400             while (error && (j < 13)) {
    01401               QString s = monthNamePossessive(j, c == 'b').lower();
    01402               int len = s.length();
    01403               if (str.mid(strpos, len) == s) {
    01404                 month = j;
    01405                 strpos += len;
    01406                 error = false;
    01407               }
    01408               j++;
    01409             }
    01410           }
    01411           j = 1;
    01412           while (error && (j < 13)) {
    01413             QString s = monthName(j, c == 'b').lower();
    01414             int len = s.length();
    01415             if (str.mid(strpos, len) == s) {
    01416               month = j;
    01417               strpos += len;
    01418               error = false;
    01419             }
    01420             j++;
    01421           }
    01422           break;
    01423         case 'd':
    01424         case 'e':
    01425           day = readInt(str, strpos);
    01426           error = (day < 1 || day > 31);
    01427           break;
    01428
    01429         case 'n':
    01430         case 'm':
    01431           month = readInt(str, strpos);
    01432           error = (month < 1 || month > 12);
    01433           break;
    01434
    01435         case 'Y':
    01436         case 'y':
    01437           year = readInt(str, strpos);
    01438           error = (year < 0);
    01439           // Qt treats a year in the range 0-100 as 1900-1999.
    01440           // It is nicer for the user if we treat 0-68 as 2000-2068
    01441           if (year < 69)
    01442             year += 2000;
    01443           else if (c == 'y')
    01444             year += 1900;
    01445
    01446           break;
    01447       }
    01448     }
    01449   }
    01450
    01451   /* for a match, we should reach the end of both strings, not just one of
    01452      them */
    01453   if ( fmt.length() > fmtpos || str.length() > strpos )
    01454   {
    01455     error = true;
    01456   }
    01457
    01458   //kdDebug(173) << "KLocale::readDate day=" << day << " month=" << month << " year=" << year << endl;
    01459   if ( year != -1 && month != -1 && day != -1 && !error)
    01460   {
    01461     if (ok) *ok = true;
    01462     return QDate(year, month, day);
    01463   }
    01464   else
    01465   {
    01466     if (ok) *ok = false;
    01467     return QDate(); // invalid date
    01468   }
    01469 }
    01470
    01471 QTime KLocale::readTime(const QString &intstr, bool *ok) const
    01472 {
    01473   QTime _time;
    01474   _time = readTime(intstr, true, ok);
    01475   if (_time.isValid()) return _time;
    01476   return readTime(intstr, false, ok);
    01477 }
    01478
    01479 QTime KLocale::readTime(const QString &intstr, bool seconds, bool *ok) const
    01480 {
    01481   QString str = intstr.simplifyWhiteSpace().lower();
    01482   QString Format = timeFormat().simplifyWhiteSpace();
    01483   if (!seconds)
    01484     Format.replace(QRegExp(QString::fromLatin1(".%S")), QString::null);
    01485
    01486   int hour = -1, minute = -1, second = seconds ? -1 : 0; // don't require seconds
    01487   bool g_12h = false;
    01488   bool pm = false;
    01489   uint strpos = 0;
    01490   uint Formatpos = 0;
    01491
    01492   while (Format.length() > Formatpos || str.length() > strpos)
    01493     {
    01494       if ( !(Format.length() > Formatpos && str.length() > strpos) ) goto error;
    01495
    01496       QChar c = Format.at(Formatpos++);
    01497
    01498       if (c != '%')
    01499         {
    01500           if (c.isSpace())
    01501             strpos++;
    01502           else if (c != str.at(strpos++))
    01503             goto error;
    01504           continue;
    01505         }
    01506
    01507       // remove space at the begining
    01508       if (str.length() > strpos && str.at(strpos).isSpace())
    01509         strpos++;
    01510
    01511       c = Format.at(Formatpos++);
    01512       switch (c)
    01513         {
    01514         case 'p':
    01515           {
    01516             QString s;
    01517             s = translate("pm").lower();
    01518             int len = s.length();
    01519             if (str.mid(strpos, len) == s)
    01520               {
    01521                 pm = true;
    01522                 strpos += len;
    01523               }
    01524             else
    01525               {
    01526                 s = translate("am").lower();
    01527                 len = s.length();
    01528                 if (str.mid(strpos, len) == s) {
    01529                   pm = false;
    01530                   strpos += len;
    01531                 }
    01532                 else
    01533                   goto error;
    01534               }
    01535           }
    01536           break;
    01537
    01538         case 'k':
    01539         case 'H':
    01540           g_12h = false;
    01541           hour = readInt(str, strpos);
    01542           if (hour < 0 || hour > 23)
    01543             goto error;
    01544
    01545           break;
    01546
    01547         case 'l':
    01548         case 'I':
    01549           g_12h = true;
    01550           hour = readInt(str, strpos);
    01551           if (hour < 1 || hour > 12)
    01552             goto error;
    01553
    01554           break;
    01555
    01556         case 'M':
    01557           minute = readInt(str, strpos);
    01558           if (minute < 0 || minute > 59)
    01559             goto error;
    01560
    01561           break;
    01562
    01563         case 'S':
    01564           second = readInt(str, strpos);
    01565           if (second < 0 || second > 59)
    01566             goto error;
    01567
    01568           break;
    01569         }
    01570     }
    01571   if (g_12h) {
    01572     hour %= 12;
    01573     if (pm) hour += 12;
    01574   }
    01575
    01576   if (ok) *ok = true;
    01577   return QTime(hour, minute, second);
    01578
    01579  error:
    01580   if (ok) *ok = false;
    01581   return QTime(-1, -1, -1); // return invalid date if it didn't work
    01582 }
    01583
    01584 QString KLocale::formatTime(const QTime &pTime, bool includeSecs) const
    01585 {
    01586   const QString rst = timeFormat();
    01587
    01588   // only "pm/am" here can grow, the rest shrinks, but
    01589   // I'm rather safe than sorry
    01590   QChar *buffer = new QChar[rst.length() * 3 / 2 + 30];
    01591
    01592   uint index = 0;
    01593   bool escape = false;
    01594   int number = 0;
    01595
    01596   for ( uint format_index = 0; format_index < rst.length(); format_index++ )
    01597     {
    01598       if ( !escape )
    01599         {
    01600           if ( rst.at( format_index ).unicode() == '%' )
    01601             escape = true;
    01602           else
    01603             buffer[index++] = rst.at( format_index );
    01604         }
    01605       else
    01606         {
    01607           switch ( rst.at( format_index ).unicode() )
    01608             {
    01609             case '%':
    01610               buffer[index++] = '%';
    01611               break;
    01612             case 'H':
    01613               put_it_in( buffer, index, pTime.hour() );
    01614               break;
    01615             case 'I':
    01616               put_it_in( buffer, index, ( pTime.hour() + 11) % 12 + 1 );
    01617               break;
    01618             case 'M':
    01619               put_it_in( buffer, index, pTime.minute() );
    01620               break;
    01621             case 'S':
    01622               if (includeSecs)
    01623                 put_it_in( buffer, index, pTime.second() );
    01624               else if ( index > 0 )
    01625                 {
    01626                   // we remove the seperator sign before the seconds and
    01627                   // assume that works everywhere
    01628                   --index;
    01629                   break;
    01630                 }
    01631               break;
    01632             case 'k':
    01633               number = pTime.hour();
    01634             case 'l':
    01635               // to share the code
    01636               if ( rst.at( format_index ).unicode() == 'l' )
    01637                 number = (pTime.hour() + 11) % 12 + 1;
    01638               if ( number / 10 )
    01639                 buffer[index++] = number / 10 + '0';
    01640               buffer[index++] = number % 10 + '0';
    01641               break;
    01642             case 'p':
    01643               {
    01644                 QString s;
    01645                 if ( pTime.hour() >= 12 )
    01646                   put_it_in( buffer, index, translate("pm") );
    01647                 else
    01648                   put_it_in( buffer, index, translate("am") );
    01649                 break;
    01650               }
    01651             default:
    01652               buffer[index++] = rst.at( format_index );
    01653               break;
    01654             }
    01655           escape = false;
    01656         }
    01657     }
    01658   QString ret( buffer, index );
    01659   delete [] buffer;
    01660   return ret;
    01661 }
    01662
    01663 bool KLocale::use12Clock() const
    01664 {
    01665   if ((timeFormat().contains(QString::fromLatin1("%I")) > 0) ||
    01666       (timeFormat().contains(QString::fromLatin1("%l")) > 0))
    01667     return true;
    01668   else
    01669     return false;
    01670 }
    01671
    01672 QString KLocale::languages() const
    01673 {
    01674   return d->languageList.join( QString::fromLatin1(":") );
    01675 }
    01676
    01677 QStringList KLocale::languageList() const
    01678 {
    01679   return d->languageList;
    01680 }
    01681
    01682 QString KLocale::formatDateTime(const QDateTime &pDateTime,
    01683                                 bool shortFormat,
    01684                                 bool includeSeconds) const
    01685 {
    01686   return translate("concatenation of dates and time", "%1 %2")
    01687     .arg( formatDate( pDateTime.date(), shortFormat ) )
    01688     .arg( formatTime( pDateTime.time(), includeSeconds ) );
    01689 }
    01690
    01691 QString i18n(const char* text)
    01692 {
    01693   register KLocale *instance = KGlobal::locale();
    01694   if (instance)
    01695     return instance->translate(text);
    01696   return QString::fromUtf8(text);
    01697 }
    01698
    01699 QString i18n(const char* index, const char *text)
    01700 {
    01701   register KLocale *instance = KGlobal::locale();
    01702   if (instance)
    01703     return instance->translate(index, text);
    01704   return QString::fromUtf8(text);
    01705 }
    01706
    01707 QString i18n(const char* singular, const char* plural, unsigned long n)
    01708 {
    01709   register KLocale *instance = KGlobal::locale();
    01710   if (instance)
    01711     return instance->translate(singular, plural, n);
    01712   if (n == 1)
    01713     return put_n_in(QString::fromUtf8(singular), n);
    01714   else
    01715     return put_n_in(QString::fromUtf8(plural), n);
    01716 }
    01717
    01718 void KLocale::initInstance()
    01719 {
    01720   if (KGlobal::_locale)
    01721     return;
    01722
    01723   KInstance *app = KGlobal::instance();
    01724   if (app) {
    01725     KGlobal::_locale = new KLocale(QString::fromLatin1(app->instanceName()));
    01726
    01727     // only do this for the global instance
    01728     QTextCodec::setCodecForLocale(KGlobal::_locale->codecForEncoding());
    01729   }
    01730   else
    01731     kdDebug(173) << "no app name available using KLocale - nothing to do\n";
    01732 }
    01733
    01734 QString KLocale::langLookup(const QString &fname, const char *rtype)
    01735 {
    01736   QStringList search;
    01737
    01738   // assemble the local search paths
    01739   const QStringList localDoc = KGlobal::dirs()->resourceDirs(rtype);
    01740
    01741   // look up the different languages
    01742   for (int id=localDoc.count()-1; id >= 0; --id)
    01743     {
    01744       QStringList langs = KGlobal::locale()->languageList();
    01745       langs.append( "en" );
    01746       langs.remove( defaultLanguage() );
    01747       QStringList::ConstIterator lang;
    01748       for (lang = langs.begin(); lang != langs.end(); ++lang)
    01749         search.append(QString("%1%2/%3").arg(localDoc[id]).arg(*lang).arg(fname));
    01750     }
    01751
    01752   // try to locate the file
    01753   QStringList::Iterator it;
    01754   for (it = search.begin(); it != search.end(); ++it)
    01755     {
    01756       kdDebug(173) << "Looking for help in: " << *it << endl;
    01757
    01758       QFileInfo info(*it);
    01759       if (info.exists() && info.isFile() && info.isReadable())
    01760         return *it;
    01761     }
    01762
    01763   return QString::null;
    01764 }
    01765
    01766 bool KLocale::useDefaultLanguage() const
    01767 {
    01768   return language() == defaultLanguage();
    01769 }
    01770
    01771 void KLocale::initEncoding(KConfig *)
    01772 {
    01773   const int mibDefault = 4; // ISO 8859-1
    01774
    01775   // This all made more sense when we still had the EncodingEnum config key.
    01776   setEncoding( QTextCodec::codecForLocale()->mibEnum() );
    01777
    01778   if ( !d->codecForEncoding )
    01779     {
    01780       kdWarning(173) << " Defaulting to ISO 8859-1 encoding." << endl;
    01781       setEncoding(mibDefault);
    01782     }
    01783
    01784   Q_ASSERT( d->codecForEncoding );
    01785 }
    01786
    01787 void KLocale::initFileNameEncoding(KConfig *)
    01788 {
    01789   // If the following environment variable is set, assume all filenames
    01790   // are in UTF-8 regardless of the current C locale.
    01791   if (getenv("KDE_UTF8_FILENAMES") != 0)
    01792   {
    01793     QFile::setEncodingFunction(KLocale::encodeFileNameUTF8);
    01794     QFile::setDecodingFunction(KLocale::decodeFileNameUTF8);
    01795   }
    01796   // Otherwise, stay with QFile's default filename encoding functions
    01797   // which, on Unix platforms, use the locale's codec.
    01798 }
    01799
    01800 QCString KLocale::encodeFileNameUTF8( const QString & fileName )
    01801 {
    01802   return fileName.utf8();
    01803 }
    01804
    01805 QString KLocale::decodeFileNameUTF8( const QCString & localFileName )
    01806 {
    01807   return QString::fromUtf8(localFileName);
    01808 }
    01809
    01810 void KLocale::initCatalogue( KCatalogue & catalogue )
    01811 {
    01812   catalogue.setFileName( catalogueFileName( language(), catalogue ) );
    01813 }
    01814
    01815 void KLocale::setDateFormat(const QString & format)
    01816 {
    01817   doFormatInit();
    01818   m_dateFormat = format.stripWhiteSpace();
    01819 }
    01820
    01821 void KLocale::setDateFormatShort(const QString & format)
    01822 {
    01823   doFormatInit();
    01824   m_dateFormatShort = format.stripWhiteSpace();
    01825 }
    01826
    01827 void KLocale::setDateMonthNamePossessive(bool possessive)
    01828 {
    01829   doFormatInit();
    01830   d->dateMonthNamePossessive = possessive;
    01831 }
    01832
    01833 void KLocale::setTimeFormat(const QString & format)
    01834 {
    01835   doFormatInit();
    01836   m_timeFormat = format.stripWhiteSpace();
    01837 }
    01838
    01839 void KLocale::setWeekStartsMonday(bool start) //deprecated
    01840 {
    01841   doFormatInit();
    01842   if (start)
    01843     d->weekStartDay = 1;
    01844   else
    01845     d->weekStartDay = 7;
    01846 }
    01847
    01848 void KLocale::setWeekStartDay(int day)
    01849 {
    01850   doFormatInit();
    01851   if (day>7 || day<1)
    01852     d->weekStartDay = 1; //Monday is default
    01853   else
    01854     d->weekStartDay = day;
    01855 }
    01856
    01857 QString KLocale::dateFormat() const
    01858 {
    01859   doFormatInit();
    01860   return m_dateFormat;
    01861 }
    01862
    01863 QString KLocale::dateFormatShort() const
    01864 {
    01865   doFormatInit();
    01866   return m_dateFormatShort;
    01867 }
    01868
    01869 QString KLocale::timeFormat() const
    01870 {
    01871   doFormatInit();
    01872   return m_timeFormat;
    01873 }
    01874
    01875 void KLocale::setDecimalSymbol(const QString & symbol)
    01876 {
    01877   doFormatInit();
    01878   m_decimalSymbol = symbol.stripWhiteSpace();
    01879 }
    01880
    01881 void KLocale::setThousandsSeparator(const QString & separator)
    01882 {
    01883   doFormatInit();
    01884   // allow spaces here
    01885   m_thousandsSeparator = separator;
    01886 }
    01887
    01888 void KLocale::setPositiveSign(const QString & sign)
    01889 {
    01890   doFormatInit();
    01891   m_positiveSign = sign.stripWhiteSpace();
    01892 }
    01893
    01894 void KLocale::setNegativeSign(const QString & sign)
    01895 {
    01896   doFormatInit();
    01897   m_negativeSign = sign.stripWhiteSpace();
    01898 }
    01899
    01900 void KLocale::setPositiveMonetarySignPosition(SignPosition signpos)
    01901 {
    01902   doFormatInit();
    01903   m_positiveMonetarySignPosition = signpos;
    01904 }
    01905
    01906 void KLocale::setNegativeMonetarySignPosition(SignPosition signpos)
    01907 {
    01908   doFormatInit();
    01909   m_negativeMonetarySignPosition = signpos;
    01910 }
    01911
    01912 void KLocale::setPositivePrefixCurrencySymbol(bool prefix)
    01913 {
    01914   doFormatInit();
    01915   m_positivePrefixCurrencySymbol = prefix;
    01916 }
    01917
    01918 void KLocale::setNegativePrefixCurrencySymbol(bool prefix)
    01919 {
    01920   doFormatInit();
    01921   m_negativePrefixCurrencySymbol = prefix;
    01922 }
    01923
    01924 void KLocale::setFracDigits(int digits)
    01925 {
    01926   doFormatInit();
    01927   m_fracDigits = digits;
    01928 }
    01929
    01930 void KLocale::setMonetaryThousandsSeparator(const QString & separator)
    01931 {
    01932   doFormatInit();
    01933   // allow spaces here
    01934   m_monetaryThousandsSeparator = separator;
    01935 }
    01936
    01937 void KLocale::setMonetaryDecimalSymbol(const QString & symbol)
    01938 {
    01939   doFormatInit();
    01940   m_monetaryDecimalSymbol = symbol.stripWhiteSpace();
    01941 }
    01942
    01943 void KLocale::setCurrencySymbol(const QString & symbol)
    01944 {
    01945   doFormatInit();
    01946   m_currencySymbol = symbol.stripWhiteSpace();
    01947 }
    01948
    01949 int KLocale::pageSize() const
    01950 {
    01951   doFormatInit();
    01952   return d->pageSize;
    01953 }
    01954
    01955 void KLocale::setPageSize(int pageSize)
    01956 {
    01957   // #### check if it's in range??
    01958   doFormatInit();
    01959   d->pageSize = pageSize;
    01960 }
    01961
    01962 KLocale::MeasureSystem KLocale::measureSystem() const
    01963 {
    01964   doFormatInit();
    01965   return d->measureSystem;
    01966 }
    01967
    01968 void KLocale::setMeasureSystem(MeasureSystem value)
    01969 {
    01970   doFormatInit();
    01971   d->measureSystem = value;
    01972 }
    01973
    01974 QString KLocale::defaultLanguage()
    01975 {
    01976   return QString::fromLatin1("en_US");
    01977 }
    01978
    01979 QString KLocale::defaultCountry()
    01980 {
    01981   return QString::fromLatin1("C");
    01982 }
    01983
    01984 const char * KLocale::encoding() const
    01985 {
    01986   return codecForEncoding()->name();
    01987 }
    01988
    01989 int KLocale::encodingMib() const
    01990 {
    01991   return codecForEncoding()->mibEnum();
    01992 }
    01993
    01994 QTextCodec * KLocale::codecForEncoding() const
    01995 {
    01996   return d->codecForEncoding;
    01997 }
    01998
    01999 bool KLocale::setEncoding(int mibEnum)
    02000 {
    02001   QTextCodec * codec = QTextCodec::codecForMib(mibEnum);
    02002   if (codec)
    02003     d->codecForEncoding = codec;
    02004
    02005   return codec != 0;
    02006 }
    02007
    02008 QStringList KLocale::languagesTwoAlpha() const
    02009 {
    02010   if (d->langTwoAlpha.count())
    02011      return d->langTwoAlpha;
    02012
    02013   const QStringList &origList = languageList();
    02014
    02015   QStringList result;
    02016
    02017   KConfig config(QString::fromLatin1("language.codes"), true, false);
    02018   config.setGroup("TwoLetterCodes");
    02019
    02020   for ( QStringList::ConstIterator it = origList.begin();
    02021         it != origList.end();
    02022         ++it )
    02023     {
    02024       QString lang = *it;
    02025       QStringList langLst;
    02026       if (config.hasKey( lang ))
    02027          langLst = config.readListEntry( lang );
    02028       else
    02029       {
    02030          int i = lang.find('_');
    02031          if (i >= 0)
    02032             lang.truncate(i);
    02033          langLst << lang;
    02034       }
    02035
    02036       for ( QStringList::ConstIterator langIt = langLst.begin();
    02037             langIt != langLst.end();
    02038             ++langIt )
    02039         {
    02040           if ( !(*langIt).isEmpty() && !result.contains( *langIt ) )
    02041             result += *langIt;
    02042         }
    02043     }
    02044   d->langTwoAlpha = result;
    02045   return result;
    02046 }
    02047
    02048 QStringList KLocale::allLanguagesTwoAlpha() const
    02049 {
    02050   if (!d->languages)
    02051     d->languages = new KConfig("all_languages", true, false, "locale");
    02052
    02053   return d->languages->groupList();
    02054 }
    02055
    02056 QString KLocale::twoAlphaToLanguageName(const QString &code) const
    02057 {
    02058   if (!d->languages)
    02059     d->languages = new KConfig("all_languages", true, false, "locale");
    02060
    02061   d->languages->setGroup(code.lower());
    02062   return d->languages->readEntry("Name");
    02063 }
    02064
    02065 QStringList KLocale::allCountriesTwoAlpha() const
    02066 {
    02067   QStringList countries;
    02068   QStringList paths = KGlobal::dirs()->findAllResources("locale", "l10n/*/entry.desktop");
    02069   for(QStringList::ConstIterator it = paths.begin();
    02070       it != paths.end(); ++it)
    02071   {
    02072     QString code = (*it).mid((*it).length()-16, 2);
    02073     if (code != "/C")
    02074        countries.append(code);
    02075   }
    02076   return countries;
    02077 }
    02078
    02079 QString KLocale::twoAlphaToCountryName(const QString &code) const
    02080 {
    02081   KConfig cfg("l10n/"+code.lower()+"/entry.desktop", true, false, "locale");
    02082   cfg.setGroup("KCM Locale");
    02083   return cfg.readEntry("Name");
    02084 }
    02085
    02086
    02087 KLocale::KLocale(const KLocale & rhs)
    02088 {
    02089   d = new KLocalePrivate;
    02090
    02091   *this = rhs;
    02092 }
    02093
    02094 KLocale & KLocale::operator=(const KLocale & rhs)
    02095 {
    02096   // Numbers and money
    02097   m_decimalSymbol = rhs.m_decimalSymbol;
    02098   m_thousandsSeparator = rhs.m_thousandsSeparator;
    02099   m_currencySymbol = rhs.m_currencySymbol;
    02100   m_monetaryDecimalSymbol = rhs.m_monetaryDecimalSymbol;
    02101   m_monetaryThousandsSeparator = rhs.m_monetaryThousandsSeparator;
    02102   m_positiveSign = rhs.m_positiveSign;
    02103   m_negativeSign = rhs.m_negativeSign;
    02104   m_fracDigits = rhs.m_fracDigits;
    02105   m_positivePrefixCurrencySymbol = rhs.m_positivePrefixCurrencySymbol;
    02106   m_negativePrefixCurrencySymbol = rhs.m_negativePrefixCurrencySymbol;
    02107   m_positiveMonetarySignPosition = rhs.m_positiveMonetarySignPosition;
    02108   m_negativeMonetarySignPosition = rhs.m_negativeMonetarySignPosition;
    02109
    02110   // Date and time
    02111   m_timeFormat = rhs.m_timeFormat;
    02112   m_dateFormat = rhs.m_dateFormat;
    02113   m_dateFormatShort = rhs.m_dateFormatShort;
    02114
    02115   m_language = rhs.m_language;
    02116   m_country = rhs.m_country;
    02117
    02118   // the assignment operator works here
    02119   *d = *rhs.d;
    02120   d->languages = 0; // Don't copy languages
    02121
    02122   return *this;
    02123 }

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:46:39 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001