Warning, file /frameworks/kio/src/filewidgets/kfilefiltercombo.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
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 QVector<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, qOverload<int>(&QComboBox::activated), this, &KFileFilterCombo::filterChanged); 0056 // TODO KF6: remove this QOverload, only KUrlComboBox::returnPressed(const QString &) will remain 0057 connect(this, qOverload<const QString &>(&KComboBox::returnPressed), this, &KFileFilterCombo::filterChanged); 0058 connect(this, &KFileFilterCombo::filterChanged, this, [this]() { 0059 d->slotFilterChanged(); 0060 }); 0061 d->m_allTypes = false; 0062 } 0063 0064 KFileFilterCombo::~KFileFilterCombo() = default; 0065 0066 void KFileFilterCombo::setFilter(const QString &filter) 0067 { 0068 clear(); 0069 d->m_filters.clear(); 0070 d->m_fileFilters.clear(); 0071 d->m_hasAllSupportedFiles = false; 0072 0073 if (!filter.isEmpty()) { 0074 QString tmp = filter; 0075 int index = tmp.indexOf(QLatin1Char('\n')); 0076 while (index > 0) { 0077 d->m_filters.append(tmp.left(index)); 0078 tmp.remove(0, index + 1); 0079 index = tmp.indexOf(QLatin1Char('\n')); 0080 } 0081 d->m_filters.append(tmp); 0082 } else { 0083 d->m_filters.append(d->m_defaultFilter); 0084 } 0085 0086 QStringList::ConstIterator it; 0087 QStringList::ConstIterator end(d->m_filters.constEnd()); 0088 for (it = d->m_filters.constBegin(); it != end; ++it) { 0089 int tab = (*it).indexOf(QLatin1Char('|')); 0090 addItem((tab < 0) ? *it : (*it).mid(tab + 1)); 0091 } 0092 0093 d->m_lastFilter = currentText(); 0094 d->m_isMimeFilter = false; 0095 } 0096 0097 QString KFileFilterCombo::currentFilter() const 0098 { 0099 QString f = currentText(); 0100 if (f == itemText(currentIndex())) { // user didn't edit the text 0101 0102 if (!d->m_filters.isEmpty()) { 0103 f = d->m_filters.value(currentIndex()); 0104 } else { 0105 f = d->m_fileFilters.value(currentIndex()).toFilterString(); 0106 } 0107 0108 if (d->m_isMimeFilter || (currentIndex() == 0 && d->m_hasAllSupportedFiles)) { 0109 return f; // we have a MIME type as filter 0110 } 0111 } 0112 0113 int tab = f.indexOf(QLatin1Char('|')); 0114 if (tab < 0) { 0115 return f; 0116 } else { 0117 return f.left(tab); 0118 } 0119 } 0120 0121 bool KFileFilterCombo::showsAllTypes() const 0122 { 0123 return d->m_allTypes; 0124 } 0125 0126 QStringList KFileFilterCombo::filters() const 0127 { 0128 if (!d->m_filters.isEmpty()) { 0129 return d->m_filters; 0130 } 0131 0132 QStringList result; 0133 0134 for (const KFileFilter &filter : std::as_const(d->m_fileFilters)) { 0135 result << filter.toFilterString(); 0136 } 0137 0138 return result; 0139 } 0140 0141 void KFileFilterCombo::setCurrentFilter(const QString &filterString) 0142 { 0143 if (!d->m_filters.isEmpty()) { 0144 setCurrentIndex(d->m_filters.indexOf(filterString)); 0145 return; 0146 } 0147 0148 auto it = std::find_if(d->m_fileFilters.cbegin(), d->m_fileFilters.cend(), [filterString](const KFileFilter &filter) { 0149 return filterString == filter.toFilterString(); 0150 }); 0151 0152 if (it == d->m_fileFilters.cend()) { 0153 qCWarning(KIO_KFILEWIDGETS_KFILEFILTERCOMBO) << "Could not find filter" << filterString; 0154 setCurrentIndex(-1); 0155 Q_EMIT filterChanged(); 0156 return; 0157 } 0158 0159 setCurrentIndex(std::distance(d->m_fileFilters.cbegin(), it)); 0160 Q_EMIT filterChanged(); 0161 } 0162 0163 void KFileFilterCombo::setMimeFilter(const QStringList &types, const QString &defaultType) 0164 { 0165 clear(); 0166 d->m_filters.clear(); 0167 d->m_fileFilters.clear(); 0168 QString delim = QStringLiteral(", "); 0169 d->m_hasAllSupportedFiles = false; 0170 bool hasAllFilesFilter = false; 0171 QMimeDatabase db; 0172 0173 d->m_allTypes = defaultType.isEmpty() && (types.count() > 1); 0174 0175 // If there's MIME types that have the same comment, we will show the extension 0176 // in addition to the MIME type comment 0177 QHash<QString, int> allTypeComments; 0178 for (QStringList::ConstIterator it = types.begin(); it != types.end(); ++it) { 0179 const QMimeType type = db.mimeTypeForName(*it); 0180 if (!type.isValid()) { 0181 qCWarning(KIO_KFILEWIDGETS_KFILEFILTERCOMBO) << *it << "is not a valid MIME type"; 0182 continue; 0183 } 0184 0185 allTypeComments[type.comment()] += 1; 0186 } 0187 0188 for (QStringList::ConstIterator it = types.begin(); it != types.end(); ++it) { 0189 // qDebug() << *it; 0190 const QMimeType type = db.mimeTypeForName(*it); 0191 if (!type.isValid()) { 0192 qCWarning(KIO_KFILEWIDGETS_KFILEFILTERCOMBO) << *it << "is not a valid MIME type"; 0193 continue; 0194 } 0195 0196 if (type.name().startsWith(QLatin1String("all/")) || type.isDefault()) { 0197 hasAllFilesFilter = true; 0198 continue; 0199 } 0200 0201 KFileFilter filter; 0202 0203 if (allTypeComments.value(type.comment()) > 1) { 0204 const QString label = i18nc("%1 is the mimetype name, %2 is the extensions", "%1 (%2)", type.comment(), type.suffixes().join(QLatin1String(", "))); 0205 filter = KFileFilter(label, {}, {*it}); 0206 } else { 0207 filter = KFileFilter::fromMimeType(*it); 0208 } 0209 0210 d->m_fileFilters.append(filter); 0211 addItem(filter.label()); 0212 0213 if (type.name() == defaultType) { 0214 setCurrentIndex(count() - 1); 0215 } 0216 } 0217 0218 if (count() == 1) { 0219 d->m_allTypes = false; 0220 } 0221 0222 if (d->m_allTypes) { 0223 QStringList allTypes; 0224 for (const KFileFilter &filter : std::as_const(d->m_fileFilters)) { 0225 allTypes << filter.mimePatterns().join(QLatin1Char(' ')); 0226 } 0227 0228 KFileFilter allSupportedFilesFilter; 0229 0230 if (count() <= 3) { // show the MIME type comments of at max 3 types 0231 QStringList allComments; 0232 for (const KFileFilter &filter : std::as_const(d->m_fileFilters)) { 0233 allComments << filter.label(); 0234 } 0235 0236 allSupportedFilesFilter = KFileFilter(allComments.join(delim), {}, allTypes); 0237 } else { 0238 allSupportedFilesFilter = KFileFilter(i18n("All Supported Files"), {}, allTypes); 0239 d->m_hasAllSupportedFiles = true; 0240 } 0241 0242 insertItem(0, allSupportedFilesFilter.label()); 0243 d->m_fileFilters.prepend(allSupportedFilesFilter); 0244 setCurrentIndex(0); 0245 } 0246 0247 if (hasAllFilesFilter) { 0248 addItem(i18n("All Files")); 0249 d->m_fileFilters.append(KFileFilter(i18n("All Files"), {}, {QStringLiteral("application/octet-stream")})); 0250 } 0251 0252 d->m_lastFilter = currentText(); 0253 d->m_isMimeFilter = true; 0254 } 0255 0256 void KFileFilterComboPrivate::slotFilterChanged() 0257 { 0258 m_lastFilter = q->currentText(); 0259 } 0260 0261 bool KFileFilterCombo::eventFilter(QObject *o, QEvent *e) 0262 { 0263 if (o == lineEdit() && e->type() == QEvent::FocusOut) { 0264 if (currentText() != d->m_lastFilter) { 0265 Q_EMIT filterChanged(); 0266 } 0267 } 0268 0269 return KComboBox::eventFilter(o, e); 0270 } 0271 0272 void KFileFilterCombo::setDefaultFilter(const QString &filter) 0273 { 0274 d->m_defaultFilter = filter; 0275 } 0276 0277 QString KFileFilterCombo::defaultFilter() const 0278 { 0279 return d->m_defaultFilter; 0280 } 0281 0282 bool KFileFilterCombo::isMimeFilter() const 0283 { 0284 return d->m_isMimeFilter; 0285 } 0286 0287 #include "moc_kfilefiltercombo.cpp"