diff --git a/NEWS b/NEWS index ee1ac639da..971843836f 100644 --- a/NEWS +++ b/NEWS @@ -1,150 +1,150 @@ digiKam 6.1.0 - Release date: 2019-03-31 ***************************************************************************************************** NEW FEATURES: General : New plugins interface for digiKam and Showfoto named dplugins. General : All export tools become generic plugins and are shared with Showfoto. General : Update internal libpgf to last 07193. General : Add compatiblity with OpenCV version 4. General : MacOS and AppImage bundles are now published with Qt 5.11.3. General : Add new optional configuration option to compile with Faces Engine Neural Network. BQM : Add new advanced settings in resize tool. BQM : All Batch Queue Manager tools become Bqm plugins. Editor : All Image Editor tools become Editor plugins and are shared with Showfoto. Item View : Add sort items by modification date. DPlugin : New plugin to copy items to a local storage. DPlugin : New plugin to set image as Linux desktop wallpaper. ***************************************************************************************************** BUGFIXES: 001 ==> 279216 - "Resize image" feature is missing some useful options [patch]. 002 ==> 368779 - Missing translations to Plugin Categories columns in setup page. 003 ==> 165852 - Google Youtube video uploader. 004 ==> 404578 - Links broken on downloadpage for 6.0.0. 005 ==> 402069 - FAQ link on Support page is broken. 006 ==> 404503 - There is a typo in support section of website. 007 ==> 404621 - I can not import the album Google Photo. 008 ==> 404642 - digiKam flatpak: Please include mysql driver (for using an external mysql db). 009 ==> 404690 - There is an unwanted bar in the left screen edge in full screen view. 010 ==> 404736 - Merging tags keeps popping up confirmation dialogs every second. 011 ==> 404737 - digiKam does not compile with opencv 3.4.1. 012 ==> 404735 - F2 should edit tag name when tag name has focus. 013 ==> 404748 - Default Album rename dialog should be larger (or save its size when changed). 014 ==> 304811 - Offer a "stretch histogram" functionality to automatically adjust brightness & gamma. 015 ==> 374464 - Can start print wizzard. 016 ==> 316687 - ImageMagick-6.8.3.9 could not be found. 017 ==> 305137 - wish for integrated(?) clip-generator. 018 ==> 404821 - Presentation offset from full screen when OpenGL transitions selected. 019 ==> 404894 - 6.0.0 x86-64 appimage startup complains about mssing ']' (startup bash script being called). 020 ==> 368262 - Google services tool does not use kaccounts. 021 ==> 376913 - Can't create a new album in picasa/googlephoto. 022 ==> 404896 - Vertical video are displayed horizontally. 023 ==> 404859 - Using Batch Queue Manager to make a JPG copy of the images on completion the "arw" images are no longer visible in the originating album. 024 ==> 404893 - Digikam::DigikamApp::slotSolidDeviceChanged: slotSolidDeviceChanged: messages referring to directory that digikam should not care about. 025 ==> 264296 - Lack of right-click delete of points in Curves [patch]. 026 ==> 404954 - Places, Devices, and Removable Devices no longer show in "Select Target Location". 027 ==> 404962 - List of subfolders: incorrect encoding (spaces -> %20, accents). 028 ==> 402724 - digiKam Settings/Configuration: missing section "Plugins" in Windows/6.0.0B3. 029 ==> 404987 - Ability to select which import/export options are included in menu. 030 ==> 404999 - Inconsistency in facetag font size. 031 ==> 244259 - Last image is displayed twice when Advanced Slideshow with KenBurns effect is run more than once. 032 ==> 405043 - Add volume control to video playback. 033 ==> 401253 - Face detect crashes every time. 034 ==> 405042 - Ability to loop video playback. 035 ==> 405138 - Can not disable webservice plugin. 036 ==> 405137 - Original items visible in Thumbnails view. 037 ==> 400606 - Dead space above thumbnails. 038 ==> 380434 - 5.6.0-pre pkg does not detect filesystem changes. 039 ==> 405250 - Menus gone missing. 040 ==> 388198 - Menu Help -> What's this is not used. 041 ==> 392570 - Missing Option to display complete filename. 042 ==> 375474 - Renaming People Tag Causes Unpredictable Sort Order In People Menu. 043 ==> 398868 - Video upside down in Preview (Thumbnail ok). 044 ==> 380065 - "Open with" menu entry missing [patch]. 045 ==> 405258 - Provide an OpenWith... function to get a specific ImageEditor. 046 ==> 402807 - Progress manager doesn't seem to be involved in the fingerprint scanning (v6.0 beta 3). 047 ==> 278935 - Please make XMP Sidecar filename configurable [patch]. 048 ==> 405231 - Monitor Color Profile is not applied in "Presentation". 049 ==> 405347 - Selecting by aspect ratio: abs function in sqlite lowercase, in mariadb uppercase. 050 ==> 405327 - Position and size of faces display depends on configuration setting. 051 ==> 405234 - Refresh does no work. 052 ==> 403649 - Filesystem changes are not visible in album view [patch]. 053 ==> 400768 - Many different trash cans hard & slow to use. 054 ==> 296864 - SETUP : Create interface for changing physical location or path of album. 055 ==> 397189 - digikam is crashing when adding this photo. 056 ==> 405378 - Missing libz.dll on launch. 057 ==> 401306 - digikam-git r41326 doesn't compile with OpenCV 4 058 ==> 379049 - IPTC and XMP metadata not always read when adding a new album. 059 ==> 404939 - AppImage package: integration with the OS with AppImageLauncher. 060 ==> 405514 - Configure Shortcuts : Shortcuts file contains space in assigned_tags. 061 ==> 405149 - The "File Name" in the thumbnail view is not visible. 062 ==> 405512 - Meta Key Not Useful For Key Modifier In Windows. 063 ==> 405513 - Configure Shortcuts : Defaults Button Does Not Apply To New Schemes. 064 ==> 388334 - Auto Filter In People Tag List Confused With Shortcut Keys. 065 ==> 405518 - digiKam can not be added to the Gnome Dash as favorite. 066 ==> 405342 - Increase slideshow caption font size and keyboard shortcut or button to display/hide it. 067 ==> 405636 - When importing picture not all people tags are present. 068 ==> 379916 - Some people tags are missing. 069 ==> 386967 - digiKam with Adobe Bridge keywords under Windows. 070 ==> 402433 - Google Maps Doesn't Zoom With Mouse Wheel. 071 ==> 396920 - EXIF info not written when files from some cameras (Pentax K3) are edited and saved. 072 ==> 375468 - Cannot turn on Menubar. 073 ==> 387253 - No more menu bar in the Gnome desktop environment. 074 ==> 397405 - Large empty space in Digikams main icon view since ~20180707 appimage. 075 ==> 399237 - Thumbnails view shows an empty dock for thumbnails. 076 ==> 393935 - Segmentation fault during face detection. 077 ==> 388533 - UpdateSchemaFromV7ToV9 fails. 078 ==> 281493 - digiKam fails to install on Windows XP. 079 ==> 405537 - Strange behavior with tag in attached file. 080 ==> 405233 - digikam: symbol lookup error: /tmp/.mount_digika5N9rGH/usr/lib/libQt5XcbQpa.so.5: undefined symbol: FT_Property_Set. 081 ==> 404853 - digikam-6.0.0 faces engine fails to compile on PowerPC. 082 ==> 405625 - digiKam 6.0.0 faces engine fails to compile on PowerPC with AltiVec enabled. 083 ==> 372340 - Tagged face areas on portait (vertical) oriented images are mispositioned. 084 ==> 405743 - Customise Tool tab in editor. 085 ==> 376014 - Moving grouped photos from one folder to another breaks the group. 086 ==> 377782 - Group is lost when moved to another album. 087 ==> 385147 - Moving grouped images into another album removes groups. 088 ==> 342017 - Reverse Geocoding doesn't work. 089 ==> 405174 - Right-click advice menu. Open with another program. 090 ==> 399285 - Would it be possible to drop kio for a better 'open with' functionality across all platforms? 091 ==> 383079 - Open the photo in GIMP under windows. 092 ==> 374356 - "Show item in file explorer" as well as "open with". 093 ==> 208201 - Icons appears and disappears. 094 ==> 202955 - thumbnails in album view are flickering with high frequency. 095 ==> 208201 - Icons appears and disappears. 096 ==> 396933 - Tooltips of thumbnails and albums not readable in light designs. 097 ==> 393777 - Item Tool Tips are unreadable in Windows 10 (white on yellow). 098 ==> 240237 - Not possible to rotate the image. 099 ==> 366446 - Creating new albums fails due to invalid path name. 100 ==> 369235 - Menu bar is not translated. 101 ==> 403132 - Lazy Update not working (or: Stop when I say so). 102 ==> 404797 - digikam-6.0.0-x86-64.appimage: stack trace shortly after startup. 103 ==> 405789 - Sidebar widths revert to their defaults after switching back from full-screen view. 104 ==> 405813 - Tab-View do not show Rating information. 105 ==> 404138 - can't connect to my account. 106 ==> 403819 - Export to Google Photos not working (bad request). 107 ==> 382367 - Unreadable light on light tooltip. 108 ==> 405825 - Feature request: "Video date" in XMP Metadata Editor. 109 ==> 405799 - Not possible to add collection. 110 ==> 389549 - "Clear all faces on this image" Does Not Remove All People Tags. 111 ==> 405904 - The saved version of the image is not linked to the original. 112 ==> 372308 - Buttons for rotate does not show very well. 113 ==> 375375 - Various bugs detecting and tagging faces in current 5.4.0 Digikam appimage. 114 ==> 405700 - Lensfun supported Camera is missing. 115 ==> 400140 - Digikam crash when exporting on google photos. 116 ==> 397744 - Face recognition not working. 117 ==> 398000 - Multi/batch rename fails almost every time. 118 ==> 396496 - QSQLITE -> MYSQL loses grouping information. 119 ==> 382311 - Photos in collapsed groups are incorrectly excluded if first photo in group does not match filter. 120 ==> 400981 - Appimage not working anymore: /lib64/libfontconfig.so.1: undefined symbol: FT_Done_MM_Var. 121 ==> 406054 - Export to google photo a picture with a "title" => no "title" in google photo. 122 ==> 254932 - New tool to export images as desktop wallpaper folder. 123 ==> 192020 - Tool to export as plasma backgrounds. 124 ==> 406171 - digiKam crashed on exit. 125 ==> 406276 - Error during Migration: "Error creating database schema". 126 ==> 406227 - Picture without any tag are not listed with button "No Tags". 127 ==> 401377 - Export to (Onedrive, Dropbox ...) crashes digikam (Segmentation Fault). -128 ==> - +128 ==> 406309 - Tags reappear after being merged when several merge processes overlap(?). +129 ==> diff --git a/core/libs/album/manager/albummanager_talbum.cpp b/core/libs/album/manager/albummanager_talbum.cpp index 57037ae67a..dd9e6fa09a 100644 --- a/core/libs/album/manager/albummanager_talbum.cpp +++ b/core/libs/album/manager/albummanager_talbum.cpp @@ -1,1020 +1,1034 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2004-06-15 * Description : Albums manager interface - Tag Album helpers. * * Copyright (C) 2006-2019 by Gilles Caulier * Copyright (C) 2006-2011 by Marcel Wiesweg * Copyright (C) 2015 by Mohamed_Anwer * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, 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 General Public License for more details. * * ============================================================ */ #include "albummanager_p.h" namespace Digikam { void AlbumManager::scanTAlbums() { d->scanTAlbumsTimer->stop(); // list TAlbums directly from the db // first insert all the current TAlbums into a map for quick lookup typedef QMap TagMap; TagMap tmap; tmap.insert(0, d->rootTAlbum); AlbumIterator it(d->rootTAlbum); while (it.current()) { TAlbum* t = (TAlbum*)(*it); tmap.insert(t->id(), t); ++it; } // Retrieve the list of tags from the database TagInfo::List tList = CoreDbAccess().db()->scanTags(); // sort the list. needed because we want the tags can be read in any order, // but we want to make sure that we are ensure to find the parent TAlbum // for a new TAlbum { QHash tagHash; // insert items into a dict for quick lookup for (TagInfo::List::const_iterator iter = tList.constBegin() ; iter != tList.constEnd() ; ++iter) { TagInfo info = *iter; TAlbum* const album = new TAlbum(info.name, info.id); album->m_icon = info.icon; album->m_iconId = info.iconId; album->m_pid = info.pid; tagHash.insert(info.id, album); } tList.clear(); // also add root tag TAlbum* const rootTag = new TAlbum(QLatin1String("root"), 0, true); tagHash.insert(0, rootTag); // build tree for (QHash::const_iterator iter = tagHash.constBegin() ; iter != tagHash.constEnd() ; ++iter) { TAlbum* album = *iter; if (album->m_id == 0) { continue; } TAlbum* const parent = tagHash.value(album->m_pid); if (parent) { album->setParent(parent); } else { qCWarning(DIGIKAM_GENERAL_LOG) << "Failed to find parent tag for tag " << album->m_title << " with pid " << album->m_pid; } } tagHash.clear(); // now insert the items into the list. becomes sorted AlbumIterator it(rootTag); while (it.current()) { TagInfo info; TAlbum* const album = static_cast(it.current()); if (album) { info.id = album->m_id; info.pid = album->m_pid; info.name = album->m_title; info.icon = album->m_icon; info.iconId = album->m_iconId; } tList.append(info); ++it; } // this will also delete all child albums delete rootTag; } for (TagInfo::List::const_iterator it = tList.constBegin() ; it != tList.constEnd() ; ++it) { TagInfo info = *it; // check if we have already added this tag if (tmap.contains(info.id)) { continue; } // Its a new album. Find the parent of the album TagMap::const_iterator iter = tmap.constFind(info.pid); if (iter == tmap.constEnd()) { qCWarning(DIGIKAM_GENERAL_LOG) << "Failed to find parent tag for tag " << info.name << " with pid " << info.pid; continue; } TAlbum* const parent = iter.value(); // Create the new TAlbum TAlbum* const album = new TAlbum(info.name, info.id, false); album->m_icon = info.icon; album->m_iconId = info.iconId; insertTAlbum(album, parent); // also insert it in the map we are doing lookup of parent tags tmap.insert(info.id, album); } if (!tList.isEmpty()) { emit signalAlbumsUpdated(Album::TAG); } getTagItemsCount(); } void AlbumManager::getTagItemsCount() { d->tagItemCountTimer->stop(); if (!ApplicationSettings::instance()->getShowFolderTreeViewItemsCount()) { return; } tagItemsCount(); personItemsCount(); } void AlbumManager::tagItemsCount() { if (d->tagListJob) { d->tagListJob->cancel(); d->tagListJob = 0; } TagsDBJobInfo jInfo; jInfo.setFoldersJob(); d->tagListJob = DBJobsManager::instance()->startTagsJobThread(jInfo); connect(d->tagListJob, SIGNAL(finished()), this, SLOT(slotTagsJobResult())); connect(d->tagListJob, SIGNAL(foldersData(QMap)), this, SLOT(slotTagsJobData(QMap))); } AlbumList AlbumManager::allTAlbums() const { AlbumList list; if (d->rootTAlbum) { list.append(d->rootTAlbum); } AlbumIterator it(d->rootTAlbum); while (it.current()) { list.append(*it); ++it; } return list; } QList AlbumManager::currentTAlbums() const { /** * This method is not yet used */ QList talbums; QList::iterator it; for (it = d->currentAlbums.begin() ; it != d->currentAlbums.end() ; ++it) { TAlbum* const temp = dynamic_cast(*it); if (temp) talbums.append(temp); } return talbums; } TAlbum* AlbumManager::findTAlbum(int id) const { if (!d->rootTAlbum) { return 0; } int gid = d->rootTAlbum->globalID() + id; return static_cast((d->allAlbumsIdHash.value(gid))); } TAlbum* AlbumManager::findTAlbum(const QString& tagPath) const { // handle gracefully with or without leading slash bool withLeadingSlash = tagPath.startsWith(QLatin1Char('/')); AlbumIterator it(d->rootTAlbum); while (it.current()) { TAlbum* const talbum = static_cast(*it); if (talbum->tagPath(withLeadingSlash) == tagPath) { return talbum; } ++it; } return 0; } TAlbum* AlbumManager::createTAlbum(TAlbum* parent, const QString& name, const QString& iconkde, QString& errMsg) { if (!parent) { errMsg = i18n("No parent found for tag"); return 0; } // sanity checks if (name.isEmpty()) { errMsg = i18n("Tag name cannot be empty"); return 0; } if (name.contains(QLatin1Char('/'))) { errMsg = i18n("Tag name cannot contain '/'"); return 0; } // first check if we have another album with the same name if (hasDirectChildAlbumWithTitle(parent, name)) { errMsg = i18n("Tag name already exists"); return 0; } ChangingDB changing(d); int id = CoreDbAccess().db()->addTag(parent->id(), name, iconkde, 0); if (id == -1) { errMsg = i18n("Failed to add tag to database"); return 0; } TAlbum* const album = new TAlbum(name, id, false); album->m_icon = iconkde; insertTAlbum(album, parent); TAlbum* personParentTag = findTAlbum(FaceTags::personParentTag()); if (personParentTag && personParentTag->isAncestorOf(album)) { FaceTags::ensureIsPerson(album->id()); } emit signalAlbumsUpdated(Album::TAG); return album; } AlbumList AlbumManager::findOrCreateTAlbums(const QStringList& tagPaths) { // find tag ids for tag paths in list, create if they don't exist QList tagIDs = TagsCache::instance()->getOrCreateTags(tagPaths); // create TAlbum objects for the newly created tags scanTAlbums(); AlbumList resultList; for (QList::const_iterator it = tagIDs.constBegin() ; it != tagIDs.constEnd() ; ++it) { resultList.append(findTAlbum(*it)); } return resultList; } bool AlbumManager::deleteTAlbum(TAlbum* album, QString& errMsg, bool askUser) { if (!album) { errMsg = i18n("No such album"); return false; } if (album == d->rootTAlbum) { errMsg = i18n("Cannot delete Root Tag"); return false; } QList imageIds; if (askUser) { imageIds = CoreDbAccess().db()->getItemIDsInTag(album->id()); } { CoreDbAccess access; ChangingDB changing(d); access.db()->deleteTag(album->id()); Album* subAlbum = 0; AlbumIterator it(album); while ((subAlbum = it.current()) != 0) { access.db()->deleteTag(subAlbum->id()); ++it; } } removeTAlbum(album); emit signalAlbumsUpdated(Album::TAG); if (askUser) { askUserForWriteChangedTAlbumToFiles(imageIds); } return true; } bool AlbumManager::renameTAlbum(TAlbum* album, const QString& name, QString& errMsg) { if (!album) { errMsg = i18n("No such album"); return false; } if (album == d->rootTAlbum) { errMsg = i18n("Cannot edit root tag"); return false; } if (name.contains(QLatin1Char('/'))) { errMsg = i18n("Tag name cannot contain '/'"); return false; } // first check if we have another sibling with the same name if (hasDirectChildAlbumWithTitle(album->m_parent, name)) { errMsg = i18n("Another tag with the same name already exists.\n" "Please choose another name."); return false; } ChangingDB changing(d); CoreDbAccess().db()->setTagName(album->id(), name); album->setTitle(name); emit signalAlbumRenamed(album); askUserForWriteChangedTAlbumToFiles(album); return true; } bool AlbumManager::moveTAlbum(TAlbum* album, TAlbum* newParent, QString& errMsg) { if (!album) { errMsg = i18n("No such album"); return false; } if (!newParent) { errMsg = i18n("Attempt to move TAlbum to nowhere"); return false; } if (album == d->rootTAlbum) { errMsg = i18n("Cannot move root tag"); return false; } + if (!ProgressManager::instance()->isEmpty()) + { + errMsg = i18n("Other process are not finished yet.\n" + "Please try again later."); + return false; + } + if (hasDirectChildAlbumWithTitle(newParent, album->title())) { QPointer msgBox = new QMessageBox(QMessageBox::Warning, qApp->applicationName(), i18n("Another tag with the same name already exists.\n" "Do you want to merge the tags?"), QMessageBox::Yes | QMessageBox::No, qApp->activeWindow()); int result = msgBox->exec(); delete msgBox; if (result == QMessageBox::Yes) { TAlbum* const destAlbum = findTAlbum(newParent->tagPath() + QLatin1Char('/') + album->title()); return mergeTAlbum(album, destAlbum, false, errMsg); } else { return true; } } d->currentlyMovingAlbum = album; emit signalAlbumAboutToBeMoved(album); emit signalAlbumAboutToBeDeleted(album); if (album->parent()) { album->parent()->removeChild(album); } album->setParent(0); emit signalAlbumDeleted(album); emit signalAlbumHasBeenDeleted(reinterpret_cast(album)); emit signalAlbumAboutToBeAdded(album, newParent, newParent->lastChild()); ChangingDB changing(d); CoreDbAccess().db()->setTagParentID(album->id(), newParent->id()); album->setParent(newParent); emit signalAlbumAdded(album); emit signalAlbumMoved(album); emit signalAlbumsUpdated(Album::TAG); d->currentlyMovingAlbum = 0; TAlbum* personParentTag = findTAlbum(FaceTags::personParentTag()); if (personParentTag && personParentTag->isAncestorOf(album)) { FaceTags::ensureIsPerson(album->id()); } askUserForWriteChangedTAlbumToFiles(album); return true; } bool AlbumManager::mergeTAlbum(TAlbum* album, TAlbum* destAlbum, bool dialog, QString& errMsg) { if (!album || !destAlbum) { errMsg = i18n("No such album"); return false; } if (album == d->rootTAlbum || destAlbum == d->rootTAlbum) { errMsg = i18n("Cannot merge root tag"); return false; } if (album->firstChild()) { errMsg = i18n("Only a tag without children can be merged!"); return false; } + if (!ProgressManager::instance()->isEmpty()) + { + errMsg = i18n("Other process are not finished yet.\n" + "Please try again later."); + return false; + } + if (dialog) { QPointer msgBox = new QMessageBox(QMessageBox::Warning, qApp->applicationName(), i18n("Do you want to merge tag '%1' into tag '%2'?", album->title(), destAlbum->title()), QMessageBox::Yes | QMessageBox::No, qApp->activeWindow()); int result = msgBox->exec(); delete msgBox; if (result == QMessageBox::No) { return true; } } int oldId = album->id(); int mergeId = destAlbum->id(); if (oldId == mergeId) { return true; } QApplication::setOverrideCursor(Qt::WaitCursor); QList imageIds = CoreDbAccess().db()->getItemIDsInTag(oldId); CoreDbOperationGroup group; group.setMaximumTime(200); foreach (const qlonglong& imageId, imageIds) { QList facesList = FaceTagsEditor().databaseFaces(imageId); bool foundFace = false; foreach (const FaceTagsIface& face, facesList) { if (face.tagId() == oldId) { foundFace = true; FaceTagsEditor().removeFace(face); FaceTagsEditor().add(imageId, mergeId, face.region(), false); } } if (!foundFace) { ItemInfo info(imageId); info.removeTag(oldId); info.setTag(mergeId); group.allowLift(); } } QApplication::restoreOverrideCursor(); if (!deleteTAlbum(album, errMsg, false)) { return false; } askUserForWriteChangedTAlbumToFiles(imageIds); return true; } bool AlbumManager::updateTAlbumIcon(TAlbum* album, const QString& iconKDE, qlonglong iconID, QString& errMsg) { if (!album) { errMsg = i18n("No such tag"); return false; } if (album == d->rootTAlbum) { errMsg = i18n("Cannot edit root tag"); return false; } { CoreDbAccess access; ChangingDB changing(d); access.db()->setTagIcon(album->id(), iconKDE, iconID); album->m_icon = iconKDE; album->m_iconId = iconID; } emit signalAlbumIconChanged(album); return true; } AlbumList AlbumManager::getRecentlyAssignedTags(bool includeInternal) const { QList tagIDs = CoreDbAccess().db()->getRecentlyAssignedTags(); AlbumList resultList; for (QList::const_iterator it = tagIDs.constBegin() ; it != tagIDs.constEnd() ; ++it) { TAlbum* const album = findTAlbum(*it); if (album) { if (!includeInternal && album->isInternalTag()) { continue; } resultList.append(album); } } return resultList; } QStringList AlbumManager::tagPaths(const QList& tagIDs, bool leadingSlash, bool includeInternal) const { QStringList tagPaths; for (QList::const_iterator it = tagIDs.constBegin() ; it != tagIDs.constEnd() ; ++it) { TAlbum* album = findTAlbum(*it); if (album) { if (!includeInternal && album->isInternalTag()) { continue; } tagPaths.append(album->tagPath(leadingSlash)); } } return tagPaths; } QStringList AlbumManager::tagNames(const QList& tagIDs, bool includeInternal) const { QStringList tagNames; foreach (int id, tagIDs) { TAlbum* const album = findTAlbum(id); if (album) { if (!includeInternal && album->isInternalTag()) { continue; } tagNames << album->title(); } } return tagNames; } QHash AlbumManager::tagPaths(bool leadingSlash, bool includeInternal) const { QHash hash; AlbumIterator it(d->rootTAlbum); while (it.current()) { TAlbum* const t = (TAlbum*)(*it); if (includeInternal || !t->isInternalTag()) { hash.insert(t->id(), t->tagPath(leadingSlash)); } ++it; } return hash; } QHash AlbumManager::tagNames(bool includeInternal) const { QHash hash; AlbumIterator it(d->rootTAlbum); while (it.current()) { TAlbum* const t = (TAlbum*)(*it); if (includeInternal || !t->isInternalTag()) { hash.insert(t->id(), t->title()); } ++it; } return hash; } QList< int > AlbumManager::subTags(int tagId, bool recursive) { TAlbum* const album = this->findTAlbum(tagId); return album->childAlbumIds(recursive); } AlbumList AlbumManager::findTagsWithProperty(const QString& property) { AlbumList list; QList ids = TagsCache::instance()->tagsWithProperty(property); foreach (int id, ids) { TAlbum* const album = findTAlbum(id); if (album) { list << album; } } return list; } AlbumList AlbumManager::findTagsWithProperty(const QString& property, const QString& value) { AlbumList list; AlbumIterator it(d->rootTAlbum); while (it.current()) { if (static_cast(*it)->property(property) == value) { list << *it; } ++it; } return list; } QMap AlbumManager::getTAlbumsCount() const { return d->tAlbumsCount; } void AlbumManager::insertTAlbum(TAlbum* album, TAlbum* parent) { if (!album) { return; } emit signalAlbumAboutToBeAdded(album, parent, parent ? parent->lastChild() : 0); if (parent) { album->setParent(parent); } d->allAlbumsIdHash.insert(album->globalID(), album); emit signalAlbumAdded(album); } void AlbumManager::removeTAlbum(TAlbum* album) { if (!album) { return; } // remove all children of this album Album* child = album->firstChild(); TAlbum* toBeRemoved = 0; while (child) { Album* next = child->next(); toBeRemoved = static_cast(child); if (toBeRemoved) { removeTAlbum(toBeRemoved); toBeRemoved = 0; } child = next; } emit signalAlbumAboutToBeDeleted(album); d->allAlbumsIdHash.remove(album->globalID()); if (!d->currentAlbums.isEmpty()) { if (album == d->currentAlbums.first()) { d->currentAlbums.clear(); emit signalAlbumCurrentChanged(d->currentAlbums); } } emit signalAlbumDeleted(album); quintptr deletedAlbum = reinterpret_cast(album); delete album; emit signalAlbumHasBeenDeleted(deletedAlbum); } void AlbumManager::slotTagsJobResult() { if (!d->tagListJob) { return; } if (d->tagListJob->hasErrors()) { qCWarning(DIGIKAM_GENERAL_LOG) << "Failed to list face tags"; // Pop-up a message about the error. DNotificationWrapper(QString(), d->personListJob->errorsList().first(), 0, i18n("digiKam")); } d->tagListJob = 0; } void AlbumManager::slotTagsJobData(const QMap& tagsStatMap) { if (tagsStatMap.isEmpty()) { return; } d->tAlbumsCount = tagsStatMap; emit signalTAlbumsDirty(tagsStatMap); } void AlbumManager::slotTagChange(const TagChangeset& changeset) { if (d->changingDB || !d->rootTAlbum) { return; } switch (changeset.operation()) { case TagChangeset::Added: case TagChangeset::Moved: case TagChangeset::Deleted: case TagChangeset::Reparented: if (!d->scanTAlbumsTimer->isActive()) { d->scanTAlbumsTimer->start(); } break; case TagChangeset::Renamed: case TagChangeset::IconChanged: /** * @todo what happens here? */ break; case TagChangeset::PropertiesChanged: { TAlbum* tag = findTAlbum(changeset.tagId()); if (tag) { emit signalTagPropertiesChanged(tag); } break; } case TagChangeset::Unknown: break; } } void AlbumManager::slotImageTagChange(const ImageTagChangeset& changeset) { if (!d->rootTAlbum) { return; } switch (changeset.operation()) { case ImageTagChangeset::Added: case ImageTagChangeset::Removed: case ImageTagChangeset::RemovedAll: // Add properties changed. // Reason: in people sidebar, the images are not // connected with the ImageTag table but by // ImageTagProperties entries. // Thus, the count of entries in face tags are not // updated. This adoption should fix the problem. case ImageTagChangeset::PropertiesChanged: if (!d->tagItemCountTimer->isActive()) { d->tagItemCountTimer->start(); } break; default: break; } } void AlbumManager::askUserForWriteChangedTAlbumToFiles(TAlbum* const album) { QList imageIds = CoreDbAccess().db()->getItemIDsInTag(album->id()); askUserForWriteChangedTAlbumToFiles(imageIds); } void AlbumManager::askUserForWriteChangedTAlbumToFiles(const QList& imageIds) { MetaEngineSettings* const settings = MetaEngineSettings::instance(); if ((!settings->settings().saveTags && !settings->settings().saveFaceTags) || imageIds.isEmpty()) { return; } if (imageIds.count() > 100) { int result = d->longTimeMessageBoxResult; if (result == -1) { QPointer msgBox = new QMessageBox(QMessageBox::Warning, qApp->applicationName(), i18n("This operation can take a long time in the background.\n" "Do you want to write the metadata to %1 files now?", imageIds.count()), QMessageBox::Yes | QMessageBox::No, qApp->activeWindow()); QCheckBox* const chkBox = new QCheckBox(i18n("Do not ask again for this session"), msgBox); msgBox->setCheckBox(chkBox); result = msgBox->exec(); if (chkBox->isChecked()) { d->longTimeMessageBoxResult = result; } delete msgBox; } if (result != QMessageBox::Yes) { return; } } ItemInfoList infos(imageIds); MetadataSynchronizer* const tool = new MetadataSynchronizer(infos, MetadataSynchronizer::WriteFromDatabaseToFile); tool->start(); } } // namespace Digikam