kpilot Library API Documentation

todo-conduit.cc

00001 /* todo-conduit.cc  Todo-Conduit for syncing KPilot and KOrganizer
00002 **
00003 ** Copyright (C) 2002 Reinhold Kainhofer
00004 ** Copyright (C) 1998-2001 Dan Pilone
00005 ** Copyright (C) 1998-2000 Preston Brown
00006 ** Copyright (C) 1998 Herwin-Jan Steehouwer
00007 ** Copyright (C) 2001 Cornelius Schumacher
00008 **
00009 ** This file is part of the todo conduit, a conduit for KPilot that
00010 ** synchronises the Pilot's todo application with the outside world,
00011 ** which currently means KOrganizer.
00012 */
00013 
00014 /*
00015 ** This program is free software; you can redistribute it and/or modify
00016 ** it under the terms of the GNU General Public License as published by
00017 ** the Free Software Foundation; either version 2 of the License, or
00018 ** (at your option) any later version.
00019 **
00020 ** This program is distributed in the hope that it will be useful,
00021 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00023 ** GNU General Public License for more details.
00024 **
00025 ** You should have received a copy of the GNU General Public License
00026 ** along with this program in a file called COPYING; if not, write to
00027 ** the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00028 ** MA 02111-1307, USA.
00029 */
00030 
00031 /*
00032 ** Bug reports and questions can be sent to kde-pim@kde.org
00033 */
00034 
00035 static const char *TodoConduit_id = "$Id: todo-conduit.cc,v 1.24.4.7 2003/03/12 23:31:13 adridg Exp $";
00036 
00037 #include <options.h>
00038 #include <unistd.h>
00039 
00040 #include <qdatetime.h>
00041 #include <qtimer.h>
00042 #include <qtextcodec.h>
00043 
00044 #include <kconfig.h>
00045 
00046 // libkcal includes
00047 #include "libkcal/calendarlocal.h"
00048 #include "libkcal/todo.h"
00049 
00050 #include "pilotUser.h"
00051 
00052 /*
00053 ** KDE 2.2 uses class KORecurrence in a different header file.
00054 */
00055 #ifdef KDE2
00056 #define DateList_t QDateList
00057 #define DateListIterator_t QDateListIterator
00058 #else
00059 #define DateList_t KCal::DateList
00060 #define DateListIterator_t KCal::DateList::ConstIterator
00061 #endif
00062 
00063 #include "pilotSerialDatabase.h"
00064 #include "pilotLocalDatabase.h"
00065 //#include <pilotTodoEntry.h>
00066 
00067 //#include "vcal-conduitbase.h"
00068 //#include "todo-factory.h"
00069 #include "todo-conduit.moc"
00070 
00071 // define conduit versions, one for the version when categories were synced for the first time, and the current version number
00072 #define CONDUIT_VERSION_CATEGORYSYNC 10
00073 #define CONDUIT_VERSION 10
00074 
00075 
00076 
00077 TodoConduitPrivate::TodoConduitPrivate(KCal::CalendarLocal *b) :
00078         VCalConduitPrivateBase(b)
00079 {
00080         fAllTodos.setAutoDelete(false);
00081 }
00082 
00083 void TodoConduitPrivate::addIncidence(KCal::Incidence*e)
00084 {
00085         fAllTodos.append(static_cast<KCal::Todo*>(e));
00086         fCalendar->addTodo(static_cast<KCal::Todo*>(e));
00087 }
00088 
00089 int TodoConduitPrivate::updateIncidences()
00090 {
00091         fAllTodos = fCalendar->todos();
00092         fAllTodos.setAutoDelete(false);
00093         return fAllTodos.count();
00094 }
00095 
00096 
00097 void TodoConduitPrivate::removeIncidence(KCal::Incidence *e)
00098 {
00099         fAllTodos.remove(static_cast<KCal::Todo*>(e));
00100         fCalendar->deleteTodo(static_cast<KCal::Todo*>(e));
00101 }
00102 
00103 
00104 
00105 KCal::Incidence *TodoConduitPrivate::findIncidence(recordid_t id)
00106 {
00107         KCal::Todo *todo = fAllTodos.first();
00108         while(todo)
00109         {
00110                 if ((recordid_t)(todo->pilotId()) == id) return todo;
00111                 todo = fAllTodos.next();
00112         }
00113 
00114         return 0L;
00115 }
00116 
00117 
00118 
00119 KCal::Incidence *TodoConduitPrivate::findIncidence(PilotAppCategory*tosearch)
00120 {
00121         PilotTodoEntry*entry=dynamic_cast<PilotTodoEntry*>(tosearch);
00122         if (!entry) return 0L;
00123         
00124         QString title=entry->getDescription();
00125         QDateTime dt=readTm( entry->getDueDate() );
00126         
00127         KCal::Todo *event = fAllTodos.first();
00128         while (event!=0)
00129         {
00130                 if ( (event->dtDue().date() == dt.date()) && (event->summary() == title) ) return event;
00131                 event = fAllTodos.next();
00132         }
00133         return 0L;
00134 }
00135 
00136 
00137 
00138 KCal::Incidence *TodoConduitPrivate::getNextIncidence()
00139 {
00140         if (reading) return fAllTodos.next();
00141         reading=true;
00142         return fAllTodos.first();
00143 }
00144 
00145 
00146 
00147 KCal::Incidence *TodoConduitPrivate::getNextModifiedIncidence()
00148 {
00149 FUNCTIONSETUP;
00150         KCal::Todo*e=0L;
00151         if (!reading)
00152         {
00153                 reading=true;
00154                 e=fAllTodos.first();
00155         }
00156         else
00157         {
00158                 e=fAllTodos.next();
00159         }
00160         while (e && e->syncStatus()!=KCal::Incidence::SYNCMOD)
00161         {
00162                 e=fAllTodos.next();
00163 #ifdef DEBUG
00164 if (e)
00165 DEBUGCONDUIT<< e->summary()<<" had SyncStatus="<<e->syncStatus()<<endl;
00166 #endif
00167         }
00168         return e;
00169 }
00170 
00171 
00172 
00173 /****************************************************************************
00174  *                          TodoConduit class                               *
00175  ****************************************************************************/
00176 
00177 TodoConduit::TodoConduit(KPilotDeviceLink *d,
00178         const char *n,
00179         const QStringList &a) : VCalConduitBase(d,n,a)
00180 {
00181         FUNCTIONSETUP;
00182 #ifdef DEBUG
00183         DEBUGCONDUIT<<TodoConduit_id<<endl;
00184 #endif
00185 }
00186 
00187 
00188 
00189 TodoConduit::~TodoConduit()
00190 {
00191 //      FUNCTIONSETUP;
00192 }
00193 
00194 
00195 
00196 void TodoConduit::_setAppInfo()
00197 {
00198         FUNCTIONSETUP;
00199         // get the address application header information
00200         unsigned char *buffer =
00201                 new unsigned char[PilotTodoEntry::APP_BUFFER_SIZE];
00202         int appLen = fDatabase->readAppBlock(buffer,PilotTodoEntry::APP_BUFFER_SIZE);
00203 
00204         unpack_ToDoAppInfo(&fTodoAppInfo, buffer, appLen);
00205         delete[]buffer;
00206         buffer = NULL;
00207 
00208 #ifdef DEBUG
00209         DEBUGCONDUIT << fname << " lastUniqueId"
00210                 << fTodoAppInfo.category.lastUniqueID << endl;
00211 #endif
00212         for (int i = 0; i < 16; i++)
00213         {
00214 #ifdef DEBUG
00215                 DEBUGCONDUIT << fname << " cat " << i << " =" <<
00216                         fTodoAppInfo.category.name[i] << endl;
00217 #endif
00218         }
00219 
00220 }
00221 
00222 
00223 
00224 const QString TodoConduit::getTitle(PilotAppCategory*de)
00225 {
00226         PilotTodoEntry*d=dynamic_cast<PilotTodoEntry*>(de);
00227         if (d) return QString(d->getDescription());
00228         return QString::null;
00229 }
00230 
00231 
00232 
00233 void TodoConduit::readConfig()
00234 {
00235         FUNCTIONSETUP;
00236         VCalConduitBase::readConfig();
00237         // determine if the categories have ever been synce. Needed to prevent loosing the categories on the desktop.
00238         // also use a full sync for the first time to make sure the palm categories are really transferred to the desktop
00239         categoriesSynced = fConfig->readNumEntry("ConduitVersion", 0)>=CONDUIT_VERSION_CATEGORYSYNC;
00240         if (!categoriesSynced) fFullSync=true;
00241 #ifdef DEBUG
00242         DEBUGCONDUIT<<"categoriesSynced="<<categoriesSynced<<endl;
00243 #endif
00244 }
00245 
00246 
00247 
00248 void TodoConduit::postSync()
00249 {
00250         FUNCTIONSETUP;
00251         VCalConduitBase::postSync();
00252         fConfig->setGroup(configGroup());
00253         // after this successful sync the categories have been synced for sure
00254         fConfig->writeEntry("ConduitVersion", CONDUIT_VERSION);
00255 }
00256 
00257 
00258 
00259 PilotRecord*TodoConduit::recordFromIncidence(PilotAppCategory*de, const KCal::Incidence*e)
00260 {
00261         // don't need to check for null pointers here, the recordFromIncidence(PTE*, KCal::Todo*) will do that.
00262         return recordFromIncidence(dynamic_cast<PilotTodoEntry*>(de), dynamic_cast<const KCal::Todo*>(e));
00263 }
00264 
00265 
00266 
00267 PilotRecord*TodoConduit::recordFromIncidence(PilotTodoEntry*de, const KCal::Todo*todo)
00268 {
00269         FUNCTIONSETUP;
00270         if (!de || !todo) {
00271 #ifdef DEBUG
00272                 DEBUGCONDUIT<<fname<<": NULL todo given... Skipping it"<<endl;
00273 #endif
00274                 return NULL;
00275         }
00276 
00277         // set secrecy, start/end times, alarms, recurrence, exceptions, summary and description:
00278         if (todo->secrecy()!=KCal::Todo::SecrecyPublic) de->makeSecret();
00279 
00280         // update it from the iCalendar Todo.
00281 
00282         if (todo->hasDueDate()) {
00283                 struct tm t = writeTm(todo->dtDue());
00284                 de->setDueDate(t);
00285                 de->setIndefinite(0);
00286         } else {
00287                 de->setIndefinite(1);
00288         }
00289         
00290         // TODO: take recurrence (code in VCAlConduit) from ActionNames
00291 
00292         setCategory(de, todo);
00293 
00294         // TODO: sync the alarm from ActionNames. Need to extend PilotTodoEntry
00295         de->setPriority(todo->priority());
00296 
00297         de->setComplete(todo->isCompleted());
00298 
00299         // what we call summary pilot calls description.
00300         de->setDescription(todo->summary());
00301 
00302         // what we call description pilot puts as a separate note
00303         de->setNote(todo->description());
00304 
00305 #ifdef DEBUG
00306 DEBUGCONDUIT<<"-------- "<<todo->summary()<<endl;
00307 #endif
00308         return de->pack();
00309 }
00310 
00311 
00312 
00313 void TodoConduit::preRecord(PilotRecord*r) 
00314 {
00315         FUNCTIONSETUP;
00316         if (!categoriesSynced && r) 
00317         {
00318                 const PilotAppCategory*de=newPilotEntry(r);
00319                 KCal::Incidence *e = fP->findIncidence(r->getID());
00320                 setCategory(dynamic_cast<KCal::Todo*>(e), dynamic_cast<const PilotTodoEntry*>(de));
00321         }
00322 }
00323  
00324  
00325 
00326 void TodoConduit::setCategory(PilotTodoEntry*de, const KCal::Todo*todo)
00327 {
00328         if (!de || !todo) return;
00329         de->setCat(_getCat(de->getCat(), todo->categories()));
00330 #ifdef DEBUG
00331         DEBUGCONDUIT<<"old Category="<<de->getCat()<<", new cat will be "<<_getCat(de->getCat(), todo->categories())<<endl;
00332         DEBUGCONDUIT<<"Available Categories: "<<todo->categories().join(CSL1(" - "))<<endl;
00333 #endif
00334 }
00335 
00336 
00337 
00342 int TodoConduit::_getCat(int cat, const QStringList cats) const
00343 {
00344         FUNCTIONSETUP;
00345         int j;
00346         if (cats.contains(PilotAppCategory::codec()->toUnicode(fTodoAppInfo.category.name[cat]))) 
00347                 return cat;
00348         for ( QStringList::ConstIterator it = cats.begin(); it != cats.end(); ++it ) {
00349                 for (j=1; j<=15; j++) 
00350                 {
00351                         if (!(*it).isEmpty() && 
00352                                 ! (*it).compare( PilotAppCategory::codec()->toUnicode(
00353                                         fTodoAppInfo.category.name[j]) ) ) 
00354                         {
00355                                 return j;
00356                         }
00357                 }
00358         }
00359         return 0;
00360 }
00361 
00362 
00363 
00364 KCal::Incidence *TodoConduit::incidenceFromRecord(KCal::Incidence *e, const PilotAppCategory *de)
00365 {
00366         return dynamic_cast<KCal::Incidence*>(incidenceFromRecord(dynamic_cast<KCal::Todo*>(e), dynamic_cast<const PilotTodoEntry*>(de)));
00367 }
00368 
00369 
00370 
00371 KCal::Todo *TodoConduit::incidenceFromRecord(KCal::Todo *e, const PilotTodoEntry *de)
00372 {
00373         FUNCTIONSETUP;
00374 
00375         KCal::Todo*vtodo=e;
00376         if (!vtodo)
00377         {
00378 #ifdef DEBUG
00379                 DEBUGCONDUIT<<fname<<": null todo entry given. skipping..."<<endl;
00380 #endif
00381                 return NULL;
00382         }
00383 
00384         e->setOrganizer(fCalendar->getEmail());
00385         e->setPilotId(de->getID());
00386         e->setSyncStatus(KCal::Incidence::SYNCNONE);
00387         e->setSecrecy(de->isSecret() ? KCal::Todo::SecrecyPrivate : KCal::Todo::SecrecyPublic);
00388 
00389         // we don't want to modify the vobject with pilot info, because it has
00390         // already been  modified on the desktop.  The VObject's modified state
00391         // overrides the PilotRec's modified state.
00392         // TODO: Also include this in the vcal conduit!!!
00393 //      if (e->syncStatus() != KCal::Incidence::SYNCNONE) return e;
00394 
00395         // otherwise, the vObject hasn't been touched.  Updated it with the
00396         // info from the PilotRec.
00397         if (de->getIndefinite()) {
00398                 e->setHasDueDate(false);
00399         } else {
00400                 e->setDtDue(readTm(de->getDueDate()));
00401                 e->setHasDueDate(true);
00402         }
00403         
00404         // Categories
00405         // TODO: Sync categories
00406         // first remove all categories and then add only the appropriate one
00407         setCategory(e, de);
00408         
00409         // PRIORITY //
00410         e->setPriority(de->getPriority());
00411 
00412         // COMPLETED? //
00413         e->setCompleted(de->getComplete());
00414 
00415         e->setSummary(de->getDescription());
00416         e->setDescription(de->getNote());
00417 
00418         e->setSyncStatus(KCal::Incidence::SYNCNONE);
00419 
00420         return e;
00421 }
00422 
00423 
00424 
00425 void TodoConduit::setCategory(KCal::Todo *e, const PilotTodoEntry *de)
00426 {
00427         if (!e || !de) return;
00428         QStringList cats=e->categories();
00429         if (!categoriesSynced)
00430         {
00431                 // TODO: This is not optimal because it has the consequence that only one of the
00432                 // palm categories can be set on the desktop, all others will be deleted from the desktop entry!
00433                 for (int j=1; j<=15; j++) 
00434                 {
00435                         cats.remove(PilotAppCategory::codec()->toUnicode(fTodoAppInfo.category.name[j]));
00436                 }
00437         }
00438         int cat=de->getCat();
00439         if (0<cat && cat<=15) 
00440         {
00441                 cats.append( PilotAppCategory::codec()->toUnicode(fTodoAppInfo.category.name[cat]) );
00442         }
00443         e->setCategories(cats);
00444 }
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 15 11:40:44 2004 by doxygen 1.3.5 written by Dimitri van Heesch, © 1997-2001