1 // SPDX-FileCopyrightText: 2003-2020 The KPhotoAlbum Development Team
2 // SPDX-FileCopyrightText: 2021 Johannes Zarl-Zierl <johannes@zarl-zierl.at>
3 //
4 // SPDX-License-Identifier: GPL-2.0-or-later
5 
6 #ifndef IMAGEDB_H
7 #define IMAGEDB_H
8 
9 #include "Category.h"
10 #include "ImageDateCollection.h"
11 #include "ImageInfoList.h"
12 #include "ImageInfoPtr.h"
13 #include "ImageSearchInfo.h"
14 #include "MediaCount.h"
15 
16 #include <kpabase/FileNameList.h>
17 
18 #include <QObject>
19 #include <memory>
20 
21 class QProgressBar;
22 
23 namespace DB
24 {
25 
26 class CategoryCollection;
27 class Category;
28 class MD5Map;
29 class MemberMap;
30 class FileName;
31 class UIDelegate;
32 
33 /**
34  * @brief The ClassificationMode enum can be used to short-circuit classification in the classify() method.
35  * This allows you to only check whether a given category has more than one sub-category (including the "No other" category).
36  * In other words, you can use a partial count when all you want to know is whether further search refinement is possible
37  * in a category.
38  * @see ImageDB::classify()
39  * @see Browser::OverviewPage::updateImageCount()
40  */
41 enum class ClassificationMode {
42     FullCount ///< @brief run a full classification. This is normally what you want.
43     ,
44     PartialCount ///< @brief Count until at least 2 categories are found
45 };
46 
47 class ImageDB : public QObject
48 {
49     Q_OBJECT
50 
51 public:
52     static ImageDB *instance();
53     static void setupXMLDB(const QString &configFile, UIDelegate &delegate);
54     static void deleteInstance();
55     static QString NONE();
56 
57     DB::FileNameSet imagesWithMD5Changed();
58     UIDelegate &uiDelegate() const;
59     DB::FileNameList currentScope(bool requireOnDisk) const;
60 
61     virtual DB::FileName findFirstItemInRange(
62         const FileNameList &files,
63         const ImageDate &range,
64         bool includeRanges) const;
65 
66     bool untaggedCategoryFeatureConfigured() const;
67 
68     virtual uint totalCount() const = 0;
69     virtual DB::ImageInfoList search(const ImageSearchInfo &, bool requireOnDisk = false) const = 0;
70 
71     virtual void renameCategory(const QString &oldName, const QString newName) = 0;
72 
73     /**
74      * @brief classify computes a histogram of tags within a category.
75      * I.e. for each sub-category within a given category it counts all images matching the current context, and
76      * computes the date range for those images.
77      *
78      * @param info ImageSearchInfo describing the current search context
79      * @param category the category for which images should be classified
80      * @param typemask images/videos/both
81      * @param mode whether accurate counts are required or not
82      * @return a mapping of sub-category (tags/tag-groups) to the number of images (and the associated date range)
83      */
84     virtual QMap<QString, CountWithRange> classify(const ImageSearchInfo &info, const QString &category, MediaType typemask, ClassificationMode mode = ClassificationMode::FullCount) = 0;
85     virtual FileNameList files(MediaType type = anyMediaType) const = 0;
86     virtual ImageInfoList images() const = 0;
87     /**
88      * @brief addImages to the database.
89      * The parameter \p doUpdate decides whether all bookkeeping should be done right away
90      * (\c true; the "normal" use-case), or if it should be deferred until later(\c false).
91      * If doUpdate is deferred, either commitDelayedImages() or clearDelayedImages() needs to be called afterwards.
92      * @param files
93      * @param doUpdate
94      */
95     virtual void addImages(const ImageInfoList &files, bool doUpdate = true) = 0;
96     virtual void commitDelayedImages() = 0;
97     virtual void clearDelayedImages() = 0;
98     /** @short Update file name stored in the DB */
99     virtual void renameImage(const ImageInfoPtr info, const DB::FileName &newName) = 0;
100 
101     virtual void addToBlockList(const DB::FileNameList &list) = 0;
102     virtual bool isBlocking(const DB::FileName &fileName) = 0;
103     virtual void deleteList(const DB::FileNameList &list) = 0;
104     virtual ImageInfoPtr info(const DB::FileName &fileName) const = 0;
105     virtual MemberMap &memberMap() = 0;
106     virtual void save(const QString &fileName, bool isAutoSave) = 0;
107     virtual MD5Map *md5Map() = 0;
108     virtual void sortAndMergeBackIn(const DB::FileNameList &list) = 0;
109 
110     virtual CategoryCollection *categoryCollection() = 0;
111     virtual const CategoryCollection *categoryCollection() const = 0;
112     virtual QExplicitlySharedDataPointer<ImageDateCollection> rangeCollection() = 0;
113 
114     /**
115      * Reorder the items in the database by placing all the items given in
116      * cutList directly before or after the given item.
117      * If the parameter "after" determines where to place it.
118      */
119     virtual void reorder(const DB::FileName &item, const DB::FileNameList &cutList, bool after) = 0;
120 
121     /** @short Create a stack of images/videos/whatever
122      *
123      * If the specified images already belong to different stacks, then no
124      * change happens and the function returns false.
125      *
126      * If some of them are in one stack and others aren't stacked at all, then
127      * the unstacked will be added to the existing stack and we return true.
128      *
129      * If none of them are stacked, then a new stack is created and we return
130      * true.
131      *
132      * All images which previously weren't in the stack are added in order they
133      * are present in the provided list and after all items that are already in
134      * the stack. The order of images which were already in the stack is not
135      * changed.
136      * */
137     virtual bool stack(const DB::FileNameList &items) = 0;
138 
139     /** @short Remove all images from whichever stacks they might be in
140      *
141      * We might destroy some stacks in the process if they become empty or just
142      * containing one image.
143      *
144      * This function doesn't touch the order of images at all.
145      * */
146     virtual void unstack(const DB::FileNameList &files) = 0;
147 
148     /** @short Return a list of images which are in the same stack as the one specified.
149      *
150      * Returns an empty list when the image is not stacked.
151      *
152      * They are returned sorted according to their stackOrder.
153      * */
154     virtual DB::FileNameList getStackFor(const DB::FileName &referenceId) const = 0;
155 
156     virtual void copyData(const DB::FileName &from, const DB::FileName &to) = 0;
157 
158     Exif::Database *exifDB() const;
159 
160 public slots:
161     void setDateRange(const ImageDate &, bool includeFuzzyCounts);
162     void clearDateRange();
163     virtual void slotRescan();
164     void slotRecalcCheckSums(const DB::FileNameList &selection);
165     virtual MediaCount count(const ImageSearchInfo &info);
166     virtual void slotReread(const DB::FileNameList &list, DB::ExifMode mode);
167     void setCurrentScope(const DB::ImageSearchInfo &info);
168 
169 signals:
170     void totalChanged(uint);
171     void dirty();
172     void imagesDeleted(const DB::FileNameList &);
173 
174 protected:
175     ImageDB(UIDelegate &delegate);
176     ImageDate m_selectionRange;
177     bool m_includeFuzzyCounts;
178     ImageInfoList m_clipboard;
179     UIDelegate &m_UI;
180     std::unique_ptr<Exif::Database> m_exifDB;
181 
182 protected slots:
183     virtual void lockDB(bool lock, bool exclude) = 0;
184     void markDirty();
185 
186 private:
187     static void connectSlots();
188     static ImageDB *s_instance;
189     DB::ImageSearchInfo m_currentScope;
190 };
191 }
192 #endif /* IMAGEDB_H */
193 
194 // vi:expandtab:tabstop=4 shiftwidth=4:
195