33 #include "holidayparserdriverplan_p.h"
34 #include "holidayscannerplan_p.h"
35 #include "holidayparserplan.hpp"
43 #include "holiday_p.h"
50 using namespace KHolidays;
54 m_traceParsing( false ),
55 m_traceScanning( false ),
56 m_parseMetadataOnly( false )
58 QFile holidayFile( filePath() );
59 if ( holidayFile.open( QIODevice::ReadOnly ) ) {
60 m_scanData = holidayFile.readAll();
64 m_scanner->set_debug( m_traceScanning );
79 Q_UNUSED( errorLocation );
82 kDebug() << errorMessage;
87 kDebug() << errorMessage;
94 foreach (
const QString &calendar, m_fileCalendarTypes ) {
102 for ( m_parseYear = m_parseStartYear; m_parseYear <= m_parseEndYear; ++m_parseYear ) {
104 m_parseCalendar->setDate( m_parseYearStart, m_parseYear, 1, 1 );
105 m_parseYearEaster = easter( m_parseYear );
106 m_parseYearPascha = pascha( m_parseYear );
108 std::istringstream iss2( std::string( m_scanData.data() ) );
109 m_scanner->yyrestart( &iss2 );
119 m_parseMetadataOnly =
true;
120 m_fileCountryCode.clear();
121 m_fileLanguageCode.clear();
123 m_fileDescription.clear();
124 m_fileCalendarTypes.clear();
125 m_fileCalendarTypes.append(
"gregorian" );
129 m_parseYear = QDate::currentDate().year();
130 std::istringstream iss2( std::string( m_scanData.data() ) );
131 m_scanner->yyrestart( &iss2 );
133 m_resultList.clear();
138 QFileInfo file( m_filePath );
139 if ( file.exists() ) {
140 QStringList metadata = file.fileName().split(
'_' );
141 if ( metadata[0] ==
"holiday" && metadata.count() > 2 ) {
142 if ( m_fileCountryCode.isEmpty() ) {
143 setFileCountryCode( metadata[1].toUpper() );
145 if ( m_fileLanguageCode.isEmpty() ) {
146 QStringList language = metadata[2].split(
'-' );
147 m_fileLanguageCode = language[0];
148 if ( language.count() > 1 ) {
149 setFileLanguageCode( language[0].append(
'_' ).append( language[1].toUpper() ) );
151 setFileLanguageCode( language[0] );
154 if ( m_fileLanguageCode.isEmpty() && metadata.count() > 3 ) {
155 m_fileName = metadata[3];
160 m_parseMetadataOnly =
false;
163 QString HolidayParserDriverPlan::filePath()
174 int HolidayParserDriverPlan::adjustedMonthNumber(
int month )
176 if ( m_eventCalendarType !=
"hebrew" ||
177 m_parseCalendar->calendarType() !=
"hebrew" ||
178 !m_parseCalendar->isLeapYear( m_parseYear ) ||
194 bool HolidayParserDriverPlan::isLeapYear(
int year )
196 return m_parseCalendar->isLeapYear( year );
199 int HolidayParserDriverPlan::parseYear()
204 int HolidayParserDriverPlan::monthsInYear(
int year )
207 m_parseCalendar->setDate( tempDate, year, 1, 1 );
208 return m_parseCalendar->monthsInYear( tempDate );
211 int HolidayParserDriverPlan::daysInMonth(
int year,
int month )
214 m_parseCalendar->setDate( tempDate, year, month, 1 );
215 return m_parseCalendar->daysInMonth( tempDate );
218 int HolidayParserDriverPlan::julianDay(
int year,
int month,
int day )
221 m_parseCalendar->setDate( tempDate, year, month, day );
222 return tempDate.toJulianDay();
225 void HolidayParserDriverPlan::julianDayToDate(
int jd,
int *year,
int *month,
int *day )
227 QDate tempDate = QDate::fromJulianDay( jd );
230 *year = m_parseCalendar->year( tempDate );
233 *month = m_parseCalendar->month( tempDate );
236 *day = m_parseCalendar->day( tempDate );
240 QDate HolidayParserDriverPlan::easter(
int year )
242 if ( m_parseCalendar->calendarType() !=
"gregorian" ) {
250 int h = ( c - ( c / 4 ) - ( ( ( 8 * c ) + 13 ) / 25 ) + ( 19 * g ) + 15 ) % 30;
251 int i = h - ( ( h / 28 ) * ( 1 - ( ( 29 / ( h + 1 ) ) * ( ( 21 - g ) / 11 ) ) ) );
252 int j = ( year + ( year / 4 ) + i + 2 - c + ( c / 4 ) ) % 7;
254 int month = 3 + ( ( l + 40 ) / 44 );
255 int day = l + 28 - ( 31 * ( month / 4 ) );
257 return QDate::fromJulianDay( julianDay( year, month, day ) );
261 QDate HolidayParserDriverPlan::pascha(
int year )
263 if ( m_parseCalendar->calendarType() ==
"gregorian" ||
264 m_parseCalendar->calendarType() ==
"julian" ) {
269 int i = ( ( 19 * g ) + 15 ) % 30;
270 int j = ( year + ( year / 4 ) + i ) % 7;
272 int month = 3 + ( ( l + 40 ) / 44 );
273 int day = l + 28 - ( 31 * ( month / 4 ) );
275 if ( m_parseCalendar->calendarType() ==
"julian" ) {
276 return QDate::fromJulianDay( julianDay( year, month, day ) );
279 if ( m_parseCalendar->calendarType() ==
"gregorian" ) {
281 int paschaJd = julianDay( year, month, day );
283 return QDate::fromJulianDay( paschaJd );
296 int HolidayParserDriverPlan::julianDayFromEventName(
const QString &eventName )
298 foreach (
const KHolidays::Holiday &thisHoliday, m_resultList ) {
299 if ( thisHoliday.text() == eventName ) {
300 return thisHoliday.date().toJulianDay();
307 int HolidayParserDriverPlan::julianDayFromEaster(
void )
309 if ( m_eventCalendarType ==
"gregorian" ) {
310 return m_parseYearEaster.toJulianDay();
312 error(
"Can only use Easter in Gregorian event rule" );
318 int HolidayParserDriverPlan::julianDayFromPascha(
void )
320 if ( m_eventCalendarType ==
"gregorian" || m_eventCalendarType ==
"julian" ) {
321 return m_parseYearPascha.toJulianDay();
323 error(
"Can only use Easter in Gregorian or Julian event rule" );
329 int HolidayParserDriverPlan::julianDayFromMonthDay(
int month,
int day ) {
330 return julianDay( m_parseYear, month, day );
334 int HolidayParserDriverPlan::julianDayFromRelativeWeekday(
int occurrence,
int weekday,
int jd )
336 if ( occurrence == ANY ) {
340 int thisWeekday = m_parseCalendar->dayOfWeek( QDate::fromJulianDay( jd ) );
344 if ( occurrence > 0 ) {
345 occurrence = occurrence - 1;
346 }
else if ( occurrence < 0 && weekday == thisWeekday ) {
347 occurrence = occurrence + 1;
350 if ( weekday < thisWeekday ) {
351 occurrence = occurrence + 1;
354 return jd + weekday - thisWeekday + ( occurrence * 7 );
358 int HolidayParserDriverPlan::julianDayFromWeekdayInMonth(
int occurrence,
int weekday,
int month )
360 if ( occurrence == LAST ) {
361 return julianDayFromRelativeWeekday( BEFORE, weekday, julianDay( m_parseYear, month, daysInMonth( m_parseYear, month ) ) );
363 return julianDayFromRelativeWeekday( occurrence, weekday, julianDay( m_parseYear, month, 1 ) );
372 void HolidayParserDriverPlan::setFileCountryCode(
const QString &countryCode )
374 m_fileCountryCode = countryCode;
377 void HolidayParserDriverPlan::setFileLanguageCode(
const QString &languageCode )
379 m_fileLanguageCode = languageCode;
382 void HolidayParserDriverPlan::setFileName(
const QString &name )
387 void HolidayParserDriverPlan::setFileDescription(
const QString &description )
389 m_fileDescription = description;
392 void HolidayParserDriverPlan::setEventName(
const QString &eventName )
394 m_eventName = eventName;
397 void HolidayParserDriverPlan::setEventColorName(
int nameColor )
399 m_eventColorName = nameColor;
402 void HolidayParserDriverPlan::setEventColorDay(
int dayColor )
404 m_eventColorDay = dayColor;
407 void HolidayParserDriverPlan::setEventCalendarType(
const QString &calendarType )
409 m_eventCalendarType = calendarType;
410 if ( m_parseMetadataOnly && !m_fileCalendarTypes.contains( calendarType ) ) {
411 m_fileCalendarTypes.append( calendarType );
415 void HolidayParserDriverPlan::setEventDate(
int eventYear,
int eventMonth,
int eventDay )
417 m_eventYear = eventYear;
418 m_eventMonth = eventMonth;
419 m_eventDay = eventDay;
422 void HolidayParserDriverPlan::setEventDate(
int jd )
424 julianDayToDate( jd, &m_eventYear, &m_eventMonth, &m_eventDay );
437 void HolidayParserDriverPlan::setFromWeekdayInMonth(
int occurrence,
int weekday,
int month,
int offset,
int duration )
440 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
444 int startMonth, endMonth;
445 if ( month == LAST ) {
446 startMonth = monthsInYear( m_parseYear );
447 endMonth = startMonth;
448 }
else if ( month == ANY ) {
450 endMonth = monthsInYear( m_parseYear );
457 for (
int thisMonth = startMonth; thisMonth <= endMonth; ++thisMonth ) {
459 if ( m_parseCalendar->isValid( m_parseYear, thisMonth, 1 ) ) {
460 int startOccurrence, endOccurrence;
461 if ( occurrence == ANY ) {
465 startOccurrence = occurrence;
466 endOccurrence = occurrence;
469 int jdMonthStart = julianDay( m_parseYear, thisMonth, 1 );
470 int jdMonthEnd = julianDay( m_parseYear, thisMonth, daysInMonth( m_parseYear, thisMonth ) );
473 for (
int thisOccurrence = startOccurrence; thisOccurrence <= endOccurrence; ++thisOccurrence ) {
474 int thisJd = julianDayFromWeekdayInMonth( thisOccurrence, weekday, thisMonth );
475 if ( thisJd >= jdMonthStart && thisJd <= jdMonthEnd ) {
476 setEvent( thisJd + offset, 0, duration );
490 void HolidayParserDriverPlan::setFromRelativeWeekday(
int occurrence,
int weekday,
int offset,
int duration )
493 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
498 if ( m_eventYear == ANY ) {
499 thisYear = m_parseYear;
501 thisYear = m_eventYear;
504 int startMonth, endMonth;
505 if ( m_eventMonth == LAST ) {
506 startMonth = monthsInYear( thisYear );
507 endMonth = startMonth;
508 }
else if ( m_eventMonth == ANY ) {
510 endMonth = monthsInYear( thisYear );
512 startMonth = m_eventMonth;
513 endMonth = m_eventMonth;
518 for ( thisMonth = startMonth; thisMonth <= endMonth; ++thisMonth ) {
520 int startDay, endDay;
521 if ( m_eventDay == LAST ) {
522 startDay = daysInMonth( thisYear, thisMonth );
524 }
else if ( m_eventDay == ANY ) {
526 endDay = daysInMonth( thisYear, thisMonth );
528 startDay = m_eventDay;
533 for (
int thisDay = startDay; thisDay <= endDay; ++thisDay ) {
534 if ( m_parseCalendar->isValid( thisYear, thisMonth, thisDay ) ) {
535 int relativeJd = julianDayFromRelativeWeekday( occurrence, weekday, julianDay( thisYear, thisMonth, thisDay ) );
536 setEvent( relativeJd + offset, 0, duration );
544 int HolidayParserDriverPlan::conditionalOffset(
int year,
int month,
int day,
int condition )
554 m_parseCalendar->setDate( tempDate, year, month, day );
555 int weekday = m_parseCalendar->dayOfWeek( tempDate );
557 if ( condition & ( 1 << weekday ) ) {
559 int to = ( condition >> 8 );
560 while ( !( to & ( 1 << ( ( weekday + offset ) % 7 ) ) ) && ( offset < 8 ) ) {
578 void HolidayParserDriverPlan::setFromDate(
int offset,
int condition,
int duration )
581 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
586 if ( m_eventYear == ANY ) {
587 thisYear = m_parseYear;
589 thisYear = m_eventYear;
592 int startMonth, endMonth;
593 if ( m_eventMonth == LAST ) {
594 startMonth = monthsInYear( thisYear );
595 endMonth = startMonth;
596 }
else if ( m_eventMonth == ANY ) {
598 endMonth = monthsInYear( thisYear );
600 startMonth = m_eventMonth;
601 endMonth = m_eventMonth;
605 for (
int thisMonth = startMonth; thisMonth <= endMonth; ++thisMonth ) {
607 int startDay, endDay;
608 if ( m_eventDay == LAST ) {
609 startDay = daysInMonth( thisYear, thisMonth );
611 }
else if ( m_eventDay == ANY ) {
613 endDay = daysInMonth( thisYear, thisMonth );
615 startDay = m_eventDay;
620 for (
int thisDay = startDay; thisDay <= endDay; ++thisDay ) {
622 if ( m_parseCalendar->isValid( thisYear, thisMonth, thisDay ) ) {
623 setEvent( julianDay( thisYear, thisMonth, thisDay ) + offset,
624 conditionalOffset( thisYear, thisMonth, thisDay, condition ), duration );
638 void HolidayParserDriverPlan::setFromEaster(
int offset,
int duration )
641 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
645 if ( m_eventCalendarType ==
"gregorian" ) {
646 setEvent( m_parseYearEaster.toJulianDay() + offset, 0, duration );
648 error(
"Can only use Easter in Gregorian event rule" );
658 void HolidayParserDriverPlan::setFromPascha(
int offset,
int duration )
661 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
665 if ( m_eventCalendarType ==
"gregorian" || m_eventCalendarType ==
"julian" ) {
666 setEvent( m_parseYearPascha.toJulianDay(), offset, duration );
668 error(
"Can only use Pascha in Julian and Gregorian event rule" );
673 void HolidayParserDriverPlan::setEvent(
int jd,
int observeOffset,
int duration )
676 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
681 int observeJd = jd + observeOffset;
683 if ( m_multidayMode == Holiday::MultidayHolidaysAsSingleEvents ) {
684 addHoliday( QDate::fromJulianDay( observeJd ), duration );
687 for (
int dd = 0; dd < duration; ++dd ) {
688 addHoliday( QDate::fromJulianDay( observeJd + dd ), 1 );
693 void HolidayParserDriverPlan::addHoliday(
const QDate &observedDate,
int duration )
696 if ( m_parseCalendar->isValid( observedDate ) &&
697 observedDate <= m_requestEnd &&
698 observedDate.addDays( duration - 1 ) >= m_requestStart ) {
699 KHolidays::Holiday holiday;
700 holiday.d->mObservedDate = observedDate;
701 holiday.d->mDuration = duration;
702 holiday.d->mText = m_eventName;
703 holiday.d->mShortText = m_eventName;
704 if ( m_eventColorName == 2 || m_eventColorName == 9 ||
705 m_eventColorDay == 2 || m_eventColorDay == 9 ) {
706 holiday.d->mDayType = KHolidays::Holiday::NonWorkday;
708 holiday.d->mDayType = KHolidays::Holiday::Workday;
710 m_resultList.append( holiday );