KHolidays

holidayregion.cpp
1 /*
2  This file is part of the kholidays library.
3 
4  SPDX-FileCopyrightText: 2001 Cornelius Schumacher <[email protected]>
5  SPDX-FileCopyrightText: 2004-2020 Allen Winter <[email protected]>
6  SPDX-FileCopyrightText: 2008 David Jarvie <[email protected]>
7  SPDX-FileCopyrightText: 2010 John Layt <[email protected]>
8 
9  The functions languageToCode(), codeToLanguage(), countryToCode() and codeToCounty() are copyright by
10  SPDX-FileCopyrightText: 2014 Digia Plc and/or its subsidiary(-ies).
11 
12  SPDX-License-Identifier: LGPL-2.0-or-later
13 */
14 
15 #include "holidayregion.h"
16 
17 #include <QLocale>
18 #include <QDirIterator>
19 #include <QFile>
20 #include <QFileInfo>
21 #include <QSharedData>
22 #include <QStandardPaths>
23 #include <QCoreApplication>
24 
25 #include "holiday_p.h"
26 #include "parsers/plan2/holidayparserdriverplan_p.h"
27 
28 using namespace KHolidays;
29 
30 // Copied from qlocale_data_p.h and qlocale.h, see copyright information at top of file
31 // To later be replaced by OpenCodes or public Qt api
32 static const unsigned char country_code_list[] =
33  "ZZ\0" // AnyCountry
34  "AF\0" // Afghanistan
35  "AL\0" // Albania
36  "DZ\0" // Algeria
37  "AS\0" // AmericanSamoa
38  "AD\0" // Andorra
39  "AO\0" // Angola
40  "AI\0" // Anguilla
41  "AQ\0" // Antarctica
42  "AG\0" // AntiguaAndBarbuda
43  "AR\0" // Argentina
44  "AM\0" // Armenia
45  "AW\0" // Aruba
46  "AU\0" // Australia
47  "AT\0" // Austria
48  "AZ\0" // Azerbaijan
49  "BS\0" // Bahamas
50  "BH\0" // Bahrain
51  "BD\0" // Bangladesh
52  "BB\0" // Barbados
53  "BY\0" // Belarus
54  "BE\0" // Belgium
55  "BZ\0" // Belize
56  "BJ\0" // Benin
57  "BM\0" // Bermuda
58  "BT\0" // Bhutan
59  "BO\0" // Bolivia
60  "BA\0" // BosniaAndHerzegowina
61  "BW\0" // Botswana
62  "BV\0" // BouvetIsland
63  "BR\0" // Brazil
64  "IO\0" // BritishIndianOceanTerritory
65  "BN\0" // Brunei
66  "BG\0" // Bulgaria
67  "BF\0" // BurkinaFaso
68  "BI\0" // Burundi
69  "KH\0" // Cambodia
70  "CM\0" // Cameroon
71  "CA\0" // Canada
72  "CV\0" // CapeVerde
73  "KY\0" // CaymanIslands
74  "CF\0" // CentralAfricanRepublic
75  "TD\0" // Chad
76  "CL\0" // Chile
77  "CN\0" // China
78  "CX\0" // ChristmasIsland
79  "CC\0" // CocosIslands
80  "CO\0" // Colombia
81  "KM\0" // Comoros
82  "CD\0" // CongoKinshasa
83  "CG\0" // CongoBrazzaville
84  "CK\0" // CookIslands
85  "CR\0" // CostaRica
86  "CI\0" // IvoryCoast
87  "HR\0" // Croatia
88  "CU\0" // Cuba
89  "CY\0" // Cyprus
90  "CZ\0" // CzechRepublic
91  "DK\0" // Denmark
92  "DJ\0" // Djibouti
93  "DM\0" // Dominica
94  "DO\0" // DominicanRepublic
95  "TL\0" // EastTimor
96  "EC\0" // Ecuador
97  "EG\0" // Egypt
98  "SV\0" // ElSalvador
99  "GQ\0" // EquatorialGuinea
100  "ER\0" // Eritrea
101  "EE\0" // Estonia
102  "ET\0" // Ethiopia
103  "FK\0" // FalklandIslands
104  "FO\0" // FaroeIslands
105  "FJ\0" // Fiji
106  "FI\0" // Finland
107  "FR\0" // France
108  "GG\0" // Guernsey
109  "GF\0" // FrenchGuiana
110  "PF\0" // FrenchPolynesia
111  "TF\0" // FrenchSouthernTerritories
112  "GA\0" // Gabon
113  "GM\0" // Gambia
114  "GE\0" // Georgia
115  "DE\0" // Germany
116  "GH\0" // Ghana
117  "GI\0" // Gibraltar
118  "GR\0" // Greece
119  "GL\0" // Greenland
120  "GD\0" // Grenada
121  "GP\0" // Guadeloupe
122  "GU\0" // Guam
123  "GT\0" // Guatemala
124  "GN\0" // Guinea
125  "GW\0" // GuineaBissau
126  "GY\0" // Guyana
127  "HT\0" // Haiti
128  "HM\0" // HeardAndMcDonaldIslands
129  "HN\0" // Honduras
130  "HK\0" // HongKong
131  "HU\0" // Hungary
132  "IS\0" // Iceland
133  "IN\0" // India
134  "ID\0" // Indonesia
135  "IR\0" // Iran
136  "IQ\0" // Iraq
137  "IE\0" // Ireland
138  "IL\0" // Israel
139  "IT\0" // Italy
140  "JM\0" // Jamaica
141  "JP\0" // Japan
142  "JO\0" // Jordan
143  "KZ\0" // Kazakhstan
144  "KE\0" // Kenya
145  "KI\0" // Kiribati
146  "KP\0" // NorthKorea
147  "KR\0" // SouthKorea
148  "KW\0" // Kuwait
149  "KG\0" // Kyrgyzstan
150  "LA\0" // Laos
151  "LV\0" // Latvia
152  "LB\0" // Lebanon
153  "LS\0" // Lesotho
154  "LR\0" // Liberia
155  "LY\0" // Libya
156  "LI\0" // Liechtenstein
157  "LT\0" // Lithuania
158  "LU\0" // Luxembourg
159  "MO\0" // Macau
160  "MK\0" // Macedonia
161  "MG\0" // Madagascar
162  "MW\0" // Malawi
163  "MY\0" // Malaysia
164  "MV\0" // Maldives
165  "ML\0" // Mali
166  "MT\0" // Malta
167  "MH\0" // MarshallIslands
168  "MQ\0" // Martinique
169  "MR\0" // Mauritania
170  "MU\0" // Mauritius
171  "YT\0" // Mayotte
172  "MX\0" // Mexico
173  "FM\0" // Micronesia
174  "MD\0" // Moldova
175  "MC\0" // Monaco
176  "MN\0" // Mongolia
177  "MS\0" // Montserrat
178  "MA\0" // Morocco
179  "MZ\0" // Mozambique
180  "MM\0" // Myanmar
181  "NA\0" // Namibia
182  "NR\0" // Nauru
183  "NP\0" // Nepal
184  "NL\0" // Netherlands
185  "CW\0" // CuraSao
186  "NC\0" // NewCaledonia
187  "NZ\0" // NewZealand
188  "NI\0" // Nicaragua
189  "NE\0" // Niger
190  "NG\0" // Nigeria
191  "NU\0" // Niue
192  "NF\0" // NorfolkIsland
193  "MP\0" // NorthernMarianaIslands
194  "NO\0" // Norway
195  "OM\0" // Oman
196  "PK\0" // Pakistan
197  "PW\0" // Palau
198  "PS\0" // PalestinianTerritories
199  "PA\0" // Panama
200  "PG\0" // PapuaNewGuinea
201  "PY\0" // Paraguay
202  "PE\0" // Peru
203  "PH\0" // Philippines
204  "PN\0" // Pitcairn
205  "PL\0" // Poland
206  "PT\0" // Portugal
207  "PR\0" // PuertoRico
208  "QA\0" // Qatar
209  "RE\0" // Reunion
210  "RO\0" // Romania
211  "RU\0" // Russia
212  "RW\0" // Rwanda
213  "KN\0" // SaintKittsAndNevis
214  "LC\0" // SaintLucia
215  "VC\0" // SaintVincentAndTheGrenadines
216  "WS\0" // Samoa
217  "SM\0" // SanMarino
218  "ST\0" // SaoTomeAndPrincipe
219  "SA\0" // SaudiArabia
220  "SN\0" // Senegal
221  "SC\0" // Seychelles
222  "SL\0" // SierraLeone
223  "SG\0" // Singapore
224  "SK\0" // Slovakia
225  "SI\0" // Slovenia
226  "SB\0" // SolomonIslands
227  "SO\0" // Somalia
228  "ZA\0" // SouthAfrica
229  "GS\0" // SouthGeorgiaAndTheSouthSandwichIslands
230  "ES\0" // Spain
231  "LK\0" // SriLanka
232  "SH\0" // SaintHelena
233  "PM\0" // SaintPierreAndMiquelon
234  "SD\0" // Sudan
235  "SR\0" // Suriname
236  "SJ\0" // SvalbardAndJanMayenIslands
237  "SZ\0" // Swaziland
238  "SE\0" // Sweden
239  "CH\0" // Switzerland
240  "SY\0" // Syria
241  "TW\0" // Taiwan
242  "TJ\0" // Tajikistan
243  "TZ\0" // Tanzania
244  "TH\0" // Thailand
245  "TG\0" // Togo
246  "TK\0" // Tokelau
247  "TO\0" // Tonga
248  "TT\0" // TrinidadAndTobago
249  "TN\0" // Tunisia
250  "TR\0" // Turkey
251  "TM\0" // Turkmenistan
252  "TC\0" // TurksAndCaicosIslands
253  "TV\0" // Tuvalu
254  "UG\0" // Uganda
255  "UA\0" // Ukraine
256  "AE\0" // UnitedArabEmirates
257  "GB\0" // UnitedKingdom
258  "US\0" // UnitedStates
259  "UM\0" // UnitedStatesMinorOutlyingIslands
260  "UY\0" // Uruguay
261  "UZ\0" // Uzbekistan
262  "VU\0" // Vanuatu
263  "VA\0" // VaticanCityState
264  "VE\0" // Venezuela
265  "VN\0" // Vietnam
266  "VG\0" // BritishVirginIslands
267  "VI\0" // UnitedStatesVirginIslands
268  "WF\0" // WallisAndFutunaIslands
269  "EH\0" // WesternSahara
270  "YE\0" // Yemen
271  "IC\0" // CanaryIslands
272  "ZM\0" // Zambia
273  "ZW\0" // Zimbabwe
274  "CP\0" // ClippertonIsland
275  "ME\0" // Montenegro
276  "RS\0" // Serbia
277  "BL\0" // Saint Barthelemy
278  "MF\0" // Saint Martin
279  "419" // LatinAmericaAndTheCaribbean
280  "AC\0" // AscensionIsland
281  "AX\0" // AlandIslands
282  "DG\0" // DiegoGarcia
283  "EA\0" // CeutaAndMelilla
284  "IM\0" // IsleOfMan
285  "JE\0" // Jersey
286  "TA\0" // TristanDaCunha
287  "SS\0" // SouthSudan
288  "BQ\0" // Bonaire
289  "SX\0" // SintMaarten
290  "XK\0" // Kosovo
291  ;
292 
293 static const unsigned char language_code_list[] =
294  " \0" // AnyLanguage
295  " \0" // C
296  "ab\0" // Abkhazian
297  "om\0" // Oromo
298  "aa\0" // Afar
299  "af\0" // Afrikaans
300  "sq\0" // Albanian
301  "am\0" // Amharic
302  "ar\0" // Arabic
303  "hy\0" // Armenian
304  "as\0" // Assamese
305  "ay\0" // Aymara
306  "az\0" // Azerbaijani
307  "ba\0" // Bashkir
308  "eu\0" // Basque
309  "bn\0" // Bengali
310  "dz\0" // Dzongkha
311  "bh\0" // Bihari
312  "bi\0" // Bislama
313  "br\0" // Breton
314  "bg\0" // Bulgarian
315  "my\0" // Burmese
316  "be\0" // Belarusian
317  "km\0" // Khmer
318  "ca\0" // Catalan
319  "zh\0" // Chinese
320  "co\0" // Corsican
321  "hr\0" // Croatian
322  "cs\0" // Czech
323  "da\0" // Danish
324  "nl\0" // Dutch
325  "en\0" // English
326  "eo\0" // Esperanto
327  "et\0" // Estonian
328  "fo\0" // Faroese
329  "fj\0" // Fijian
330  "fi\0" // Finnish
331  "fr\0" // French
332  "fy\0" // Western Frisian
333  "gd\0" // Gaelic
334  "gl\0" // Galician
335  "ka\0" // Georgian
336  "de\0" // German
337  "el\0" // Greek
338  "kl\0" // Greenlandic
339  "gn\0" // Guarani
340  "gu\0" // Gujarati
341  "ha\0" // Hausa
342  "he\0" // Hebrew
343  "hi\0" // Hindi
344  "hu\0" // Hungarian
345  "is\0" // Icelandic
346  "id\0" // Indonesian
347  "ia\0" // Interlingua
348  "ie\0" // Interlingue
349  "iu\0" // Inuktitut
350  "ik\0" // Inupiak
351  "ga\0" // Irish
352  "it\0" // Italian
353  "ja\0" // Japanese
354  "jv\0" // Javanese
355  "kn\0" // Kannada
356  "ks\0" // Kashmiri
357  "kk\0" // Kazakh
358  "rw\0" // Kinyarwanda
359  "ky\0" // Kirghiz
360  "ko\0" // Korean
361  "ku\0" // Kurdish
362  "rn\0" // Rundi
363  "lo\0" // Lao
364  "la\0" // Latin
365  "lv\0" // Latvian
366  "ln\0" // Lingala
367  "lt\0" // Lithuanian
368  "mk\0" // Macedonian
369  "mg\0" // Malagasy
370  "ms\0" // Malay
371  "ml\0" // Malayalam
372  "mt\0" // Maltese
373  "mi\0" // Maori
374  "mr\0" // Marathi
375  "mh\0" // Marshallese
376  "mn\0" // Mongolian
377  "na\0" // Nauru
378  "ne\0" // Nepali
379  "nb\0" // NorwegianBokmal
380  "oc\0" // Occitan
381  "or\0" // Oriya
382  "ps\0" // Pashto
383  "fa\0" // Persian
384  "pl\0" // Polish
385  "pt\0" // Portuguese
386  "pa\0" // Punjabi
387  "qu\0" // Quechua
388  "rm\0" // Romansh
389  "ro\0" // Romanian
390  "ru\0" // Russian
391  "sm\0" // Samoan
392  "sg\0" // Sango
393  "sa\0" // Sanskrit
394  "sr\0" // Serbian
395  "os\0" // Ossetic
396  "st\0" // Southern Sotho
397  "tn\0" // Tswana
398  "sn\0" // Shona
399  "sd\0" // Sindhi
400  "si\0" // Sinhala
401  "ss\0" // Swati
402  "sk\0" // Slovak
403  "sl\0" // Slovenian
404  "so\0" // Somali
405  "es\0" // Spanish
406  "su\0" // Sundanese
407  "sw\0" // Swahili
408  "sv\0" // Swedish
409  "sc\0" // Sardinian
410  "tg\0" // Tajik
411  "ta\0" // Tamil
412  "tt\0" // Tatar
413  "te\0" // Telugu
414  "th\0" // Thai
415  "bo\0" // Tibetan
416  "ti\0" // Tigrinya
417  "to\0" // Tongan
418  "ts\0" // Tsonga
419  "tr\0" // Turkish
420  "tk\0" // Turkmen
421  "ty\0" // Tahitian
422  "ug\0" // Uighur
423  "uk\0" // Ukrainian
424  "ur\0" // Urdu
425  "uz\0" // Uzbek
426  "vi\0" // Vietnamese
427  "vo\0" // Volapuk
428  "cy\0" // Welsh
429  "wo\0" // Wolof
430  "xh\0" // Xhosa
431  "yi\0" // Yiddish
432  "yo\0" // Yoruba
433  "za\0" // Zhuang
434  "zu\0" // Zulu
435  "nn\0" // NorwegianNynorsk
436  "bs\0" // Bosnian
437  "dv\0" // Divehi
438  "gv\0" // Manx
439  "kw\0" // Cornish
440  "ak\0" // Akan
441  "kok" // Konkani
442  "gaa" // Ga
443  "ig\0" // Igbo
444  "kam" // Kamba
445  "syr" // Syriac
446  "byn" // Blin
447  "gez" // Geez
448  "kfo" // Koro
449  "sid" // Sidamo
450  "cch" // Atsam
451  "tig" // Tigre
452  "kaj" // Jju
453  "fur" // Friulian
454  "ve\0" // Venda
455  "ee\0" // Ewe
456  "wal" // Walamo
457  "haw" // Hawaiian
458  "kcg" // Tyap
459  "ny\0" // Nyanja
460  "fil" // Filipino
461  "gsw" // Swiss German
462  "ii\0" // Sichuan Yi
463  "kpe" // Kpelle
464  "nds" // Low German
465  "nr\0" // South Ndebele
466  "nso" // Northern Sotho
467  "se\0" // Northern Sami
468  "trv" // Taroko
469  "guz" // Gusii
470  "dav" // Taita
471  "ff\0" // Fulah
472  "ki\0" // Kikuyu
473  "saq" // Samburu
474  "seh" // Sena
475  "nd\0" // North Ndebele
476  "rof" // Rombo
477  "shi" // Tachelhit
478  "kab" // Kabyle
479  "nyn" // Nyankole
480  "bez" // Bena
481  "vun" // Vunjo
482  "bm\0" // Bambara
483  "ebu" // Embu
484  "chr" // Cherokee
485  "mfe" // Morisyen
486  "kde" // Makonde
487  "lag" // Langi
488  "lg\0" // Ganda
489  "bem" // Bemba
490  "kea" // Kabuverdianu
491  "mer" // Meru
492  "kln" // Kalenjin
493  "naq" // Nama
494  "jmc" // Machame
495  "ksh" // Colognian
496  "mas" // Masai
497  "xog" // Soga
498  "luy" // Luyia
499  "asa" // Asu
500  "teo" // Teso
501  "ssy" // Saho
502  "khq" // Koyra Chiini
503  "rwk" // Rwa
504  "luo" // Luo
505  "cgg" // Chiga
506  "tzm" // Central Morocco Tamazight
507  "ses" // Koyraboro Senni
508  "ksb" // Shambala
509  "brx" // Bodo
510  "av\0" // Avaric
511  "ch\0" // Chamorro
512  "ce\0" // Chechen
513  "cu\0" // Church
514  "cv\0" // Chuvash
515  "cr\0" // Cree
516  "ht\0" // Haitian
517  "hz\0" // Herero
518  "ho\0" // Hiri Motu
519  "kr\0" // Kanuri
520  "kv\0" // Komi
521  "kg\0" // Kongo
522  "kj\0" // Kwanyama
523  "li\0" // Limburgish
524  "lu\0" // LubaKatanga
525  "lb\0" // Luxembourgish
526  "nv\0" // Navaho
527  "ng\0" // Ndonga
528  "oj\0" // Ojibwa
529  "pi\0" // Pali
530  "wa\0" // Walloon
531  "agq" // Aghem
532  "bas" // Basaa
533  "dje" // Zarma
534  "dua" // Duala
535  "dyo" // JolaFonyi
536  "ewo" // Ewondo
537  "ksf" // Bafia
538  "mgh" // MakhuwaMeetto
539  "mua" // Mundang
540  "nmg" // Kwasio
541  "nus" // Nuer
542  "sah" // Sakha
543  "sbp" // Sangu
544  "swc" // Congo Swahili
545  "twq" // Tasawaq
546  "vai" // Vai
547  "wae" // Walser
548  "yav" // Yangben
549  "ae\0" // Avestan
550  "ast" // Asturian
551  "jgo" // Ngomba
552  "kkj" // Kako
553  "mgo" // Meta
554  "nnh" // Ngiemboon
555  "an\0" // Aragonese
556  "akk" // Akkadian
557  "egy" // AncientEgyptian
558  "grc" // AncientGreek
559  "arc" // Aramaic
560  "ban" // Balinese
561  "bax" // Bamun
562  "bbc" // BatakToba
563  "bug" // Buginese
564  "bku" // Buhid
565  "xcr" // Carian
566  "ccp" // Chakma
567  "myz" // ClassicalMandaic
568  "cop" // Coptic
569  "doi" // Dogri
570  "cjm" // EasternCham
571  "eky" // EasternKayah
572  "ett" // Etruscan
573  "got" // Gothic
574  "hnn" // Hanunoo
575  "inh" // Ingush
576  "hmd" // LargeFloweryMiao
577  "lep" // Lepcha
578  "lif" // Limbu
579  "lis" // Lisu
580  "khb" // Lu
581  "xlc" // Lycian
582  "xld" // Lydian
583  "man" // Mandingo
584  "mni" // Manipuri
585  "xmr" // Meroitic
586  "nod" // NorthernThai
587  "sga" // OldIrish
588  "non" // OldNorse
589  "peo" // OldPersian
590  "otk" // OldTurkish
591  "pal" // Pahlavi
592  "xpr" // Parthian
593  "phn" // Phoenician
594  "pra" // PrakritLanguage
595  "rej" // Rejang
596  "xsa" // Sabaean
597  "smp" // Samaritan
598  "sat" // Santali
599  "saz" // Saurashtra
600  "srb" // Sora
601  "syl" // Sylheti
602  "tbw" // Tagbanwa
603  "blt" // TaiDam
604  "tdd" // TaiNua
605  "uga" // Ugaritic
606  "bss" // Akoose
607  "lkt" // Lakota
608  "zgh" // Standard Moroccan Tamazight
609  ;
610 
611 static QString languageToCode(QLocale::Language language)
612 {
613  if (language == QLocale::AnyLanguage) {
614  return QString();
615  }
616  if (language == QLocale::C) {
617  return QStringLiteral("C");
618  }
619 
620  const unsigned char *c = language_code_list + 3 * (uint(language));
621 
622  QString code(c[2] == 0 ? 2 : 3, Qt::Uninitialized);
623 
624  code[0] = ushort(c[0]);
625  code[1] = ushort(c[1]);
626  if (c[2] != 0) {
627  code[2] = ushort(c[2]);
628  }
629 
630  return code;
631 }
632 
633 static QString countryToCode(QLocale::Country country)
634 {
635  if (country == QLocale::AnyCountry) {
636  return QString();
637  }
638 
639  const unsigned char *c = country_code_list + 3 * (uint(country));
640 
641  QString code(c[2] == 0 ? 2 : 3, Qt::Uninitialized);
642 
643  code[0] = ushort(c[0]);
644  code[1] = ushort(c[1]);
645  if (c[2] != 0) {
646  code[2] = ushort(c[2]);
647  }
648 
649  return code;
650 }
651 
652 static QLocale::Country codeToCountry(const QString &code)
653 {
654  int len = code.length();
655  if (len != 2 && len != 3) {
656  return QLocale::AnyCountry;
657  }
658  ushort uc1 = len-- > 0 ? code[0].toUpper().unicode() : 0;
659  ushort uc2 = len-- > 0 ? code[1].toUpper().unicode() : 0;
660  ushort uc3 = len-- > 0 ? code[2].toUpper().unicode() : 0;
661 
662  const unsigned char *c = country_code_list;
663  for (; *c != 0; c += 3) {
664  if (uc1 == c[0] && uc2 == c[1] && uc3 == c[2]) {
665  return QLocale::Country((c - country_code_list) / 3);
666  }
667  }
668 
669  return QLocale::AnyCountry;
670 }
671 
672 #if 0
673 static QLocale::Language codeToLanguage(const QString &code)
674 {
675  int len = code.length();
676  if (len != 2 && len != 3) {
677  return QLocale::C;
678  }
679  ushort uc1 = len-- > 0 ? code[0].toLower().unicode() : 0;
680  ushort uc2 = len-- > 0 ? code[1].toLower().unicode() : 0;
681  ushort uc3 = len-- > 0 ? code[2].toLower().unicode() : 0;
682 
683  const unsigned char *c = language_code_list;
684  for (; *c != 0; c += 3) {
685  if (uc1 == c[0] && uc2 == c[1] && uc3 == c[2]) {
686  return QLocale::Language((c - language_code_list) / 3);
687  }
688  }
689 
690  // legacy codes
691  if (uc1 == 'n' && uc2 == 'o' && uc3 == 0) { // no -> nb
692  Q_STATIC_ASSERT(QLocale::Norwegian == QLocale::NorwegianBokmal);
693  return QLocale::Norwegian;
694  }
695  if (uc1 == 't' && uc2 == 'l' && uc3 == 0) { // tl -> fil
696  Q_STATIC_ASSERT(QLocale::Tagalog == QLocale::Filipino);
697  return QLocale::Tagalog;
698  }
699  if (uc1 == 's' && uc2 == 'h' && uc3 == 0) { // sh -> sr[_Latn]
700  Q_STATIC_ASSERT(QLocale::SerboCroatian == QLocale::Serbian);
701  return QLocale::SerboCroatian;
702  }
703  if (uc1 == 'm' && uc2 == 'o' && uc3 == 0) { // mo -> ro
704  Q_STATIC_ASSERT(QLocale::Moldavian == QLocale::Romanian);
705  return QLocale::Moldavian;
706  }
707 
708  return QLocale::C;
709 }
710 #endif
711 // End Qt copied code
712 
713 static void initResources()
714 {
715  static bool initDone = false;
716  if (!initDone) {
717  Q_INIT_RESOURCE(holidays);
718  initDone = true;
719  }
720 }
721 
722 static QStringList allHolidayFiles(const QString &location = QString())
723 {
724  initResources();
725  QStringList dirs{ QStringLiteral(":/org.kde.kholidays/plan2") };
727  QStringLiteral("kf5/libkholidays/plan2"),
729  QStringList files;
730  for (const QString &dir : qAsConst(dirs)) {
731  QDirIterator it(dir, QStringList() << QStringLiteral("holiday_") + location + '*');
732  while (it.hasNext()) {
733  files.push_back(it.next());
734  }
735  }
736  return files;
737 }
738 
739 class Q_DECL_HIDDEN HolidayRegion::HolidayRegionPrivate
740 {
741 public:
742  explicit HolidayRegionPrivate(const QString &regionCode) : mDriver(nullptr),
743  mRegionCode(regionCode)
744  {
745  if (!mRegionCode.isEmpty()) {
747  QLatin1String("kf5/libkholidays/plan2/holiday_") + mRegionCode);
748  if (!file.isEmpty()) {
749  mHolidayFile.setFile(file);
750  } else {
751  initResources();
752  file = QStringLiteral(":/org.kde.kholidays/plan2/holiday_") + mRegionCode;
753  if (QFile::exists(file)) {
754  mHolidayFile.setFile(file);
755  }
756  }
757  }
758 
759  init();
760  }
761 
762  explicit HolidayRegionPrivate(const QFileInfo &regionFile) : mDriver(nullptr),
763  mHolidayFile(regionFile)
764  {
765  init();
766  }
767 
768  ~HolidayRegionPrivate()
769  {
770  delete mDriver;
771  }
772 
773  void init()
774  {
775  if (mHolidayFile.exists()) {
776  mDriver = new HolidayParserDriverPlan(mHolidayFile.absoluteFilePath());
777  if (mDriver) {
778 
779  if (mRegionCode.isEmpty()) {
780  if (mHolidayFile.fileName().startsWith(QLatin1String("holiday_"))) {
781  mRegionCode = mHolidayFile.fileName().mid(8);
782  } else {
783  mRegionCode = mHolidayFile.fileName();
784  }
785  }
786 
787  } else {
788  mRegionCode.clear();
789  }
790  } else {
791  mRegionCode.clear();
792  }
793  }
794 
795  HolidayParserDriver *mDriver; // The parser driver for the holiday file
796  QString mRegionCode; // region code of holiday region
797  QFileInfo mHolidayFile; // file containing holiday data, or null
798 };
799 
801  : d(new HolidayRegionPrivate(regionCode))
802 {
803 }
804 
806  : d(new HolidayRegionPrivate(regionFile))
807 {
808 }
809 
811 {
812  delete d;
813 }
814 
816 {
817  const QStringList files = allHolidayFiles();
818 
819  QStringList regionCodesList;
820  regionCodesList.reserve(files.count());
821  for (const QString &filename : files) {
822  regionCodesList.append(filename.mid(filename.lastIndexOf(QLatin1String("holiday_")) + 8));
823  }
824 
825  std::sort(regionCodesList.begin(), regionCodesList.end());
826  return regionCodesList;
827 }
828 
830 {
831  return d->mRegionCode;
832 }
833 
835 {
836  return d->mDriver->fileCountryCode();
837 }
838 
840 {
841  HolidayRegion temp(regionCode);
842  if (temp.isValid()) {
843  return temp.countryCode();
844  } else {
845  return QString();
846  }
847 }
848 
850 {
851  return d->mDriver->fileLanguageCode();
852 }
853 
855 {
856  HolidayRegion temp(regionCode);
857  if (temp.isValid()) {
858  return temp.languageCode();
859  } else {
860  return QString();
861  }
862 }
863 
865 {
866  QString tempName = d->mDriver->fileName();
867 
868  if (tempName.isEmpty()) {
869  QStringList countryParts = countryCode().toLower().split(QLatin1Char('-'));
870  const QString &country = countryParts.at(0);
871  QString regionName, typeName;
872 
873  if (country != QLatin1String("xx")) {
874  if (countryParts.count() == 2) {
875  // Temporary measure to get regions translated, only those files that already exist
876  // In 4.6 hope to have isocodes project integration for translations via KLocale
877  const QString &subdivision = countryParts.at(1);
878  if (country == QLatin1String("ca") && subdivision == QLatin1String("qc")) {
879  regionName = QCoreApplication::translate("HolidayRegion", "Quebec", "Canadian region");
880  } else if (country == QLatin1String("de")) {
881  if (subdivision == QLatin1String("by")) {
882  regionName = QCoreApplication::translate("HolidayRegion", "Germany, Bavaria", "German region");
883  } else if (subdivision == QLatin1String("bb")) {
884  regionName = QCoreApplication::translate("HolidayRegion", "Germany, Brandenburg", "German region");
885  } else if (subdivision == QLatin1String("be")) {
886  regionName = QCoreApplication::translate("HolidayRegion", "Germany, Berlin", "German region");
887  } else if (subdivision == QLatin1String("bw")) {
888  regionName = QCoreApplication::translate("HolidayRegion", "Germany, Baden-Wuerttemberg", "German region");
889  } else if (subdivision == QLatin1String("he")) {
890  regionName = QCoreApplication::translate("HolidayRegion", "Germany, Hesse", "German region");
891  } else if (subdivision == QLatin1String("mv")) {
892  regionName = QCoreApplication::translate("HolidayRegion", "Germany, Mecklenburg-Hither Pomerania", "German region");
893  } else if (subdivision == QLatin1String("ni")) {
894  regionName = QCoreApplication::translate("HolidayRegion", "Germany, Lower Saxony", "German region");
895  } else if (subdivision == QLatin1String("nw")) {
896  regionName = QCoreApplication::translate("HolidayRegion", "Germany, North Rhine-Westphalia", "German region");
897  } else if (subdivision == QLatin1String("rp")) {
898  regionName = QCoreApplication::translate("HolidayRegion", "Germany, Rhineland-Palatinate", "German region");
899  } else if (subdivision == QLatin1String("sh")) {
900  regionName = QCoreApplication::translate("HolidayRegion", "Germany, Schleswig-Holstein", "German region");
901  } else if (subdivision == QLatin1String("sl")) {
902  regionName = QCoreApplication::translate("HolidayRegion", "Germany, Saarland", "German region");
903  } else if (subdivision == QLatin1String("sn")) {
904  regionName = QCoreApplication::translate("HolidayRegion", "Germany, Saxony", "German region");
905  } else if (subdivision == QLatin1String("st")) {
906  regionName = QCoreApplication::translate("HolidayRegion", "Germany, Saxony-Anhalt", "German region");
907  } else if (subdivision == QLatin1String("th")) {
908  regionName = QCoreApplication::translate("HolidayRegion", "Germany, Thuringia", "German region");
909  }
910  } else if (country == QLatin1String("es") && subdivision == QLatin1String("ct")) {
911  regionName = QCoreApplication::translate("HolidayRegion", "Catalonia", "Spanish region");
912  } else if (country == QLatin1String("gb") && subdivision == QLatin1String("eaw")) {
913  regionName = QCoreApplication::translate("HolidayRegion", "England and Wales", "UK Region");
914  } else if (country == QLatin1String("gb") && subdivision == QLatin1String("eng")) {
915  regionName = QCoreApplication::translate("HolidayRegion", "England", "UK Region");
916  } else if (country == QLatin1String("gb") && subdivision == QLatin1String("wls")) {
917  regionName = QCoreApplication::translate("HolidayRegion", "Wales", "UK Region");
918  } else if (country == QLatin1String("gb") && subdivision == QLatin1String("sct")) {
919  regionName = QCoreApplication::translate("HolidayRegion", "Scotland", "UK Region");
920  } else if (country == QLatin1String("gb") && subdivision == QLatin1String("nir")) {
921  regionName = QCoreApplication::translate("HolidayRegion", "Northern Ireland", "UK Region");
922  } else if (country == QLatin1String("it") && subdivision == QLatin1String("bz")) {
923  regionName = QCoreApplication::translate("HolidayRegion", "South Tyrol", "Italian Region");
924  } else if (country == QLatin1String("au") && subdivision == QLatin1String("nsw")) {
925  regionName = QCoreApplication::translate("HolidayRegion", "New South Wales");
926  } else if (country == QLatin1String("au") && subdivision == QLatin1String("qld")) {
927  regionName = QCoreApplication::translate("HolidayRegion", "Queensland", "Australian Region");
928  } else if (country == QLatin1String("au") && subdivision == QLatin1String("vic")) {
929  regionName = QCoreApplication::translate("HolidayRegion", "Victoria", "Australian Region");
930  } else if (country == QLatin1String("au") && subdivision == QLatin1String("sa")) {
931  regionName = QCoreApplication::translate("HolidayRegion", "South Australia", "Australian Region");
932  } else if (country == QLatin1String("au") && subdivision == QLatin1String("nt")) {
933  regionName = QCoreApplication::translate("HolidayRegion",
934  "Northern Territory", "Australian Region");
935  } else if (country == QLatin1String("au") && subdivision == QLatin1String("act")) {
936  regionName = QCoreApplication::translate("HolidayRegion",
937  "Australian Capital Territory", "Australian Region");
938  } else if (country == QLatin1String("au") && subdivision == QLatin1String("wa")) {
939  regionName = QCoreApplication::translate("HolidayRegion",
940  "Western Australia", "Australian Region");
941  } else if (country == QLatin1String("au") && subdivision == QLatin1String("tas")) {
942  regionName = QCoreApplication::translate("HolidayRegion",
943  "Tasmania", "Australian Region");
944  } else if (country == QLatin1String("ba") && subdivision == QLatin1String("srp")) {
945  regionName = QCoreApplication::translate("HolidayRegion",
946  "Republic of Srpska", "Bosnian and Herzegovinian Region");
947  } else {
948  // TODO Note this does not give the current QLocale translation!
949  regionName = QLocale::countryToString(codeToCountry(country)) + QLatin1String(" (") + subdivision + QLatin1Char(')');
950  }
951  } else {
952  // TODO Note this does not give the current QLocale translation!
953  regionName = QLocale::countryToString(codeToCountry(country));
954  }
955  }
956 
957  //Cheat on type for now,take direct from region code until API is introduced in SC 4.6
958  QStringList regionParts = regionCode().toLower().split(QLatin1Char('_'));
959  if (regionParts.count() == 3) {
960  const QString &type = regionParts.at(2);
961  // Will create lots more in 4.6
962  // Religious types, just simple for now
963  if (type == QLatin1String("public")) {
964  typeName = QCoreApplication::translate("HolidayRegion", "Public", "Holiday type");
965  } else if (type == QLatin1String("civil")) {
966  typeName = QCoreApplication::translate("HolidayRegion", "Civil", "Holiday type");
967  } else if (type == QLatin1String("religious")) {
968  typeName = QCoreApplication::translate("HolidayRegion", "Religious", "Holiday type");
969  } else if (type == QLatin1String("government")) {
970  typeName = QCoreApplication::translate("HolidayRegion", "Government", "Holiday type");
971  } else if (type == QLatin1String("financial")) {
972  typeName = QCoreApplication::translate("HolidayRegion", "Financial", "Holiday type");
973  } else if (type == QLatin1String("cultural")) {
974  typeName = QCoreApplication::translate("HolidayRegion", "Cultural", "Holiday type");
975  } else if (type == QLatin1String("commemorative")) {
976  typeName = QCoreApplication::translate("HolidayRegion", "Commemorative", "Holiday type");
977  } else if (type == QLatin1String("historical")) {
978  typeName = QCoreApplication::translate("HolidayRegion", "Historical", "Holiday type");
979  } else if (type == QLatin1String("school")) {
980  typeName = QCoreApplication::translate("HolidayRegion", "School", "Holiday type");
981  } else if (type == QLatin1String("seasonal")) {
982  typeName = QCoreApplication::translate("HolidayRegion", "Seasonal", "Holiday type");
983  } else if (type == QLatin1String("nameday")) {
984  typeName = QCoreApplication::translate("HolidayRegion", "Name Days", "Holiday type");
985  } else if (type == QLatin1String("personal")) {
986  typeName = QCoreApplication::translate("HolidayRegion", "Personal", "Holiday type");
987  } else if (type == QLatin1String("christian")) {
988  typeName = QCoreApplication::translate("HolidayRegion", "Christian", "Holiday type");
989  } else if (type == QLatin1String("anglican")) {
990  typeName = QCoreApplication::translate("HolidayRegion", "Anglican", "Holiday type");
991  } else if (type == QLatin1String("catholic")) {
992  typeName = QCoreApplication::translate("HolidayRegion", "Catholic", "Holiday type");
993  } else if (type == QLatin1String("protestant")) {
994  typeName = QCoreApplication::translate("HolidayRegion", "Protestant", "Holiday type");
995  } else if (type == QLatin1String("orthodox")) {
996  typeName = QCoreApplication::translate("HolidayRegion", "Orthodox", "Holiday type");
997  } else if (type == QLatin1String("jewish")) {
998  typeName = QCoreApplication::translate("HolidayRegion", "Jewish", "Holiday type");
999  } else if (type == QLatin1String("jewish-orthodox")) {
1000  typeName = QCoreApplication::translate("HolidayRegion", "Jewish Orthodox", "Holiday type");
1001  } else if (type == QLatin1String("jewish-conservative")) {
1002  typeName = QCoreApplication::translate("HolidayRegion", "Jewish Conservative", "Holiday type");
1003  } else if (type == QLatin1String("jewish-reform")) {
1004  typeName = QCoreApplication::translate("HolidayRegion", "Jewish Reform", "Holiday type");
1005  } else if (type == QLatin1String("islamic")) {
1006  typeName = QCoreApplication::translate("HolidayRegion", "Islamic", "Holiday type");
1007  } else if (type == QLatin1String("islamic-sunni")) {
1008  typeName = QCoreApplication::translate("HolidayRegion", "Islamic Sunni", "Holiday type");
1009  } else if (type == QLatin1String("islamic-shia")) {
1010  typeName = QCoreApplication::translate("HolidayRegion", "Islamic Shia", "Holiday type");
1011  } else if (type == QLatin1String("islamic-sufi")) {
1012  typeName = QCoreApplication::translate("HolidayRegion", "Islamic Sufi", "Holiday type");
1013  }
1014  }
1015 
1016  if (!regionName.isEmpty()) {
1017  if (!typeName.isEmpty()) {
1018  tempName =
1020  "HolidayRegion",
1021  "%1 - %2",
1022  "Holiday file display name, %1 = region name, %2 = holiday type").arg(regionName, typeName);
1023  } else {
1024  tempName = regionName;
1025  }
1026  } else if (!typeName.isEmpty()) {
1027  tempName = typeName;
1028  } else {
1029  tempName = QCoreApplication::translate("HolidayRegion", "Unknown", "Unknown holiday region");
1030  }
1031  }
1032  return tempName;
1033 }
1034 
1036 {
1037  HolidayRegion temp(regionCode);
1038  if (temp.isValid()) {
1039  return temp.name();
1040  } else {
1041  return QString();
1042  }
1043 }
1044 
1046 {
1047  return d->mDriver->fileDescription();
1048 }
1049 
1051 {
1052  HolidayRegion temp(regionCode);
1053  if (temp.isValid()) {
1054  return temp.description();
1055  } else {
1056  return QString();
1057  }
1058 }
1059 
1061 {
1062  return d->mHolidayFile.exists() && d->mDriver;
1063 }
1064 
1065 bool HolidayRegion::isValid(const QString &regionCode)
1066 {
1067  HolidayRegion temp(regionCode);
1068  return temp.isValid();
1069 }
1070 
1071 Holiday::List HolidayRegion::holidays(const QDate &startDate, const QDate &endDate) const
1072 {
1073  if (isValid()) {
1074  return d->mDriver->parseHolidays(startDate, endDate);
1075  } else {
1076  return Holiday::List();
1077  }
1078 }
1079 
1081 {
1082  if (isValid()) {
1083  return d->mDriver->parseHolidays(date);
1084  } else {
1085  return Holiday::List();
1086  }
1087 }
1088 
1090 {
1091  if (isValid()) {
1092  return d->mDriver->parseHolidays(calendarYear);
1093  } else {
1094  return Holiday::List();
1095  }
1096 }
1097 
1098 bool HolidayRegion::isHoliday(const QDate &date) const
1099 {
1100  const Holiday::List holidayList = holidays(date);
1101  if (!holidayList.isEmpty()) {
1102  for (const KHolidays::Holiday &holiday : holidayList) {
1103  if (holiday.dayType() == Holiday::NonWorkday) {
1104  return true;
1105  }
1106  }
1107  }
1108  return false;
1109 }
1110 
1112 {
1113  // Try to match against the users country and language, or failing that the language country.
1114  // Scan through all the regions finding the first match for each possible default
1115  // Holiday Region Country Code can be a country subdivision or the country itself,
1116  // e.g. US or US-CA for California, so we can try match on both but an exact match has priority
1117  // The Holiday Region file is in one language only, so give priority to any file in the
1118  // users language, e.g. bilingual countries with a separate file for each language
1119  // Locale language can have a country code embedded in it e.g. en_GB, which we can try use if
1120  // no country set, but a lot of countries use en_GB so it's a lower priority option
1121 
1122  QString localeCountry, localeLanguage, localeLanguageCountry;
1123 
1124  if (country.isEmpty()) {
1125  localeCountry = countryToCode(QLocale().country()).toLower();
1126  } else {
1127  localeCountry = country.toLower();
1128  }
1129 
1130  if (language.isEmpty()) {
1131  localeLanguage = languageToCode(QLocale().language()).toLower();
1132  } else {
1133  localeLanguage = language.toLower();
1134  }
1135 
1136  if (localeLanguage.split(QLatin1Char('_')).count() > 1) {
1137  localeLanguageCountry = localeLanguage.split(QLatin1Char('_')).at(1);
1138  }
1139 
1140  QString countryAndLanguageMatch, countryOnlyMatch, subdivisionAndLanguageMatch,
1141  subdivisionOnlyMatch, languageCountryAndLanguageMatch, languageCountryOnlyMatch,
1142  languageSubdivisionAndLanguageMatch, languageSubdivisionOnlyMatch;
1143 
1145  for (const QString &regionCode : regionList) {
1146  QString regionCountry = KHolidays::HolidayRegion::countryCode(regionCode).toLower();
1147  QString regionSubdivisionCountry;
1148  if (regionCountry.split(QLatin1Char('-')).count() > 1) {
1149  regionSubdivisionCountry = regionCountry.split(QLatin1Char('-')).at(0);
1150  }
1151  QString regionLanguage = KHolidays::HolidayRegion::languageCode(regionCode).toLower();
1152 
1153  if (regionCountry == localeCountry && regionLanguage == localeLanguage) {
1154  countryAndLanguageMatch = regionCode;
1155  break; // exact match so don't look further
1156  } else if (regionCountry == localeCountry) {
1157  if (countryOnlyMatch.isEmpty()) {
1158  countryOnlyMatch = regionCode;
1159  }
1160  } else if (!regionSubdivisionCountry.isEmpty() &&
1161  regionSubdivisionCountry == localeCountry &&
1162  regionLanguage == localeLanguage) {
1163  if (subdivisionAndLanguageMatch.isEmpty()) {
1164  subdivisionAndLanguageMatch = regionCode;
1165  }
1166  } else if (!regionSubdivisionCountry.isEmpty() && regionSubdivisionCountry == localeCountry) {
1167  if (subdivisionOnlyMatch.isEmpty()) {
1168  subdivisionOnlyMatch = regionCode;
1169  }
1170  } else if (!localeLanguageCountry.isEmpty() &&
1171  regionCountry == localeLanguageCountry &&
1172  regionLanguage == localeLanguage) {
1173  if (languageCountryAndLanguageMatch.isEmpty()) {
1174  languageCountryAndLanguageMatch = regionCode;
1175  }
1176  } else if (!localeLanguageCountry.isEmpty() && regionCountry == localeLanguageCountry) {
1177  if (languageCountryOnlyMatch.isEmpty()) {
1178  languageCountryOnlyMatch = regionCode;
1179  }
1180  } else if (!regionSubdivisionCountry.isEmpty() &&
1181  !localeLanguageCountry.isEmpty() &&
1182  regionSubdivisionCountry == localeLanguageCountry &&
1183  regionLanguage == localeLanguage) {
1184  if (languageSubdivisionAndLanguageMatch.isEmpty()) {
1185  languageSubdivisionAndLanguageMatch = regionCode;
1186  }
1187  } else if (!regionSubdivisionCountry.isEmpty() &&
1188  !localeLanguageCountry.isEmpty() &&
1189  regionSubdivisionCountry == localeLanguageCountry) {
1190  if (languageSubdivisionOnlyMatch.isEmpty()) {
1191  languageSubdivisionOnlyMatch = regionCode;
1192  }
1193  }
1194  }
1195 
1197 
1198  if (!countryAndLanguageMatch.isEmpty()) {
1199  defaultRegionCode = countryAndLanguageMatch;
1200  } else if (!countryOnlyMatch.isEmpty()) {
1201  defaultRegionCode = countryOnlyMatch;
1202  } else if (!subdivisionAndLanguageMatch.isEmpty()) {
1203  defaultRegionCode = subdivisionAndLanguageMatch;
1204  } else if (!subdivisionOnlyMatch.isEmpty()) {
1205  defaultRegionCode = subdivisionOnlyMatch;
1206  } else if (!languageCountryAndLanguageMatch.isEmpty()) {
1207  defaultRegionCode = languageCountryAndLanguageMatch;
1208  } else if (!languageCountryOnlyMatch.isEmpty()) {
1209  defaultRegionCode = languageCountryOnlyMatch;
1210  } else if (!languageSubdivisionAndLanguageMatch.isEmpty()) {
1211  defaultRegionCode = languageSubdivisionAndLanguageMatch;
1212  } else if (!languageSubdivisionOnlyMatch.isEmpty()) {
1213  defaultRegionCode = languageSubdivisionOnlyMatch;
1214  }
1215 
1216  return defaultRegionCode;
1217 }
QString toUpper() const const
Represents a holiday region.
Definition: holidayregion.h:30
bool isHoliday(const QDate &date) const
Checks whether there is any holiday defined for a date.
QStringList locateAll(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
void push_back(const T &value)
QString languageCode() const
The holiday is a real holiday.
Definition: holiday.h:49
void reserve(int alloc)
const T & at(int i) const const
QString translate(const char *context, const char *sourceText, const char *disambiguation, int n)
static QString defaultRegionCode(const QString &country=QString(), const QString &language=QString())
bool exists() const const
Holiday::List holidays(const QDate &startDate, const QDate &endDate) const
static QStringList regionCodes()
int count(const T &value) const const
void append(const T &value)
QList< Holiday > List
A list of holiday descriptions.
Definition: holiday.h:41
bool isValid() const
Returns whether the instance contains any holiday data.
QString regionCode() const
bool isEmpty() const const
bool isEmpty() const const
~HolidayRegion()
Destroys the holidays object.
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString description() const
QString countryCode() const
QList::iterator end()
QString toLower() const const
QCA_EXPORT void init()
const QChar * unicode() const const
Represents a holiday event.
Definition: holiday.h:30
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
int length() const const
QString countryToString(QLocale::Country country)
HolidayRegion(const QString &regionCode=QString())
Creates a new Holiday Region object for a given standard Region Code.
QList::iterator begin()
QString locate(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
KStandardDirs * dirs()
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Tue Oct 20 2020 23:02:56 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.