File indexing completed on 2024-10-06 03:39:29
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2022 Nicolas Fella <nicolas.fella@gmx.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "kfilefilter.h" 0009 0010 #include <QDebug> 0011 #include <QMetaType> 0012 #include <QMimeDatabase> 0013 #include <algorithm> 0014 #include <qchar.h> 0015 0016 #include "kiocoredebug.h" 0017 0018 class KFileFilterPrivate : public QSharedData 0019 { 0020 public: 0021 KFileFilterPrivate() 0022 { 0023 } 0024 0025 KFileFilterPrivate(const KFileFilterPrivate &other) 0026 : QSharedData(other) 0027 , m_label(other.m_label) 0028 , m_filePatterns(other.m_filePatterns) 0029 , m_mimePatterns(other.m_mimePatterns) 0030 { 0031 } 0032 0033 QString m_label; 0034 QStringList m_filePatterns; 0035 QStringList m_mimePatterns; 0036 bool m_isValid = true; 0037 }; 0038 0039 QList<KFileFilter> KFileFilter::fromFilterString(const QString &filterString) 0040 { 0041 int pos = filterString.indexOf(QLatin1Char('/')); 0042 0043 // Check for an un-escaped '/', if found 0044 // interpret as a MIME filter. 0045 0046 if (pos > 0 && filterString[pos - 1] != QLatin1Char('\\')) { 0047 const QStringList filters = filterString.split(QLatin1Char(' '), Qt::SkipEmptyParts); 0048 0049 QList<KFileFilter> result; 0050 result.reserve(filters.size()); 0051 0052 std::transform(filters.begin(), filters.end(), std::back_inserter(result), [](const QString &mimeType) { 0053 return KFileFilter::fromMimeType(mimeType); 0054 }); 0055 0056 return result; 0057 } 0058 0059 // Strip the escape characters from 0060 // escaped '/' characters. 0061 0062 QString escapeRemoved(filterString); 0063 for (pos = 0; (pos = escapeRemoved.indexOf(QLatin1String("\\/"), pos)) != -1; ++pos) { 0064 escapeRemoved.remove(pos, 1); 0065 } 0066 0067 const QStringList filters = escapeRemoved.split(QLatin1Char('\n'), Qt::SkipEmptyParts); 0068 0069 QList<KFileFilter> result; 0070 0071 for (const QString &filter : filters) { 0072 int separatorPos = filter.indexOf(QLatin1Char('|')); 0073 0074 QString label; 0075 QStringList patterns; 0076 0077 if (separatorPos != -1) { 0078 label = filter.mid(separatorPos + 1); 0079 patterns = filter.left(separatorPos).split(QLatin1Char(' ')); 0080 } else { 0081 patterns = filter.split(QLatin1Char(' ')); 0082 label = patterns.join(QLatin1Char(' ')); 0083 } 0084 0085 result << KFileFilter(label, patterns, {}); 0086 } 0087 0088 return result; 0089 } 0090 0091 KFileFilter::KFileFilter() 0092 : d(new KFileFilterPrivate) 0093 { 0094 } 0095 0096 KFileFilter::KFileFilter(const QString &label, const QStringList &filePatterns, const QStringList &mimePatterns) 0097 : d(new KFileFilterPrivate) 0098 { 0099 d->m_filePatterns = filePatterns; 0100 d->m_mimePatterns = mimePatterns; 0101 d->m_label = label; 0102 } 0103 0104 KFileFilter::~KFileFilter() = default; 0105 0106 KFileFilter::KFileFilter(const KFileFilter &other) 0107 : d(other.d) 0108 { 0109 } 0110 0111 KFileFilter &KFileFilter::operator=(const KFileFilter &other) 0112 { 0113 if (this != &other) { 0114 d = other.d; 0115 } 0116 0117 return *this; 0118 } 0119 0120 QString KFileFilter::label() const 0121 { 0122 return d->m_label; 0123 } 0124 0125 QStringList KFileFilter::filePatterns() const 0126 { 0127 return d->m_filePatterns; 0128 } 0129 0130 QStringList KFileFilter::mimePatterns() const 0131 { 0132 return d->m_mimePatterns; 0133 } 0134 0135 bool KFileFilter::operator==(const KFileFilter &other) const 0136 { 0137 return d->m_label == other.d->m_label && d->m_filePatterns == other.d->m_filePatterns && d->m_mimePatterns == other.d->m_mimePatterns; 0138 } 0139 0140 bool KFileFilter::isEmpty() const 0141 { 0142 return d->m_filePatterns.isEmpty() && d->m_mimePatterns.isEmpty(); 0143 } 0144 0145 bool KFileFilter::isValid() const 0146 { 0147 return d->m_isValid; 0148 } 0149 0150 QString KFileFilter::toFilterString() const 0151 { 0152 if (!d->m_filePatterns.isEmpty() && !d->m_mimePatterns.isEmpty()) { 0153 qCWarning(KIO_CORE) << "KFileFilters with both mime and file patterns cannot be converted to filter strings"; 0154 return QString(); 0155 } 0156 0157 if (!d->m_mimePatterns.isEmpty()) { 0158 return d->m_mimePatterns.join(QLatin1Char(' ')); 0159 } 0160 0161 if (!d->m_label.isEmpty()) { 0162 const QString patterns = d->m_filePatterns.join(QLatin1Char(' ')); 0163 const QString escapedLabel = QString(d->m_label).replace(QLatin1String("/"), QLatin1String("\\/")); 0164 0165 if (patterns != d->m_label) { 0166 return patterns + QLatin1Char('|') + escapedLabel; 0167 } else { 0168 return patterns; 0169 } 0170 } else { 0171 return d->m_filePatterns.join(QLatin1Char(' ')); 0172 } 0173 } 0174 0175 KFileFilter KFileFilter::fromMimeType(const QString &mimeType) 0176 { 0177 if (mimeType.isEmpty()) { 0178 qCWarning(KIO_CORE) << "KFileFilter::fromMimeType() called with empty input"; 0179 0180 KFileFilter filter; 0181 filter.d->m_isValid = false; 0182 return filter; 0183 } 0184 0185 static QMimeDatabase db; 0186 const QMimeType type = db.mimeTypeForName(mimeType); 0187 0188 if (type.isValid()) { 0189 KFileFilter filter(type.comment(), {}, {mimeType}); 0190 return filter; 0191 } else { 0192 qCWarning(KIO_CORE) << "KFileFilter::fromMimeType() called with unknown MIME type" << mimeType; 0193 0194 KFileFilter filter; 0195 filter.d->m_isValid = false; 0196 return filter; 0197 } 0198 } 0199 0200 QList<KFileFilter> KFileFilter::fromMimeTypes(const QStringList &mimeTypes) 0201 { 0202 QList<KFileFilter> ret; 0203 ret.reserve(mimeTypes.size()); 0204 for (const QString &type : mimeTypes) { 0205 ret << KFileFilter::fromMimeType(type); 0206 } 0207 return ret; 0208 } 0209 0210 QDebug operator<<(QDebug dbg, const KFileFilter &filter) 0211 { 0212 dbg << "KFileFilter("; 0213 0214 dbg << "MIME patterns: " << filter.mimePatterns(); 0215 dbg << " "; 0216 dbg << "File patterns: " << filter.filePatterns(); 0217 dbg << " "; 0218 dbg << "label: " << filter.label(); 0219 0220 dbg << ")"; 0221 return dbg; 0222 } 0223 0224 Q_DECLARE_METATYPE(KFileFilter);