File indexing completed on 2024-11-24 04:42:24
0001 /* 0002 * karecurrence.h - recurrence with special yearly February 29th handling 0003 * This file is part of kalarmcalendar library, which provides access to KAlarm 0004 * calendar data. 0005 * Program: kalarm 0006 * SPDX-FileCopyrightText: 2005-2022 David Jarvie <djarvie@kde.org> 0007 * 0008 * SPDX-License-Identifier: LGPL-2.0-or-later 0009 */ 0010 0011 #pragma once 0012 0013 #include "kalarmcal_export.h" 0014 #include "kadatetime.h" 0015 0016 #include <KCalendarCore/RecurrenceRule> 0017 #include <KCalendarCore/Duration> 0018 #include <KCalendarCore/IncidenceBase> 0019 namespace KCalendarCore 0020 { 0021 class Recurrence; 0022 } 0023 0024 #include <QBitArray> 0025 0026 namespace KAlarmCal 0027 { 0028 0029 /** 0030 * @short Represents recurrences for KAlarm. 0031 * 0032 * This class represents the restricted range of recurrence types which are 0033 * handled by KAlarm, and translates between these and the libkcalendarcore 0034 * Recurrence class. In particular, it handles yearly recurrences on 29th 0035 * February in non-leap years specially: 0036 * 0037 * KARecurrence allows annual 29th February recurrences to fall on 28th 0038 * February or 1st March, or not at all, in non-leap years. It allows such 0039 * 29th February recurrences to be combined with the 29th of other months in 0040 * a simple way, represented simply as the 29th of multiple months including 0041 * February. For storage in the libkcalendarcore calendar, the 29th day of the month 0042 * recurrence for other months is combined with a last-day-of-February or a 0043 * 60th-day-of-the-year recurrence rule, thereby conforming to RFC2445. 0044 * 0045 * @author David Jarvie <djarvie@kde.org> 0046 */ 0047 class KALARMCAL_EXPORT KARecurrence 0048 { 0049 public: 0050 /** The recurrence's period type. 0051 * This is a subset of the possible KCalendarCore recurrence types. 0052 */ 0053 enum Type 0054 { 0055 NO_RECUR, //!< does not recur 0056 MINUTELY, //!< at an hours/minutes interval 0057 DAILY, //!< daily 0058 WEEKLY, //!< weekly, on specified weekdays 0059 MONTHLY_POS, //!< monthly, on specified weekdays in a specified week of the month 0060 MONTHLY_DAY, //!< monthly, on a specified day of the month 0061 ANNUAL_DATE, //!< yearly, on a specified date in each of the specified months 0062 ANNUAL_POS //!< yearly, on specified weekdays in the specified weeks of the specified months 0063 }; 0064 0065 /** When annual February 29th recurrences should occur in non-leap years. */ 0066 enum Feb29Type 0067 { 0068 Feb29_Feb28, //!< occurs on 28 February in non-leap years 0069 Feb29_Mar1, //!< occurs on 1 March in non-leap years 0070 Feb29_None //!< does not occur in non-leap years 0071 }; 0072 0073 KARecurrence(); 0074 KARecurrence(const KCalendarCore::Recurrence& r); //cppcheck-suppress noExplicitConstructor; Allow implicit conversion 0075 KARecurrence(const KARecurrence& r); 0076 ~KARecurrence(); 0077 0078 /** 0079 * Assignment operator. 0080 * @param r the recurrence which will be assigned to this. 0081 */ 0082 KARecurrence& operator=(const KARecurrence& r) = delete; 0083 0084 /** 0085 * Comparison operator for equality. 0086 * @param r instance to compare with 0087 * @return true if recurrences are the same, false otherwise 0088 */ 0089 bool operator==(const KARecurrence& r) const; 0090 0091 /** 0092 * Comparison operator for inequality. 0093 * @param r instance to compare with 0094 * @return true if recurrences are the different, false if the same 0095 */ 0096 bool operator!=(const KARecurrence& r) const 0097 { 0098 return !operator==(r); 0099 } 0100 0101 /** Initialise the recurrence from an iCalendar RRULE string. 0102 * @return true if successful, false if an error occurred. 0103 */ 0104 bool set(const QString& icalRRULE); 0105 0106 /** Set up a KARecurrence from recurrence parameters, using the start date to 0107 * determine the recurrence day/month as appropriate. 0108 * Annual 29th February recurrences in non-leap years will be handled 0109 * according to the default set by setDefaultFeb29Type(). 0110 * Only a restricted subset of recurrence types is allowed: minutely, daily, 0111 * weekly, monthly, yearly or none. 0112 * @return true if successful. 0113 */ 0114 bool set(Type t, int freq, int count, const KADateTime& start, const KADateTime& end); 0115 0116 /** Set up a KARecurrence from recurrence parameters, using the start date to 0117 * determine the recurrence day/month as appropriate, and specifying how 0118 * annual 29th February recurrences in non-leap years should be handled. 0119 * @return true if successful. 0120 */ 0121 bool set(Type t, int freq, int count, const KADateTime& start, const KADateTime& end, Feb29Type f29); 0122 0123 /** Set up a KARecurrence from recurrence parameters. 0124 * Annual 29th February recurrences in non-leap years will be handled 0125 * according to the default set by setDefaultFeb29Type(). 0126 * Only a restricted subset of recurrence types is allowed: minutely, daily, 0127 * weekly, monthly, yearly or none. 0128 * @return true if successful. 0129 */ 0130 bool init(KCalendarCore::RecurrenceRule::PeriodType t, int freq, int count, const KADateTime& start, const KADateTime& end); 0131 0132 /** Set up a KARecurrence from recurrence parameters, specifying how 0133 * annual 29th February recurrences in non-leap years should be handled. 0134 * Only a restricted subset of recurrence types is allowed: minutely, daily, 0135 * weekly, monthly, yearly or none. 0136 * @return true if successful. 0137 */ 0138 bool init(KCalendarCore::RecurrenceRule::PeriodType t, int freq, int count, const KADateTime& start, const KADateTime& end, Feb29Type f29); 0139 0140 /** Removes all recurrence and exception rules and dates. */ 0141 void clear(); 0142 0143 /** Initialise a KCalendarCore::Recurrence to be the same as this instance. 0144 * Additional recurrence rules are created as necessary if it recurs on Feb 29th. 0145 */ 0146 void writeRecurrence(KCalendarCore::Recurrence&) const; 0147 0148 /** Convert the recurrence to KARecurrence types. 0149 * Must be called after presetting with a KCalendarCore::Recurrence. 0150 * - Convert hourly recurrences to minutely. 0151 * - Remove all but the first day in yearly date recurrences. 0152 * - Check for yearly recurrences falling on February 29th and adjust them as 0153 * necessary. A 29th of the month rule can be combined with either a 60th day 0154 * of the year rule or a last day of February rule. 0155 */ 0156 void fix(); 0157 0158 /** Return the start date/time of the recurrence (Time for all-day recurrences will be 0:00). 0159 * @return the current start/time of the recurrence. 0160 */ 0161 KADateTime startDateTime() const; 0162 0163 /** Return the start date/time of the recurrence */ 0164 QDate startDate() const; 0165 0166 /** Set the recurrence start date/time, and optionally set it to all-day. 0167 * @param dt start date/time. 0168 * @param dateOnly if true, sets the recurrence to all-day. 0169 */ 0170 void setStartDateTime(const KADateTime& dt, bool dateOnly); 0171 0172 /** Return the date/time of the last recurrence. */ 0173 KADateTime endDateTime() const; 0174 0175 /** Return the date of the last recurrence. */ 0176 QDate endDate() const; 0177 0178 /** Sets the date of the last recurrence. The end time is set to the recurrence start time. 0179 * @param endDate the ending date after which to stop recurring. If the 0180 * recurrence is not all-day, the end time will be 23:59. 0181 */ 0182 void setEndDate(const QDate& endDate); 0183 0184 /** Sets the date and time of the last recurrence. 0185 * @param endDateTime the ending date/time after which to stop recurring. 0186 */ 0187 void setEndDateTime(const KADateTime& endDateTime); 0188 0189 /** Set whether the recurrence has no time, just a date. 0190 * All-day means -- according to rfc2445 -- that the event has no time 0191 * associated. 0192 * N.B. This property is derived by default from whether setStartDateTime() is 0193 * called with a date-only or date/time parameter. 0194 * @return whether the recurrence has a time (false) or it is just a date (true). 0195 */ 0196 bool allDay() const; 0197 0198 /** Set if recurrence is read-only or can be changed. */ 0199 void setRecurReadOnly(bool readOnly); 0200 0201 /** Returns true if the recurrence is read-only, or false if it can be changed. */ 0202 bool recurReadOnly() const; 0203 0204 /** Returns whether the event recurs at all. */ 0205 bool recurs() const; 0206 0207 /** Returns week day mask (bit 0 = Monday). */ 0208 QBitArray days() const; // Emulate the old behavior 0209 0210 /** Returns list of day positions in months. */ 0211 QList<KCalendarCore::RecurrenceRule::WDayPos> monthPositions() const; 0212 0213 /** Returns list of day numbers of a month. */ 0214 // Emulate old behavior 0215 QList<int> monthDays() const; 0216 0217 /** Returns the day numbers within a yearly recurrence. 0218 * @return the days of the year for the event. E.g. if the list contains 0219 * 60, this means the recurrence happens on day 60 of the year, i.e. 0220 * on Feb 29 in leap years and March 1 in non-leap years. 0221 */ 0222 QList<int> yearDays() const; 0223 0224 /** Returns the dates within a yearly recurrence. 0225 * @return the days of the month for the event. E.g. if the list contains 0226 * 13, this means the recurrence happens on the 13th of the month. 0227 * The months for the recurrence can be obtained through 0228 * yearlyMonths(). If this list is empty, the month of the start 0229 * date is used. 0230 */ 0231 QList<int> yearDates() const; 0232 0233 /** Returns the months within a yearly recurrence. 0234 * @return the months for the event. E.g. if the list contains 0235 * 11, this means the recurrence happens in November. 0236 * The days for the recurrence can be obtained either through 0237 * yearDates() if they are given as dates within the month or 0238 * through yearlyPositions() if they are given as positions within the 0239 * month. If none is specified, the date of the start date is used. 0240 */ 0241 QList<int> yearMonths() const; 0242 0243 /** Returns the positions within a yearly recurrence. 0244 * @return the positions for the event, either within a month (if months 0245 * are set through addYearlyMonth()) or within the year. 0246 * E.g. if the list contains {Pos=3, Day=5}, this means the third 0247 * friday. If a month is set this position is understoodas third 0248 * Friday in the given months, otherwise as third Friday of the 0249 * year. 0250 */ 0251 QList<KCalendarCore::RecurrenceRule::WDayPos> yearPositions() const; 0252 0253 /** Adds days to the weekly day recurrence list. 0254 * @param days a 7 bit array indicating which days on which to recur (bit 0 = Monday). 0255 */ 0256 void addWeeklyDays(const QBitArray& days); 0257 0258 /** Adds day number of year within a yearly recurrence. 0259 * By default infinite recurrence is used. To set an end date use the 0260 * method setEndDate and to set the number of occurrences use setDuration. 0261 * @param day the day of the year for the event. E.g. if day is 60, this 0262 * means Feb 29 in leap years and March 1 in non-leap years. 0263 */ 0264 void addYearlyDay(int day); 0265 0266 /** Adds date within a yearly recurrence. The month(s) for the recurrence 0267 * can be specified with addYearlyMonth(), otherwise the month of the 0268 * start date is used. 0269 * 0270 * By default infinite recurrence is used. To set an end date use the 0271 * method setEndDate and to set the number of occurrences use setDuration. 0272 * @param date the day of the month for the event 0273 */ 0274 void addYearlyDate(int date); 0275 0276 /** Adds month in yearly recurrence. You can specify specific day numbers 0277 * within the months (by calling addYearlyDate()) or specific day positions 0278 * within the month (by calling addYearlyPos). 0279 * @param month the month in which the event will recur. 0280 */ 0281 void addYearlyMonth(short month); 0282 0283 /** Adds position within month/year within a yearly recurrence. If months 0284 * are specified (via addYearlyMonth()), the parameters are understood as 0285 * position within these months, otherwise within the year. 0286 * 0287 * By default infinite recurrence is used. 0288 * To set an end date use the method setEndDate and to set the number 0289 * of occurrences use setDuration. 0290 * @param pos the position in the month/year for the recurrence, with valid 0291 * values being 1 to 53 and -1 to -53 (53 weeks max in a year). 0292 * @param days the days for the position to recur on (bit 0 = Monday). 0293 * Example: pos = 2, and bits 0 and 2 are set in days 0294 * If months are specified (via addYearlyMonth), e.g. March, the rule is 0295 * to repeat every year on the 2nd Monday and Wednesday of March. 0296 * If no months are specified, the rule is to repeat every year on the 0297 * 2nd Monday and Wednesday of the year. 0298 */ 0299 void addYearlyPos(short pos, const QBitArray& days); 0300 0301 /** Adds a position (e.g. first monday) to the monthly recurrence rule. 0302 * @param pos the position in the month for the recurrence, with valid 0303 * values being 1-5 (5 weeks max in a month). 0304 * @param days the days for the position to recur on (bit 0 = Monday). 0305 * Example: pos = 2, and bits 0 and 2 are set in days: 0306 * the rule is to repeat every 2nd Monday and Wednesday in the month. 0307 */ 0308 void addMonthlyPos(short pos, const QBitArray& days); 0309 void addMonthlyPos(short pos, ushort day); 0310 0311 /** Adds a date (e.g. the 15th of each month) to the monthly day 0312 * recurrence list. 0313 * @param day the date in the month to recur. 0314 */ 0315 void addMonthlyDate(short day); 0316 0317 /** Get the next time the recurrence occurs, strictly after a specified time. */ 0318 KADateTime getNextDateTime(const KADateTime& preDateTime) const; 0319 0320 /** Get the previous time the recurrence occurred, strictly before a specified time. */ 0321 KADateTime getPreviousDateTime(const KADateTime& afterDateTime) const; 0322 0323 /** Return whether the event will recur on the specified date. 0324 * The start date only returns true if it matches the recurrence rules. */ 0325 bool recursOn(const QDate&, const KADateTime::Spec&) const; 0326 0327 /** 0328 * Returns true if the date/time specified is one at which the event will 0329 * recur. Times are rounded down to the nearest minute to determine the result. 0330 * 0331 * @param dt is the date/time to check. 0332 */ 0333 bool recursAt(const KADateTime& dt) const; 0334 0335 /** Returns a list of the times on the specified date at which the 0336 * recurrence will occur. The returned times should be interpreted in the 0337 * context of @p timeSpec. 0338 * @param date the date for which to find the recurrence times 0339 * @param timeSpec time specification for @p date 0340 */ 0341 KCalendarCore::TimeList recurTimesOn(const QDate& date, const KADateTime::Spec& timeSpec) const; 0342 0343 /** Returns a list of all the times at which the recurrence will occur 0344 * between two specified times. 0345 * 0346 * There is a (large) maximum limit to the number of times returned. If due to 0347 * this limit the list is incomplete, this is indicated by the last entry being 0348 * set to an invalid KADateTime value. If you need further values, call the 0349 * method again with a start time set to just after the last valid time returned. 0350 * 0351 * @param start inclusive start of interval 0352 * @param end inclusive end of interval 0353 * @return list of date/time values 0354 */ 0355 KCalendarCore::DateTimeList timesInInterval(const KADateTime& start, const KADateTime& end) const; 0356 0357 /** Returns frequency of recurrence, in terms of the recurrence time period type. */ 0358 int frequency() const; 0359 0360 /** Sets the frequency of recurrence, in terms of the recurrence time period type. */ 0361 void setFrequency(int freq); 0362 0363 /** 0364 * Returns -1 if the event recurs infinitely, 0 if the end date is set, 0365 * otherwise the total number of recurrences, including the initial occurrence. 0366 */ 0367 int duration() const; 0368 0369 /** Sets the total number of times the event is to occur, including both the 0370 * first and last. 0371 */ 0372 void setDuration(int duration); 0373 0374 /** Returns the number of recurrences up to and including the date/time specified. 0375 * @warning This function can be very time consuming - use it sparingly! 0376 */ 0377 int durationTo(const KADateTime& dt) const; 0378 0379 /** Returns the number of recurrences up to and including the date specified. 0380 * @warning This function can be very time consuming - use it sparingly! 0381 */ 0382 int durationTo(const QDate& date) const; 0383 0384 /** Return the longest interval between recurrences. 0385 * @return 0 if it never recurs. 0386 */ 0387 KCalendarCore::Duration longestInterval() const; 0388 0389 /** Return the interval between recurrences, if the interval between 0390 * successive occurrences does not vary. 0391 * @return 0 if recurrence does not occur at fixed intervals. 0392 */ 0393 KCalendarCore::Duration regularInterval() const; 0394 KCalendarCore::DateTimeList exDateTimes() const; 0395 KCalendarCore::DateList exDates() const; 0396 void setExDateTimes(const KCalendarCore::DateTimeList& exdates); 0397 void setExDates(const KCalendarCore::DateList& exdates); 0398 void addExDateTime(const KADateTime& exdate); 0399 void addExDate(const QDate& exdate); 0400 0401 /** 0402 * Shift the times of the recurrence so that they appear at the same clock 0403 * time as before but in a new time zone. The shift is done from a viewing 0404 * time zone rather than from the actual recurrence time zone. 0405 * 0406 * For example, shifting a recurrence whose start time is 09:00 America/New York, 0407 * using an old viewing time zone (@p oldSpec) of Europe/London, to a new time 0408 * zone (@p newSpec) of Europe/Paris, will result in the time being shifted 0409 * from 14:00 (which is the London time of the recurrence start) to 14:00 Paris 0410 * time. 0411 * 0412 * @param oldSpec the time specification which provides the clock times 0413 * @param newSpec the new time specification 0414 */ 0415 void shiftTimes(const QTimeZone& oldSpec, const QTimeZone& newSpec); 0416 0417 KCalendarCore::RecurrenceRule* defaultRRuleConst() const; 0418 /** Return the recurrence's period type. */ 0419 Type type() const; 0420 0421 /** Return the type of a recurrence rule. */ 0422 static Type type(const KCalendarCore::RecurrenceRule*); 0423 0424 /** Check if the recurrence rule is a daily rule with or without BYDAYS specified. */ 0425 static bool dailyType(const KCalendarCore::RecurrenceRule*); 0426 0427 /** Return when 29th February annual recurrences should occur in non-leap years. */ 0428 Feb29Type feb29Type() const; 0429 0430 /** Return the default way that 29th February annual recurrences should occur 0431 * in non-leap years. 0432 * @see setDefaultFeb29Type(). 0433 */ 0434 static Feb29Type defaultFeb29Type(); 0435 0436 /** Set the default way that 29th February annual recurrences should occur 0437 * in non-leap years. 0438 * @see defaultFeb29Type(). 0439 */ 0440 static void setDefaultFeb29Type(Feb29Type t); 0441 0442 private: 0443 //@cond PRIVATE 0444 class Private; 0445 Private* const d; 0446 //@endcond 0447 }; 0448 0449 } // namespace KAlarmCal 0450 0451 // vim: et sw=4: