|
|
|
/*
|
|
|
|
This file is part of libkcal.
|
|
|
|
|
|
|
|
Copyright (c) 1998 Preston Brown <pbrown@kde.org>
|
|
|
|
Copyright (c) 2001,2003,2004 Cornelius Schumacher <schumacher@kde.org>
|
|
|
|
Copyright (C) 2003-2004 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <tqdatetime.h>
|
|
|
|
#include <tqstring.h>
|
|
|
|
#include <tqptrlist.h>
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
|
|
|
|
#include "vcaldrag.h"
|
|
|
|
#include "vcalformat.h"
|
|
|
|
#include "icalformat.h"
|
|
|
|
#include "exceptions.h"
|
|
|
|
#include "incidence.h"
|
|
|
|
#include "journal.h"
|
|
|
|
#include "filestorage.h"
|
|
|
|
|
|
|
|
#include "calendarlocal.h"
|
|
|
|
|
|
|
|
using namespace KCal;
|
|
|
|
|
|
|
|
CalendarLocal::CalendarLocal( const TQString &timeZoneId )
|
|
|
|
: Calendar( timeZoneId ), mEvents( 47 )
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CalendarLocal::init()
|
|
|
|
{
|
|
|
|
mDeletedIncidences.setAutoDelete( true );
|
|
|
|
mFileName = TQString();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CalendarLocal::~CalendarLocal()
|
|
|
|
{
|
|
|
|
close();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CalendarLocal::load( const TQString &fileName, CalFormat *format )
|
|
|
|
{
|
|
|
|
mFileName = fileName;
|
|
|
|
FileStorage storage( this, fileName, format );
|
|
|
|
return storage.load();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CalendarLocal::reload( const TQString &tz )
|
|
|
|
{
|
|
|
|
const TQString filename = mFileName;
|
|
|
|
save();
|
|
|
|
close();
|
|
|
|
mFileName = filename;
|
|
|
|
setTimeZoneId( tz );
|
|
|
|
FileStorage storage( this, mFileName );
|
|
|
|
return storage.load();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CalendarLocal::save( const TQString &fileName, CalFormat *format )
|
|
|
|
{
|
|
|
|
// Save only if the calendar is either modified, or saved to a
|
|
|
|
// different file than it was loaded from
|
|
|
|
if ( mFileName != fileName || isModified() ) {
|
|
|
|
FileStorage storage( this, fileName, format );
|
|
|
|
return storage.save();
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CalendarLocal::close()
|
|
|
|
{
|
|
|
|
setObserversEnabled( false );
|
|
|
|
mFileName = TQString();
|
|
|
|
|
|
|
|
deleteAllEvents();
|
|
|
|
deleteAllTodos();
|
|
|
|
deleteAllJournals();
|
|
|
|
|
|
|
|
mDeletedIncidences.clear();
|
|
|
|
setModified( false );
|
|
|
|
|
|
|
|
setObserversEnabled( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CalendarLocal::closeEvents()
|
|
|
|
{
|
|
|
|
setObserversEnabled( false );
|
|
|
|
mFileName = TQString();
|
|
|
|
|
|
|
|
deleteAllEvents();
|
|
|
|
|
|
|
|
mDeletedIncidences.clear();
|
|
|
|
setModified( false );
|
|
|
|
|
|
|
|
setObserversEnabled( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CalendarLocal::closeTodos()
|
|
|
|
{
|
|
|
|
setObserversEnabled( false );
|
|
|
|
mFileName = TQString();
|
|
|
|
|
|
|
|
deleteAllTodos();
|
|
|
|
|
|
|
|
mDeletedIncidences.clear();
|
|
|
|
setModified( false );
|
|
|
|
|
|
|
|
setObserversEnabled( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CalendarLocal::closeJournals()
|
|
|
|
{
|
|
|
|
setObserversEnabled( false );
|
|
|
|
mFileName = TQString();
|
|
|
|
|
|
|
|
deleteAllJournals();
|
|
|
|
|
|
|
|
mDeletedIncidences.clear();
|
|
|
|
setModified( false );
|
|
|
|
|
|
|
|
setObserversEnabled( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CalendarLocal::addEvent( Event *event )
|
|
|
|
{
|
|
|
|
insertEvent( event );
|
|
|
|
|
|
|
|
event->registerObserver( this );
|
|
|
|
|
|
|
|
setModified( true );
|
|
|
|
|
|
|
|
notifyIncidenceAdded( event );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CalendarLocal::deleteEvent( Event *event )
|
|
|
|
{
|
|
|
|
// kdDebug(5800) << "CalendarLocal::deleteEvent" << endl;
|
|
|
|
|
|
|
|
if ( mEvents.remove( event->uid() ) ) {
|
|
|
|
setModified( true );
|
|
|
|
notifyIncidenceDeleted( event );
|
|
|
|
mDeletedIncidences.append( event );
|
|
|
|
// Delete child events
|
|
|
|
if (!event->hasRecurrenceID()) {
|
|
|
|
deleteChildEvents(event);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
kdWarning() << "CalendarLocal::deleteEvent(): Event not found." << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CalendarLocal::deleteChildEvents( Event *event )
|
|
|
|
{
|
|
|
|
EventDictIterator it( mEvents );
|
|
|
|
for( ; it.current(); ++it ) {
|
|
|
|
Event *e = *it;
|
|
|
|
if (e->uid() == event->uid()) {
|
|
|
|
if ( e->hasRecurrenceID() ) {
|
|
|
|
deleteEvent(( e ));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CalendarLocal::deleteAllEvents()
|
|
|
|
{
|
|
|
|
// kdDebug(5800) << "CalendarLocal::deleteAllEvents" << endl;
|
|
|
|
TQDictIterator<Event> it( mEvents );
|
|
|
|
while( it.current() ) {
|
|
|
|
notifyIncidenceDeleted( it.current() );
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
|
|
|
|
mEvents.setAutoDelete( true );
|
|
|
|
mEvents.clear();
|
|
|
|
mEvents.setAutoDelete( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
Event *CalendarLocal::event( const TQString &uid )
|
|
|
|
{
|
|
|
|
// kdDebug(5800) << "CalendarLocal::event(): " << uid << endl;
|
|
|
|
return mEvents[ uid ];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CalendarLocal::addTodo( Todo *todo )
|
|
|
|
{
|
|
|
|
mTodoList.append( todo );
|
|
|
|
|
|
|
|
todo->registerObserver( this );
|
|
|
|
|
|
|
|
// Set up subtask relations
|
|
|
|
setupRelations( todo );
|
|
|
|
|
|
|
|
setModified( true );
|
|
|
|
|
|
|
|
notifyIncidenceAdded( todo );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CalendarLocal::deleteTodo( Todo *todo )
|
|
|
|
{
|
|
|
|
// Handle orphaned children
|
|
|
|
removeRelations( todo );
|
|
|
|
|
|
|
|
if ( mTodoList.removeRef( todo ) ) {
|
|
|
|
setModified( true );
|
|
|
|
notifyIncidenceDeleted( todo );
|
|
|
|
mDeletedIncidences.append( todo );
|
|
|
|
// Delete child todos
|
|
|
|
if (!todo->hasRecurrenceID()) {
|
|
|
|
deleteChildTodos(todo);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
kdWarning() << "CalendarLocal::deleteTodo(): Todo not found." << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CalendarLocal::deleteChildTodos( Todo *todo )
|
|
|
|
{
|
|
|
|
Todo::List::ConstIterator it;
|
|
|
|
for( it = mTodoList.begin(); it != mTodoList.end(); ++it ) {
|
|
|
|
Todo *t = *it;
|
|
|
|
if (t->uid() == todo->uid()) {
|
|
|
|
if ( t->hasRecurrenceID() ) {
|
|
|
|
deleteTodo(( t ));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CalendarLocal::deleteAllTodos()
|
|
|
|
{
|
|
|
|
// kdDebug(5800) << "CalendarLocal::deleteAllTodos()\n";
|
|
|
|
Todo::List::ConstIterator it;
|
|
|
|
for( it = mTodoList.begin(); it != mTodoList.end(); ++it ) {
|
|
|
|
notifyIncidenceDeleted( *it );
|
|
|
|
}
|
|
|
|
|
|
|
|
mTodoList.setAutoDelete( true );
|
|
|
|
mTodoList.clearAll();
|
|
|
|
mTodoList.setAutoDelete( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
Todo::List CalendarLocal::rawTodos( TodoSortField sortField,
|
|
|
|
SortDirection sortDirection )
|
|
|
|
{
|
|
|
|
return sortTodos( &mTodoList, sortField, sortDirection );
|
|
|
|
}
|
|
|
|
|
|
|
|
Todo *CalendarLocal::todo( const TQString &uid )
|
|
|
|
{
|
|
|
|
Todo::List::ConstIterator it;
|
|
|
|
for ( it = mTodoList.begin(); it != mTodoList.end(); ++it ) {
|
|
|
|
if ( (*it)->uid() == uid ) return *it;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Todo::List CalendarLocal::rawTodosForDate( const TQDate &date )
|
|
|
|
{
|
|
|
|
Todo::List todos;
|
|
|
|
|
|
|
|
Todo::List::ConstIterator it;
|
|
|
|
for ( it = mTodoList.begin(); it != mTodoList.end(); ++it ) {
|
|
|
|
Todo *todo = *it;
|
|
|
|
if ( todo->hasDueDate() && todo->dtDue().date() == date ) {
|
|
|
|
todos.append( todo );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return todos;
|
|
|
|
}
|
|
|
|
|
|
|
|
Alarm::List CalendarLocal::alarmsTo( const TQDateTime &to )
|
|
|
|
{
|
|
|
|
return alarms( TQDateTime( TQDate( 1900, 1, 1 ) ), to );
|
|
|
|
}
|
|
|
|
|
|
|
|
Alarm::List CalendarLocal::alarms( const TQDateTime &from, const TQDateTime &to )
|
|
|
|
{
|
|
|
|
// kdDebug(5800) << "CalendarLocal::alarms(" << from.toString() << " - "
|
|
|
|
// << to.toString() << ")" << endl;
|
|
|
|
|
|
|
|
Alarm::List alarms;
|
|
|
|
|
|
|
|
EventDictIterator it( mEvents );
|
|
|
|
for( ; it.current(); ++it ) {
|
|
|
|
Event *e = *it;
|
|
|
|
if ( e->doesRecur() ) appendRecurringAlarms( alarms, e, from, to );
|
|
|
|
else appendAlarms( alarms, e, from, to );
|
|
|
|
}
|
|
|
|
|
|
|
|
Todo::List::ConstIterator it2;
|
|
|
|
for( it2 = mTodoList.begin(); it2 != mTodoList.end(); ++it2 ) {
|
|
|
|
Todo *t = *it2;
|
|
|
|
if ( t->isCompleted() ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ( t->doesRecur() ) appendRecurringAlarms( alarms, t, from, to );
|
|
|
|
else appendAlarms( alarms, t, from, to );
|
|
|
|
}
|
|
|
|
|
|
|
|
return alarms;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CalendarLocal::appendAlarms( Alarm::List &alarms, Incidence *incidence,
|
|
|
|
const TQDateTime &from, const TQDateTime &to )
|
|
|
|
{
|
|
|
|
TQDateTime preTime = from.addSecs(-1);
|
|
|
|
Alarm::List::ConstIterator it;
|
|
|
|
for( it = incidence->alarms().begin(); it != incidence->alarms().end();
|
|
|
|
++it ) {
|
|
|
|
Alarm *alarm = *it;
|
|
|
|
if ( alarm->enabled() ) {
|
|
|
|
TQDateTime dt = alarm->nextRepetition( preTime );
|
|
|
|
if ( dt.isValid() && dt <= to ) {
|
|
|
|
kdDebug(5800) << "CalendarLocal::appendAlarms() '"
|
|
|
|
<< incidence->summary() << "': "
|
|
|
|
<< dt.toString() << endl;
|
|
|
|
alarms.append( alarm );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CalendarLocal::appendRecurringAlarms( Alarm::List &alarms,
|
|
|
|
Incidence *incidence,
|
|
|
|
const TQDateTime &from,
|
|
|
|
const TQDateTime &to )
|
|
|
|
{
|
|
|
|
TQDateTime dt;
|
|
|
|
Duration endOffset( 0 );
|
|
|
|
bool endOffsetValid = false;
|
|
|
|
Duration period( from, to );
|
|
|
|
|
|
|
|
Event *e = static_cast<Event *>( incidence );
|
|
|
|
Todo *t = static_cast<Todo *>( incidence );
|
|
|
|
|
|
|
|
Alarm::List::ConstIterator it;
|
|
|
|
for( it = incidence->alarms().begin(); it != incidence->alarms().end();
|
|
|
|
++it ) {
|
|
|
|
Alarm *alarm = *it;
|
|
|
|
if ( alarm->enabled() ) {
|
|
|
|
if ( alarm->hasTime() ) {
|
|
|
|
// The alarm time is defined as an absolute date/time
|
|
|
|
dt = alarm->nextRepetition( from.addSecs(-1) );
|
|
|
|
if ( !dt.isValid() || dt > to ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Alarm time is defined by an offset from the event start or end time.
|
|
|
|
// Find the offset from the event start time, which is also used as the
|
|
|
|
// offset from the recurrence time.
|
|
|
|
Duration offset( 0 );
|
|
|
|
if ( alarm->hasStartOffset() ) {
|
|
|
|
offset = alarm->startOffset().asSeconds();
|
|
|
|
} else if ( alarm->hasEndOffset() ) {
|
|
|
|
offset = alarm->endOffset().asSeconds();
|
|
|
|
if ( !endOffsetValid ) {
|
|
|
|
if ( incidence->type() == "Event" ) {
|
|
|
|
endOffset = Duration( e->dtStart(), e->dtEnd() );
|
|
|
|
endOffsetValid = true;
|
|
|
|
} else if ( incidence->type() == "Todo" &&
|
|
|
|
t->hasStartDate() && t->hasDueDate() ) {
|
|
|
|
endOffset = Duration( t->dtStart(), t->dtDue() );
|
|
|
|
endOffsetValid = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the incidence's earliest alarm
|
|
|
|
TQDateTime alarmStart;
|
|
|
|
if ( incidence->type() == "Event" ) {
|
|
|
|
alarmStart =
|
|
|
|
offset.end( alarm->hasEndOffset() ? e->dtEnd() : e->dtStart() );
|
|
|
|
} else if ( incidence->type() == "Todo" ) {
|
|
|
|
alarmStart =
|
|
|
|
offset.end( alarm->hasEndOffset() ? t->dtDue() : t->dtStart() );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( alarmStart.isValid() && alarmStart > to ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDateTime baseStart;
|
|
|
|
if ( incidence->type() == "Event" ) {
|
|
|
|
baseStart = e->dtStart();
|
|
|
|
} else if ( incidence->type() == "Todo" ) {
|
|
|
|
baseStart = t->dtDue();
|
|
|
|
}
|
|
|
|
if ( alarmStart.isValid() && from > alarmStart ) {
|
|
|
|
alarmStart = from; // don't look earlier than the earliest alarm
|
|
|
|
baseStart = (-offset).end( (-endOffset).end( alarmStart ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Adjust the 'alarmStart' date/time and find the next recurrence
|
|
|
|
// at or after it. Treat the two offsets separately in case one
|
|
|
|
// is daily and the other not.
|
|
|
|
dt = incidence->recurrence()->getNextDateTime( baseStart.addSecs(-1) );
|
|
|
|
if ( !dt.isValid() ||
|
|
|
|
( dt = endOffset.end( offset.end( dt ) ) ) > to ) // adjust 'dt' to get the alarm time
|
|
|
|
{
|
|
|
|
// The next recurrence is too late.
|
|
|
|
if ( !alarm->repeatCount() ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The alarm has repetitions, so check whether repetitions of
|
|
|
|
// previous recurrences fall within the time period.
|
|
|
|
bool found = false;
|
|
|
|
Duration alarmDuration = alarm->duration();
|
|
|
|
for ( TQDateTime base = baseStart;
|
|
|
|
( dt = incidence->recurrence()->getPreviousDateTime( base ) ).isValid();
|
|
|
|
base = dt ) {
|
|
|
|
if ( alarm->duration().end( dt ) < base ) {
|
|
|
|
break; // recurrence's last repetition is too early, so give up
|
|
|
|
}
|
|
|
|
|
|
|
|
// The last repetition of this recurrence is on or after
|
|
|
|
// 'alarmStart' time. Check if a repetition occurs between
|
|
|
|
// 'alarmStart' and 'to'.
|
|
|
|
int snooze = alarm->snoozeTime().value(); // in seconds or days
|
|
|
|
if ( alarm->snoozeTime().isDaily() ) {
|
|
|
|
Duration toFromDuration( dt, base );
|
|
|
|
int toFrom = toFromDuration.asDays();
|
|
|
|
if ( alarm->snoozeTime().end( from ) <= to ||
|
|
|
|
( toFromDuration.isDaily() && toFrom % snooze == 0 ) ||
|
|
|
|
( toFrom / snooze + 1 ) * snooze <= toFrom + period.asDays() ) {
|
|
|
|
found = true;
|
|
|
|
#ifndef NDEBUG
|
|
|
|
// for debug output
|
|
|
|
dt = offset.end( dt ).addDays( ( ( toFrom - 1 ) / snooze + 1 ) * snooze );
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
int toFrom = dt.secsTo( base );
|
|
|
|
if ( period.asSeconds() >= snooze ||
|
|
|
|
toFrom % snooze == 0 ||
|
|
|
|
( toFrom / snooze + 1 ) * snooze <= toFrom + period.asSeconds() )
|
|
|
|
{
|
|
|
|
found = true;
|
|
|
|
#ifndef NDEBUG
|
|
|
|
// for debug output
|
|
|
|
dt = offset.end( dt ).addSecs( ( ( toFrom - 1 ) / snooze + 1 ) * snooze );
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !found ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
kdDebug(5800) << "CalendarLocal::appendAlarms() '" << incidence->summary()
|
|
|
|
<< "': " << dt.toString() << endl;
|
|
|
|
alarms.append( alarm );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CalendarLocal::incidenceUpdated( IncidenceBase *incidence )
|
|
|
|
{
|
|
|
|
incidence->setSyncStatusSilent( Event::SYNCMOD );
|
|
|
|
incidence->setLastModified( TQDateTime::currentDateTime() );
|
|
|
|
// we should probably update the revision number here,
|
|
|
|
// or internally in the Event itself when certain things change.
|
|
|
|
// need to verify with ical documentation.
|
|
|
|
|
|
|
|
// The static_cast is ok as the CalendarLocal only observes Incidence objects
|
|
|
|
notifyIncidenceChanged( static_cast<Incidence *>( incidence ) );
|
|
|
|
|
|
|
|
setModified( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CalendarLocal::insertEvent( Event *event )
|
|
|
|
{
|
|
|
|
TQString uid = event->uid();
|
|
|
|
if ( mEvents[ uid ] == 0 ) {
|
|
|
|
mEvents.insert( uid, event );
|
|
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
|
|
else // if we already have an event with this UID, it has to be the same event,
|
|
|
|
// otherwise something's really broken
|
|
|
|
Q_ASSERT( mEvents[uid] == event );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
Event::List CalendarLocal::rawEventsForDate( const TQDate &qd,
|
|
|
|
EventSortField sortField,
|
|
|
|
SortDirection sortDirection )
|
|
|
|
{
|
|
|
|
Event::List eventList;
|
|
|
|
|
|
|
|
EventDictIterator it( mEvents );
|
|
|
|
for( ; it.current(); ++it ) {
|
|
|
|
Event *event = *it;
|
|
|
|
|
|
|
|
if ( event->doesRecur() ) {
|
|
|
|
if ( event->isMultiDay() ) {
|
|
|
|
int extraDays = event->dtStart().date().daysTo( event->dtEnd().date() );
|
|
|
|
int i;
|
|
|
|
for ( i = 0; i <= extraDays; i++ ) {
|
|
|
|
if ( event->recursOn( qd.addDays( -i ), this ) ) {
|
|
|
|
eventList.append( event );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( event->recursOn( qd, this ) )
|
|
|
|
eventList.append( event );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( event->dtStart().date() <= qd && event->dateEnd() >= qd ) {
|
|
|
|
eventList.append( event );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return sortEventsForDate( &eventList, qd, sortField, sortDirection );
|
|
|
|
}
|
|
|
|
|
|
|
|
Event::List CalendarLocal::rawEvents( const TQDate &start, const TQDate &end,
|
|
|
|
bool inclusive )
|
|
|
|
{
|
|
|
|
Event::List eventList;
|
|
|
|
TQDate yesterStart = start.addDays(-1);
|
|
|
|
|
|
|
|
// Get non-recurring events
|
|
|
|
EventDictIterator it( mEvents );
|
|
|
|
for( ; it.current(); ++it ) {
|
|
|
|
Event *event = *it;
|
|
|
|
|
|
|
|
TQDate rStart = event->dtStart().date();
|
|
|
|
if (end < rStart) {
|
|
|
|
// kdDebug(5800) << "Skipping event starting after TOI" << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ( inclusive && rStart < start) {
|
|
|
|
// kdDebug(5800) << "Skipping event starting before TOI while inclusive" << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! event->doesRecur() ) { // non-recurring events
|
|
|
|
TQDate rEnd = event->dtEnd().date();
|
|
|
|
if (rEnd < start) {
|
|
|
|
// kdDebug(5800) << "Skipping event ending before TOI" << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ( inclusive && end < rEnd ) {
|
|
|
|
// kdDebug(5800) << "Skipping event ending after TOI while inclusive" << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else { // recurring events
|
|
|
|
switch ( event->recurrence()->duration() ) {
|
|
|
|
case -1: // infinite
|
|
|
|
if ( inclusive ) {
|
|
|
|
// kdDebug(5800) << "Skipping infinite event because inclusive" << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0: // end date given
|
|
|
|
default: // count given
|
|
|
|
TQDate rEnd = event->recurrence()->endDate();
|
|
|
|
if ( ! rEnd.isValid() ) {
|
|
|
|
// kdDebug(5800) << "Skipping recurring event without occurences" << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ( rEnd < start ) {
|
|
|
|
// kdDebug(5800) << "Skipping recurring event ending before TOI" << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ( inclusive && end < rEnd ) {
|
|
|
|
// kdDebug(5800) << "Skipping recurring event ending after TOI while inclusive" << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* FIXME: too much conversion between TQDate and TQDateTime makes this useless:
|
|
|
|
* freebusy(end=TQDateTime(day, "00:00:00")) ->
|
|
|
|
* rawEvents(end=TQDate(day)) ->
|
|
|
|
* durationTo(TQDateTime(day, "23:59:59"))
|
|
|
|
* so events repeating at the end day match and are included.
|
|
|
|
*/
|
|
|
|
#if 0
|
|
|
|
int durationBeforeStart = event->recurrence()->durationTo(yesterStart);
|
|
|
|
int durationUntilEnd = event->recurrence()->durationTo(end);
|
|
|
|
if (durationBeforeStart == durationUntilEnd) {
|
|
|
|
kdDebug(5800) << "Skipping recurring event without occurences in TOI" << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
} // switch(duration)
|
|
|
|
} // if(doesRecur)
|
|
|
|
|
|
|
|
eventList.append( event );
|
|
|
|
}
|
|
|
|
|
|
|
|
return eventList;
|
|
|
|
}
|
|
|
|
|
|
|
|
Event::List CalendarLocal::rawEventsForDate( const TQDateTime &qdt )
|
|
|
|
{
|
|
|
|
return rawEventsForDate( qdt.date() );
|
|
|
|
}
|
|
|
|
|
|
|
|
Event::List CalendarLocal::rawEvents( EventSortField sortField, SortDirection sortDirection )
|
|
|
|
{
|
|
|
|
Event::List eventList;
|
|
|
|
EventDictIterator it( mEvents );
|
|
|
|
for( ; it.current(); ++it )
|
|
|
|
eventList.append( *it );
|
|
|
|
return sortEvents( &eventList, sortField, sortDirection );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CalendarLocal::addJournal(Journal *journal)
|
|
|
|
{
|
|
|
|
// if (journal->dtStart().isValid())
|
|
|
|
// kdDebug(5800) << "Adding Journal on " << journal->dtStart().toString() << endl;
|
|
|
|
// else
|
|
|
|
// kdDebug(5800) << "Adding Journal without a DTSTART" << endl;
|
|
|
|
|
|
|
|
mJournalList.append(journal);
|
|
|
|
|
|
|
|
journal->registerObserver( this );
|
|
|
|
|
|
|
|
setModified( true );
|
|
|
|
|
|
|
|
notifyIncidenceAdded( journal );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CalendarLocal::deleteJournal( Journal *journal )
|
|
|
|
{
|
|
|
|
if ( mJournalList.removeRef( journal ) ) {
|
|
|
|
setModified( true );
|
|
|
|
notifyIncidenceDeleted( journal );
|
|
|
|
mDeletedIncidences.append( journal );
|
|
|
|
// Delete child journals
|
|
|
|
if (!journal->hasRecurrenceID()) {
|
|
|
|
deleteChildJournals(journal);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
kdWarning() << "CalendarLocal::deleteJournal(): Journal not found." << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CalendarLocal::deleteChildJournals( Journal *journal )
|
|
|
|
{
|
|
|
|
Journal::List::ConstIterator it;
|
|
|
|
for( it = mJournalList.begin(); it != mJournalList.end(); ++it ) {
|
|
|
|
Journal *j = *it;
|
|
|
|
if (j->uid() == journal->uid()) {
|
|
|
|
if ( j->hasRecurrenceID() ) {
|
|
|
|
deleteJournal(( j ));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CalendarLocal::deleteAllJournals()
|
|
|
|
{
|
|
|
|
Journal::List::ConstIterator it;
|
|
|
|
for( it = mJournalList.begin(); it != mJournalList.end(); ++it ) {
|
|
|
|
notifyIncidenceDeleted( *it );
|
|
|
|
}
|
|
|
|
|
|
|
|
mJournalList.setAutoDelete( true );
|
|
|
|
mJournalList.clearAll();
|
|
|
|
mJournalList.setAutoDelete( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
Journal *CalendarLocal::journal( const TQString &uid )
|
|
|
|
{
|
|
|
|
Journal::List::ConstIterator it;
|
|
|
|
for ( it = mJournalList.begin(); it != mJournalList.end(); ++it )
|
|
|
|
if ( (*it)->uid() == uid )
|
|
|
|
return *it;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Journal::List CalendarLocal::rawJournals( JournalSortField sortField, SortDirection sortDirection )
|
|
|
|
{
|
|
|
|
return sortJournals( &mJournalList, sortField, sortDirection );
|
|
|
|
}
|
|
|
|
|
|
|
|
Journal::List CalendarLocal::rawJournalsForDate( const TQDate &date )
|
|
|
|
{
|
|
|
|
Journal::List journals;
|
|
|
|
|
|
|
|
Journal::List::ConstIterator it;
|
|
|
|
for ( it = mJournalList.begin(); it != mJournalList.end(); ++it ) {
|
|
|
|
Journal *journal = *it;
|
|
|
|
if ( journal->dtStart().date() == date ) {
|
|
|
|
journals.append( journal );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return journals;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CalendarLocal::setTimeZoneIdViewOnly( const TQString& tz )
|
|
|
|
{
|
|
|
|
const TQString question( i18n("The timezone setting was changed. In order to display the calendar "
|
|
|
|
"you are looking at in the new timezone, it needs to be saved. Do you want to save the pending "
|
|
|
|
"changes or rather wait and apply the new timezone on the next reload?" ) );
|
|
|
|
int rc = KMessageBox::Yes;
|
|
|
|
if ( isModified() ) {
|
|
|
|
rc = KMessageBox::questionYesNo( 0, question,
|
|
|
|
i18n("Save before applying timezones?"),
|
|
|
|
KStdGuiItem::save(),
|
|
|
|
KGuiItem(i18n("Apply Timezone Change on Next Reload")),
|
|
|
|
"calendarLocalSaveBeforeTimezoneShift");
|
|
|
|
}
|
|
|
|
if ( rc == KMessageBox::Yes ) {
|
|
|
|
reload( tz );
|
|
|
|
}
|
|
|
|
}
|