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 #include "options.h"
00029
00030 #include "memofiles.h"
00031 #include "memofile.h"
00032
00033 QString Memofiles::FIELD_SEP = CSL1("\t");
00034
00035 Memofiles::Memofiles (MemoCategoryMap & categories, PilotMemoInfo &appInfo,
00036 QString & baseDirectory, CUDCounter &fCtrPC) :
00037 _categories(categories), _memoAppInfo(appInfo),
00038 _baseDirectory(baseDirectory), _cudCounter(fCtrPC)
00039 {
00040 FUNCTIONSETUP;
00041 _memofiles.clear();
00042 _memoMetadataFile = _baseDirectory + QDir::separator() + CSL1(".ids");
00043 _categoryMetadataFile = _baseDirectory + QDir::separator() + CSL1(".categories");
00044 _memofiles.setAutoDelete(true);
00045
00046 _ready = ensureDirectoryReady();
00047
00048 _metadataLoaded = loadFromMetadata();
00049 }
00050
00051 Memofiles::~Memofiles()
00052 {
00053 FUNCTIONSETUP;
00054 }
00055
00056 void Memofiles::load (bool loadAll)
00057 {
00058 FUNCTIONSETUP;
00059
00060 DEBUGKPILOT << fname
00061 << ": now looking at all memofiles in your directory." << endl;
00062
00063
00064
00065 MemoCategoryMap::ConstIterator it;
00066 int counter = -1;
00067
00068 for ( it = _categories.begin(); it != _categories.end(); ++it ) {
00069 int category = it.key();
00070 QString categoryName = it.data();
00071 QString categoryDirname = _baseDirectory + QDir::separator() + categoryName;
00072
00073 QDir dir = QDir(categoryDirname);
00074 if (! dir.exists() ) {
00075 DEBUGKPILOT << fname
00076 << ": category directory: [" << categoryDirname
00077 << "] doesn't exist. skipping." << endl;
00078 continue;
00079 }
00080
00081
00082 QStringList entries = dir.entryList(QDir::Files);
00083 QString file;
00084 for(QStringList::Iterator it = entries.begin(); it != entries.end(); ++it) {
00085 file = *it;
00086 QFileInfo info(dir, file);
00087
00088 if(info.isFile() && info.isReadable()) {
00089
00090
00091
00092 Memofile * memofile = find(categoryName, file);
00093 if (NULL == memofile) {
00094 memofile = new Memofile(category, categoryName, file, _baseDirectory);
00095 memofile->setModified(true);
00096 _memofiles.append(memofile);
00097 DEBUGKPILOT << fname
00098 << ": looks like we didn't know about this one until now. "
00099 << "created new memofile for category: ["
00100 << categoryName << "], file: [" << file << "]." << endl;
00101
00102 }
00103
00104 counter++;
00105
00106
00107
00108 if (memofile->isModified() || loadAll) {
00109 DEBUGKPILOT << fname
00110 << ": now loading text for: [" << info.filePath() << "]." << endl;
00111 memofile->load();
00112 }
00113 } else {
00114 DEBUGKPILOT << fname
00115 << ": couldn't read file: [" << info.filePath() << "]. skipping it." << endl;
00116
00117 }
00118 }
00119
00120 }
00121
00122 DEBUGKPILOT << fname
00123 << ": looked at: [" << counter << "] files from your directories." << endl;
00124
00125
00126
00127
00128
00129
00130 Memofile * memofile;
00131
00132 for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) {
00133 if (! memofile->fileExists()) {
00134 memofile->setDeleted( true );
00135 }
00136 }
00137 }
00138
00145 bool Memofiles::ensureDirectoryReady()
00146 {
00147 FUNCTIONSETUP;
00148
00149 if (!checkDirectory(_baseDirectory))
00150 return false;
00151
00152 int failures = 0;
00153
00154 QString _category_name;
00155 QString dir;
00156
00157 MemoCategoryMap::Iterator it;
00158 for ( it = _categories.begin(); it != _categories.end(); ++it ) {
00159 _category_name = it.data();
00160 dir = _baseDirectory + QDir::separator() + _category_name;
00161
00162 DEBUGKPILOT << fname
00163 << ": checking directory: [" << dir << "]" << endl;
00164
00165 if (!checkDirectory(dir))
00166 failures++;
00167 }
00168
00169 return failures == 0;
00170 }
00171
00172 bool Memofiles::checkDirectory(QString & dir)
00173 {
00174 FUNCTIONSETUP;
00175
00176 QDir d(dir);
00177 QFileInfo fid( dir );
00178
00179 if ( ! fid.isDir() ) {
00180
00181 DEBUGKPILOT << fname
00182 << ": directory: [" << dir
00183 << "] doesn't exist. creating...."
00184 << endl;
00185
00186 if (!d.mkdir(dir)) {
00187
00188 DEBUGKPILOT << fname
00189 << ": could not create directory: [" << dir
00190 << "]. this won't end well." << endl;
00191 return false;
00192 } else {
00193 DEBUGKPILOT << fname
00194 << ": directory created: ["
00195 << dir << "]." << endl;
00196
00197 }
00198 } else {
00199 DEBUGKPILOT << fname
00200 << ": directory already existed: ["
00201 << dir << "]." << endl;
00202
00203 }
00204
00205 return true;
00206
00207 }
00208
00209 void Memofiles::eraseLocalMemos ()
00210 {
00211 FUNCTIONSETUP;
00212
00213 MemoCategoryMap::Iterator it;
00214 for ( it = _categories.begin(); it != _categories.end(); ++it ) {
00215 QString dir = _baseDirectory + QDir::separator() + it.data();
00216
00217 if (!folderRemove(QDir(dir))) {
00218 DEBUGKPILOT << fname
00219 << ": couldn't erase all local memos from: ["
00220 << dir << "]." << endl;
00221 }
00222 }
00223 QDir d(_baseDirectory);
00224 d.remove(_memoMetadataFile);
00225
00226 ensureDirectoryReady();
00227
00228 _memofiles.clear();
00229 }
00230
00231 void Memofiles::setPilotMemos (QPtrList<PilotMemo> & memos)
00232 {
00233 FUNCTIONSETUP;
00234
00235 PilotMemo * memo;
00236
00237 _memofiles.clear();
00238
00239 for ( memo = memos.first(); memo; memo = memos.next() ) {
00240 addModifiedMemo(memo);
00241 }
00242
00243 DEBUGKPILOT << fname
00244 << ": set: ["
00245 << _memofiles.count() << "] from Palm to local." << endl;
00246
00247 }
00248
00249 bool Memofiles::loadFromMetadata ()
00250 {
00251 FUNCTIONSETUP;
00252
00253 _memofiles.clear();
00254
00255 QFile f( _memoMetadataFile );
00256 if ( !f.open( IO_ReadOnly ) ) {
00257 DEBUGKPILOT << fname
00258 << ": ooh, bad. couldn't open your memo-id file for reading."
00259 << endl;
00260 return false;
00261 }
00262
00263 QTextStream t( &f );
00264 Memofile * memofile;
00265
00266 while ( !t.atEnd() ) {
00267 QString data = t.readLine();
00268 int errors = 0;
00269 bool ok;
00270
00271 QStringList fields = QStringList::split( FIELD_SEP, data );
00272 if ( fields.count() >= 4 ) {
00273 int id = fields[0].toInt( &ok );
00274 if ( !ok )
00275 errors++;
00276 int category = fields[1].toInt( &ok );
00277 if ( !ok )
00278 errors++;
00279 uint lastModified = fields[2].toInt( &ok );
00280 if ( !ok )
00281 errors++;
00282 uint size = fields[3].toInt( &ok );
00283 if ( !ok )
00284 errors++;
00285 QString filename = fields[4];
00286 if ( filename.isEmpty() )
00287 errors++;
00288
00289 if (errors <= 0) {
00290 memofile = new Memofile(id, category, lastModified, size,
00291 _categories[category], filename, _baseDirectory);
00292 _memofiles.append(memofile);
00293
00294
00295
00296
00297
00298 }
00299 } else {
00300 errors++;
00301 }
00302
00303 if (errors > 0) {
00304 DEBUGKPILOT << fname
00305 << ": error: couldn't understand this line: [" << data << "]."
00306 << endl;
00307 }
00308 }
00309
00310 DEBUGKPILOT << fname
00311 << ": loaded: [" << _memofiles.count() << "] memofiles."
00312 << endl;
00313
00314 f.close();
00315
00316 return true;
00317 }
00318
00319 Memofile * Memofiles::find (recordid_t id)
00320 {
00321
00322 Memofile * memofile;
00323
00324 for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) {
00325 if ( memofile->id() == id) {
00326 return memofile;
00327 }
00328 }
00329
00330 return NULL;
00331
00332 }
00333
00334 Memofile * Memofiles::find (const QString & category, const QString & filename)
00335 {
00336
00337 Memofile * memofile;
00338
00339 for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) {
00340 if ( memofile->getCategoryName() == category &&
00341 memofile->getFilename() == filename ) {
00342 return memofile;
00343 }
00344 }
00345
00346 return NULL;
00347
00348 }
00349
00350 void Memofiles::deleteMemo(PilotMemo * memo)
00351 {
00352 FUNCTIONSETUP;
00353 if (! memo->isDeleted())
00354 return;
00355
00356 Memofile * memofile = find(memo->id());
00357 if (memofile) {
00358 memofile->deleteFile();
00359 _memofiles.remove(memofile);
00360 _cudCounter.deleted();
00361 }
00362 }
00363
00364
00365 void Memofiles::addModifiedMemo (PilotMemo * memo)
00366 {
00367 FUNCTIONSETUP;
00368
00369 if (memo->isDeleted()) {
00370 deleteMemo(memo);
00371 return;
00372 }
00373
00374 QString debug = CSL1(": adding a PilotMemo. id: [")
00375 + QString::number(memo->id()) + CSL1("], title: [")
00376 + memo->getTitle() + CSL1("]. ");
00377
00378 Memofile * memofile = find(memo->id());
00379
00380 if (NULL == memofile) {
00381 _cudCounter.created();
00382 debug += CSL1(" new from pilot.");
00383 } else {
00384
00385
00386
00387
00388
00389 _cudCounter.updated();
00390 _memofiles.remove(memofile);
00391 debug += CSL1(" modified from pilot.");
00392 }
00393
00394 DEBUGKPILOT << fname
00395 << debug << endl;
00396
00397 memofile = new Memofile(memo, _categories[memo->category()], filename(memo), _baseDirectory);
00398 memofile->setModifiedByPalm(true);
00399 _memofiles.append(memofile);
00400
00401 }
00402
00403 QPtrList<Memofile> Memofiles::getModified ()
00404 {
00405 FUNCTIONSETUP;
00406
00407 QPtrList<Memofile> modList;
00408 modList.clear();
00409
00410 Memofile * memofile;
00411
00412 for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) {
00413 if ( memofile->isModified() && ! memofile->isModifiedByPalm() ) {
00414 modList.append(memofile);
00415 }
00416 }
00417
00418 DEBUGKPILOT << fname
00419 << ": found: [" << modList.count() << "] memofiles modified on filesystem." << endl;
00420
00421 return modList;
00422 }
00423
00424 void Memofiles::save()
00425 {
00426 FUNCTIONSETUP;
00427
00428 saveCategoryMetadata();
00429 saveMemos();
00430
00431
00432 saveMemoMetadata();
00433
00434 }
00435
00436 bool Memofiles::saveMemoMetadata()
00437 {
00438 FUNCTIONSETUP;
00439
00440 DEBUGKPILOT << fname
00441 << ": saving memo metadata to file: ["
00442 << _memoMetadataFile << "]" << endl;
00443
00444 QFile f( _memoMetadataFile );
00445 QTextStream stream(&f);
00446
00447 if( !f.open(IO_WriteOnly) ) {
00448 DEBUGKPILOT << fname
00449 << ": ooh, bad. couldn't open your memo-id file for writing."
00450 << endl;
00451 return false;
00452 }
00453
00454 Memofile * memofile;
00455
00456
00457
00458 for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) {
00459
00460 if (! memofile->isDeleted()) {
00461 stream << memofile->id() << FIELD_SEP
00462 << memofile->category() << FIELD_SEP
00463 << memofile->lastModified() << FIELD_SEP
00464 << memofile->size() << FIELD_SEP
00465 << memofile->filename()
00466 << endl;
00467 }
00468 }
00469
00470 f.close();
00471
00472 return true;
00473
00474 }
00475
00476 MemoCategoryMap Memofiles::readCategoryMetadata()
00477 {
00478 FUNCTIONSETUP;
00479
00480 DEBUGKPILOT << fname
00481 << ": reading categories from file: ["
00482 << _categoryMetadataFile << "]" << endl;
00483
00484 MemoCategoryMap map;
00485 map.clear();
00486
00487 QFile f( _categoryMetadataFile );
00488 QTextStream stream(&f);
00489
00490 if( !f.open(IO_ReadOnly) ) {
00491 DEBUGKPILOT << fname
00492 << ": ooh, bad. couldn't open your categories file for reading."
00493 << endl;
00494 return map;
00495 }
00496
00497
00498 while ( !stream.atEnd() ) {
00499 QString data = stream.readLine();
00500 int errors = 0;
00501 bool ok;
00502
00503 QStringList fields = QStringList::split( FIELD_SEP, data );
00504 if ( fields.count() >= 2 ) {
00505 int id = fields[0].toInt( &ok );
00506 if ( !ok )
00507 errors++;
00508 QString categoryName = fields[1];
00509 if ( categoryName.isEmpty() )
00510 errors++;
00511
00512 if (errors <= 0) {
00513 map[id] = categoryName;
00514 }
00515 } else {
00516 errors++;
00517 }
00518
00519 if (errors > 0) {
00520 DEBUGKPILOT << fname
00521 << ": error: couldn't understand this line: [" << data << "]."
00522 << endl;
00523 }
00524 }
00525
00526 DEBUGKPILOT << fname
00527 << ": loaded: [" << map.count() << "] categories."
00528 << endl;
00529
00530 f.close();
00531
00532 return map;
00533 }
00534
00535 bool Memofiles::saveCategoryMetadata()
00536 {
00537 FUNCTIONSETUP;
00538
00539
00540 DEBUGKPILOT << fname
00541 << ": saving categories to file: ["
00542 << _categoryMetadataFile << "]" << endl;
00543
00544 QFile f( _categoryMetadataFile );
00545 QTextStream stream(&f);
00546
00547 if( !f.open(IO_WriteOnly) ) {
00548 DEBUGKPILOT << fname
00549 << ": ooh, bad. couldn't open your categories file for writing."
00550 << endl;
00551 return false;
00552 }
00553
00554 MemoCategoryMap::Iterator it;
00555 for ( it = _categories.begin(); it != _categories.end(); ++it ) {
00556 stream << it.key()
00557 << FIELD_SEP
00558 << it.data()
00559 << endl;
00560 }
00561
00562 f.close();
00563
00564 return true;
00565 }
00566
00567 bool Memofiles::saveMemos()
00568 {
00569 FUNCTIONSETUP;
00570
00571 Memofile * memofile;
00572 bool result = true;
00573
00574 for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) {
00575 if (memofile->isDeleted()) {
00576 _memofiles.remove(memofile);
00577 } else {
00578 result = memofile->save();
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588 if (!result) {
00589 DEBUGKPILOT << fname
00590 << ": unable to save memofile: ["
00591 << memofile->filename()
00592 << "], now removing it from the metadata list."
00593 << endl;
00594 _memofiles.remove(memofile);
00595 }
00596 }
00597 }
00598 return true;
00599 }
00600
00601 bool Memofiles::isFirstSync()
00602 {
00603 FUNCTIONSETUP;
00604 bool metadataExists = QFile::exists(_memoMetadataFile) &&
00605 QFile::exists(_categoryMetadataFile);
00606
00607 bool valid = metadataExists && _metadataLoaded;
00608
00609 DEBUGKPILOT << fname
00610 << ": local metadata exists: [" << metadataExists
00611 << "], metadata loaded: [" << _metadataLoaded
00612 << "], returning: [" << ! valid << "]" << endl;
00613 return ! valid;
00614 }
00615
00616
00617
00618 bool Memofiles::folderRemove(const QDir &_d)
00619 {
00620 FUNCTIONSETUP;
00621
00622 QDir d = _d;
00623
00624 QStringList entries = d.entryList();
00625 for(QStringList::Iterator it = entries.begin(); it != entries.end(); ++it) {
00626 if(*it == CSL1(".") || *it == CSL1(".."))
00627 continue;
00628 QFileInfo info(d, *it);
00629 if(info.isDir()) {
00630 if(!folderRemove(QDir(info.filePath())))
00631 return FALSE;
00632 } else {
00633 DEBUGKPILOT << fname
00634 << ": deleting file: [" << info.filePath() << "]" << endl;
00635 d.remove(info.filePath());
00636 }
00637 }
00638 QString name = d.dirName();
00639 if(!d.cdUp())
00640 return FALSE;
00641 DEBUGKPILOT << fname
00642 << ": removing folder: [" << name << "]" << endl;
00643 d.rmdir(name);
00644
00645 return TRUE;
00646 }
00647
00648 QString Memofiles::filename(PilotMemo * memo)
00649 {
00650 FUNCTIONSETUP;
00651
00652 QString filename = memo->getTitle();
00653
00654 if (filename.isEmpty()) {
00655 QString text = memo->text();
00656 int i = text.find(CSL1("\n"));
00657 if (i > 1) {
00658 filename = text.left(i);
00659 }
00660 if (filename.isEmpty()) {
00661 filename = CSL1("empty");
00662 }
00663 }
00664
00665 filename = sanitizeName(filename);
00666
00667 QString category = _categories[memo->category()];
00668
00669 Memofile * memofile = find(category, filename);
00670
00671
00672
00673
00674 if (NULL == memofile || memofile == memo) {
00675 return filename;
00676 }
00677
00678 int uniq = 2;
00679 QString newfilename;
00680
00681
00682
00683
00684 while (NULL != memofile && uniq <=20) {
00685 newfilename = QString(filename + CSL1(".") + QString::number(uniq++) );
00686 memofile = find(category, newfilename);
00687 }
00688
00689 return newfilename;
00690 }
00691
00692 QString Memofiles::sanitizeName(QString name)
00693 {
00694 QString clean = name;
00695
00696
00697 clean.replace('/', CSL1("-"));
00698 return clean;
00699 }
00700