diff --git a/core/libs/album/engine/album.cpp b/core/libs/album/engine/album.cpp index aa7f6b15ab..4c352816ec 100644 --- a/core/libs/album/engine/album.cpp +++ b/core/libs/album/engine/album.cpp @@ -1,857 +1,859 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2004-06-15 * Description : digiKam album types * * Copyright (C) 2004-2005 by Renchi Raju * Copyright (C) 2006-2020 by Gilles Caulier * Copyright (C) 2014-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 "album.h" // KDE includes #include // Local includes #include "digikam_debug.h" #include "coredb.h" #include "albummanager.h" #include "collectionmanager.h" #include "coredbaccess.h" #include "coredburl.h" #include "tagscache.h" namespace Digikam { Album::Album(Album::Type type, int id, bool root) : m_root(root), m_usedByLabelsTree(false), m_id(id), m_type(type), m_parent(nullptr) { } Album::~Album() { if (m_parent) { m_parent->removeChild(this); } clear(); AlbumManager::internalInstance->notifyAlbumDeletion(this); } void Album::setParent(Album* const parent) { if (parent) { m_parent = parent; parent->insertChild(this); } } Album* Album::parent() const { return m_parent; } Album* Album::firstChild() const { if (m_childCache.isEmpty()) { return nullptr; } return m_childCache.constFirst(); } Album* Album::lastChild() const { if (m_childCache.isEmpty()) { return nullptr; } return m_childCache.constLast(); } Album* Album::next() const { if (!m_parent) { return nullptr; } int row = m_parent->m_childCache.indexOf(const_cast(this)); - if (row < 0 || (row + 1 >= m_parent->m_childCache.count())) + if ((row < 0) || ((row + 1) >= m_parent->m_childCache.count())) { return nullptr; } return m_parent->m_childCache.at(row + 1); } Album* Album::prev() const { if (!m_parent) { return nullptr; } int row = m_parent->m_childCache.indexOf(const_cast(this)); if (row < 1) { return nullptr; } return m_parent->m_childCache.at(row - 1); } Album* Album::childAtRow(int row) const { return m_childCache.value(row, 0); } AlbumList Album::childAlbums(bool recursive) { AlbumList childList; QVector::const_iterator it = m_childCache.constBegin(); while (it != m_childCache.constEnd()) { childList << (*it); if (recursive) { childList << (*it)->childAlbums(recursive); } ++it; } return childList; } QList Album::childAlbumIds(bool recursive) { QList ids; AlbumList childList = childAlbums(recursive); QListIterator it(childList); while (it.hasNext()) { ids << it.next()->id(); } return ids; } void Album::insertChild(Album* const child) { if (!child) { return; } m_childCache.append(child); } void Album::removeChild(Album* const child) { if (!child) { return; } m_childCache.removeOne(child); } void Album::clear() { while (!m_childCache.isEmpty()) { delete m_childCache.takeFirst(); } } int Album::globalID() const { return globalID(m_type, m_id); } int Album::globalID(Type type, int id) { switch (type) { // Use the upper bits to create unique ids. case (PHYSICAL): return id; case (TAG): - return id | (1 << 27); + return (id | (1 << 27)); case (DATE): - return id | (1 << 28); + return (id | (1 << 28)); case (SEARCH): - return id | (1 << 29); + return (id | (1 << 29)); case (FACE): - return id | (1 << 30); + return (id | (1 << 30)); default: qCDebug(DIGIKAM_GENERAL_LOG) << "Unknown album type"; return -1; } } int Album::id() const { return m_id; } int Album::childCount() const { return m_childCache.count(); } int Album::rowFromAlbum() const { if (!m_parent) { return 0; } int row = m_parent->m_childCache.indexOf(const_cast(this)); return ((row != -1) ? row : 0); } void Album::setTitle(const QString& title) { m_title = title; } QString Album::title() const { return m_title; } Album::Type Album::type() const { return m_type; } void Album::setExtraData(const void* const key, void* const value) { m_extraMap.insert(key, value); } void Album::removeExtraData(const void* const key) { m_extraMap.remove(key); } void* Album::extraData(const void* const key) const { return m_extraMap.value(key, 0); } bool Album::isRoot() const { return m_root; } bool Album::isAncestorOf(Album* const album) const { bool val = false; Album* a = album; while (a && !a->isRoot()) { if (a == this) { val = true; break; } a = a->parent(); } return val; } bool Album::isUsedByLabelsTree() const { return m_usedByLabelsTree; } bool Album::isTrashAlbum() const { if ((m_id < -1) && (m_type == PHYSICAL)) { return true; } return false; } void Album::setUsedByLabelsTree(bool isUsed) { m_usedByLabelsTree = isUsed; } // ------------------------------------------------------------------------------ int PAlbum::m_uniqueTrashId = -2; PAlbum::PAlbum(const QString& title) : Album(Album::PHYSICAL, 0, true), m_isAlbumRootAlbum(false), m_albumRootId(-1), m_parentPath(QLatin1Char('/')), m_iconId(0) { setTitle(title); m_path.clear(); } PAlbum::PAlbum(int albumRoot, const QString& label) : Album(Album::PHYSICAL, -1, false), m_isAlbumRootAlbum(true), m_albumRootId(albumRoot), m_parentPath(QLatin1Char('/')), m_iconId(0) { // set the id to -1 (line above). AlbumManager may change that later. setTitle(label); m_path.clear(); } PAlbum::PAlbum(int albumRoot, const QString& parentPath, const QString& title, int id) : Album(Album::PHYSICAL, id, false), m_isAlbumRootAlbum(false), m_albumRootId(albumRoot), m_path(title), m_parentPath(parentPath + QLatin1Char('/')), m_iconId(0), m_date(QDate::currentDate()) { // If path is /holidays/2007, title is only "2007", path is "/holidays" setTitle(title); } PAlbum::PAlbum(const QString& parentPath, int albumRoot) : Album(Album::PHYSICAL, m_uniqueTrashId--, false), m_isAlbumRootAlbum(false), m_albumRootId(albumRoot), m_path(QLatin1String("Trash")), m_parentPath(parentPath + QLatin1Char('/')), m_iconId(0) { setTitle(i18n("Trash")); } PAlbum::~PAlbum() { } bool PAlbum::isAlbumRoot() const { return m_isAlbumRootAlbum; } void PAlbum::setCaption(const QString& caption) { m_caption = caption; CoreDbAccess access; access.db()->setAlbumCaption(id(), m_caption); } void PAlbum::setCategory(const QString& category) { m_category = category; CoreDbAccess access; access.db()->setAlbumCategory(id(), m_category); } void PAlbum::setDate(const QDate& date) { m_date = date; CoreDbAccess access; access.db()->setAlbumDate(id(), m_date); } QString PAlbum::albumRootPath() const { return CollectionManager::instance()->albumRootPath(m_albumRootId); } QString PAlbum::albumRootLabel() const { return CollectionManager::instance()->albumRootLabel(m_albumRootId); } int PAlbum::albumRootId() const { return m_albumRootId; } QString PAlbum::caption() const { return m_caption; } QString PAlbum::category() const { return m_category; } QDate PAlbum::date() const { return m_date; } QString PAlbum::albumPath() const { - return m_parentPath + m_path; + return (m_parentPath + m_path); } CoreDbUrl PAlbum::databaseUrl() const { return CoreDbUrl::fromAlbumAndName(QString(), albumPath(), QUrl::fromLocalFile(albumRootPath()), m_albumRootId); } QString PAlbum::prettyUrl() const { QString u = i18n("Albums") + QLatin1Char('/') + albumRootLabel() + albumPath(); if (u.endsWith(QLatin1Char('/'))) { u.chop(1); } return u; } qlonglong PAlbum::iconId() const { return m_iconId; } QUrl PAlbum::fileUrl() const { return databaseUrl().fileUrl(); } QString PAlbum::folderPath() const { return databaseUrl().fileUrl().toLocalFile(); } // -------------------------------------------------------------------------- TAlbum::TAlbum(const QString& title, int id, bool root) : Album(Album::TAG, id, root), m_pid(0), m_iconId(0) { setTitle(title); } TAlbum::~TAlbum() { } QString TAlbum::tagPath(bool leadingSlash) const { if (isRoot()) { - return leadingSlash ? QLatin1String("/") : QLatin1String(""); + return (leadingSlash ? QLatin1String("/") : QLatin1String("")); } QString u; if (parent()) { u = (static_cast(parent()))->tagPath(leadingSlash); if (!parent()->isRoot()) { u += QLatin1Char('/'); } } u += title(); return u; } QString TAlbum::prettyUrl() const { - return i18n("Tags") + tagPath(true); + return (i18n("Tags") + tagPath(true)); } CoreDbUrl TAlbum::databaseUrl() const { return CoreDbUrl::fromTagIds(tagIDs()); } QList TAlbum::tagIDs() const { if (isRoot()) { return QList(); } else if (parent()) { - return static_cast(parent())->tagIDs() << id(); + return (static_cast(parent())->tagIDs() << id()); } else { - return QList() << id(); + return (QList() << id()); } } QString TAlbum::icon() const { return m_icon; } bool TAlbum::isInternalTag() const { return TagsCache::instance()->isInternalTag(id()); } qlonglong TAlbum::iconId() const { return m_iconId; } bool TAlbum::hasProperty(const QString& key) const { return TagsCache::instance()->hasProperty(id(), key); } QString TAlbum::property(const QString& key) const { return TagsCache::instance()->propertyValue(id(), key); } QMap TAlbum::properties() const { return TagsCache::instance()->properties(id()); } // -------------------------------------------------------------------------- int DAlbum::m_uniqueID = 0; DAlbum::DAlbum(const QDate& date, bool root, Range range) : Album(Album::DATE, root ? 0 : ++m_uniqueID, root), m_date(date), m_range(range) { // Set the name of the date album + QString dateTitle; if (m_range == Month) { dateTitle = m_date.toString(QLatin1String("MMMM yyyy")); } else { dateTitle = m_date.toString(QLatin1String("yyyy")); } setTitle(dateTitle); } DAlbum::~DAlbum() { } QDate DAlbum::date() const { return m_date; } DAlbum::Range DAlbum::range() const { return m_range; } CoreDbUrl DAlbum::databaseUrl() const { if (m_range == Month) { return CoreDbUrl::fromDateForMonth(m_date); } return CoreDbUrl::fromDateForYear(m_date); } // -------------------------------------------------------------------------- SAlbum::SAlbum(const QString& title, int id, bool root) : Album(Album::SEARCH, id, root), m_searchType(DatabaseSearch::UndefinedType) { setTitle(title); } SAlbum::~SAlbum() { } void SAlbum::setSearch(DatabaseSearch::Type type, const QString& query) { m_searchType = type; m_query = query; } CoreDbUrl SAlbum::databaseUrl() const { return CoreDbUrl::searchUrl(id()); } QString SAlbum::query() const { return m_query; } DatabaseSearch::Type SAlbum::searchType() const { return m_searchType; } bool SAlbum::isNormalSearch() const { switch (m_searchType) { case DatabaseSearch::KeywordSearch: case DatabaseSearch::AdvancedSearch: case DatabaseSearch::LegacyUrlSearch: return true; default: return false; } } bool SAlbum::isAdvancedSearch() const { return (m_searchType == DatabaseSearch::AdvancedSearch); } bool SAlbum::isKeywordSearch() const { return (m_searchType == DatabaseSearch::KeywordSearch); } bool SAlbum::isTimelineSearch() const { return (m_searchType == DatabaseSearch::TimeLineSearch); } bool SAlbum::isHaarSearch() const { return (m_searchType == DatabaseSearch::HaarSearch); } bool SAlbum::isMapSearch() const { return (m_searchType == DatabaseSearch::MapSearch); } bool SAlbum::isDuplicatesSearch() const { return (m_searchType == DatabaseSearch::DuplicatesSearch); } bool SAlbum::isTemporarySearch() const { if (isHaarSearch()) { return ((title() == getTemporaryHaarTitle(DatabaseSearch::HaarImageSearch))) || (title() == getTemporaryHaarTitle(DatabaseSearch::HaarSketchSearch)); } return (title() == getTemporaryTitle(m_searchType)); } QString SAlbum::displayTitle() const { if (isTemporarySearch()) { switch (m_searchType) { case DatabaseSearch::TimeLineSearch: return i18n("Current Timeline Search"); case DatabaseSearch::HaarSearch: { if (title() == getTemporaryHaarTitle(DatabaseSearch::HaarImageSearch)) { return i18n("Current Fuzzy Image Search"); } else if (title() == getTemporaryHaarTitle(DatabaseSearch::HaarSketchSearch)) { return i18n("Current Fuzzy Sketch Search"); } break; } case DatabaseSearch::MapSearch: return i18n("Current Map Search"); case DatabaseSearch::KeywordSearch: case DatabaseSearch::AdvancedSearch: case DatabaseSearch::LegacyUrlSearch: return i18n("Current Search"); case DatabaseSearch::DuplicatesSearch: return i18n("Current Duplicates Search"); case DatabaseSearch::UndefinedType: break; } } return title(); } QString SAlbum::getTemporaryTitle(DatabaseSearch::Type type, DatabaseSearch::HaarSearchType haarType) { switch (type) { case DatabaseSearch::TimeLineSearch: return QLatin1String("_Current_Time_Line_Search_"); case DatabaseSearch::HaarSearch: return getTemporaryHaarTitle(haarType); case DatabaseSearch::MapSearch: return QLatin1String("_Current_Map_Search_"); case DatabaseSearch::KeywordSearch: case DatabaseSearch::AdvancedSearch: case DatabaseSearch::LegacyUrlSearch: return QLatin1String("_Current_Search_View_Search_"); case DatabaseSearch::DuplicatesSearch: return QLatin1String("_Current_Duplicates_Search_"); default: qCDebug(DIGIKAM_GENERAL_LOG) << "Untreated temporary search type " << type; return QLatin1String("_Current_Unknown_Search_"); } } QString SAlbum::getTemporaryHaarTitle(DatabaseSearch::HaarSearchType haarType) { switch (haarType) { case DatabaseSearch::HaarImageSearch: return QLatin1String("_Current_Fuzzy_Image_Search_"); case DatabaseSearch::HaarSketchSearch: return QLatin1String("_Current_Fuzzy_Sketch_Search_"); default: qCDebug(DIGIKAM_GENERAL_LOG) << "Untreated temporary haar search type " << haarType; return QLatin1String("_Current_Unknown_Haar_Search_"); } } // -------------------------------------------------------------------------- AlbumIterator::AlbumIterator(Album* const album) : m_current(album ? album->firstChild() : nullptr), m_root(album) { } AlbumIterator::~AlbumIterator() { } AlbumIterator& AlbumIterator::operator++() { if (!m_current) { return *this; } Album* album = m_current->firstChild(); if (!album) { while ((album = m_current->next()) == nullptr) { m_current = m_current->parent(); if (m_current == m_root) { // we have reached the root. // that means no more children + m_current = nullptr; break; } if (m_current == nullptr) { break; } } } m_current = album; return *this; } Album* AlbumIterator::operator*() { return m_current; } Album* AlbumIterator::current() const { return m_current; } } // namespace Digikam diff --git a/core/libs/album/engine/album.h b/core/libs/album/engine/album.h index 0685abe241..2feb426677 100644 --- a/core/libs/album/engine/album.h +++ b/core/libs/album/engine/album.h @@ -1,593 +1,599 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2004-06-15 * Description : digiKam album types * * Copyright (C) 2004-2005 by Renchi Raju * Copyright (C) 2006-2020 by Gilles Caulier * Copyright (C) 2014-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. * * ============================================================ */ #ifndef DIGIKAM_ALBUM_H #define DIGIKAM_ALBUM_H // Qt includes #include #include #include #include #include #include #include // Local includes #include "coredbalbuminfo.h" #include "digikam_export.h" namespace Digikam { -/** Album list type definition. +/** + * Album list type definition. */ class Album; typedef QList AlbumList; class CoreDbUrl; /** * \class Album * \brief Abstract base class for all album types * * A class which provides an abstraction for a type Album. This class is meant to * be derived and every time a new Album Type is defined add a enum corresponding * to that to Album::Type * * This class provides a means of building a tree representation for * Albums @see Album::setParent(). */ class DIGIKAM_GUI_EXPORT Album { public: enum Type { PHYSICAL=0, ///< A physical album type @see PAlbum TAG, ///< A tag album type @see TAlbum DATE, ///< A date album type @see DAlbum SEARCH, ///< A search album type @see SAlbum FACE ///< A faces album type @see FAlbum }; /** * @return the parent album for this album */ Album* parent() const; /** * @return the first child of this album or 0 if no children */ Album* firstChild() const; /** * @return the last child of this album or 0 if no children */ Album* lastChild() const; /** * @return the next sibling of this album of this album or 0 * if no next sibling * @see AlbumIterator */ Album* next() const; /** * @return the previous sibling of this album of this album or 0 if no * previous sibling * @see AlbumIterator */ Album* prev() const; /** * @return the child of this album at row */ Album* childAtRow(int row) const; /** * @return a list of all child Albums */ AlbumList childAlbums(bool recursive = false); /** * @return a list of all child Albums */ QList childAlbumIds(bool recursive = false); /** * @return the type of album * @see Type */ Type type() const; /** * Each album has a @p ID uniquely identifying it in the set of Albums of * a Type * * \note The @p ID for a root Album is always 0 * * @return the @p ID of the album * @see globalID() */ int id() const; /** * An album ID is only unique among the set of all Albums of its Type. * This is a global Identifier which will uniquely identifying the Album * among all Albums * * \note If you are adding a new Album Type make sure to update * this implementation. * * You can always get the @p ID of the album using something like * * \code * int albumID = rootAlbum->globalID() - album->globalID(); * \endcode * * @return the @p globalID of the album * @see id() */ int globalID() const; /** * @return the @p childCount of the album */ int childCount() const; /** * @return the @p rowFromAlbum of the album */ int rowFromAlbum() const; /** * @return the @p title aka name of the album */ QString title() const; /** * @return the kde url of the album */ virtual CoreDbUrl databaseUrl() const = 0; /** * @return true is the album is a Root Album */ bool isRoot() const; /** * @return true if the @p album is in the parent hierarchy * * @param album Album to check whether it belongs in the child * hierarchy */ bool isAncestorOf(Album* const album) const; /** * @return true if the Album was created by Labels Tree * */ bool isUsedByLabelsTree() const; /** * @return true if the album was created to be a trash * virtual album */ bool isTrashAlbum() const; /** * This allows to associate some "extra" data to a Album. As one * Album can be used by several objects (often views) which all need * to add some data, you have to use a key to reference your extra data * within the Album. * * That way a Album can hold and provide access to all those views * separately. * * for eg, * * \code * album->setExtraData( this, searchFolderItem ); * \endcode * * and can later access the searchFolderItem by doing * * \code * SearchFolderItem *item = static_cast(album->extraData(this)); * \endcode * * Note: you have to remove and destroy the data you associated yourself * when you don't need it anymore! * * @param key the key of the extra data * @param value the value of the extra data * @see extraData * @see removeExtraData */ void setExtraData(const void* const key, void* const value); /** * Remove the associated extra data associated with @p key * * @param key the key of the extra data * @see setExtraData * @see extraData */ void removeExtraData(const void* const key); /** * Retrieve the associated extra data associated with @p key * * @param key the key of the extra data * @see setExtraData * @see extraData */ void* extraData(const void* const key) const; /** * Sets the property m_usedByLabelsTree to true if the search album * was created using the Colors and labels tree view * * @param isUsed => the status of the usage */ void setUsedByLabelsTree(bool isUsed); /** * @brief Produces the global id * @param type The type of the album * @param id the (type-specific) id of the album * @return the global id */ static int globalID(Type type, int id); protected: /** * Constructor */ Album(Album::Type type, int id, bool root); /** * Destructor * * this will also recursively delete all child Albums */ virtual ~Album(); /** * Delete all child albums and also remove any associated extra data */ void clear(); /** * @internal use only * * Set a new title for the album * * @param title new title for the album */ void setTitle(const QString& title); /** * @internal use only * * Set the parent of the album * * @param parent set the parent album of album to @p parent */ void setParent(Album* const parent); /** * @internal use only * * Insert an Album as a child for this album * * @param child the Album to add as child */ void insertChild(Album* const child); /** * @internal use only * * Remove a Album from the children list for this album * * @param child the Album to remove */ void removeChild(Album* const child); private: /** * Disable copy and default constructor */ Album(); Q_DISABLE_COPY(Album) Album& operator==(const Album&); private: bool m_root; bool m_usedByLabelsTree; int m_id; QString m_name; QString m_title; QMap m_extraMap; QVector m_childCache; Type m_type; Album* m_parent; friend class AlbumManager; }; /** * \class PAlbum * * A Physical Album representation */ class DIGIKAM_GUI_EXPORT PAlbum : public Album { public: /// Constructor for root album explicit PAlbum(const QString& title); + /// Constructor for album root albums PAlbum(int albumRoot, const QString& label); + /// Constructor for normal albums PAlbum(int albumRoot, const QString& parentPath, const QString& title, int id); + /// Constructor for Trash album PAlbum(const QString& parentPath, int albumRoot); ~PAlbum(); void setCaption(const QString& caption); void setCategory(const QString& category); void setDate(const QDate& date); QString albumRootPath() const; QString albumRootLabel() const; int albumRootId() const; QString caption() const; QString category() const; QDate date() const; QString albumPath() const; QString prettyUrl() const; QString folderPath() const; CoreDbUrl databaseUrl() const override; QUrl fileUrl() const; qlonglong iconId() const; bool isAlbumRoot() const; private: - /// A special integer for Trash virtual folders Ids; - /// That gets decremented not incremented + /** + * A special integer for Trash virtual folders Ids; + * That gets decremented not incremented + */ static int m_uniqueTrashId; bool m_isAlbumRootAlbum; int m_albumRootId; QString m_path; QString m_parentPath; QString m_category; QString m_caption; qlonglong m_iconId; QDate m_date; friend class AlbumManager; }; /** * \class TAlbum * * A Tag Album representation */ class DIGIKAM_GUI_EXPORT TAlbum : public Album { public: TAlbum(const QString& title, int id, bool root=false); ~TAlbum(); /** * @return The tag path, e.g. "/People/Friend/John" if leadingSlash is true, - "People/Friend/John" if leadingSlash if false. + * "People/Friend/John" if leadingSlash if false. * The root TAlbum returns "/" resp. "". */ QString tagPath(bool leadingSlash = true) const; CoreDbUrl databaseUrl() const override; QString prettyUrl() const; QString icon() const; qlonglong iconId() const; QList tagIDs() const; bool isInternalTag() const; bool hasProperty(const QString& key) const; QString property(const QString& key) const; QMap properties() const; private: int m_pid; QString m_icon; qlonglong m_iconId; friend class AlbumManager; }; /** * \class DAlbum * * A Date Album representation */ class DIGIKAM_GUI_EXPORT DAlbum : public Album { public: enum Range { Month = 0, Year }; public: explicit DAlbum(const QDate& date, bool root=false, Range range=Month); ~DAlbum(); QDate date() const; Range range() const; CoreDbUrl databaseUrl() const override; private: static int m_uniqueID; QDate m_date; Range m_range; friend class AlbumManager; }; /** * \class SAlbum * * A Search Album representation */ class DIGIKAM_GUI_EXPORT SAlbum : public Album { public: SAlbum(const QString& title, int id, bool root=false); ~SAlbum(); CoreDbUrl databaseUrl() const override; QString query() const; DatabaseSearch::Type searchType() const; bool isNormalSearch() const; bool isAdvancedSearch() const; bool isKeywordSearch() const; bool isTimelineSearch() const; bool isHaarSearch() const; bool isMapSearch() const; bool isDuplicatesSearch() const; /** * Indicates whether this album is a temporary search or not. * * @return true if this is a temporary search album, else false */ bool isTemporarySearch() const; QString displayTitle() const; /** * Returns the title of search albums that is used to mark them as a * temporary search that isn't saved officially yet and is only used for * viewing purposes. * * @param type type of the search to get the temporary title for * @param haarType there are several haar searches, so that this search type * needs a special handling * @return string that identifies this album uniquely as an unsaved search */ static QString getTemporaryTitle(DatabaseSearch::Type type, DatabaseSearch::HaarSearchType haarType = DatabaseSearch::HaarImageSearch); /** * Returns the title for a temporary haar search depending on the sub-type * used for this search * * @param haarType type of the haar search to get the name for * @return string that identifies this album uniquely as an unsaved search */ static QString getTemporaryHaarTitle(DatabaseSearch::HaarSearchType haarType); private: void setSearch(DatabaseSearch::Type type, const QString& query); private: QString m_query; DatabaseSearch::Type m_searchType; friend class AlbumManager; }; /** * \class AlbumIterator * * Iterate over all children of this Album. * \note It will not include the specified album * * Example usage: * \code * AlbumIterator it(album); * while ( it.current() ) * { * qCDebug(DIGIKAM_GENERAL_LOG) << "Album: " << it.current()->title(); * ++it; * } * \endcode * * \warning Do not delete albums using this iterator. */ class DIGIKAM_GUI_EXPORT AlbumIterator { public: explicit AlbumIterator(Album* const album); ~AlbumIterator(); AlbumIterator& operator++(); Album* operator*(); Album* current() const; private: // disable copying and construction without an album AlbumIterator(); Q_DISABLE_COPY(AlbumIterator) private: Album* m_current; Album* m_root; }; } // namespace Digikam Q_DECLARE_METATYPE(Digikam::Album*) #endif // DIGIKAM_ALBUM_H diff --git a/core/libs/album/engine/albumhistory.cpp b/core/libs/album/engine/albumhistory.cpp index 2b7c8b5af3..d4f8ed4100 100644 --- a/core/libs/album/engine/albumhistory.cpp +++ b/core/libs/album/engine/albumhistory.cpp @@ -1,595 +1,599 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2004-11-17 * Description : albums history manager. * * Copyright (C) 2004 by Joern Ahrens * Copyright (C) 2006-2020 by Gilles Caulier * Copyright (C) 2014 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 "albumhistory.h" // Qt includes #include #include #include // Local includes #include "digikam_debug.h" #include "album.h" #include "iteminfo.h" #include "albummanager.h" #include "labelstreeview.h" namespace Digikam { inline uint qHash(const QList& key) { if (key.isEmpty()) { return 0; } Album* const temp = key.first(); quint64 myint = (unsigned long long)temp; uint value = ::qHash(myint); for (int it = 1 ; it < key.size() ; ++it) { Album* const al = key.at(it); quint64 myint2 = (unsigned long long)al; value ^= ::qHash(myint2); } return value; } /** * Stores an album along with the sidebar view, where the album * is selected */ class Q_DECL_HIDDEN HistoryItem { public: HistoryItem() { widget = nullptr; }; HistoryItem(QList const a, QWidget* const w) { albums.append(a); widget = w; }; HistoryItem(QList const a, QWidget* const w, QHash > selectedLabels) { albums.append(a); widget = w; labels = selectedLabels; }; bool operator==(const HistoryItem& item) { if (widget != item.widget) { return false; } - return albums == item.albums; + return (albums == item.albums); } QList albums; QWidget* widget; QHash > labels; }; // --------------------------------------------------------------------- class Q_DECL_HIDDEN HistoryPosition { public: HistoryPosition() { }; HistoryPosition(const ItemInfo& c, const QList& s) : current(c), select(s) { }; bool operator==(const HistoryPosition& item) { - return (current == item.current) && (select == item.select); + return ((current == item.current) && (select == item.select)); } +public: + ItemInfo current; QList select; }; // --------------------------------------------------------------------- class Q_DECL_HIDDEN AlbumHistory::Private { public: explicit Private() : moving(false), blockSelection(false) { } void forward(unsigned int steps = 1); public: bool moving; bool blockSelection; QList backwardStack; QList forwardStack; QHash, HistoryPosition> historyPos; QHash > neededLabels; }; void AlbumHistory::Private::forward(unsigned int steps) { - if (forwardStack.isEmpty() || (int)steps > forwardStack.count()) + if (forwardStack.isEmpty() || ((int)steps > forwardStack.count())) { return; } while (steps) { backwardStack << forwardStack.takeFirst(); --steps; } moving = true; } AlbumHistory::AlbumHistory() : d(new Private) { } AlbumHistory::~AlbumHistory() { clearHistory(); delete d; } void AlbumHistory::clearHistory() { d->backwardStack.clear(); d->forwardStack.clear(); d->historyPos.clear(); d->moving = false; } void AlbumHistory::addAlbums(const QList& albums, QWidget* const widget) { if (albums.isEmpty() || !widget || d->moving) { d->moving = false; + return; } // Same album as before in the history if (!d->backwardStack.isEmpty() && d->backwardStack.last().albums == albums) { d->backwardStack.last().widget = widget; + return; } d->backwardStack << HistoryItem(albums, widget); // The forward stack has to be cleared, if backward stack was changed d->forwardStack.clear(); } /** * @brief AlbumHistory::addAlbums * A special overloaded function for handling AlbumHistory * for the Labels tree-view * * @author Mohamed_Anwer */ void AlbumHistory::addAlbums(const QList& albums, QWidget* const widget, QHash > selectedLabels) { if (albums.isEmpty() || !widget || d->moving) { d->moving = false; return; } if (!d->backwardStack.isEmpty() && d->backwardStack.last().albums.first()->isUsedByLabelsTree()) { d->backwardStack.last().widget = widget; d->backwardStack.last().labels = selectedLabels; return; } d->backwardStack << HistoryItem(albums, widget, selectedLabels); // The forward stack has to be cleared, if backward stack was changed d->forwardStack.clear(); } void AlbumHistory::deleteAlbum(Album* const album) { if (!album || d->backwardStack.isEmpty()) { return; } QList albums; albums << album; // Search all HistoryItems, with album and delete them QList::iterator it = d->backwardStack.begin(); while (it != d->backwardStack.end()) { if (it->albums == albums) { it = d->backwardStack.erase(it); } else { ++it; } } it = d->forwardStack.begin(); while (it != d->forwardStack.end()) { if (it->albums == albums) { it = d->forwardStack.erase(it); } else { ++it; } } if (d->backwardStack.isEmpty() && d->forwardStack.isEmpty()) { return; } // If backwardStack is empty, then there is no current album. // So make the first album of the forwardStack the current one. if (d->backwardStack.isEmpty()) { d->forward(); } // After the album is deleted from the history it has to be ensured, // that neighboring albums are different QList::iterator lhs = d->backwardStack.begin(); QList::iterator rhs = lhs; ++rhs; while (rhs != d->backwardStack.end()) { if (*lhs == *rhs) { rhs = d->backwardStack.erase(rhs); } else { ++lhs; rhs = lhs; ++rhs; } } rhs = d->forwardStack.begin(); while (rhs != d->forwardStack.end()) { if (*lhs == *rhs) { rhs = d->forwardStack.erase(rhs); } else { if (lhs == (d->backwardStack.isEmpty() ? d->backwardStack.end() : --d->backwardStack.end())) { lhs = d->forwardStack.begin(); } else { ++lhs; rhs = lhs; } ++rhs; } } if (d->backwardStack.isEmpty() && !d->forwardStack.isEmpty()) { d->forward(); } } void AlbumHistory::getBackwardHistory(QStringList& list) const { if (d->backwardStack.isEmpty()) { return; } QList::const_iterator it = d->backwardStack.constBegin(); for ( ; it != (d->backwardStack.isEmpty() ? d->backwardStack.constEnd() : --d->backwardStack.constEnd()) ; ++it) { if (!(it->albums.isEmpty())) { QString name; for (int iter = 0 ; iter < it->albums.size() ; ++iter) { name.append(it->albums.at(iter)->title()); if (iter+1 < it->albums.size()) { name.append(QLatin1Char('/')); } } list.prepend(name); } } } void AlbumHistory::getForwardHistory(QStringList& list) const { if (d->forwardStack.isEmpty()) { return; } QList::const_iterator it; for (it = d->forwardStack.constBegin() ; it != d->forwardStack.constEnd() ; ++it) { if (!(it->albums.isEmpty())) { QString name; for (int iter = 0 ; iter < it->albums.size() ; ++iter) { name.append(it->albums.at(iter)->title()); if (iter+1 < it->albums.size()) { name.append(QLatin1Char('/')); } } list.append(name); } } } void AlbumHistory::back(QList& album, QWidget** const widget, unsigned int steps) { *widget = nullptr; if ((d->backwardStack.count() <= 1) || ((int)steps > d->backwardStack.count())) { return; // Only the current album available } while (steps) { d->forwardStack.prepend(d->backwardStack.takeLast()); --steps; } d->moving = true; if (d->backwardStack.isEmpty()) { return; } album.append(d->backwardStack.last().albums); *widget = d->backwardStack.last().widget; d->neededLabels = d->backwardStack.last().labels; } void AlbumHistory::forward(QList& album, QWidget** const widget, unsigned int steps) { *widget = nullptr; - if (d->forwardStack.isEmpty() || (int)steps > d->forwardStack.count()) + if (d->forwardStack.isEmpty() || ((int)steps > d->forwardStack.count())) { return; } d->forward(steps); if (d->backwardStack.isEmpty()) { return; } album.append(d->backwardStack.last().albums); *widget = d->backwardStack.last().widget; d->neededLabels = d->backwardStack.last().labels; } void AlbumHistory::getCurrentAlbum(Album** const album, QWidget** const widget) const { *album = nullptr; *widget = nullptr; if (d->backwardStack.isEmpty()) { return; } if (!(d->backwardStack.last().albums.isEmpty())) { *album = d->backwardStack.last().albums.first(); } *widget = d->backwardStack.last().widget; } bool AlbumHistory::isForwardEmpty() const { return d->forwardStack.isEmpty(); } bool AlbumHistory::isBackwardEmpty() const { // the last album of the backwardStack is the currently shown // album, and therefore not really a previous album - return (d->backwardStack.count() <= 1) ? true : false; + return ((d->backwardStack.count() <= 1) ? true : false); } QHash > AlbumHistory::neededLabels() { return d->neededLabels; } void AlbumHistory::slotAlbumSelected() { QList albumList = AlbumManager::instance()->currentAlbums(); if (d->historyPos.contains(albumList)) { d->blockSelection = true; emit signalSetCurrent(d->historyPos[albumList].current.id()); } } void AlbumHistory::slotAlbumCurrentChanged() { QList albumList = AlbumManager::instance()->currentAlbums(); if (!(albumList.isEmpty()) && d->historyPos.contains(albumList)) { if (d->historyPos[albumList].select.size()) { emit signalSetSelectedInfos(d->historyPos[albumList].select); } } d->blockSelection = false; } void AlbumHistory::slotCurrentChange(const ItemInfo& info) { QList albumList = AlbumManager::instance()->currentAlbums(); if (albumList.isEmpty()) { return; } d->historyPos[albumList].current = info; } void AlbumHistory::slotImageSelected(const ItemInfoList& selectedImages) { if (d->blockSelection) { return; } QList albumList = AlbumManager::instance()->currentAlbums(); if (d->historyPos.contains(albumList)) { d->historyPos[albumList].select = selectedImages; } } void AlbumHistory::slotClearSelectPAlbum(const ItemInfo& imageInfo) { Album* const album = dynamic_cast(AlbumManager::instance()->findPAlbum(imageInfo.albumId())); QList albums; albums << album; if (d->historyPos.contains(albums)) { d->historyPos[albums].select.clear(); } } void AlbumHistory::slotClearSelectTAlbum(int id) { Album* const album = dynamic_cast(AlbumManager::instance()->findTAlbum(id)); QList albums; albums << album; if (d->historyPos.contains(albums)) { d->historyPos[albums].select.clear(); } } void AlbumHistory::slotAlbumDeleted(Album* album) { deleteAlbum(album); QList albums; albums << album; if (d->historyPos.contains(albums)) { d->historyPos.remove(albums); } } void AlbumHistory::slotAlbumsCleared() { clearHistory(); } } // namespace Digikam diff --git a/core/libs/album/engine/albummodificationhelper.cpp b/core/libs/album/engine/albummodificationhelper.cpp index 8021269cfd..734899e138 100644 --- a/core/libs/album/engine/albummodificationhelper.cpp +++ b/core/libs/album/engine/albummodificationhelper.cpp @@ -1,350 +1,357 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2000-12-05 * Description : helper class used to modify physical albums in views * * Copyright (C) 2009-2011 by Johannes Wienke * Copyright (C) 2014-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 "albummodificationhelper.h" // Qt includes #include #include #include #include #include // KDE includes #include // Local includes #include "digikam_debug.h" #include "albummanager.h" #include "albumpropsedit.h" #include "albumpointer.h" #include "applicationsettings.h" #include "collectionmanager.h" #include "deletedialog.h" #include "dio.h" #include "itemiconview.h" #include "digikamapp.h" #include "coredb.h" #include "coredbaccess.h" namespace Digikam { class Q_DECL_HIDDEN AlbumModificationHelper::Private { public: explicit Private() : dialogParent(nullptr) { } QWidget* dialogParent; }; AlbumModificationHelper::AlbumModificationHelper(QObject* const parent, QWidget* const dialogParent) - : QObject(parent), d(new Private) + : QObject(parent), + d(new Private) { d->dialogParent = dialogParent; } AlbumModificationHelper::~AlbumModificationHelper() { delete d; } void AlbumModificationHelper::bindAlbum(QAction* const action, PAlbum* const album) const { action->setData(QVariant::fromValue(AlbumPointer(album))); } PAlbum* AlbumModificationHelper::boundAlbum(QObject* const sender) const { QAction* action = nullptr; - if ( (action = qobject_cast(sender)) ) + if ((action = qobject_cast(sender))) { return action->data().value >(); } return nullptr; } PAlbum* AlbumModificationHelper::slotAlbumNew() { return slotAlbumNew(boundAlbum(sender())); } PAlbum* AlbumModificationHelper::slotAlbumNew(PAlbum* parent) { if (!parent) { qCWarning(DIGIKAM_GENERAL_LOG) << "No parent album given"; return nullptr; } ApplicationSettings* settings = ApplicationSettings::instance(); if (!settings) { qCWarning(DIGIKAM_GENERAL_LOG) << "could not get Album Settings"; return nullptr; } /* QDir libraryDir(settings->getAlbumLibraryPath()); if (!libraryDir.exists()) { QMessageBox::critical(qApp->activeWindow(), qApp->applicationName(), i18n("The album library has not been set correctly.\n" "Select \"Configure Digikam\" from the Settings " "menu and choose a folder to use for the album " "library.")); return; } */ // if we create an album under root, need to supply the album root path. + QString albumRootPath; albumRootPath = CollectionManager::instance()->oneAlbumRootPath(); QString title; QString comments; QString category; QDate date; QStringList albumCategories; int parentSelector; if (!AlbumPropsEdit::createNew(parent, title, comments, date, category, albumCategories, parentSelector)) { return nullptr; } QStringList oldAlbumCategories(ApplicationSettings::instance()->getAlbumCategoryNames()); if (albumCategories != oldAlbumCategories) { ApplicationSettings::instance()->setAlbumCategoryNames(albumCategories); } QString errMsg; PAlbum* album = nullptr; - if (parent->isRoot() || parentSelector == 1) + if (parent->isRoot() || (parentSelector == 1)) { album = AlbumManager::instance()->createPAlbum(albumRootPath, title, comments, date, category, errMsg); } else { album = AlbumManager::instance()->createPAlbum(parent, title, comments, date, category, errMsg); } if (!album) { QMessageBox::critical(qApp->activeWindow(), qApp->applicationName(), errMsg); + return nullptr; } return album; } void AlbumModificationHelper::slotAlbumDelete() { slotAlbumDelete(boundAlbum(sender())); } void AlbumModificationHelper::slotAlbumDelete(PAlbum* album) { if (!album || album->isRoot() || album->isAlbumRoot()) { return; } // find subalbums + QList childrenList; addAlbumChildrenToList(childrenList, album); DeleteDialog dialog(d->dialogParent); // All subalbums will be presented in the list as well + if (!dialog.confirmDeleteList(childrenList, - childrenList.size() == 1 ? - DeleteDialogMode::Albums : DeleteDialogMode::Subalbums, + (childrenList.size() == 1) ? DeleteDialogMode::Albums + : DeleteDialogMode::Subalbums, DeleteDialogMode::UserPreference)) { return; } bool useTrash = !dialog.shouldDelete(); DIO::del(album, useTrash); } void AlbumModificationHelper::slotAlbumRename() { slotAlbumRename(boundAlbum(sender())); } void AlbumModificationHelper::slotAlbumRename(PAlbum* album) { if (!album) { return; } QString oldTitle(album->title()); QPointer textDlg = new QInputDialog(d->dialogParent); textDlg->setWindowTitle(i18n("Rename Album (%1)", oldTitle)); textDlg->setLabelText(i18n("Enter new album name:")); textDlg->resize(450, textDlg->sizeHint().height()); textDlg->setInputMode(QInputDialog::TextInput); textDlg->setTextEchoMode(QLineEdit::Normal); textDlg->setTextValue(oldTitle); if (textDlg->exec() != QDialog::Accepted) { delete textDlg; return; } QString title = textDlg->textValue(); delete textDlg; if (title != oldTitle) { QString errMsg; if (!AlbumManager::instance()->renamePAlbum(album, title, errMsg)) { QMessageBox::critical(qApp->activeWindow(), qApp->applicationName(), errMsg); } } } void AlbumModificationHelper::addAlbumChildrenToList(QList& list, Album* const album) { // simple recursive helper function + if (album) { if (!list.contains(album->databaseUrl())) { list.append(album->databaseUrl()); } AlbumIterator it(album); while (it.current()) { addAlbumChildrenToList(list, *it); ++it; } } } void AlbumModificationHelper::slotAlbumEdit() { slotAlbumEdit(boundAlbum(sender())); } void AlbumModificationHelper::slotAlbumEdit(PAlbum* album) { if (!album || album->isRoot() || album->isAlbumRoot()) { return; } QString oldTitle(album->title()); QString oldComments(album->caption()); QString oldCategory(album->category()); QDate oldDate(album->date()); QStringList oldAlbumCategories(ApplicationSettings::instance()->getAlbumCategoryNames()); QString title, comments, category; QDate date; QStringList albumCategories; if (AlbumPropsEdit::editProps(album, title, comments, date, category, albumCategories)) { if (comments != oldComments) { album->setCaption(comments); } - if (date != oldDate && date.isValid()) + if ((date != oldDate) && date.isValid()) { album->setDate(date); } if (category != oldCategory) { album->setCategory(category); } ApplicationSettings::instance()->setAlbumCategoryNames(albumCategories); // Do this last : so that if anything else changed we can // successfully save to the db with the old name if (title != oldTitle) { QString errMsg; if (!AlbumManager::instance()->renamePAlbum(album, title, errMsg)) { QMessageBox::critical(d->dialogParent, qApp->applicationName(), errMsg); } } // Resorting the tree View after changing metadata + DigikamApp::instance()->view()->slotSortAlbums(ApplicationSettings::instance()->getAlbumSortRole()); } } void AlbumModificationHelper::slotAlbumResetIcon(PAlbum* album) { if (!album) { return; } QString err; AlbumManager::instance()->updatePAlbumIcon(album, 0, err); } void AlbumModificationHelper::slotAlbumResetIcon() { slotAlbumResetIcon(boundAlbum(sender())); } } // namespace Digikam diff --git a/core/libs/album/engine/albumpointer.h b/core/libs/album/engine/albumpointer.h index 647f153132..8e333517ba 100644 --- a/core/libs/album/engine/albumpointer.h +++ b/core/libs/album/engine/albumpointer.h @@ -1,165 +1,167 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2004-06-15 * Description : Albums manager interface. * * Copyright (C) 2006-2020 by Gilles Caulier * Copyright (C) 2006-2011 by Marcel Wiesweg * * 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. * * ============================================================ */ #ifndef DIGIKAM_ALBUM_POINTER_H #define DIGIKAM_ALBUM_POINTER_H // Qt includes #include // Local includes #include "album.h" #include "albummanager.h" namespace Digikam { /** * You can use AlbumPointer to store a guarded pointer to Album * or one of the subclasses (use template parameter). * The pointer will be set to 0 when the album object is deleted. */ template class AlbumPointer { public: AlbumPointer() : album(nullptr) { } // cppcheck-suppress noExplicitConstructor AlbumPointer(T* const a) // krazy:exclude=explicit : album(a) { AlbumManager::instance()->addGuardedPointer(album, &album); } // cppcheck-suppress noExplicitConstructor AlbumPointer(const AlbumPointer& p) // krazy:exclude=explicit : album(p.album) { AlbumManager::instance()->addGuardedPointer(album, &album); } ~AlbumPointer() { AlbumManager::instance()->removeGuardedPointer(album, &album); } AlbumPointer& operator=(T* const a) { Album* const oldAlbum = album; album = a; AlbumManager::instance()->changeGuardedPointer(oldAlbum, album, &album); + return *this; } AlbumPointer& operator=(const AlbumPointer& p) { Album* const oldAlbum = album; album = p.album; AlbumManager::instance()->changeGuardedPointer(oldAlbum, album, &album); + return *this; } T* operator->() const { return static_cast(const_cast(album)); } T& operator*() const { return *static_cast(const_cast(album)); } operator T* () const { return static_cast(const_cast(album)); } bool operator!() const { return !album; } private: friend class AlbumManager; Album* album; }; // ------------------------------------------------------------------------------------ template class AlbumPointerList : public QList > { public: AlbumPointerList() { } explicit AlbumPointerList(const AlbumPointerList& list) : QList >(list) { } explicit AlbumPointerList(const QList& list) { operator=(list); } + // cppcheck-suppress operatorEqRetRefThis AlbumPointerList& operator=(const AlbumPointerList& list) { return QList >::operator=(list); } - // cppcheck-suppress operatorEqRetRefThis AlbumPointerList& operator=(const QList& list) { foreach (T* const t, list) { this->append(AlbumPointer(t)); } return *this; } }; } // namespace Digikam Q_DECLARE_METATYPE(Digikam::AlbumPointer<>) Q_DECLARE_METATYPE(Digikam::AlbumPointer) Q_DECLARE_METATYPE(Digikam::AlbumPointer) Q_DECLARE_METATYPE(Digikam::AlbumPointer) Q_DECLARE_METATYPE(Digikam::AlbumPointer) Q_DECLARE_METATYPE(QList) #endif // DIGIKAM_ALBUM_POINTER_H diff --git a/core/libs/album/engine/albumthumbnailloader.cpp b/core/libs/album/engine/albumthumbnailloader.cpp index 384bdcf509..fc9157c6b4 100644 --- a/core/libs/album/engine/albumthumbnailloader.cpp +++ b/core/libs/album/engine/albumthumbnailloader.cpp @@ -1,544 +1,561 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2006-04-14 * Description : Load and cache tag thumbnails * * Copyright (C) 2006-2010 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 "albumthumbnailloader.h" // C++ includes #include // Qt includes #include #include #include #include // Local includes #include "album.h" #include "albummanager.h" #include "applicationsettings.h" #include "iteminfo.h" #include "metaenginesettings.h" #include "thumbnailloadthread.h" #include "thumbnailsize.h" #include "facetagseditor.h" #include "thumbnailcreator.h" namespace Digikam { typedef QMap, QList > IdAlbumMap; typedef QMap AlbumThumbnailMap; class Q_DECL_HIDDEN AlbumThumbnailLoaderCreator { public: AlbumThumbnailLoader object; }; Q_GLOBAL_STATIC(AlbumThumbnailLoaderCreator, creator) // --------------------------------------------------------------------------------------------- class Q_DECL_HIDDEN AlbumThumbnailLoader::Private { public: explicit Private() : iconSize(ApplicationSettings::instance()->getTreeViewIconSize()), minBlendSize(20), iconTagThumbThread(nullptr), iconAlbumThumbThread(nullptr) { } int iconSize; int minBlendSize; ThumbnailLoadThread* iconTagThumbThread; ThumbnailLoadThread* iconAlbumThumbThread; IdAlbumMap idAlbumMap; AlbumThumbnailMap thumbnailMap; QCache, QPixmap> iconCache; }; bool operator<(const ThumbnailIdentifier& a, const ThumbnailIdentifier& b) { if (a.id || b.id) { return (a.id < b.id); } else { return (a.filePath < b.filePath); } } AlbumThumbnailLoader* AlbumThumbnailLoader::instance() { return &creator->object; } AlbumThumbnailLoader::AlbumThumbnailLoader() : d(new Private) { connect(this, SIGNAL(signalDispatchThumbnailInternal(int,QPixmap)), this, SLOT(slotDispatchThumbnailInternal(int,QPixmap))); connect(AlbumManager::instance(), SIGNAL(signalAlbumIconChanged(Album*)), this, SLOT(slotIconChanged(Album*))); connect(AlbumManager::instance(), SIGNAL(signalAlbumDeleted(Album*)), this, SLOT(slotIconChanged(Album*))); } AlbumThumbnailLoader::~AlbumThumbnailLoader() { delete d->iconTagThumbThread; delete d->iconAlbumThumbThread; delete d; } void AlbumThumbnailLoader::cleanUp() { delete d->iconTagThumbThread; d->iconTagThumbThread = nullptr; delete d->iconAlbumThumbThread; d->iconAlbumThumbThread = nullptr; } QPixmap AlbumThumbnailLoader::getStandardTagIcon(RelativeSize relativeSize) { return loadIcon(QLatin1String("tag"), computeIconSize(relativeSize)); } QPixmap AlbumThumbnailLoader::getStandardTagRootIcon(RelativeSize relativeSize) { return loadIcon(QLatin1String("document-open"), computeIconSize(relativeSize)); } QPixmap AlbumThumbnailLoader::getStandardTagIcon(TAlbum* const album, RelativeSize relativeSize) { if (album->isRoot()) { return getStandardTagRootIcon(relativeSize); } else { return getStandardTagIcon(relativeSize); } } QPixmap AlbumThumbnailLoader::getNewTagIcon(RelativeSize relativeSize) { return loadIcon(QLatin1String("tag-new"), computeIconSize(relativeSize)); } QPixmap AlbumThumbnailLoader::getStandardAlbumIcon(RelativeSize relativeSize) { return loadIcon(QLatin1String("folder"), computeIconSize(relativeSize)); } QPixmap AlbumThumbnailLoader::getStandardAlbumTrashIcon(RelativeSize relativeSize) { return loadIcon(QLatin1String("user-trash"), computeIconSize(relativeSize)); } QPixmap AlbumThumbnailLoader::getStandardAlbumRootIcon(RelativeSize relativeSize) { return loadIcon(QLatin1String("folder-pictures"), computeIconSize(relativeSize)); } QPixmap AlbumThumbnailLoader::getStandardAlbumIcon(PAlbum* const album, RelativeSize relativeSize) { if (album->isRoot() || album->isAlbumRoot()) { return getStandardAlbumRootIcon(relativeSize); } else if (album->isTrashAlbum()) { return getStandardAlbumTrashIcon(); } else { return getStandardAlbumIcon(relativeSize); } } int AlbumThumbnailLoader::computeIconSize(RelativeSize relativeSize) const { if (relativeSize == SmallerSize) { // when size was 32 smaller was 20. Scale. + return lround(20.0 / 32.0 * (double)d->iconSize); } return d->iconSize; } QPixmap AlbumThumbnailLoader::loadIcon(const QString& name, int size) const { QPixmap* pix = d->iconCache[qMakePair(name, size)]; if (!pix) { d->iconCache.insert(qMakePair(name, size), new QPixmap(QIcon::fromTheme(name).pixmap(size))); pix = d->iconCache[qMakePair(name, size)]; } return (*pix); // ownership of the pointer is kept by the icon cache. } bool AlbumThumbnailLoader::getTagThumbnail(TAlbum* const album, QPixmap& icon) { if (album->iconId() && (d->iconSize > d->minBlendSize)) { addUrl(album, album->iconId()); icon = QPixmap(); + return true; } else if (!album->icon().isEmpty()) { icon = loadIcon(album->icon(), d->iconSize); + return false; } icon = QPixmap(); return false; } QPixmap AlbumThumbnailLoader::getTagThumbnailDirectly(TAlbum* const album) { if (album->iconId() && (d->iconSize > d->minBlendSize)) { // icon cached? AlbumThumbnailMap::const_iterator it = d->thumbnailMap.constFind(album->globalID()); if (it != d->thumbnailMap.constEnd()) { return *it; } addUrl(album, album->iconId()); } else if (!album->icon().isEmpty()) { QPixmap pixmap = loadIcon(album->icon(), d->iconSize); return pixmap; } return getStandardTagIcon(album); } bool AlbumThumbnailLoader::getAlbumThumbnail(PAlbum* const album) { if (album->iconId() && (d->iconSize > d->minBlendSize)) { addUrl(album, album->iconId()); } else { return false; } return true; } QPixmap AlbumThumbnailLoader::getAlbumThumbnailDirectly(PAlbum* const album) { if (album->iconId() && (d->iconSize > d->minBlendSize)) { // icon cached? + AlbumThumbnailMap::const_iterator it = d->thumbnailMap.constFind(album->globalID()); if (it != d->thumbnailMap.constEnd()) { return *it; } // schedule for loading + addUrl(album, album->iconId()); } return getStandardAlbumIcon(album); } void AlbumThumbnailLoader::addUrl(Album* const album, qlonglong id) { // First check cached thumbnails. // We use a private cache which is actually a map to be sure to cache _all_ album thumbnails. // At startup, this is not relevant, as the views will add their requests in a row. // This is to speed up context menu and IE imagedescedit AlbumThumbnailMap::const_iterator ttit = d->thumbnailMap.constFind(album->globalID()); if (ttit != d->thumbnailMap.constEnd()) { // It is not necessary to return cached icon asynchronously - they could be // returned by getTagThumbnail already - but this would make the API // less elegant, it feels much better this way. emit signalDispatchThumbnailInternal(album->globalID(), *ttit); + return; } // Finding face rect to identify correct tag QRect faceRect = QRect(); if (album->type() == Album::TAG && static_cast(album)->hasProperty(TagPropertyName::person())) { QList faces = FaceTagsEditor().databaseFaces(id); foreach (const FaceTagsIface& face, faces) { if (face.tagId() == album->id()) { faceRect = face.region().toRect(); } } } // Simple way to put QRect into QMap QString faceRectStr = QString(QLatin1String("%1%2%3%4")) .arg(faceRect.x()).arg(faceRect.y()).arg(faceRect.right()).arg(faceRect.bottom()); // Check if the URL has already been added + IdAlbumMap::iterator it = d->idAlbumMap.find(QPair(id, faceRectStr)); if (it == d->idAlbumMap.end()) { // use two threads so that tag and album thumbnails are loaded // in parallel and not first album, then tag thumbnails + if (album->type() == Album::TAG) { if (!d->iconTagThumbThread) { d->iconTagThumbThread = new ThumbnailLoadThread(); d->iconTagThumbThread->setThumbnailSize(d->iconSize); d->iconTagThumbThread->setSendSurrogatePixmap(false); connect(d->iconTagThumbThread, SIGNAL(signalThumbnailLoaded(LoadingDescription,QPixmap)), SLOT(slotGotThumbnailFromIcon(LoadingDescription,QPixmap)), Qt::QueuedConnection); } if (static_cast(album)->hasProperty(TagPropertyName::person())) { d->iconTagThumbThread->find(ItemInfo::thumbnailIdentifier(id), faceRect); } else { d->iconTagThumbThread->find(ItemInfo::thumbnailIdentifier(id)); } } else { if (!d->iconAlbumThumbThread) { d->iconAlbumThumbThread = new ThumbnailLoadThread(); d->iconAlbumThumbThread->setThumbnailSize(d->iconSize); d->iconAlbumThumbThread->setSendSurrogatePixmap(false); connect(d->iconAlbumThumbThread, SIGNAL(signalThumbnailLoaded(LoadingDescription,QPixmap)), SLOT(slotGotThumbnailFromIcon(LoadingDescription,QPixmap)), Qt::QueuedConnection); } d->iconAlbumThumbThread->find(ItemInfo::thumbnailIdentifier(id)); } // insert new entry to map, add album globalID + QList &list = d->idAlbumMap[QPair(id, faceRectStr)]; list.removeAll(album->globalID()); list.append(album->globalID()); } else { // only add album global ID to list which is already inserted in map + (*it).removeAll(album->globalID()); (*it).append(album->globalID()); } } void AlbumThumbnailLoader::setThumbnailSize(int size) { if (d->iconSize == size) { return; } d->iconSize = size; // clear task list + d->idAlbumMap.clear(); + // clear cached thumbnails + d->thumbnailMap.clear(); if (d->iconAlbumThumbThread) { d->iconAlbumThumbThread->stopLoading(); d->iconAlbumThumbThread->setThumbnailSize(size); } if (d->iconTagThumbThread) { d->iconTagThumbThread->stopLoading(); d->iconTagThumbThread->setThumbnailSize(size); } emit signalReloadThumbnails(); } int AlbumThumbnailLoader::thumbnailSize() const { return d->iconSize; } void AlbumThumbnailLoader::slotGotThumbnailFromIcon(const LoadingDescription& loadingDescription, const QPixmap& thumbnail) { // We need to find all albums for which the given url has been requested, // and emit a signal for each album. QRect faceRect = QRect(); if (loadingDescription.previewParameters.extraParameter.type() == QVariant::Rect) { faceRect = loadingDescription.previewParameters.extraParameter.toRect(); } // Simple way to put QRect into QMap QString faceRectStr = QString(QLatin1String("%1%2%3%4")) .arg(faceRect.x()).arg(faceRect.y()).arg(faceRect.right()).arg(faceRect.bottom()); ThumbnailIdentifier id = loadingDescription.thumbnailIdentifier(); IdAlbumMap::iterator it = d->idAlbumMap.find(QPair(id.id, faceRectStr)); if (it != d->idAlbumMap.end()) { AlbumManager* const manager = AlbumManager::instance(); if (thumbnail.isNull()) { // Loading failed + for (QList::const_iterator vit = (*it).constBegin() ; vit != (*it).constEnd() ; ++vit) { Album* const album = manager->findAlbum(*vit); if (album) { emit signalFailed(album); } } } else { // Loading succeeded for (QList::const_iterator vit = (*it).constBegin() ; vit != (*it).constEnd() ; ++vit) { // look up with global id + Album* const album = manager->findAlbum(*vit); if (album) { d->thumbnailMap.insert(album->globalID(), thumbnail); emit signalThumbnail(album, thumbnail); } } } d->idAlbumMap.erase(it); } } void AlbumThumbnailLoader::slotDispatchThumbnailInternal(int albumID, const QPixmap& thumbnail) { // for cached thumbnails AlbumManager* const manager = AlbumManager::instance(); Album* const album = manager->findAlbum(albumID); if (album) { if (thumbnail.isNull()) { emit signalFailed(album); } else { emit signalThumbnail(album, thumbnail); } } } void AlbumThumbnailLoader::slotIconChanged(Album* album) { - if (!album || (album->type() != Album::TAG && album->type() != Album::PHYSICAL)) + if (!album || ((album->type() != Album::TAG) && (album->type() != Album::PHYSICAL))) { return; } d->thumbnailMap.remove(album->globalID()); } /* * This code is maximally inefficient QImage AlbumThumbnailLoader::getAlbumPreviewDirectly(PAlbum* const album, int size) { if (album->iconId()) { ThumbnailLoadThread* const thread = new ThumbnailLoadThread; thread->setPixmapRequested(false); thread->setThumbnailSize(size); ThumbnailImageCatcher* const catcher = new ThumbnailImageCatcher(thread); catcher->setActive(true); catcher->thread()->find(ThumbnailIdentifier(album->iconId()); catcher->enqueue(); QList images = catcher->waitForThumbnails(); catcher->setActive(false); delete thread; delete catcher; if (!images.isEmpty()) + { return images[0]; + } } return loadIcon("folder", size).toImage(); } */ } // namespace Digikam diff --git a/core/libs/album/engine/albumthumbnailloader.h b/core/libs/album/engine/albumthumbnailloader.h index 279230ae10..9593997a19 100644 --- a/core/libs/album/engine/albumthumbnailloader.h +++ b/core/libs/album/engine/albumthumbnailloader.h @@ -1,206 +1,209 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2006-04-14 * Description : Load and cache tag thumbnails * * Copyright (C) 2006-2010 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. * * ============================================================ */ #ifndef DIGIKAM_ALBUM_THUMBNAIL_LOADER_H #define DIGIKAM_ALBUM_THUMBNAIL_LOADER_H // Qt includes #include #include // Local includes #include "digikam_export.h" namespace Digikam { class Album; class TAlbum; class PAlbum; class LoadingDescription; class DIGIKAM_GUI_EXPORT AlbumThumbnailLoader : public QObject { Q_OBJECT public: /** * Album thumbnail size is configurable via the settings menu. * Some widgets use smaller icons than other widgets. * These widgets do not need to know the currently set icon size from * the setup and calculate a smaller size, but can simply request * a relatively smaller icon. * Depending on the user-chosen icon size, this size may in fact not * be smaller than the normal size. */ enum RelativeSize { NormalSize, SmallerSize }; public: void cleanUp(); /** * Change the size of the thumbnails. * If the size differs from the current size, * signalReloadThumbnails will be emitted. */ void setThumbnailSize(int size); /** * Get the current default icon size */ int thumbnailSize() const; /** * Request thumbnail for given album. * The thumbnail will be loaded * and returned asynchronously by the signals. * If no thumbnail is associated with given album, * no action will be taken, and false is returned. */ bool getAlbumThumbnail(PAlbum* const album); /** * Request thumbnail for given album, * with slightly different behavior than the above method: * If the thumbnail is already available in the cache, * it is returned. * If the icon is not yet loaded, it will be returned asynchronously * by the signals, and a default icon is returned here. * If no icon is associated, the default icon is returned. */ QPixmap getAlbumThumbnailDirectly(PAlbum* const album); /** * Behaves similar to the above method. * Tag thumbnails will be processed as appropriate. * Tags may have associated an icon that is loaded * synchronously by the system icon loader. * In this case, icon is set to this icon, and false is returned. * If no icon is associated with the tag, icon is set to null, * and false is returned. * If a custom icon is associated with the tag, * it is loaded asynchronously, icon is set to null, * and true is returned. * Tag thumbnails are always smaller than album thumbnails - * as small as an album thumbnail with SmallerSize. * They are supposed to be blended into the standard tag icon * obtained below, or used as is when SmallerSize is requested anyway. * @return Returns true if icon is loaded asynchronously. */ bool getTagThumbnail(TAlbum* const album, QPixmap& icon); /** * Loads tag thumbnail, * with slightly different behavior than the above method: * If the thumbnail is already available in the cache, * it is returned, already blended with the standard icon, if requested. * If the icon is not yet loaded, it will be returned asynchronously * by the signals (unblended), and a default icon is returned here. * If no icon is associated, the default icon is returned. */ QPixmap getTagThumbnailDirectly(TAlbum* const album); /** * Return standard tag and album icons. * The third methods check if album is the root, * and returns the standard icon or the root standard icon. */ QPixmap getStandardTagIcon(RelativeSize size = NormalSize); QPixmap getStandardTagRootIcon(RelativeSize size = NormalSize); QPixmap getStandardTagIcon(TAlbum* const album, RelativeSize size = NormalSize); QPixmap getNewTagIcon(RelativeSize size = NormalSize); QPixmap getStandardAlbumIcon(RelativeSize size = NormalSize); QPixmap getStandardAlbumTrashIcon(RelativeSize size = NormalSize); QPixmap getStandardAlbumRootIcon(RelativeSize size = NormalSize); QPixmap getStandardAlbumIcon(PAlbum* const album, RelativeSize size = NormalSize); - /** Return a preview of physical album directly without to use cache. - * Size of image can be passed as argument. + /** + * Return a preview of physical album directly without to use cache. + * Size of image can be passed as argument. */ - //QImage getAlbumPreviewDirectly(PAlbum* const album, int size); +/* + QImage getAlbumPreviewDirectly(PAlbum* const album, int size); +*/ public: static AlbumThumbnailLoader* instance(); Q_SIGNALS: /** * This signal is emitted as soon as a thumbnail has become available * for given album. * This class is a singleton, so any object connected to this * signal might not actually have requested a thumbnail for given url */ void signalThumbnail(Album* album, const QPixmap&); /** This signal is emitted if thumbnail generation for given album failed. * Same considerations as above. */ void signalFailed(Album* album); /** * Indicates that all album and tag thumbnails need to be reloaded. * This is usually because the icon size has changed in the setup. */ void signalReloadThumbnails(); /** * Internal signal to dispatch Album thumbnail change. */ void signalDispatchThumbnailInternal(int albumID, const QPixmap& thumbnail); protected Q_SLOTS: void slotGotThumbnailFromIcon(const LoadingDescription& loadingDescription, const QPixmap& pixmap); void slotIconChanged(Album* album); void slotDispatchThumbnailInternal(int albumID, const QPixmap& thumbnail); private: AlbumThumbnailLoader(); ~AlbumThumbnailLoader(); void addUrl(Album* const album, qlonglong id); QPixmap loadIcon(const QString& name, int size = 0) const; int computeIconSize(RelativeSize size) const; private: friend class AlbumThumbnailLoaderCreator; class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_ALBUM_THUMBNAIL_LOADER_H diff --git a/core/libs/album/engine/albumwatch.cpp b/core/libs/album/engine/albumwatch.cpp index 71b653356d..d829b0b3d8 100644 --- a/core/libs/album/engine/albumwatch.cpp +++ b/core/libs/album/engine/albumwatch.cpp @@ -1,315 +1,324 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2011-11-07 * Description : Directory watch interface * * Copyright (C) 2011 by Marcel Wiesweg * Copyright (C) 2015-2020 by Gilles Caulier * * 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 "albumwatch.h" // Qt includes #include #include #include #include // Local includes #include "digikam_debug.h" #include "album.h" #include "albummanager.h" #include "collectionlocation.h" #include "collectionmanager.h" #include "dbengineparameters.h" #include "applicationsettings.h" #include "scancontroller.h" #include "dio.h" namespace Digikam { class Q_DECL_HIDDEN AlbumWatch::Private { public: explicit Private() : dirWatch(nullptr) { } bool inBlackList(const QString& path) const; bool inDirWatchParametersBlackList(const QFileInfo& info, const QString& path); QList buildDirectoryModList(const QFileInfo& dbFile) const; public: QFileSystemWatcher* dirWatch; DbEngineParameters params; QStringList fileNameBlackList; QList dbPathModificationDateList; }; bool AlbumWatch::Private::inBlackList(const QString& path) const { // Filter out dirty signals triggered by changes on the database file + foreach (const QString& bannedFile, fileNameBlackList) { if (path.endsWith(bannedFile)) { return true; } } return false; } bool AlbumWatch::Private::inDirWatchParametersBlackList(const QFileInfo& info, const QString& path) { if (params.isSQLite()) { QDir dir; if (info.isDir()) { dir = QDir(path); } else { dir = info.dir(); } QFileInfo dbFile(params.SQLiteDatabaseFile()); // is the signal for the directory containing the database file? + if (dbFile.dir() == dir) { // retrieve modification dates + QList modList = buildDirectoryModList(dbFile); // check for equality + if (modList == dbPathModificationDateList) { //qCDebug(DIGIKAM_GENERAL_LOG) << "Filtering out db-file-triggered dir watch signal"; + // we can skip the signal + return true; } // set new list + dbPathModificationDateList = modList; } } return false; } QList AlbumWatch::Private::buildDirectoryModList(const QFileInfo& dbFile) const { // Retrieve modification dates QList modList; QFileInfoList fileInfoList = dbFile.dir().entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); // Build the list foreach (const QFileInfo& info, fileInfoList) { // Ignore digikam4.db and journal and other temporary files if (!fileNameBlackList.contains(info.fileName())) { modList << info.lastModified(); } } return modList; } // ------------------------------------------------------------------------------------- AlbumWatch::AlbumWatch(AlbumManager* const parent) : QObject(parent), d(new Private) { d->dirWatch = new QFileSystemWatcher(this); if (ApplicationSettings::instance()->getAlbumMonitoring()) { qCDebug(DIGIKAM_GENERAL_LOG) << "AlbumWatch use QFileSystemWatcher"; connect(d->dirWatch, SIGNAL(directoryChanged(QString)), this, SLOT(slotQFSWatcherDirty(QString))); connect(d->dirWatch, SIGNAL(fileChanged(QString)), this, SLOT(slotQFSWatcherDirty(QString))); connect(parent, SIGNAL(signalAlbumAdded(Album*)), this, SLOT(slotAlbumAdded(Album*))); connect(parent, SIGNAL(signalAlbumRenamed(Album*)), this, SLOT(slotAlbumAdded(Album*))); connect(parent, SIGNAL(signalAlbumNewPath(Album*)), this, SLOT(slotAlbumAdded(Album*))); connect(parent, SIGNAL(signalAlbumAboutToBeDeleted(Album*)), this, SLOT(slotAlbumAboutToBeDeleted(Album*))); } else { qCDebug(DIGIKAM_GENERAL_LOG) << "AlbumWatch is disabled"; } } AlbumWatch::~AlbumWatch() { delete d; } void AlbumWatch::clear() { if (d->dirWatch && !d->dirWatch->directories().isEmpty()) { d->dirWatch->removePaths(d->dirWatch->directories()); } } void AlbumWatch::removeWatchedPAlbums(const PAlbum* const album) { if (!album || d->dirWatch->directories().isEmpty()) { return; } foreach (const QString& dir, d->dirWatch->directories()) { if (dir.startsWith(album->folderPath())) { d->dirWatch->removePath(dir); } } } void AlbumWatch::setDbEngineParameters(const DbEngineParameters& params) { d->params = params; d->fileNameBlackList.clear(); // filter out notifications caused by database operations + if (params.isSQLite()) { d->fileNameBlackList << QLatin1String("thumbnails-digikam.db") << QLatin1String("thumbnails-digikam.db-journal"); d->fileNameBlackList << QLatin1String("recognition.db") << QLatin1String("recognition.db-journal"); QFileInfo dbFile(params.SQLiteDatabaseFile()); d->fileNameBlackList << dbFile.fileName() << dbFile.fileName() + QLatin1String("-journal"); // ensure this is done after setting up the black list + d->dbPathModificationDateList = d->buildDirectoryModList(dbFile); } } void AlbumWatch::slotAlbumAdded(Album* a) { - if (a->isRoot() || a->isTrashAlbum() || a->type() != Album::PHYSICAL) + if (a->isRoot() || a->isTrashAlbum() || (a->type() != Album::PHYSICAL)) { return; } PAlbum* const album = static_cast(a); CollectionLocation location = CollectionManager::instance()->locationForAlbumRootId(album->albumRootId()); if (!location.isAvailable()) { return; } QString dir = album->folderPath(); if (dir.isEmpty()) { return; } d->dirWatch->addPath(dir); } void AlbumWatch::slotAlbumAboutToBeDeleted(Album* a) { - if (a->isRoot() || a->isTrashAlbum() || a->type() != Album::PHYSICAL) + if (a->isRoot() || a->isTrashAlbum() || (a->type() != Album::PHYSICAL)) { return; } PAlbum* const album = static_cast(a); QString dir = album->folderPath(); if (dir.isEmpty()) { return; } d->dirWatch->removePath(dir); } void AlbumWatch::rescanDirectory(const QString& dir) { if (DIO::itemsUnderProcessing()) { return; } qCDebug(DIGIKAM_GENERAL_LOG) << "Detected change, triggering rescan of" << dir; ScanController::instance()->scheduleCollectionScanExternal(dir); } void AlbumWatch::slotQFSWatcherDirty(const QString& path) { if (d->inBlackList(path)) { return; } QFileInfo info(path); if (d->inDirWatchParametersBlackList(info, path)) { return; } if (info.isDir()) { rescanDirectory(path); } else { rescanDirectory(info.path()); } } } // namespace Digikam