1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2009-03-05
7  * Description : Qt item model for database entries
8  *
9  * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
10  * Copyright (C)      2011 by Gilles Caulier <caulier dot gilles at gmail dot com>
11  * Copyright (C)      2010 by Andi Clemens <andi dot clemens at gmail dot com>
12  * Copyright (C)      2011 by Michael G. Hansen <mike at mghansen dot de>
13  * Copyright (C)      2014 by Mohamed_Anwer <m_dot_anwer at gmx dot com>
14  *
15  * This program is free software; you can redistribute it
16  * and/or modify it under the terms of the GNU General
17  * Public License as published by the Free Software Foundation;
18  * either version 2, or (at your option)
19  * any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * ============================================================ */
27 
28 #ifndef DIGIKAM_ITEM_FILTER_MODEL_H
29 #define DIGIKAM_ITEM_FILTER_MODEL_H
30 
31 // Local includes
32 
33 #include "dcategorizedsortfilterproxymodel.h"
34 #include "textfilter.h"
35 #include "itemfiltersettings.h"
36 #include "itemmodel.h"
37 #include "itemsortsettings.h"
38 #include "digikam_export.h"
39 
40 namespace Digikam
41 {
42 
43 class ImageChangeset;
44 class ItemFilterModel;
45 class ImageTagChangeset;
46 class FaceTagsIface;
47 
48 class DIGIKAM_DATABASE_EXPORT ItemFilterModelPrepareHook
49 {
50 public:
51 
~ItemFilterModelPrepareHook()52     virtual ~ItemFilterModelPrepareHook() {};
53     virtual void prepare(const QVector<ItemInfo>& infos) = 0;
54 
55 private:
56 
57     Q_DISABLE_COPY(ItemFilterModelPrepareHook)
58 };
59 
60 // -----------------------------------------------------------------------------------------------
61 
62 class DIGIKAM_DATABASE_EXPORT ImageSortFilterModel : public DCategorizedSortFilterProxyModel
63 {
64     Q_OBJECT
65 
66 public:
67 
68     explicit ImageSortFilterModel(QObject* const parent = nullptr);
69 
70     void       setSourceItemModel(ItemModel* const model);
71     ItemModel* sourceItemModel()                                                            const;
72 
73     void                  setSourceFilterModel(ImageSortFilterModel* const model);
74     ImageSortFilterModel* sourceFilterModel()                                               const;
75 
76     QModelIndex mapToSourceItemModel(const QModelIndex& index)                              const;
77     QModelIndex mapFromSourceItemModel(const QModelIndex& imagemodel_index)                 const;
78     QModelIndex mapFromDirectSourceToSourceItemModel(const QModelIndex& sourceModel_index)  const;
79 
80     /**
81      * Convenience methods mapped to ItemModel.
82      * Mentioned indexes returned come from the source image model.
83      */
84     QList<QModelIndex> mapListToSource(const QList<QModelIndex>& indexes)                   const;
85     QList<QModelIndex> mapListFromSource(const QList<QModelIndex>& sourceIndexes)           const;
86 
87     ItemInfo         imageInfo(const QModelIndex& index)                                    const;
88     qlonglong        imageId(const QModelIndex& index)                                      const;
89     QList<ItemInfo>  imageInfos(const QList<QModelIndex>& indexes)                          const;
90     QList<qlonglong> imageIds(const QList<QModelIndex>& indexes)                            const;
91 
92     QModelIndex indexForPath(const QString& filePath)                                       const;
93     QModelIndex indexForItemInfo(const ItemInfo& info)                                      const;
94     QModelIndex indexForImageId(qlonglong id)                                               const;
95 
96     /**
97      * Returns a list of all image infos, sorted according to this model.
98      * If you do not need a sorted list, use ItemModel's imageInfos() method.
99      */
100     QList<ItemInfo> imageInfosSorted()                                                      const;
101 
102     /**
103      * Returns this, any chained ItemFilterModel, or 0.
104      */
105     virtual ItemFilterModel* imageFilterModel()                                             const;
106 
107 protected:
108 
109     /**
110      * Reimplement if needed. Called only when model shall be set as (direct) sourceModel.
111      */
112     virtual void setDirectSourceItemModel(ItemModel* const model);
113 
114     /// NOTE: made protected
115     void setSourceModel(QAbstractItemModel* const model)                                   override;
116 
117 protected:
118 
119     ImageSortFilterModel* m_chainedModel;
120 };
121 
122 // -----------------------------------------------------------------------------------------------
123 
124 class DIGIKAM_DATABASE_EXPORT ItemFilterModel : public ImageSortFilterModel
125 {
126     Q_OBJECT
127 
128 public:
129 
130     enum ItemFilterModelRoles
131     {
132         /// Returns the current categorization mode
133         CategorizationModeRole      = ItemModel::FilterModelRoles + 1,
134 
135         /// Returns the current sort order
136         SortOrderRole               = ItemModel::FilterModelRoles + 2,
137 
138         /// Returns the number of items in the index category
139         //CategoryCountRole         = ItemModel::FilterModelRoles + 3,
140 
141         /// Returns the id of the PAlbum of the index which is used for category
142         CategoryAlbumIdRole         = ItemModel::FilterModelRoles + 3,
143 
144         /// Returns the format of the index which is used for category
145         CategoryFormatRole          = ItemModel::FilterModelRoles + 4,
146 
147         /// Returns the date of the index which is used for category
148         CategoryDateRole            = ItemModel::FilterModelRoles + 5,
149 
150         /// Returns the suggested name for the face in this index
151         CategoryFaceRole            = ItemModel::FilterModelRoles + 6,
152 
153         /// Returns true if the given image is a group leader, and the group is opened
154         GroupIsOpenRole             = ItemModel::FilterModelRoles + 7,
155         ItemFilterModelPointerRole  = ItemModel::FilterModelRoles + 50
156     };
157 
158 public:
159 
160     explicit ItemFilterModel(QObject* const parent = nullptr);
161     ~ItemFilterModel() override;
162 
163     /**
164      * Add a hook to get added images for preparation tasks before they are added in the model
165      */
166     void addPrepareHook(ItemFilterModelPrepareHook* const hook);
167     void removePrepareHook(ItemFilterModelPrepareHook* const hook);
168 
169     /**
170      * Returns a set of DatabaseFields suggested to set as watch flags on the source ItemModel.
171      * The contained flags will be those that this model can sort or filter by.
172      */
173     DatabaseFields::Set suggestedWatchFlags()                                               const;
174 
175     ItemFilterSettings        imageFilterSettings()                                         const;
176     VersionItemFilterSettings versionItemFilterSettings()                                   const;
177     GroupItemFilterSettings   groupItemFilterSettings()                                     const;
178     ItemSortSettings          imageSortSettings()                                           const;
179 
180     /**
181      * group is identified by the id of its group leader
182      */
183     bool isGroupOpen(qlonglong group)                                                       const;
184     bool isAllGroupsOpen()                                                                  const;
185 
186     /**
187      * Enables sending imageInfosAdded and imageInfosAboutToBeRemoved
188      */
189     void setSendItemInfoSignals(bool sendSignals);
190 
191     QVariant data(const QModelIndex& index, int role = Qt::DisplayRole)             const override;
192     ItemFilterModel* imageFilterModel()                                             const override;
193 
194 public Q_SLOTS:
195 
196     /**
197      * Changes the current version image filter settings and refilters.
198      */
199     void setVersionItemFilterSettings(const VersionItemFilterSettings& settings);
200 
201     /**
202      * Changes the current version image filter settings and refilters.
203      */
204     void setGroupItemFilterSettings(const GroupItemFilterSettings& settings);
205 
206     /**
207      * Adjust the current ItemFilterSettings.
208      * Equivalent to retrieving the current filter settings, adjusting the parameter
209      * and calling setItemFilterSettings.
210      * Provided for convenience.
211      * It is encouraged to use setItemFilterSettings if you change more than one
212      * parameter at a time.
213      */
214     void setDayFilter(const QList<QDateTime>& days);
215     void setTagFilter(const QList<int>& includedTags, const QList<int>& excludedTags,
216                       ItemFilterSettings::MatchingCondition matchingCond, bool showUnTagged,
217                       const QList<int>& clTagIds, const QList<int>& plTagIds);
218     void setRatingFilter(int rating, ItemFilterSettings::RatingCondition ratingCond, bool isUnratedExcluded);
219     void setMimeTypeFilter(int mimeTypeFilter);
220     void setGeolocationFilter(const ItemFilterSettings::GeolocationCondition& condition);
221     void setTextFilter(const SearchTextFilterSettings& settings);
222 
223     void setCategorizationMode(ItemSortSettings::CategorizationMode mode);
224     void setCategorizationSortOrder(ItemSortSettings::SortOrder order);
225     void setSortRole(ItemSortSettings::SortRole role);
226     void setSortOrder(ItemSortSettings::SortOrder order);
227     void setStringTypeNatural(bool natural);
228     void setUrlWhitelist(const QList<QUrl>& urlList, const QString& id);
229     void setIdWhitelist(const QList<qlonglong>& idList, const QString& id);
230 
231     void setVersionManagerSettings(const VersionManagerSettings& settings);
232     void setExceptionList(const QList<qlonglong>& idlist, const QString& id);
233 
234     void setGroupOpen(qlonglong group, bool open);
235     void toggleGroupOpen(qlonglong group);
236     void setAllGroupsOpen(bool open);
237 
238     /**
239      * Changes the current image filter settings and refilters.
240      */
241     virtual void setItemFilterSettings(const ItemFilterSettings& settings);
242 
243     /**
244      * Changes the current image sort settings and resorts.
245      */
246     virtual void setItemSortSettings(const ItemSortSettings& settings);
247 
248 Q_SIGNALS:
249 
250     /**
251      * Signals that the set filter matches at least one index
252      */
253     void filterMatches(bool matches);
254 
255     /**
256      * Signals that the set text filter matches at least one entry.
257      * If no text filter is set, this signal is emitted
258      * with 'false' when filterMatches() is emitted.
259      */
260     void filterMatchesForText(bool matchesByText);
261 
262     /**
263      * Emitted when the filter settings have been changed
264      * (the model may not yet have been updated)
265      */
266     void filterSettingsChanged(const ItemFilterSettings& settings);
267 
268     /**
269      * These signals need to be explicitly enabled with setSendItemInfoSignals()
270      */
271     void imageInfosAdded(const QList<ItemInfo>& infos);
272     void imageInfosAboutToBeRemoved(const QList<ItemInfo>& infos);
273 
274 public:
275 
276     /// NOTE: Declared as public because of use in sub-classes.
277     class ItemFilterModelPrivate;
278 
279 protected:
280 
281     ItemFilterModelPrivate* const d_ptr;
282 
283 protected:
284 
285     ItemFilterModel(ItemFilterModelPrivate& dd, QObject* const parent);
286 
287     void setDirectSourceItemModel(ItemModel* const model)                                 override;
288 
289     bool filterAcceptsRow(int source_row, const QModelIndex& source_parent)         const override;
290 
291     int  compareCategories(const QModelIndex& left, const QModelIndex& right)       const override;
292     bool subSortLessThan(const QModelIndex& left, const QModelIndex& right)         const override;
293 /*
294     virtual int  categoryCount(const ItemInfo& info)                                        const;
295 */
296     /**
297      * Reimplement to customize category sorting,
298      * Return negative if category of left < category right,
299      * Return 0 if left and right are in the same category, else return positive.
300      */
301     virtual int compareInfosCategories(const ItemInfo& left, const ItemInfo& right)          const;
302 
303     /**
304      * In order to be able to Categorize by Faces, it's necessary to pass in the
305      * face as well. One image may have multiple Faces in it, hence just the ItemInfo
306      * isn't sufficient.
307      */
308     virtual int compareInfosCategories(const ItemInfo& left, const ItemInfo& right,
309                                        const FaceTagsIface& leftFace,
310                                        const FaceTagsIface& rightFace)                       const;
311 
312     /**
313      * Reimplement to customize sorting. Do not take categories into account here.
314      */
315     virtual bool infosLessThan(const ItemInfo& left, const ItemInfo& right)                  const;
316 
317     /**
318      * Returns a unique identifier for the category if info. The string need not be for user display.
319      */
320     virtual QString categoryIdentifier(const ItemInfo& info, const FaceTagsIface& face)      const;
321 
322 protected Q_SLOTS:
323 
324     void slotModelReset();
325     void slotUpdateFilter();
326 
327     void slotImageTagChange(const ImageTagChangeset& changeset);
328     void slotImageChange(const ImageChangeset& changeset);
329 
330     void slotRowsInserted(const QModelIndex& parent, int start, int end);
331     void slotRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end);
332 
333 private:
334 
335     Q_DECLARE_PRIVATE(ItemFilterModel)
336 };
337 
338 // -----------------------------------------------------------------------------------------------------
339 
340 class DIGIKAM_DATABASE_EXPORT NoDuplicatesItemFilterModel : public ImageSortFilterModel
341 {
342     Q_OBJECT
343 
344 public:
345 
346     explicit NoDuplicatesItemFilterModel(QObject* const parent = nullptr);
347 
348 protected:
349 
350     bool filterAcceptsRow(int source_row, const QModelIndex& source_parent)         const override;
351 };
352 
353 } // namespace Digikam
354 
355 Q_DECLARE_METATYPE(Digikam::ItemFilterModel*)
356 
357 #endif // DIGIKAM_ITEM_FILTER_MODEL_H
358