File indexing completed on 2024-12-22 05:15:22
0001 /* 0002 SPDX-FileCopyrightText: 2012 Aurélien Gâteau <agateau@kde.org> 0003 SPDX-FileCopyrightText: 2014 Eike Hein <hein@kde.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "runnermodel.h" 0009 #include "runnermatchesmodel.h" 0010 0011 #include <QSet> 0012 0013 #include <KConfigGroup> 0014 #include <KLocalizedString> 0015 #include <KRunner/AbstractRunner> 0016 #include <KRunner/RunnerManager> 0017 #include <chrono> 0018 #include <optional> 0019 0020 using namespace std::chrono_literals; 0021 0022 RunnerModel::RunnerModel(QObject *parent) 0023 : QAbstractListModel(parent) 0024 , m_favoritesModel(nullptr) 0025 , m_appletInterface(nullptr) 0026 , m_mergeResults(false) 0027 , m_krunnerConfig(KSharedConfig::openConfig(QStringLiteral("krunnerrc"))) 0028 { 0029 m_queryTimer.setSingleShot(true); 0030 m_queryTimer.setInterval(10ms); 0031 connect(&m_queryTimer, &QTimer::timeout, this, &RunnerModel::startQuery); 0032 const auto readFavorites = [this]() { 0033 m_favoritePluginIds = m_krunnerConfig 0034 ->group(QStringLiteral("Plugins")) // 0035 .group(QStringLiteral("Favorites")) 0036 .readEntry("plugins", QStringList(QStringLiteral("krunner_services"))); 0037 if (m_mergeResults && !m_models.isEmpty()) { 0038 m_models.constFirst()->setFavoriteIds(m_favoritePluginIds); 0039 } 0040 }; 0041 m_configWatcher = KConfigWatcher::create(m_krunnerConfig); 0042 connect(m_configWatcher.data(), &KConfigWatcher::configChanged, this, readFavorites); 0043 readFavorites(); 0044 } 0045 0046 RunnerModel::~RunnerModel() 0047 { 0048 } 0049 0050 QHash<int, QByteArray> RunnerModel::roleNames() const 0051 { 0052 return {{Qt::DisplayRole, "display"}}; 0053 } 0054 0055 AbstractModel *RunnerModel::favoritesModel() const 0056 { 0057 return m_favoritesModel; 0058 } 0059 0060 void RunnerModel::setFavoritesModel(AbstractModel *model) 0061 { 0062 if (m_favoritesModel != model) { 0063 m_favoritesModel = model; 0064 0065 clear(); 0066 0067 for (auto *model : std::as_const(m_models)) { 0068 model->setFavoritesModel(m_favoritesModel); 0069 } 0070 0071 if (!m_query.isEmpty()) { 0072 m_queryTimer.start(); 0073 } 0074 0075 Q_EMIT favoritesModelChanged(); 0076 } 0077 } 0078 0079 QObject *RunnerModel::appletInterface() const 0080 { 0081 return m_appletInterface; 0082 } 0083 0084 void RunnerModel::setAppletInterface(QObject *appletInterface) 0085 { 0086 if (m_appletInterface != appletInterface) { 0087 m_appletInterface = appletInterface; 0088 0089 clear(); 0090 0091 if (!m_query.isEmpty()) { 0092 m_queryTimer.start(); 0093 } 0094 0095 Q_EMIT appletInterfaceChanged(); 0096 } 0097 } 0098 0099 bool RunnerModel::mergeResults() const 0100 { 0101 return m_mergeResults; 0102 } 0103 0104 void RunnerModel::setMergeResults(bool merge) 0105 { 0106 if (m_mergeResults != merge) { 0107 m_mergeResults = merge; 0108 Q_EMIT mergeResultsChanged(); 0109 0110 // If we haven't lazy-initialzed our models, we do not need to re-create them 0111 if (!m_models.isEmpty()) { 0112 qDeleteAll(m_models); 0113 m_models.clear(); 0114 // Just re-create all models, 0115 initializeModels(); 0116 } 0117 } 0118 } 0119 0120 QVariant RunnerModel::data(const QModelIndex &index, int role) const 0121 { 0122 if (!index.isValid() || index.row() >= m_models.count()) { 0123 return QVariant(); 0124 } 0125 0126 if (role == Qt::DisplayRole) { 0127 return m_models.at(index.row())->name(); 0128 } 0129 0130 return QVariant(); 0131 } 0132 0133 int RunnerModel::rowCount(const QModelIndex &parent) const 0134 { 0135 return parent.isValid() ? 0 : m_models.count(); 0136 } 0137 0138 int RunnerModel::count() const 0139 { 0140 return rowCount(); 0141 } 0142 0143 RunnerMatchesModel *RunnerModel::modelForRow(int row) 0144 { 0145 if (row < 0 || row >= m_models.count()) { 0146 return nullptr; 0147 } 0148 0149 return m_models.at(row); 0150 } 0151 0152 QStringList RunnerModel::runners() const 0153 { 0154 return m_runners; 0155 } 0156 0157 void RunnerModel::setRunners(const QStringList &runners) 0158 { 0159 if (runners == m_runners) { 0160 return; 0161 } 0162 0163 m_runners = runners; 0164 Q_EMIT runnersChanged(); 0165 0166 // Update the existing models only, if we have intialized the models 0167 if (!m_models.isEmpty()) { 0168 if (m_mergeResults) { 0169 Q_ASSERT(m_models.length() == 1); 0170 m_models.constFirst()->runnerManager()->setAllowedRunners(runners); 0171 } else { 0172 // Just re-create all the models, it is an edge-case anyway 0173 qDeleteAll(m_models); 0174 m_models.clear(); 0175 initializeModels(); 0176 } 0177 } 0178 } 0179 0180 QString RunnerModel::query() const 0181 { 0182 return m_query; 0183 } 0184 0185 void RunnerModel::setQuery(const QString &query) 0186 { 0187 if (m_query == query) { 0188 return; // do not init models if the query doesn't change. particularly important during startup! 0189 } 0190 if (m_models.isEmpty()) { 0191 initializeModels(); 0192 } 0193 m_query = query; 0194 m_queryTimer.start(); 0195 Q_EMIT queryChanged(); 0196 } 0197 0198 void RunnerModel::startQuery() 0199 { 0200 if (m_query.isEmpty()) { 0201 clear(); 0202 QTimer::singleShot(0, this, &RunnerModel::queryFinished); 0203 } else { 0204 m_queryingModels = m_models.size(); 0205 for (KRunner::ResultsModel *model : std::as_const(m_models)) { 0206 model->setQueryString(m_query); 0207 } 0208 } 0209 } 0210 0211 void RunnerModel::clear() 0212 { 0213 for (KRunner::ResultsModel *model : std::as_const(m_models)) { 0214 model->clear(); 0215 } 0216 } 0217 0218 void RunnerModel::initializeModels() 0219 { 0220 beginResetModel(); 0221 if (m_mergeResults) { 0222 auto model = new RunnerMatchesModel(QString(), i18n("Search results"), this); 0223 model->runnerManager()->setAllowedRunners(m_runners); 0224 model->setFavoritesModel(m_favoritesModel); 0225 model->setFavoriteIds(m_favoritePluginIds); 0226 m_models.append(model); 0227 } else { 0228 for (const QString &runnerId : std::as_const(m_runners)) { 0229 auto *model = new RunnerMatchesModel(runnerId, std::nullopt, this); 0230 model->setFavoritesModel(m_favoritesModel); 0231 m_models.append(model); 0232 } 0233 } 0234 for (auto model : std::as_const(m_models)) { 0235 connect(model->runnerManager(), &KRunner::RunnerManager::queryFinished, this, [this]() { 0236 if (--m_queryingModels == 0) { 0237 Q_EMIT queryFinished(); 0238 } 0239 }); 0240 } 0241 endResetModel(); 0242 Q_EMIT countChanged(); 0243 }