libkcal Library API Documentation

calendar.cpp

00001 /*
00002     This file is part of libkcal.
00003 
00004     Copyright (c) 1998 Preston Brown
00005     Copyright (c) 2000-2004 Cornelius Schumacher <schumacher@kde.org>
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Library General Public
00009     License as published by the Free Software Foundation; either
00010     version 2 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Library General Public License for more details.
00016 
00017     You should have received a copy of the GNU Library General Public License
00018     along with this library; see the file COPYING.LIB.  If not, write to
00019     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020     Boston, MA 02111-1307, USA.
00021 */
00022 
00023 #include <stdlib.h>
00024 
00025 #include <kdebug.h>
00026 #include <klocale.h>
00027 
00028 #include "exceptions.h"
00029 #include "calfilter.h"
00030 
00031 #include "calendar.h"
00032 
00033 using namespace KCal;
00034 
00035 Calendar::Calendar()
00036 {
00037   mTimeZoneId = QString::fromLatin1( "UTC" );
00038   mLocalTime = false;
00039 
00040   init();
00041 }
00042 
00043 Calendar::Calendar( const QString &timeZoneId )
00044 {
00045   mTimeZoneId = timeZoneId;
00046   mLocalTime = false;
00047 
00048   init();
00049 }
00050 
00051 void Calendar::init()
00052 {
00053   mNewObserver = false;
00054   mObserversEnabled = true;
00055 
00056   mModified = false;
00057 
00058   // Setup default filter, which does nothing
00059   mDefaultFilter = new CalFilter;
00060   mFilter = mDefaultFilter;
00061   mFilter->setEnabled(false);
00062 
00063   // initialize random numbers.  This is a hack, and not
00064   // even that good of one at that.
00065 //  srandom(time(0));
00066 
00067   // user information...
00068   setOwner(i18n("Unknown Name"));
00069   setEmail(i18n("unknown@nowhere"));
00070 
00071 #if 0
00072   tmpStr = KOPrefs::instance()->mTimeZone;
00073 //  kdDebug(5800) << "Calendar::Calendar(): TimeZone: " << tmpStr << endl;
00074   int dstSetting = KOPrefs::instance()->mDaylightSavings;
00075   extern long int timezone;
00076   struct tm *now;
00077   time_t curtime;
00078   curtime = time(0);
00079   now = localtime(&curtime);
00080   int hourOff = - ((timezone / 60) / 60);
00081   if (now->tm_isdst)
00082     hourOff += 1;
00083   QString tzStr;
00084   tzStr.sprintf("%.2d%.2d",
00085         hourOff,
00086         abs((timezone / 60) % 60));
00087 
00088   // if no time zone was in the config file, write what we just discovered.
00089   if (tmpStr.isEmpty()) {
00090 //    KOPrefs::instance()->mTimeZone = tzStr;
00091   } else {
00092     tzStr = tmpStr;
00093   }
00094 
00095   // if daylight savings has changed since last load time, we need
00096   // to rewrite these settings to the config file.
00097   if ((now->tm_isdst && !dstSetting) ||
00098       (!now->tm_isdst && dstSetting)) {
00099     KOPrefs::instance()->mTimeZone = tzStr;
00100     KOPrefs::instance()->mDaylightSavings = now->tm_isdst;
00101   }
00102 
00103   setTimeZone(tzStr);
00104 #endif
00105 
00106 //  KOPrefs::instance()->writeConfig();
00107 }
00108 
00109 Calendar::~Calendar()
00110 {
00111   delete mDefaultFilter;
00112 }
00113 
00114 const QString &Calendar::getOwner() const
00115 {
00116   return mOwner;
00117 }
00118 
00119 void Calendar::setOwner(const QString &os)
00120 {
00121   int i;
00122   mOwner = os;
00123   i = mOwner.find(',');
00124   if (i != -1)
00125     mOwner = mOwner.left(i);
00126 
00127   setModified( true );
00128 }
00129 
00130 void Calendar::setTimeZoneId(const QString &id)
00131 {
00132   mTimeZoneId = id;
00133   mLocalTime = false;
00134 
00135   setModified( true );
00136   doSetTimeZoneId( id );
00137 }
00138 
00139 QString Calendar::timeZoneId() const
00140 {
00141   return mTimeZoneId;
00142 }
00143 
00144 void Calendar::setLocalTime()
00145 {
00146   mLocalTime = true;
00147   mTimeZone = 0;
00148   mTimeZoneId = "";
00149 
00150   setModified( true );
00151 }
00152 
00153 bool Calendar::isLocalTime() const
00154 {
00155   return mLocalTime;
00156 }
00157 
00158 const QString &Calendar::getEmail()
00159 {
00160   return mOwnerEmail;
00161 }
00162 
00163 void Calendar::setEmail(const QString &e)
00164 {
00165   mOwnerEmail = e;
00166 
00167   setModified( true );
00168 }
00169 
00170 void Calendar::setFilter(CalFilter *filter)
00171 {
00172   mFilter = filter;
00173 }
00174 
00175 CalFilter *Calendar::filter()
00176 {
00177   return mFilter;
00178 }
00179 
00180 QStringList Calendar::incidenceCategories()
00181 {
00182   Incidence::List rawInc( rawIncidences() );
00183   QStringList categories, thisCats;
00184   // TODO: For now just iterate over all incidences. In the future, 
00185   // the list of categories should be built when reading the file.
00186   for ( Incidence::List::ConstIterator i = rawInc.constBegin(); i != rawInc.constEnd(); ++i ) {
00187     thisCats = (*i)->categories();
00188     for ( QStringList::ConstIterator si = thisCats.constBegin(); si != thisCats.constEnd(); ++si ) {
00189       if ( categories.find( *si ) == categories.end() ) {
00190         categories.append( *si );
00191       }
00192     }
00193   }
00194   return categories;
00195 }
00196 
00197 Incidence::List Calendar::incidences( const QDate &qdt )
00198 {
00199   Journal::List jnls;
00200   Journal*jnl = journal(qdt);
00201   if (jnl) jnls.append( journal(qdt) );
00202   return mergeIncidenceList( events( qdt ), todos( qdt ), jnls );
00203 }
00204 
00205 Incidence::List Calendar::incidences()
00206 {
00207   return mergeIncidenceList( events(), todos(), journals() );
00208 }
00209 
00210 Incidence::List Calendar::rawIncidences()
00211 {
00212   return mergeIncidenceList( rawEvents(), rawTodos(), journals() );
00213 }
00214 
00215 Event::List Calendar::events( const QDate &date, bool sorted )
00216 {
00217   Event::List el = rawEventsForDate( date, sorted );
00218 
00219   mFilter->apply(&el);
00220 
00221   return el;
00222 }
00223 
00224 Event::List Calendar::events( const QDateTime &qdt )
00225 {
00226   Event::List el = rawEventsForDate(qdt);
00227   mFilter->apply(&el);
00228   return el;
00229 }
00230 
00231 Event::List Calendar::events( const QDate &start, const QDate &end,
00232                                   bool inclusive)
00233 {
00234   Event::List el = rawEvents(start,end,inclusive);
00235   mFilter->apply(&el);
00236   return el;
00237 }
00238 
00239 Event::List Calendar::events()
00240 {
00241   Event::List el = rawEvents();
00242   mFilter->apply(&el);
00243   return el;
00244 }
00245 
00246 
00247 bool Calendar::addIncidence(Incidence *i)
00248 {
00249   Incidence::AddVisitor<Calendar> v(this);
00250 
00251   return i->accept(v);
00252 }
00253 
00254 bool Calendar::deleteIncidence( Incidence *i )
00255 {
00256   Incidence::DeleteVisitor<Calendar> v( this );
00257   return i->accept( v );
00258 }
00259 
00260 Incidence *Calendar::dissociateOccurrence( Incidence *incidence, QDate date,
00261                                            bool single )
00262 {
00263   if ( !incidence || !incidence->doesRecur() ) return 0;
00264   
00265   Incidence *newInc = incidence->clone();
00266   newInc->recreate();
00267   newInc->setRelatedTo( incidence );
00268   Recurrence *recur = newInc->recurrence();
00269   if ( single ) {
00270     recur->unsetRecurs();
00271   } else {
00272     // Adjust the recurrence for the future incidences. In particular
00273     // adjust the "end after n occurences" rules! "No end date" and "end by ..."
00274     // don't need to be modified.
00275     int duration = recur->duration();
00276     if ( duration > 0 ) {
00277       int doneduration = recur->durationTo( date.addDays(-1) );
00278       if ( doneduration >= duration ) {
00279         kdDebug(5850) << "The dissociated event already occured more often that it was supposed to ever occur. ERROR!" << endl;
00280         recur->unsetRecurs();
00281       } else {
00282         recur->setDuration( duration - doneduration );
00283       }
00284     }
00285   }
00286   // Adjust the date of the incidence
00287   if ( incidence->type() == "Event" ) {
00288     Event *ev = static_cast<Event *>( newInc );
00289     QDateTime start( ev->dtStart() );
00290     int daysTo = start.date().daysTo( date );
00291     ev->setDtStart( start.addDays( daysTo ) );
00292     ev->setDtEnd( ev->dtEnd().addDays( daysTo ) );    
00293   } else if ( incidence->type() == "Todo" ) {
00294     Todo *td = static_cast<Todo *>( newInc );
00295     bool haveOffset = false;
00296     int daysTo = 0;
00297     if ( td->hasDueDate() ) {
00298       QDateTime due( td->dtDue() );
00299       daysTo = due.date().daysTo( date ) ;
00300       td->setDtDue( due.addDays( daysTo ) );
00301       haveOffset = true;
00302     }
00303     if ( td->hasStartDate() ) {
00304       QDateTime start( td->dtStart() );
00305       if ( !haveOffset ) daysTo = start.date().daysTo( date );
00306       td->setDtStart( start.addDays( daysTo ) );
00307       haveOffset = true;
00308     }
00309   }
00310   if ( addIncidence( newInc ) ) {
00311     if (single) {
00312       incidence->addExDate( date );
00313     } else {
00314       recur = incidence->recurrence();
00315       if ( recur ) {
00316         // Make sure the recurrence of the past events ends at the corresponding day
00317         recur->setEndDate( date.addDays(-1) );
00318       }
00319     }
00320   } else {
00321     delete newInc;
00322     return 0;
00323   }
00324   return newInc;
00325 }
00326 
00327 Incidence *Calendar::incidence( const QString& uid )
00328 {
00329   Incidence *i = event( uid );
00330   if ( i ) return i;
00331   i = todo( uid );
00332   if ( i ) return i;
00333   i = journal( uid );
00334   return i;
00335 }
00336 
00337 Todo::List Calendar::todos()
00338 {
00339   Todo::List tl = rawTodos();
00340   mFilter->apply( &tl );
00341   return tl;
00342 }
00343 
00344 Todo::List Calendar::todos( const QDate &date )
00345 {
00346   Todo::List el = rawTodosForDate( date );
00347 
00348   mFilter->apply(&el);
00349 
00350   return el;
00351 }
00352 
00353 
00354 // When this is called, the todo have already been added to the calendar.
00355 // This method is only about linking related todos
00356 void Calendar::setupRelations( Incidence *incidence )
00357 {
00358   QString uid = incidence->uid();
00359 
00360   // First, go over the list of orphans and see if this is their parent
00361   while( Incidence* i = mOrphans[ uid ] ) {
00362     mOrphans.remove( uid );
00363     i->setRelatedTo( incidence );
00364     incidence->addRelation( i );
00365     mOrphanUids.remove( i->uid() );
00366   }
00367 
00368   // Now see about this incidences parent
00369   if( !incidence->relatedTo() && !incidence->relatedToUid().isEmpty() ) {
00370     // This incidence has a uid it is related to, but is not registered to it yet
00371     // Try to find it
00372     Incidence* parent = this->incidence( incidence->relatedToUid() );
00373     if( parent ) {
00374       // Found it
00375       incidence->setRelatedTo( parent );
00376       parent->addRelation( incidence );
00377     } else {
00378       // Not found, put this in the mOrphans list
00379       mOrphans.insert( incidence->relatedToUid(), incidence );
00380       mOrphanUids.insert( incidence->uid(), incidence );
00381     }
00382   }
00383 }
00384 
00385 // If a task with subtasks is deleted, move it's subtasks to the orphans list
00386 void Calendar::removeRelations( Incidence *incidence )
00387 {
00388   if( !incidence ) {
00389     kdDebug(5800) << "Warning: Calendar::removeRelations( 0 )!\n";
00390     return;
00391   }
00392 
00393   QString uid = incidence->uid();
00394 
00395   Incidence::List relations = incidence->relations();
00396   Incidence::List::ConstIterator it;
00397   for( it = relations.begin(); it != relations.end(); ++it ) {
00398     Incidence *i = *it;
00399     if( !mOrphanUids.find( i->uid() ) ) {
00400       mOrphans.insert( uid, i );
00401       mOrphanUids.insert( i->uid(), i );
00402       i->setRelatedTo( 0 );
00403       i->setRelatedToUid( uid );
00404     }
00405   }
00406 
00407   // If this incidence is related to something else, tell that about it
00408   if( incidence->relatedTo() )
00409     incidence->relatedTo()->removeRelation( incidence );
00410 
00411   // Remove this one from the orphans list
00412   if( mOrphanUids.remove( uid ) )
00413     // This incidence is located in the orphans list - it should be removed
00414     if( !( incidence->relatedTo() != 0 && mOrphans.remove( incidence->relatedTo()->uid() ) ) ) {
00415       // Removing wasn't that easy
00416       for( QDictIterator<Incidence> it( mOrphans ); it.current(); ++it ) {
00417     if( it.current()->uid() == uid ) {
00418       mOrphans.remove( it.currentKey() );
00419       break;
00420     }
00421       }
00422     }
00423 }
00424 
00425 void Calendar::registerObserver( Observer *observer )
00426 {
00427   if( !mObservers.contains( observer ) ) mObservers.append( observer );
00428   mNewObserver = true;
00429 }
00430 
00431 void Calendar::unregisterObserver( Observer *observer )
00432 {
00433   mObservers.remove( observer );
00434 }
00435 
00436 void Calendar::setModified( bool modified )
00437 {
00438   if ( modified != mModified || mNewObserver ) {
00439     mNewObserver = false;
00440     Observer *observer;
00441     for( observer = mObservers.first(); observer;
00442          observer = mObservers.next() ) {
00443       observer->calendarModified( modified, this );
00444     }
00445     mModified = modified;
00446   }
00447 }
00448 
00449 void Calendar::notifyIncidenceAdded( Incidence *i )
00450 {
00451   if ( !mObserversEnabled ) return;
00452 
00453   Observer *observer;
00454   for( observer = mObservers.first(); observer;
00455        observer = mObservers.next() ) {
00456     observer->calendarIncidenceAdded( i );
00457   }
00458 }
00459 
00460 void Calendar::notifyIncidenceChanged( Incidence *i )
00461 {
00462   if ( !mObserversEnabled ) return;
00463 
00464   Observer *observer;
00465   for( observer = mObservers.first(); observer;
00466        observer = mObservers.next() ) {
00467     observer->calendarIncidenceChanged( i );
00468   }
00469 }
00470 
00471 void Calendar::notifyIncidenceDeleted( Incidence *i )
00472 {
00473   if ( !mObserversEnabled ) return;
00474 
00475   Observer *observer;
00476   for( observer = mObservers.first(); observer;
00477        observer = mObservers.next() ) {
00478     observer->calendarIncidenceDeleted( i );
00479   }
00480 }
00481 
00482 void Calendar::setLoadedProductId( const QString &id )
00483 {
00484   mLoadedProductId = id;
00485 }
00486 
00487 QString Calendar::loadedProductId()
00488 {
00489   return mLoadedProductId;
00490 }
00491 
00492 Incidence::List Calendar::mergeIncidenceList( const Event::List &e,
00493                                               const Todo::List &t,
00494                                               const Journal::List &j )
00495 {
00496   Incidence::List incidences;
00497   
00498   Event::List::ConstIterator it1;
00499   for( it1 = e.begin(); it1 != e.end(); ++it1 ) incidences.append( *it1 );
00500 
00501   Todo::List::ConstIterator it2;
00502   for( it2 = t.begin(); it2 != t.end(); ++it2 ) incidences.append( *it2 );
00503 
00504   Journal::List::ConstIterator it3;
00505   for( it3 = j.begin(); it3 != j.end(); ++it3 ) incidences.append( *it3 );
00506 
00507   return incidences;
00508 }
00509 
00510 bool Calendar::beginChange( Incidence * )
00511 {
00512   return true;
00513 }
00514 
00515 bool Calendar::endChange( Incidence * )
00516 {
00517   return true;
00518 }
00519 
00520 void Calendar::setObserversEnabled( bool enabled )
00521 {
00522   mObserversEnabled = enabled;
00523 }
00524 
00525 #include "calendar.moc"
KDE Logo
This file is part of the documentation for libkcal Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Apr 4 04:45:02 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003