kpilot Library API Documentation

knotes-action.cc

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