diff --git a/applets/kicker/plugin/runnermodel.cpp b/applets/kicker/plugin/runnermodel.cpp index 0d7b9178b..22a4016c6 100644 --- a/applets/kicker/plugin/runnermodel.cpp +++ b/applets/kicker/plugin/runnermodel.cpp @@ -1,337 +1,338 @@ /*************************************************************************** * Copyright (C) 2012 by Aurélien Gâteau * * Copyright (C) 2014 by Eike Hein * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "runnermodel.h" #include "runnermatchesmodel.h" #include #include #include #include RunnerModel::RunnerModel(QObject *parent) : QAbstractListModel(parent) , m_favoritesModel(nullptr) , m_appletInterface(nullptr) , m_runnerManager(nullptr) , m_mergeResults(false) , m_deleteWhenEmpty(false) { m_queryTimer.setSingleShot(true); m_queryTimer.setInterval(10); connect(&m_queryTimer, &QTimer::timeout, this, &RunnerModel::startQuery); } RunnerModel::~RunnerModel() { } QHash RunnerModel::roleNames() const { return {{ Qt::DisplayRole, "display" }}; } AbstractModel *RunnerModel::favoritesModel() const { return m_favoritesModel; } void RunnerModel::setFavoritesModel(AbstractModel *model) { if (m_favoritesModel != model) { m_favoritesModel = model; clear(); if (!m_query.isEmpty()) { m_queryTimer.start(); } emit favoritesModelChanged(); } } QObject *RunnerModel::appletInterface() const { return m_appletInterface; } void RunnerModel::setAppletInterface(QObject *appletInterface) { if (m_appletInterface != appletInterface) { m_appletInterface = appletInterface; clear(); if (!m_query.isEmpty()) { m_queryTimer.start(); } emit appletInterfaceChanged(); } } bool RunnerModel::deleteWhenEmpty() const { return m_deleteWhenEmpty; } void RunnerModel::setDeleteWhenEmpty(bool deleteWhenEmpty) { if (m_deleteWhenEmpty != deleteWhenEmpty) { m_deleteWhenEmpty = deleteWhenEmpty; clear(); if (!m_query.isEmpty()) { m_queryTimer.start(); } emit deleteWhenEmptyChanged(); } } bool RunnerModel::mergeResults() const { return m_mergeResults; } void RunnerModel::setMergeResults(bool merge) { if (m_mergeResults != merge) { m_mergeResults = merge; clear(); if (!m_query.isEmpty()) { m_queryTimer.start(); } emit mergeResultsChanged(); } } QVariant RunnerModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() >= m_models.count()) { return QVariant(); } if (role == Qt::DisplayRole) { return m_models.at(index.row())->name(); } return QVariant(); } int RunnerModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : m_models.count(); } int RunnerModel::count() const { return rowCount(); } QObject *RunnerModel::modelForRow(int row) { if (row < 0 || row >= m_models.count()) { return nullptr; } return m_models.at(row); } QStringList RunnerModel::runners() const { return m_runners; } void RunnerModel::setRunners(const QStringList &runners) { if (m_runners.toSet() != runners.toSet()) { m_runners = runners; if (m_runnerManager) { m_runnerManager->setAllowedRunners(runners); } emit runnersChanged(); } } QString RunnerModel::query() const { return m_query; } void RunnerModel::setQuery(const QString &query) { if (m_query != query) { m_query = query; m_queryTimer.start(); emit queryChanged(); } } void RunnerModel::startQuery() { if (m_query.isEmpty()) { clear(); } if (m_query.isEmpty() && m_runnerManager) { return; } createManager(); m_runnerManager->launchQuery(m_query); } void RunnerModel::matchesChanged(const QList &matches) { // Group matches by runner. // We do not use a QMultiHash here because it keeps values in LIFO order, while we want FIFO. QHash > matchesForRunner; foreach (const Plasma::QueryMatch &match, matches) { auto it = matchesForRunner.find(match.runner()->id()); if (it == matchesForRunner.end()) { it = matchesForRunner.insert(match.runner()->id(), QList()); } it.value().append(match); } // Sort matches for all runners in descending order. This allows the best // match to win whilest preserving order between runners. for (auto &list : matchesForRunner) { std::sort(list.begin(), list.end(), qGreater()); } if (m_mergeResults) { RunnerMatchesModel *matchesModel = nullptr; if (m_models.isEmpty()) { matchesModel = new RunnerMatchesModel(QString(), i18n("Search results"), m_runnerManager, this); beginInsertRows(QModelIndex(), 0, 0); m_models.append(matchesModel); endInsertRows(); emit countChanged(); } else { matchesModel = m_models.at(0); } QList matches; foreach (const QString &runnerId, m_runners) { matches.append(matchesForRunner.take(runnerId)); } matchesModel->setMatches(matches); return; } // Assign matches to existing models. If there is no match for a model, delete it. for (int row = m_models.count() - 1; row >= 0; --row) { RunnerMatchesModel *matchesModel = m_models.at(row); QList matches = matchesForRunner.take(matchesModel->runnerId()); if (m_deleteWhenEmpty && matches.isEmpty()) { beginRemoveRows(QModelIndex(), row, row); m_models.removeAt(row); delete matchesModel; endRemoveRows(); emit countChanged(); } else { matchesModel->setMatches(matches); } } // At this point, matchesForRunner contains only matches for runners which // do not have a model yet. Create new models for them. if (!matchesForRunner.isEmpty()) { auto it = matchesForRunner.constBegin(); auto end = matchesForRunner.constEnd(); int appendCount = 0; for (; it != end; ++it) { QList matches = it.value(); Q_ASSERT(!matches.isEmpty()); RunnerMatchesModel *matchesModel = new RunnerMatchesModel(it.key(), matches.first().runner()->name(), m_runnerManager, this); matchesModel->setMatches(matches); if (it.key() == QLatin1String("services")) { beginInsertRows(QModelIndex(), 0, 0); m_models.prepend(matchesModel); endInsertRows(); emit countChanged(); } else { m_models.append(matchesModel); ++appendCount; } } if (appendCount > 0) { beginInsertRows(QModelIndex(), rowCount() - appendCount, rowCount() - 1); endInsertRows(); emit countChanged(); } } } void RunnerModel::createManager() { if (!m_runnerManager) { m_runnerManager = new Plasma::RunnerManager(this); // FIXME: Which KConfigGroup is this using now? m_runnerManager->setAllowedRunners(m_runners); connect(m_runnerManager, &Plasma::RunnerManager::matchesChanged, this, &RunnerModel::matchesChanged); } } void RunnerModel::clear() { if (m_runnerManager) { m_runnerManager->reset(); + m_runnerManager->matchSessionComplete(); } if (m_models.isEmpty()) { return; } beginResetModel(); qDeleteAll(m_models); m_models.clear(); endResetModel(); emit countChanged(); }