DigiKam – digital photo management application
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1679 lines
42 KiB

  1. /* ============================================================
  2. *
  3. * This file is a part of digiKam project
  4. * http://www.digikam.org
  5. *
  6. * Date : 2004-06-15
  7. * Description : Albums manager interface.
  8. *
  9. * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
  10. * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
  11. *
  12. * This program is free software; you can redistribute it
  13. * and/or modify it under the terms of the GNU General
  14. * Public License as published by the Free Software Foundation;
  15. * either version 2, or (at your option)
  16. * any later version.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * ============================================================ */
  24. #include <config.h>
  25. // C Ansi includes.
  26. extern "C"
  27. {
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #include <unistd.h>
  31. }
  32. // C++ includes.
  33. #include <clocale>
  34. #include <cstdlib>
  35. #include <cstdio>
  36. #include <cerrno>
  37. // TQt includes.
  38. #include <tqfile.h>
  39. #include <tqdir.h>
  40. #include <tqdict.h>
  41. #include <tqintdict.h>
  42. #include <tqcstring.h>
  43. #include <tqtextcodec.h>
  44. #include <tqdatetime.h>
  45. // KDE includes.
  46. #include <tdeconfig.h>
  47. #include <tdelocale.h>
  48. #include <tdeversion.h>
  49. #include <tdemessagebox.h>
  50. #include <kstandarddirs.h>
  51. #include <tdeio/netaccess.h>
  52. #include <tdeio/global.h>
  53. #include <tdeio/job.h>
  54. #include <kdirwatch.h>
  55. // Local includes.
  56. #include "ddebug.h"
  57. #include "album.h"
  58. #include "albumdb.h"
  59. #include "albumitemhandler.h"
  60. #include "dio.h"
  61. #include "albumsettings.h"
  62. #include "scanlib.h"
  63. #include "splashscreen.h"
  64. #include "upgradedb_sqlite2tosqlite3.h"
  65. #include "albummanager.h"
  66. #include "albummanager.moc"
  67. namespace Digikam
  68. {
  69. typedef TQDict<PAlbum> PAlbumDict;
  70. typedef TQIntDict<Album> AlbumIntDict;
  71. typedef TQValueList<TQDateTime> DDateList;
  72. class AlbumManagerPriv
  73. {
  74. public:
  75. AlbumManagerPriv()
  76. {
  77. db = 0;
  78. dateListJob = 0;
  79. albumListJob = 0;
  80. tagListJob = 0;
  81. rootPAlbum = 0;
  82. rootTAlbum = 0;
  83. rootDAlbum = 0;
  84. rootSAlbum = 0;
  85. itemHandler = 0;
  86. currentAlbum = 0;
  87. dirWatch = 0;
  88. changed = false;
  89. }
  90. bool changed;
  91. TQString libraryPath;
  92. TQStringList dirtyAlbums;
  93. DDateList dbPathModificationDateList;
  94. KDirWatch *dirWatch;
  95. TDEIO::TransferJob *albumListJob;
  96. TDEIO::TransferJob *dateListJob;
  97. TDEIO::TransferJob *tagListJob;
  98. PAlbum *rootPAlbum;
  99. TAlbum *rootTAlbum;
  100. DAlbum *rootDAlbum;
  101. SAlbum *rootSAlbum;
  102. PAlbumDict pAlbumDict;
  103. AlbumIntDict albumIntDict;
  104. Album *currentAlbum;
  105. AlbumDB *db;
  106. AlbumItemHandler *itemHandler;
  107. TQValueList<TQDateTime> buildDirectoryModList(const TQFileInfo &dbFile)
  108. {
  109. // retrieve modification dates of all files in the database-file dir
  110. TQValueList<TQDateTime> modList;
  111. const TQFileInfoList *fileInfoList = dbFile.dir().entryInfoList(TQDir::Files | TQDir::Dirs );
  112. // build list
  113. TQFileInfoListIterator it(*fileInfoList);
  114. TQFileInfo *fi;
  115. while ( (fi = it.current()) != 0 )
  116. {
  117. if ( fi->fileName() != dbFile.fileName())
  118. {
  119. modList << fi->lastModified();
  120. }
  121. ++it;
  122. }
  123. return modList;
  124. }
  125. };
  126. AlbumManager* AlbumManager::m_instance = 0;
  127. AlbumManager* AlbumManager::instance()
  128. {
  129. return m_instance;
  130. }
  131. AlbumManager::AlbumManager()
  132. {
  133. m_instance = this;
  134. d = new AlbumManagerPriv;
  135. d->db = new AlbumDB;
  136. }
  137. AlbumManager::~AlbumManager()
  138. {
  139. if (d->dateListJob)
  140. {
  141. d->dateListJob->kill();
  142. d->dateListJob = 0;
  143. }
  144. if (d->albumListJob)
  145. {
  146. d->albumListJob->kill();
  147. d->albumListJob = 0;
  148. }
  149. if (d->tagListJob)
  150. {
  151. d->tagListJob->kill();
  152. d->tagListJob = 0;
  153. }
  154. delete d->rootPAlbum;
  155. delete d->rootTAlbum;
  156. delete d->rootDAlbum;
  157. delete d->rootSAlbum;
  158. delete d->dirWatch;
  159. delete d->db;
  160. delete d;
  161. m_instance = 0;
  162. }
  163. AlbumDB* AlbumManager::albumDB()
  164. {
  165. return d->db;
  166. }
  167. void AlbumManager::setLibraryPath(const TQString& path, SplashScreen *splash)
  168. {
  169. TQString cleanPath = TQDir::cleanDirPath(path);
  170. if (cleanPath == d->libraryPath)
  171. return;
  172. d->changed = true;
  173. if (d->dateListJob)
  174. {
  175. d->dateListJob->kill();
  176. d->dateListJob = 0;
  177. }
  178. if (d->albumListJob)
  179. {
  180. d->albumListJob->kill();
  181. d->albumListJob = 0;
  182. }
  183. if (d->tagListJob)
  184. {
  185. d->tagListJob->kill();
  186. d->tagListJob = 0;
  187. }
  188. delete d->dirWatch;
  189. d->dirWatch = 0;
  190. d->dirtyAlbums.clear();
  191. d->currentAlbum = 0;
  192. emit signalAlbumCurrentChanged(0);
  193. emit signalAlbumsCleared();
  194. d->pAlbumDict.clear();
  195. d->albumIntDict.clear();
  196. delete d->rootPAlbum;
  197. delete d->rootTAlbum;
  198. delete d->rootDAlbum;
  199. d->rootPAlbum = 0;
  200. d->rootTAlbum = 0;
  201. d->rootDAlbum = 0;
  202. d->rootSAlbum = 0;
  203. d->libraryPath = cleanPath;
  204. TQString dbPath = cleanPath + "/digikam3.db";
  205. #ifdef NFS_HACK
  206. dbPath = locateLocal("appdata", TDEIO::encodeFileName(TQDir::cleanDirPath(dbPath)));
  207. #endif
  208. d->db->setDBPath(dbPath);
  209. // -- Locale Checking ---------------------------------------------------------
  210. TQString currLocale(TQTextCodec::codecForLocale()->name());
  211. TQString dbLocale = d->db->getSetting("Locale");
  212. // guilty until proven innocent
  213. bool localeChanged = true;
  214. if (dbLocale.isNull())
  215. {
  216. DDebug() << "No locale found in database" << endl;
  217. // Copy an existing locale from the settings file (used < 0.8)
  218. // to the database.
  219. TDEConfig* config = TDEGlobal::config();
  220. config->setGroup("General Settings");
  221. if (config->hasKey("Locale"))
  222. {
  223. DDebug() << "Locale found in configfile" << endl;
  224. dbLocale = config->readEntry("Locale");
  225. // this hack is necessary, as we used to store the entire
  226. // locale info LC_ALL (for eg: en_US.UTF-8) earlier,
  227. // we now save only the encoding (UTF-8)
  228. TQString oldConfigLocale = ::setlocale(0, 0);
  229. if (oldConfigLocale == dbLocale)
  230. {
  231. dbLocale = currLocale;
  232. localeChanged = false;
  233. d->db->setSetting("Locale", dbLocale);
  234. }
  235. }
  236. else
  237. {
  238. DDebug() << "No locale found in config file" << endl;
  239. dbLocale = currLocale;
  240. localeChanged = false;
  241. d->db->setSetting("Locale",dbLocale);
  242. }
  243. }
  244. else
  245. {
  246. if (dbLocale == currLocale)
  247. localeChanged = false;
  248. }
  249. if (localeChanged)
  250. {
  251. // TODO it would be better to replace all yes/no confirmation dialogs with ones that has custom
  252. // buttons that denote the actions directly, i.e.: ["Ignore and Continue"] ["Adjust locale"]
  253. int result =
  254. KMessageBox::warningYesNo(0,
  255. i18n("Your locale has changed since this album "
  256. "was last opened.\n"
  257. "Old Locale : %1, New Locale : %2\n"
  258. "This can cause unexpected problems. "
  259. "If you are sure that you want to "
  260. "continue, click 'Yes' to work with this album. "
  261. "Otherwise, click 'No' and correct your "
  262. "locale setting before restarting digiKam")
  263. .arg(dbLocale)
  264. .arg(currLocale));
  265. if (result != KMessageBox::Yes)
  266. exit(0);
  267. d->db->setSetting("Locale",currLocale);
  268. }
  269. // -- Check if we need to upgrade 0.7.x db to 0.8 db ---------------------
  270. if (!upgradeDB_Sqlite2ToSqlite3(d->libraryPath))
  271. {
  272. KMessageBox::error(0, i18n("Failed to update the old Database to the new Database format\n"
  273. "This error can happen if the Album Path '%1' does not exist or is write-protected.\n"
  274. "If you have moved your photo collection, you need to adjust the 'Album Path' in digikam's configuration file.")
  275. .arg(d->libraryPath));
  276. exit(0);
  277. }
  278. // set an initial modification list to filter out KDirWatch signals
  279. // caused by database operations
  280. TQFileInfo dbFile(dbPath);
  281. d->dbPathModificationDateList = d->buildDirectoryModList(dbFile);
  282. // -- Check if we need to do scanning -------------------------------------
  283. TDEConfig* config = TDEGlobal::config();
  284. config->setGroup("General Settings");
  285. if (config->readBoolEntry("Scan At Start", true) ||
  286. d->db->getSetting("Scanned").isEmpty())
  287. {
  288. ScanLib sLib(splash);
  289. sLib.startScan();
  290. }
  291. }
  292. TQString AlbumManager::getLibraryPath() const
  293. {
  294. return d->libraryPath;
  295. }
  296. void AlbumManager::startScan()
  297. {
  298. if (!d->changed)
  299. return;
  300. d->changed = false;
  301. d->dirWatch = new KDirWatch(this);
  302. connect(d->dirWatch, TQT_SIGNAL(dirty(const TQString&)),
  303. this, TQT_SLOT(slotDirty(const TQString&)));
  304. KDirWatch::Method m = d->dirWatch->internalMethod();
  305. TQString mName("FAM");
  306. if (m == KDirWatch::DNotify)
  307. mName = TQString("DNotify");
  308. else if (m == KDirWatch::Stat)
  309. mName = TQString("Stat");
  310. else if (m == KDirWatch::INotify)
  311. mName = TQString("INotify");
  312. DDebug() << "KDirWatch method = " << mName << endl;
  313. d->dirWatch->addDir(d->libraryPath);
  314. d->rootPAlbum = new PAlbum(i18n("My Albums"), 0, true);
  315. insertPAlbum(d->rootPAlbum);
  316. d->rootTAlbum = new TAlbum(i18n("My Tags"), 0, true);
  317. insertTAlbum(d->rootTAlbum);
  318. d->rootSAlbum = new SAlbum(0, KURL(), true, true);
  319. d->rootDAlbum = new DAlbum(TQDate(), true);
  320. refresh();
  321. emit signalAllAlbumsLoaded();
  322. }
  323. void AlbumManager::refresh()
  324. {
  325. scanPAlbums();
  326. scanTAlbums();
  327. scanSAlbums();
  328. scanDAlbums();
  329. if (!d->dirtyAlbums.empty())
  330. {
  331. KURL u;
  332. u.setProtocol("digikamalbums");
  333. u.setPath(d->dirtyAlbums.first());
  334. d->dirtyAlbums.pop_front();
  335. DIO::scan(u);
  336. }
  337. }
  338. void AlbumManager::scanPAlbums()
  339. {
  340. // first insert all the current PAlbums into a map for quick lookup
  341. typedef TQMap<TQString, PAlbum*> AlbumMap;
  342. AlbumMap aMap;
  343. AlbumIterator it(d->rootPAlbum);
  344. while (it.current())
  345. {
  346. PAlbum* a = (PAlbum*)(*it);
  347. aMap.insert(a->url(), a);
  348. ++it;
  349. }
  350. // scan db and get a list of all albums
  351. AlbumInfo::List aList = d->db->scanAlbums();
  352. qHeapSort(aList);
  353. AlbumInfo::List newAlbumList;
  354. // go through all the Albums and see which ones are already present
  355. for (AlbumInfo::List::iterator it = aList.begin(); it != aList.end(); ++it)
  356. {
  357. AlbumInfo info = *it;
  358. info.url = TQDir::cleanDirPath(info.url);
  359. if (!aMap.contains(info.url))
  360. {
  361. newAlbumList.append(info);
  362. }
  363. else
  364. {
  365. aMap.remove(info.url);
  366. }
  367. }
  368. // now aMap contains all the deleted albums and
  369. // newAlbumList contains all the new albums
  370. // first inform all frontends of the deleted albums
  371. for (AlbumMap::iterator it = aMap.begin(); it != aMap.end(); ++it)
  372. {
  373. // the albums have to be removed with children being removed first.
  374. // removePAlbum takes care of that.
  375. // So never delete the PAlbum using it.data(). instead check if the
  376. // PAlbum is still in the Album Dict before trying to remove it.
  377. // this might look like there is memory leak here, since removePAlbum
  378. // doesn't delete albums and looks like child Albums don't get deleted.
  379. // But when the parent album gets deleted, the children are also deleted.
  380. PAlbum* album = d->pAlbumDict.find(it.key());
  381. if (!album)
  382. continue;
  383. removePAlbum(album);
  384. delete album;
  385. }
  386. qHeapSort(newAlbumList);
  387. for (AlbumInfo::List::iterator it = newAlbumList.begin(); it != newAlbumList.end(); ++it)
  388. {
  389. AlbumInfo info = *it;
  390. if (info.url.isEmpty() || info.url == "/")
  391. continue;
  392. // Despite its name info.url is a TQString.
  393. // setPath takes care for escaping characters that are valid for files but not for URLs ('#')
  394. KURL u;
  395. u.setPath(info.url);
  396. TQString name = u.fileName();
  397. // Get its parent
  398. TQString purl = u.upURL().path(-1);
  399. PAlbum* parent = d->pAlbumDict.find(purl);
  400. if (!parent)
  401. {
  402. DWarning() << k_funcinfo << "Could not find parent with url: "
  403. << purl << " for: " << info.url << endl;
  404. continue;
  405. }
  406. // Create the new album
  407. PAlbum* album = new PAlbum(name, info.id, false);
  408. album->m_caption = info.caption;
  409. album->m_collection = info.collection;
  410. album->m_date = info.date;
  411. album->m_icon = info.icon;
  412. album->setParent(parent);
  413. d->dirWatch->addDir(album->folderPath());
  414. insertPAlbum(album);
  415. }
  416. if (!AlbumSettings::instance()->getShowFolderTreeViewItemsCount())
  417. return;
  418. // List albums using tdeioslave
  419. if (d->albumListJob)
  420. {
  421. d->albumListJob->kill();
  422. d->albumListJob = 0;
  423. }
  424. KURL u;
  425. u.setProtocol("digikamalbums");
  426. u.setPath("/");
  427. TQByteArray ba;
  428. TQDataStream ds(ba, IO_WriteOnly);
  429. ds << d->libraryPath;
  430. ds << KURL();
  431. ds << AlbumSettings::instance()->getAllFileFilter();
  432. ds << 0; // getting dimensions (not needed here)
  433. ds << 0; // recursive sub-album (not needed here)
  434. ds << 0; // recursive sub-tags (not needed here)
  435. d->albumListJob = new TDEIO::TransferJob(u, TDEIO::CMD_SPECIAL,
  436. ba, TQByteArray(), false);
  437. d->albumListJob->addMetaData("folders", "yes");
  438. connect(d->albumListJob, TQT_SIGNAL(result(TDEIO::Job*)),
  439. this, TQT_SLOT(slotAlbumsJobResult(TDEIO::Job*)));
  440. connect(d->albumListJob, TQT_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
  441. this, TQT_SLOT(slotAlbumsJobData(TDEIO::Job*, const TQByteArray&)));
  442. }
  443. void AlbumManager::scanTAlbums()
  444. {
  445. // list TAlbums directly from the db
  446. // first insert all the current TAlbums into a map for quick lookup
  447. typedef TQMap<int, TAlbum*> TagMap;
  448. TagMap tmap;
  449. tmap.insert(0, d->rootTAlbum);
  450. AlbumIterator it(d->rootTAlbum);
  451. while (it.current())
  452. {
  453. TAlbum* t = (TAlbum*)(*it);
  454. tmap.insert(t->id(), t);
  455. ++it;
  456. }
  457. // Retrieve the list of tags from the database
  458. TagInfo::List tList = d->db->scanTags();
  459. // sort the list. needed because we want the tags can be read in any order,
  460. // but we want to make sure that we are ensure to find the parent TAlbum
  461. // for a new TAlbum
  462. {
  463. TQIntDict<TAlbum> tagDict;
  464. tagDict.setAutoDelete(false);
  465. // insert items into a dict for quick lookup
  466. for (TagInfo::List::iterator it = tList.begin(); it != tList.end(); ++it)
  467. {
  468. TagInfo info = *it;
  469. TAlbum* album = new TAlbum(info.name, info.id);
  470. album->m_icon = info.icon;
  471. album->m_pid = info.pid;
  472. tagDict.insert(info.id, album);
  473. }
  474. tList.clear();
  475. // also add root tag
  476. TAlbum* rootTag = new TAlbum("root", 0, true);
  477. tagDict.insert(0, rootTag);
  478. // build tree
  479. TQIntDictIterator<TAlbum> iter(tagDict);
  480. for ( ; iter.current(); ++iter )
  481. {
  482. TAlbum* album = iter.current();
  483. if (album->m_id == 0)
  484. continue;
  485. TAlbum* parent = tagDict.find(album->m_pid);
  486. if (parent)
  487. {
  488. album->setParent(parent);
  489. }
  490. else
  491. {
  492. DWarning() << "Failed to find parent tag for tag "
  493. << iter.current()->m_title
  494. << " with pid "
  495. << iter.current()->m_pid << endl;
  496. }
  497. }
  498. // now insert the items into the list. becomes sorted
  499. AlbumIterator it(rootTag);
  500. while (it.current())
  501. {
  502. TAlbum* album = (TAlbum*)it.current();
  503. TagInfo info;
  504. info.id = album->m_id;
  505. info.pid = album->m_pid;
  506. info.name = album->m_title;
  507. info.icon = album->m_icon;
  508. tList.append(info);
  509. ++it;
  510. }
  511. // this will also delete all child albums
  512. delete rootTag;
  513. }
  514. for (TagInfo::List::iterator it = tList.begin(); it != tList.end(); ++it)
  515. {
  516. TagInfo info = *it;
  517. // check if we have already added this tag
  518. if (tmap.contains(info.id))
  519. continue;
  520. // Its a new album. Find the parent of the album
  521. TagMap::iterator iter = tmap.find(info.pid);
  522. if (iter == tmap.end())
  523. {
  524. DWarning() << "Failed to find parent tag for tag "
  525. << info.name
  526. << " with pid "
  527. << info.pid << endl;
  528. continue;
  529. }
  530. TAlbum* parent = iter.data();
  531. // Create the new TAlbum
  532. TAlbum* album = new TAlbum(info.name, info.id, false);
  533. album->m_icon = info.icon;
  534. album->setParent(parent);
  535. insertTAlbum(album);
  536. // also insert it in the map we are doing lookup of parent tags
  537. tmap.insert(info.id, album);
  538. }
  539. if (!AlbumSettings::instance()->getShowFolderTreeViewItemsCount())
  540. return;
  541. // List tags using tdeioslave
  542. if (d->tagListJob)
  543. {
  544. d->tagListJob->kill();
  545. d->tagListJob = 0;
  546. }
  547. KURL u;
  548. u.setProtocol("digikamtags");
  549. u.setPath("/");
  550. TQByteArray ba;
  551. TQDataStream ds(ba, IO_WriteOnly);
  552. ds << d->libraryPath;
  553. ds << KURL();
  554. ds << AlbumSettings::instance()->getAllFileFilter();
  555. ds << 0; // getting dimensions (not needed here)
  556. ds << 0; // recursive sub-album (not needed here)
  557. ds << 0; // recursive sub-tags (not needed here)
  558. d->tagListJob = new TDEIO::TransferJob(u, TDEIO::CMD_SPECIAL,
  559. ba, TQByteArray(), false);
  560. d->tagListJob->addMetaData("folders", "yes");
  561. connect(d->tagListJob, TQT_SIGNAL(result(TDEIO::Job*)),
  562. this, TQT_SLOT(slotTagsJobResult(TDEIO::Job*)));
  563. connect(d->tagListJob, TQT_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
  564. this, TQT_SLOT(slotTagsJobData(TDEIO::Job*, const TQByteArray&)));
  565. }
  566. void AlbumManager::scanSAlbums()
  567. {
  568. // list SAlbums directly from the db
  569. // first insert all the current SAlbums into a map for quick lookup
  570. typedef TQMap<int, SAlbum*> SearchMap;
  571. SearchMap sMap;
  572. AlbumIterator it(d->rootSAlbum);
  573. while (it.current())
  574. {
  575. SAlbum* t = (SAlbum*)(*it);
  576. sMap.insert(t->id(), t);
  577. ++it;
  578. }
  579. // Retrieve the list of searches from the database
  580. SearchInfo::List sList = d->db->scanSearches();
  581. for (SearchInfo::List::iterator it = sList.begin(); it != sList.end(); ++it)
  582. {
  583. SearchInfo info = *it;
  584. // check if we have already added this search
  585. if (sMap.contains(info.id))
  586. continue;
  587. bool simple = (info.url.queryItem("1.key") == TQString::fromLatin1("keyword"));
  588. // Its a new album.
  589. SAlbum* album = new SAlbum(info.id, info.url, simple, false);
  590. album->setParent(d->rootSAlbum);
  591. d->albumIntDict.insert(album->globalID(), album);
  592. emit signalAlbumAdded(album);
  593. }
  594. }
  595. void AlbumManager::scanDAlbums()
  596. {
  597. // List dates using tdeioslave
  598. if (d->dateListJob)
  599. {
  600. d->dateListJob->kill();
  601. d->dateListJob = 0;
  602. }
  603. KURL u;
  604. u.setProtocol("digikamdates");
  605. u.setPath("/");
  606. TQByteArray ba;
  607. TQDataStream ds(ba, IO_WriteOnly);
  608. ds << d->libraryPath;
  609. ds << KURL();
  610. ds << AlbumSettings::instance()->getAllFileFilter();
  611. ds << 0; // getting dimensions (not needed here)
  612. ds << 0; // recursive sub-album (not needed here)
  613. ds << 0; // recursive sub-tags (not needed here)
  614. d->dateListJob = new TDEIO::TransferJob(u, TDEIO::CMD_SPECIAL,
  615. ba, TQByteArray(), false);
  616. d->dateListJob->addMetaData("folders", "yes");
  617. connect(d->dateListJob, TQT_SIGNAL(result(TDEIO::Job*)),
  618. this, TQT_SLOT(slotDatesJobResult(TDEIO::Job*)));
  619. connect(d->dateListJob, TQT_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
  620. this, TQT_SLOT(slotDatesJobData(TDEIO::Job*, const TQByteArray&)));
  621. }
  622. AlbumList AlbumManager::allPAlbums() const
  623. {
  624. AlbumList list;
  625. if (d->rootPAlbum)
  626. list.append(d->rootPAlbum);
  627. AlbumIterator it(d->rootPAlbum);
  628. while (it.current())
  629. {
  630. list.append(*it);
  631. ++it;
  632. }
  633. return list;
  634. }
  635. AlbumList AlbumManager::allTAlbums() const
  636. {
  637. AlbumList list;
  638. if (d->rootTAlbum)
  639. list.append(d->rootTAlbum);
  640. AlbumIterator it(d->rootTAlbum);
  641. while (it.current())
  642. {
  643. list.append(*it);
  644. ++it;
  645. }
  646. return list;
  647. }
  648. AlbumList AlbumManager::allSAlbums() const
  649. {
  650. AlbumList list;
  651. if (d->rootSAlbum)
  652. list.append(d->rootSAlbum);
  653. AlbumIterator it(d->rootSAlbum);
  654. while (it.current())
  655. {
  656. list.append(*it);
  657. ++it;
  658. }
  659. return list;
  660. }
  661. AlbumList AlbumManager::allDAlbums() const
  662. {
  663. AlbumList list;
  664. if (d->rootDAlbum)
  665. list.append(d->rootDAlbum);
  666. AlbumIterator it(d->rootDAlbum);
  667. while (it.current())
  668. {
  669. list.append(*it);
  670. ++it;
  671. }
  672. return list;
  673. }
  674. void AlbumManager::setCurrentAlbum(Album *album)
  675. {
  676. d->currentAlbum = album;
  677. emit signalAlbumCurrentChanged(album);
  678. }
  679. Album* AlbumManager::currentAlbum() const
  680. {
  681. return d->currentAlbum;
  682. }
  683. PAlbum* AlbumManager::findPAlbum(const KURL& url) const
  684. {
  685. TQString path = url.path();
  686. path.remove(d->libraryPath);
  687. path = TQDir::cleanDirPath(path);
  688. return d->pAlbumDict.find(path);
  689. }
  690. PAlbum* AlbumManager::findPAlbum(int id) const
  691. {
  692. if (!d->rootPAlbum)
  693. return 0;
  694. int gid = d->rootPAlbum->globalID() + id;
  695. return (PAlbum*)(d->albumIntDict.find(gid));
  696. }
  697. TAlbum* AlbumManager::findTAlbum(int id) const
  698. {
  699. if (!d->rootTAlbum)
  700. return 0;
  701. int gid = d->rootTAlbum->globalID() + id;
  702. return (TAlbum*)(d->albumIntDict.find(gid));
  703. }
  704. SAlbum* AlbumManager::findSAlbum(int id) const
  705. {
  706. if (!d->rootTAlbum)
  707. return 0;
  708. int gid = d->rootSAlbum->globalID() + id;
  709. return (SAlbum*)(d->albumIntDict.find(gid));
  710. }
  711. DAlbum* AlbumManager::findDAlbum(int id) const
  712. {
  713. if (!d->rootDAlbum)
  714. return 0;
  715. int gid = d->rootDAlbum->globalID() + id;
  716. return (DAlbum*)(d->albumIntDict.find(gid));
  717. }
  718. Album* AlbumManager::findAlbum(int gid) const
  719. {
  720. return d->albumIntDict.find(gid);
  721. }
  722. TAlbum* AlbumManager::findTAlbum(const TQString &tagPath) const
  723. {
  724. // handle gracefully with or without leading slash
  725. bool withLeadingSlash = tagPath.startsWith("/");
  726. AlbumIterator it(d->rootTAlbum);
  727. while (it.current())
  728. {
  729. TAlbum *talbum = static_cast<TAlbum *>(*it);
  730. if (talbum->tagPath(withLeadingSlash) == tagPath)
  731. return talbum;
  732. ++it;
  733. }
  734. return 0;
  735. }
  736. PAlbum* AlbumManager::createPAlbum(PAlbum* parent,
  737. const TQString& name,
  738. const TQString& caption,
  739. const TQDate& date,
  740. const TQString& collection,
  741. TQString& errMsg)
  742. {
  743. if (!parent)
  744. {
  745. errMsg = i18n("No parent found for album.");
  746. return 0;
  747. }
  748. // sanity checks
  749. if (name.isEmpty())
  750. {
  751. errMsg = i18n("Album name cannot be empty.");
  752. return 0;
  753. }
  754. if (name.contains("/"))
  755. {
  756. errMsg = i18n("Album name cannot contain '/'.");
  757. return 0;
  758. }
  759. // first check if we have another album with the same name
  760. Album *child = parent->m_firstChild;
  761. while (child)
  762. {
  763. if (child->title() == name)
  764. {
  765. errMsg = i18n("An existing album has the same name.");
  766. return 0;
  767. }
  768. child = child->m_next;
  769. }
  770. TQString path = parent->folderPath();
  771. path += '/' + name;
  772. path = TQDir::cleanDirPath(path);
  773. // make the directory synchronously, so that we can add the
  774. // album info to the database directly
  775. if (::mkdir(TQFile::encodeName(path), 0777) != 0)
  776. {
  777. if (errno == EEXIST)
  778. errMsg = i18n("Another file or folder with same name exists");
  779. else if (errno == EACCES)
  780. errMsg = i18n("Access denied to path");
  781. else if (errno == ENOSPC)
  782. errMsg = i18n("Disk is full");
  783. else
  784. errMsg = i18n("Unknown error"); // being lazy
  785. return 0;
  786. }
  787. // Now insert the album properties into the database
  788. path = path.remove(0, d->libraryPath.length());
  789. if (!path.startsWith("/"))
  790. path.prepend("/");
  791. int id = d->db->addAlbum(path, caption, date, collection);
  792. if (id == -1)
  793. {
  794. errMsg = i18n("Failed to add album to database");
  795. return 0;
  796. }
  797. PAlbum *album = new PAlbum(name, id, false);
  798. album->m_caption = caption;
  799. album->m_collection = collection;
  800. album->m_date = date;
  801. album->setParent(parent);
  802. d->dirWatch->addDir(album->folderPath());
  803. insertPAlbum(album);
  804. return album;
  805. }
  806. bool AlbumManager::renamePAlbum(PAlbum* album, const TQString& newName,
  807. TQString& errMsg)
  808. {
  809. if (!album)
  810. {
  811. errMsg = i18n("No such album");
  812. return false;
  813. }
  814. if (album == d->rootPAlbum)
  815. {
  816. errMsg = i18n("Cannot rename root album");
  817. return false;
  818. }
  819. if (newName.contains("/"))
  820. {
  821. errMsg = i18n("Album name cannot contain '/'");
  822. return false;
  823. }
  824. // first check if we have another sibling with the same name
  825. Album *sibling = album->m_parent->m_firstChild;
  826. while (sibling)
  827. {
  828. if (sibling->title() == newName)
  829. {
  830. errMsg = i18n("Another album with same name exists\n"
  831. "Please choose another name");
  832. return false;
  833. }
  834. sibling = sibling->m_next;
  835. }
  836. TQString oldURL = album->url();
  837. KURL u = KURL::fromPathOrURL(album->folderPath()).upURL();
  838. u.addPath(newName);
  839. u.cleanPath();
  840. if (::rename(TQFile::encodeName(album->folderPath()),
  841. TQFile::encodeName(u.path(-1))) != 0)
  842. {
  843. errMsg = i18n("Failed to rename Album");
  844. return false;
  845. }
  846. // now rename the album and subalbums in the database
  847. // all we need to do is set the title of the album which is being
  848. // renamed correctly and all the sub albums will automatically get
  849. // their url set correctly
  850. album->setTitle(newName);
  851. d->db->setAlbumURL(album->id(), album->url());
  852. Album* subAlbum = 0;
  853. AlbumIterator it(album);
  854. while ((subAlbum = it.current()) != 0)
  855. {
  856. d->db->setAlbumURL(subAlbum->id(), ((PAlbum*)subAlbum)->url());
  857. ++it;
  858. }
  859. // Update AlbumDict. basically clear it and rebuild from scratch
  860. {
  861. d->pAlbumDict.clear();
  862. d->pAlbumDict.insert(d->rootPAlbum->url(), d->rootPAlbum);
  863. AlbumIterator it(d->rootPAlbum);
  864. PAlbum* subAlbum = 0;
  865. while ((subAlbum = (PAlbum*)it.current()) != 0)
  866. {
  867. d->pAlbumDict.insert(subAlbum->url(), subAlbum);
  868. ++it;
  869. }
  870. }
  871. emit signalAlbumRenamed(album);
  872. return true;
  873. }
  874. bool AlbumManager::updatePAlbumIcon(PAlbum *album, TQ_LLONG iconID, TQString& errMsg)
  875. {
  876. if (!album)
  877. {
  878. errMsg = i18n("No such album");
  879. return false;
  880. }
  881. if (album == d->rootPAlbum)
  882. {
  883. errMsg = i18n("Cannot edit root album");
  884. return false;
  885. }
  886. d->db->setAlbumIcon(album->id(), iconID);
  887. album->m_icon = d->db->getAlbumIcon(album->id());
  888. emit signalAlbumIconChanged(album);
  889. return true;
  890. }
  891. TAlbum* AlbumManager::createTAlbum(TAlbum* parent, const TQString& name,
  892. const TQString& iconkde, TQString& errMsg)
  893. {
  894. if (!parent)
  895. {
  896. errMsg = i18n("No parent found for tag");
  897. return 0;
  898. }
  899. // sanity checks
  900. if (name.isEmpty())
  901. {
  902. errMsg = i18n("Tag name cannot be empty");
  903. return 0;
  904. }
  905. if (name.contains("/"))
  906. {
  907. errMsg = i18n("Tag name cannot contain '/'");
  908. return 0;
  909. }
  910. // first check if we have another album with the same name
  911. Album *child = parent->m_firstChild;
  912. while (child)
  913. {
  914. if (child->title() == name)
  915. {
  916. errMsg = i18n("Tag name already exists");
  917. return 0;
  918. }
  919. child = child->m_next;
  920. }
  921. int id = d->db->addTag(parent->id(), name, iconkde, 0);
  922. if (id == -1)
  923. {
  924. errMsg = i18n("Failed to add tag to database");
  925. return 0;
  926. }
  927. TAlbum *album = new TAlbum(name, id, false);
  928. album->m_icon = iconkde;
  929. album->setParent(parent);
  930. insertTAlbum(album);
  931. return album;
  932. }
  933. AlbumList AlbumManager::findOrCreateTAlbums(const TQStringList &tagPaths)
  934. {
  935. IntList tagIDs;
  936. // find tag ids for tag paths in list, create if they don't exist
  937. tagIDs = d->db->getTagsFromTagPaths(tagPaths);
  938. // create TAlbum objects for the newly created tags
  939. scanTAlbums();
  940. AlbumList resultList;
  941. for (IntList::iterator it = tagIDs.begin(); it != tagIDs.end(); ++it)
  942. {
  943. resultList.append(findTAlbum(*it));
  944. }
  945. return resultList;
  946. }
  947. bool AlbumManager::deleteTAlbum(TAlbum* album, TQString& errMsg)
  948. {
  949. if (!album)
  950. {
  951. errMsg = i18n("No such album");
  952. return false;
  953. }
  954. if (album == d->rootTAlbum)
  955. {
  956. errMsg = i18n("Cannot delete Root Tag");
  957. return false;
  958. }
  959. d->db->deleteTag(album->id());
  960. Album* subAlbum = 0;
  961. AlbumIterator it(album);
  962. while ((subAlbum = it.current()) != 0)
  963. {
  964. d->db->deleteTag(subAlbum->id());
  965. ++it;
  966. }
  967. removeTAlbum(album);
  968. d->albumIntDict.remove(album->globalID());
  969. delete album;
  970. return true;
  971. }
  972. bool AlbumManager::renameTAlbum(TAlbum* album, const TQString& name,
  973. TQString& errMsg)
  974. {
  975. if (!album)
  976. {
  977. errMsg = i18n("No such album");
  978. return false;
  979. }
  980. if (album == d->rootTAlbum)
  981. {
  982. errMsg = i18n("Cannot edit root tag");
  983. return false;
  984. }
  985. if (name.contains("/"))
  986. {
  987. errMsg = i18n("Tag name cannot contain '/'");
  988. return false;
  989. }
  990. // first check if we have another sibling with the same name
  991. Album *sibling = album->m_parent->m_firstChild;
  992. while (sibling)
  993. {
  994. if (sibling->title() == name)
  995. {
  996. errMsg = i18n("Another tag with same name exists\n"
  997. "Please choose another name");
  998. return false;
  999. }
  1000. sibling = sibling->m_next;
  1001. }
  1002. d->db->setTagName(album->id(), name);
  1003. album->setTitle(name);
  1004. emit signalAlbumRenamed(album);
  1005. return true;
  1006. }
  1007. bool AlbumManager::moveTAlbum(TAlbum* album, TAlbum *newParent, TQString &errMsg)
  1008. {
  1009. if (!album)
  1010. {
  1011. errMsg = i18n("No such album");
  1012. return false;
  1013. }
  1014. if (album == d->rootTAlbum)
  1015. {
  1016. errMsg = i18n("Cannot move root tag");
  1017. return false;
  1018. }
  1019. d->db->setTagParentID(album->id(), newParent->id());
  1020. album->parent()->removeChild(album);
  1021. album->setParent(newParent);
  1022. emit signalTAlbumMoved(album, newParent);
  1023. return true;
  1024. }
  1025. bool AlbumManager::updateTAlbumIcon(TAlbum* album, const TQString& iconKDE,
  1026. TQ_LLONG iconID, TQString& errMsg)
  1027. {
  1028. if (!album)
  1029. {
  1030. errMsg = i18n("No such tag");
  1031. return false;
  1032. }
  1033. if (album == d->rootTAlbum)
  1034. {
  1035. errMsg = i18n("Cannot edit root tag");
  1036. return false;
  1037. }
  1038. d->db->setTagIcon(album->id(), iconKDE, iconID);
  1039. album->m_icon = d->db->getTagIcon(album->id());
  1040. emit signalAlbumIconChanged(album);
  1041. return true;
  1042. }
  1043. SAlbum* AlbumManager::createSAlbum(const KURL& url, bool simple)
  1044. {
  1045. TQString name = url.queryItem("name");
  1046. // first iterate through all the search albums and see if there's an existing
  1047. // SAlbum with same name. (Remember, SAlbums are arranged in a flat list)
  1048. for (Album* album = d->rootSAlbum->firstChild(); album; album = album->next())
  1049. {
  1050. if (album->title() == name)
  1051. {
  1052. SAlbum* sa = (SAlbum*)album;
  1053. sa->m_kurl = url;
  1054. d->db->updateSearch(sa->id(), url.queryItem("name"), url);
  1055. return sa;
  1056. }
  1057. }
  1058. int id = d->db->addSearch(url.queryItem("name"), url);
  1059. if (id == -1)
  1060. return 0;
  1061. SAlbum* album = new SAlbum(id, url, simple, false);
  1062. album->setTitle(url.queryItem("name"));
  1063. album->setParent(d->rootSAlbum);
  1064. d->albumIntDict.insert(album->globalID(), album);
  1065. emit signalAlbumAdded(album);
  1066. return album;
  1067. }
  1068. bool AlbumManager::updateSAlbum(SAlbum* album, const KURL& newURL)
  1069. {
  1070. if (!album)
  1071. return false;
  1072. d->db->updateSearch(album->id(), newURL.queryItem("name"), newURL);
  1073. TQString oldName = album->title();
  1074. album->m_kurl = newURL;
  1075. album->setTitle(newURL.queryItem("name"));
  1076. if (oldName != album->title())
  1077. emit signalAlbumRenamed(album);
  1078. return true;
  1079. }
  1080. bool AlbumManager::deleteSAlbum(SAlbum* album)
  1081. {
  1082. if (!album)
  1083. return false;
  1084. emit signalAlbumDeleted(album);
  1085. d->db->deleteSearch(album->id());
  1086. d->albumIntDict.remove(album->globalID());
  1087. delete album;
  1088. return true;
  1089. }
  1090. void AlbumManager::insertPAlbum(PAlbum *album)
  1091. {
  1092. if (!album)
  1093. return;
  1094. d->pAlbumDict.insert(album->url(), album);
  1095. d->albumIntDict.insert(album->globalID(), album);
  1096. emit signalAlbumAdded(album);
  1097. }
  1098. void AlbumManager::removePAlbum(PAlbum *album)
  1099. {
  1100. if (!album)
  1101. return;
  1102. // remove all children of this album
  1103. Album* child = album->m_firstChild;
  1104. while (child)
  1105. {
  1106. Album *next = child->m_next;
  1107. removePAlbum((PAlbum*)child);
  1108. child = next;
  1109. }
  1110. d->pAlbumDict.remove(album->url());
  1111. d->albumIntDict.remove(album->globalID());
  1112. d->dirtyAlbums.remove(album->url());
  1113. d->dirWatch->removeDir(album->folderPath());
  1114. if (album == d->currentAlbum)
  1115. {
  1116. d->currentAlbum = 0;
  1117. emit signalAlbumCurrentChanged(0);
  1118. }
  1119. emit signalAlbumDeleted(album);
  1120. }
  1121. void AlbumManager::insertTAlbum(TAlbum *album)
  1122. {
  1123. if (!album)
  1124. return;
  1125. d->albumIntDict.insert(album->globalID(), album);
  1126. emit signalAlbumAdded(album);
  1127. }
  1128. void AlbumManager::removeTAlbum(TAlbum *album)
  1129. {
  1130. if (!album)
  1131. return;
  1132. // remove all children of this album
  1133. Album* child = album->m_firstChild;
  1134. while (child)
  1135. {
  1136. Album *next = child->m_next;
  1137. removeTAlbum((TAlbum*)child);
  1138. child = next;
  1139. }
  1140. d->albumIntDict.remove(album->globalID());
  1141. if (album == d->currentAlbum)
  1142. {
  1143. d->currentAlbum = 0;
  1144. emit signalAlbumCurrentChanged(0);
  1145. }
  1146. emit signalAlbumDeleted(album);
  1147. }
  1148. void AlbumManager::emitAlbumItemsSelected(bool val)
  1149. {
  1150. emit signalAlbumItemsSelected(val);
  1151. }
  1152. void AlbumManager::setItemHandler(AlbumItemHandler *handler)
  1153. {
  1154. d->itemHandler = handler;
  1155. }
  1156. AlbumItemHandler* AlbumManager::getItemHandler()
  1157. {
  1158. return d->itemHandler;
  1159. }
  1160. void AlbumManager::refreshItemHandler(const KURL::List& itemList)
  1161. {
  1162. if (itemList.empty())
  1163. d->itemHandler->refresh();
  1164. else
  1165. d->itemHandler->refreshItems(itemList);
  1166. }
  1167. void AlbumManager::slotAlbumsJobResult(TDEIO::Job* job)
  1168. {
  1169. d->albumListJob = 0;
  1170. if (job->error())
  1171. {
  1172. DWarning() << k_funcinfo << "Failed to list albums" << endl;
  1173. return;
  1174. }
  1175. }
  1176. void AlbumManager::slotAlbumsJobData(TDEIO::Job*, const TQByteArray& data)
  1177. {
  1178. if (data.isEmpty())
  1179. return;
  1180. TQMap<int, int> albumsStatMap;
  1181. TQDataStream ds(data, IO_ReadOnly);
  1182. ds >> albumsStatMap;
  1183. emit signalPAlbumsDirty(albumsStatMap);
  1184. }
  1185. void AlbumManager::slotTagsJobResult(TDEIO::Job* job)
  1186. {
  1187. d->tagListJob = 0;
  1188. if (job->error())
  1189. {
  1190. DWarning() << k_funcinfo << "Failed to list tags" << endl;
  1191. return;
  1192. }
  1193. }
  1194. void AlbumManager::slotTagsJobData(TDEIO::Job*, const TQByteArray& data)
  1195. {
  1196. if (data.isEmpty())
  1197. return;
  1198. TQMap<int, int> tagsStatMap;
  1199. TQDataStream ds(data, IO_ReadOnly);
  1200. ds >> tagsStatMap;
  1201. emit signalTAlbumsDirty(tagsStatMap);
  1202. }
  1203. void AlbumManager::slotDatesJobResult(TDEIO::Job* job)
  1204. {
  1205. d->dateListJob = 0;
  1206. if (job->error())
  1207. {
  1208. DWarning() << k_funcinfo << "Failed to list dates" << endl;
  1209. return;
  1210. }
  1211. emit signalAllDAlbumsLoaded();
  1212. }
  1213. void AlbumManager::slotDatesJobData(TDEIO::Job*, const TQByteArray& data)
  1214. {
  1215. if (data.isEmpty())
  1216. return;
  1217. // insert all the DAlbums into a qmap for quick access
  1218. TQMap<TQDate, DAlbum*> mAlbumMap;
  1219. TQMap<int, DAlbum*> yAlbumMap;
  1220. AlbumIterator it(d->rootDAlbum);
  1221. while (it.current())
  1222. {
  1223. DAlbum* a = (DAlbum*)(*it);
  1224. if (a->range() == DAlbum::Month)
  1225. mAlbumMap.insert(a->date(), a);
  1226. else
  1227. yAlbumMap.insert(a->date().year(), a);
  1228. ++it;
  1229. }
  1230. TQMap<TQDateTime, int> datesStatMap;
  1231. TQDataStream ds(data, IO_ReadOnly);
  1232. ds >> datesStatMap;
  1233. TQMap<YearMonth, int> yearMonthMap;
  1234. for ( TQMap<TQDateTime, int>::iterator it = datesStatMap.begin();
  1235. it != datesStatMap.end(); ++it )
  1236. {
  1237. TQMap<YearMonth, int>::iterator it2 = yearMonthMap.find(YearMonth(it.key().date().year(), it.key().date().month()));
  1238. if ( it2 == yearMonthMap.end() )
  1239. {
  1240. yearMonthMap.insert( YearMonth(it.key().date().year(), it.key().date().month()), it.data() );
  1241. }
  1242. else
  1243. {
  1244. yearMonthMap.replace( YearMonth(it.key().date().year(), it.key().date().month()), it2.data() + it.data() );
  1245. }
  1246. }
  1247. int year, month;
  1248. for ( TQMap<YearMonth, int>::iterator it = yearMonthMap.begin();
  1249. it != yearMonthMap.end(); ++it )
  1250. {
  1251. year = it.key().first;
  1252. month = it.key().second;
  1253. TQDate md(year, month, 1);
  1254. // Do we already have this Month album
  1255. if (mAlbumMap.contains(md))
  1256. {
  1257. // already there. remove Month album from map
  1258. mAlbumMap.remove(md);
  1259. if (yAlbumMap.contains(year))
  1260. {
  1261. // already there. remove from map
  1262. yAlbumMap.remove(year);
  1263. }
  1264. continue;
  1265. }
  1266. // Check if Year Album already exist.
  1267. DAlbum *yAlbum = 0;
  1268. AlbumIterator it2(d->rootDAlbum);
  1269. while (it2.current())
  1270. {
  1271. DAlbum* a = (DAlbum*)(*it2);
  1272. if (a->date() == TQDate(year, 1, 1) && a->range() == DAlbum::Year)
  1273. {
  1274. yAlbum = a;
  1275. break;
  1276. }
  1277. ++it2;
  1278. }
  1279. // If no, create Year album.
  1280. if (!yAlbum)
  1281. {
  1282. yAlbum = new DAlbum(TQDate(year, 1, 1), false, DAlbum::Year);
  1283. yAlbum->setParent(d->rootDAlbum);
  1284. d->albumIntDict.insert(yAlbum->globalID(), yAlbum);
  1285. emit signalAlbumAdded(yAlbum);
  1286. }
  1287. // Create Month album
  1288. DAlbum *mAlbum = new DAlbum(md);
  1289. mAlbum->setParent(yAlbum);
  1290. d->albumIntDict.insert(mAlbum->globalID(), mAlbum);
  1291. emit signalAlbumAdded(mAlbum);
  1292. }
  1293. // Now the items contained in the maps are the ones which
  1294. // have been deleted.
  1295. for (TQMap<TQDate, DAlbum*>::iterator it = mAlbumMap.begin();
  1296. it != mAlbumMap.end(); ++it)
  1297. {
  1298. DAlbum* album = it.data();
  1299. emit signalAlbumDeleted(album);
  1300. d->albumIntDict.remove(album->globalID());
  1301. delete album;
  1302. }
  1303. for (TQMap<int, DAlbum*>::iterator it = yAlbumMap.begin();
  1304. it != yAlbumMap.end(); ++it)
  1305. {
  1306. DAlbum* album = it.data();
  1307. emit signalAlbumDeleted(album);
  1308. d->albumIntDict.remove(album->globalID());
  1309. delete album;
  1310. }
  1311. emit signalDAlbumsDirty(yearMonthMap);
  1312. emit signalDatesMapDirty(datesStatMap);
  1313. }
  1314. void AlbumManager::slotDirty(const TQString& path)
  1315. {
  1316. DDebug() << "Noticed file change in directory " << path << endl;
  1317. TQString url = TQDir::cleanDirPath(path);
  1318. url = TQDir::cleanDirPath(url.remove(d->libraryPath));
  1319. if (url.isEmpty())
  1320. url = "/";
  1321. if (d->dirtyAlbums.contains(url))
  1322. return;
  1323. // is the signal for the directory containing the database file?
  1324. if (url == "/")
  1325. {
  1326. // retrieve modification dates
  1327. TQFileInfo dbFile(d->libraryPath);
  1328. TQValueList<TQDateTime> modList = d->buildDirectoryModList(dbFile);
  1329. // check for equality
  1330. if (modList == d->dbPathModificationDateList)
  1331. {
  1332. DDebug() << "Filtering out db-file-triggered dir watch signal" << endl;
  1333. // we can skip the signal
  1334. return;
  1335. }
  1336. // set new list
  1337. d->dbPathModificationDateList = modList;
  1338. }
  1339. d->dirtyAlbums.append(url);
  1340. if (DIO::running())
  1341. return;
  1342. KURL u;
  1343. u.setProtocol("digikamalbums");
  1344. u.setPath(d->dirtyAlbums.first());
  1345. d->dirtyAlbums.pop_front();
  1346. DIO::scan(u);
  1347. }
  1348. } // namespace Digikam