|
|
|
/*
|
|
|
|
This file is part of libkcal.
|
|
|
|
|
|
|
|
Copyright (c) 1998 Preston Brown <pbrown@kde.org>
|
|
|
|
Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org>
|
|
|
|
Copyright (c) 2002 David Jarvie <software@astrojar.org.uk>
|
|
|
|
Copyright (c) 2005, Reinhold Kainhofer <reinhold@kainhofer.com>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
#ifndef KCAL_RECURRENCERULE_H
|
|
|
|
#define KCAL_RECURRENCERULE_H
|
|
|
|
|
|
|
|
#include <tqdatetime.h>
|
|
|
|
#include <libkcal/listbase.h>
|
|
|
|
|
|
|
|
#include "libkcal_export.h"
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
TQ_INLINE_TEMPLATES void qSortUnique( TQValueList<T> &lst )
|
|
|
|
{
|
|
|
|
qHeapSort( lst );
|
|
|
|
if ( lst.isEmpty() ) return;
|
|
|
|
// Remove all duplicates from the times list
|
|
|
|
// TODO: Make this more efficient!
|
|
|
|
TQValueListIterator<T> it = lst.begin();
|
|
|
|
T last = *it;
|
|
|
|
++it;
|
|
|
|
T newlast;
|
|
|
|
while ( it != lst.end() ) {
|
|
|
|
newlast = (*it);
|
|
|
|
if ( newlast == last ) it = lst.remove( it );
|
|
|
|
else {
|
|
|
|
last = newlast;
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
TQ_INLINE_TEMPLATES int findGE( const TQValueList<T> &lst, const T &value, int start )
|
|
|
|
{
|
|
|
|
// Do a binary search to find the first item >= value
|
|
|
|
int st = start - 1;
|
|
|
|
int end = lst.count();
|
|
|
|
while ( end - st > 1 ) {
|
|
|
|
int i = ( st + end ) / 2;
|
|
|
|
if ( value <= lst[i] ) {
|
|
|
|
end = i;
|
|
|
|
} else {
|
|
|
|
st = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++st;
|
|
|
|
return ( st == int( lst.count() ) ) ? -1 : st;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
TQ_INLINE_TEMPLATES int findGT( const TQValueList<T> &lst, const T &value, int start )
|
|
|
|
{
|
|
|
|
// Do a binary search to find the first item > value
|
|
|
|
int st = start - 1;
|
|
|
|
int end = lst.count();
|
|
|
|
while ( end - st > 1 ) {
|
|
|
|
int i = ( st + end ) / 2;
|
|
|
|
if ( value < lst[i] ) {
|
|
|
|
end = i;
|
|
|
|
} else {
|
|
|
|
st = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++st;
|
|
|
|
return ( st == int( lst.count() ) ) ? -1 : st;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
TQ_INLINE_TEMPLATES int findLE( const TQValueList<T> &lst, const T &value, int start )
|
|
|
|
{
|
|
|
|
// Do a binary search to find the last item <= value
|
|
|
|
int st = start - 1;
|
|
|
|
int end = lst.count();
|
|
|
|
while ( end - st > 1 ) {
|
|
|
|
int i = ( st + end ) / 2;
|
|
|
|
if ( value < lst[i] ) {
|
|
|
|
end = i;
|
|
|
|
} else {
|
|
|
|
st = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ( end > start ) ? st : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
TQ_INLINE_TEMPLATES int findLT( const TQValueList<T> &lst, const T &value, int start )
|
|
|
|
{
|
|
|
|
// Do a binary search to find the last item < value
|
|
|
|
int st = start - 1;
|
|
|
|
int end = lst.count();
|
|
|
|
while ( end - st > 1 ) {
|
|
|
|
int i = ( st + end ) / 2;
|
|
|
|
if ( value <= lst[i] ) {
|
|
|
|
end = i;
|
|
|
|
} else {
|
|
|
|
st = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ( end > start ) ? st : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
TQ_INLINE_TEMPLATES int findSorted( const TQValueList<T> &lst, const T &value, int start )
|
|
|
|
{
|
|
|
|
// Do a binary search to find the item == value
|
|
|
|
int st = start - 1;
|
|
|
|
int end = lst.count();
|
|
|
|
while ( end - st > 1 ) {
|
|
|
|
int i = ( st + end ) / 2;
|
|
|
|
if ( value < lst[i] ) {
|
|
|
|
end = i;
|
|
|
|
} else {
|
|
|
|
st = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ( end > start && value == lst[st] ) ? st : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
TQ_INLINE_TEMPLATES int removeSorted( TQValueList<T> &lst, const T &value, int start )
|
|
|
|
{
|
|
|
|
int i = findSorted( lst, value, start );
|
|
|
|
if ( i >= 0 ) {
|
|
|
|
lst.remove( lst.at( i ) );
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
TQ_INLINE_TEMPLATES bool containsSorted( const TQValueList<T> &lst, const T &value )
|
|
|
|
{
|
|
|
|
return findSorted( lst, value, 0 ) >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
namespace KCal {
|
|
|
|
|
|
|
|
typedef TQValueList<TQDateTime> DateTimeList;
|
|
|
|
typedef TQValueList<TQDate> DateList;
|
|
|
|
typedef TQValueList<TQTime> TimeList;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
This class represents a recurrence rule for a calendar incidence.
|
|
|
|
*/
|
|
|
|
class LIBKCAL_EXPORT RecurrenceRule
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
class Observer {
|
|
|
|
public:
|
|
|
|
virtual ~Observer() {}
|
|
|
|
/** This method will be called on each change of the recurrence object */
|
|
|
|
virtual void recurrenceChanged( RecurrenceRule * ) = 0;
|
|
|
|
};
|
|
|
|
typedef ListBase<RecurrenceRule> List;
|
|
|
|
/** enum for describing the frequency how an event recurs, if at all. */
|
|
|
|
enum PeriodType { rNone = 0,
|
|
|
|
rSecondly, rMinutely, rHourly,
|
|
|
|
rDaily, rWeekly, rMonthly, rYearly
|
|
|
|
};
|
|
|
|
/** structure for describing the n-th weekday of the month/year. */
|
|
|
|
class WDayPos {
|
|
|
|
public:
|
|
|
|
WDayPos( int ps = 0 , short dy = 0 ) : mDay(dy), mPos(ps) {}
|
|
|
|
short day() const { return mDay; }
|
|
|
|
int pos() const { return mPos; }
|
|
|
|
void setDay( short dy ) { mDay = dy; }
|
|
|
|
void setPos( int ps ) { mPos = ps; }
|
|
|
|
|
|
|
|
bool operator==( const RecurrenceRule::WDayPos &pos2 ) const {
|
|
|
|
return ( mDay == pos2.mDay ) && ( mPos == pos2.mPos );
|
|
|
|
}
|
|
|
|
protected:
|
|
|
|
short mDay; // Weekday, 1=monday, 7=sunday
|
|
|
|
int mPos; // week of the day (-1 for last, 1 for first, 0 for all weeks)
|
|
|
|
// Bounded by -366 and +366, 0 means all weeks in that period
|
|
|
|
};
|
|
|
|
|
|
|
|
RecurrenceRule( /*Incidence *parent, int compatVersion = 0*/ );
|
|
|
|
RecurrenceRule(const RecurrenceRule&);
|
|
|
|
~RecurrenceRule();
|
|
|
|
|
|
|
|
bool operator==( const RecurrenceRule& ) const;
|
|
|
|
bool operator!=( const RecurrenceRule& r ) const { return !operator==(r); }
|
|
|
|
RecurrenceRule &operator=(const RecurrenceRule&);
|
|
|
|
|
|
|
|
// Incidence *parent() const { return mParent; }
|
|
|
|
|
|
|
|
|
|
|
|
/** Set if recurrence is read-only or can be changed. */
|
|
|
|
void setReadOnly(bool readOnly) { mIsReadOnly = readOnly; }
|
|
|
|
/** Returns true if the recurrence is read-only, or false if it can be changed. */
|
|
|
|
bool isReadOnly() const { return mIsReadOnly; }
|
|
|
|
|
|
|
|
|
|
|
|
/** Returns the event's recurrence status. See the enumeration at the top
|
|
|
|
* of this file for possible values. */
|
|
|
|
bool doesRecur() const { return mPeriod!=rNone; }
|
|
|
|
void setRecurrenceType( PeriodType period );
|
|
|
|
PeriodType recurrenceType() const { return mPeriod; }
|
|
|
|
/** Turns off recurrence for the event. */
|
|
|
|
void clear();
|
|
|
|
|
|
|
|
|
|
|
|
/** Returns frequency of recurrence, in terms of the recurrence time period type. */
|
|
|
|
uint frequency() const { return mFrequency; }
|
|
|
|
/** Sets the frequency of recurrence, in terms of the recurrence time period type. */
|
|
|
|
void setFrequency( int freq );
|
|
|
|
|
|
|
|
|
|
|
|
/** Return the start of the recurrence */
|
|
|
|
TQDateTime startDt() const { return mDateStart; }
|
|
|
|
/** Set start of recurrence, as a date and time. */
|
|
|
|
void setStartDt(const TQDateTime &start);
|
|
|
|
|
|
|
|
/** Returns whether the start date has no time associated. Floating
|
|
|
|
means -- according to rfc2445 -- that the event has no time associate. */
|
|
|
|
bool doesFloat() const { return mFloating; }
|
|
|
|
/** Sets whether the dtstart is a floating time (i.e. has no time attached) */
|
|
|
|
void setFloats( bool floats );
|
|
|
|
|
|
|
|
|
|
|
|
/** Returns the date and time of the last recurrence.
|
|
|
|
* An invalid date is returned if the recurrence has no end.
|
|
|
|
* @param result if non-null, *result is updated to true if successful,
|
|
|
|
* or false if there is no recurrence.
|
|
|
|
*/
|
|
|
|
TQDateTime endDt( bool* result = 0 ) const;
|
|
|
|
/** Sets the date and time of the last recurrence.
|
|
|
|
* @param endDateTime the ending date/time after which to stop recurring. */
|
|
|
|
void setEndDt(const TQDateTime &endDateTime);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns -1 if the event recurs infinitely, 0 if the end date is set,
|
|
|
|
* otherwise the total number of recurrences, including the initial occurrence.
|
|
|
|
*/
|
|
|
|
int duration() const { return mDuration; }
|
|
|
|
/** Sets the total number of times the event is to occur, including both the
|
|
|
|
* first and last. */
|
|
|
|
void setDuration(int duration);
|
|
|
|
// /** Returns the number of recurrences up to and including the date specified. */
|
|
|
|
// int durationTo(const TQDate &) const;
|
|
|
|
/** Returns the number of recurrences up to and including the date/time specified. */
|
|
|
|
int durationTo(const TQDateTime &) const;
|
|
|
|
/** Returns the number of recurrences up to and including the date specified. */
|
|
|
|
int durationTo( const TQDate &date ) const { return durationTo( TQDateTime( date, TQTime( 23, 59, 59 ) ) ); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Returns true if the date specified is one on which the event will
|
|
|
|
* recur. The start date returns true only if it actually matches the rule. */
|
|
|
|
bool recursOn( const TQDate &qd ) const;
|
|
|
|
/** Returns true if the date/time specified is one at which the event will
|
|
|
|
* recur. Times are rounded down to the nearest minute to determine the result.
|
|
|
|
* The start date/time returns true only if it actually matches the rule. */
|
|
|
|
bool recursAt( const TQDateTime & ) const;
|
|
|
|
/** Returns true if the date matches the rules. It does not necessarily
|
|
|
|
mean that this is an actual occurrence. In particular, the method does
|
|
|
|
not check if the date is after the end date, or if the frequency interval
|
|
|
|
matches */
|
|
|
|
bool dateMatchesRules( const TQDateTime &qdt ) const;
|
|
|
|
|
|
|
|
|
|
|
|
/** Returns a list of the times on the specified date at which the
|
|
|
|
* recurrence will occur.
|
|
|
|
* @param date the date for which to find the recurrence times.
|
|
|
|
*/
|
|
|
|
TimeList recurTimesOn( const TQDate &date ) const;
|
|
|
|
|
|
|
|
/** Returns a list of all the times at which the recurrence will occur
|
|
|
|
* between two specified times.
|
|
|
|
*
|
|
|
|
* There is a (large) maximum limit to the number of times returned. If due to
|
|
|
|
* this limit the list is incomplete, this is indicated by the last entry being
|
|
|
|
* set to an invalid KDateTime value. If you need further values, call the
|
|
|
|
* method again with a start time set to just after the last valid time returned.
|
|
|
|
* @param start inclusive start of interval
|
|
|
|
* @param end inclusive end of interval
|
|
|
|
* @return list of date/time values
|
|
|
|
*/
|
|
|
|
DateTimeList timesInInterval( const TQDateTime &start, const TQDateTime &end ) const;
|
|
|
|
|
|
|
|
/** Returns the date and time of the next recurrence, after the specified date/time.
|
|
|
|
* If the recurrence has no time, the next date after the specified date is returned.
|
|
|
|
* @param preDateTime the date/time after which to find the recurrence.
|
|
|
|
* @return date/time of next recurrence, or invalid date if none.
|
|
|
|
*/
|
|
|
|
TQDateTime getNextDate( const TQDateTime& preDateTime ) const;
|
|
|
|
/** Returns the date and time of the last previous recurrence, before the specified date/time.
|
|
|
|
* If a time later than 00:00:00 is specified and the recurrence has no time, 00:00:00 on
|
|
|
|
* the specified date is returned if that date recurs.
|
|
|
|
* @param afterDateTime the date/time before which to find the recurrence.
|
|
|
|
* @return date/time of previous recurrence, or invalid date if none.
|
|
|
|
*/
|
|
|
|
TQDateTime getPreviousDate( const TQDateTime& afterDateTime ) const;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void setBySeconds( const TQValueList<int> bySeconds );
|
|
|
|
void setByMinutes( const TQValueList<int> byMinutes );
|
|
|
|
void setByHours( const TQValueList<int> byHours );
|
|
|
|
|
|
|
|
void setByDays( const TQValueList<WDayPos> byDays );
|
|
|
|
void setByMonthDays( const TQValueList<int> byMonthDays );
|
|
|
|
void setByYearDays( const TQValueList<int> byYearDays );
|
|
|
|
void setByWeekNumbers( const TQValueList<int> byWeekNumbers );
|
|
|
|
void setByMonths( const TQValueList<int> byMonths );
|
|
|
|
void setBySetPos( const TQValueList<int> bySetPos );
|
|
|
|
void setWeekStart( short weekStart );
|
|
|
|
|
|
|
|
const TQValueList<int> &bySeconds() const { return mBySeconds; }
|
|
|
|
const TQValueList<int> &byMinutes() const { return mByMinutes; }
|
|
|
|
const TQValueList<int> &byHours() const { return mByHours; }
|
|
|
|
|
|
|
|
const TQValueList<WDayPos> &byDays() const { return mByDays; }
|
|
|
|
const TQValueList<int> &byMonthDays() const { return mByMonthDays; }
|
|
|
|
const TQValueList<int> &byYearDays() const { return mByYearDays; }
|
|
|
|
const TQValueList<int> &byWeekNumbers() const { return mByWeekNumbers; }
|
|
|
|
const TQValueList<int> &byMonths() const { return mByMonths; }
|
|
|
|
const TQValueList<int> &bySetPos() const { return mBySetPos; }
|
|
|
|
short weekStart() const { return mWeekStart; }
|
|
|
|
|
|
|
|
|
|
|
|
void setDirty();
|
|
|
|
/**
|
|
|
|
Installs an observer. Whenever some setting of this recurrence
|
|
|
|
object is changed, the recurrenceUpdated( Recurrence* ) method
|
|
|
|
of each observer will be called to inform it of changes.
|
|
|
|
@param observer the Recurrence::Observer-derived object, which
|
|
|
|
will be installed as an observer of this object.
|
|
|
|
*/
|
|
|
|
void addObserver( Observer *observer );
|
|
|
|
/**
|
|
|
|
Removes an observer that was added with addObserver. If the
|
|
|
|
given object was not an observer, it does nothing.
|
|
|
|
@param observer the Recurrence::Observer-derived object to
|
|
|
|
be removed from the list of observers of this object.
|
|
|
|
*/
|
|
|
|
void removeObserver( Observer *observer );
|
|
|
|
|
|
|
|
/**
|
|
|
|
Debug output.
|
|
|
|
*/
|
|
|
|
void dump() const;
|
|
|
|
TQString mRRule;
|
|
|
|
|
|
|
|
private:
|
|
|
|
class Constraint {
|
|
|
|
public:
|
|
|
|
typedef TQValueList<Constraint> List;
|
|
|
|
|
|
|
|
Constraint( int wkst = 1 );
|
|
|
|
/* Constraint( const Constraint &con ) :
|
|
|
|
year(con.year), month(con.month), day(con.day),
|
|
|
|
hour(con.hour), minute(con.minute), second(con.second),
|
|
|
|
weekday(con.weekday), weeknumber(con.weeknumber),
|
|
|
|
yearday(con.yearday), weekstart(con.weekstart) {}*/
|
|
|
|
Constraint( const TQDateTime &preDate, PeriodType type, int wkst );
|
|
|
|
void clear();
|
|
|
|
|
|
|
|
int year; // 0 means unspecified
|
|
|
|
int month; // 0 means unspecified
|
|
|
|
int day; // 0 means unspecified
|
|
|
|
int hour; // -1 means unspecified
|
|
|
|
int minute; // -1 means unspecified
|
|
|
|
int second; // -1 means unspecified
|
|
|
|
int weekday; // 0 means unspecified
|
|
|
|
int weekdaynr; // index of weekday in month/year (0=unspecified)
|
|
|
|
int weeknumber; // 0 means unspecified
|
|
|
|
int yearday; // 0 means unspecified
|
|
|
|
int weekstart; // first day of week (1=monday, 7=sunday, 0=unspec.)
|
|
|
|
|
|
|
|
bool readDateTime( const TQDateTime &preDate, PeriodType type );
|
|
|
|
bool matches( const TQDate &dt, RecurrenceRule::PeriodType type ) const;
|
|
|
|
bool matches( const TQDateTime &dt, RecurrenceRule::PeriodType type ) const;
|
|
|
|
bool isConsistent() const;
|
|
|
|
bool isConsistent( PeriodType period ) const;
|
|
|
|
bool increase( PeriodType type, int freq );
|
|
|
|
TQDateTime intervalDateTime( PeriodType type ) const;
|
|
|
|
DateTimeList dateTimes( PeriodType type ) const;
|
|
|
|
void dump() const;
|
|
|
|
};
|
|
|
|
|
|
|
|
Constraint getNextValidDateInterval( const TQDateTime &preDate, PeriodType type ) const;
|
|
|
|
Constraint getPreviousValidDateInterval( const TQDateTime &preDate, PeriodType type ) const;
|
|
|
|
DateTimeList datesForInterval( const Constraint &interval, PeriodType type ) const;
|
|
|
|
bool mergeIntervalConstraint( Constraint *merged, const Constraint &conit,
|
|
|
|
const Constraint &interval ) const;
|
|
|
|
bool buildCache() const;
|
|
|
|
|
|
|
|
|
|
|
|
PeriodType mPeriod;
|
|
|
|
TQDateTime mDateStart;
|
|
|
|
/** how often it recurs (including dtstart):
|
|
|
|
-1 means infinitely,
|
|
|
|
0 means an explicit end date,
|
|
|
|
positive values give the number of occurrences */
|
|
|
|
int mDuration;
|
|
|
|
TQDateTime mDateEnd;
|
|
|
|
uint mFrequency;
|
|
|
|
|
|
|
|
bool mIsReadOnly;
|
|
|
|
bool mFloating;
|
|
|
|
|
|
|
|
TQValueList<int> mBySeconds; // values: second 0-59
|
|
|
|
TQValueList<int> mByMinutes; // values: minute 0-59
|
|
|
|
TQValueList<int> mByHours; // values: hour 0-23
|
|
|
|
|
|
|
|
TQValueList<WDayPos> mByDays; // n-th weekday of the month or year
|
|
|
|
TQValueList<int> mByMonthDays; // values: day -31 to -1 and 1-31
|
|
|
|
TQValueList<int> mByYearDays; // values: day -366 to -1 and 1-366
|
|
|
|
TQValueList<int> mByWeekNumbers; // values: week -53 to -1 and 1-53
|
|
|
|
TQValueList<int> mByMonths; // values: month 1-12
|
|
|
|
TQValueList<int> mBySetPos; // values: position -366 to -1 and 1-366
|
|
|
|
short mWeekStart; // first day of the week (1=Monday, 7=Sunday)
|
|
|
|
|
|
|
|
Constraint::List mConstraints;
|
|
|
|
void buildConstraints();
|
|
|
|
bool mDirty;
|
|
|
|
TQValueList<Observer*> mObservers;
|
|
|
|
|
|
|
|
// Cache for duration
|
|
|
|
mutable DateTimeList mCachedDates;
|
|
|
|
mutable TQDateTime mCachedDateEnd;
|
|
|
|
mutable TQDateTime mCachedLastDate; // when mCachedDateEnd invalid, last date checked
|
|
|
|
mutable bool mCached;
|
|
|
|
|
|
|
|
bool mNoByRules; // no BySeconds, ByMinutes, ... rules exist
|
|
|
|
uint mTimedRepetition; // repeats at a regular number of seconds interval, or 0
|
|
|
|
|
|
|
|
class Private;
|
|
|
|
Private *d;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|