diff options
Diffstat (limited to 'conduits/memofileconduit')
19 files changed, 2533 insertions, 0 deletions
diff --git a/conduits/memofileconduit/CMakeLists.txt b/conduits/memofileconduit/CMakeLists.txt new file mode 100644 index 0000000..5699457 --- /dev/null +++ b/conduits/memofileconduit/CMakeLists.txt @@ -0,0 +1,44 @@ +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} +) + +set(conduit_memofile_SRCS + memofile-factory.cc + memofile.cc + memofiles.cc + memofile-conduit.cc +) + +set(conduit_memofile_UIS + setup_base.ui +) + +set(conduit_memofile_KCFGS + memofileSettings.kcfgc +) + +kde3_add_kcfg_files(conduit_memofile_SRCS ${conduit_memofile_KCFGS}) +kde3_add_ui_files(conduit_memofile_SRCS ${conduit_memofile_UIS}) +kde3_automoc(${conduit_memofile_SRCS}) +add_library(conduit_memofile SHARED ${conduit_memofile_SRCS}) + +set_target_properties( + conduit_memofile PROPERTIES LOCATION ${KDE3_PLUGIN_INSTALL_DIR} + INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib + PREFIX "" +) + +kde3_install_libtool_file(conduit_memofile) + +install( + TARGETS conduit_memofile + LIBRARY DESTINATION ${KDE3_PLUGIN_INSTALL_DIR} +) + +install( + FILES memofile-conduit.desktop DESTINATION ${KDE3_SERVICES_DIR} +) + +install( + FILES memofileconduit.kcfg DESTINATION ${KDE3_KCFG_DIR} +) diff --git a/conduits/memofileconduit/Makefile.am b/conduits/memofileconduit/Makefile.am new file mode 100644 index 0000000..e4a244b --- /dev/null +++ b/conduits/memofileconduit/Makefile.am @@ -0,0 +1,16 @@ +INCLUDES= $(PISOCK_INCLUDE) -I$(top_srcdir)/kpilot/lib $(all_includes) + +METASOURCES = AUTO + +servicedir = $(kde_servicesdir) +service_DATA = memofile-conduit.desktop + +kde_module_LTLIBRARIES = conduit_memofile.la + + +conduit_memofile_la_SOURCES = memofileSettings.kcfgc setup_base.ui \ + memofile-factory.cc memofile.cc memofiles.cc memofile-conduit.cc +conduit_memofile_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +conduit_memofile_la_LIBADD = ../../lib/libkpilot.la $(LIB_KDEUI) $(LIB_KFILE) + +kde_kcfg_DATA = memofileconduit.kcfg diff --git a/conduits/memofileconduit/design/SQD - copyHHToPC.jpg b/conduits/memofileconduit/design/SQD - copyHHToPC.jpg Binary files differnew file mode 100644 index 0000000..82cc118 --- /dev/null +++ b/conduits/memofileconduit/design/SQD - copyHHToPC.jpg diff --git a/conduits/memofileconduit/design/SQD - copyPCToHH.jpg b/conduits/memofileconduit/design/SQD - copyPCToHH.jpg Binary files differnew file mode 100644 index 0000000..ef4254d --- /dev/null +++ b/conduits/memofileconduit/design/SQD - copyPCToHH.jpg diff --git a/conduits/memofileconduit/design/SQD - detailed load.jpg b/conduits/memofileconduit/design/SQD - detailed load.jpg Binary files differnew file mode 100644 index 0000000..4e0601f --- /dev/null +++ b/conduits/memofileconduit/design/SQD - detailed load.jpg diff --git a/conduits/memofileconduit/design/SQD - sync.jpg b/conduits/memofileconduit/design/SQD - sync.jpg Binary files differnew file mode 100644 index 0000000..91299ce --- /dev/null +++ b/conduits/memofileconduit/design/SQD - sync.jpg diff --git a/conduits/memofileconduit/memofile-conduit.cc b/conduits/memofileconduit/memofile-conduit.cc new file mode 100644 index 0000000..954af38 --- /dev/null +++ b/conduits/memofileconduit/memofile-conduit.cc @@ -0,0 +1,567 @@ +/* memofile-conduit.cc KPilot +** +** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper +** +** This file does the actual conduit work. +*/ + +/* +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Bug reports and questions can be sent to [email protected] +*/ + + +#include "options.h" + +// Only include what we really need: +// First UNIX system stuff, then std C++, +// then Qt, then KDE, then local includes. +// +// + +#include <time.h> // required by pilot-link includes + +#include <pi-memo.h> + +#include "pilotMemo.h" + +#include <tqfile.h> +#include <tqdir.h> +#include <tqtextcodec.h> + +#include <kconfig.h> +#include <kdebug.h> + +#include "pilotRecord.h" +#include "pilotSerialDatabase.h" +#include "memofile-factory.h" +#include "memofile-conduit.h" +#include "memofileSettings.h" + + +/** + * Our workhorse. This is the main driver for the conduit. + */ +MemofileConduit::MemofileConduit(KPilotLink *d, + const char *n, + const TQStringList &l) : + ConduitAction(d,n,l), + _DEFAULT_MEMODIR(TQDir::homeDirPath() + CSL1("/MyMemos")), + fMemoAppInfo(0L), + _memofiles(0L) +{ + FUNCTIONSETUP; + fConduitName=i18n("Memofile"); + fMemoList.setAutoDelete(true); +} + +MemofileConduit::~MemofileConduit() +{ + FUNCTIONSETUP; + KPILOT_DELETE(_memofiles); +} + +/* virtual */ bool MemofileConduit::exec() +{ + FUNCTIONSETUP; + + setFirstSync( false ); + // try new format first... + // DEBUGKPILOT << fname << ": trying new format database first." << endl; + bool _open = false; + /* + _open = openDatabases(CSL1("MemosDB-PMem")); + if(!_open) { + DEBUGKPILOT << fname << ": unable to open new format database. trying old one." << endl; + */ + _open = openDatabases(CSL1("MemoDB")); + /* + } else { + DEBUGKPILOT << fname << ": able to open new format database." << endl; + } + */ + + if(!_open) { + emit logError(i18n("Unable to open the memo databases on the handheld.")); + DEBUGKPILOT << fname << ": unable to open new or old format database." << endl; + return false; + } + + readConfig(); + + if (! initializeFromPilot()) { + emit logError(i18n("Cannot initialize from pilot.")); + return false; + } + + _memofiles = new Memofiles(fCategories, *fMemoAppInfo, + _memo_directory, *fCtrHH); + if (! _memofiles || ! _memofiles->isReady()) { + emit logError(i18n("Cannot initialize the memo files from disk.")); + return false; + } + + fCtrPC->setStartCount(_memofiles->count()); + + setFirstSync( _memofiles->isFirstSync() ); + addSyncLogEntry(i18n(" Syncing with %1.").arg(_memo_directory)); + + if ( (syncMode() == SyncAction::SyncMode::eCopyHHToPC) || _memofiles->isFirstSync() ) { + addSyncLogEntry(i18n(" Copying Pilot to PC...")); + DEBUGKPILOT << fname << ": copying Pilot to PC." << endl; + copyHHToPC(); + } else if ( syncMode() == SyncAction::SyncMode::eCopyPCToHH ) { + DEBUGKPILOT << fname << ": copying PC to Pilot." << endl; + addSyncLogEntry(i18n(" Copying PC to Pilot...")); + copyPCToHH(); + } else { + DEBUGKPILOT << fname << ": doing regular sync." << endl; + addSyncLogEntry(i18n(" Doing regular sync...")); + sync(); + } + + cleanup(); + + return delayDone(); +} + +bool MemofileConduit::readConfig() +{ + FUNCTIONSETUP; + + TQString dir(MemofileConduitSettings::directory()); + if (dir.isEmpty()) { + dir = _DEFAULT_MEMODIR; + + DEBUGKPILOT << fname + << ": no directory given to us. defaulting to: [" + << _DEFAULT_MEMODIR + << "]" << endl; + } + + _memo_directory = dir; + _sync_private = MemofileConduitSettings::syncPrivate(); + + + DEBUGKPILOT << fname + << ": Settings... " + << " directory: [" << _memo_directory + << "], first sync: [" << isFirstSync() + << "], sync private: [" << _sync_private + << "]" << endl; + + return true; + +} + +bool MemofileConduit::setAppInfo() +{ + FUNCTIONSETUP; + + // reset our category mapping from the filesystem + MemoCategoryMap map = _memofiles->readCategoryMetadata(); + + if (map.count() <=0) { + DEBUGKPILOT << fname + << ": category metadata map is empty, nothing to do." << endl; + return true; + } + + fCategories = map; + + for (unsigned int i = 0; i < Pilot::CATEGORY_COUNT; i++) + { + if (fCategories.tqcontains(i)) { + fMemoAppInfo->setCategoryName(i,fCategories[i]); + } + } + + if (fDatabase) + { + fMemoAppInfo->writeTo(fDatabase); + } + if (fLocalDatabase) + { + fMemoAppInfo->writeTo(fLocalDatabase); + } + + return true; +} + +bool MemofileConduit::getAppInfo() +{ + FUNCTIONSETUP; + + KPILOT_DELETE(fMemoAppInfo); + fMemoAppInfo = new PilotMemoInfo(fDatabase); + fMemoAppInfo->dump(); + return true; +} + + +/** + * Methods related to getting set up from the Pilot. + */ + +bool MemofileConduit::initializeFromPilot() +{ + + if (!getAppInfo()) return false; + + if (!loadPilotCategories()) return false; + + return true; +} + +bool MemofileConduit::loadPilotCategories() +{ + FUNCTIONSETUP; + + fCategories.clear(); + + TQString _category_name; + int _category_id=0; + int _category_num=0; + + for (unsigned int i = 0; i < Pilot::CATEGORY_COUNT; i++) + { + _category_name = fMemoAppInfo->categoryName(i); + if (!_category_name.isEmpty()) + { + _category_name = Memofiles::sanitizeName( _category_name ); + _category_id = fMemoAppInfo->categoryInfo()->ID[i]; + _category_num = i; + fCategories[_category_num] = _category_name; + + DEBUGKPILOT << fname + << ": Category #" + << _category_num + << " has ID " + << _category_id + << " and name " + <<_category_name << endl; + } + } + return true; +} + +/** + * Read all memos in from Pilot. + */ +void MemofileConduit::getAllFromPilot() +{ + FUNCTIONSETUP; + + DEBUGKPILOT << fname + << ": Database has " << fDatabase->recordCount() + << " records." << endl; + + fMemoList.clear(); + + int currentRecord = 0; + PilotRecord *pilotRec; + PilotMemo *memo = 0; + + while ((pilotRec = fDatabase->readRecordByIndex(currentRecord)) != NULL) { + if ((!pilotRec->isSecret()) || _sync_private) { + memo = new PilotMemo(pilotRec); + fMemoList.append(memo); + + DEBUGKPILOT << fname + << ": Added memo: [" + << currentRecord + << "], id: [" + << memo->id() + << "], category: [" + << fCategories[memo->category()] + << "], title: [" + << memo->getTitle() + << "]" << endl; + } else { + DEBUGKPILOT << fname + << ": Skipped secret record: [" + << currentRecord + << "], title: [" + << memo->getTitle() + << "]" << endl; + } + + KPILOT_DELETE(pilotRec); + + currentRecord++; + } + + DEBUGKPILOT << fname + << ": read: [" << fMemoList.count() + << "] records from palm." << endl; +} + +/** + * Read all modified memos in from Pilot. + */ +void MemofileConduit::getModifiedFromPilot() +{ + FUNCTIONSETUP; + + fMemoList.clear(); + + int currentRecord = 0; + PilotRecord *pilotRec; + PilotMemo *memo = 0; + + while ((pilotRec = fDatabase->readNextModifiedRec()) != NULL) { + memo = new PilotMemo(pilotRec); + // we are syncing to both our filesystem and to the local + // database, so take care of the local database here + if (memo->isDeleted()) { + fLocalDatabase->deleteRecord(memo->id()); + } else { + fLocalDatabase->writeRecord(pilotRec); + } + + if ((!pilotRec->isSecret()) || _sync_private) { + fMemoList.append(memo); + + DEBUGKPILOT << fname + << ": modified memo id: [" + << memo->id() + << "], title: [" + << memo->getTitle() + << "]" << endl; + } else { + DEBUGKPILOT << fname + << ": skipped secret modified record id: [" + << memo->id() + << "], title: [" + << memo->getTitle() + << "]" << endl; + } + + KPILOT_DELETE(pilotRec); + + currentRecord++; + } + + DEBUGKPILOT << fname + << ": read: [" << fMemoList.count() + << "] modified records from palm." << endl; +} + + +/* slot */ void MemofileConduit::process() +{ + FUNCTIONSETUP; + + DEBUGKPILOT << fname << ": Now in state " << fActionStatus << endl; +} + + +void MemofileConduit::listPilotMemos() +{ + FUNCTIONSETUP; + + PilotMemo *memo; + for ( memo = fMemoList.first(); memo; memo = fMemoList.next() ) { + TQString _category_name = fCategories[memo->category()]; + + DEBUGKPILOT << fConduitName + << ": listing record id: [" << memo->id() + << "] category id: [" << memo->category() + << "] category name: [" << _category_name + << "] title: [" << memo->getTitle() + << "]" << endl; + } +} + +bool MemofileConduit::copyHHToPC() +{ + FUNCTIONSETUP; + + getAllFromPilot(); + + _memofiles->eraseLocalMemos(); + + _memofiles->setPilotMemos(fMemoList); + + _memofiles->save(); + + return true; + +} + +bool MemofileConduit::copyPCToHH() +{ + FUNCTIONSETUP; + + // set category info from the filesystem, if we can. + // Note: This will reset both fCategories and fMemoAppInfo, so + // after this, we need to reinitialize our memofiles object... + setAppInfo(); + + // re-create our memofiles helper... + KPILOT_DELETE(_memofiles); + _memofiles = new Memofiles(fCategories, *fMemoAppInfo, + _memo_directory, *fCtrHH); + + _memofiles->load(true); + + TQPtrList<Memofile> memofiles = _memofiles->getAll(); + + Memofile * memofile; + + for ( memofile = memofiles.first(); memofile; memofile = memofiles.next() ) { + writeToPilot(memofile); + } + + _memofiles->save(); + + // now that we've copied from the PC to our handheld, remove anything extra from the + // handheld... + deleteUnsyncedHHRecords(); + + return true; + +} + +void MemofileConduit::deleteUnsyncedHHRecords() +{ + FUNCTIONSETUP; + if ( syncMode()==SyncMode::eCopyPCToHH ) + { + Pilot::RecordIDList ids=fDatabase->idList(); + Pilot::RecordIDList::iterator it; + for ( it = ids.begin(); it != ids.end(); ++it ) + { + if (!_memofiles->find(*it)) + { + DEBUGKPILOT << fname + << "Deleting record with ID "<< *it <<" from handheld " + << "(is not on PC, and syncing with PC->HH direction)" + << endl; + fDatabase->deleteRecord(*it); + fLocalDatabase->deleteRecord(*it); + } + } + } +} + +int MemofileConduit::writeToPilot(Memofile * memofile) +{ + FUNCTIONSETUP; + + int oldid = memofile->id(); + + PilotRecord *r = memofile->pack(); + + if (!r) { + DEBUGKPILOT << fname + << ": ERROR: [" << memofile->toString() + << "] could not be written to the pilot." + << endl; + return -1; + } + + int newid = fDatabase->writeRecord(r); + fLocalDatabase->writeRecord(r); + + KPILOT_DELETE(r); + + memofile->setID(newid); + + TQString status; + if (oldid <=0) { + fCtrHH->created(); + status = "new to pilot"; + } else { + fCtrHH->updated(); + status = "updated"; + } + + DEBUGKPILOT << fname + << ": memofile: [" << memofile->toString() + << "] written to the pilot, [" << status << "]." + << endl; + + return newid; +} + +void MemofileConduit::deleteFromPilot(PilotMemo * memo) +{ + FUNCTIONSETUP; + + PilotRecord *r = memo->pack(); + if (r) { + r->setDeleted(true); + fDatabase->writeRecord(r); + fLocalDatabase->writeRecord(r); + } + KPILOT_DELETE(r); + + fCtrHH->deleted(); + + DEBUGKPILOT << fname + << ": memo: [" << memo->getTitle() + << "] deleted from the pilot." + << endl; +} + +bool MemofileConduit::sync() +{ + FUNCTIONSETUP; + + _memofiles->load(false); + + getModifiedFromPilot(); + + PilotMemo *memo; + for ( memo = fMemoList.first(); memo; memo = fMemoList.next() ) { + _memofiles->addModifiedMemo(memo); + } + + TQPtrList<Memofile> memofiles = _memofiles->getModified(); + + Memofile *memofile; + for ( memofile = memofiles.first(); memofile; memofile = memofiles.next() ) { + if (memofile->isDeleted()) { + deleteFromPilot(memofile); + } else { + writeToPilot(memofile); + } + } + + _memofiles->save(); + + return true; +} + +void MemofileConduit::cleanup() +{ + FUNCTIONSETUP; + + fDatabase->resetSyncFlags(); + fDatabase->cleanup(); + fLocalDatabase->resetSyncFlags(); + fLocalDatabase->cleanup(); + + fCtrPC->setEndCount(_memofiles->count()); +} + + +#include "memofile-conduit.moc" + diff --git a/conduits/memofileconduit/memofile-conduit.desktop b/conduits/memofileconduit/memofile-conduit.desktop new file mode 100644 index 0000000..cb288d2 --- /dev/null +++ b/conduits/memofileconduit/memofile-conduit.desktop @@ -0,0 +1,91 @@ +[Desktop Entry] +Type=Service +Name=Memo File +Name[af]=Memo Lêer +Name[bg]=Бележка +Name[ca]=Fitxer de notes +Name[cs]=Soubor s poznámkou +Name[da]=Memo-fil +Name[de]=Memo Datei +Name[el]=Αρχείο υπομνήματος +Name[eo]=Memo-dosiero +Name[es]=Archivo de nota +Name[et]=Memofail +Name[eu]=Ohar fitxategia +Name[fa]=پروندۀ Memo +Name[fi]=Muistiotiedosto +Name[fr]=Fichier mémo +Name[fy]=Memotriem +Name[ga]=Comhad Meamraim +Name[gl]=Ficheiro Memo +Name[hu]=Memófájl +Name[is]=Minnismiðaskrá +Name[it]=File appunti +Name[ja]=メモファイル +Name[kk]=Жазба файлы +Name[km]=ឯកសារអនុស្សរណៈ +Name[lt]=Memo byla +Name[ms]=Fail Memo +Name[nb]=Notatfil +Name[nds]=Notiz-Datei +Name[ne]=स्मृति फाइल +Name[nl]=Memobestand +Name[nn]=Memofil +Name[pl]=Plik notatki +Name[pt]=Ficheiro Memorando +Name[pt_BR]=Arquivo Memo +Name[ru]=Заметка +Name[sk]=Memo súbor +Name[sl]=Datoteka z opombami +Name[sv]=Anteckningsfil +Name[ta]=மெமோ கோப்பு +Name[tr]=Hatırlatma Dosyası +Name[uk]=Файл примітки +Name[zh_CN]=备忘文件 +Name[zh_TW]=Memo 檔 +Comment=This conduit syncs your handheld memos with a local directory. +Comment[af]=Hierdie pad sinkroniseer jou draagbare toestel se memos met 'n plaaslike gids. +Comment[bg]=Синхронизация на бележките на KDE с мобилни устройства. +Comment[ca]=Aquest conducte sincronitza les notes de l'agenda electrònica amb un directori local. +Comment[cs]=Toto propojení synchronizuje vaše poznámky v PDA s lokálním adresářem. +Comment[da]=Denne kanal synkroniserer dine håndholdte memoer med en lokal mappe. +Comment[de]=Abgleich der Memos von Taschencomputer und einem lokalen Ordner +Comment[el]=Αυτός ο σύνδεσμος συγχρονίζει τα υπομνήματα του υπολογιστή παλάμης σας με έναν τοπικό κατάλογο. +Comment[eo]=Tiu kanalo sinkronigas viajn poŝkomputil-memoojn kun loka dosierujo. +Comment[es]=Este conducto sincroniza las notas de su agenda electrónica con el directorio local. +Comment[et]=See kanal sünkroniseerib pihuarvutis ja arvutis olevad memod. +Comment[eu]=Kanal honek zure agendako oharrak direktorio lokal batekin sinkronizatzen ditu. +Comment[fa]=این لوله، memoهای دستی خود را با فهرست راهنمای محلی همگامسازی میکند. +Comment[fi]=Tämä yhdyskäytävä synkronoi taskutietokoneen muistiot paikalliseen kansioon. +Comment[fr]=Ce canal synchronise les mémos du Palm avec ceux de KDE. +Comment[fy]=Dit conduit syngronisearret de memo's fan jo handheld mei in lokale triemtafel. +Comment[gl]=Este conducto sincroniza os memos do seu aparello portátil cun cartafol local. +Comment[hu]=Ezzel a csatolóval egy kézi számítógép memóit lehet szinkronizálni a helyi címjegyzékkel. +Comment[is]=Þessi rás samstillir minnismiða lófatölvunnar þinnar við staðbundna möppu. +Comment[it]=Questo condotto sincronizza gli appunti del tuo palmare con una cartella locale. +Comment[ja]=このコンジットはハンドヘルドのメモをローカルのディレクトリと同期させます。 +Comment[kk]=Қалта құрылғыдағы жазбаларды қапшықтағы файлымен қадамдастыру арнасы. +Comment[km]=បំពង់នេះអាចឲ្យអនុស្សរណៈឧបករណ៍យួរដៃរបស់អ្នក ធ្វើសមកាលកម្មជាមួយនឹងថតមូលដ្ឋាន ។ +Comment[lt]=Šis kanalas sinchronizuoja Jūsų užrašus su vietiniu aplanku. +Comment[ms]=Saluran ini mensegerakkan memo komputer telapak anda dengan direktori setempat. +Comment[nb]=Denne kanalen synkroniserer PDA-ens notater med en lokal mappe. +Comment[nds]=Synkroniseert de Notizen op den Handreekner mit en lokaal Orner. +Comment[ne]=यो कन्ड्युटले स्थानीय डाइरेक्टरीमा तपाईँका ह्यान्डहेल्ड मेमो सिन्क गर्दछ । +Comment[nl]=Dit conduit synchroniseert de memo's van uw handheld met een lokale map. +Comment[pl]=Ten łącznik synchronizuje notatki z palmtopa z lokalnym katalogiem. +Comment[pt]=Esta conduta sincroniza os memorandos do seu PDA com uma pasta local. +Comment[pt_BR]=Este conduíte sincroniza as anotações no seu handheld com um diretório local. +Comment[ru]=Канал синхронизации заметок КПК и KDE. +Comment[sk]=Táto spojka synchronizuje adresár vášho prenosného zariadenia s lokálnym priečinkom. +Comment[sl]=Ta veznik usklajuje opombe v ročnem računalniku s krajevnim imenikom. +Comment[sr]=Овај провод синхронизује белешке на вашем ручном рачунару са локалним директоријумом. +Comment[sr@Latn]=Ovaj provod sinhronizuje beleške na vašem ručnom računaru sa lokalnim direktorijumom. +Comment[sv]=Den här kanalen synkroniserar handdatorns anteckningar med en lokal katalog. +Comment[ta]=இந்த குழாய் கையில் உள்ள முகவரிப்புத்தகத்தை கேடிஇயின் முகவரிப்புத்தகத்தோடு ஒத்திசைக்கிறது +Comment[tr]=Bu bileşen el bilgisayarı hatırlatmalarını yerel bir dosyaya aktarır veya alır. +Comment[uk]=Цей акведук синхронізує примітки кишенькового пристрою з локальним каталогом. +Comment[zh_CN]=此管道会将您手持设备中的备忘与本地目录同步。 +Comment[zh_TW]=此軟體同步您的 handheld memo 及本地端目錄。 +Implemented=file +ServiceTypes=KPilotConduit +X-KDE-Library=conduit_memofile diff --git a/conduits/memofileconduit/memofile-conduit.h b/conduits/memofileconduit/memofile-conduit.h new file mode 100644 index 0000000..c795066 --- /dev/null +++ b/conduits/memofileconduit/memofile-conduit.h @@ -0,0 +1,92 @@ +#ifndef _MEMOFILE_MEMOFILE_CONDUIT_H +#define _MEMOFILE_MEMOFILE_CONDUIT_H +/* memofile-conduit.h KPilot +** +** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper +*/ + +/* +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Bug reports and questions can be sent to [email protected] +*/ + +#include <pi-memo.h> + +#include "plugin.h" + +#include "memofiles.h" + +class PilotMemo; + +class MemofileConduit : public ConduitAction +{ +Q_OBJECT +public: + MemofileConduit(KPilotLink *, + const char *name=0L, + const TQStringList &args = TQStringList()); + virtual ~MemofileConduit(); + +protected: + virtual bool exec(); + + +protected slots: + void process(); + +private: + // configuration settings... + QString _DEFAULT_MEMODIR; + QString _memo_directory; + bool _sync_private; + + PilotMemoInfo *fMemoAppInfo; + TQPtrList<PilotMemo> fMemoList; + + // our categories + MemoCategoryMap fCategories; + + Memofiles * _memofiles; + + + bool readConfig(); + bool getAppInfo(); + bool setAppInfo(); + + bool initializeFromPilot(); + bool loadPilotCategories(); + + void listPilotMemos(); + + void getAllFromPilot(); + void getModifiedFromPilot(); + + bool copyHHToPC(); + bool copyPCToHH(); + void deleteUnsyncedHHRecords(); + bool sync(); + + int writeToPilot(Memofile * memofile); + void deleteFromPilot(PilotMemo* memo); + + void cleanup(); + +}; + +#endif diff --git a/conduits/memofileconduit/memofile-factory.cc b/conduits/memofileconduit/memofile-factory.cc new file mode 100644 index 0000000..795edc3 --- /dev/null +++ b/conduits/memofileconduit/memofile-factory.cc @@ -0,0 +1,128 @@ +/* memofile-factory.cc KPilot +** +** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper +** +** This file defines the factory for the memofile-conduit plugin. +*/ + +/* +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Bug reports and questions can be sent to [email protected] +*/ + +#include "options.h" + +#include <tqtabwidget.h> +#include <tqlineedit.h> +#include <tqcheckbox.h> + +#include <kconfig.h> +#include <kinstance.h> +#include <kaboutdata.h> +#include <kurlrequester.h> + +#include "setup_base.h" +#include "memofile-conduit.h" +#include "memofileSettings.h" + +#include "pluginfactory.h" + +class MemofileConduitConfig : public ConduitConfigBase +{ +public: + MemofileConduitConfig(TQWidget *parent=0L, const char *n=0L); + virtual void commit(); + virtual void load(); +protected: + MemofileWidget *fConfigWidget; +} ; + +MemofileConduitConfig::MemofileConduitConfig(TQWidget *p, const char *n) : + ConduitConfigBase(p,n), + fConfigWidget(new MemofileWidget(p)) +{ + FUNCTIONSETUP; + fConduitName = i18n("Memofile"); + KAboutData *about = new KAboutData("MemofileConduit", + I18N_NOOP("Memofile Conduit for KPilot"), + KPILOT_VERSION, + I18N_NOOP("Configures the Memofile Conduit for KPilot"), + KAboutData::License_GPL, + "(C) 2004, Jason 'vanRijn' Kasper"); + about->addAuthor("Jason 'vanRijn' Kasper", + I18N_NOOP("Primary Author"), + "[email protected]", + "http://www.cs.kun.nl/~adridg/kpilot"); + + ConduitConfigBase::addAboutPage(fConfigWidget->tabWidget,about); + fWidget=fConfigWidget; + TQObject::connect(fConfigWidget->fDirectory,TQT_SIGNAL(textChanged(const TQString&)), + this,TQT_SLOT(modified())); + TQObject::connect(fConfigWidget->fSyncPrivate,TQT_SIGNAL(toggled(bool)), + this,TQT_SLOT(modified())); + +} + +/* virtual */ void MemofileConduitConfig::commit() +{ + FUNCTIONSETUP; + + DEBUGKPILOT << fname + << ": Directory=" + << fConfigWidget->fDirectory->url() + << endl; + + MemofileConduitSettings::setDirectory( fConfigWidget->fDirectory->url() ); + MemofileConduitSettings::setSyncPrivate( fConfigWidget->fSyncPrivate->isChecked() ); + MemofileConduitSettings::self()->writeConfig(); + unmodified(); +} + +/* virtual */ void MemofileConduitConfig::load() +{ + FUNCTIONSETUP; + MemofileConduitSettings::self()->readConfig(); + + fConfigWidget->fDirectory->setURL( MemofileConduitSettings::directory() ); + fConfigWidget->fSyncPrivate->setChecked( MemofileConduitSettings::syncPrivate() ); + + DEBUGKPILOT << fname + << ": Read Directory: [" + << fConfigWidget->fDirectory->url() + << "], sync private records: [" + << fConfigWidget->fSyncPrivate + << "]" << endl; + + unmodified(); +} + + + +extern "C" +{ + +void *init_conduit_memofile() +{ + return new ConduitFactory<MemofileConduitConfig,MemofileConduit>(0,"memofileconduit"); +} + +unsigned long version_conduit_memofile = Pilot::PLUGIN_API; + +} + diff --git a/conduits/memofileconduit/memofile-factory.h b/conduits/memofileconduit/memofile-factory.h new file mode 100644 index 0000000..b42fb65 --- /dev/null +++ b/conduits/memofileconduit/memofile-factory.h @@ -0,0 +1,40 @@ +#ifndef _KPILOT_MEMOFILE_FACTORY_H +#define _KPILOT_MEMOFILE_FACTORY_H +/* memofile-factory.h KPilot +** +** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper +** +** This file defines the factory for the Memofile-conduit plugin. +** It also defines the class for the behavior of the setup dialog. +*/ + +/* +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Bug reports and questions can be sent to [email protected] +*/ + + +extern "C" +{ + +void *init_libmemofileconduit(); + +} + +#endif diff --git a/conduits/memofileconduit/memofile.cc b/conduits/memofileconduit/memofile.cc new file mode 100644 index 0000000..3a7ff6c --- /dev/null +++ b/conduits/memofileconduit/memofile.cc @@ -0,0 +1,239 @@ +/* memofile.cc KPilot +** +** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper +** +*/ + +/* +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Bug reports and questions can be sent to [email protected] +*/ + +#include "memofile.h" + +Memofile::Memofile(PilotMemo * memo, TQString categoryName, TQString fileName, TQString baseDirectory) : + PilotMemo(memo,memo->text()), _categoryName(categoryName), _filename(fileName), _baseDirectory(baseDirectory) +{ + _lastModified = 0; + _size = 0; + _modified = _modifiedByPalm = false; +} + +Memofile::Memofile(recordid_t id, int category, uint lastModifiedTime, uint size, + TQString categoryName, TQString fileName, TQString baseDirectory) : + PilotMemo(), _categoryName(categoryName), + _filename(fileName),_baseDirectory(baseDirectory) +{ + setID(id); + PilotRecordBase::setCategory(category); + _lastModified = lastModifiedTime; + _size = size; + _modified = _modifiedByPalm = false; +} + +Memofile::Memofile(int category, TQString categoryName, TQString fileName, TQString baseDirectory) : + PilotMemo(), + _categoryName(categoryName), _filename(fileName), _baseDirectory(baseDirectory) +{ + setID(0); + _new = true; + PilotRecordBase::setCategory(category); + _modified = true; + _modifiedByPalm = false; + _lastModified = 0; + _size = 0; +} + +bool Memofile::load() +{ + FUNCTIONSETUP; + if (filename().isEmpty()) { + DEBUGKPILOT << fname + << ": I was asked to load, but have no filename to load. " + << endl; + return false; + } + + TQFile f( filenameAbs() ); + if ( !f.open( IO_ReadOnly ) ) { + DEBUGKPILOT << fname + << ": Couldn't open file: [" << filenameAbs() << "] to read. " + << endl; + return false; + } + + TQTextStream ts( &f ); + + TQString text,title,body; + title = filename(); + body = ts.read(); + + // funky magic. we want the text of the memofile to have the filename + // as the first line.... + if (body.startsWith(title)) { + text = body; + } else { + DEBUGKPILOT << fname + << ": text of your memofile: [" << filename() + << "] didn't include the filename as the first line. fixing it..." << endl; + text = title + CSL1("\n") + body; + } + + // check length of text. if it's over the allowable length, warn user. + // NOTE: We don't need to truncate this here, since PilotMemo::setText() + // does it for us. + int _len = text.length(); + int _maxlen = PilotMemo::MAX_MEMO_LEN; + if (_len > _maxlen) { + DEBUGKPILOT << fname << ": memofile: [" << filename() + << "] length: [" << _len << "] is over maximum: [" + << _maxlen << "] and will be truncated to fit." << endl; + } + + setText(text); + f.close(); + + return true; +} + +void Memofile::setID(recordid_t i) +{ + if (i != id()) + _modifiedByPalm = true; + + PilotMemo::setID(i); +} + +bool Memofile::save() +{ + bool result = true; + + if ((isModified() && isLoaded()) || _modifiedByPalm) { + result = saveFile(); + } + + return result; +} + +bool Memofile::deleteFile() +{ + FUNCTIONSETUP; + DEBUGKPILOT << fname + << ": deleting file: [" << filenameAbs() << "]." << endl; + return TQFile::remove(filenameAbs()); + +} + +bool Memofile::saveFile() +{ + FUNCTIONSETUP; + + if (filename().isEmpty()) { + DEBUGKPILOT << fname + << ": I was asked to save, but have no filename to save to. " + << endl; + return false; + } + + DEBUGKPILOT << fname + << ": saving memo to file: [" + << filenameAbs() << "]" << endl; + + + TQFile f( filenameAbs() ); + if ( !f.open( IO_WriteOnly ) ) { + DEBUGKPILOT << fname + << ": Couldn't open file: [" << filenameAbs() << "] to write your memo to. " + << "This won't end well." << endl; + return false; + } + + TQTextStream stream(&f); + stream << text() << endl; + f.close(); + + _lastModified = getFileLastModified(); + _size = getFileSize(); + + return true; + +} + +bool Memofile::isModified(void) +{ + // first, check to see if this file is deleted.... + if (!fileExists()) { + return true; + } + + bool modByTimestamp = false; + bool modBySize = false; + + if (_lastModified > 0) + modByTimestamp = isModifiedByTimestamp(); + + if (_size > 0) + modBySize = isModifiedBySize(); + + bool ret = _modified || modByTimestamp || modBySize; + + return ret; +} + +bool Memofile::isModifiedByTimestamp() +{ + if (_lastModified <=0) { + return true; + } + + uint lastModifiedTime = getFileLastModified(); + if ( lastModifiedTime != _lastModified) { + return true; + } + + return false; +} + +bool Memofile::isModifiedBySize() +{ + if (_size <=0) { + return true; + } + + uint size = getFileSize(); + if ( size != _size) { + return true; + } + + return false; +} + +uint Memofile::getFileLastModified() +{ + TQFileInfo f = TQFileInfo(filenameAbs()); + uint lastModifiedTime = f.lastModified().toTime_t(); + return lastModifiedTime; +} + +uint Memofile::getFileSize() +{ + TQFileInfo f = TQFileInfo(filenameAbs()); + uint size = f.size(); + return size; +} diff --git a/conduits/memofileconduit/memofile.h b/conduits/memofileconduit/memofile.h new file mode 100644 index 0000000..4bd5fb7 --- /dev/null +++ b/conduits/memofileconduit/memofile.h @@ -0,0 +1,113 @@ +#ifndef _MEMOFILE_MEMOFILE_H +#define _MEMOFILE_MEMOFILE_H +/* memofile.h KPilot +** +** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper +** +*/ + +/* +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Bug reports and questions can be sent to [email protected] +*/ + + +#include "options.h" + +// Only include what we really need: +// First UNIX system stuff, then std C++, +// then Qt, then KDE, then local includes. +// +// + +#include <time.h> // required by pilot-link includes + +#include <pi-memo.h> + +#include <tqfile.h> +#include <tqdir.h> +#include <tqtextstream.h> +#include <tqtextcodec.h> + +#include "pilotMemo.h" + +#include "memofiles.h" + +/** + * Class that represents our filesystem memo. + */ +class Memofile : public PilotMemo +{ + public: + Memofile(PilotMemo * memo, TQString categoryName, TQString fileName, TQString baseDirectory); + Memofile(recordid_t id, int category, uint lastModifiedTime, uint size, TQString categoryName, TQString filename, TQString baseDirectory); + Memofile(int category, TQString categoryName, TQString fileName, TQString baseDirectory); + + uint lastModified() const { return _lastModified; } ; + uint size() const { return _size; } ; + + void setModifiedByPalm(bool mod) { _modifiedByPalm = mod; } ; + void setModified(bool modified) { _modified = modified; } ; + + bool isModified(void); + bool isModifiedByPalm() { return _modifiedByPalm; } ; + bool isLoaded(void) { return (! text().isEmpty()); } ; + bool isNew(void) { return _new; } ; + + bool load(); + + bool fileExists() { return TQFile::exists(filenameAbs()); } ; + + void setID(recordid_t id); + + bool save(); + bool deleteFile(); + + TQString toString() { + return CSL1("id: [") + TQString::number(id()) + + CSL1("], category:[") + _categoryName + + CSL1("], filename: [") + _filename + CSL1("]"); + } ; + const TQString & getCategoryName() { return _categoryName; } ; + const TQString & getFilename() { return _filename; } ; + const TQString & filename() { return _filename; } ; + + private: + bool saveFile(); + bool isModifiedByTimestamp(); + bool isModifiedBySize(); + + TQString filenameAbs() { return dirName() + filename(); } ; + TQString dirName() { return _baseDirectory + TQDir::separator() + _categoryName + TQDir::separator(); } ; + bool setCategory(const TQString &label); + uint getFileLastModified(); + uint getFileSize(); + + bool _modifiedByPalm; + bool _modified; + bool _new; + uint _lastModified; + uint _size; + + TQString _categoryName; + TQString _filename; + TQString _baseDirectory; +} ; + +#endif diff --git a/conduits/memofileconduit/memofileSettings.kcfgc b/conduits/memofileconduit/memofileSettings.kcfgc new file mode 100644 index 0000000..3d1373b --- /dev/null +++ b/conduits/memofileconduit/memofileSettings.kcfgc @@ -0,0 +1,7 @@ +File=memofileconduit.kcfg +ClassName= MemofileConduitSettings +Singleton=true +ItemAccessors=true +Mutators=true +GlobalEnums=true +SetUserTexts=true diff --git a/conduits/memofileconduit/memofileconduit.kcfg b/conduits/memofileconduit/memofileconduit.kcfg new file mode 100644 index 0000000..506e040 --- /dev/null +++ b/conduits/memofileconduit/memofileconduit.kcfg @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE kcfg SYSTEM "http://www.kde.org/standards/kcfg/1.0/kcfg.dtd"> +<kcfg><kcfgfile name="kpilotrc"/> + <group name="memofile-conduit"> + <entry name="Directory" type="Path"> + <label>What directory do you want to sync your PDA's memos with?</label> + <default>$HOME/MyMemos</default> + </entry> + <entry name="SyncPrivate" type="Bool"> + <label>Do you want to sync your private records to the filesystem?</label> + <default>true</default> + </entry> + + </group> + +</kcfg> diff --git a/conduits/memofileconduit/memofileconduit.xmi b/conduits/memofileconduit/memofileconduit.xmi new file mode 100644 index 0000000..33ff89f --- /dev/null +++ b/conduits/memofileconduit/memofileconduit.xmi @@ -0,0 +1,241 @@ +<?xml version="1.0" encoding="UTF-8"?> +<XMI xmlns:UML="org.omg/standards/UML" verified="false" timestamp="" xmi.version="1.2" > + <XMI.header> + <XMI.documentation> + <XMI.exporter>umbrello uml modeller http://uml.sf.net</XMI.exporter> + <XMI.exporterVersion>1.2.90</XMI.exporterVersion> + <XMI.exporterEncoding>UnicodeUTF8</XMI.exporterEncoding> + </XMI.documentation> + <XMI.model xmi.name="umbrelloJSFhpc" href="/tmp/kde-gideon/umbrelloJSFhpc.tmp" /> + <XMI.metamodel xmi.name="UML" href="UML.xml" xmi.version="1.3" /> + </XMI.header> + <XMI.content> + <UML:Model> + <UML:Stereotype visibility="public" xmi.id="3" name="datatype" /> + <UML:Stereotype visibility="public" xmi.id="18" name="enum" /> + <UML:Stereotype visibility="public" xmi.id="35" name="typedef" /> + <UML:DataType stereotype="3" visibility="public" xmi.id="2" name="int" /> + <UML:DataType stereotype="3" visibility="public" xmi.id="4" name="char" /> + <UML:DataType stereotype="3" visibility="public" xmi.id="5" name="bool" /> + <UML:DataType stereotype="3" visibility="public" xmi.id="6" name="float" /> + <UML:DataType stereotype="3" visibility="public" xmi.id="7" name="double" /> + <UML:DataType stereotype="3" visibility="public" xmi.id="8" name="long" /> + <UML:DataType stereotype="3" visibility="public" xmi.id="9" name="short" /> + <UML:DataType stereotype="3" visibility="public" xmi.id="10" name="string" /> + <UML:Class visibility="public" xmi.id="11" name="MemofileConduit" > + <UML:Operation visibility="public" xmi.id="12" type="" name="MemofileConduit" > + <UML:Parameter visibility="public" xmi.id="13" value="" type="KPilotDeviceLink*" /> + <UML:Parameter visibility="public" xmi.id="14" value="" type="const char*" name="name" /> + <UML:Parameter visibility="public" xmi.id="15" value="" type="const QStringList&" name="args" /> + </UML:Operation> + <UML:Operation visibility="public" xmi.id="16" type="" name="~ MemofileConduit" /> + <UML:Operation visibility="protected" xmi.id="26" type="bool" name="exec" /> + <UML:Operation visibility="protected" xmi.id="27" type="void" name="listPilotMemos" /> + <UML:Operation visibility="protected" xmi.id="28" type="void" name="process" /> + <UML:Operation visibility="private" xmi.id="43" type="bool" name="readConfig" /> + <UML:Operation visibility="private" xmi.id="44" type="void" name="getAppInfo" /> + <UML:Operation visibility="private" xmi.id="45" type="QString" name="getCategoryName" > + <UML:Parameter visibility="public" xmi.id="46" value="" type="int" name="category" /> + </UML:Operation> + <UML:Operation visibility="private" xmi.id="47" type="bool" name="initializeFromPilot" /> + <UML:Operation visibility="private" xmi.id="48" type="bool" name="loadPilotMemos" /> + <UML:Operation visibility="private" xmi.id="49" type="bool" name="loadPilotCategories" /> + <UML:Operation visibility="private" xmi.id="50" type="bool" name="initializeFromFilesystem" /> + <UML:Operation visibility="private" xmi.id="51" type="bool" name="initializeMemofileList" /> + <UML:Operation visibility="private" xmi.id="52" type="bool" name="checkDirectory" > + <UML:Parameter visibility="public" xmi.id="53" value="" type="QString" name="dir" /> + </UML:Operation> + <UML:Operation visibility="private" xmi.id="54" type="bool" name="ensureFilesystemReady" /> + <UML:Operation visibility="private" xmi.id="55" type="bool" name="copyHHToPC" /> + <UML:Operation visibility="private" xmi.id="56" type="bool" name="saveCategoriesToFilesystem" /> + <UML:Operation visibility="private" xmi.id="57" type="bool" name="saveMemoInfoToFilesystem" /> + <UML:Operation visibility="private" xmi.id="58" type="bool" name="saveMemosToFilesystem" /> + <UML:Operation visibility="private" xmi.id="59" type="bool" name="saveAsText" > + <UML:Parameter visibility="public" xmi.id="60" value="" type="const QString&" name="fileName" /> + <UML:Parameter visibility="public" xmi.id="61" value="" type="Memofile*" name="theMemo" /> + </UML:Operation> + <UML:Attribute visibility="private" xmi.id="29" value="" type="QString" name="_DEFAULT_MEMODIR" /> + <UML:Attribute visibility="private" xmi.id="30" value="" type="QString" name="_memo_directory" /> + <UML:Attribute visibility="private" xmi.id="31" value="" type="bool" name="_sync_private" /> + <UML:Attribute visibility="private" xmi.id="32" value="" type="QPtrList< PilotMemo >" name="fMemoList" /> + <UML:Attribute visibility="private" xmi.id="33" value="" type="struct MemoAppInfo" name="fMemoAppInfo" /> + <UML:Attribute visibility="private" xmi.id="37" value="" type="QPtrList< Memofile >" name="fMemofileList" /> + <UML:Attribute visibility="private" xmi.id="38" value="" type="int" name="fRecordIndex" /> + <UML:Attribute visibility="private" xmi.id="39" value="" type="QTimer*" name="fTimer" /> + <UML:Attribute visibility="private" xmi.id="40" value="" type="int" name="fCounter" /> + <UML:Attribute visibility="private" xmi.id="41" value="" type="int" name="fDeleteCounter" /> + <UML:Attribute visibility="private" xmi.id="42" value="" type="int" name="fModifyCounter" /> + <UML:Enumeration stereotype="18" visibility="public" xmi.id="17" name="Status" > + <UML:EnumerationLiteral visibility="public" xmi.id="19" name="Init" /> + <UML:EnumerationLiteral visibility="public" xmi.id="20" name="ModifiedFilesToPilot" /> + <UML:EnumerationLiteral visibility="public" xmi.id="21" name="DeleteFilesOnPilot" /> + <UML:EnumerationLiteral visibility="public" xmi.id="22" name="NewFilesToPilot" /> + <UML:EnumerationLiteral visibility="public" xmi.id="23" name="MemosToFiles" /> + <UML:EnumerationLiteral visibility="public" xmi.id="24" name="Cleanup" /> + <UML:EnumerationLiteral visibility="public" xmi.id="25" name="Done" /> + </UML:Enumeration> + <UML:Class stereotype="35" visibility="public" xmi.id="34" name="MemoCategoryMap" /> + </UML:Class> + <UML:Class visibility="public" xmi.id="63" name="Memofiles" > + <UML:Operation visibility="public" xmi.id="80" type="Memofiles" name="Memofiles" > + <UML:Parameter visibility="public" xmi.id="81" value="" type="QMap" name="categories" /> + <UML:Parameter visibility="public" xmi.id="82" value="" type="QString" name="baseDirectory" /> + </UML:Operation> + <UML:Operation visibility="public" xmi.id="87" type="void" name="load" > + <UML:Parameter visibility="public" xmi.id="88" value="" type="bool" name="loadAll" /> + </UML:Operation> + <UML:Operation visibility="public" xmi.id="89" type="QPtrList<Memofile>" name="getAll" /> + <UML:Operation visibility="public" xmi.id="90" type="void" name="save" /> + <UML:Operation visibility="public" xmi.id="91" type="void" name="eraseLocalMemos" /> + <UML:Operation visibility="public" xmi.id="95" type="void" name="setModified" > + <UML:Parameter visibility="public" xmi.id="96" value="" type="QPtrList<PilotMemo>" name="memos" /> + </UML:Operation> + <UML:Operation visibility="private" xmi.id="97" type="void" name="ensureDirectoryReady" /> + <UML:Operation visibility="public" xmi.id="98" type="void" name="loadIds" /> + <UML:Operation visibility="public" xmi.id="99" type="Memofile" name="find" > + <UML:Parameter visibility="public" xmi.id="100" value="" type="QString" name="category" /> + <UML:Parameter visibility="public" xmi.id="101" value="" type="QString" name="filename" /> + </UML:Operation> + <UML:Operation visibility="public" xmi.id="102" type="void" name="addModified" > + <UML:Parameter visibility="public" xmi.id="103" value="" type="PilotMemo *" name="memo" /> + </UML:Operation> + <UML:Operation visibility="public" xmi.id="104" type="QPtrList<Memofile>" name="getModified" /> + <UML:Attribute visibility="private" xmi.id="83" value="" type="QMap" name="_categories" /> + <UML:Attribute visibility="private" xmi.id="85" value="" type="QString" name="_baseDirectory" /> + <UML:Attribute visibility="private" xmi.id="93" value="" type="QPtrList<Memofile>" name="_memofiles" /> + </UML:Class> + <UML:Class visibility="public" xmi.id="64" name="Memofile" > + <UML:Operation visibility="public" xmi.id="65" type="" name="Memofile" > + <UML:Parameter visibility="public" xmi.id="66" value="" type="PilotMemo*" name="memo" /> + <UML:Parameter visibility="public" xmi.id="67" value="" type="QString" name="categoryName" /> + </UML:Operation> + <UML:Operation visibility="public" xmi.id="68" type="" name="Memofile" > + <UML:Parameter visibility="public" xmi.id="69" value="" type="recordid_t" name="id" /> + <UML:Parameter visibility="public" xmi.id="70" value="" type="int" name="category" /> + <UML:Parameter visibility="public" xmi.id="71" value="" type="QString" name="categoryName" /> + <UML:Parameter visibility="public" xmi.id="72" value="" type="uint" name="lastModifiedTime" /> + <UML:Parameter visibility="public" xmi.id="73" value="" type="QString" name="filename" /> + <UML:Parameter visibility="public" xmi.id="74" value="" type="QString" name="text" /> + </UML:Operation> + <UML:Operation visibility="public" xmi.id="75" type="uint" name="lastModified" /> + <UML:Operation visibility="public" xmi.id="76" type="QString" name="filename" /> + <UML:Attribute visibility="private" xmi.id="77" value="" type="uint" name="_lastModified" /> + <UML:Attribute visibility="private" xmi.id="78" value="" type="QString" name="_categoryName" /> + <UML:Attribute visibility="private" xmi.id="79" value="" type="QString" name="_filename" /> + </UML:Class> + <UML:DataType stereotype="3" visibility="public" xmi.id="84" name="QMap" /> + <UML:DataType stereotype="3" visibility="public" xmi.id="86" name="QString" /> + <UML:DataType stereotype="3" visibility="public" xmi.id="94" name="QPtrList<Memofile>" /> + <UML:Association visibility="public" xmi.id="36" > + <UML:Association.connection> + <UML:AssociationEndRole visibility="public" aggregation="composite" type="11" /> + <UML:AssociationEndRole visibility="private" type="34" /> + </UML:Association.connection> + </UML:Association> + </UML:Model> + </XMI.content> + <XMI.extensions xmi.extender="umbrello" > + <docsettings viewid="62" documentation="" uniqueid="107" /> + <diagrams> + <diagram snapgrid="0" showattsig="1" fillcolor="#ffffc0" linewidth="0" zoom="100" showgrid="0" showopsig="1" usefillcolor="1" snapx="10" canvaswidth="807" snapy="10" showatts="1" xmi.id="1" documentation="" type="402" showops="1" showpackage="0" name="class diagram" localid="30000" showstereotype="0" showscope="1" snapcsgrid="0" font="Sans,10,-1,5,50,0,0,0,0,0" linecolor="#ff0000" canvasheight="591" > + <widgets/> + <messages/> + <associations/> + </diagram> + <diagram snapgrid="0" showattsig="1" fillcolor="#ffffc0" linewidth="0" zoom="100" showgrid="0" showopsig="1" usefillcolor="1" snapx="10" canvaswidth="999" snapy="10" showatts="1" xmi.id="62" documentation="" type="402" showops="1" showpackage="0" name="memofile classes" localid="30000" showstereotype="0" showscope="1" snapcsgrid="0" font="Sans,10,-1,5,50,0,0,0,0,0" linecolor="#ff0000" canvasheight="630" > + <widgets> + <classwidget usesdiagramfillcolour="1" width="543" showattsigs="601" usesdiagramusefillcolour="1" x="428" linecolour="none" y="62" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="1" fillcolour="none" height="544" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="11" showoperations="1" showpackage="0" showscope="1" showstereotype="0" font="Sans,10,-1,5,75,0,0,0,0,0" /> + <classwidget usesdiagramfillcolour="1" width="432" showattsigs="601" usesdiagramusefillcolour="1" x="17" linecolour="none" y="33" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="1" fillcolour="none" height="255" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="63" showoperations="1" showpackage="0" showscope="1" showstereotype="0" font="Sans,10,-1,5,75,0,0,0,0,0" /> + <classwidget usesdiagramfillcolour="1" width="767" showattsigs="601" usesdiagramusefillcolour="1" x="3" linecolour="none" y="467" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="1" fillcolour="none" height="136" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="64" showoperations="1" showpackage="0" showscope="1" showstereotype="0" font="Sans,10,-1,5,75,0,0,0,0,0" /> + </widgets> + <messages/> + <associations/> + </diagram> + </diagrams> + <listview> + <listitem open="1" type="800" id="-1" label="Views" > + <listitem open="1" type="801" id="-1" label="Logical View" > + <listitem open="0" type="807" id="1" label="class diagram" /> + <listitem open="0" type="807" id="62" label="memofile classes" /> + <listitem open="0" type="813" id="64" > + <listitem open="0" type="814" id="78" /> + <listitem open="0" type="814" id="79" /> + <listitem open="0" type="814" id="77" /> + <listitem open="0" type="815" id="65" /> + <listitem open="0" type="815" id="68" /> + <listitem open="0" type="815" id="76" /> + <listitem open="0" type="815" id="75" /> + </listitem> + <listitem open="0" type="813" id="11" > + <listitem open="1" type="813" id="34" /> + <listitem open="0" type="814" id="29" /> + <listitem open="0" type="814" id="30" /> + <listitem open="0" type="814" id="31" /> + <listitem open="0" type="814" id="40" /> + <listitem open="0" type="814" id="41" /> + <listitem open="0" type="814" id="33" /> + <listitem open="0" type="814" id="32" /> + <listitem open="0" type="814" id="37" /> + <listitem open="0" type="814" id="42" /> + <listitem open="0" type="814" id="38" /> + <listitem open="0" type="814" id="39" /> + <listitem open="0" type="815" id="12" /> + <listitem open="0" type="815" id="52" /> + <listitem open="0" type="815" id="55" /> + <listitem open="0" type="815" id="54" /> + <listitem open="0" type="815" id="26" /> + <listitem open="0" type="815" id="44" /> + <listitem open="0" type="815" id="45" /> + <listitem open="0" type="815" id="50" /> + <listitem open="0" type="815" id="47" /> + <listitem open="0" type="815" id="51" /> + <listitem open="0" type="815" id="27" /> + <listitem open="0" type="815" id="49" /> + <listitem open="0" type="815" id="48" /> + <listitem open="0" type="815" id="28" /> + <listitem open="0" type="815" id="43" /> + <listitem open="0" type="815" id="59" /> + <listitem open="0" type="815" id="56" /> + <listitem open="0" type="815" id="57" /> + <listitem open="0" type="815" id="58" /> + <listitem open="0" type="815" id="16" /> + <listitem open="1" type="831" id="17" /> + </listitem> + <listitem open="1" type="813" id="63" > + <listitem open="0" type="814" id="85" /> + <listitem open="0" type="814" id="83" /> + <listitem open="0" type="814" id="93" /> + <listitem open="0" type="815" id="80" /> + <listitem open="0" type="815" id="102" /> + <listitem open="0" type="815" id="97" /> + <listitem open="0" type="815" id="91" /> + <listitem open="0" type="815" id="99" /> + <listitem open="0" type="815" id="89" /> + <listitem open="0" type="815" id="104" /> + <listitem open="0" type="815" id="87" /> + <listitem open="0" type="815" id="98" /> + <listitem open="0" type="815" id="90" /> + <listitem open="0" type="815" id="95" /> + </listitem> + <listitem open="0" type="830" id="-1" label="Datatypes" > + <listitem open="1" type="829" id="84" /> + <listitem open="1" type="829" id="94" /> + <listitem open="1" type="829" id="86" /> + <listitem open="1" type="829" id="5" /> + <listitem open="1" type="829" id="4" /> + <listitem open="1" type="829" id="7" /> + <listitem open="1" type="829" id="6" /> + <listitem open="1" type="829" id="2" /> + <listitem open="1" type="829" id="8" /> + <listitem open="1" type="829" id="9" /> + <listitem open="1" type="829" id="10" /> + </listitem> + </listitem> + <listitem open="1" type="802" id="-1" label="Use Case View" /> + <listitem open="1" type="821" id="-1" label="Component View" /> + <listitem open="1" type="827" id="-1" label="Deployment View" /> + </listitem> + </listview> + <codegeneration/> + </XMI.extensions> +</XMI> diff --git a/conduits/memofileconduit/memofiles.cc b/conduits/memofileconduit/memofiles.cc new file mode 100644 index 0000000..c51915b --- /dev/null +++ b/conduits/memofileconduit/memofiles.cc @@ -0,0 +1,700 @@ +/* memofile-conduit.cc KPilot +** +** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper +** +*/ + +/* +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Bug reports and questions can be sent to [email protected] +*/ + +#include "options.h" + +#include "memofiles.h" +#include "memofile.h" + +TQString Memofiles::FIELD_SEP = CSL1("\t"); + +Memofiles::Memofiles (MemoCategoryMap & categories, PilotMemoInfo &appInfo, + TQString & baseDirectory, CUDCounter &fCtrPC) : + _categories(categories), _memoAppInfo(appInfo), + _baseDirectory(baseDirectory), _cudCounter(fCtrPC) +{ + FUNCTIONSETUP; + _memofiles.clear(); + _memoMetadataFile = _baseDirectory + TQDir::separator() + CSL1(".ids"); + _categoryMetadataFile = _baseDirectory + TQDir::separator() + CSL1(".categories"); + _memofiles.setAutoDelete(true); + + _ready = ensureDirectoryReady(); + + _metadataLoaded = loadFromMetadata(); +} + +Memofiles::~Memofiles() +{ + FUNCTIONSETUP; +} + +void Memofiles::load (bool loadAll) +{ + FUNCTIONSETUP; + + DEBUGKPILOT << fname + << ": now looking at all memofiles in your directory." << endl; + + // now go through each of our known categories and look in each directory + // for that category for memo files + MemoCategoryMap::ConstIterator it; + int counter = -1; + + for ( it = _categories.begin(); it != _categories.end(); ++it ) { + int category = it.key(); + TQString categoryName = it.data(); + TQString categoryDirname = _baseDirectory + TQDir::separator() + categoryName; + + TQDir dir = TQDir(categoryDirname); + if (! dir.exists() ) { + DEBUGKPILOT << fname + << ": category directory: [" << categoryDirname + << "] doesn't exist. skipping." << endl; + continue; + } + + + TQStringList entries = dir.entryList(TQDir::Files); + TQString file; + for(TQStringList::Iterator it = entries.begin(); it != entries.end(); ++it) { + file = *it; + TQFileInfo info(dir, file); + + if(info.isFile() && info.isReadable()) { +// DEBUGKPILOT << fname +// << ": checking category: [" << categoryName +// << "], file: [" << file << "]." << endl; + Memofile * memofile = find(categoryName, file); + if (NULL == memofile) { + memofile = new Memofile(category, categoryName, file, _baseDirectory); + memofile->setModified(true); + _memofiles.append(memofile); + DEBUGKPILOT << fname + << ": looks like we didn't know about this one until now. " + << "created new memofile for category: [" + << categoryName << "], file: [" << file << "]." << endl; + + } + + counter++; + + // okay, we should have a memofile for this file now. see if we need + // to load its text... + if (memofile->isModified() || loadAll) { + DEBUGKPILOT << fname + << ": now loading text for: [" << info.filePath() << "]." << endl; + memofile->load(); + } + } else { + DEBUGKPILOT << fname + << ": couldn't read file: [" << info.filePath() << "]. skipping it." << endl; + + } + } // end of iterating through files in this directory + + } // end of iterating through our categories/directories + + DEBUGKPILOT << fname + << ": looked at: [" << counter << "] files from your directories." << endl; + + + // okay, now we've loaded everything from our directories. make one last + // pass through our loaded memofiles and see if we need to mark any of them + // as deleted (i.e. we created a memofile object from our metadata, but + // the file is now gone, so it's deleted. + Memofile * memofile; + + for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) { + if (! memofile->fileExists()) { + memofile->setDeleted( true ); + } + } +} + +/** +* Make sure that our directory is ready to synchronize with our +* Palm's database. This means we need to make sure that the directory +* that our user has specified for storing his/her memos exists, as well +* as a directory inside that directory for each of his/her memo categories. +*/ +bool Memofiles::ensureDirectoryReady() +{ + FUNCTIONSETUP; + + if (!checkDirectory(_baseDirectory)) + return false; + + int failures = 0; + // now make sure that a directory for each category exists. + TQString _category_name; + TQString dir; + + MemoCategoryMap::Iterator it; + for ( it = _categories.begin(); it != _categories.end(); ++it ) { + _category_name = it.data(); + dir = _baseDirectory + TQDir::separator() + _category_name; + + DEBUGKPILOT << fname + << ": checking directory: [" << dir << "]" << endl; + + if (!checkDirectory(dir)) + failures++; + } + + return failures == 0; +} + +bool Memofiles::checkDirectory(TQString & dir) +{ + FUNCTIONSETUP; + // make sure that the directory we're asked to write to exists + TQDir d(dir); + TQFileInfo fid( dir ); + + if ( ! fid.isDir() ) { + + DEBUGKPILOT << fname + << ": directory: [" << dir + << "] doesn't exist. creating...." + << endl; + + if (!d.mkdir(dir)) { + + DEBUGKPILOT << fname + << ": could not create directory: [" << dir + << "]. this won't end well." << endl; + return false; + } else { + DEBUGKPILOT << fname + << ": directory created: [" + << dir << "]." << endl; + + } + } else { + DEBUGKPILOT << fname + << ": directory already existed: [" + << dir << "]." << endl; + + } + + return true; + +} + +void Memofiles::eraseLocalMemos () +{ + FUNCTIONSETUP; + + MemoCategoryMap::Iterator it; + for ( it = _categories.begin(); it != _categories.end(); ++it ) { + TQString dir = _baseDirectory + TQDir::separator() + it.data(); + + if (!folderRemove(TQDir(dir))) { + DEBUGKPILOT << fname + << ": couldn't erase all local memos from: [" + << dir << "]." << endl; + } + } + TQDir d(_baseDirectory); + d.remove(_memoMetadataFile); + + ensureDirectoryReady(); + + _memofiles.clear(); +} + +void Memofiles::setPilotMemos (TQPtrList<PilotMemo> & memos) +{ + FUNCTIONSETUP; + + PilotMemo * memo; + + _memofiles.clear(); + + for ( memo = memos.first(); memo; memo = memos.next() ) { + addModifiedMemo(memo); + } + + DEBUGKPILOT << fname + << ": set: [" + << _memofiles.count() << "] from Palm to local." << endl; + +} + +bool Memofiles::loadFromMetadata () +{ + FUNCTIONSETUP; + + _memofiles.clear(); + + TQFile f( _memoMetadataFile ); + if ( !f.open( IO_ReadOnly ) ) { + DEBUGKPILOT << fname + << ": ooh, bad. couldn't open your memo-id file for reading." + << endl; + return false; + } + + TQTextStream t( &f ); + Memofile * memofile; + + while ( !t.atEnd() ) { + TQString data = t.readLine(); + int errors = 0; + bool ok; + + TQStringList fields = TQStringList::split( FIELD_SEP, data ); + if ( fields.count() >= 4 ) { + int id = fields[0].toInt( &ok ); + if ( !ok ) + errors++; + int category = fields[1].toInt( &ok ); + if ( !ok ) + errors++; + uint lastModified = fields[2].toInt( &ok ); + if ( !ok ) + errors++; + uint size = fields[3].toInt( &ok ); + if ( !ok ) + errors++; + TQString filename = fields[4]; + if ( filename.isEmpty() ) + errors++; + + if (errors <= 0) { + memofile = new Memofile(id, category, lastModified, size, + _categories[category], filename, _baseDirectory); + _memofiles.append(memofile); + // DEBUGKPILOT << fname + // << ": created memofile from metadata. id: [" << id + // << "], category: [" + // << _categories[category] << "], filename: [" << filename << "]." + // << endl; + } + } else { + errors++; + } + + if (errors > 0) { + DEBUGKPILOT << fname + << ": error: couldn't understand this line: [" << data << "]." + << endl; + } + } + + DEBUGKPILOT << fname + << ": loaded: [" << _memofiles.count() << "] memofiles." + << endl; + + f.close(); + + return true; +} + +Memofile * Memofiles::find (recordid_t id) +{ + + Memofile * memofile; + + for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) { + if ( memofile->id() == id) { + return memofile; + } + } + + return NULL; + +} + +Memofile * Memofiles::find (const TQString & category, const TQString & filename) +{ + + Memofile * memofile; + + for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) { + if ( memofile->getCategoryName() == category && + memofile->getFilename() == filename ) { + return memofile; + } + } + + return NULL; + +} + +void Memofiles::deleteMemo(PilotMemo * memo) +{ + FUNCTIONSETUP; + if (! memo->isDeleted()) + return; + + Memofile * memofile = find(memo->id()); + if (memofile) { + memofile->deleteFile(); + _memofiles.remove(memofile); + _cudCounter.deleted(); + } +} + + +void Memofiles::addModifiedMemo (PilotMemo * memo) +{ + FUNCTIONSETUP; + + if (memo->isDeleted()) { + deleteMemo(memo); + return; + } + + TQString debug = CSL1(": adding a PilotMemo. id: [") + + TQString::number(memo->id()) + CSL1("], title: [") + + memo->getTitle() + CSL1("]. "); + + Memofile * memofile = find(memo->id()); + + if (NULL == memofile) { + _cudCounter.created(); + debug += CSL1(" new from pilot."); + } else { + // we have found a local memofile that was modified on the palm. for the time + // being (until someone complains, etc.), we will always overwrite changes to + // the local filesystem with changes to the palm (palm overrides local). at + // some point in the future, we should probably honor a user preference for + // this... + _cudCounter.updated(); + _memofiles.remove(memofile); + debug += CSL1(" modified from pilot."); + } + + DEBUGKPILOT << fname + << debug << endl; + + memofile = new Memofile(memo, _categories[memo->category()], filename(memo), _baseDirectory); + memofile->setModifiedByPalm(true); + _memofiles.append(memofile); + +} + +TQPtrList<Memofile> Memofiles::getModified () +{ + FUNCTIONSETUP; + + TQPtrList<Memofile> modList; + modList.clear(); + + Memofile * memofile; + + for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) { + if ( memofile->isModified() && ! memofile->isModifiedByPalm() ) { + modList.append(memofile); + } + } + + DEBUGKPILOT << fname + << ": found: [" << modList.count() << "] memofiles modified on filesystem." << endl; + + return modList; +} + +void Memofiles::save() +{ + FUNCTIONSETUP; + + saveCategoryMetadata(); + saveMemos(); + // this needs to be done last, because saveMemos() might change + // attributes of the Memofiles + saveMemoMetadata(); + +} + +bool Memofiles::saveMemoMetadata() +{ + FUNCTIONSETUP; + + DEBUGKPILOT << fname + << ": saving memo metadata to file: [" + << _memoMetadataFile << "]" << endl; + + TQFile f( _memoMetadataFile ); + TQTextStream stream(&f); + + if( !f.open(IO_WriteOnly) ) { + DEBUGKPILOT << fname + << ": ooh, bad. couldn't open your memo-id file for writing." + << endl; + return false; + } + + Memofile * memofile; + + // each line looks like this, but FIELD_SEP is the separator instead of "," + // id,category,lastModifiedTime,filesize,filename + for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) { + // don't save deleted memos to our id file + if (! memofile->isDeleted()) { + stream << memofile->id() << FIELD_SEP + << memofile->category() << FIELD_SEP + << memofile->lastModified() << FIELD_SEP + << memofile->size() << FIELD_SEP + << memofile->filename() + << endl; + } + } + + f.close(); + + return true; + +} + +MemoCategoryMap Memofiles::readCategoryMetadata() +{ + FUNCTIONSETUP; + + DEBUGKPILOT << fname + << ": reading categories from file: [" + << _categoryMetadataFile << "]" << endl; + + MemoCategoryMap map; + map.clear(); + + TQFile f( _categoryMetadataFile ); + TQTextStream stream(&f); + + if( !f.open(IO_ReadOnly) ) { + DEBUGKPILOT << fname + << ": ooh, bad. couldn't open your categories file for reading." + << endl; + return map; + } + + + while ( !stream.atEnd() ) { + TQString data = stream.readLine(); + int errors = 0; + bool ok; + + TQStringList fields = TQStringList::split( FIELD_SEP, data ); + if ( fields.count() >= 2 ) { + int id = fields[0].toInt( &ok ); + if ( !ok ) + errors++; + TQString categoryName = fields[1]; + if ( categoryName.isEmpty() ) + errors++; + + if (errors <= 0) { + map[id] = categoryName; + } + } else { + errors++; + } + + if (errors > 0) { + DEBUGKPILOT << fname + << ": error: couldn't understand this line: [" << data << "]." + << endl; + } + } + + DEBUGKPILOT << fname + << ": loaded: [" << map.count() << "] categories." + << endl; + + f.close(); + + return map; +} + +bool Memofiles::saveCategoryMetadata() +{ + FUNCTIONSETUP; + + + DEBUGKPILOT << fname + << ": saving categories to file: [" + << _categoryMetadataFile << "]" << endl; + + TQFile f( _categoryMetadataFile ); + TQTextStream stream(&f); + + if( !f.open(IO_WriteOnly) ) { + DEBUGKPILOT << fname + << ": ooh, bad. couldn't open your categories file for writing." + << endl; + return false; + } + + MemoCategoryMap::Iterator it; + for ( it = _categories.begin(); it != _categories.end(); ++it ) { + stream << it.key() + << FIELD_SEP + << it.data() + << endl; + } + + f.close(); + + return true; +} + +bool Memofiles::saveMemos() +{ + FUNCTIONSETUP; + + Memofile * memofile; + bool result = true; + + for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) { + if (memofile->isDeleted()) { + _memofiles.remove(memofile); + } else { + result = memofile->save(); + // Fix prompted by Bug #103922 + // if we weren't able to save the file, then remove it from the list. + // if we don't do this, the next sync will think that the user deliberately + // deleted the memofile and will then delete it from the Pilot. + // TODO -- at some point, we should probably tell the user that this + // did not work, but that will require a String change. + // Also, this is a partial fix since at this point + // this memo will never make its way onto the PC, but at least + // we won't delete it from the Pilot erroneously either. *sigh* + if (!result) { + DEBUGKPILOT << fname + << ": unable to save memofile: [" + << memofile->filename() + << "], now removing it from the metadata list." + << endl; + _memofiles.remove(memofile); + } + } + } + return true; +} + +bool Memofiles::isFirstSync() +{ + FUNCTIONSETUP; + bool metadataExists = TQFile::exists(_memoMetadataFile) && + TQFile::exists(_categoryMetadataFile); + + bool valid = metadataExists && _metadataLoaded; + + DEBUGKPILOT << fname + << ": local metadata exists: [" << metadataExists + << "], metadata loaded: [" << _metadataLoaded + << "], returning: [" << ! valid << "]" << endl; + return ! valid; +} + + + +bool Memofiles::folderRemove(const TQDir &_d) +{ + FUNCTIONSETUP; + + TQDir d = _d; + + TQStringList entries = d.entryList(); + for(TQStringList::Iterator it = entries.begin(); it != entries.end(); ++it) { + if(*it == CSL1(".") || *it == CSL1("..")) + continue; + TQFileInfo info(d, *it); + if(info.isDir()) { + if(!folderRemove(TQDir(info.filePath()))) + return FALSE; + } else { + DEBUGKPILOT << fname + << ": deleting file: [" << info.filePath() << "]" << endl; + d.remove(info.filePath()); + } + } + TQString name = d.dirName(); + if(!d.cdUp()) + return FALSE; + DEBUGKPILOT << fname + << ": removing folder: [" << name << "]" << endl; + d.rmdir(name); + + return TRUE; +} + +TQString Memofiles::filename(PilotMemo * memo) +{ + FUNCTIONSETUP; + + TQString filename = memo->getTitle(); + + if (filename.isEmpty()) { + TQString text = memo->text(); + int i = text.find(CSL1("\n")); + if (i > 1) { + filename = text.left(i); + } + if (filename.isEmpty()) { + filename = CSL1("empty"); + } + } + + filename = sanitizeName(filename); + + TQString category = _categories[memo->category()]; + + Memofile * memofile = find(category, filename); + + // if we couldn't find a memofile with this filename, or if the + // memofile that is found is the same as the memo that we're looking + // at, then use the filename + if (NULL == memofile || memofile == memo) { + return filename; + } + + int uniq = 2; + TQString newfilename; + + // try to find a good filename, but only do this 20 times at the most. + // if our user has 20 memos with the same filename, he/she is asking + // for trouble. + while (NULL != memofile && uniq <=20) { + newfilename = TQString(filename + CSL1(".") + TQString::number(uniq++) ); + memofile = find(category, newfilename); + } + + return newfilename; +} + +TQString Memofiles::sanitizeName(TQString name) +{ + TQString clean = name; + // safety net. we can't save a + // filesystem separator as part of a filename, now can we? + clean.tqreplace('/', CSL1("-")); + return clean; +} + diff --git a/conduits/memofileconduit/memofiles.h b/conduits/memofileconduit/memofiles.h new file mode 100644 index 0000000..72b6ed4 --- /dev/null +++ b/conduits/memofileconduit/memofiles.h @@ -0,0 +1,96 @@ +#ifndef _MEMOFILE_MEMOFILES_H +#define _MEMOFILE_MEMOFILES_H +/* memofiles.h KPilot +** +** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper +*/ + +/* +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Bug reports and questions can be sent to [email protected] +*/ + +#include "plugin.h" +#include <tqmap.h> + +#include "memofile.h" + +typedef TQMap<int, TQString> MemoCategoryMap; + +class Memofile; + +class Memofiles { + +public: + + Memofiles (MemoCategoryMap & categories, PilotMemoInfo &appInfo, + TQString & baseDirectory, CUDCounter &fCtrHH); + ~Memofiles(); + + void load(bool loadAll); + void save(); + void eraseLocalMemos(); + void setPilotMemos (TQPtrList<PilotMemo> & memos); + void addModifiedMemo (PilotMemo * memo); + void deleteMemo (PilotMemo * memo); + + bool isFirstSync(); + bool isReady() { return _ready; }; + + TQPtrList<Memofile> getModified(); + TQPtrList<Memofile> getAll() { return _memofiles; } ; + Memofile * find (const TQString & category, const TQString & filename); + Memofile * find (recordid_t id); + + MemoCategoryMap readCategoryMetadata(); + void setCategories(MemoCategoryMap map) { _categories = map; } ; + + static TQString FIELD_SEP; + static TQString sanitizeName(TQString name); + + int count() { return _memofiles.count(); } + +private: + + MemoCategoryMap _categories; + PilotMemoInfo &_memoAppInfo; + TQString & _baseDirectory; + CUDCounter &_cudCounter; + TQPtrList<Memofile> _memofiles; + + bool loadFromMetadata(); + bool ensureDirectoryReady(); + bool checkDirectory(TQString & dir); + bool saveMemoMetadata(); + bool saveCategoryMetadata(); + bool saveMemos(); + bool folderRemove(const TQDir & dir); + + TQString filename(PilotMemo * memo); + + + TQString _categoryMetadataFile; + TQString _memoMetadataFile; + + bool _metadataLoaded; + bool _ready; + +}; +#endif //MEMOFILES_H + diff --git a/conduits/memofileconduit/setup_base.ui b/conduits/memofileconduit/setup_base.ui new file mode 100644 index 0000000..4237626 --- /dev/null +++ b/conduits/memofileconduit/setup_base.ui @@ -0,0 +1,143 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>MemofileWidget</class> +<comment>A tabWidget for configuring +the Memofile-conduit settings.</comment> +<author>Jason 'vanRijn' Kasper</author> +<widget class="QWidget"> + <property name="name"> + <cstring>Form1</cstring> + </property> + <property name="tqgeometry"> + <rect> + <x>0</x> + <y>0</y> + <width>342</width> + <height>412</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="baseSize"> + <size> + <width>570</width> + <height>270</height> + </size> + </property> + <property name="caption"> + <string>Memofile Conduit Options</string> + </property> + <property name="tqlayoutMargin" stdset="0"> + </property> + <property name="tqlayoutSpacing" stdset="0"> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QTabWidget" row="0" column="0"> + <property name="name"> + <cstring>tabWidget</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="tqlayoutMargin" stdset="0"> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>Widget2</cstring> + </property> + <attribute name="title"> + <string>General</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer row="2" column="2"> + <property name="name"> + <cstring>Spacer4</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="tqsizeHint"> + <size> + <width>20</width> + <height>180</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Sync private records:</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Memos directory:</string> + </property> + </widget> + <widget class="KURLRequester" row="0" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>fDirectory</cstring> + </property> + <property name="mode"> + <number>18</number> + </property> + <property name="toolTip" stdset="0"> + <string>Select the directory you want to store your PDA's memos in</string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="1"> + <property name="name"> + <cstring>fSyncPrivate</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </grid> + </widget> + </widget> + </grid> +</widget> +<tabstops> + <tabstop>tabWidget</tabstop> +</tabstops> +<tqlayoutdefaults spacing="6" margin="11"/> +<includes> + <include location="global" impldecl="in implementation">kurlrequester.h</include> + <include location="global" impldecl="in implementation">klineedit.h</include> + <include location="global" impldecl="in implementation">kpushbutton.h</include> +</includes> +</UI> |