33#include "holidayparserdriverplan_p.h"
34#include "holidayscannerplan_p.h"
35#include "holidayparserplan.hpp"
41#include <KCalendarSystem>
51using namespace KHolidays;
55 m_traceParsing( false ),
56 m_traceScanning( false ),
57 m_parseMetadataOnly( false )
59 QFile holidayFile( filePath() );
60 if ( holidayFile.open( QIODevice::ReadOnly ) ) {
61 m_scanData = holidayFile.readAll();
65 m_scanner->set_debug( m_traceScanning );
67 m_parser->set_debug_level( m_traceParsing );
68 m_fileToParse =
new std::string( filePath().toLocal8Bit().data() );
82 Q_UNUSED( errorLocation );
85 kDebug() << errorMessage;
90 kDebug() << errorMessage;
97 foreach (
const QString &calendar, m_fileCalendarTypes ) {
105 for ( m_parseYear = m_parseStartYear; m_parseYear <= m_parseEndYear; ++m_parseYear ) {
107 m_parseCalendar->setDate( m_parseYearStart, m_parseYear, 1, 1 );
108 m_parseYearEaster = easter( m_parseYear );
109 m_parseYearPascha = pascha( m_parseYear );
111 std::istringstream iss2( std::string( m_scanData.data() ) );
112 m_scanner->yyrestart( &iss2 );
122 m_parseMetadataOnly =
true;
123 m_fileCountryCode.clear();
124 m_fileLanguageCode.clear();
126 m_fileDescription.clear();
127 m_fileCalendarTypes.clear();
128 m_fileCalendarTypes.append( QLatin1String(
"gregorian") );
132 m_parseYear = QDate::currentDate().year();
133 std::istringstream iss2( std::string( m_scanData.data() ) );
134 m_scanner->yyrestart( &iss2 );
136 m_resultList.clear();
141 QFileInfo file( m_filePath );
142 if ( file.exists() ) {
143 QStringList metadata = file.fileName().split( QLatin1Char(
'_') );
144 if ( metadata[0] == QLatin1String(
"holiday") && metadata.count() > 2 ) {
145 if ( m_fileCountryCode.isEmpty() ) {
146 setFileCountryCode( metadata[1].toUpper() );
148 if ( m_fileLanguageCode.isEmpty() ) {
149 QStringList language = metadata[2].split( QLatin1Char(
'-') );
150 m_fileLanguageCode = language[0];
151 if ( language.count() > 1 ) {
152 setFileLanguageCode( language[0].append( QLatin1Char(
'_') ).append( language[1].toUpper() ) );
154 setFileLanguageCode( language[0] );
157 if ( m_fileLanguageCode.isEmpty() && metadata.count() > 3 ) {
158 m_fileName = metadata[3];
163 m_parseMetadataOnly =
false;
166QString HolidayParserDriverPlan::filePath()
171std::string *HolidayParserDriverPlan::fileToParse()
const
173 return m_fileToParse;
181int HolidayParserDriverPlan::adjustedMonthNumber(
int month )
183 if ( m_eventCalendarType != QLatin1String(
"hebrew") ||
184 m_parseCalendar->calendarType() != QLatin1String(
"hebrew") ||
185 !m_parseCalendar->isLeapYear( m_parseYear ) ||
201bool HolidayParserDriverPlan::isLeapYear(
int year )
203 return m_parseCalendar->isLeapYear( year );
206int HolidayParserDriverPlan::parseYear()
211int HolidayParserDriverPlan::monthsInYear(
int year )
214 m_parseCalendar->setDate( tempDate, year, 1, 1 );
215 return m_parseCalendar->monthsInYear( tempDate );
218int HolidayParserDriverPlan::daysInMonth(
int year,
int month )
221 m_parseCalendar->setDate( tempDate, year, month, 1 );
222 return m_parseCalendar->daysInMonth( tempDate );
225int HolidayParserDriverPlan::julianDay(
int year,
int month,
int day )
228 m_parseCalendar->setDate( tempDate, year, month, day );
229 return tempDate.toJulianDay();
232void HolidayParserDriverPlan::julianDayToDate(
int jd,
int *year,
int *month,
int *day )
234 QDate tempDate = QDate::fromJulianDay( jd );
237 *year = m_parseCalendar->year( tempDate );
240 *month = m_parseCalendar->month( tempDate );
243 *day = m_parseCalendar->day( tempDate );
247QDate HolidayParserDriverPlan::easter(
int year )
249 if ( m_parseCalendar->calendarType() != QLatin1String(
"gregorian") ) {
257 int h = ( c - ( c / 4 ) - ( ( ( 8 * c ) + 13 ) / 25 ) + ( 19 * g ) + 15 ) % 30;
258 int i = h - ( ( h / 28 ) * ( 1 - ( ( 29 / ( h + 1 ) ) * ( ( 21 - g ) / 11 ) ) ) );
259 int j = ( year + ( year / 4 ) + i + 2 - c + ( c / 4 ) ) % 7;
261 int month = 3 + ( ( l + 40 ) / 44 );
262 int day = l + 28 - ( 31 * ( month / 4 ) );
264 return QDate::fromJulianDay( julianDay( year, month, day ) );
268QDate HolidayParserDriverPlan::pascha(
int year )
270 if ( m_parseCalendar->calendarType() == QLatin1String(
"gregorian") ||
271 m_parseCalendar->calendarType() == QLatin1String(
"julian") ) {
276 int i = ( ( 19 * g ) + 15 ) % 30;
277 int j = ( year + ( year / 4 ) + i ) % 7;
279 int month = 3 + ( ( l + 40 ) / 44 );
280 int day = l + 28 - ( 31 * ( month / 4 ) );
282 if ( m_parseCalendar->calendarType() == QLatin1String(
"julian") ) {
283 return QDate::fromJulianDay( julianDay( year, month, day ) );
286 if ( m_parseCalendar->calendarType() == QLatin1String(
"gregorian") ) {
288 int paschaJd = julianDay( year, month, day );
290 return QDate::fromJulianDay( paschaJd );
303int HolidayParserDriverPlan::julianDayFromEventName(
const QString &eventName )
305 foreach (
const KHolidays::Holiday &thisHoliday, m_resultList ) {
306 if ( thisHoliday.text() == eventName ) {
307 return thisHoliday.date().toJulianDay();
314int HolidayParserDriverPlan::julianDayFromEaster(
void )
316 if ( m_eventCalendarType == QLatin1String(
"gregorian") ) {
317 return m_parseYearEaster.toJulianDay();
319 error( QLatin1String(
"Can only use Easter in Gregorian event rule") );
325int HolidayParserDriverPlan::julianDayFromPascha(
void )
327 if ( m_eventCalendarType == QLatin1String(
"gregorian") || m_eventCalendarType == QLatin1String(
"julian") ) {
328 return m_parseYearPascha.toJulianDay();
330 error( QLatin1String(
"Can only use Easter in Gregorian or Julian event rule") );
336int HolidayParserDriverPlan::julianDayFromMonthDay(
int month,
int day ) {
337 return julianDay( m_parseYear, month, day );
341int HolidayParserDriverPlan::julianDayFromRelativeWeekday(
int occurrence,
int weekday,
int jd )
343 if ( occurrence == ANY ) {
347 int thisWeekday = m_parseCalendar->dayOfWeek( QDate::fromJulianDay( jd ) );
351 if ( occurrence > 0 ) {
352 occurrence = occurrence - 1;
353 }
else if ( occurrence < 0 && weekday == thisWeekday ) {
354 occurrence = occurrence + 1;
357 if ( weekday < thisWeekday ) {
358 occurrence = occurrence + 1;
361 return jd + weekday - thisWeekday + ( occurrence * 7 );
365int HolidayParserDriverPlan::julianDayFromWeekdayInMonth(
int occurrence,
int weekday,
int month )
367 if ( occurrence == LAST ) {
368 return julianDayFromRelativeWeekday( BEFORE, weekday, julianDay( m_parseYear, month, daysInMonth( m_parseYear, month ) ) );
370 return julianDayFromRelativeWeekday( occurrence, weekday, julianDay( m_parseYear, month, 1 ) );
379void HolidayParserDriverPlan::setFileCountryCode(
const QString &countryCode )
381 m_fileCountryCode = countryCode;
384void HolidayParserDriverPlan::setFileLanguageCode(
const QString &languageCode )
386 m_fileLanguageCode = languageCode;
389void HolidayParserDriverPlan::setFileName(
const QString &name )
394void HolidayParserDriverPlan::setFileDescription(
const QString &description )
396 m_fileDescription = description;
399void HolidayParserDriverPlan::setEventName(
const QString &eventName )
402 m_eventCategories.clear();
403 m_eventName = eventName;
406void HolidayParserDriverPlan::setEventCategory(
const QString &category )
408 m_eventCategories.append( category );
411void HolidayParserDriverPlan::setEventCalendarType(
const QString &calendarType )
413 m_eventCalendarType = calendarType;
414 if ( m_parseMetadataOnly && !m_fileCalendarTypes.contains( calendarType ) ) {
415 m_fileCalendarTypes.append( calendarType );
419void HolidayParserDriverPlan::setEventDate(
int eventYear,
int eventMonth,
int eventDay )
421 m_eventYear = eventYear;
422 m_eventMonth = eventMonth;
423 m_eventDay = eventDay;
426void HolidayParserDriverPlan::setEventDate(
int jd )
428 julianDayToDate( jd, &m_eventYear, &m_eventMonth, &m_eventDay );
441void HolidayParserDriverPlan::setFromWeekdayInMonth(
int occurrence,
int weekday,
int month,
int offset,
int duration )
444 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
448 int startMonth, endMonth;
449 if ( month == LAST ) {
450 startMonth = monthsInYear( m_parseYear );
451 endMonth = startMonth;
452 }
else if ( month == ANY ) {
454 endMonth = monthsInYear( m_parseYear );
461 for (
int thisMonth = startMonth; thisMonth <= endMonth; ++thisMonth ) {
463 if ( m_parseCalendar->isValid( m_parseYear, thisMonth, 1 ) ) {
464 int startOccurrence, endOccurrence;
465 if ( occurrence == ANY ) {
469 startOccurrence = occurrence;
470 endOccurrence = occurrence;
473 int jdMonthStart = julianDay( m_parseYear, thisMonth, 1 );
474 int jdMonthEnd = julianDay( m_parseYear, thisMonth, daysInMonth( m_parseYear, thisMonth ) );
477 for (
int thisOccurrence = startOccurrence; thisOccurrence <= endOccurrence; ++thisOccurrence ) {
478 int thisJd = julianDayFromWeekdayInMonth( thisOccurrence, weekday, thisMonth );
479 if ( thisJd >= jdMonthStart && thisJd <= jdMonthEnd ) {
480 setEvent( thisJd + offset, 0, duration );
494void HolidayParserDriverPlan::setFromRelativeWeekday(
int occurrence,
int weekday,
int offset,
int duration )
497 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
502 if ( m_eventYear == ANY ) {
503 thisYear = m_parseYear;
505 thisYear = m_eventYear;
508 int startMonth, endMonth;
509 if ( m_eventMonth == LAST ) {
510 startMonth = monthsInYear( thisYear );
511 endMonth = startMonth;
512 }
else if ( m_eventMonth == ANY ) {
514 endMonth = monthsInYear( thisYear );
516 startMonth = m_eventMonth;
517 endMonth = m_eventMonth;
522 for ( thisMonth = startMonth; thisMonth <= endMonth; ++thisMonth ) {
524 int startDay, endDay;
525 if ( m_eventDay == LAST ) {
526 startDay = daysInMonth( thisYear, thisMonth );
528 }
else if ( m_eventDay == ANY ) {
530 endDay = daysInMonth( thisYear, thisMonth );
532 startDay = m_eventDay;
537 for (
int thisDay = startDay; thisDay <= endDay; ++thisDay ) {
538 if ( m_parseCalendar->isValid( thisYear, thisMonth, thisDay ) ) {
539 int relativeJd = julianDayFromRelativeWeekday( occurrence, weekday, julianDay( thisYear, thisMonth, thisDay ) );
540 setEvent( relativeJd + offset, 0, duration );
548int HolidayParserDriverPlan::conditionalOffset(
int year,
int month,
int day,
int condition )
558 m_parseCalendar->setDate( tempDate, year, month, day );
559 int weekday = m_parseCalendar->dayOfWeek( tempDate );
561 if ( condition & ( 1 << weekday ) ) {
563 int to = ( condition >> 8 );
564 while ( !( to & ( 1 << ( ( weekday + offset ) % 7 ) ) ) && ( offset < 8 ) ) {
582void HolidayParserDriverPlan::setFromDate(
int offset,
int condition,
int duration )
585 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
590 if ( m_eventYear == ANY ) {
591 thisYear = m_parseYear;
593 thisYear = m_eventYear;
596 int startMonth, endMonth;
597 if ( m_eventMonth == LAST ) {
598 startMonth = monthsInYear( thisYear );
599 endMonth = startMonth;
600 }
else if ( m_eventMonth == ANY ) {
602 endMonth = monthsInYear( thisYear );
604 startMonth = m_eventMonth;
605 endMonth = m_eventMonth;
609 for (
int thisMonth = startMonth; thisMonth <= endMonth; ++thisMonth ) {
611 int startDay, endDay;
612 if ( m_eventDay == LAST ) {
613 startDay = daysInMonth( thisYear, thisMonth );
615 }
else if ( m_eventDay == ANY ) {
617 endDay = daysInMonth( thisYear, thisMonth );
619 startDay = m_eventDay;
624 for (
int thisDay = startDay; thisDay <= endDay; ++thisDay ) {
626 if ( m_parseCalendar->isValid( thisYear, thisMonth, thisDay ) ) {
627 setEvent( julianDay( thisYear, thisMonth, thisDay ) + offset,
628 conditionalOffset( thisYear, thisMonth, thisDay, condition ), duration );
642void HolidayParserDriverPlan::setFromEaster(
int offset,
int duration )
645 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
649 if ( m_eventCalendarType == QLatin1String(
"gregorian") ) {
650 setEvent( m_parseYearEaster.toJulianDay() + offset, 0, duration );
652 error( QLatin1String(
"Can only use Easter in Gregorian event rule") );
662void HolidayParserDriverPlan::setFromPascha(
int offset,
int duration )
665 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
669 if ( m_eventCalendarType == QLatin1String(
"gregorian") || m_eventCalendarType == QLatin1String(
"julian") ) {
670 setEvent( m_parseYearPascha.toJulianDay(), offset, duration );
672 error( QLatin1String(
"Can only use Pascha in Julian and Gregorian event rule") );
677void HolidayParserDriverPlan::setEvent(
int jd,
int observeOffset,
int duration )
680 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
685 int observeJd = jd + observeOffset;
687 if ( m_multidayMode == Holiday::MultidayHolidaysAsSingleEvents ) {
688 addHoliday( QDate::fromJulianDay( observeJd ), duration );
691 for (
int dd = 0; dd < duration; ++dd ) {
692 addHoliday( QDate::fromJulianDay( observeJd + dd ), 1 );
697void HolidayParserDriverPlan::addHoliday(
const QDate &observedDate,
int duration )
700 if ( m_parseCalendar->isValid( observedDate ) &&
701 observedDate <= m_requestEnd &&
702 observedDate.addDays( duration - 1 ) >= m_requestStart ) {
703 KHolidays::Holiday holiday;
704 holiday.d->mObservedDate = observedDate;
705 holiday.d->mDuration = duration;
706 holiday.d->mText = m_eventName;
707 holiday.d->mShortText = m_eventName;
708 if ( m_eventCategories.contains(
"public" ) ) {
709 holiday.d->mDayType = KHolidays::Holiday::NonWorkday;
711 holiday.d->mDayType = KHolidays::Holiday::Workday;
713 m_resultList.append( holiday );
HolidayParserDriverPlan(const QString &planFilename)
Constructor of Plan file parser driver.
void parseMetadata()
Parse the file for metadata only and populate the metadata variables.
void parse()
Actually parse the file, new plan format implementation.
void error(const KHolidays::location &errorLocation, const QString &errorMessage)
Bison C++ skeleton error message handling.
~HolidayParserDriverPlan()
Destructor.
HolidayParserDriver abstract base class.
virtual void setParseStartEnd()
Initialise parse year variables for calendar system.
virtual void setParseCalendar(const QString &calendarType)
Set the calendar system to use.
virtual int parse()
Parse.
HolidayScannerPlan implementation class.