File indexing completed on 2024-04-28 15:29:42
0001 /* 0002 SPDX-FileCopyrightText: 2006-2007 Aaron Seigo <aseigo@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "abstractrunner.h" 0008 0009 #ifndef KSERVICE_BUILD_DEPRECATED_SINCE 0010 #define KSERVICE_BUILD_DEPRECATED_SINCE(a, b) 0 0011 #endif 0012 0013 #include "abstractrunner_p.h" 0014 0015 #include <QAction> 0016 #include <QElapsedTimer> 0017 #include <QHash> 0018 #include <QMimeData> 0019 #include <QMutex> 0020 0021 #include <KConfigGroup> 0022 #include <KLocalizedString> 0023 #include <KSharedConfig> 0024 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 65) 0025 #include <Plasma/Package> 0026 #endif 0027 0028 #include "krunner_debug.h" 0029 0030 namespace Plasma 0031 { 0032 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 77) 0033 AbstractRunner::AbstractRunner(QObject *parent, const QString &path) 0034 : QObject(parent) 0035 , d(new AbstractRunnerPrivate(this)) 0036 { 0037 d->init(path); 0038 } 0039 #endif 0040 0041 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 86) 0042 AbstractRunner::AbstractRunner(const KPluginMetaData &pluginMetaData, QObject *parent) 0043 : QObject(parent) 0044 , d(new AbstractRunnerPrivate(this)) 0045 { 0046 d->init(pluginMetaData); 0047 } 0048 #endif 0049 0050 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 72) && KSERVICE_BUILD_DEPRECATED_SINCE(5, 0) 0051 AbstractRunner::AbstractRunner(const KService::Ptr service, QObject *parent) 0052 : QObject(parent) 0053 , d(new AbstractRunnerPrivate(this)) 0054 { 0055 d->init(service); 0056 } 0057 #endif 0058 0059 AbstractRunner::AbstractRunner(QObject *parent, const KPluginMetaData &pluginMetaData, const QVariantList &args) 0060 : QObject(parent) 0061 , d(new AbstractRunnerPrivate(this)) 0062 { 0063 Q_UNUSED(args) 0064 0065 d->init(pluginMetaData); 0066 } 0067 0068 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 77) 0069 AbstractRunner::AbstractRunner(QObject *parent, const QVariantList &args) 0070 : QObject(parent) 0071 , d(new AbstractRunnerPrivate(this)) 0072 { 0073 if (!args.isEmpty()) { 0074 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 72) && KSERVICE_BUILD_DEPRECATED_SINCE(5, 0) 0075 // backward-compatible support has metadata only as second argument 0076 // which we prefer of course 0077 if (args.size() > 1) { 0078 const KPluginMetaData metaData = args[1].value<KPluginMetaData>(); 0079 #else 0080 const KPluginMetaData metaData = args[0].value<KPluginMetaData>(); 0081 #endif 0082 if (metaData.isValid()) { 0083 d->init(metaData); 0084 return; 0085 } 0086 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 72) && KSERVICE_BUILD_DEPRECATED_SINCE(5, 0) 0087 } 0088 0089 KService::Ptr service = KService::serviceByStorageId(args[0].toString()); 0090 if (service) { 0091 d->init(service); 0092 } 0093 #endif 0094 } 0095 } 0096 #endif 0097 0098 AbstractRunner::~AbstractRunner() = default; 0099 0100 KConfigGroup AbstractRunner::config() const 0101 { 0102 QString group = id(); 0103 if (group.isEmpty()) { 0104 group = QStringLiteral("UnnamedRunner"); 0105 } 0106 0107 KConfigGroup runners(KSharedConfig::openConfig(QStringLiteral("krunnerrc")), "Runners"); 0108 return KConfigGroup(&runners, group); 0109 } 0110 0111 void AbstractRunner::reloadConfiguration() 0112 { 0113 } 0114 0115 void AbstractRunner::addSyntax(const RunnerSyntax &syntax) 0116 { 0117 d->syntaxes.append(syntax); 0118 } 0119 0120 bool AbstractRunner::hasUniqueResults() 0121 { 0122 return d->hasUniqueResults; 0123 } 0124 0125 bool AbstractRunner::hasWeakResults() 0126 { 0127 return d->hasWeakResults; 0128 } 0129 0130 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 76) 0131 void AbstractRunner::setDefaultSyntax(const RunnerSyntax &syntax) 0132 { 0133 d->syntaxes.append(syntax); 0134 d->defaultSyntax = &(d->syntaxes.last()); 0135 } 0136 #endif 0137 0138 void AbstractRunner::setSyntaxes(const QList<RunnerSyntax> &syntaxes) 0139 { 0140 d->syntaxes = syntaxes; 0141 } 0142 0143 QList<RunnerSyntax> AbstractRunner::syntaxes() const 0144 { 0145 return d->syntaxes; 0146 } 0147 0148 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 76) 0149 RunnerSyntax *AbstractRunner::defaultSyntax() const 0150 { 0151 return d->defaultSyntax; 0152 } 0153 #endif 0154 0155 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 81) 0156 void AbstractRunner::performMatch(Plasma::RunnerContext &localContext) 0157 { 0158 static const int reasonableRunTime = 1500; 0159 static const int fastEnoughTime = 250; 0160 0161 QElapsedTimer time; 0162 time.start(); 0163 0164 // The local copy is already obtained in the job 0165 match(localContext); 0166 0167 // automatically rate limit runners that become slooow 0168 const int runtime = time.elapsed(); 0169 bool slowed = speed() == SlowSpeed; 0170 0171 if (!slowed && runtime > reasonableRunTime) { 0172 // we punish runners that return too slowly, even if they don't bring 0173 // back matches 0174 d->fastRuns = 0; 0175 setSpeed(SlowSpeed); 0176 } 0177 0178 if (slowed && runtime < fastEnoughTime && localContext.query().size() > 2) { 0179 ++d->fastRuns; 0180 0181 if (d->fastRuns > 2) { 0182 // we reward slowed runners who bring back matches fast enough 0183 // 3 times in a row 0184 setSpeed(NormalSpeed); 0185 } 0186 } 0187 } 0188 #endif 0189 0190 QList<QAction *> AbstractRunner::actionsForMatch(const Plasma::QueryMatch &match) 0191 { 0192 return match.isValid() ? match.actions() : QList<QAction *>(); 0193 } 0194 0195 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 86) 0196 QAction *AbstractRunner::addAction(const QString &id, const QIcon &icon, const QString &text) 0197 { 0198 QAction *a = new QAction(icon, text, this); 0199 d->actions.insert(id, a); 0200 return a; 0201 } 0202 0203 void AbstractRunner::addAction(const QString &id, QAction *action) 0204 { 0205 d->actions.insert(id, action); 0206 } 0207 0208 void AbstractRunner::removeAction(const QString &id) 0209 { 0210 QAction *a = d->actions.take(id); 0211 delete a; 0212 } 0213 0214 QAction *AbstractRunner::action(const QString &id) const 0215 { 0216 return d->actions.value(id); 0217 } 0218 0219 QHash<QString, QAction *> AbstractRunner::actions() const 0220 { 0221 return d->actions; 0222 } 0223 0224 void AbstractRunner::clearActions() 0225 { 0226 qDeleteAll(d->actions); 0227 d->actions.clear(); 0228 } 0229 #endif 0230 0231 QMimeData *AbstractRunner::mimeDataForMatch(const QueryMatch &match) 0232 { 0233 if (match.urls().isEmpty()) { 0234 return nullptr; 0235 } 0236 QMimeData *result = new QMimeData(); 0237 result->setUrls(match.urls()); 0238 return result; 0239 } 0240 0241 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 71) 0242 bool AbstractRunner::hasRunOptions() 0243 { 0244 return d->hasRunOptions; 0245 } 0246 #endif 0247 0248 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 71) 0249 void AbstractRunner::setHasRunOptions(bool hasRunOptions) 0250 { 0251 d->hasRunOptions = hasRunOptions; 0252 } 0253 #endif 0254 0255 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 71) 0256 void AbstractRunner::createRunOptions(QWidget *parent) 0257 { 0258 Q_UNUSED(parent) 0259 } 0260 #endif 0261 0262 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 81) 0263 AbstractRunner::Speed AbstractRunner::speed() const 0264 { 0265 // the only time the read lock will fail is if we were slow are going to speed up 0266 // or if we were fast and are going to slow down; so don't wait in this case, just 0267 // say we're slow. we either will be soon or were just a moment ago and it doesn't 0268 // hurt to do one more run the slow way 0269 if (!d->speedLock.tryLockForRead()) { 0270 return SlowSpeed; 0271 } 0272 Speed s = d->speed; 0273 d->speedLock.unlock(); 0274 return s; 0275 } 0276 #endif 0277 0278 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 81) 0279 void AbstractRunner::setSpeed(Speed speed) 0280 { 0281 d->speedLock.lockForWrite(); 0282 d->speed = speed; 0283 d->speedLock.unlock(); 0284 } 0285 #endif 0286 0287 AbstractRunner::Priority AbstractRunner::priority() const 0288 { 0289 return d->priority; 0290 } 0291 0292 void AbstractRunner::setPriority(Priority priority) 0293 { 0294 d->priority = priority; 0295 } 0296 0297 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 76) 0298 RunnerContext::Types AbstractRunner::ignoredTypes() const 0299 { 0300 return d->blackListed; 0301 } 0302 #endif 0303 0304 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 76) 0305 void AbstractRunner::setIgnoredTypes(RunnerContext::Types types) 0306 { 0307 d->blackListed = types; 0308 } 0309 #endif 0310 0311 void AbstractRunner::run(const Plasma::RunnerContext &search, const Plasma::QueryMatch &action) 0312 { 0313 Q_UNUSED(search); 0314 Q_UNUSED(action); 0315 } 0316 0317 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 76) 0318 QStringList AbstractRunner::categories() const 0319 { 0320 return QStringList() << name(); 0321 } 0322 #endif 0323 0324 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 76) 0325 QIcon AbstractRunner::categoryIcon(const QString &) const 0326 { 0327 return icon(); 0328 } 0329 #endif 0330 0331 void AbstractRunner::match(Plasma::RunnerContext &) 0332 { 0333 } 0334 0335 QString AbstractRunner::name() const 0336 { 0337 if (d->runnerDescription.isValid()) { 0338 return d->runnerDescription.name(); 0339 } 0340 0341 return objectName(); 0342 } 0343 0344 QIcon AbstractRunner::icon() const 0345 { 0346 if (d->runnerDescription.isValid()) { 0347 return QIcon::fromTheme(d->runnerDescription.iconName()); 0348 } 0349 0350 return QIcon(); 0351 } 0352 0353 QString AbstractRunner::id() const 0354 { 0355 if (d->runnerDescription.isValid()) { 0356 return d->runnerDescription.pluginId(); 0357 } 0358 0359 return objectName(); 0360 } 0361 0362 QString AbstractRunner::description() const 0363 { 0364 if (d->runnerDescription.isValid()) { 0365 return d->runnerDescription.description(); 0366 } 0367 0368 return objectName(); 0369 } 0370 0371 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 72) 0372 KPluginInfo AbstractRunner::metadata() const 0373 { 0374 QT_WARNING_PUSH 0375 QT_WARNING_DISABLE_DEPRECATED 0376 return KPluginInfo::fromMetaData(d->runnerDescription); 0377 QT_WARNING_POP 0378 } 0379 #endif 0380 0381 KPluginMetaData AbstractRunner::metadata(RunnerReturnPluginMetaDataConstant) const 0382 { 0383 return d->runnerDescription; 0384 } 0385 0386 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 65) 0387 Package AbstractRunner::package() const 0388 { 0389 QT_WARNING_PUSH 0390 QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations") 0391 QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations") 0392 return Package(); 0393 QT_WARNING_POP 0394 } 0395 #endif 0396 0397 void AbstractRunner::init() 0398 { 0399 reloadConfiguration(); 0400 } 0401 0402 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 73) 0403 DataEngine *AbstractRunner::dataEngine(const QString &name) const 0404 { 0405 return d->dataEngine(name); 0406 } 0407 #endif 0408 0409 bool AbstractRunner::isMatchingSuspended() const 0410 { 0411 return d->suspendMatching; 0412 } 0413 0414 void AbstractRunner::suspendMatching(bool suspend) 0415 { 0416 if (d->suspendMatching == suspend) { 0417 return; 0418 } 0419 0420 d->suspendMatching = suspend; 0421 Q_EMIT matchingSuspended(suspend); 0422 } 0423 0424 int AbstractRunner::minLetterCount() const 0425 { 0426 return d->minLetterCount; 0427 } 0428 0429 void AbstractRunner::setMinLetterCount(int count) 0430 { 0431 d->minLetterCount = count; 0432 } 0433 0434 QRegularExpression AbstractRunner::matchRegex() const 0435 { 0436 return d->matchRegex; 0437 } 0438 0439 void AbstractRunner::setMatchRegex(const QRegularExpression ®ex) 0440 { 0441 d->matchRegex = regex; 0442 d->hasMatchRegex = regex.isValid() && !regex.pattern().isEmpty(); 0443 } 0444 0445 void AbstractRunner::setTriggerWords(const QStringList &triggerWords) 0446 { 0447 int minTriggerWordLetters = 0; 0448 QString constructedRegex = QStringLiteral("^"); 0449 for (const QString &triggerWord : triggerWords) { 0450 // We want to link them with an or 0451 if (constructedRegex.length() > 1) { 0452 constructedRegex += QLatin1Char('|'); 0453 } 0454 constructedRegex += QRegularExpression::escape(triggerWord); 0455 if (minTriggerWordLetters == 0 || triggerWord.length() < minTriggerWordLetters) { 0456 minTriggerWordLetters = triggerWord.length(); 0457 } 0458 } 0459 // If we can reject the query because of the length we don't need the regex 0460 setMinLetterCount(minTriggerWordLetters); 0461 QRegularExpression regex(constructedRegex); 0462 setMatchRegex(regex); 0463 } 0464 0465 bool AbstractRunner::hasMatchRegex() const 0466 { 0467 return d->hasMatchRegex; 0468 } 0469 0470 AbstractRunnerPrivate::AbstractRunnerPrivate(AbstractRunner *r) 0471 : priority(AbstractRunner::NormalPriority) 0472 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 81) 0473 , speed(AbstractRunner::NormalSpeed) 0474 #endif 0475 , blackListed(RunnerContext::None) 0476 , runner(r) 0477 , fastRuns(0) 0478 , defaultSyntax(nullptr) 0479 , hasRunOptions(false) 0480 , suspendMatching(false) 0481 { 0482 } 0483 0484 AbstractRunnerPrivate::~AbstractRunnerPrivate() 0485 { 0486 } 0487 0488 void AbstractRunnerPrivate::init() 0489 { 0490 minLetterCount = runnerDescription.value(QStringLiteral("X-Plasma-Runner-Min-Letter-Count"), 0); 0491 if (runnerDescription.isValid()) { 0492 const auto rawData = runnerDescription.rawData(); 0493 if (rawData.contains(QStringLiteral("X-Plasma-Runner-Match-Regex"))) { 0494 matchRegex = QRegularExpression(rawData.value(QStringLiteral("X-Plasma-Runner-Match-Regex")).toString()); 0495 hasMatchRegex = matchRegex.isValid() && !matchRegex.pattern().isEmpty(); 0496 } 0497 hasUniqueResults = runnerDescription.value(QStringLiteral("X-Plasma-Runner-Unique-Results"), false); 0498 hasWeakResults = runnerDescription.value(QStringLiteral("X-Plasma-Runner-Weak-Results"), false); 0499 } 0500 } 0501 0502 void AbstractRunnerPrivate::init(const KPluginMetaData &pluginMetaData) 0503 { 0504 runnerDescription = pluginMetaData; 0505 init(); 0506 } 0507 0508 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 72) && KSERVICE_BUILD_DEPRECATED_SINCE(5, 0) 0509 void AbstractRunnerPrivate::init(const KService::Ptr service) 0510 { 0511 QT_WARNING_PUSH 0512 QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations") 0513 QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations") 0514 const KPluginInfo pluginInfo(service); 0515 runnerDescription = pluginInfo.isValid() ? pluginInfo.toMetaData() : KPluginMetaData(); 0516 QT_WARNING_POP 0517 init(); 0518 } 0519 #endif 0520 0521 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 77) 0522 void AbstractRunnerPrivate::init(const QString &path) 0523 { 0524 runnerDescription = KPluginMetaData(path + QStringLiteral("/metadata.desktop")); 0525 init(); 0526 } 0527 #endif 0528 0529 } // Plasma namespace 0530 0531 #include "moc_abstractrunner.cpp"