Commit a458e4c7 authored by Eduardo Cruz's avatar Eduardo Cruz Committed by Nate Graham
Browse files

Avoid sorting old results based on new query input string

`SortProxyModel` reorders the results provided by krunner. It uses the query input string to judge the associated results and sort them. It works great, however we have a little bug that causes a nonsensical list to be shown for the a few milliseconds right after we input a new query string.

At the time `setQueryString()` is called, we still haven't received any matches result list from krunner for this new query. Milou still has the previous query's results, which are completely dissociated from the new query input.

So at this point it was  doing its logic using the old results list from the previous input string, but evaluating them against the newly provided input string, which resulted in bogus behavior.

This example might make it more clear:

1 - We type string "fire" and wait for the query to finish and the final results are displayed. We get this result set:

![Screenshot_20211227_055336](/uploads/3a2711a4f873dd619ab7f0d34bc93135/Screenshot_20211227_055336.png)

2- We type one more letter, "f", so now we have "firef" as input. `SortProxyModel::setQueryString()` would set "firef" as its new `m_words` and it would call its own `invalidate()`, however at this moment the results list for "firef" haven't been provided by krunner yet: Milou still has the results list for "fire", our previous query.

So `SortProxyModel` is processing the results from "fire" using the string "firef" as criteria to judge its sorting, and this results in a quick exhibition of this bogus list to the user. 

This is only shown for 250ms. It took some tries to take a screenshot of it, but here it is:

![Screenshot_20211227_055504](/uploads/de49b9e0ea584f9f90867cff9b1ca704/Screenshot_20211227_055504.png)

As we can see, we have some bogus results like "Command line: run fire" and "System Settings: Firewall" that have no business being there for the input string "firef". They are there because they are still the results from the old "fire" query. Also the ordering is different from the first list since the proxy judged the relevancy in a different manner because it's evaluating that list against the string "firef" and not "fire".

3 - 250ms later, krunner will have provided its results for "firef", and `SortProxyModel` gets in action again, now sanely sorting the "firef" result against its associated "firef" input string, and we get this final correct list:

![Screenshot_20211227_055527](/uploads/af0dce0e73aa62225e2bdc89eabb56ed/Screenshot_20211227_055527.png)

So I fixed it by not calling `SortProxyModel::setQueryString()` anymore when we have a query string change. Now we call it whenever we have a matches result set change. So the `SortProxyModel` will maintain the old query string until we receive the first result set for the new query string. That method's inner logic will detect whenever a true query string change happened and will properly call `invalidate()` when necessary.

With this patch applied, the bogus list in step 2 above will never be generated and it won't be shown to the user.

CCBUG: 427672


(cherry picked from commit 58728acc)
parent aeb419db
Pipeline #134997 passed with stage
in 40 seconds
......@@ -322,7 +322,13 @@ ResultsModel::ResultsModel(QObject *parent)
connect(d->resultsModel, &RunnerResultsModel::queryingChanged, this, &ResultsModel::queryingChanged);
connect(d->resultsModel, &RunnerResultsModel::queryStringChangeRequested, this, &ResultsModel::queryStringChangeRequested);
connect(d->resultsModel, &RunnerResultsModel::queryStringChanged, d->sortModel, &SortProxyModel::setQueryString);
// The matches for the old query string remain on display until the first set of matches arrive for the new query string.
// Therefore we must not update the query string inside RunnerResultsModel exactly when the query string changes, otherwise it would
// re-sort the old query string matches based on the new query string.
// So we only make it aware of the query string change at the time when we receive the first set of matches for the new query string.
connect(d->resultsModel, &RunnerResultsModel::matchesChanged, this, [this]() {
d->sortModel->setQueryString(queryString());
});
connect(d->distributionModel, &CategoryDistributionProxyModel::limitChanged, this, &ResultsModel::limitChanged);
......
......@@ -160,6 +160,8 @@ void RunnerResultsModel::onMatchesChanged(const QList<Plasma::QueryMatch> &match
Q_ASSERT(m_categories.count() == m_matches.count());
m_hasMatches = !m_matches.isEmpty();
Q_EMIT matchesChanged();
}
QString RunnerResultsModel::queryString() const
......
......@@ -60,6 +60,8 @@ public:
Q_SIGNALS:
void queryStringChangeRequested(const QString &queryString, int pos);
void matchesChanged();
private:
void setQuerying(bool querying);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment