sorteddirmodel.cpp 8.84 KB
Newer Older
1
2
/*
Gwenview: an image viewer
Aurélien Gâteau's avatar
Aurélien Gâteau committed
3
Copyright 2007 Aurélien Gâteau <agateau@kde.org>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

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
of the License, 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.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

*/
David Edmundson's avatar
David Edmundson committed
20
#include "sorteddirmodel.h"
Aurélien Gâteau's avatar
Aurélien Gâteau committed
21
22

// Qt
David Edmundson's avatar
David Edmundson committed
23
#include <QTimer>
Lukáš Tinkl's avatar
Lukáš Tinkl committed
24
#include <QUrl>
25

26
// KF
Aurélien Gâteau's avatar
Aurélien Gâteau committed
27
#include <KDirLister>
28
29
30
#ifdef GWENVIEW_SEMANTICINFO_BACKEND_NONE
#include <KDirModel>
#endif
31
// Local
32
#include "gwenview_lib_debug.h"
33
#include <lib/archiveutils.h>
34
#include <lib/timeutils.h>
35
#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
Aurélien Gâteau's avatar
Aurélien Gâteau committed
36
37
#include "abstractsemanticinfobackend.h"
#include "semanticinfodirmodel.h"
38
#include <lib/sorting.h>
39
#endif
40

