X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/e242d9548d11d92568a648efece5ff6c280b36cd..9616edbb66a8efbdd2bbc9be18e24aaf38a45b59:/src/search/dolphinsearchbox.cpp diff --git a/src/search/dolphinsearchbox.cpp b/src/search/dolphinsearchbox.cpp index ae93030ac..61f5c2db4 100644 --- a/src/search/dolphinsearchbox.cpp +++ b/src/search/dolphinsearchbox.cpp @@ -21,49 +21,47 @@ #include "dolphin_searchsettings.h" #include "dolphinfacetswidget.h" +#include "panels/places/placesitemmodel.h" -#include -#include -#include +#include +#include #include -#include +#include +#ifdef HAVE_BALOO +#include +#include +#endif #include #include -#include -#include +#include #include -#include +#include #include +#include #include #include #include -#include - -#include -#ifdef HAVE_BALOO - #include - #include - #include -#endif +#include DolphinSearchBox::DolphinSearchBox(QWidget* parent) : QWidget(parent), m_startedSearching(false), m_active(true), - m_topLayout(0), - m_searchLabel(0), - m_searchInput(0), - m_optionsScrollArea(0), - m_fileNameButton(0), - m_contentButton(0), - m_separator(0), - m_fromHereButton(0), - m_everywhereButton(0), - m_facetsToggleButton(0), - m_facetsWidget(0), + m_topLayout(nullptr), + m_searchLabel(nullptr), + m_searchInput(nullptr), + m_saveSearchAction(nullptr), + m_optionsScrollArea(nullptr), + m_fileNameButton(nullptr), + m_contentButton(nullptr), + m_separator(nullptr), + m_fromHereButton(nullptr), + m_everywhereButton(nullptr), + m_facetsToggleButton(nullptr), + m_facetsWidget(nullptr), m_searchPath(), - m_startSearchTimer(0) + m_startSearchTimer(nullptr) { } @@ -82,7 +80,7 @@ QString DolphinSearchBox::text() const return m_searchInput->text(); } -void DolphinSearchBox::setSearchPath(const KUrl& url) +void DolphinSearchBox::setSearchPath(const QUrl& url) { m_searchPath = url; @@ -92,9 +90,9 @@ void DolphinSearchBox::setSearchPath(const KUrl& url) QString location = url.fileName(); if (location.isEmpty()) { if (url.isLocalFile()) { - location = QLatin1String("/"); + location = QStringLiteral("/"); } else { - location = url.protocol() + QLatin1String(" - ") + url.host(); + location = url.scheme() + QLatin1String(" - ") + url.host(); } } @@ -114,14 +112,14 @@ void DolphinSearchBox::setSearchPath(const KUrl& url) m_facetsWidget->setEnabled(hasFacetsSupport); } -KUrl DolphinSearchBox::searchPath() const +QUrl DolphinSearchBox::searchPath() const { return m_searchPath; } -KUrl DolphinSearchBox::urlForSearching() const +QUrl DolphinSearchBox::urlForSearching() const { - KUrl url; + QUrl url; bool useBalooSearch = false; #ifdef HAVE_BALOO const Baloo::IndexerConfig searchInfo; @@ -130,10 +128,12 @@ KUrl DolphinSearchBox::urlForSearching() const if (useBalooSearch) { url = balooUrlForSearching(); } else { - url.setProtocol("filenamesearch"); - url.addQueryItem("search", m_searchInput->text()); + url.setScheme(QStringLiteral("filenamesearch")); + + QUrlQuery query; + query.addQueryItem(QStringLiteral("search"), m_searchInput->text()); if (m_contentButton->isChecked()) { - url.addQueryItem("checkContent", "yes"); + query.addQueryItem(QStringLiteral("checkContent"), QStringLiteral("yes")); } QString encodedUrl; @@ -145,21 +145,23 @@ KUrl DolphinSearchBox::urlForSearching() const } else { encodedUrl = m_searchPath.url(); } - url.addQueryItem("url", encodedUrl); + query.addQueryItem(QStringLiteral("url"), encodedUrl); + + url.setQuery(query); } return url; } -void DolphinSearchBox::fromSearchUrl(const KUrl& url) +void DolphinSearchBox::fromSearchUrl(const QUrl& url) { - if (url.protocol() == "baloosearch") { + if (url.scheme() == QLatin1String("baloosearch")) { fromBalooSearchUrl(url); - } else if (url.protocol() == "filenamesearch") { - const QMap& queryItems = url.queryItems(); - setText(queryItems.value("search")); - setSearchPath(queryItems.value("url")); - m_contentButton->setChecked(queryItems.value("checkContent") == "yes"); + } else if (url.scheme() == QLatin1String("filenamesearch")) { + const QUrlQuery query(url); + setText(query.queryItemValue(QStringLiteral("search"))); + setSearchPath(QUrl::fromUserInput(query.queryItemValue(QStringLiteral("url")), QString(), QUrl::AssumeLocalFile)); + m_contentButton->setChecked(query.queryItemValue(QStringLiteral("checkContent")) == QLatin1String("yes")); } else { setText(QString()); setSearchPath(url); @@ -203,6 +205,13 @@ void DolphinSearchBox::showEvent(QShowEvent* event) } } +void DolphinSearchBox::hideEvent(QHideEvent* event) +{ + Q_UNUSED(event); + m_startedSearching = false; + m_startSearchTimer->stop(); +} + void DolphinSearchBox::keyReleaseEvent(QKeyEvent* event) { QWidget::keyReleaseEvent(event); @@ -219,8 +228,17 @@ bool DolphinSearchBox::eventFilter(QObject* obj, QEvent* event) { switch (event->type()) { case QEvent::FocusIn: - setActive(true); - setFocus(); + // #379135: we get the FocusIn event when we close a tab but we don't want to emit + // the activated() signal before the removeTab() call in DolphinTabWidget::closeTab() returns. + // To avoid this issue, we delay the activation of the search box. + // We also don't want to schedule the activation process if we are already active, + // otherwise we can enter in a loop of FocusIn/FocusOut events with the searchbox of another tab. + if (!isActive()) { + QTimer::singleShot(0, this, [this] { + setActive(true); + setFocus(); + }); + } break; default: @@ -234,6 +252,7 @@ void DolphinSearchBox::emitSearchRequest() { m_startSearchTimer->stop(); m_startedSearching = true; + m_saveSearchAction->setEnabled(true); emit searchRequest(); } @@ -241,6 +260,7 @@ void DolphinSearchBox::emitCloseRequest() { m_startSearchTimer->stop(); m_startedSearching = false; + m_saveSearchAction->setEnabled(false); emit closeRequest(); } @@ -254,6 +274,7 @@ void DolphinSearchBox::slotConfigurationChanged() void DolphinSearchBox::slotSearchTextChanged(const QString& text) { + if (text.isEmpty()) { m_startSearchTimer->stop(); } else { @@ -262,10 +283,10 @@ void DolphinSearchBox::slotSearchTextChanged(const QString& text) emit searchTextChanged(text); } -void DolphinSearchBox::slotReturnPressed(const QString& text) +void DolphinSearchBox::slotReturnPressed() { emitSearchRequest(); - emit returnPressed(text); + emit returnPressed(); } void DolphinSearchBox::slotFacetsButtonToggled() @@ -282,6 +303,18 @@ void DolphinSearchBox::slotFacetChanged() emit searchRequest(); } +void DolphinSearchBox::slotSearchSaved() +{ + const QUrl searchURL = urlForSearching(); + if (searchURL.isValid()) { + PlacesItemModel model; + const QString label = i18n("Search for %1 in %2", text(), searchPath().fileName()); + model.createPlacesItem(label, + searchURL, + QStringLiteral("folder-saved-search-symbolic")); + } +} + void DolphinSearchBox::initButton(QToolButton* button) { button->installEventFilter(this); @@ -310,10 +343,10 @@ void DolphinSearchBox::loadSettings() void DolphinSearchBox::saveSettings() { - SearchSettings::setLocation(m_fromHereButton->isChecked() ? "FromHere" : "Everywhere"); - SearchSettings::setWhat(m_fileNameButton->isChecked() ? "FileName" : "Content"); + SearchSettings::setLocation(m_fromHereButton->isChecked() ? QStringLiteral("FromHere") : QStringLiteral("Everywhere")); + SearchSettings::setWhat(m_fileNameButton->isChecked() ? QStringLiteral("FileName") : QStringLiteral("Content")); SearchSettings::setShowFacetsWidget(m_facetsToggleButton->isChecked()); - SearchSettings::self()->writeConfig(); + SearchSettings::self()->save(); } void DolphinSearchBox::init() @@ -321,7 +354,7 @@ void DolphinSearchBox::init() // Create close button QToolButton* closeButton = new QToolButton(this); closeButton->setAutoRaise(true); - closeButton->setIcon(KIcon("dialog-close")); + closeButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-close"))); closeButton->setToolTip(i18nc("@info:tooltip", "Quit searching")); connect(closeButton, &QToolButton::clicked, this, &DolphinSearchBox::emitCloseRequest); @@ -329,15 +362,23 @@ void DolphinSearchBox::init() m_searchLabel = new QLabel(this); // Create search box - m_searchInput = new KLineEdit(this); + m_searchInput = new QLineEdit(this); m_searchInput->installEventFilter(this); - m_searchInput->setClearButtonShown(true); - m_searchInput->setFont(KGlobalSettings::generalFont()); - setFocusProxy(m_searchInput); - connect(m_searchInput, static_cast(&KLineEdit::returnPressed), + m_searchInput->setClearButtonEnabled(true); + m_searchInput->setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); + connect(m_searchInput, &QLineEdit::returnPressed, this, &DolphinSearchBox::slotReturnPressed); - connect(m_searchInput, &KLineEdit::textChanged, + connect(m_searchInput, &QLineEdit::textChanged, this, &DolphinSearchBox::slotSearchTextChanged); + setFocusProxy(m_searchInput); + + // Add "Save search" button inside search box + m_saveSearchAction = new QAction(this); + m_saveSearchAction->setIcon (QIcon::fromTheme(QStringLiteral("document-save-symbolic"))); + m_saveSearchAction->setText(i18nc("action:button", "Save this search to quickly access it again in the future")); + m_saveSearchAction->setEnabled(false); + m_searchInput->addAction(m_saveSearchAction, QLineEdit::TrailingPosition); + connect(m_saveSearchAction, &QAction::triggered, this, &DolphinSearchBox::slotSearchSaved); // Apply layout for the search input QHBoxLayout* searchInputLayout = new QHBoxLayout(); @@ -374,6 +415,20 @@ void DolphinSearchBox::init() searchLocationGroup->addButton(m_fromHereButton); searchLocationGroup->addButton(m_everywhereButton); + auto moreSearchToolsButton = new QToolButton(this); + moreSearchToolsButton->setAutoRaise(true); + moreSearchToolsButton->setPopupMode(QToolButton::InstantPopup); + moreSearchToolsButton->setIcon(QIcon::fromTheme("arrow-down-double")); + moreSearchToolsButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + moreSearchToolsButton->setText(i18n("More Search Tools")); + moreSearchToolsButton->setMenu(new QMenu(this)); + connect(moreSearchToolsButton->menu(), &QMenu::aboutToShow, moreSearchToolsButton->menu(), [this, moreSearchToolsButton]() + { + m_menuFactory.reset(new KMoreToolsMenuFactory("dolphin/search-tools")); + moreSearchToolsButton->menu()->clear(); + m_menuFactory->fillMenuFromGroupingNames(moreSearchToolsButton->menu(), { "files-find" }, this->m_searchPath); + } ); + // Create "Facets" widgets m_facetsToggleButton = new QToolButton(this); m_facetsToggleButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); @@ -393,8 +448,10 @@ void DolphinSearchBox::init() optionsLayout->addWidget(m_separator); optionsLayout->addWidget(m_fromHereButton); optionsLayout->addWidget(m_everywhereButton); - optionsLayout->addStretch(1); + optionsLayout->addWidget(new KSeparator(Qt::Vertical, this)); optionsLayout->addWidget(m_facetsToggleButton); + optionsLayout->addWidget(moreSearchToolsButton); + optionsLayout->addStretch(1); // Put the options into a QScrollArea. This prevents increasing the view width // in case that not enough width for the options is available. @@ -428,73 +485,67 @@ void DolphinSearchBox::init() updateFacetsToggleButton(); } -KUrl DolphinSearchBox::balooUrlForSearching() const +QUrl DolphinSearchBox::balooUrlForSearching() const { #ifdef HAVE_BALOO const QString text = m_searchInput->text(); Baloo::Query query; - query.addType("File"); query.addType(m_facetsWidget->facetType()); - Baloo::Term term(Baloo::Term::And); - - Baloo::Term ratingTerm = m_facetsWidget->ratingTerm(); - if (ratingTerm.isValid()) { - term.addSubTerm(ratingTerm); + QStringList queryStrings; + QString ratingQuery = m_facetsWidget->ratingTerm(); + if (!ratingQuery.isEmpty()) { + queryStrings << ratingQuery; } if (m_contentButton->isChecked()) { - query.setSearchString(text); + queryStrings << text; } else if (!text.isEmpty()) { - term.addSubTerm(Baloo::Term(QLatin1String("filename"), text)); + queryStrings << QStringLiteral("filename:\"%1\"").arg(text); } if (m_fromHereButton->isChecked()) { - query.addCustomOption("includeFolder", m_searchPath.toLocalFile()); + query.setIncludeFolder(m_searchPath.toLocalFile()); } - query.setTerm(term); + query.setSearchString(queryStrings.join(QStringLiteral(" "))); return query.toSearchUrl(i18nc("@title UDS_DISPLAY_NAME for a KIO directory listing. %1 is the query the user entered.", "Query Results from '%1'", text)); #else - return KUrl(); + return QUrl(); #endif } -void DolphinSearchBox::fromBalooSearchUrl(const KUrl& url) +void DolphinSearchBox::fromBalooSearchUrl(const QUrl& url) { #ifdef HAVE_BALOO const Baloo::Query query = Baloo::Query::fromSearchUrl(url); - const Baloo::Term term = query.term(); // Block all signals to avoid unnecessary "searchRequest" signals // while we adjust the search text and the facet widget. blockSignals(true); - const QVariantMap customOptions = query.customOptions(); - if (customOptions.contains("includeFolder")) { - setSearchPath(customOptions.value("includeFolder").toString()); + const QString customDir = query.includeFolder(); + if (!customDir.isEmpty()) { + setSearchPath(QUrl::fromLocalFile(customDir)); } else { - setSearchPath(QDir::homePath()); + setSearchPath(QUrl::fromLocalFile(QDir::homePath())); } - if (!query.searchString().isEmpty()) { - setText(query.searchString()); - } + setText(query.searchString()); QStringList types = query.types(); - types.removeOne("File"); // We are only interested in facet widget types if (!types.isEmpty()) { m_facetsWidget->setFacetType(types.first()); } - foreach (const Baloo::Term& subTerm, term.subTerms()) { - const QString property = subTerm.property(); - - if (property == QLatin1String("filename")) { - setText(subTerm.value().toString()); + const QStringList subTerms = query.searchString().split(' ', QString::SkipEmptyParts); + foreach (const QString& subTerm, subTerms) { + if (subTerm.startsWith(QLatin1String("filename:"))) { + const QString value = subTerm.mid(9); + setText(value); } else if (m_facetsWidget->isRatingTerm(subTerm)) { m_facetsWidget->setRatingTerm(subTerm); } @@ -502,6 +553,8 @@ void DolphinSearchBox::fromBalooSearchUrl(const KUrl& url) m_startSearchTimer->stop(); blockSignals(false); +#else + Q_UNUSED(url); #endif } @@ -509,7 +562,7 @@ void DolphinSearchBox::updateFacetsToggleButton() { const bool facetsIsVisible = SearchSettings::showFacetsWidget(); m_facetsToggleButton->setChecked(facetsIsVisible ? true : false); - m_facetsToggleButton->setIcon(KIcon(facetsIsVisible ? "arrow-up-double" : "arrow-down-double")); + m_facetsToggleButton->setIcon(QIcon::fromTheme(facetsIsVisible ? QStringLiteral("arrow-up-double") : QStringLiteral("arrow-down-double"))); m_facetsToggleButton->setText(facetsIsVisible ? i18nc("action:button", "Fewer Options") : i18nc("action:button", "More Options")); }