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
00030 #include "options.h"
00031
00032 #include <qmap.h>
00033 #include <qtimer.h>
00034
00035 #include <kapplication.h>
00036
00037 #include <kurl.h>
00038 #include <libkcal/calendarlocal.h>
00039 #include <kstandarddirs.h>
00040
00041
00042 #include <kconfig.h>
00043
00044
00045 #include <time.h>
00046
00047 #include <pi-memo.h>
00048
00049 #include "pilotMemo.h"
00050 #include "pilotSerialDatabase.h"
00051
00052
00053
00054 #include "knotes-factory.h"
00055
00056 #include "knotes-action.moc"
00057 #include "knotesconduitSettings.h"
00058
00059 extern "C"
00060 {
00061
00062 unsigned long version_conduit_knotes = Pilot::PLUGIN_API;
00063
00064 }
00065
00066 typedef QString KNoteID_t;
00067 typedef const QString &KNoteID_pt;
00068
00069 class NoteAndMemo
00070 {
00071 public:
00072 NoteAndMemo() : noteId(),memoId(-1) { } ;
00073 NoteAndMemo(KNoteID_pt noteid,int memoid) : noteId(noteid),memoId(memoid) { } ;
00074 bool operator ==(const NoteAndMemo &p) const
00075 {
00076 return (p.memo()==memoId) && (p.note()==noteId);
00077 }
00078
00079 int memo() const { return memoId; } ;
00080 KNoteID_t note() const { return noteId; } ;
00081 inline bool valid() const { return (memoId>0) && (!noteId.isEmpty()) ; } ;
00082 QString toString() const { return CSL1("<%1,%2>").arg(noteId).arg(memoId); } ;
00083
00084 static NoteAndMemo findNote(const QValueList<NoteAndMemo> &,KNoteID_pt note);
00085 static NoteAndMemo findMemo(const QValueList<NoteAndMemo> &,int memo);
00086
00087 protected:
00088 KNoteID_t noteId;
00089 int memoId;
00090 } ;
00091
00092 NoteAndMemo NoteAndMemo::findNote(const QValueList<NoteAndMemo> &l ,KNoteID_pt note)
00093 {
00094 FUNCTIONSETUP;
00095
00096 for (QValueList<NoteAndMemo>::ConstIterator it = l.begin();
00097 it != l.end();
00098 ++it)
00099 {
00100 if ((*it).note()==note) return *it;
00101 }
00102
00103 return NoteAndMemo();
00104 }
00105
00106 NoteAndMemo NoteAndMemo::findMemo(const QValueList<NoteAndMemo> &l , int memo)
00107 {
00108 FUNCTIONSETUP;
00109
00110 for (QValueList<NoteAndMemo>::ConstIterator it =l.begin();
00111 it != l.end();
00112 ++it)
00113 {
00114 if ((*it).memo()==memo) return *it;
00115 }
00116
00117 return NoteAndMemo();
00118 }
00119
00120 class KNotesAction::KNotesActionPrivate
00121 {
00122 public:
00123 KNotesActionPrivate() :
00124 fNotesResource(0L),
00125 fTimer(0L),
00126 fDeleteCounter(0),
00127 fModifiedNotesCounter(0),
00128 fModifiedMemosCounter(0),
00129 fAddedNotesCounter(0),
00130 fAddedMemosCounter(0),
00131 fDeletedNotesCounter(0),
00132 fDeletedMemosCounter(0),
00133 fDeleteNoteForMemo(false)
00134 { } ;
00135 ~KNotesActionPrivate()
00136 {
00137 fNotesResource->save();
00138
00139 KPILOT_DELETE(fNotesResource);
00140 KPILOT_DELETE(fTimer);
00141 }
00142
00143
00144
00145 int fRecordIndex;
00146
00147 KCal::CalendarLocal *fNotesResource;
00148
00149 KCal::Journal::List fNotes;
00150
00151
00152
00153
00154 KCal::Journal::List::ConstIterator fIndex;
00155
00156
00157
00158
00159
00160
00161 QTimer *fTimer;
00162
00163
00164
00165
00166
00167 int fDeleteCounter;
00168 unsigned int fModifiedNotesCounter;
00169 unsigned int fModifiedMemosCounter;
00170 unsigned int fAddedNotesCounter;
00171 unsigned int fAddedMemosCounter;
00172 unsigned int fDeletedNotesCounter;
00173 unsigned int fDeletedMemosCounter;
00174
00175
00176
00177
00178 QValueList<NoteAndMemo> fIdList;
00179
00180
00181
00182 bool fDeleteNoteForMemo;
00183 };
00184
00185
00186
00187 KNotesAction::KNotesAction(KPilotLink *o,
00188 const char *n, const QStringList &a) :
00189 ConduitAction(o,n ? n : "knotes-conduit",a),
00190 fP(new KNotesActionPrivate)
00191 {
00192 FUNCTIONSETUP;
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202 }
00203
00204 KNotesAction::~KNotesAction()
00205 {
00206 FUNCTIONSETUP;
00207
00208 KPILOT_DELETE(fP);
00209 }
00210
00211 bool KNotesAction::exec()
00212 {
00213 FUNCTIONSETUP;
00214 DEBUGKPILOT << fname << ": Starting knotes conduit." << endl;
00215
00216 if (syncMode().isTest())
00217 {
00218 test();
00219 delayDone();
00220 return true;
00221 }
00222
00223 QString e;
00224 if (!openKNotesResource()) return false;
00225
00226
00227 if (!openDatabases(CSL1("MemoDB")))
00228 {
00229 #ifdef DEBUG
00230 DEBUGKPILOT << fname << "Can not open databases." << endl;
00231 #endif
00232 emit logError(i18n("Could not open MemoDB on the handheld."));
00233 return false;
00234 }
00235
00236 fP->fTimer = new QTimer(this);
00237 fActionStatus = Init;
00238
00239
00240
00241
00242 connect(fP->fTimer,SIGNAL(timeout()),SLOT(process()));
00243 fP->fTimer->start(0,false);
00244
00245 return true;
00246 }
00247
00248 void KNotesAction::test()
00249 {
00250 if (!openKNotesResource()) return;
00251 listNotes();
00252 }
00253
00254 bool KNotesAction::openKNotesResource()
00255 {
00256 FUNCTIONSETUP;
00257
00258 KConfig korgcfg( locate( "config", CSL1("korganizerrc") ) );
00259 korgcfg.setGroup( "Time & Date" );
00260 QString tz(korgcfg.readEntry( "TimeZoneId" ) );
00261
00262 fP->fNotesResource = new KCal::CalendarLocal(tz);
00263 KURL mURL = KGlobal::dirs()->saveLocation( "data", "knotes/" ) + "notes.ics";
00264
00265 if( fP->fNotesResource->load( mURL.path() ) )
00266 {
00267 fP->fNotes = fP->fNotesResource->journals();
00268 return true;
00269 }
00270 else
00271 {
00272 emit logError( i18n("Could not load the resource at: %1").arg(mURL.path()) );
00273 return false;
00274 }
00275 }
00276
00277
00278 void KNotesAction::resetIndexes()
00279 {
00280 FUNCTIONSETUP;
00281
00282 fP->fRecordIndex = 0;
00283 fP->fIndex = fP->fNotes.begin();
00284 }
00285
00286 void KNotesAction::listNotes()
00287 {
00288 FUNCTIONSETUP;
00289
00290 KCal::Journal::List notes = fP->fNotesResource->journals();
00291 DEBUGKPILOT << fname << ": the resource contains " << notes.size()
00292 << " note(s)." << endl;
00293
00294 KCal::Journal::List::ConstIterator it;
00295 int i = 1;
00296 for ( it = notes.begin(); it != notes.end(); ++it )
00297 {
00298 DEBUGKPILOT << fname << ": note " << i << " has id " << (*it)->uid()
00299 << endl;
00300 i++;
00301 }
00302
00303 DEBUGKPILOT << fname << ": "
00304 << "Sync direction: " << syncMode().name() << endl;
00305 }
00306
00307 void KNotesAction::process()
00308 {
00309 FUNCTIONSETUP;
00310
00311 DEBUGKPILOT << fname << ": Now in state " << fActionStatus << endl;
00312
00313 switch(fActionStatus)
00314 {
00315 case Init:
00316 resetIndexes();
00317 getAppInfo();
00318 getConfigInfo();
00319 switch(syncMode().mode())
00320 {
00321 case SyncAction::SyncMode::eBackup:
00322 case SyncAction::SyncMode::eRestore:
00323
00324 fActionStatus = Done;
00325 break;
00326 case SyncAction::SyncMode::eCopyHHToPC :
00327 listNotes();
00328 fActionStatus = MemosToKNotes;
00329 break;
00330 case SyncAction::SyncMode::eHotSync:
00331 case SyncAction::SyncMode::eFullSync:
00332 case SyncAction::SyncMode::eCopyPCToHH:
00333 fActionStatus = ModifiedNotesToPilot;
00334 break;
00335 }
00336 break;
00337 case ModifiedNotesToPilot:
00338 if (modifyNoteOnPilot())
00339 {
00340 resetIndexes();
00341 fActionStatus = DeleteNotesOnPilot;
00342 }
00343 break;
00344 case DeleteNotesOnPilot:
00345 if (deleteNoteOnPilot())
00346 {
00347 resetIndexes();
00348 fActionStatus = NewNotesToPilot;
00349 }
00350 break;
00351 case NewNotesToPilot :
00352 if (addNewNoteToPilot())
00353 {
00354 resetIndexes();
00355 fDatabase->resetDBIndex();
00356 switch(syncMode().mode())
00357 {
00358 case SyncAction::SyncMode::eBackup:
00359 case SyncAction::SyncMode::eRestore:
00360 case SyncAction::SyncMode::eCopyHHToPC :
00361
00362 fActionStatus = Done;
00363 break;
00364 case SyncAction::SyncMode::eHotSync:
00365 case SyncAction::SyncMode::eFullSync:
00366 fActionStatus = MemosToKNotes;
00367 break;
00368 case SyncAction::SyncMode::eCopyPCToHH:
00369 fActionStatus = Cleanup;
00370 break;
00371 }
00372 }
00373 break;
00374 case MemosToKNotes :
00375 if (syncMemoToKNotes())
00376 {
00377 fActionStatus=Cleanup;
00378 }
00379 break;
00380 case Cleanup :
00381 cleanupMemos();
00382 break;
00383 default :
00384 if (fP->fTimer) fP->fTimer->stop();
00385 delayDone();
00386 }
00387 }
00388
00389
00390 void KNotesAction::getConfigInfo()
00391 {
00392 FUNCTIONSETUP;
00393
00394 KNotesConduitSettings::self()->readConfig();
00395
00396 fP->fDeleteNoteForMemo = KNotesConduitSettings::deleteNoteForMemo();
00397
00398 QValueList<KNoteID_t> notes;
00399 QValueList<int> memos;
00400
00401
00402 notes=KNotesConduitSettings::noteIds();
00403 memos=KNotesConduitSettings::memoIds();
00404
00405 if (notes.count() != memos.count())
00406 {
00407 WARNINGKPILOT
00408 << ": Notes and memo id lists don't match ("
00409 << notes.count()
00410 << ","
00411 << memos.count()
00412 << ")"
00413 << endl;
00414 notes.clear();
00415 memos.clear();
00416 setFirstSync( true );
00417 }
00418
00419 QValueList<KNoteID_t>::ConstIterator iNotes = notes.begin();
00420 QValueList<int>::ConstIterator iMemos = memos.begin();
00421
00422 while((iNotes != notes.end()) && (iMemos != memos.end()))
00423 {
00424 fP->fIdList.append(NoteAndMemo(*iNotes,*iMemos));
00425 ++iNotes;
00426 ++iMemos;
00427 }
00428 }
00429
00430 void KNotesAction::getAppInfo()
00431 {
00432 FUNCTIONSETUP;
00433
00434 resetIndexes();
00435 }
00436
00437
00438 bool KNotesAction::modifyNoteOnPilot()
00439 {
00440 FUNCTIONSETUP;
00441 return true;
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513 }
00514
00515 bool KNotesAction::deleteNoteOnPilot()
00516 {
00517 FUNCTIONSETUP;
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544 return true;
00545 }
00546
00547 bool KNotesAction::addNewNoteToPilot()
00548 {
00549 FUNCTIONSETUP;
00550
00551 if (fP->fIndex == fP->fNotes.end())
00552 {
00553 return true;
00554 }
00555
00556 KCal::Journal *j = (*fP->fIndex);
00557
00558 if( j->pilotId() == 0 )
00559 {
00560 DEBUGKPILOT << fname << ": Adding note with id " << j->uid()
00561 << " to pilot." << endl;
00562
00563 int newid = addNoteToPilot();
00564
00565 ++(fP->fAddedMemosCounter);
00566 }
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577 ++(fP->fIndex);
00578 return false;
00579 }
00580
00581 bool KNotesAction::syncMemoToKNotes()
00582 {
00583 FUNCTIONSETUP;
00584
00585 PilotRecord *rec = 0L;
00586
00587 if ( syncMode() == SyncAction::SyncMode::eCopyHHToPC )
00588 {
00589 #ifdef DEBUG
00590 DEBUGKPILOT << fname << ": Read record " << fP->fRecordIndex << endl;
00591 #endif
00592 rec = fDatabase->readRecordByIndex(fP->fRecordIndex);
00593 fP->fRecordIndex++;
00594 }
00595 else
00596 {
00597 rec = fDatabase->readNextModifiedRec();
00598 }
00599
00600 if (!rec)
00601 {
00602 return true;
00603 }
00604
00605 PilotMemo *memo = new PilotMemo(rec);
00606 NoteAndMemo m = NoteAndMemo::findMemo(fP->fIdList,memo->id());
00607
00608 #ifdef DEBUG
00609 DEBUGKPILOT << fname << ": Looking at memo "
00610 << memo->id()
00611 << " which was found "
00612 << m.toString()
00613 << endl;
00614 #endif
00615
00616 if (memo->isDeleted())
00617 {
00618 #ifdef DEBUG
00619 DEBUGKPILOT << fname << ": It's been deleted." << endl;
00620 #endif
00621 if (m.valid())
00622 {
00623
00624
00625
00626
00627 if (fP->fDeleteNoteForMemo)
00628 {
00629
00630
00631
00632 fP->fDeletedNotesCounter++;
00633 }
00634 }
00635 else
00636 {
00637 #ifdef DEBUG
00638 DEBUGKPILOT << fname << ": It's new and deleted." << endl;
00639 #endif
00640 }
00641
00642 fLocalDatabase->deleteRecord(rec->id());
00643 }
00644 else
00645 {
00646 if (m.valid())
00647 {
00648 #ifdef DEBUG
00649 DEBUGKPILOT << fname << ": It's just modified." << endl;
00650 DEBUGKPILOT << fname << ": <"
00651
00652 << "> <"
00653 << memo->shortTitle()
00654 << ">"
00655 << endl;
00656 #endif
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676 }
00677 else
00678 {
00679 addMemoToKNotes(memo);
00680 }
00681 fLocalDatabase->writeRecord(rec);
00682 }
00683
00684 KPILOT_DELETE(memo);
00685 KPILOT_DELETE(rec);
00686
00687 return false;
00688 }
00689
00690 void KNotesAction::updateNote(const NoteAndMemo &m, const PilotMemo *memo)
00691 {
00692 FUNCTIONSETUP;
00693
00694 if (true)
00695 {
00696
00697
00698
00699 }
00700
00701
00702 fP->fModifiedNotesCounter++;
00703 }
00704
00705 void KNotesAction::addMemoToKNotes(const PilotMemo *memo)
00706 {
00707 FUNCTIONSETUP;
00708
00709
00710
00711
00712
00713
00714 #ifdef DEBUG
00715
00716
00717 #endif
00718 }
00719 int KNotesAction::addNoteToPilot()
00720 {
00721 FUNCTIONSETUP;
00722
00723 KCal::Journal *j = (*fP->fIndex);
00724
00725 #ifdef DEBUG
00726 DEBUGKPILOT << fname
00727 << ": The note #"
00728 << j->uid()
00729 << " with name "
00730 << j->summary()
00731 << " is new to the Pilot."
00732 << endl;
00733 #endif
00734
00735 QString text = j->summary() + CSL1("\n");
00736 text.append( j->description() );
00737
00738
00739
00740 PilotMemo *a = new PilotMemo(text);
00741 PilotRecord *r = a->pack();
00742
00743 int newid = fDatabase->writeRecord(r);
00744 fLocalDatabase->writeRecord(r);
00745
00746 j->setPilotId( newid );
00747
00748 delete r;
00749 delete a;
00750 delete j;
00751
00752 fP->fAddedMemosCounter++;
00753
00754 return newid;
00755 }
00756
00757
00758 void KNotesAction::cleanupMemos()
00759 {
00760 FUNCTIONSETUP;
00761
00762
00763
00764
00765
00766 #ifdef DEBUG
00767 DEBUGKPILOT << fname
00768 << ": Writing "
00769 << fP->fIdList.count()
00770 << " pairs to the config file."
00771 << endl;
00772 DEBUGKPILOT << fname
00773 << ": The config file is read-only: "
00774 << KNotesConduitSettings::self()->config()->isReadOnly()
00775 << endl;
00776 #endif
00777
00778 QValueList<KNoteID_t> notes;
00779 QValueList<int> memos;
00780
00781 for (QValueList<NoteAndMemo>::ConstIterator i =
00782 fP->fIdList.begin();
00783 i!=fP->fIdList.end();
00784 ++i)
00785 {
00786 notes.append((*i).note());
00787 memos.append((*i).memo());
00788 }
00789
00790 KNotesConduitSettings::setNoteIds(notes);
00791 KNotesConduitSettings::setMemoIds(memos);
00792 KNotesConduitSettings::self()->writeConfig();
00793
00794 fActionStatus=Done;
00795 fDatabase->cleanup();
00796 fDatabase->resetSyncFlags();
00797 fLocalDatabase->cleanup();
00798 fLocalDatabase->resetSyncFlags();
00799
00800
00801
00802
00803
00804 bool spoke = false;
00805 if (fP->fAddedMemosCounter)
00806 {
00807 addSyncLogEntry(i18n("Added one new memo.",
00808 "Added %n new memos.",
00809 fP->fAddedMemosCounter));
00810 }
00811 if (fP->fModifiedMemosCounter)
00812 {
00813 addSyncLogEntry(i18n("Modified one memo.",
00814 "Modified %n memos.",
00815 fP->fModifiedMemosCounter));
00816 spoke = true;
00817 }
00818 if (fP->fDeletedMemosCounter)
00819 {
00820 addSyncLogEntry(i18n("Deleted one memo.",
00821 "Deleted %n memos.",fP->fDeletedMemosCounter));
00822 spoke = true;
00823 }
00824 if (fP->fAddedNotesCounter)
00825 {
00826 addSyncLogEntry(i18n("Added one note to KNotes.",
00827 "Added %n notes to KNotes.",fP->fAddedNotesCounter));
00828 spoke = true;
00829 }
00830 if (fP->fModifiedNotesCounter)
00831 {
00832 addSyncLogEntry(i18n("Modified one note in KNotes.",
00833 "Modified %n notes in KNotes.",fP->fModifiedNotesCounter));
00834 spoke = true;
00835 }
00836 if (fP->fDeletedNotesCounter)
00837 {
00838 addSyncLogEntry(i18n("Deleted one note from KNotes.",
00839 "Deleted %n notes from KNotes.",fP->fDeletedNotesCounter));
00840 spoke = true;
00841 }
00842 if (!spoke)
00843 {
00844 addSyncLogEntry(i18n("No change to KNotes."));
00845 }
00846 }
00847
00848
00849 QString KNotesAction::statusString() const
00850 {
00851 switch(fActionStatus)
00852 {
00853 case Init : return CSL1("Init");
00854 case NewNotesToPilot :
00855 return CSL1("NewNotesToPilot key=%1");
00856
00857 case ModifiedNotesToPilot :
00858 return CSL1("ModifiedNotesToPilot key=%1");
00859
00860 case MemosToKNotes :
00861 return CSL1("MemosToKNotes rec=%1")
00862 .arg(fP->fRecordIndex);
00863 case Cleanup : return CSL1("Cleanup");
00864 case Done :
00865 return CSL1("Done");
00866 default :
00867 return CSL1("Unknown (%1)").arg(fActionStatus);
00868 }
00869 }
00870
00871
00872