File indexing completed on 2024-04-28 15:39:57
0001 // SPDX-FileCopyrightText: 2003-2014 Jesper K. Pedersen <jesper.pedersen@kdab.com> 0002 // SPDX-FileCopyrightText: 2006-2010 Tuomas Suutari <tuomas@nepnep.net> 0003 // SPDX-FileCopyrightText: 2007 Dirk Mueller <mueller@kde.org> 0004 // SPDX-FileCopyrightText: 2007-2008 Jan Kundrát <jkt@flaska.net> 0005 // SPDX-FileCopyrightText: 2008-2009 Henner Zeller <h.zeller@acm.org> 0006 // SPDX-FileCopyrightText: 2012-2015 Miika Turkia <miika.turkia@gmail.com> 0007 // SPDX-FileCopyrightText: 2012-2023 Johannes Zarl-Zierl <johannes@zarl-zierl.at> 0008 // SPDX-FileCopyrightText: 2015-2022 Tobias Leupold <tl@stonemx.de> 0009 // SPDX-FileCopyrightText: 2018 Robert Krawitz <rlk@alum.mit.edu> 0010 // 0011 // SPDX-License-Identifier: GPL-2.0-or-later 0012 0013 #ifndef IMAGEDB_H 0014 #define IMAGEDB_H 0015 0016 #include "Category.h" 0017 #include "ImageInfoList.h" 0018 #include "ImageInfoPtr.h" 0019 #include "MediaCount.h" 0020 0021 #include <DB/CategoryCollection.h> 0022 #include <DB/MD5Map.h> 0023 #include <DB/MemberMap.h> 0024 #include <DB/XML/FileReader.h> 0025 #include <DB/search/ImageSearchInfo.h> 0026 #include <kpabase/FileNameList.h> 0027 0028 #include <QObject> 0029 #include <QPointer> 0030 #include <memory> 0031 0032 class QProgressBar; 0033 0034 namespace DB 0035 { 0036 class FileWriter; 0037 } 0038 namespace DB 0039 { 0040 Q_NAMESPACE 0041 0042 class CategoryCollection; 0043 class Category; 0044 class MD5Map; 0045 class MemberMap; 0046 class FileName; 0047 class TagInfo; 0048 class UIDelegate; 0049 0050 /** 0051 * @brief The SearchOption enum influences the way a search is conducted. 0052 */ 0053 enum class SearchOption { 0054 NoOption = 0b0000, ///< No special query options 0055 RequireOnDisk = 0b0001, ///< Check for each file, if it is currently available on disk and discard any image that is not available. 0056 AllowRangeMatch = 0b0010 ///< In addition to the standard date match (returning images within the given range), allow matching on image dates that overlap with the search range ("range match"). 0057 }; 0058 Q_DECLARE_FLAGS(SearchOptions, SearchOption); 0059 Q_FLAG_NS(SearchOption); 0060 0061 /** 0062 * @brief The ClassificationMode enum can be used to short-circuit classification in the classify() method. 0063 * This allows you to only check whether a given category has more than one sub-category (including the "No other" category). 0064 * In other words, you can use a partial count when all you want to know is whether further search refinement is possible 0065 * in a category. 0066 * @see ImageDB::classify() 0067 * @see Browser::OverviewPage::updateImageCount() 0068 */ 0069 enum class ClassificationMode { 0070 FullCount ///< @brief run a full classification. This is normally what you want. 0071 , 0072 PartialCount ///< @brief Count until at least 2 categories are found 0073 }; 0074 0075 class ImageDB : public QObject 0076 { 0077 Q_OBJECT 0078 0079 public: 0080 static ImageDB *instance(); 0081 static void setupXMLDB(const QString &configFile, UIDelegate &delegate); 0082 static void deleteInstance(); 0083 static QString NONE(); 0084 0085 UIDelegate &uiDelegate() const; 0086 DB::FileNameList currentScope(bool requireOnDisk) const; 0087 0088 DB::FileName findFirstItemInRange(const FileNameList &files, const ImageDate &range, bool includeRanges) const; 0089 0090 bool untaggedCategoryFeatureConfigured() const; 0091 0092 int totalCount() const; 0093 DB::ImageInfoList search(const ImageSearchInfo &, bool requireOnDisk) const; 0094 DB::ImageInfoList search(const DB::ImageSearchInfo &searchInfo, DB::SearchOptions options = DB::SearchOption::NoOption) const; 0095 0096 /** 0097 * @brief Rename category in media items stored in database. 0098 */ 0099 void renameCategory(const QString &oldName, const QString newName); 0100 0101 /** 0102 * @brief classify computes a histogram of tags within a category. 0103 * I.e. for each sub-category within a given category it counts all images matching the current context, and 0104 * computes the date range for those images. 0105 * 0106 * @param info ImageSearchInfo describing the current search context 0107 * @param category the category for which images should be classified 0108 * @param typemask images/videos/both 0109 * @param mode whether accurate counts are required or not 0110 * @return a mapping of sub-category (tags/tag-groups) to the number of images (and the associated date range) 0111 */ 0112 QMap<QString, CountWithRange> classify(const ImageSearchInfo &info, const QString &category, MediaType typemask, ClassificationMode mode = ClassificationMode::FullCount); 0113 FileNameList files(MediaType type = anyMediaType) const; 0114 ImageInfoList images() const; 0115 /** 0116 * @brief addImages to the database. 0117 * The parameter \p doUpdate decides whether all bookkeeping should be done right away 0118 * (\c true; the "normal" use-case), or if it should be deferred until later(\c false). 0119 * If doUpdate is deferred, either commitDelayedImages() or clearDelayedImages() needs to be called afterwards. 0120 * @param images 0121 * @param doUpdate 0122 */ 0123 void addImages(const ImageInfoList &images, bool doUpdate = true); 0124 void commitDelayedImages(); 0125 void clearDelayedImages(); 0126 /** @short Update file name stored in the DB */ 0127 void renameImage(const ImageInfoPtr info, const DB::FileName &newName); 0128 0129 void addToBlockList(const DB::FileNameList &list); 0130 bool isBlocking(const DB::FileName &fileName); 0131 void deleteList(const DB::FileNameList &list); 0132 ImageInfoPtr info(const DB::FileName &fileName) const; 0133 MemberMap &memberMap(); 0134 void save(const QString &fileName, bool isAutoSave); 0135 MD5Map *md5Map(); 0136 void sortAndMergeBackIn(const DB::FileNameList &fileNameList); 0137 0138 CategoryCollection *categoryCollection(); 0139 const CategoryCollection *categoryCollection() const; 0140 0141 /** 0142 * Reorder the items in the database by placing all the items given in 0143 * selection directly before or after the given item. 0144 * If the parameter "after" determines where to place it. 0145 */ 0146 void reorder(const DB::FileName &item, const DB::FileNameList &selection, bool after); 0147 0148 /** @short Create a stack of images/videos/whatever 0149 * 0150 * If the specified images already belong to different stacks, then no 0151 * change happens and the function returns false. 0152 * 0153 * If some of them are in one stack and others aren't stacked at all, then 0154 * the unstacked will be added to the existing stack and we return true. 0155 * 0156 * If none of them are stacked, then a new stack is created and we return 0157 * true. 0158 * 0159 * All images which previously weren't in the stack are added in order they 0160 * are present in the provided list and after all items that are already in 0161 * the stack. The order of images which were already in the stack is not 0162 * changed. 0163 * */ 0164 bool stack(const DB::FileNameList &items); 0165 0166 /** @short Remove all images from whichever stacks they might be in 0167 * 0168 * We might destroy some stacks in the process if they become empty or just 0169 * containing one image. 0170 * 0171 * This function doesn't touch the order of images at all. 0172 * */ 0173 void unstack(const DB::FileNameList &items); 0174 0175 /** @short Return a list of images which are in the same stack as the one specified. 0176 * 0177 * Returns an empty list when the image is not stacked. 0178 * 0179 * They are returned sorted according to their stackOrder. 0180 * */ 0181 DB::FileNameList getStackFor(const DB::FileName &referenceImage) const; 0182 0183 void copyData(const DB::FileName &from, const DB::FileName &to); 0184 0185 Exif::Database *exifDB() const; 0186 0187 /** 0188 * @brief untaggedTag 0189 * @return the untaggedTag, or \c nullptr if the feature is not configured 0190 */ 0191 const DB::TagInfo *untaggedTag() const; 0192 0193 static int fileVersion(); 0194 static DB::ImageInfoPtr createImageInfo(const DB::FileName &fileName, DB::ReaderPtr, ImageDB *db = nullptr, const QMap<QString, QString> *newToOldCategory = nullptr); 0195 static void possibleLoadCompressedCategories(DB::ReaderPtr reader, DB::ImageInfoPtr info, ImageDB *db, const QMap<QString, QString> *newToOldCategory = nullptr); 0196 public Q_SLOTS: 0197 void setDateRange(const ImageDate &, bool includeFuzzyCounts); 0198 void clearDateRange(); 0199 virtual MediaCount count(const ImageSearchInfo &info); 0200 virtual void slotReread(const DB::FileNameList &list, DB::ExifMode mode); 0201 void setCurrentScope(const DB::ImageSearchInfo &info); 0202 0203 Q_SIGNALS: 0204 void totalChanged(int); 0205 void dirty(); 0206 void imagesDeleted(const DB::FileNameList &); 0207 0208 protected: 0209 ImageDB(const QString &configFile, UIDelegate &delegate); 0210 0211 bool rangeInclude(DB::ImageInfoPtr info) const; 0212 0213 DB::ImageInfoList takeImagesFromSelection(const DB::FileNameList &selection); 0214 void insertList(const DB::FileName &fileName, const DB::ImageInfoList &list, bool after); 0215 static void readOptions(DB::ImageInfoPtr info, DB::ReaderPtr reader, const QMap<QString, QString> *newToOldCategory = nullptr); 0216 0217 ImageInfoList m_clipboard; 0218 UIDelegate &m_UI; 0219 std::unique_ptr<Exif::Database> m_exifDB; 0220 ImageDate m_selectionRange; 0221 bool m_includeFuzzyCounts; 0222 0223 protected Q_SLOTS: 0224 void renameItem(DB::Category *category, const QString &oldName, const QString &newName); 0225 void deleteItem(DB::Category *category, const QString &value); 0226 void lockDB(bool lock, bool exclude); 0227 void markDirty(); 0228 /** 0229 * @brief setUntaggedTag sets the untaggedTag for the database and also updates the corresponding settings value. 0230 * If tag is null, the untaggedTag is cleared. 0231 * @param tag 0232 * @see Settings::SettingsData::untaggedTag() 0233 * @see Settings::SettingsData::untaggedCategory() 0234 */ 0235 void setUntaggedTag(DB::TagInfo *tag); 0236 void setUntaggedTag(const QString &category, const QString &tag); 0237 0238 private: 0239 friend class DB::FileReader; 0240 friend class DB::FileWriter; 0241 0242 static void connectSlots(); 0243 static ImageDB *s_instance; 0244 DB::ImageSearchInfo m_currentScope; 0245 QPointer<DB::TagInfo> m_untaggedTag; 0246 0247 void forceUpdate(const DB::ImageInfoList &images); 0248 0249 QString m_fileName; 0250 DB::ImageInfoList m_images; 0251 QSet<DB::FileName> m_blockList; 0252 DB::ImageInfoList m_missingTimes; 0253 DB::CategoryCollection m_categoryCollection; 0254 DB::MemberMap m_members; 0255 DB::MD5Map m_md5map; 0256 // QMap<QString, QString> m_settings; 0257 0258 DB::StackID m_nextStackId; 0259 typedef QMap<DB::StackID, DB::FileNameList> StackMap; 0260 mutable StackMap m_stackMap; 0261 DB::ImageInfoList m_delayedUpdate; 0262 mutable QHash<const QString, DB::ImageInfoPtr> m_imageCache; 0263 mutable QHash<const QString, DB::ImageInfoPtr> m_delayedCache; 0264 0265 // used for checking if any images are without image attribute from the database. 0266 static bool s_anyImageWithEmptySize; 0267 }; 0268 } 0269 #endif /* IMAGEDB_H */ 0270 0271 // vi:expandtab:tabstop=4 shiftwidth=4: