From d08a61343cde25ddb061c58289b495ec6c9c601f Mon Sep 17 00:00:00 2001 From: Baris Date: Mon, 4 Aug 2025 03:29:40 +0200 Subject: [PATCH 01/13] fix(unifiedsearch): open folder or file requested via traymenu-searchbar directly and locally Signed-off-by: Baris --- src/gui/tray/UnifiedSearchResultListItem.qml | 2 +- .../tray/unifiedsearchresultslistmodel.cpp | 55 +++++++++++++------ src/gui/tray/unifiedsearchresultslistmodel.h | 2 +- test/testunifiedsearchlistmodel.cpp | 2 +- 4 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/gui/tray/UnifiedSearchResultListItem.qml b/src/gui/tray/UnifiedSearchResultListItem.qml index 7e8935484369c..9df1bfb567f1f 100644 --- a/src/gui/tray/UnifiedSearchResultListItem.qml +++ b/src/gui/tray/UnifiedSearchResultListItem.qml @@ -68,7 +68,7 @@ MouseArea { if (isFetchMoreTrigger) { unifiedSearchResultMouseArea.fetchMoreTriggerClicked(model.providerId) } else { - unifiedSearchResultMouseArea.resultClicked(model.providerId, model.resourceUrlRole) + unifiedSearchResultMouseArea.resultClicked(model.providerId, model.resourceUrlRole, model.subline, model.resultTitle) } } } diff --git a/src/gui/tray/unifiedsearchresultslistmodel.cpp b/src/gui/tray/unifiedsearchresultslistmodel.cpp index 5a6ac2ad97d69..9d71a41839126 100644 --- a/src/gui/tray/unifiedsearchresultslistmodel.cpp +++ b/src/gui/tray/unifiedsearchresultslistmodel.cpp @@ -324,29 +324,48 @@ bool UnifiedSearchResultsListModel::isSearchInProgress() const return !_searchJobConnections.isEmpty(); } -void UnifiedSearchResultsListModel::resultClicked(const QString &providerId, const QUrl &resourceUrl) const +void UnifiedSearchResultsListModel::resultClicked( + const QString &providerId, const QUrl &resourceUrl, const QString &subline, const QString &title +) const { - const QUrlQuery urlQuery{resourceUrl}; - const auto dir = urlQuery.queryItemValue(QStringLiteral("dir"), QUrl::ComponentFormattingOption::FullyDecoded); - const auto fileName = - urlQuery.queryItemValue(QStringLiteral("scrollto"), QUrl::ComponentFormattingOption::FullyDecoded); - - if (providerId.contains(QStringLiteral("file"), Qt::CaseInsensitive) && !dir.isEmpty() && !fileName.isEmpty()) { - if (!_accountState || !_accountState->account()) { - return; + if (_accountState == nullptr || _accountState->account() == nullptr || !providerId.contains(QStringLiteral("file"), Qt::CaseInsensitive)) { + qCInfo(lcUnifiedSearch) << "immediately returning from resultClicked"; + return; + } + + const QUrlQuery urlQuery{resourceUrl}; + QString dir = urlQuery.queryItemValue(QStringLiteral("dir"), QUrl::ComponentFormattingOption::FullyDecoded); + QString fileName = urlQuery.queryItemValue(QStringLiteral("scrollto"), QUrl::ComponentFormattingOption::FullyDecoded); + + QString relativePath; + // server version above 20 + if (dir.isEmpty() && fileName.isEmpty() && !title.isEmpty()) { + if (!subline.isEmpty()) { + dir = subline; + dir.remove(0,3); + fileName = QLatin1Char('/') + title; } + else { + dir = title; + } + relativePath = dir + fileName; + } + // server version 20 + else { + relativePath = dir + QLatin1Char('/') + fileName; + } - const QString relativePath = dir + QLatin1Char('/') + fileName; - const auto localFiles = - FolderMan::instance()->findFileInLocalFolders(QFileInfo(relativePath).path(), _accountState->account()); + qCInfo(lcUnifiedSearch) << "relativePath: " << relativePath; + const QStringList localFiles = FolderMan::instance()->findFileInLocalFolders(relativePath, _accountState->account()); - if (!localFiles.isEmpty()) { - qCInfo(lcUnifiedSearch) << "Opening file:" << localFiles.constFirst(); - QDesktopServices::openUrl(QUrl::fromLocalFile(localFiles.constFirst())); - return; - } + if (!localFiles.isEmpty()) { + qCInfo(lcUnifiedSearch) << "Opening requested file or folder locally:" << localFiles.constFirst(); + QDesktopServices::openUrl(QUrl::fromLocalFile(localFiles.constFirst())); + } + else { + qCInfo(lcUnifiedSearch) << "Opening requested file or folder in webbrowser: " << localFiles.constFirst(); + Utility::openBrowser(resourceUrl); } - Utility::openBrowser(resourceUrl); } void UnifiedSearchResultsListModel::fetchMoreTriggerClicked(const QString &providerId) diff --git a/src/gui/tray/unifiedsearchresultslistmodel.h b/src/gui/tray/unifiedsearchresultslistmodel.h index a2c07eb651fab..b014adf53a140 100644 --- a/src/gui/tray/unifiedsearchresultslistmodel.h +++ b/src/gui/tray/unifiedsearchresultslistmodel.h @@ -71,7 +71,7 @@ class UnifiedSearchResultsListModel : public QAbstractListModel [[nodiscard]] QString errorString() const; [[nodiscard]] bool waitingForSearchTermEditEnd() const; - Q_INVOKABLE void resultClicked(const QString &providerId, const QUrl &resourceUrl) const; + Q_INVOKABLE void resultClicked(const QString &providerId, const QUrl &resourceUrl, const QString &subline, const QString &title) const; Q_INVOKABLE void fetchMoreTriggerClicked(const QString &providerId); [[nodiscard]] QHash roleNames() const override; diff --git a/test/testunifiedsearchlistmodel.cpp b/test/testunifiedsearchlistmodel.cpp index ed948d2a3993d..e913182c2e929 100644 --- a/test/testunifiedsearchlistmodel.cpp +++ b/test/testunifiedsearchlistmodel.cpp @@ -581,7 +581,7 @@ private slots: urlForClickedResult = model->data(model->index(i), OCC::UnifiedSearchResultsListModel::DataRole::ResourceUrlRole).toString(); if (!providerId.isEmpty() && !urlForClickedResult.isEmpty()) { - model->resultClicked(providerId, QUrl(urlForClickedResult)); + model->resultClicked(providerId, QUrl(urlForClickedResult), "dummyStringNeedToFix", "dummyStringNeedToFix"); break; } } From ac8b2bef2305f768af4ebac1071f37735ea75e60 Mon Sep 17 00:00:00 2001 From: Baris Date: Mon, 4 Aug 2025 03:29:40 +0200 Subject: [PATCH 02/13] fix(unifiedsearch): open folder or file requested via traymenu-searchbar directly and locally Signed-off-by: Baris --- .../tray/unifiedsearchresultslistmodel.cpp | 71 ++++++++++--------- test/testunifiedsearchlistmodel.cpp | 19 +++-- 2 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/gui/tray/unifiedsearchresultslistmodel.cpp b/src/gui/tray/unifiedsearchresultslistmodel.cpp index 9d71a41839126..ec964e41c6904 100644 --- a/src/gui/tray/unifiedsearchresultslistmodel.cpp +++ b/src/gui/tray/unifiedsearchresultslistmodel.cpp @@ -324,48 +324,49 @@ bool UnifiedSearchResultsListModel::isSearchInProgress() const return !_searchJobConnections.isEmpty(); } + void UnifiedSearchResultsListModel::resultClicked( const QString &providerId, const QUrl &resourceUrl, const QString &subline, const QString &title ) const { - if (_accountState == nullptr || _accountState->account() == nullptr || !providerId.contains(QStringLiteral("file"), Qt::CaseInsensitive)) { - qCInfo(lcUnifiedSearch) << "immediately returning from resultClicked"; - return; - } - - const QUrlQuery urlQuery{resourceUrl}; - QString dir = urlQuery.queryItemValue(QStringLiteral("dir"), QUrl::ComponentFormattingOption::FullyDecoded); - QString fileName = urlQuery.queryItemValue(QStringLiteral("scrollto"), QUrl::ComponentFormattingOption::FullyDecoded); - - QString relativePath; - // server version above 20 - if (dir.isEmpty() && fileName.isEmpty() && !title.isEmpty()) { - if (!subline.isEmpty()) { - dir = subline; - dir.remove(0,3); - fileName = QLatin1Char('/') + title; - } - else { - dir = title; - } - relativePath = dir + fileName; - } - // server version 20 - else { - relativePath = dir + QLatin1Char('/') + fileName; - } + const QUrlQuery urlQuery{resourceUrl}; + QString dir = urlQuery.queryItemValue(QStringLiteral("dir"), QUrl::ComponentFormattingOption::FullyDecoded); + QString fileName = urlQuery.queryItemValue(QStringLiteral("scrollto"), QUrl::ComponentFormattingOption::FullyDecoded); - qCInfo(lcUnifiedSearch) << "relativePath: " << relativePath; - const QStringList localFiles = FolderMan::instance()->findFileInLocalFolders(relativePath, _accountState->account()); + if (providerId.contains(QStringLiteral("file"), Qt::CaseInsensitive)){ + if (_accountState == nullptr || _accountState->account() == nullptr) { + return; + } - if (!localFiles.isEmpty()) { - qCInfo(lcUnifiedSearch) << "Opening requested file or folder locally:" << localFiles.constFirst(); - QDesktopServices::openUrl(QUrl::fromLocalFile(localFiles.constFirst())); - } - else { - qCInfo(lcUnifiedSearch) << "Opening requested file or folder in webbrowser: " << localFiles.constFirst(); - Utility::openBrowser(resourceUrl); + QString relativePath; + // server version above 20 + if (dir.isEmpty() && fileName.isEmpty()) { + // file is direct child of syncfolder + if (subline.isEmpty()) { + dir = title; + } + else { + dir = subline.split(' ', Qt::SkipEmptyParts).last(); + fileName = QLatin1Char('/') + title; + } + } + // server version 20 + else if (dir.length() > 1) { + fileName.prepend(QLatin1Char('/')); + } + relativePath = dir + fileName; + + const QStringList localFiles = FolderMan::instance()->findFileInLocalFolders(relativePath, _accountState->account()); + if (!localFiles.isEmpty()) { + qCInfo(lcUnifiedSearch) << "Opening file: " << localFiles.constFirst(); + const bool fileOpenedLocally = QDesktopServices::openUrl(QUrl::fromLocalFile(localFiles.constFirst())); + if (fileOpenedLocally) { + return; + } + qCWarning(lcUnifiedSearch) << "Warning: QDesktopServices::openUrl unexpectedly failed to open the file. Opening resourceUrl in web browser is attempted next."; + } } + Utility::openBrowser(resourceUrl); } void UnifiedSearchResultsListModel::fetchMoreTriggerClicked(const QString &providerId) diff --git a/test/testunifiedsearchlistmodel.cpp b/test/testunifiedsearchlistmodel.cpp index e913182c2e929..23d417b65a571 100644 --- a/test/testunifiedsearchlistmodel.cpp +++ b/test/testunifiedsearchlistmodel.cpp @@ -274,12 +274,12 @@ FakeSearchResultsStorage *FakeSearchResultsStorage::_instance = nullptr; } -class TestUnifiedSearchListmodel : public QObject +class TestUnifiedSearchListModel : public QObject { Q_OBJECT public: - TestUnifiedSearchListmodel() = default; + TestUnifiedSearchListModel() = default; QScopedPointer fakeQnam; OCC::AccountPtr account; @@ -575,13 +575,22 @@ private slots: const auto type = model->data(model->index(i), OCC::UnifiedSearchResultsListModel::DataRole::TypeRole); if (type == OCC::UnifiedSearchResult::Type::Default) { - const auto providerId = + const QString providerId = model->data(model->index(i), OCC::UnifiedSearchResultsListModel::DataRole::ProviderIdRole) .toString(); + + const QString subline = + model->data(model->index(i), OCC::UnifiedSearchResultsListModel::DataRole::SublineRole) + .toString(); + + const QString title = + model->data(model->index(i), OCC::UnifiedSearchResultsListModel::DataRole::TitleRole) + .toString(); + urlForClickedResult = model->data(model->index(i), OCC::UnifiedSearchResultsListModel::DataRole::ResourceUrlRole).toString(); if (!providerId.isEmpty() && !urlForClickedResult.isEmpty()) { - model->resultClicked(providerId, QUrl(urlForClickedResult), "dummyStringNeedToFix", "dummyStringNeedToFix"); + model->resultClicked(providerId, QUrl(urlForClickedResult), subline, title); break; } } @@ -632,5 +641,5 @@ private slots: } }; -QTEST_MAIN(TestUnifiedSearchListmodel) +QTEST_MAIN(TestUnifiedSearchListModel) #include "testunifiedsearchlistmodel.moc" From 744619d5b84a3c9305c01a8eb5a7b146f553b579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F?= <90838023+barisbasar1209@users.noreply.github.com> Date: Mon, 25 Aug 2025 19:59:58 +0200 Subject: [PATCH 03/13] Update src/gui/tray/unifiedsearchresultslistmodel.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthieu Gallien Signed-off-by: Barış <90838023+barisbasar1209@users.noreply.github.com> --- src/gui/tray/unifiedsearchresultslistmodel.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gui/tray/unifiedsearchresultslistmodel.cpp b/src/gui/tray/unifiedsearchresultslistmodel.cpp index ec964e41c6904..b9530423ed180 100644 --- a/src/gui/tray/unifiedsearchresultslistmodel.cpp +++ b/src/gui/tray/unifiedsearchresultslistmodel.cpp @@ -344,8 +344,7 @@ void UnifiedSearchResultsListModel::resultClicked( // file is direct child of syncfolder if (subline.isEmpty()) { dir = title; - } - else { + } else { dir = subline.split(' ', Qt::SkipEmptyParts).last(); fileName = QLatin1Char('/') + title; } From 7ec6a645ad73062b6b49486f3d9cadb5ad6a14d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F?= <90838023+barisbasar1209@users.noreply.github.com> Date: Mon, 25 Aug 2025 20:00:42 +0200 Subject: [PATCH 04/13] Update src/gui/tray/unifiedsearchresultslistmodel.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthieu Gallien Signed-off-by: Barış <90838023+barisbasar1209@users.noreply.github.com> --- src/gui/tray/unifiedsearchresultslistmodel.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/gui/tray/unifiedsearchresultslistmodel.cpp b/src/gui/tray/unifiedsearchresultslistmodel.cpp index b9530423ed180..acb8de2662960 100644 --- a/src/gui/tray/unifiedsearchresultslistmodel.cpp +++ b/src/gui/tray/unifiedsearchresultslistmodel.cpp @@ -325,9 +325,10 @@ bool UnifiedSearchResultsListModel::isSearchInProgress() const } -void UnifiedSearchResultsListModel::resultClicked( - const QString &providerId, const QUrl &resourceUrl, const QString &subline, const QString &title -) const +void UnifiedSearchResultsListModel::resultClicked(const QString &providerId, + const QUrl &resourceUrl, + const QString &subline, + const QString &title) const { const QUrlQuery urlQuery{resourceUrl}; QString dir = urlQuery.queryItemValue(QStringLiteral("dir"), QUrl::ComponentFormattingOption::FullyDecoded); From 5f704454ba5bb3124a7ef6e45326595e8f49846e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F?= <90838023+barisbasar1209@users.noreply.github.com> Date: Mon, 25 Aug 2025 20:00:56 +0200 Subject: [PATCH 05/13] Update test/testunifiedsearchlistmodel.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthieu Gallien Signed-off-by: Barış <90838023+barisbasar1209@users.noreply.github.com> --- test/testunifiedsearchlistmodel.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/testunifiedsearchlistmodel.cpp b/test/testunifiedsearchlistmodel.cpp index 23d417b65a571..15dbac8f8ea82 100644 --- a/test/testunifiedsearchlistmodel.cpp +++ b/test/testunifiedsearchlistmodel.cpp @@ -575,15 +575,15 @@ private slots: const auto type = model->data(model->index(i), OCC::UnifiedSearchResultsListModel::DataRole::TypeRole); if (type == OCC::UnifiedSearchResult::Type::Default) { - const QString providerId = + const auto providerId = model->data(model->index(i), OCC::UnifiedSearchResultsListModel::DataRole::ProviderIdRole) .toString(); - const QString subline = + const auto subline = model->data(model->index(i), OCC::UnifiedSearchResultsListModel::DataRole::SublineRole) .toString(); - const QString title = + const auto title = model->data(model->index(i), OCC::UnifiedSearchResultsListModel::DataRole::TitleRole) .toString(); From 738220263938feb6aedb9f0d1183ffb01d3a9618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F?= <90838023+barisbasar1209@users.noreply.github.com> Date: Mon, 25 Aug 2025 20:02:23 +0200 Subject: [PATCH 06/13] Update src/gui/tray/unifiedsearchresultslistmodel.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthieu Gallien Signed-off-by: Barış <90838023+barisbasar1209@users.noreply.github.com> --- src/gui/tray/unifiedsearchresultslistmodel.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/tray/unifiedsearchresultslistmodel.cpp b/src/gui/tray/unifiedsearchresultslistmodel.cpp index acb8de2662960..1e1d0636b27c8 100644 --- a/src/gui/tray/unifiedsearchresultslistmodel.cpp +++ b/src/gui/tray/unifiedsearchresultslistmodel.cpp @@ -362,8 +362,9 @@ void UnifiedSearchResultsListModel::resultClicked(const QString &providerId, const bool fileOpenedLocally = QDesktopServices::openUrl(QUrl::fromLocalFile(localFiles.constFirst())); if (fileOpenedLocally) { return; + } else { + qCWarning(lcUnifiedSearch) << "Warning: QDesktopServices::openUrl unexpectedly failed to open the file. Opening resourceUrl in web browser is attempted next."; } - qCWarning(lcUnifiedSearch) << "Warning: QDesktopServices::openUrl unexpectedly failed to open the file. Opening resourceUrl in web browser is attempted next."; } } Utility::openBrowser(resourceUrl); From bb1c3daeadff6ca40ab15b37ce18212c629e1876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F?= <90838023+barisbasar1209@users.noreply.github.com> Date: Mon, 25 Aug 2025 20:03:54 +0200 Subject: [PATCH 07/13] Update src/gui/tray/unifiedsearchresultslistmodel.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthieu Gallien Signed-off-by: Barış <90838023+barisbasar1209@users.noreply.github.com> --- src/gui/tray/unifiedsearchresultslistmodel.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gui/tray/unifiedsearchresultslistmodel.cpp b/src/gui/tray/unifiedsearchresultslistmodel.cpp index 1e1d0636b27c8..ab7acb9ee1d76 100644 --- a/src/gui/tray/unifiedsearchresultslistmodel.cpp +++ b/src/gui/tray/unifiedsearchresultslistmodel.cpp @@ -349,9 +349,8 @@ void UnifiedSearchResultsListModel::resultClicked(const QString &providerId, dir = subline.split(' ', Qt::SkipEmptyParts).last(); fileName = QLatin1Char('/') + title; } - } + } else if (dir.length() > 1) { // server version 20 - else if (dir.length() > 1) { fileName.prepend(QLatin1Char('/')); } relativePath = dir + fileName; From 74b790477ed952c93faf63755860e41aef8aec0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F?= <90838023+barisbasar1209@users.noreply.github.com> Date: Mon, 25 Aug 2025 20:04:08 +0200 Subject: [PATCH 08/13] Update src/gui/tray/unifiedsearchresultslistmodel.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthieu Gallien Signed-off-by: Barış <90838023+barisbasar1209@users.noreply.github.com> --- src/gui/tray/unifiedsearchresultslistmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/tray/unifiedsearchresultslistmodel.cpp b/src/gui/tray/unifiedsearchresultslistmodel.cpp index ab7acb9ee1d76..07ff3d332aa2d 100644 --- a/src/gui/tray/unifiedsearchresultslistmodel.cpp +++ b/src/gui/tray/unifiedsearchresultslistmodel.cpp @@ -358,7 +358,7 @@ void UnifiedSearchResultsListModel::resultClicked(const QString &providerId, const QStringList localFiles = FolderMan::instance()->findFileInLocalFolders(relativePath, _accountState->account()); if (!localFiles.isEmpty()) { qCInfo(lcUnifiedSearch) << "Opening file: " << localFiles.constFirst(); - const bool fileOpenedLocally = QDesktopServices::openUrl(QUrl::fromLocalFile(localFiles.constFirst())); + const auto fileOpenedLocally = QDesktopServices::openUrl(QUrl::fromLocalFile(localFiles.constFirst())); if (fileOpenedLocally) { return; } else { From a252e407e5f21f9526a0bed0f083ac416c3cf825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F?= <90838023+barisbasar1209@users.noreply.github.com> Date: Mon, 25 Aug 2025 20:04:27 +0200 Subject: [PATCH 09/13] Update src/gui/tray/unifiedsearchresultslistmodel.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthieu Gallien Signed-off-by: Barış <90838023+barisbasar1209@users.noreply.github.com> --- src/gui/tray/unifiedsearchresultslistmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/tray/unifiedsearchresultslistmodel.cpp b/src/gui/tray/unifiedsearchresultslistmodel.cpp index 07ff3d332aa2d..34e2dc16d033a 100644 --- a/src/gui/tray/unifiedsearchresultslistmodel.cpp +++ b/src/gui/tray/unifiedsearchresultslistmodel.cpp @@ -355,7 +355,7 @@ void UnifiedSearchResultsListModel::resultClicked(const QString &providerId, } relativePath = dir + fileName; - const QStringList localFiles = FolderMan::instance()->findFileInLocalFolders(relativePath, _accountState->account()); + const auto localFiles = FolderMan::instance()->findFileInLocalFolders(relativePath, _accountState->account()); if (!localFiles.isEmpty()) { qCInfo(lcUnifiedSearch) << "Opening file: " << localFiles.constFirst(); const auto fileOpenedLocally = QDesktopServices::openUrl(QUrl::fromLocalFile(localFiles.constFirst())); From 2f7bebc9c8faf6c2c85af8b2d0c8c98c93e2493c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F?= <90838023+barisbasar1209@users.noreply.github.com> Date: Mon, 25 Aug 2025 20:05:03 +0200 Subject: [PATCH 10/13] Update src/gui/tray/unifiedsearchresultslistmodel.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthieu Gallien Signed-off-by: Barış <90838023+barisbasar1209@users.noreply.github.com> --- src/gui/tray/unifiedsearchresultslistmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/tray/unifiedsearchresultslistmodel.cpp b/src/gui/tray/unifiedsearchresultslistmodel.cpp index 34e2dc16d033a..f8b18bff3f071 100644 --- a/src/gui/tray/unifiedsearchresultslistmodel.cpp +++ b/src/gui/tray/unifiedsearchresultslistmodel.cpp @@ -335,7 +335,7 @@ void UnifiedSearchResultsListModel::resultClicked(const QString &providerId, QString fileName = urlQuery.queryItemValue(QStringLiteral("scrollto"), QUrl::ComponentFormattingOption::FullyDecoded); if (providerId.contains(QStringLiteral("file"), Qt::CaseInsensitive)){ - if (_accountState == nullptr || _accountState->account() == nullptr) { + if (!_accountState || !_accountState->account()) { return; } From 0ea557d7cadff98cb66b0d08b0b5350ba341160b Mon Sep 17 00:00:00 2001 From: Baris Date: Mon, 25 Aug 2025 20:15:04 +0200 Subject: [PATCH 11/13] Update src/gui/tray/unifiedsearchresultslistmodel.cpp Signed-off-by: Baris --- src/gui/tray/unifiedsearchresultslistmodel.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/gui/tray/unifiedsearchresultslistmodel.cpp b/src/gui/tray/unifiedsearchresultslistmodel.cpp index f8b18bff3f071..f1ce286b98163 100644 --- a/src/gui/tray/unifiedsearchresultslistmodel.cpp +++ b/src/gui/tray/unifiedsearchresultslistmodel.cpp @@ -331,15 +331,14 @@ void UnifiedSearchResultsListModel::resultClicked(const QString &providerId, const QString &title) const { const QUrlQuery urlQuery{resourceUrl}; - QString dir = urlQuery.queryItemValue(QStringLiteral("dir"), QUrl::ComponentFormattingOption::FullyDecoded); - QString fileName = urlQuery.queryItemValue(QStringLiteral("scrollto"), QUrl::ComponentFormattingOption::FullyDecoded); + auto dir = urlQuery.queryItemValue(QStringLiteral("dir"), QUrl::ComponentFormattingOption::FullyDecoded); + auto fileName = urlQuery.queryItemValue(QStringLiteral("scrollto"), QUrl::ComponentFormattingOption::FullyDecoded); if (providerId.contains(QStringLiteral("file"), Qt::CaseInsensitive)){ if (!_accountState || !_accountState->account()) { return; } - QString relativePath; // server version above 20 if (dir.isEmpty() && fileName.isEmpty()) { // file is direct child of syncfolder @@ -353,7 +352,7 @@ void UnifiedSearchResultsListModel::resultClicked(const QString &providerId, // server version 20 fileName.prepend(QLatin1Char('/')); } - relativePath = dir + fileName; + const auto relativePath = dir + fileName; const auto localFiles = FolderMan::instance()->findFileInLocalFolders(relativePath, _accountState->account()); if (!localFiles.isEmpty()) { From 3cc9dd180adb67ea33d69e09170aa9ce91ae7031 Mon Sep 17 00:00:00 2001 From: Mike Mengjie Huang Date: Sat, 30 Aug 2025 05:08:32 +0200 Subject: [PATCH 12/13] test(unifiedsearch): Add tests for resultClicked method Signed-off-by: Mike Mengjie Huang --- src/gui/folderman.h | 2 + test/testunifiedsearchlistmodel.cpp | 238 ++++++++++++++++++++-------- 2 files changed, 175 insertions(+), 65 deletions(-) diff --git a/src/gui/folderman.h b/src/gui/folderman.h index bf3775ad115cb..5b80bd70dc57f 100644 --- a/src/gui/folderman.h +++ b/src/gui/folderman.h @@ -27,6 +27,7 @@ class ShareTestHelper; class EndToEndTestHelper; class TestSyncConflictsModel; class TestRemoteWipe; +class TestUnifiedSearchListModel; namespace OCC { @@ -415,6 +416,7 @@ private slots: friend class ::EndToEndTestHelper; friend class ::TestFolderStatusModel; friend class ::TestRemoteWipe; + friend class ::TestUnifiedSearchListModel; }; } // namespace OCC diff --git a/test/testunifiedsearchlistmodel.cpp b/test/testunifiedsearchlistmodel.cpp index 15dbac8f8ea82..78263ac42fd5b 100644 --- a/test/testunifiedsearchlistmodel.cpp +++ b/test/testunifiedsearchlistmodel.cpp @@ -7,7 +7,9 @@ #include "account.h" #include "accountstate.h" +#include "folderman.h" #include "syncenginetestutils.h" +#include "testhelper.h" #include #include @@ -30,7 +32,8 @@ class FakeDesktopServicesUrlHandler : public QObject public: signals: - void resultClicked(const QUrl &url); + void resultClickedBrowser(const QUrl &url); + void resultClickedLocalFile(const QUrl &url); }; /** @@ -278,6 +281,8 @@ class TestUnifiedSearchListModel : public QObject { Q_OBJECT + std::unique_ptr _folderMan; + public: TestUnifiedSearchListModel() = default; @@ -305,6 +310,7 @@ private slots: account->setUrl(QUrl(("http://example.de"))); accountState.reset(new OCC::AccountState(account)); + _folderMan.reset(new OCC::FolderMan{}); fakeQnam->setOverride([this](QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *device) { Q_UNUSED(device); @@ -538,71 +544,173 @@ private slots: } } - void testSearchResultlicked() + void testSearchResultClicked() { - // make sure the model is empty - model->setSearchTerm(QStringLiteral("")); - QVERIFY(model->rowCount() == 0); - - // test that search term gets set, search gets started and enough results get returned - model->setSearchTerm(model->searchTerm() + QStringLiteral("discuss")); - - QSignalSpy searchInProgressChanged( - model.data(), &OCC::UnifiedSearchResultsListModel::isSearchInProgressChanged); - - QVERIFY(searchInProgressChanged.wait()); - - // make sure search has started - QCOMPARE(searchInProgressChanged.count(), 1); - QVERIFY(model->isSearchInProgress()); - - QVERIFY(searchInProgressChanged.wait()); - - // make sure search has finished and some results has been received - QVERIFY(!model->isSearchInProgress()); - - QVERIFY(model->rowCount() != 0); - - QDesktopServices::setUrlHandler("http", fakeDesktopServicesUrlHandler.data(), "resultClicked"); - QDesktopServices::setUrlHandler("https", fakeDesktopServicesUrlHandler.data(), "resultClicked"); - - QSignalSpy resultClicked(fakeDesktopServicesUrlHandler.data(), &FakeDesktopServicesUrlHandler::resultClicked); - - // test click on a result item - QString urlForClickedResult; - - for (int i = 0; i < model->rowCount(); ++i) { - const auto type = model->data(model->index(i), OCC::UnifiedSearchResultsListModel::DataRole::TypeRole); - - if (type == OCC::UnifiedSearchResult::Type::Default) { - const auto providerId = - model->data(model->index(i), OCC::UnifiedSearchResultsListModel::DataRole::ProviderIdRole) - .toString(); - - const auto subline = - model->data(model->index(i), OCC::UnifiedSearchResultsListModel::DataRole::SublineRole) - .toString(); - - const auto title = - model->data(model->index(i), OCC::UnifiedSearchResultsListModel::DataRole::TitleRole) - .toString(); - - urlForClickedResult = model->data(model->index(i), OCC::UnifiedSearchResultsListModel::DataRole::ResourceUrlRole).toString(); - - if (!providerId.isEmpty() && !urlForClickedResult.isEmpty()) { - model->resultClicked(providerId, QUrl(urlForClickedResult), subline, title); - break; - } - } - } - - QCOMPARE(resultClicked.count(), 1); - - const auto arguments = resultClicked.takeFirst(); - - const auto urlOpenTriggeredViaDesktopServices = arguments.at(0).toString(); - - QCOMPARE(urlOpenTriggeredViaDesktopServices, urlForClickedResult); + QDesktopServices::setUrlHandler("http", fakeDesktopServicesUrlHandler.data(), "resultClickedBrowser"); + QDesktopServices::setUrlHandler("https", fakeDesktopServicesUrlHandler.data(), "resultClickedBrowser"); + QDesktopServices::setUrlHandler("file", fakeDesktopServicesUrlHandler.data(), "resultClickedLocalFile"); + + QSignalSpy resultClickedBrowser(fakeDesktopServicesUrlHandler.data(), &FakeDesktopServicesUrlHandler::resultClickedBrowser); + QSignalSpy resultClickedLocalFile(fakeDesktopServicesUrlHandler.data(), &FakeDesktopServicesUrlHandler::resultClickedLocalFile); + + // Setup folder structure for further tests + FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()}; + const auto localFolderPrefix = "file:///" + fakeFolder.localPath(); + auto folderDef = folderDefinition(fakeFolder.localPath()); + folderDef.targetPath = ""; + const auto folder = OCC::FolderMan::instance()->addFolder(accountState.data(), folderDef); + QVERIFY(folder); + + // Provider IDs which are not files, will be opened in the browser + const auto providerIdTestProviderId = "settings_apps"; + const auto sublineTestProviderId = "John Doe in Apps"; + const auto titleTestProviderId = " We had a discussion about Apps already. But, let's have a follow up tomorrow afternoon."; + const auto resourceUrlTestProviderId = "http://example.de/call/abcde12345#message_12345"; + model->resultClicked(providerIdTestProviderId, + QUrl(resourceUrlTestProviderId), sublineTestProviderId, titleTestProviderId); + + QCOMPARE(resultClickedBrowser.count(), 1); + QCOMPARE(resultClickedLocalFile.count(), 0); + + auto arguments = resultClickedBrowser.takeFirst(); + auto urlOpenTriggeredViaDesktopServices = arguments.at(0).toString(); + QCOMPARE(urlOpenTriggeredViaDesktopServices, resourceUrlTestProviderId); + + resultClickedBrowser.clear(); + resultClickedLocalFile.clear(); + + // Nextcloud 20 opens in browser if the folder is not available locally + const auto providerIdTestNextcloud20Browser = "file"; + const auto sublineTestNextcloud20Browser = "in folder/nested/searched_file.cpp"; + const auto titleTestNextcloud20Browser = "searched_file.cpp"; + const auto resourceUrlTestNextcloud20Browser = "http://example.de/files/?dir=folder/nested&scrollto=searched_file.cpp"; + model->resultClicked(providerIdTestNextcloud20Browser, + QUrl(resourceUrlTestNextcloud20Browser), sublineTestNextcloud20Browser, titleTestNextcloud20Browser); + + QCOMPARE(resultClickedBrowser.count(), 1); + QCOMPARE(resultClickedLocalFile.count(), 0); + + arguments = resultClickedBrowser.takeFirst(); + urlOpenTriggeredViaDesktopServices = arguments.at(0).toString(); + QCOMPARE(urlOpenTriggeredViaDesktopServices, resourceUrlTestNextcloud20Browser); + + resultClickedBrowser.clear(); + resultClickedLocalFile.clear(); + + // Nextcloud versions above 20 opens in browser if the folder is not available locally + const auto providerIdTestNextcloudAbove20Browser = "file"; + const auto sublineTestNextcloudAbove20Browser = "in folder/nested"; + const auto titleTestNextcloudAbove20Browser = "searched_file.cpp"; + const auto resourceUrlTestNextcloudAbove20Browser = "http://example.de/index.php/f/123"; + model->resultClicked(providerIdTestNextcloudAbove20Browser, + QUrl(resourceUrlTestNextcloudAbove20Browser), sublineTestNextcloudAbove20Browser, + titleTestNextcloudAbove20Browser); + + QCOMPARE(resultClickedBrowser.count(), 1); + QCOMPARE(resultClickedLocalFile.count(), 0); + + arguments = resultClickedBrowser.takeFirst(); + urlOpenTriggeredViaDesktopServices = arguments.at(0).toString(); + QCOMPARE(urlOpenTriggeredViaDesktopServices, resourceUrlTestNextcloudAbove20Browser); + + resultClickedBrowser.clear(); + resultClickedLocalFile.clear(); + + // Nextcloud 20 opens in local files if the file is available locally + const auto providerIdTestNextcloud20LocalFile = "file"; + const auto sublineTestNextcloud20LocalFile = "in B/b1"; + const auto titleTestNextcloud20LocalFile = "b1"; + const auto resourceUrlTestNextcloud20LocalFile = "http://example.de/files/?dir=/B&scrollto=b1"; + const auto expectedFileUrlNextcloud20 = localFolderPrefix + "B/b1"; + model->resultClicked(providerIdTestNextcloud20LocalFile, + QUrl(resourceUrlTestNextcloud20LocalFile), sublineTestNextcloud20LocalFile, titleTestNextcloud20LocalFile); + + QCOMPARE(resultClickedBrowser.count(), 0); + QCOMPARE(resultClickedLocalFile.count(), 1); + + arguments = resultClickedLocalFile.takeFirst(); + urlOpenTriggeredViaDesktopServices = arguments.at(0).toString(); + QCOMPARE(urlOpenTriggeredViaDesktopServices, expectedFileUrlNextcloud20); + + resultClickedBrowser.clear(); + resultClickedLocalFile.clear(); + + // Nextcloud 20 opens in local files if the file is available locally + // The rood directory has a special syntax + const auto providerIdTestNextcloud20LocalFileRoot = "file"; + const auto sublineTestNextcloud20LocalFileRoot = "in B"; + const auto titleTestNextcloud20LocalFileRoot = "/B"; + const auto resourceUrlTestNextcloud20LocalFileRoot = "http://example.de/files/?dir=/&scrollto=B"; + const auto expectedFileUrlNextcloud20Root = localFolderPrefix + "B"; + model->resultClicked(providerIdTestNextcloud20LocalFileRoot, + QUrl(resourceUrlTestNextcloud20LocalFileRoot), sublineTestNextcloud20LocalFileRoot, titleTestNextcloud20LocalFileRoot); + + QCOMPARE(resultClickedBrowser.count(), 0); + QCOMPARE(resultClickedLocalFile.count(), 1); + + arguments = resultClickedLocalFile.takeFirst(); + urlOpenTriggeredViaDesktopServices = arguments.at(0).toString(); + QCOMPARE(urlOpenTriggeredViaDesktopServices, expectedFileUrlNextcloud20Root); + + resultClickedBrowser.clear(); + resultClickedLocalFile.clear(); + + // Nextcloud versions above 20 opens in local file if the file is available locally + const auto providerIdTestNextcloudAbove20LocalFile = "file"; + const auto sublineTestNextcloudAbove20LocalFile = "in A"; + const auto titleTestNextcloudAbove20LocalFile = "a1"; + const auto resourceUrlTestNextcloudAbove20LocalFile = "http://example.de/index.php/f/456"; + const auto expectedFileUrlNextcloudAbove20 = localFolderPrefix + "A/a1"; + model->resultClicked(providerIdTestNextcloudAbove20LocalFile, + QUrl(resourceUrlTestNextcloudAbove20LocalFile), sublineTestNextcloudAbove20LocalFile, + titleTestNextcloudAbove20LocalFile); + + QCOMPARE(resultClickedBrowser.count(), 0); + QCOMPARE(resultClickedLocalFile.count(), 1); + + arguments = resultClickedLocalFile.takeFirst(); + urlOpenTriggeredViaDesktopServices = arguments.at(0).toString(); + QCOMPARE(urlOpenTriggeredViaDesktopServices, expectedFileUrlNextcloudAbove20); + + resultClickedBrowser.clear(); + resultClickedLocalFile.clear(); + + // Nextcloud versions above 20 opens in local folder if the file is available locally + // In this case the local folder is opened in the root directory + const auto providerIdTestNextcloudAbove20LocalFileRoot = "file"; + const auto sublineTestNextcloudAbove20LocalFileRoot = ""; + const auto titleTestNextcloudAbove20LocalFileRoot = "A"; + const auto resourceUrlTestNextcloudAbove20LocalFileRoot = "http://example.de/index.php/f/789"; + const auto expectedFileUrlNextcloudAbove20Root = localFolderPrefix + "A"; + model->resultClicked(providerIdTestNextcloudAbove20LocalFileRoot, + QUrl(resourceUrlTestNextcloudAbove20LocalFileRoot), sublineTestNextcloudAbove20LocalFileRoot, + titleTestNextcloudAbove20LocalFileRoot); + + QCOMPARE(resultClickedBrowser.count(), 0); + QCOMPARE(resultClickedLocalFile.count(), 1); + + arguments = resultClickedLocalFile.takeFirst(); + urlOpenTriggeredViaDesktopServices = arguments.at(0).toString(); + QCOMPARE(urlOpenTriggeredViaDesktopServices, expectedFileUrlNextcloudAbove20Root); + + resultClickedBrowser.clear(); + resultClickedLocalFile.clear(); + + // Accountptr is invalid + model.reset(new OCC::UnifiedSearchResultsListModel(nullptr)); + modelTester.reset(new QAbstractItemModelTester(model.data())); + const auto providerIdTestNullptr = "file"; + const auto sublineTestNullptr = ""; + const auto titleTestNullptr = "A"; + const auto resourceUrlTestNullptr = "http://example.de/index.php/f/789"; + model->resultClicked(providerIdTestNullptr, + QUrl(resourceUrlTestNullptr), sublineTestNullptr, titleTestNullptr); + + QCOMPARE(resultClickedBrowser.count(), 0); + QCOMPARE(resultClickedLocalFile.count(), 0); + + resultClickedBrowser.clear(); + resultClickedLocalFile.clear(); } void testSetSearchTermResultsError() From 8ec00aae0314610c4cf9b1518993ed0d45c4fab2 Mon Sep 17 00:00:00 2001 From: Mike Mengjie Huang Date: Sat, 13 Sep 2025 15:40:35 +0200 Subject: [PATCH 13/13] test(unifiedsearch): Restore old account state after test Signed-off-by: Mike Mengjie Huang --- test/testunifiedsearchlistmodel.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/testunifiedsearchlistmodel.cpp b/test/testunifiedsearchlistmodel.cpp index 78263ac42fd5b..2c309e5678023 100644 --- a/test/testunifiedsearchlistmodel.cpp +++ b/test/testunifiedsearchlistmodel.cpp @@ -697,6 +697,7 @@ private slots: resultClickedLocalFile.clear(); // Accountptr is invalid + const auto prevAccountState = accountState.data(); model.reset(new OCC::UnifiedSearchResultsListModel(nullptr)); modelTester.reset(new QAbstractItemModelTester(model.data())); const auto providerIdTestNullptr = "file"; @@ -711,6 +712,9 @@ private slots: resultClickedBrowser.clear(); resultClickedLocalFile.clear(); + + model.reset(new OCC::UnifiedSearchResultsListModel(prevAccountState)); + modelTester.reset(new QAbstractItemModelTester(model.data())); } void testSetSearchTermResultsError()