File indexing completed on 2024-05-05 04:19:15

0001 // vim: set tabstop=4 shiftwidth=4 expandtab:
0002 /*
0003 Gwenview: an image viewer
0004 Copyright 2008 Aurélien Gâteau <agateau@kde.org>
0005 
0006 This program is free software; you can redistribute it and/or
0007 modify it under the terms of the GNU General Public License
0008 as published by the Free Software Foundation; either version 2
0009 of the License, or (at your option) any later version.
0010 
0011 This program is distributed in the hope that it will be useful,
0012 but WITHOUT ANY WARRANTY; without even the implied warranty of
0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014 GNU General Public License for more details.
0015 
0016 You should have received a copy of the GNU General Public License
0017 along with this program; if not, write to the Free Software
0018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA.
0019 
0020 */
0021 #ifndef FILTERCONTROLLER_H
0022 #define FILTERCONTROLLER_H
0023 
0024 #include <config-gwenview.h>
0025 
0026 // Qt
0027 #include <QDate>
0028 #include <QList>
0029 #include <QObject>
0030 #include <QWidget>
0031 
0032 // KF
0033 #include <KFileItem>
0034 
0035 // Local
0036 #include <lib/datewidget.h>
0037 #include <lib/semanticinfo/sorteddirmodel.h>
0038 #include <lib/timeutils.h>
0039 
0040 #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
0041 // KF
0042 #include <KRatingWidget>
0043 
0044 // Local
0045 #include <lib/semanticinfo/abstractsemanticinfobackend.h>
0046 #include <lib/semanticinfo/tagmodel.h>
0047 #endif
0048 
0049 class QAction;
0050 class QFrame;
0051 class QLineEdit;
0052 class QComboBox;
0053 class KComboBox;
0054 
0055 namespace Gwenview
0056 {
0057 class SortedDirModel;
0058 
0059 /**
0060  * An AbstractSortedDirModelFilter which filters on the file names
0061  */
0062 class NameFilter : public AbstractSortedDirModelFilter
0063 {
0064 public:
0065     enum Mode {
0066         Contains,
0067         DoesNotContain,
0068     };
0069     NameFilter(SortedDirModel *model)
0070         : AbstractSortedDirModelFilter(model)
0071         , mText()
0072         , mMode(Contains)
0073     {
0074     }
0075 
0076     bool needsSemanticInfo() const override
0077     {
0078         return false;
0079     }
0080 
0081     bool acceptsIndex(const QModelIndex &index) const override
0082     {
0083         if (mText.isEmpty()) {
0084             return true;
0085         }
0086         switch (mMode) {
0087         case Contains:
0088             return index.data().toString().contains(mText, Qt::CaseInsensitive);
0089         default: /*DoesNotContain:*/
0090             return !index.data().toString().contains(mText, Qt::CaseInsensitive);
0091         }
0092     }
0093 
0094     void setText(const QString &text)
0095     {
0096         mText = text;
0097         model()->applyFilters();
0098     }
0099 
0100     void setMode(Mode mode)
0101     {
0102         mMode = mode;
0103         model()->applyFilters();
0104     }
0105 
0106 private:
0107     QString mText;
0108     Mode mMode;
0109 };
0110 
0111 class NameFilterWidget : public QWidget
0112 {
0113     Q_OBJECT
0114 public:
0115     NameFilterWidget(SortedDirModel *);
0116     ~NameFilterWidget() override;
0117 
0118 private Q_SLOTS:
0119     void applyNameFilter();
0120 
0121 private:
0122     QPointer<NameFilter> mFilter;
0123     KComboBox *mModeComboBox;
0124     QLineEdit *mLineEdit;
0125 };
0126 
0127 /**
0128  * An AbstractSortedDirModelFilter which filters on the file dates
0129  */
0130 class DateFilter : public AbstractSortedDirModelFilter
0131 {
0132 public:
0133     enum Mode {
0134         GreaterOrEqual,
0135         Equal,
0136         LessOrEqual,
0137     };
0138     DateFilter(SortedDirModel *model)
0139         : AbstractSortedDirModelFilter(model)
0140         , mMode(GreaterOrEqual)
0141     {
0142     }
0143 
0144     bool needsSemanticInfo() const override
0145     {
0146         return false;
0147     }
0148 
0149     bool acceptsIndex(const QModelIndex &index) const override
0150     {
0151         if (!mDate.isValid()) {
0152             return true;
0153         }
0154         KFileItem fileItem = model()->itemForSourceIndex(index);
0155         QDate date = TimeUtils::dateTimeForFileItem(fileItem).date();
0156         switch (mMode) {
0157         case GreaterOrEqual:
0158             return date >= mDate;
0159         case Equal:
0160             return date == mDate;
0161         default: /* LessOrEqual */
0162             return date <= mDate;
0163         }
0164     }
0165 
0166     void setDate(const QDate &date)
0167     {
0168         mDate = date;
0169         model()->applyFilters();
0170     }
0171 
0172     void setMode(Mode mode)
0173     {
0174         mMode = mode;
0175         model()->applyFilters();
0176     }
0177 
0178 private:
0179     QDate mDate;
0180     Mode mMode;
0181 };
0182 
0183 class DateFilterWidget : public QWidget
0184 {
0185     Q_OBJECT
0186 public:
0187     DateFilterWidget(SortedDirModel *);
0188     ~DateFilterWidget() override;
0189 
0190 private Q_SLOTS:
0191     void applyDateFilter();
0192 
0193 private:
0194     QPointer<DateFilter> mFilter;
0195     KComboBox *mModeComboBox;
0196     DateWidget *mDateWidget;
0197 };
0198 
0199 #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
0200 /**
0201  * An AbstractSortedDirModelFilter which filters on file ratings
0202  */
0203 class RatingFilter : public AbstractSortedDirModelFilter
0204 {
0205 public:
0206     enum Mode {
0207         GreaterOrEqual,
0208         Equal,
0209         LessOrEqual,
0210     };
0211 
0212     RatingFilter(SortedDirModel *model)
0213         : AbstractSortedDirModelFilter(model)
0214         , mRating(0)
0215         , mMode(GreaterOrEqual)
0216     {
0217     }
0218 
0219     bool needsSemanticInfo() const override
0220     {
0221         return true;
0222     }
0223 
0224     bool acceptsIndex(const QModelIndex &index) const override
0225     {
0226         SemanticInfo info = model()->semanticInfoForSourceIndex(index);
0227         switch (mMode) {
0228         case GreaterOrEqual:
0229             return info.mRating >= mRating;
0230         case Equal:
0231             return info.mRating == mRating;
0232         default: /* LessOrEqual */
0233             return info.mRating <= mRating;
0234         }
0235     }
0236 
0237     void setRating(int value)
0238     {
0239         mRating = value;
0240         model()->applyFilters();
0241     }
0242 
0243     void setMode(Mode mode)
0244     {
0245         mMode = mode;
0246         model()->applyFilters();
0247     }
0248 
0249 private:
0250     int mRating;
0251     Mode mMode;
0252 };
0253 
0254 class RatingFilterWidget : public QWidget
0255 {
0256     Q_OBJECT
0257 public:
0258     RatingFilterWidget(SortedDirModel *);
0259     ~RatingFilterWidget() override;
0260 
0261 private Q_SLOTS:
0262     void slotRatingChanged(int value);
0263     void updateFilterMode();
0264 
0265 private:
0266     KComboBox *mModeComboBox;
0267     KRatingWidget *mRatingWidget;
0268     QPointer<RatingFilter> mFilter;
0269 };
0270 
0271 /**
0272  * An AbstractSortedDirModelFilter which filters on associated tags
0273  */
0274 class TagFilter : public AbstractSortedDirModelFilter
0275 {
0276 public:
0277     TagFilter(SortedDirModel *model)
0278         : AbstractSortedDirModelFilter(model)
0279         , mWantMatchingTag(true)
0280     {
0281     }
0282 
0283     bool needsSemanticInfo() const override
0284     {
0285         return true;
0286     }
0287 
0288     bool acceptsIndex(const QModelIndex &index) const override
0289     {
0290         if (mTag.isEmpty()) {
0291             return true;
0292         }
0293         SemanticInfo info = model()->semanticInfoForSourceIndex(index);
0294         if (mWantMatchingTag) {
0295             return info.mTags.contains(mTag);
0296         } else {
0297             return !info.mTags.contains(mTag);
0298         }
0299     }
0300 
0301     void setTag(const SemanticInfoTag &tag)
0302     {
0303         mTag = tag;
0304         model()->applyFilters();
0305     }
0306 
0307     void setWantMatchingTag(bool value)
0308     {
0309         mWantMatchingTag = value;
0310         model()->applyFilters();
0311     }
0312 
0313 private:
0314     SemanticInfoTag mTag;
0315     bool mWantMatchingTag;
0316 };
0317 
0318 class TagFilterWidget : public QWidget
0319 {
0320     Q_OBJECT
0321 public:
0322     TagFilterWidget(SortedDirModel *);
0323     ~TagFilterWidget() override;
0324 
0325 private Q_SLOTS:
0326     void updateTagSetFilter();
0327 
0328 private:
0329     KComboBox *mModeComboBox;
0330     QComboBox *mTagComboBox;
0331     QPointer<TagFilter> mFilter;
0332 };
0333 #endif
0334 
0335 /**
0336  * This class manages the filter widgets in the filter frame and assign the
0337  * corresponding filters to the SortedDirModel
0338  */
0339 class FilterController : public QObject
0340 {
0341     Q_OBJECT
0342 public:
0343     FilterController(QFrame *filterFrame, SortedDirModel *model);
0344 
0345     QList<QAction *> actionList() const;
0346 
0347 private Q_SLOTS:
0348     void addFilterByName();
0349     void addFilterByDate();
0350 #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
0351     void addFilterByRating();
0352     void addFilterByTag();
0353 #endif
0354     void slotFilterWidgetClosed();
0355 
0356 private:
0357     void addAction(const QString &text, const char *slot, const QKeySequence &shortcut);
0358     void addFilter(QWidget *widget);
0359 
0360     FilterController *q;
0361     QFrame *mFrame;
0362     SortedDirModel *mDirModel;
0363     QList<QAction *> mActionList;
0364 
0365     int mFilterWidgetCount; /**< How many filter widgets are in mFrame */
0366 };
0367 
0368 } // namespace
0369 
0370 #endif /* FILTERCONTROLLER_H */