41
42
namespace Gwenview
{
43

44
45
46
47
AbstractSortedDirModelFilter::AbstractSortedDirModelFilter(SortedDirModel* model)
: QObject(model)
, mModel(model)
{
48
49
50
    if (mModel) {
        mModel->addFilter(this);
    }
51
52
53
54
}

AbstractSortedDirModelFilter::~AbstractSortedDirModelFilter()
{
55
56
57
    if (mModel) {
        mModel->removeFilter(this);
    }
58
59
}

Aurélien Gâteau's avatar
Aurélien Gâteau committed
60
61
struct SortedDirModelPrivate
{
Aurélien Gâteau's avatar
Aurélien Gâteau committed
62
#ifdef GWENVIEW_SEMANTICINFO_BACKEND_NONE
63
    KDirModel* mSourceModel;
64
#else
65
    SemanticInfoDirModel* mSourceModel;
66
#endif
67
68
69
70
    QStringList mBlackListedExtensions;
    QList<AbstractSortedDirModelFilter*> mFilters;
    QTimer mDelayedApplyFiltersTimer;
    MimeTypeUtils::Kinds mKindFilter;
71
72
73
};

SortedDirModel::SortedDirModel(QObject* parent)
74
: KDirSortFilterProxyModel(parent)
75
, d(new SortedDirModelPrivate)
76
{
Aurélien Gâteau's avatar
Aurélien Gâteau committed
77
#ifdef GWENVIEW_SEMANTICINFO_BACKEND_NONE
78
    d->mSourceModel = new KDirModel(this);
79
#else
80
    d->mSourceModel = new SemanticInfoDirModel(this);
81
#endif
82
    setSourceModel(d->mSourceModel);
83
84
85
86
87

#ifdef KIO_REQUEST_MIMETYPE
    d->mSourceModel->dirLister()->setRequestMimeTypeWhileListing(true);
#endif

88
89
    d->mDelayedApplyFiltersTimer.setInterval(0);
    d->mDelayedApplyFiltersTimer.setSingleShot(true);
Laurent Montel's avatar
Laurent Montel committed
90
    connect(&d->mDelayedApplyFiltersTimer, &QTimer::timeout, this, &SortedDirModel::doApplyFilters);
91
92
}

93
94
95
SortedDirModel::~SortedDirModel()
{
    delete d;
96
97
}

98
99
100
MimeTypeUtils::Kinds SortedDirModel::kindFilter() const
{
    return d->mKindFilter;
101
102
}

103
104
105
106
107
108
109
void SortedDirModel::setKindFilter(MimeTypeUtils::Kinds kindFilter)
{
    if (d->mKindFilter == kindFilter) {
        return;
    }
    d->mKindFilter = kindFilter;
    applyFilters();
110
111
}

112
113
114
115
116
117
118
119
120
void SortedDirModel::adjustKindFilter(MimeTypeUtils::Kinds kinds, bool set)
{
    MimeTypeUtils::Kinds kindFilter = d->mKindFilter;
    if (set) {
        kindFilter |= kinds;
    } else {
        kindFilter &= ~kinds;
    }
    setKindFilter(kindFilter);
121
122
}

123
124
125
126
void SortedDirModel::addFilter(AbstractSortedDirModelFilter* filter)
{
    d->mFilters << filter;
    applyFilters();
127
128
}

129
130
131
132
void SortedDirModel::removeFilter(AbstractSortedDirModelFilter* filter)
{
    d->mFilters.removeAll(filter);
    applyFilters();
133
134
}

135
136
137
KDirLister* SortedDirModel::dirLister() const
{
    return d->mSourceModel->dirLister();
138
139
}

140
141
142
143
144
145
void SortedDirModel::reload()
{
#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
    d->mSourceModel->clearSemanticInfoCache();
#endif
    dirLister()->updateDirectory(dirLister()->url());
146
147
}

148
149
150
void SortedDirModel::setBlackListedExtensions(const QStringList& list)
{
    d->mBlackListedExtensions = list;
151
152
}

153
154
155
156
157
KFileItem SortedDirModel::itemForIndex(const QModelIndex& index) const
{
    if (!index.isValid()) {
        return KFileItem();
    }
158

159
160
    QModelIndex sourceIndex = mapToSource(index);
    return d->mSourceModel->itemForIndex(sourceIndex);
161
162
}

David Edmundson's avatar
David Edmundson committed
163
QUrl SortedDirModel::urlForIndex(const QModelIndex& index) const
164
{
165
    KFileItem item = itemForIndex(index);
David Edmundson's avatar
David Edmundson committed
166
    return item.isNull() ? QUrl() : item.url();
167
168
}

169
170
171
172
173
174
KFileItem SortedDirModel::itemForSourceIndex(const QModelIndex& sourceIndex) const
{
    if (!sourceIndex.isValid()) {
        return KFileItem();
    }
    return d->mSourceModel->itemForIndex(sourceIndex);
175
176
}

177
178
179
180
181
QModelIndex SortedDirModel::indexForItem(const KFileItem& item) const
{
    if (item.isNull()) {
        return QModelIndex();
    }
182

183
184
    QModelIndex sourceIndex = d->mSourceModel->indexForItem(item);
    return mapFromSource(sourceIndex);
185
186
}

David Edmundson's avatar
David Edmundson committed
187
QModelIndex SortedDirModel::indexForUrl(const QUrl &url) const
188
189
190
191
192
193
{
    if (!url.isValid()) {
        return QModelIndex();
    }
    QModelIndex sourceIndex = d->mSourceModel->indexForUrl(url);
    return mapFromSource(sourceIndex);
194
195
}

196
197
198
199
200
201
202
203
204
205
206
bool SortedDirModel::filterAcceptsRow(int row, const QModelIndex& parent) const
{
    QModelIndex index = d->mSourceModel->index(row, 0, parent);
    KFileItem fileItem = d->mSourceModel->itemForIndex(index);

    MimeTypeUtils::Kinds kind = MimeTypeUtils::fileItemKind(fileItem);
    if (d->mKindFilter != MimeTypeUtils::Kinds() && !(d->mKindFilter & kind)) {
        return false;
    }

    if (kind != MimeTypeUtils::KIND_DIR && kind != MimeTypeUtils::KIND_ARCHIVE) {
207
        int dotPos = fileItem.name().lastIndexOf(QLatin1Char('.'));
208
209
210
211
212
213
        if (dotPos >= 1) {
            QString extension = fileItem.name().mid(dotPos + 1).toLower();
            if (d->mBlackListedExtensions.contains(extension)) {
                return false;
            }
        }
214
#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
215
        if (!d->mSourceModel->semanticInfoAvailableForIndex(index)) {
216
            for (const AbstractSortedDirModelFilter * filter : qAsConst(d->mFilters)) {
217
218
219
220
221
222
223
224
225
                // Make sure we have semanticinfo, otherwise retrieve it and
                // return false, we will be called again later when it is
                // there.
                if (filter->needsSemanticInfo()) {
                    d->mSourceModel->retrieveSemanticInfoForIndex(index);
                    return false;
                }
            }
        }
226
227
#endif

228
        for (const AbstractSortedDirModelFilter * filter : qAsConst(d->mFilters)) {
229
230
231
232
233
234
            if (!filter->acceptsIndex(index)) {
                return false;
            }
        }
    }
    return KDirSortFilterProxyModel::filterAcceptsRow(row, parent);
235
236
}

237
238
AbstractSemanticInfoBackEnd* SortedDirModel::semanticInfoBackEnd() const
{
Aurélien Gâteau's avatar
Aurélien Gâteau committed
239
#ifdef GWENVIEW_SEMANTICINFO_BACKEND_NONE
240
    return 0;
241
#else
242
    return d->mSourceModel->semanticInfoBackEnd();
243
#endif
244
245
}

246
#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
247
248
249
SemanticInfo SortedDirModel::semanticInfoForSourceIndex(const QModelIndex& sourceIndex) const
{
    return d->mSourceModel->semanticInfoForIndex(sourceIndex);
250
251
}
#endif
Aurélien Gâteau's avatar
Aurélien Gâteau committed
252

253
254
255
void SortedDirModel::applyFilters()
{
    d->mDelayedApplyFiltersTimer.start();
256
257
}

258
259
260
void SortedDirModel::doApplyFilters()
{
    QSortFilterProxyModel::invalidateFilter();
261
262
}

263
264
265
266
bool SortedDirModel::lessThan(const QModelIndex& left, const QModelIndex& right) const
{
    const KFileItem leftItem = itemForSourceIndex(left);
    const KFileItem rightItem = itemForSourceIndex(right);
267

268
269
    const bool leftIsDirOrArchive = ArchiveUtils::fileItemIsDirOrArchive(leftItem);
    const bool rightIsDirOrArchive = ArchiveUtils::fileItemIsDirOrArchive(rightItem);
270

271
    if (leftIsDirOrArchive != rightIsDirOrArchive) {
272
        return sortOrder() == Qt::AscendingOrder ? leftIsDirOrArchive : rightIsDirOrArchive;
273
    }
274

275
276
277
278
279
280
281
282
283
284
    // Apply special sort handling only to images. For folders/archives or when
    // a secondary criterion is needed, delegate sorting to the parent class.
    if (!leftIsDirOrArchive) {
        if (sortColumn() == KDirModel::ModifiedTime) {
            const QDateTime leftDate = TimeUtils::dateTimeForFileItem(leftItem);
            const QDateTime rightDate = TimeUtils::dateTimeForFileItem(rightItem);

            if (leftDate != rightDate) {
                return leftDate < rightDate;
            }
__ __'s avatar
__ __ committed
285
        }
286
#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
287
288
289
        if (sortRole() == SemanticInfoDirModel::RatingRole) {
            const int leftRating = d->mSourceModel->data(left, SemanticInfoDirModel::RatingRole).toInt();
            const int rightRating = d->mSourceModel->data(right, SemanticInfoDirModel::RatingRole).toInt();
290

291
292
293
            if (leftRating != rightRating) {
                return leftRating < rightRating;
            }
294
295
        }
#endif
296
    }
297

298
    return KDirSortFilterProxyModel::lessThan(left, right);
299
300
}

301
302
bool SortedDirModel::hasDocuments() const
{
303
304
305
306
307
308
309
310
311
312
313
314
    const int count = rowCount();
    if (count == 0) {
        return false;
    }
    for (int row = 0; row < count; ++row) {
        const QModelIndex idx = index(row, 0);
        const KFileItem item = itemForIndex(idx);
        if (!ArchiveUtils::fileItemIsDirOrArchive(item)) {
            return true;
        }
    }
    return false;
315
316
}

317
318
319
320
321
void SortedDirModel::setDirLister(KDirLister* dirLister)
{
    d->mSourceModel->setDirLister(dirLister);
}

322
} //namespace