KIO

kfilefilter.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2022 Nicolas Fella <nicolas.fella@gmx.de>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "kfilefilter.h"
9
10#include <QDebug>
11#include <QMetaType>
12#include <QMimeDatabase>
13#include <algorithm>
14#include <qchar.h>
15
16#include "kiocoredebug.h"
17
18class KFileFilterPrivate : public QSharedData
19{
20public:
21 KFileFilterPrivate()
22 {
23 }
24
25 KFileFilterPrivate(const KFileFilterPrivate &other)
26 : QSharedData(other)
27 , m_label(other.m_label)
28 , m_filePatterns(other.m_filePatterns)
29 , m_mimePatterns(other.m_mimePatterns)
30 {
31 }
32
33 QString m_label;
34 QStringList m_filePatterns;
35 QStringList m_mimePatterns;
36 bool m_isValid = true;
37};
38
39QList<KFileFilter> KFileFilter::fromFilterString(const QString &filterString)
40{
41 int pos = filterString.indexOf(QLatin1Char('/'));
42
43 // Check for an un-escaped '/', if found
44 // interpret as a MIME filter.
45
46 if (pos > 0 && filterString[pos - 1] != QLatin1Char('\\')) {
47 const QStringList filters = filterString.split(QLatin1Char(' '), Qt::SkipEmptyParts);
48
49 QList<KFileFilter> result;
50 result.reserve(filters.size());
51
52 std::transform(filters.begin(), filters.end(), std::back_inserter(result), [](const QString &mimeType) {
53 return KFileFilter::fromMimeType(mimeType);
54 });
55
56 return result;
57 }
58
59 // Strip the escape characters from
60 // escaped '/' characters.
61
62 QString escapeRemoved(filterString);
63 for (pos = 0; (pos = escapeRemoved.indexOf(QLatin1String("\\/"), pos)) != -1; ++pos) {
64 escapeRemoved.remove(pos, 1);
65 }
66
67 const QStringList filters = escapeRemoved.split(QLatin1Char('\n'), Qt::SkipEmptyParts);
68
69 QList<KFileFilter> result;
70
71 for (const QString &filter : filters) {
72 int separatorPos = filter.indexOf(QLatin1Char('|'));
73
75 QStringList patterns;
76
77 if (separatorPos != -1) {
78 label = filter.mid(separatorPos + 1);
79 patterns = filter.left(separatorPos).split(QLatin1Char(' '));
80 } else {
81 patterns = filter.split(QLatin1Char(' '));
82 label = patterns.join(QLatin1Char(' '));
83 }
84
85 result << KFileFilter(label, patterns, {});
86 }
87
88 return result;
89}
90
92 : d(new KFileFilterPrivate)
93{
94}
95
96KFileFilter::KFileFilter(const QString &label, const QStringList &filePatterns, const QStringList &mimePatterns)
97 : d(new KFileFilterPrivate)
98{
99 d->m_filePatterns = filePatterns;
100 d->m_mimePatterns = mimePatterns;
101 d->m_label = label;
102}
103
104KFileFilter::~KFileFilter() = default;
105
107 : d(other.d)
108{
109}
110
111KFileFilter &KFileFilter::operator=(const KFileFilter &other)
112{
113 if (this != &other) {
114 d = other.d;
115 }
116
117 return *this;
118}
119
121{
122 return d->m_label;
123}
124
126{
127 return d->m_filePatterns;
128}
129
131{
132 return d->m_mimePatterns;
133}
134
135bool KFileFilter::operator==(const KFileFilter &other) const
136{
137 return d->m_filePatterns == other.d->m_filePatterns && d->m_mimePatterns == other.d->m_mimePatterns;
138}
139
141{
142 return d->m_filePatterns.isEmpty() && d->m_mimePatterns.isEmpty();
143}
144
146{
147 return d->m_isValid;
148}
149
151{
152 if (!d->m_filePatterns.isEmpty() && !d->m_mimePatterns.isEmpty()) {
153 qCWarning(KIO_CORE) << "KFileFilters with both mime and file patterns cannot be converted to filter strings";
154 return QString();
155 }
156
157 if (!d->m_mimePatterns.isEmpty()) {
158 return d->m_mimePatterns.join(QLatin1Char(' '));
159 }
160
161 if (!d->m_label.isEmpty()) {
162 const QString patterns = d->m_filePatterns.join(QLatin1Char(' '));
163 const QString escapedLabel = QString(d->m_label).replace(QLatin1String("/"), QLatin1String("\\/"));
164
165 if (patterns != d->m_label) {
166 return patterns + QLatin1Char('|') + escapedLabel;
167 } else {
168 return patterns;
169 }
170 } else {
171 return d->m_filePatterns.join(QLatin1Char(' '));
172 }
173}
174
175KFileFilter KFileFilter::fromMimeType(const QString &mimeType)
176{
177 if (mimeType.isEmpty()) {
178 qCWarning(KIO_CORE) << "KFileFilter::fromMimeType() called with empty input";
179
180 KFileFilter filter;
181 filter.d->m_isValid = false;
182 return filter;
183 }
184
185 static QMimeDatabase db;
186 const QMimeType type = db.mimeTypeForName(mimeType);
187
188 if (type.isValid() || mimeType.endsWith(QLatin1String("/*"))) {
189 KFileFilter filter(type.comment(), {}, {mimeType});
190 return filter;
191 } else {
192 qCWarning(KIO_CORE) << "KFileFilter::fromMimeType() called with unknown MIME type" << mimeType;
193
195 filter.d->m_isValid = false;
196 return filter;
197 }
198}
199
201{
203 ret.reserve(mimeTypes.size());
204 for (const QString &type : mimeTypes) {
205 ret << KFileFilter::fromMimeType(type);
206 }
207 return ret;
208}
209
210QDebug operator<<(QDebug dbg, const KFileFilter &filter)
211{
212 dbg.nospace() << "KFileFilter(";
213
214 dbg.nospace() << "MIME patterns: " << filter.mimePatterns();
215 dbg.nospace() << " ";
216 dbg.nospace() << "File patterns: " << filter.filePatterns();
217 dbg.nospace() << " ";
218 dbg.nospace() << "label: " << filter.label();
219
220 dbg.nospace() << ")";
221 return dbg;
222}
223
224Q_DECLARE_METATYPE(KFileFilter);
Encapsulates rules to filter a list of files.
Definition kfilefilter.h:29
KFileFilter()
Creates an empty filter.
QStringList filePatterns() const
List of file name patterns that are included by this filter.
QString label() const
The user-facing label for this filter.
QString toFilterString() const
Converts this filter to a string representation.
bool isEmpty() const
Whether the filer is empty, i.e. matches all files.
bool isValid() const
Whether the filter is valid.
static QList< KFileFilter > fromMimeTypes(const QStringList &mimeTypes)
Creates filters from a list of MIME types.
bool operator==(const KFileFilter &other) const
Checks whether two filters are equal.
QStringList mimePatterns() const
List of MIME types that are included by this filter;.
Type type(const QSqlDatabase &db)
KCALUTILS_EXPORT QString mimeType()
QDebug & nospace()
iterator begin()
iterator end()
void reserve(qsizetype size)
qsizetype size() const const
QMimeType mimeTypeForName(const QString &nameOrAlias) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString join(QChar separator) const const
SkipEmptyParts
QFuture< void > filter(QThreadPool *pool, Sequence &sequence, KeepFunctor &&filterFunction)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:16:27 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.