File indexing completed on 2024-04-28 11:41:00

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 };
0037 
0038 QVector<KFileFilter> KFileFilter::fromFilterString(const QString &filterString)
0039 {
0040     int pos = filterString.indexOf(QLatin1Char('/'));
0041 
0042     // Check for an un-escaped '/', if found
0043     // interpret as a MIME filter.
0044 
0045     if (pos > 0 && filterString[pos - 1] != QLatin1Char('\\')) {
0046         const QStringList filters = filterString.split(QLatin1Char(' '), Qt::SkipEmptyParts);
0047 
0048         QVector<KFileFilter> result;
0049         result.reserve(filters.size());
0050 
0051         std::transform(filters.begin(), filters.end(), std::back_inserter(result), [](const QString &mimeType) {
0052             return KFileFilter::fromMimeType(mimeType);
0053         });
0054 
0055         return result;
0056     }
0057 
0058     // Strip the escape characters from
0059     // escaped '/' characters.
0060 
0061     QString escapeRemoved(filterString);
0062     for (pos = 0; (pos = escapeRemoved.indexOf(QLatin1String("\\/"), pos)) != -1; ++pos) {
0063         escapeRemoved.remove(pos, 1);
0064     }
0065 
0066     const QStringList filters = escapeRemoved.split(QLatin1Char('\n'), Qt::SkipEmptyParts);
0067 
0068     QVector<KFileFilter> result;
0069 
0070     for (const QString &filter : filters) {
0071         int separatorPos = filter.indexOf(QLatin1Char('|'));
0072 
0073         QString label;
0074         QStringList patterns;
0075 
0076         if (separatorPos != -1) {
0077             label = filter.mid(separatorPos + 1);
0078             patterns = filter.left(separatorPos).split(QLatin1Char(' '));
0079         } else {
0080             patterns = filter.split(QLatin1Char(' '));
0081             label = patterns.join(QLatin1Char(' '));
0082         }
0083 
0084         result << KFileFilter(label, patterns, {});
0085     }
0086 
0087     return result;
0088 }
0089 
0090 KFileFilter::KFileFilter()
0091     : d(new KFileFilterPrivate)
0092 {
0093 }
0094 
0095 KFileFilter::KFileFilter(const QString &label, const QStringList &filePatterns, const QStringList &mimePatterns)
0096     : d(new KFileFilterPrivate)
0097 {
0098     d->m_filePatterns = filePatterns;
0099     d->m_mimePatterns = mimePatterns;
0100     d->m_label = label;
0101 }
0102 
0103 KFileFilter::~KFileFilter() = default;
0104 
0105 KFileFilter::KFileFilter(const KFileFilter &other)
0106     : d(other.d)
0107 {
0108 }
0109 
0110 KFileFilter &KFileFilter::operator=(const KFileFilter &other)
0111 {
0112     if (this != &other) {
0113         d = other.d;
0114     }
0115 
0116     return *this;
0117 }
0118 
0119 QString KFileFilter::label() const
0120 {
0121     return d->m_label;
0122 }
0123 
0124 QStringList KFileFilter::filePatterns() const
0125 {
0126     return d->m_filePatterns;
0127 }
0128 
0129 QStringList KFileFilter::mimePatterns() const
0130 {
0131     return d->m_mimePatterns;
0132 }
0133 
0134 bool KFileFilter::operator==(const KFileFilter &other) const
0135 {
0136     return d->m_label == other.d->m_label && d->m_filePatterns == other.d->m_filePatterns && d->m_mimePatterns == other.d->m_mimePatterns;
0137 }
0138 
0139 bool KFileFilter::isEmpty() const
0140 {
0141     return d->m_filePatterns.isEmpty() && d->m_mimePatterns.isEmpty();
0142 }
0143 
0144 QString KFileFilter::toFilterString() const
0145 {
0146     if (!d->m_filePatterns.isEmpty() && !d->m_mimePatterns.isEmpty()) {
0147         qCWarning(KIO_CORE) << "KFileFilters with both mime and file patterns cannot be converted to filter strings";
0148         return QString();
0149     }
0150 
0151     if (!d->m_mimePatterns.isEmpty()) {
0152         return d->m_mimePatterns.join(QLatin1Char(' '));
0153     }
0154 
0155     if (!d->m_label.isEmpty()) {
0156         const QString patterns = d->m_filePatterns.join(QLatin1Char(' '));
0157         const QString escapedLabel = QString(d->m_label).replace(QLatin1String("/"), QLatin1String("\\/"));
0158 
0159         if (patterns != d->m_label) {
0160             return patterns + QLatin1Char('|') + escapedLabel;
0161         } else {
0162             return patterns;
0163         }
0164     } else {
0165         return d->m_filePatterns.join(QLatin1Char(' '));
0166     }
0167 }
0168 
0169 KFileFilter KFileFilter::fromMimeType(const QString &mimeType)
0170 {
0171     if (mimeType.isEmpty()) {
0172         return KFileFilter();
0173     }
0174 
0175     static QMimeDatabase db;
0176     const QMimeType type = db.mimeTypeForName(mimeType);
0177 
0178     KFileFilter filter(type.comment(), {}, {mimeType});
0179     return filter;
0180 }
0181 
0182 Q_DECLARE_METATYPE(KFileFilter);