kpilot Library API Documentation

knotes-action.cc

00001 /* knotes-action.cc                      KPilot
00002 **
00003 ** Copyright (C) 2001,2002 by Dan Pilone
00004 **
00005 ** This file defines the SyncAction for the knotes-conduit plugin.
00006 */
00007  
00008 /*
00009 ** This program is free software; you can redistribute it and/or modify
00010 ** it under the terms of the GNU General Public License as published by
00011 ** the Free Software Foundation; either version 2 of the License, or
00012 ** (at your option) any later version.
00013 **
00014 ** This program is distributed in the hope that it will be useful,
00015 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00017 ** GNU General Public License for more details.
00018 **
00019 ** You should have received a copy of the GNU General Public License
00020 ** along with this program in a file called COPYING; if not, write to
00021 ** the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00022 ** MA 02111-1307, USA.
00023 */
00024  
00025 /*
00026 ** Bug reports and questions can be sent to kde-pim@kde.org
00027 */
00028 
00029 #include "options.h"
00030 
00031 #include <qmap.h>
00032 #include <qtimer.h>
00033 
00034 #include <kapplication.h>
00035 
00036 #include <kconfig.h>
00037 #include <dcopclient.h>
00038 
00039 #include <time.h>  // required by pilot-link includes
00040 
00041 #include <pi-memo.h>
00042 
00043 #include "pilotMemo.h"
00044 #include "pilotSerialDatabase.h"
00045 
00046 #include "KNotesIface_stub.h"
00047 
00048 #include "knotes-factory.h"
00049 
00050 #include "knotes-action.moc"
00051 
00052 
00053 class NoteAndMemo
00054 {
00055 public:
00056         NoteAndMemo() : noteId(-1),memoId(-1) { } ;
00057         NoteAndMemo(int noteid,int memoid) : noteId(noteid),memoId(memoid) { } ;
00058 
00059         int memo() const { return memoId; } ;
00060         int note() const { return noteId; } ;
00061         bool valid() const { return (noteId>0) && (memoId>0); } ;
00062         QString toString() const { return CSL1("<%1,%2>").arg(noteId).arg(memoId); } ;
00063 
00064         static NoteAndMemo findNote(const QValueList<NoteAndMemo> &,int note);
00065         static NoteAndMemo findMemo(const QValueList<NoteAndMemo> &,int memo);
00066 
00067 protected:
00068         int noteId;
00069         int memoId;
00070 } ;
00071 
00072 NoteAndMemo NoteAndMemo::findNote(const QValueList<NoteAndMemo> &l ,int note)
00073 {
00074         FUNCTIONSETUP;
00075 
00076         for (QValueList<NoteAndMemo>::ConstIterator it =l.begin();
00077                 it != l.end();
00078                 ++it)
00079         {
00080                 if ((*it).note()==note) return *it;
00081         }
00082 
00083         return NoteAndMemo();
00084 }
00085 
00086 NoteAndMemo NoteAndMemo::findMemo(const QValueList<NoteAndMemo> &l ,int memo)
00087 {
00088         FUNCTIONSETUP;
00089 
00090         for (QValueList<NoteAndMemo>::ConstIterator it =l.begin();
00091                 it != l.end();
00092                 ++it)
00093         {
00094                 if ((*it).memo()==memo) return *it;
00095         }
00096 
00097         return NoteAndMemo();
00098 }
00099 
00100 class KNotesAction::KNotesActionPrivate
00101 {
00102 public:
00103         KNotesActionPrivate() :
00104                 fDCOP(0L),
00105                 fKNotes(0L),
00106                 fTimer(0L),
00107                 // fDatabase(0L),
00108                 fCounter(0)
00109         { } ;
00110 
00111         // These are  the notes that we got from KNotes
00112         QMap <int,QString> fNotes;
00113         // This iterates through that list; it's in here because
00114         // we use slots to process one item at a time and need
00115         // to keep track of where we are between slot calls.
00116         QMap <int,QString>::ConstIterator fIndex;
00117         // The DCOP client for this application, and the KNotes stub.
00118         DCOPClient *fDCOP;
00119         KNotesIface_stub *fKNotes;
00120         // The timer for invoking process() to do some more work.
00121         QTimer *fTimer;
00122         // The database we're working with (MemoDB)
00123         // PilotSerialDatabase *fDatabase;
00124         // Some counter that needs to be preserved between calls to
00125         // process(). Typically used to note hom much work is done.
00126         int fCounter;
00127 
00128         // We need to translate between the ids that KNotes uses and
00129         // Pilot id's, so we make a list of pairs.
00130         //
00131         QValueList<NoteAndMemo> fIdList;
00132 } ;
00133 
00134 
00135 /* static */ const char * const KNotesAction::noteIdsKey="NoteIds";
00136 /* static */ const char * const KNotesAction::memoIdsKey="MemoIds";
00137 
00138 
00139 KNotesAction::KNotesAction(KPilotDeviceLink *o,
00140         const char *n, const QStringList &a) :
00141         ConduitAction(o,!n ? "knotes-conduit" : n,a),
00142         fP(new KNotesActionPrivate)
00143 {
00144         FUNCTIONSETUP;
00145 
00146 
00147         fP->fDCOP = KApplication::kApplication()->dcopClient();
00148 
00149         if (!fP->fDCOP)
00150         {
00151                 kdWarning() << k_funcinfo
00152                         << ": Can't get DCOP client."
00153                         << endl;
00154         }
00155 }
00156 
00157 /* virtual */ KNotesAction::~KNotesAction()
00158 {
00159         FUNCTIONSETUP;
00160 
00161         KPILOT_DELETE(fP->fTimer);
00162         KPILOT_DELETE(fP->fKNotes);
00163         // KPILOT_DELETE(fP->fDatabase);
00164         KPILOT_DELETE(fP);
00165 }
00166 
00167 /* virtual */ bool KNotesAction::exec()
00168 {
00169         FUNCTIONSETUP;
00170 
00171         QString e;
00172         if (!fP->fDCOP)
00173         {
00174                 emit logError(i18n("No DCOP connection could be made. The "
00175                         "conduit cannot function like this."));
00176                 return false;
00177 
00178         }
00179         if (!PluginUtility::isRunning("knotes"))
00180         {
00181                 emit logError(i18n("KNotes is not running. The conduit must "
00182                         "be able to make a DCOP connection to KNotes "
00183                         "for synchronization to take place. "
00184                         "Please start KNotes and try again."));
00185                 return false;
00186         }
00187 
00188         if (!fConfig) return false;
00189 
00190         fP->fKNotes = new KNotesIface_stub("knotes","KNotesIface");
00191 
00192         fP->fNotes = fP->fKNotes->notes();
00193 
00194         // Database names seem to be latin1
00195         openDatabases(QString::fromLatin1("MemoDB"));
00196 
00197         if (isTest())
00198         {
00199                 listNotes();
00200         }
00201         else
00202         {
00203                 fP->fTimer = new QTimer(this);
00204                 fStatus = Init;
00205                 resetIndexes();
00206 
00207                 connect(fP->fTimer,SIGNAL(timeout()),SLOT(process()));
00208 
00209                 fP->fTimer->start(0,false);
00210         }
00211 
00212         return true;
00213 }
00214 
00215 void KNotesAction::resetIndexes()
00216 {
00217         FUNCTIONSETUP;
00218 
00219         fP->fCounter = 0;
00220         fP->fIndex = fP->fNotes.begin();
00221 }
00222 
00223 void KNotesAction::listNotes()
00224 {
00225         FUNCTIONSETUP;
00226 
00227         QMap<int,QString>::ConstIterator i = fP->fNotes.begin();
00228         while (i != fP->fNotes.end())
00229         {
00230 #ifdef DEBUG
00231                 DEBUGCONDUIT << fname
00232                         << ": "
00233                         << i.key()
00234                         << "->"
00235                         << i.data()
00236                         << (fP->fKNotes->isNew(CSL1("kpilot"),i.key()) ?
00237                                 " (new)" : "" )
00238                         << endl;
00239 #endif
00240                 i++;
00241         }
00242 
00243         emit syncDone(this);
00244 }
00245 
00246 /* slot */ void KNotesAction::process()
00247 {
00248         FUNCTIONSETUP;
00249 #ifdef DEBUG
00250         DEBUGCONDUIT << fname 
00251                 << ": Now in state " << fStatus << endl;
00252 #endif
00253 
00254         switch(fStatus)
00255         {
00256         case Init:
00257                 getAppInfo();
00258                 getConfigInfo();
00259                 break;
00260         case ModifiedNotesToPilot :
00261                 if (modifyNoteOnPilot())
00262                 {
00263                         resetIndexes();
00264                         fStatus = NewNotesToPilot;
00265                 }
00266                 break;
00267         case NewNotesToPilot :
00268                 if (addNewNoteToPilot())
00269                 {
00270                         resetIndexes();
00271                         fStatus = MemosToKNotes;
00272                         fDatabase->resetDBIndex();
00273                 }
00274                 break;
00275         case MemosToKNotes :
00276                 if (syncMemoToKNotes())
00277                 {
00278                         fStatus=Cleanup;
00279                 }
00280                 break;
00281         case Cleanup :
00282                 cleanupMemos();
00283                 break;
00284         default :
00285                 fP->fTimer->stop();
00286                 emit syncDone(this);
00287         }
00288 }
00289 
00290 
00291 void KNotesAction::getConfigInfo()
00292 {
00293         FUNCTIONSETUP;
00294 
00295         if (fConfig)
00296         {
00297                 KConfigGroupSaver g(fConfig,KNotesConduitFactory::group);
00298 
00299                 QValueList<int> notes;
00300                 QValueList<int> memos;
00301 
00302 
00303                 notes=fConfig->readIntListEntry(noteIdsKey);
00304                 memos=fConfig->readIntListEntry(memoIdsKey);
00305 
00306                 if (notes.count() != memos.count())
00307                 {
00308                         kdWarning() << k_funcinfo
00309                                 << ": Notes and memo id lists don't match ("
00310                                 << notes.count()
00311                                 << ","
00312                                 << memos.count()
00313                                 << ")"
00314                                 << endl;
00315                 }
00316 
00317                 QValueList<int>::ConstIterator iNotes = notes.begin();
00318                 QValueList<int>::ConstIterator iMemos = memos.begin();
00319 
00320                 while((iNotes != notes.end()) && (iMemos != memos.end()))
00321                 {
00322                         fP->fIdList.append(NoteAndMemo(*iNotes,*iMemos));
00323                         ++iNotes;
00324                         ++iMemos;
00325                 }
00326         }
00327 }
00328 
00329 void KNotesAction::getAppInfo()
00330 {
00331         FUNCTIONSETUP;
00332 
00333 
00334         unsigned char buffer[PilotDatabase::MAX_APPINFO_SIZE];
00335         int appInfoSize = fDatabase->readAppBlock(buffer,PilotDatabase::MAX_APPINFO_SIZE);
00336         struct MemoAppInfo memoInfo;
00337 
00338         if (appInfoSize<0)
00339         {
00340                 fStatus=Error;
00341                 return;
00342         }
00343 
00344         unpack_MemoAppInfo(&memoInfo,buffer,appInfoSize);
00345         PilotDatabase::listAppInfo(&memoInfo.category);
00346 
00347         resetIndexes();
00348         fStatus=ModifiedNotesToPilot;
00349         
00350         addSyncLogEntry(i18n("[KNotes conduit: "));
00351 }
00352 
00353 
00354 bool KNotesAction::modifyNoteOnPilot()
00355 {
00356         FUNCTIONSETUP;
00357 
00358         if (fP->fIndex == fP->fNotes.end())
00359         {
00360                 if (fP->fCounter)
00361                 {
00362                         addSyncLogEntry(i18n("Modified one memo.",
00363                                 "Modified %n memos.",
00364                                 fP->fCounter));
00365                 }
00366                 else
00367                 {
00368                         addSyncLogEntry(TODO_I18N("No memos were changed."));
00369                 }
00370                 return true;
00371         }
00372 
00373         if (fP->fKNotes->isModified(CSL1("kpilot"),fP->fIndex.key()))
00374         {
00375 #ifdef DEBUG
00376                 DEBUGCONDUIT << fname
00377                         << ": The note #"
00378                         << fP->fIndex.key()
00379                         << " with name "
00380                         << fP->fIndex.data()
00381                         << " is modified in KNotes."
00382                         << endl;
00383 #endif
00384 
00385                 NoteAndMemo nm = NoteAndMemo::findNote(fP->fIdList,
00386                         fP->fIndex.key());
00387 
00388                 if (nm.valid())
00389                 {
00390                         QString text = fP->fIndex.data() + CSL1("\n") ;
00391                         text.append(fP->fKNotes->text(fP->fIndex.key()));
00392 
00393                         PilotMemo *a = new PilotMemo(text);
00394                         PilotRecord *r = a->pack();
00395                         r->setID(nm.memo());
00396 
00397                         int newid = fDatabase->writeRecord(r);
00398 
00399                         if (newid != nm.memo())
00400                         {
00401                                 kdWarning() << k_funcinfo
00402                                         << ": Memo id changed during write? "
00403                                         << "From "
00404                                         << nm.memo()
00405                                         << " to "
00406                                         << newid
00407                                         << endl;
00408                         }
00409                 }
00410                 else
00411                 {
00412                         kdWarning() << ": Modified note unknown to Pilot" << endl;
00413                 }
00414 
00415                 fP->fCounter++;
00416         }
00417 
00418         ++(fP->fIndex);
00419         return false;
00420 }
00421 
00422 bool KNotesAction::addNewNoteToPilot()
00423 {
00424         FUNCTIONSETUP;
00425 
00426         if (fP->fIndex == fP->fNotes.end())
00427         {
00428                 if (fP->fCounter)
00429                 {
00430                         addSyncLogEntry(i18n("Added one new memo.",
00431                                 "Added %n new memos.",
00432                                 fP->fCounter));
00433                 }
00434                 else
00435                 {
00436                         addSyncLogEntry(TODO_I18N("No memos were added."));
00437                 }
00438                 return true;
00439         }
00440 
00441         if (fP->fKNotes->isNew(CSL1("kpilot"),fP->fIndex.key()))
00442         {
00443 #ifdef DEBUG
00444                 DEBUGCONDUIT << fname
00445                         << ": The note #"
00446                         << fP->fIndex.key()
00447                         << " with name "
00448                         << fP->fIndex.data()
00449                         << " is new to the Pilot."
00450                         << endl;
00451 #endif
00452 
00453                 QString text = fP->fIndex.data() + CSL1("\n") ;
00454                 text.append(fP->fKNotes->text(fP->fIndex.key()));
00455 
00456                 PilotMemo *a = new PilotMemo(text);
00457                 PilotRecord *r = a->pack();
00458 
00459                 int newid = fDatabase->writeRecord(r);
00460 
00461                 fP->fIdList.append(NoteAndMemo(fP->fIndex.key(),newid));
00462 
00463                 delete r;
00464                 delete a;
00465 
00466                 fP->fCounter++;
00467         }
00468 
00469         ++(fP->fIndex);
00470         return false;
00471 }
00472 
00473 bool KNotesAction::syncMemoToKNotes()
00474 {
00475         FUNCTIONSETUP;
00476 
00477         PilotRecord *rec = fDatabase->readNextModifiedRec();
00478         if (!rec)
00479         {
00480                 if (fP->fCounter)
00481                 {
00482                         addSyncLogEntry(i18n("Added one memo to KNotes.",
00483                                 "Added %n memos to KNotes.",fP->fCounter));
00484                 }
00485                 else
00486                 {
00487                         addSyncLogEntry(TODO_I18N("No memos added to KNotes."));
00488                 }
00489                 return true;
00490         }
00491 
00492         fP->fCounter++;
00493 
00494         PilotMemo *memo = new PilotMemo(rec);
00495         NoteAndMemo m = NoteAndMemo::findMemo(fP->fIdList,memo->id());
00496 
00497 #ifdef DEBUG
00498         DEBUGCONDUIT << fname << ": Looking at memo " 
00499                 << memo->id()
00500                 << " which was found "
00501                 << m.toString()
00502                 << endl;
00503 #endif
00504 
00505         if (m.valid())
00506         {
00507                 // We knew about the note already, but it
00508                 // has changed on the Pilot.
00509                 //
00510                 //
00511                 if (memo->isDeleted())
00512                 {
00513 #ifdef DEBUG
00514                         DEBUGCONDUIT << fname << ": It's been deleted." << endl;
00515 #endif
00516                         fP->fKNotes->killNote(m.note());
00517                 }
00518                 else
00519                 {
00520 #ifdef DEBUG
00521                         DEBUGCONDUIT << fname << ": It's just modified." << endl;
00522                         DEBUGCONDUIT << fname << ": <"
00523                                 << fP->fNotes[m.note()]
00524                                 << "> <"
00525                                 << memo->shortTitle()
00526                                 << ">"
00527                                 << endl;
00528 #endif
00529                         if (fP->fNotes[m.note()] != memo->shortTitle())
00530                         {
00531                                 // Name changed. KNotes might complain though.
00532                                 fP->fKNotes->setName(m.note(),memo->shortTitle());
00533                         }
00534                         fP->fKNotes->setText(m.note(),memo->text());
00535                 }
00536         }
00537         else
00538         {
00539                 if (memo->isDeleted())
00540                 {
00541 #ifdef DEBUG
00542                         DEBUGCONDUIT << fname << ": It's new and deleted." << endl;
00543 #endif
00544                         // Do nothing, it's new and deleted at the same time
00545                 }
00546                 else
00547                 {
00548                         int i = fP->fKNotes->newNote(memo->shortTitle(),memo->text());
00549                         fP->fIdList.append(NoteAndMemo(i,memo->id()));
00550 #ifdef DEBUG
00551                         DEBUGCONDUIT << fname << ": It's new with knote id " << i << endl;
00552 #endif
00553                 }
00554         }
00555 
00556         if (memo) delete memo;
00557         if (rec) delete rec;
00558 
00559         return false;
00560 }
00561 
00562 
00563 void KNotesAction::cleanupMemos()
00564 {
00565         FUNCTIONSETUP;
00566 
00567         // Tell KNotes we're up-to-date
00568         fP->fKNotes->sync(CSL1("kpilot"));
00569 
00570         if (fConfig)
00571         {
00572 #ifdef DEBUG
00573                 DEBUGCONDUIT << fname
00574                         << ": Writing "
00575                         << fP->fIdList.count()
00576                         << " pairs to the config file."
00577                         << endl;
00578                 DEBUGCONDUIT << fname
00579                         << ": The config file is read-only: "
00580                         << fConfig->isReadOnly()
00581                         << endl;
00582 #endif
00583 
00584                 KConfigGroupSaver g(fConfig,KNotesConduitFactory::group);
00585 
00586                 QValueList<int> notes;
00587                 QValueList<int> memos;
00588 
00589                 for (QValueList<NoteAndMemo>::ConstIterator i =
00590                         fP->fIdList.begin();
00591                         i!=fP->fIdList.end();
00592                         ++i)
00593                 {
00594                         notes.append((*i).note());
00595                         memos.append((*i).memo());
00596                 }
00597 
00598                 fConfig->writeEntry(noteIdsKey,notes);
00599                 fConfig->writeEntry(memoIdsKey,memos);
00600                 fConfig->sync();
00601         }
00602 
00603         fStatus=Done;
00604         fDatabase->cleanup();
00605         fDatabase->resetSyncFlags();
00606 
00607         addSyncLogEntry(CSL1("]\n"));
00608 }
00609 
00610 
00611 /* virtual */ QString KNotesAction::statusString() const
00612 {
00613         switch(fStatus)
00614         {
00615         case Init : return CSL1("Init");
00616         case NewNotesToPilot :
00617                 return CSL1("NewNotesToPilot key=%1")
00618                         .arg(fP->fIndex.key());
00619         case Done :
00620                 return CSL1("Done");
00621         default :
00622                 return CSL1("Unknown (%1)").arg(fStatus);
00623         }
00624 }
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:43 2004 by doxygen 1.3.5 written by Dimitri van Heesch, © 1997-2001