File indexing completed on 2024-04-21 03:56:47
0001 /* 0002 SPDX-FileCopyrightText: 2006-2007 Aaron Seigo <aseigo@kde.org> 0003 SPDX-FileCopyrightText: 2020-2023 Alexander Lohnau <alexander.lohnau@gmx.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "abstractrunner.h" 0009 #include "abstractrunner_p.h" 0010 0011 #include <QHash> 0012 #include <QIcon> 0013 #include <QMimeData> 0014 #include <QRegularExpression> 0015 #include <QTimer> 0016 0017 #include <KConfigGroup> 0018 #include <KLocalizedString> 0019 #include <KSharedConfig> 0020 0021 namespace KRunner 0022 { 0023 AbstractRunner::AbstractRunner(QObject *parent, const KPluginMetaData &pluginMetaData) 0024 : QObject(nullptr) 0025 , d(new AbstractRunnerPrivate(this, pluginMetaData)) 0026 { 0027 // By now, runners who do "qobject_cast<Krunner::RunnerManager*>(parent)" should have saved the value 0028 // By setting the parent to a nullptr, we are allowed to move the object to another thread 0029 Q_ASSERT(parent); 0030 setObjectName(pluginMetaData.pluginId()); // Only for debugging purposes 0031 0032 // Suspend matching while we initialize the runner. Once it is ready, the last query will be run 0033 QTimer::singleShot(0, this, [this]() { 0034 init(); 0035 // In case the runner didn't specify anything explicitly, we resume matching after the initialization 0036 bool doesNotHaveExplicitSuspend = true; 0037 { 0038 QReadLocker l(&d->lock); 0039 doesNotHaveExplicitSuspend = !d->suspendMatching.has_value(); 0040 } 0041 if (doesNotHaveExplicitSuspend) { 0042 suspendMatching(false); 0043 } 0044 }); 0045 } 0046 0047 AbstractRunner::~AbstractRunner() = default; 0048 0049 KConfigGroup AbstractRunner::config() const 0050 { 0051 KConfigGroup runners(KSharedConfig::openConfig(QStringLiteral("krunnerrc")), QStringLiteral("Runners")); 0052 return runners.group(id()); 0053 } 0054 0055 void AbstractRunner::reloadConfiguration() 0056 { 0057 } 0058 0059 void AbstractRunner::addSyntax(const RunnerSyntax &syntax) 0060 { 0061 d->syntaxes.append(syntax); 0062 } 0063 0064 void AbstractRunner::setSyntaxes(const QList<RunnerSyntax> &syntaxes) 0065 { 0066 d->syntaxes = syntaxes; 0067 } 0068 0069 QList<RunnerSyntax> AbstractRunner::syntaxes() const 0070 { 0071 return d->syntaxes; 0072 } 0073 0074 QMimeData *AbstractRunner::mimeDataForMatch(const QueryMatch &match) 0075 { 0076 if (match.urls().isEmpty()) { 0077 return nullptr; 0078 } 0079 QMimeData *result = new QMimeData(); 0080 result->setUrls(match.urls()); 0081 return result; 0082 } 0083 0084 void AbstractRunner::run(const KRunner::RunnerContext & /*search*/, const KRunner::QueryMatch & /*action*/) 0085 { 0086 } 0087 0088 QString AbstractRunner::name() const 0089 { 0090 return d->translatedName; 0091 } 0092 0093 QString AbstractRunner::id() const 0094 { 0095 return d->runnerDescription.pluginId(); 0096 } 0097 0098 KPluginMetaData AbstractRunner::metadata() const 0099 { 0100 return d->runnerDescription; 0101 } 0102 0103 void AbstractRunner::init() 0104 { 0105 reloadConfiguration(); 0106 } 0107 0108 bool AbstractRunner::isMatchingSuspended() const 0109 { 0110 QReadLocker lock(&d->lock); 0111 return d->suspendMatching.value_or(true); 0112 } 0113 0114 void AbstractRunner::suspendMatching(bool suspend) 0115 { 0116 QWriteLocker lock(&d->lock); 0117 if (d->suspendMatching.has_value() && d->suspendMatching.value() == suspend) { 0118 return; 0119 } 0120 0121 d->suspendMatching = suspend; 0122 if (!suspend) { 0123 Q_EMIT matchingResumed(); 0124 } 0125 } 0126 0127 int AbstractRunner::minLetterCount() const 0128 { 0129 return d->minLetterCount; 0130 } 0131 0132 void AbstractRunner::setMinLetterCount(int count) 0133 { 0134 d->minLetterCount = count; 0135 } 0136 0137 QRegularExpression AbstractRunner::matchRegex() const 0138 { 0139 return d->matchRegex; 0140 } 0141 0142 void AbstractRunner::setMatchRegex(const QRegularExpression ®ex) 0143 { 0144 d->matchRegex = regex; 0145 d->hasMatchRegex = regex.isValid() && !regex.pattern().isEmpty(); 0146 } 0147 0148 void AbstractRunner::setTriggerWords(const QStringList &triggerWords) 0149 { 0150 int minTriggerWordLetters = 0; 0151 QString constructedRegex = QStringLiteral("^"); 0152 for (const QString &triggerWord : triggerWords) { 0153 // We want to link them with an or 0154 if (constructedRegex.length() > 1) { 0155 constructedRegex += QLatin1Char('|'); 0156 } 0157 constructedRegex += QRegularExpression::escape(triggerWord); 0158 if (minTriggerWordLetters == 0 || triggerWord.length() < minTriggerWordLetters) { 0159 minTriggerWordLetters = triggerWord.length(); 0160 } 0161 } 0162 // If we can reject the query because of the length we don't need the regex 0163 setMinLetterCount(minTriggerWordLetters); 0164 setMatchRegex(QRegularExpression(constructedRegex)); 0165 } 0166 0167 bool AbstractRunner::hasMatchRegex() const 0168 { 0169 return d->hasMatchRegex; 0170 } 0171 0172 void AbstractRunner::matchInternal(KRunner::RunnerContext context) 0173 { 0174 if (context.isValid()) { // Otherwise, we would just waste resources 0175 match(context); 0176 } 0177 Q_EMIT matchInternalFinished(context.runnerJobId(this)); 0178 } 0179 // Suspend the runner while reloading the config 0180 void AbstractRunner::reloadConfigurationInternal() 0181 { 0182 bool isSuspended = isMatchingSuspended(); 0183 suspendMatching(true); 0184 reloadConfiguration(); 0185 suspendMatching(isSuspended); 0186 } 0187 0188 } // KRunner namespace 0189 0190 #include "moc_abstractrunner.cpp"