00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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>
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
00112 fCounter(0)
00113 { } ;
00114 ~KNotesActionPrivate()
00115 {
00116 KPILOT_DELETE(fKNotes);
00117 KPILOT_DELETE(fTimer);
00118 }
00119
00120
00121
00122 QMap <KNoteID_t,QString> fNotes;
00123
00124
00125
00126 QMap <KNoteID_t,QString>::ConstIterator fIndex;
00127
00128 DCOPClient *fDCOP;
00129 KNotesIface_stub *fKNotes;
00130
00131 QTimer *fTimer;
00132
00133
00134
00135
00136
int fCounter;
00137
00138
00139
00140
00141 QValueList<NoteAndMemo> fIdList;
00142 } ;
00143
00144
00145
const char *
const KNotesAction::noteIdsKey=
"KNoteIds";
00146
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 KNotesAction::~KNotesAction()
00168 {
00169 FUNCTIONSETUP;
00170
00171 KPILOT_DELETE(fP);
00172 }
00173
00174
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
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
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
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
00519
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
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
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
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 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