summaryrefslogtreecommitdiffstats
path: root/libkcal/recurrencerule.h
blob: 4d8139070c1d5fccfb0bbcb1456cc7147e1fc65b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
/*
    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