File indexing completed on 2023-11-26 10:44:06
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: Stephan Kulow <coolo@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "kfilefiltercombo.h" 0009 #include "kfilefilter.h" 0010 #include "kfilefiltercombo_debug.h" 0011 0012 #include <KLocalizedString> 0013 #include <QDebug> 0014 #include <QEvent> 0015 #include <QLineEdit> 0016 #include <QMimeDatabase> 0017 0018 #include <config-kiofilewidgets.h> 0019 0020 #include <algorithm> 0021 #include <utility> 0022 0023 class KFileFilterComboPrivate 0024 { 0025 public: 0026 explicit KFileFilterComboPrivate(KFileFilterCombo *qq) 0027 : q(qq) 0028 { 0029 } 0030 0031 void slotFilterChanged(); 0032 0033 KFileFilterCombo *const q; 0034 // when we have more than 3 mimefilters and no default-filter, 0035 // we don't show the comments of all mimefilters in one line, 0036 // instead we show "All supported files". We have to translate 0037 // that back to the list of mimefilters in currentFilter() tho. 0038 bool m_hasAllSupportedFiles = false; 0039 // true when setMimeFilter was called 0040 bool m_isMimeFilter = false; 0041 QString m_lastFilter; 0042 QString m_defaultFilter = i18nc("Default mime type filter that shows all file types", "*|All Files"); 0043 0044 QList<KFileFilter> m_fileFilters; 0045 QStringList m_filters; 0046 bool m_allTypes; 0047 }; 0048 0049 KFileFilterCombo::KFileFilterCombo(QWidget *parent) 0050 : KComboBox(true, parent) 0051 , d(new KFileFilterComboPrivate(this)) 0052 { 0053 setTrapReturnKey(true); 0054 setInsertPolicy(QComboBox::NoInsert); 0055 connect(this, &QComboBox::activated, this, &KFileFilterCombo::filterChanged); 0056 connect(this, &KComboBox::returnPressed, this, &KFileFilterCombo::filterChanged); 0057 connect(this, &KFileFilterCombo::filterChanged, this, [this]() { 0058 d->slotFilterChanged(); 0059 }); 0060 d->m_allTypes = false; 0061 } 0062 0063 KFileFilterCombo::~KFileFilterCombo() = default; 0064 0065 void KFileFilterCombo::setFilter(const QString &filter) 0066 { 0067 clear(); 0068 d->m_filters.clear(); 0069 d->m_fileFilters.clear(); 0070 d->m_hasAllSupportedFiles = false; 0071 0072 if (!filter.isEmpty()) { 0073 QString tmp = filter; 0074 int index = tmp.indexOf(QLatin1Char('\n')); 0075 while (index > 0) { 0076 d->m_filters.append(tmp.left(index)); 0077 tmp.remove(0, index + 1); 0078 index = tmp.indexOf(QLatin1Char('\n')); 0079 } 0080 d->m_filters.append(tmp); 0081 } else { 0082 d->m_filters.append(d->m_defaultFilter); 0083 } 0084 0085 QStringList::ConstIterator it; 0086 QStringList::ConstIterator end(d->m_filters.constEnd()); 0087 for (it = d->m_filters.constBegin(); it != end; ++it) { 0088 int tab = (*it).indexOf(QLatin1Char('|')); 0089 addItem((tab < 0) ? *it : (*it).mid(tab + 1)); 0090 } 0091 0092 d->m_lastFilter = currentText(); 0093 d->m_isMimeFilter = false; 0094 } 0095 0096 QString KFileFilterCombo::currentFilter() const 0097 { 0098 QString f = currentText(); 0099 if (f == itemText(currentIndex())) { // user didn't edit the text 0100 0101 if (!d->m_filters.isEmpty()) { 0102 f = d->m_filters.value(currentIndex()); 0103 } else { 0104 f = d->m_fileFilters.value(currentIndex()).toFilterString(); 0105 } 0106 0107 if (d->m_isMimeFilter || (currentIndex() == 0 && d->m_hasAllSupportedFiles)) { 0108 return f; // we have a MIME type as filter 0109 } 0110 } 0111 0112 int tab = f.indexOf(QLatin1Char('|')); 0113 if (tab < 0) { 0114 return f; 0115 } else { 0116 return f.left(tab); 0117 } 0118 } 0119 0120 bool KFileFilterCombo::showsAllTypes() const 0121 { 0122 return d->m_allTypes; 0123 } 0124 0125 QStringList KFileFilterCombo::filters() const 0126 { 0127 if (!d->m_filters.isEmpty()) { 0128 return d->m_filters; 0129 } 0130 0131 QStringList result; 0132 0133 for (const KFileFilter &filter : std::as_const(d->m_fileFilters)) { 0134 result << filter.toFilterString(); 0135 } 0136 0137 return result; 0138 } 0139 0140 void KFileFilterCombo::setCurrentFilter(const QString &filterString) 0141 { 0142 if (!d->m_filters.isEmpty()) { 0143 setCurrentIndex(d->m_filters.indexOf(filterString)); 0144 return; 0145 } 0146 0147 auto it = std::find_if(d->m_fileFilters.cbegin(), d->m_fileFilters.cend(), [filterString](const KFileFilter &filter) { 0148 return filterString == filter.toFilterString(); 0149 }); 0150 0151 if (it == d->m_fileFilters.cend()) { 0152 qCWarning(KIO_KFILEWIDGETS_KFILEFILTERCOMBO) << "Could not find filter" << filterString; 0153 setCurrentIndex(-1); 0154 Q_EMIT filterChanged(); 0155 return; 0156 } 0157 0158 setCurrentIndex(std::distance(d->m_fileFilters.cbegin(), it)); 0159 Q_EMIT filterChanged(); 0160 } 0161 0162 void KFileFilterCombo::setMimeFilter(const QStringList &types, const QString &defaultType) 0163 { 0164 clear(); 0165 d->m_filters.clear(); 0166 d->m_fileFilters.clear(); 0167 QString delim = QStringLiteral(", "); 0168 d->m_hasAllSupportedFiles = false; 0169 bool hasAllFilesFilter = false; 0170 QMimeDatabase db; 0171 0172 d->m_allTypes = defaultType.isEmpty() && (types.count() > 1); 0173 0174 // If there's MIME types that have the same comment, we will show the extension 0175 // in addition to the MIME type comment 0176 QHash<QString, int> allTypeComments; 0177 for (QStringList::ConstIterator it = types.begin(); it != types.end(); ++it) { 0178 const QMimeType type = db.mimeTypeForName(*it); 0179 if (!type.isValid()) { 0180 qCWarning(KIO_KFILEWIDGETS_KFILEFILTERCOMBO) << *it << "is not a valid MIME type"; 0181 continue; 0182 } 0183 0184 allTypeComments[type.comment()] += 1; 0185 } 0186 0187 for (QStringList::ConstIterator it = types.begin(); it != types.end(); ++it) { 0188 // qDebug() << *it; 0189 const QMimeType type = db.mimeTypeForName(*it); 0190 if (!type.isValid()) { 0191 qCWarning(KIO_KFILEWIDGETS_KFILEFILTERCOMBO) << *it << "is not a valid MIME type"; 0192 continue; 0193 } 0194 0195 if (type.name().startsWith(QLatin1String("all/")) || type.isDefault()) { 0196 hasAllFilesFilter = true; 0197 continue; 0198 } 0199 0200 KFileFilter filter; 0201 0202 if (allTypeComments.value(type.comment()) > 1) { 0203 const QString label = i18nc("%1 is the mimetype name, %2 is the extensions", "%1 (%2)", type.comment(), type.suffixes().join(QLatin1String(", "))); 0204 filter = KFileFilter(label, {}, {*it}); 0205 } else { 0206 filter = KFileFilter::fromMimeType(*it); 0207 } 0208 0209 d->m_fileFilters.append(filter); 0210 addItem(filter.label()); 0211 0212 if (type.name() == defaultType) { 0213 setCurrentIndex(count() - 1); 0214 } 0215 } 0216 0217 if (count() == 1) { 0218 d->m_allTypes = false; 0219 } 0220 0221 if (d->m_allTypes) { 0222 QStringList allTypes; 0223 for (const KFileFilter &filter : std::as_const(d->m_fileFilters)) { 0224 allTypes << filter.mimePatterns().join(QLatin1Char(' ')); 0225 } 0226 0227 KFileFilter allSupportedFilesFilter; 0228 0229 if (count() <= 3) { // show the MIME type comments of at max 3 types 0230 QStringList allComments; 0231 for (const KFileFilter &filter : std::as_const(d->m_fileFilters)) { 0232 allComments << filter.label(); 0233 } 0234 0235 allSupportedFilesFilter = KFileFilter(allComments.join(delim), {}, allTypes); 0236 } else { 0237 allSupportedFilesFilter = KFileFilter(i18n("All Supported Files"), {}, allTypes); 0238 d->m_hasAllSupportedFiles = true; 0239 } 0240 0241 insertItem(0, allSupportedFilesFilter.label()); 0242 d->m_fileFilters.prepend(allSupportedFilesFilter); 0243 setCurrentIndex(0); 0244 } 0245 0246 if (hasAllFilesFilter) { 0247 addItem(i18n("All Files")); 0248 d->m_fileFilters.append(KFileFilter(i18n("All Files"), {}, {QStringLiteral("application/octet-stream")})); 0249 } 0250 0251 d->m_lastFilter = currentText(); 0252 d->m_isMimeFilter = true; 0253 } 0254 0255 void KFileFilterComboPrivate::slotFilterChanged() 0256 { 0257 m_lastFilter = q->currentText(); 0258 } 0259 0260 bool KFileFilterCombo::eventFilter(QObject *o, QEvent *e) 0261 { 0262 if (o == lineEdit() && e->type() == QEvent::FocusOut) { 0263 if (currentText() != d->m_lastFilter) { 0264 Q_EMIT filterChanged(); 0265 } 0266 } 0267 0268 return KComboBox::eventFilter(o, e); 0269 } 0270 0271 void KFileFilterCombo::setDefaultFilter(const QString &filter) 0272 { 0273 d->m_defaultFilter = filter; 0274 } 0275 0276 QString KFileFilterCombo::defaultFilter() const 0277 { 0278 return d->m_defaultFilter; 0279 } 0280 0281 bool KFileFilterCombo::isMimeFilter() const 0282 { 0283 return d->m_isMimeFilter; 0284 } 0285 0286 #include "moc_kfilefiltercombo.cpp"