File indexing completed on 2024-05-12 05:38:20
0001 /* 0002 SPDX-FileCopyrightText: 2008 David Edmundson <kde@davidedmundson.co.uk> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "placesrunner.h" 0008 0009 #include <QCoreApplication> 0010 #include <QTimer> 0011 0012 #include <QDebug> 0013 #include <QIcon> 0014 #include <QMimeData> 0015 #include <QUrl> 0016 0017 #include <KIO/OpenUrlJob> 0018 #include <KLocalizedString> 0019 #include <KNotificationJobUiDelegate> 0020 #include <qttypetraits.h> 0021 0022 K_PLUGIN_CLASS_WITH_JSON(PlacesRunner, "plasma-runner-places.json") 0023 0024 PlacesRunner::PlacesRunner(QObject *parent, const KPluginMetaData &metaData) 0025 : KRunner::AbstractRunner(parent, metaData) 0026 { 0027 addSyntax(i18n("places"), i18n("Lists all file manager locations")); 0028 addSyntax(QStringLiteral(":q:"), i18n("Finds file manager locations that match :q:")); 0029 0030 setMinLetterCount(3); 0031 } 0032 0033 void PlacesRunner::init() 0034 { 0035 Q_ASSERT(!m_places); 0036 m_places = new KFilePlacesModel(this); 0037 connect(m_places, &KFilePlacesModel::setupDone, this, [this](const QModelIndex &index, bool success) { 0038 if (success && m_pendingUdi == m_places->deviceForIndex(index).udi()) { 0039 auto *job = new KIO::OpenUrlJob(m_places->url(index)); 0040 job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoErrorHandlingEnabled)); 0041 job->setRunExecutables(false); 0042 job->start(); 0043 } 0044 m_pendingUdi.clear(); 0045 }); 0046 } 0047 void PlacesRunner::match(KRunner::RunnerContext &context) 0048 { 0049 const QString term = context.query(); 0050 QList<KRunner::QueryMatch> matches; 0051 const bool all = term.compare(i18n("places"), Qt::CaseInsensitive) == 0; 0052 for (int i = 0; i <= m_places->rowCount(); i++) { 0053 QModelIndex current_index = m_places->index(i, 0); 0054 qreal relevance = 0; 0055 0056 const QString text = m_places->text(current_index); 0057 int categoryRelevance = 0; 0058 if ((all && !text.isEmpty()) || text.compare(term, Qt::CaseInsensitive) == 0) { 0059 categoryRelevance = qToUnderlying(KRunner::QueryMatch::CategoryRelevance::Highest); 0060 relevance = all ? 0.9 : 1.0; 0061 } else if (text.contains(term, Qt::CaseInsensitive)) { 0062 categoryRelevance = qToUnderlying(KRunner::QueryMatch::CategoryRelevance::High); 0063 relevance = 0.7; 0064 } else { 0065 continue; 0066 } 0067 0068 KRunner::QueryMatch match(this); 0069 match.setCategoryRelevance(categoryRelevance); 0070 match.setRelevance(relevance); 0071 match.setIcon(m_places->icon(current_index)); 0072 match.setText(text); 0073 0074 // Add category as subtext so one can tell "Pictures" folder from "Search for Pictures" 0075 // Don't add it if it would match the category ("Places") of the runner to avoid "Places: Pictures (Places)" 0076 const QString groupName = m_places->data(current_index, KFilePlacesModel::GroupRole).toString(); 0077 if (!groupName.isEmpty() && name() != groupName) { 0078 match.setSubtext(groupName); 0079 } 0080 0081 // if we have to mount it set the device udi instead of the URL, as we can't open it directly 0082 if (m_places->isDevice(current_index) && m_places->setupNeeded(current_index)) { 0083 const QString udi = m_places->deviceForIndex(current_index).udi(); 0084 match.setId(udi); 0085 match.setData(udi); 0086 } else { 0087 const QUrl url = KFilePlacesModel::convertedUrl(m_places->url(current_index)); 0088 match.setData(url); 0089 match.setUrls({url}); 0090 match.setId(url.toDisplayString()); 0091 } 0092 0093 matches << match; 0094 } 0095 0096 context.addMatches(matches); 0097 } 0098 0099 void PlacesRunner::openDevice(const QString &udi) 0100 { 0101 m_pendingUdi.clear(); 0102 0103 for (int i = 0; i < m_places->rowCount(); ++i) { 0104 const QModelIndex idx = m_places->index(i, 0); 0105 if (m_places->isDevice(idx) && m_places->deviceForIndex(idx).udi() == udi) { 0106 m_pendingUdi = udi; 0107 m_places->requestSetup(idx); 0108 break; 0109 } 0110 } 0111 } 0112 0113 void PlacesRunner::run(const KRunner::RunnerContext & /*context*/, const KRunner::QueryMatch &match) 0114 { 0115 // I don't just pass the model index because the list could change before the user clicks on it, which would make everything go wrong. Ideally we don't want 0116 // things to go wrong. 0117 if (match.data().typeId() == QMetaType::QUrl) { 0118 auto *job = new KIO::OpenUrlJob(match.data().toUrl()); 0119 job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoErrorHandlingEnabled)); 0120 job->setRunExecutables(false); 0121 job->start(); 0122 } else if (match.data().canConvert<QString>()) { 0123 QMetaObject::invokeMethod(this, "openDevice", match.data().toString()); 0124 } 0125 } 0126 0127 #include "placesrunner.moc"