KHolidays Library
holidayregion.cpp
00001 /* 00002 This file is part of the kholidays library. 00003 00004 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> 00005 Copyright (c) 2004 Allen Winter <winter@kde.org> 00006 Copyright (c) 2008 David Jarvie <djarvie@kde.org> 00007 Copyright 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 00017 GNU 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 the 00021 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00022 Boston, MA 02110-1301, USA. 00023 */ 00024 00025 #include "holidayregion.h" 00026 00027 #include <QtCore/QDateTime> 00028 #include <QtCore/QFile> 00029 #include <QtCore/QSharedData> 00030 #include <QtCore/QFileInfo> 00031 00032 #include <KStandardDirs> 00033 #include <KGlobal> 00034 #include <KLocale> 00035 #include <KDebug> 00036 00037 #include "holiday_p.h" 00038 #include "parsers/plan2/holidayparserdriverplan_p.h" 00039 00040 using namespace KHolidays; 00041 00042 class HolidayRegion::Private 00043 { 00044 public: 00045 Private( const QString ®ionCode ) : mDriver( 0 ), 00046 mRegionCode( regionCode ) 00047 { 00048 if ( !mRegionCode.isEmpty() ) { 00049 00050 if ( mRegionCode.length() == 2 ) { //Backwards compatible mode for old location code 00051 mLocation = mRegionCode; 00052 QStringList locationFiles = KGlobal::dirs()->findAllResources( "data", 00053 "libkholidays/plan2/holiday_" + mLocation + '*', 00054 KStandardDirs::NoDuplicates ); 00055 if ( locationFiles.count() > 0 ) { 00056 mRegionCode = locationFiles.at( 0 ). 00057 mid( locationFiles.at( 0 ).lastIndexOf( "holiday_" ) + 8 ); 00058 } 00059 } 00060 00061 mHolidayFile.setFile( 00062 KStandardDirs::locate( "data", "libkholidays/plan2/holiday_" + mRegionCode ) ); 00063 } 00064 00065 init(); 00066 } 00067 00068 Private( const QFileInfo ®ionFile ) : mDriver( 0 ), 00069 mHolidayFile( regionFile ) 00070 { 00071 init(); 00072 } 00073 00074 ~Private() 00075 { 00076 delete mDriver; 00077 } 00078 00079 void init() 00080 { 00081 if ( mHolidayFile.exists() ) { 00082 mDriver = new HolidayParserDriverPlan( mHolidayFile.absoluteFilePath() ); 00083 if ( mDriver ) { 00084 00085 if ( mLocation.isEmpty() ) { 00086 mLocation = mDriver->fileCountryCode().left( 2 ); 00087 } 00088 00089 if ( mRegionCode.isEmpty() ) { 00090 if ( mHolidayFile.fileName().startsWith( QLatin1String( "holiday_" ) ) ) { 00091 mRegionCode = mHolidayFile.fileName().mid( 8 ); 00092 } else { 00093 mRegionCode = mHolidayFile.fileName(); 00094 } 00095 } 00096 00097 } else { 00098 mRegionCode.clear(); 00099 mLocation.clear(); 00100 } 00101 } else { 00102 mRegionCode.clear(); 00103 mLocation.clear(); 00104 } 00105 } 00106 00107 HolidayParserDriver *mDriver; // The parser driver for the holiday file 00108 QString mRegionCode; // region code of holiday region 00109 QString mLocation; // old location code, use now deprecated 00110 QFileInfo mHolidayFile; // file containing holiday data, or null 00111 }; 00112 00113 HolidayRegion::HolidayRegion( const QString ®ionCode ) 00114 : d( new Private( regionCode ) ) 00115 { 00116 } 00117 00118 HolidayRegion::HolidayRegion( const QFileInfo ®ionFile ) 00119 : d( new Private( regionFile ) ) 00120 { 00121 } 00122 00123 HolidayRegion::~HolidayRegion() 00124 { 00125 delete d; 00126 } 00127 00128 QStringList HolidayRegion::locations() 00129 { 00130 const QStringList files = 00131 KGlobal::dirs()->findAllResources( "data", "libkholidays/plan2/holiday_*", 00132 KStandardDirs::NoDuplicates ); 00133 00134 QStringList locations; 00135 foreach ( const QString &filename, files ) { 00136 locations.append( filename.mid( filename.lastIndexOf( "holiday_" ) + 8, 2 ) ); 00137 } 00138 00139 locations.removeDuplicates(); 00140 qSort( locations ); 00141 return locations; 00142 } 00143 00144 QString HolidayRegion::location() const 00145 { 00146 return d->mLocation; 00147 } 00148 00149 QStringList HolidayRegion::regionCodes() 00150 { 00151 const QStringList files = 00152 KGlobal::dirs()->findAllResources( "data", "libkholidays/plan2/holiday_*", 00153 KStandardDirs::NoDuplicates ); 00154 00155 QStringList regionCodesList; 00156 foreach ( const QString &filename, files ) { 00157 regionCodesList.append( filename.mid( filename.lastIndexOf( "holiday_" ) + 8 ) ); 00158 } 00159 00160 qSort( regionCodesList ); 00161 return regionCodesList; 00162 } 00163 00164 QString HolidayRegion::regionCode() const 00165 { 00166 return d->mRegionCode; 00167 } 00168 00169 QString HolidayRegion::countryCode() const 00170 { 00171 return d->mDriver->fileCountryCode(); 00172 } 00173 00174 QString HolidayRegion::countryCode( const QString ®ionCode ) 00175 { 00176 HolidayRegion temp = HolidayRegion( regionCode ); 00177 if ( temp.isValid() ) { 00178 return temp.countryCode(); 00179 } else { 00180 return QString(); 00181 } 00182 } 00183 00184 QString HolidayRegion::languageCode() const 00185 { 00186 return d->mDriver->fileLanguageCode(); 00187 } 00188 00189 QString HolidayRegion::languageCode( const QString ®ionCode ) 00190 { 00191 HolidayRegion temp = HolidayRegion( regionCode ); 00192 if ( temp.isValid() ) { 00193 return temp.languageCode(); 00194 } else { 00195 return QString(); 00196 } 00197 } 00198 00199 QString HolidayRegion::name() const 00200 { 00201 QString tempName = d->mDriver->fileName(); 00202 00203 if ( tempName.isEmpty() ) { 00204 QStringList countryParts = countryCode().toLower().split( '-' ); 00205 QString country = countryParts.at( 0 ); 00206 QString regionName, typeName; 00207 00208 if ( country != "xx" ) { 00209 if ( countryParts.count() == 2 ) { 00210 // Temporary measure to get regions translated, only those files that already exist 00211 // In 4.6 hope to have isocodes project integration for translations via KLocale 00212 QString subdivision = countryParts.at( 1 ); 00213 if ( country == "ca" && subdivision == "qc" ) { 00214 regionName = i18nc( "Canadian region", "Quebec" ); 00215 } else if ( country == "de" && subdivision == "by" ) { 00216 regionName = i18nc( "German region", "Bavaria" ); 00217 } else if ( country == "es" && subdivision == "ct" ) { 00218 regionName = i18nc( "Spanish region", "Catalonia" ); 00219 } else if ( country == "gb" && subdivision == "eaw" ) { 00220 regionName = i18nc( "UK Region", "England and Wales" ); 00221 } else if ( country == "gb" && subdivision == "eng" ) { 00222 regionName = i18nc( "UK Region", "England" ); 00223 } else if ( country == "gb" && subdivision == "wls" ) { 00224 regionName = i18nc( "UK Region", "Wales" ); 00225 } else if ( country == "gb" && subdivision == "sct" ) { 00226 regionName = i18nc( "UK Region", "Scotland" ); 00227 } else if ( country == "gb" && subdivision == "nir" ) { 00228 regionName = i18nc( "UK Region", "Northern Ireland" ); 00229 } else if ( country == "it" && subdivision == "bz" ) { 00230 regionName = i18nc( "Italian Region", "South Tyrol" ); 00231 } else if ( country == "au" && subdivision == "nsw" ) { 00232 regionName = i18nc( "Australian Region", "New South Wales" ); 00233 } else if ( country == "au" && subdivision == "qld" ) { 00234 regionName = i18nc( "Australian Region", "Queensland" ); 00235 } else if ( country == "au" && subdivision == "vic" ) { 00236 regionName = i18nc( "Australian Region", "Victoria" ); 00237 } else if ( country == "au" && subdivision == "sa" ) { 00238 regionName = i18nc( "Australian Region", "South Australia" ); 00239 } else if ( country == "au" && subdivision == "nt" ) { 00240 regionName = i18nc( "Australian Region", "Northern Territory" ); 00241 } else if ( country == "au" && subdivision == "act" ) { 00242 regionName = i18nc( "Australian Region", "Australian Capital Territory" ); 00243 } else if ( country == "au" && subdivision == "wa" ) { 00244 regionName = i18nc( "Australian Region", "Western Australia" ); 00245 } else if ( country == "au" && subdivision == "tas" ) { 00246 regionName = i18nc( "Australian Region", "Tasmania" ); 00247 } else if ( country == "ba" && subdivision == "srp" ) { 00248 regionName = i18nc( "Bosnian and Herzegovinian Region", "Republic of Srpska" ); 00249 } else { 00250 regionName = KGlobal::locale()->countryCodeToName( country ); 00251 } 00252 } else { 00253 regionName = KGlobal::locale()->countryCodeToName( country ); 00254 } 00255 } 00256 00257 //Cheat on type for now,take direct from region code until API is introduced in SC 4.6 00258 QStringList regionParts = regionCode().toLower().split( '_' ); 00259 if ( regionParts.count() == 3 ) { 00260 QString type = regionParts.at( 2 ); 00261 // Will create lots more in 4.6 00262 // Religious types, just simple for now 00263 if ( type == "public" ) { 00264 typeName = i18nc( "Holiday type", "Public" ); 00265 } else if ( type == "religious" ) { 00266 typeName = i18nc( "Holiday type", "Religious" ); 00267 } else if ( type == "financial" ) { 00268 typeName = i18nc( "Holiday type", "Financial" ); 00269 } else if ( type == "cultural" ) { 00270 typeName = i18nc( "Holiday type", "Cultural" ); 00271 } else if ( type == "school" ) { 00272 typeName = i18nc( "Holiday type", "School" ); 00273 } else if ( type == "seasons" ) { 00274 typeName = i18nc( "Holiday type", "Seasons" ); 00275 } else if ( type == "name" ) { 00276 typeName = i18nc( "Holiday type", "Name Days" ); 00277 } else if ( type == "personal" ) { 00278 typeName = i18nc( "Holiday type", "Personal" ); 00279 } else if ( type == "catholic" ) { 00280 typeName = i18nc( "Holiday type", "Catholic" ); 00281 } else if ( type == "protestant" ) { 00282 typeName = i18nc( "Holiday type", "Protestant" ); 00283 } else if ( type == "orthodox" ) { 00284 typeName = i18nc( "Holiday type", "Orthodox" ); 00285 } else if ( type == "jewish" ) { 00286 typeName = i18nc( "Holiday type", "Jewish" ); 00287 } else if ( type == "islamic" ) { 00288 typeName = i18nc( "Holiday type", "Islamic" ); 00289 } 00290 } 00291 00292 if ( !regionName.isEmpty() ) { 00293 if ( !typeName.isEmpty() ) { 00294 //TODO translate when not frozen 00295 tempName = QString( "%1 - %2" ).arg( regionName ).arg( typeName ); 00296 } else { 00297 tempName = regionName; 00298 } 00299 } else if ( !typeName.isEmpty() ) { 00300 tempName = typeName; 00301 } else { 00302 tempName = i18nc( "Unknown holiday region", "Unknown" ); 00303 } 00304 } 00305 return tempName; 00306 } 00307 00308 QString HolidayRegion::name( const QString ®ionCode ) 00309 { 00310 HolidayRegion temp = HolidayRegion( regionCode ); 00311 if ( temp.isValid() ) { 00312 return temp.name(); 00313 } else { 00314 return QString(); 00315 } 00316 } 00317 00318 QString HolidayRegion::description() const 00319 { 00320 return d->mDriver->fileDescription(); 00321 } 00322 00323 QString HolidayRegion::description( const QString ®ionCode ) 00324 { 00325 HolidayRegion temp = HolidayRegion( regionCode ); 00326 if ( temp.isValid() ) { 00327 return temp.description(); 00328 } else { 00329 return QString(); 00330 } 00331 } 00332 00333 bool HolidayRegion::isValid() const 00334 { 00335 return d->mHolidayFile.exists() && d->mDriver; 00336 } 00337 00338 bool HolidayRegion::isValid( const QString ®ionCode ) 00339 { 00340 HolidayRegion temp = HolidayRegion( regionCode ); 00341 return temp.isValid(); 00342 } 00343 00344 Holiday::List HolidayRegion::holidays( const QDate &startDate, const QDate &endDate ) const 00345 { 00346 return holidays( startDate, endDate, Holiday::MultidayHolidaysAsMultipleEvents ); 00347 } 00348 00349 Holiday::List HolidayRegion::holidays( const QDate &startDate, const QDate &endDate, 00350 Holiday::MultidayMode multidayMode ) const 00351 { 00352 if ( isValid() ) { 00353 return d->mDriver->parseHolidays( startDate, endDate, multidayMode ); 00354 } else { 00355 return Holiday::List(); 00356 } 00357 } 00358 00359 Holiday::List HolidayRegion::holidays( const QDate &date ) const 00360 { 00361 return holidays( date, Holiday::MultidayHolidaysAsMultipleEvents ); 00362 } 00363 00364 Holiday::List HolidayRegion::holidays( const QDate &date, Holiday::MultidayMode multidayMode ) const 00365 { 00366 if ( isValid() ) { 00367 return d->mDriver->parseHolidays( date, multidayMode ); 00368 } else { 00369 return Holiday::List(); 00370 } 00371 } 00372 00373 Holiday::List HolidayRegion::holidays( int calendarYear, const QString &calendarType ) const 00374 { 00375 return holidays( calendarYear, calendarType, Holiday::MultidayHolidaysAsMultipleEvents ); 00376 } 00377 00378 Holiday::List HolidayRegion::holidays( int calendarYear, const QString &calendarType, 00379 Holiday::MultidayMode multidayMode ) const 00380 { 00381 if ( isValid() ) { 00382 return d->mDriver->parseHolidays( calendarYear, calendarType, multidayMode ); 00383 } else { 00384 return Holiday::List(); 00385 } 00386 } 00387 00388 bool HolidayRegion::isHoliday( const QDate &date ) const 00389 { 00390 Holiday::List holidayList = holidays( date, Holiday::MultidayHolidaysAsMultipleEvents ); 00391 if ( holidayList.count() > 0 ) { 00392 foreach ( const KHolidays::Holiday &holiday, holidayList ) { 00393 if ( holiday.dayType() == Holiday::NonWorkday ) { 00394 return true; 00395 } 00396 } 00397 } 00398 return false; 00399 } 00400 00401 QString HolidayRegion::defaultRegionCode( const QString &country, const QString &language ) 00402 { 00403 // Try to match against the users country and language, or failing that the language country. 00404 // Scan through all the regions finding the first match for each possible default 00405 // Holiday Region Country Code can be a country subdivision or the country itself, 00406 // e.g. US or US-CA for California, so we can try match on both but an exact match has priority 00407 // The Holiday Region file is in one language only, so give priority to any file in the 00408 // users language, e.g. bilingual countries with a separate file for each language 00409 // Locale language can have a country code embedded in it e.g. en_GB, which we can try use if 00410 // no country set, but a lot of countries use en_GB so it's a lower priority option 00411 00412 QString localeCountry, localeLanguage, localeLanguageCountry; 00413 00414 if ( country.isEmpty() ) { 00415 localeCountry = KGlobal::locale()->country().toLower(); 00416 } else { 00417 localeCountry = country.toLower(); 00418 } 00419 00420 if ( language.isEmpty() ) { 00421 localeLanguage = KGlobal::locale()->language().toLower(); 00422 } else { 00423 localeLanguage = language.toLower(); 00424 } 00425 00426 if ( localeLanguage.split( '_' ).count() > 1 ) { 00427 localeLanguageCountry = localeLanguage.split( '_' ).at( 1 ); 00428 } 00429 00430 QStringList regionList = KHolidays::HolidayRegion::regionCodes(); 00431 00432 QString countryAndLanguageMatch, countryOnlyMatch, subdivisionAndLanguageMatch, 00433 subdivisionOnlyMatch, languageCountryAndLanguageMatch, languageCountryOnlyMatch, 00434 languageSubdivisionAndLanguageMatch, languageSubdivisionOnlyMatch; 00435 00436 foreach ( const QString ®ionCode, regionList ) { 00437 QString regionCountry = KHolidays::HolidayRegion::countryCode( regionCode ).toLower(); 00438 QString regionSubdivisionCountry; 00439 if ( regionCountry.split( '-' ).count() > 1 ) { 00440 regionSubdivisionCountry = regionCountry.split( '-' ).at( 0 ); 00441 } 00442 QString regionLanguage = KHolidays::HolidayRegion::languageCode( regionCode ).toLower(); 00443 00444 if ( regionCountry == localeCountry && regionLanguage == localeLanguage ) { 00445 countryAndLanguageMatch = regionCode; 00446 break; // exact match so don't look further 00447 } else if ( regionCountry == localeCountry ) { 00448 if ( countryOnlyMatch.isEmpty() ) { 00449 countryOnlyMatch = regionCode; 00450 } 00451 } else if ( !regionSubdivisionCountry.isEmpty() && 00452 regionSubdivisionCountry == localeCountry && 00453 regionLanguage == localeLanguage ) { 00454 if ( subdivisionAndLanguageMatch.isEmpty() ) { 00455 subdivisionAndLanguageMatch = regionCode; 00456 } 00457 } else if ( !regionSubdivisionCountry.isEmpty() && regionSubdivisionCountry == localeCountry ) { 00458 if ( subdivisionOnlyMatch.isEmpty() ) { 00459 subdivisionOnlyMatch = regionCode; 00460 } 00461 } else if ( !localeLanguageCountry.isEmpty() && 00462 regionCountry == localeLanguageCountry && 00463 regionLanguage == localeLanguage ) { 00464 if ( languageCountryAndLanguageMatch.isEmpty() ) { 00465 languageCountryAndLanguageMatch = regionCode; 00466 } 00467 } else if ( !localeLanguageCountry.isEmpty() && regionCountry == localeLanguageCountry ) { 00468 if ( languageCountryOnlyMatch.isEmpty() ) { 00469 languageCountryOnlyMatch = regionCode; 00470 } 00471 } else if ( !regionSubdivisionCountry.isEmpty() && 00472 !localeLanguageCountry.isEmpty() && 00473 regionSubdivisionCountry == localeLanguageCountry && 00474 regionLanguage == localeLanguage ) { 00475 if ( languageSubdivisionAndLanguageMatch.isEmpty() ) { 00476 languageSubdivisionAndLanguageMatch = regionCode; 00477 } 00478 } else if ( !regionSubdivisionCountry.isEmpty() && 00479 !localeLanguageCountry.isEmpty() && 00480 regionSubdivisionCountry == localeLanguageCountry ) { 00481 if ( languageSubdivisionOnlyMatch.isEmpty() ) { 00482 languageSubdivisionOnlyMatch = regionCode; 00483 } 00484 } 00485 } 00486 00487 QString defaultRegionCode; 00488 00489 if ( !countryAndLanguageMatch.isEmpty() ) { 00490 defaultRegionCode = countryAndLanguageMatch; 00491 } else if ( !countryOnlyMatch.isEmpty() ) { 00492 defaultRegionCode = countryOnlyMatch; 00493 } else if ( !subdivisionAndLanguageMatch.isEmpty() ) { 00494 defaultRegionCode = subdivisionAndLanguageMatch; 00495 } else if ( !subdivisionOnlyMatch.isEmpty() ) { 00496 defaultRegionCode = subdivisionOnlyMatch; 00497 } else if ( !languageCountryAndLanguageMatch.isEmpty() ) { 00498 defaultRegionCode = languageCountryAndLanguageMatch; 00499 } else if ( !languageCountryOnlyMatch.isEmpty() ) { 00500 defaultRegionCode = languageCountryOnlyMatch; 00501 } else if ( !languageSubdivisionAndLanguageMatch.isEmpty() ) { 00502 defaultRegionCode = languageSubdivisionAndLanguageMatch; 00503 } else if ( !languageSubdivisionOnlyMatch.isEmpty() ) { 00504 defaultRegionCode = languageSubdivisionOnlyMatch; 00505 } 00506 00507 return defaultRegionCode; 00508 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Apr 30 2012 21:48:30 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Apr 30 2012 21:48:30 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.