diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 14701a1f4..617d59480 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,415 +1,416 @@ include(ECMAddAppIcon) configure_file(config-baloo.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-baloo.h) configure_file(config-kactivities.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kactivities.h) configure_file(config-terminal.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-terminal.h) add_definitions( -DTRANSLATION_DOMAIN=\"dolphin\" ) remove_definitions( -DQT_NO_CAST_FROM_BYTEARRAY -DQT_NO_SIGNALS_SLOTS_KEYWORDS -DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII ) ########################################## set(dolphinvcs_LIB_SRCS views/versioncontrol/kversioncontrolplugin.cpp ) add_library(dolphinvcs ${dolphinvcs_LIB_SRCS}) generate_export_header(dolphinvcs BASE_NAME dolphinvcs) target_link_libraries( dolphinvcs PUBLIC Qt5::Widgets ) set_target_properties(dolphinvcs PROPERTIES VERSION ${DOLPHINVCS_VERSION_STRING} SOVERSION ${DOLPHINVCS_SOVERSION} EXPORT_NAME DolphinVcs ) ecm_generate_headers(dolphinvcs_LIB_HEADERS HEADER_NAMES KVersionControlPlugin RELATIVE "views/versioncontrol" REQUIRED_HEADERS dolphinvcs_LIB_HEADERS ) install(TARGETS dolphinvcs EXPORT DolphinVcsTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES views/versioncontrol/fileviewversioncontrolplugin.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dolphinvcs_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR} COMPONENT Devel) install(FILES ${dolphinvcs_LIB_HEADERS} DESTINATION "${KDE_INSTALL_INCLUDEDIR}/Dolphin" COMPONENT Devel) ########### next target ############### set(dolphinprivate_LIB_SRCS kitemviews/kfileitemlistview.cpp kitemviews/kfileitemlistwidget.cpp kitemviews/kfileitemmodel.cpp kitemviews/kfileitemmodelrolesupdater.cpp kitemviews/kitemlistcontainer.cpp kitemviews/kitemlistcontroller.cpp kitemviews/kitemlistgroupheader.cpp kitemviews/kitemlistheader.cpp kitemviews/kitemlistselectionmanager.cpp kitemviews/kitemliststyleoption.cpp kitemviews/kitemlistview.cpp kitemviews/kitemlistviewaccessible.cpp kitemviews/kitemlistwidget.cpp kitemviews/kitemmodelbase.cpp kitemviews/kitemset.cpp kitemviews/kstandarditem.cpp kitemviews/kstandarditemlistgroupheader.cpp kitemviews/kstandarditemlistwidget.cpp kitemviews/kstandarditemlistview.cpp kitemviews/kstandarditemmodel.cpp kitemviews/private/kdirectorycontentscounter.cpp kitemviews/private/kdirectorycontentscounterworker.cpp kitemviews/private/kfileitemclipboard.cpp kitemviews/private/kfileitemmodeldirlister.cpp kitemviews/private/kfileitemmodelfilter.cpp kitemviews/private/kitemlistheaderwidget.cpp kitemviews/private/kitemlistkeyboardsearchmanager.cpp kitemviews/private/kitemlistroleeditor.cpp kitemviews/private/kitemlistrubberband.cpp kitemviews/private/kitemlistselectiontoggle.cpp kitemviews/private/kitemlistsizehintresolver.cpp kitemviews/private/kitemlistsmoothscroller.cpp kitemviews/private/kitemlistviewanimation.cpp kitemviews/private/kitemlistviewlayouter.cpp kitemviews/private/kpixmapmodifier.cpp settings/applyviewpropsjob.cpp settings/viewmodes/viewmodesettings.cpp settings/viewpropertiesdialog.cpp settings/viewpropsprogressinfo.cpp views/dolphinfileitemlistwidget.cpp views/dolphinitemlistview.cpp views/dolphinnewfilemenuobserver.cpp views/dolphinremoteencoding.cpp views/dolphinview.cpp views/dolphinviewactionhandler.cpp views/draganddrophelper.cpp views/renamedialog.cpp views/versioncontrol/updateitemstatesthread.cpp views/versioncontrol/versioncontrolobserver.cpp views/viewmodecontroller.cpp views/viewproperties.cpp views/zoomlevelinfo.cpp dolphinremoveaction.cpp middleclickactioneventfilter.cpp dolphinnewfilemenu.cpp ) ecm_qt_declare_logging_category(dolphinprivate_LIB_SRCS HEADER dolphindebug.h IDENTIFIER DolphinDebug CATEGORY_NAME org.kde.dolphin) if(HAVE_BALOO) set(dolphinprivate_LIB_SRCS ${dolphinprivate_LIB_SRCS} views/tooltips/dolphinfilemetadatawidget.cpp views/tooltips/tooltipmanager.cpp kitemviews/private/kbaloorolesprovider.cpp ) endif() kconfig_add_kcfg_files(dolphinprivate_LIB_SRCS GENERATE_MOC settings/dolphin_compactmodesettings.kcfgc settings/dolphin_directoryviewpropertysettings.kcfgc settings/dolphin_detailsmodesettings.kcfgc settings/dolphin_iconsmodesettings.kcfgc settings/dolphin_generalsettings.kcfgc settings/dolphin_versioncontrolsettings.kcfgc ) add_library(dolphinprivate ${dolphinprivate_LIB_SRCS}) generate_export_header(dolphinprivate BASE_NAME dolphin) target_link_libraries( dolphinprivate PUBLIC dolphinvcs Qt5::Concurrent Qt5::Gui KF5::I18n KF5::IconThemes KF5::KIOCore KF5::KIOWidgets KF5::KIOFileWidgets KF5::Completion KF5::TextWidgets KF5::ConfigCore KF5::NewStuff KF5::Parts KF5::WindowSystem ) if(HAVE_BALOO) target_link_libraries( dolphinprivate PUBLIC KF5::FileMetaData KF5::Baloo KF5::BalooWidgets ) endif() set_target_properties(dolphinprivate PROPERTIES VERSION ${DOLPHINPRIVATE_VERSION_STRING} SOVERSION ${DOLPHINPRIVATE_SOVERSION} ) install(TARGETS dolphinprivate ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dolphin_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR} COMPONENT Devel) ########################################## set(dolphinpart_SRCS dolphinpart.cpp dolphinpart_ext.cpp dolphindebug.cpp ) qt5_add_resources(dolphinpart_SRCS dolphinpart.qrc) add_library(dolphinpart MODULE ${dolphinpart_SRCS}) target_link_libraries(dolphinpart dolphinprivate ) install(TARGETS dolphinpart DESTINATION ${KDE_INSTALL_PLUGINDIR}) install(FILES dolphinpart.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) ########################################## set(dolphinstatic_SRCS dolphinbookmarkhandler.cpp dolphindockwidget.cpp dolphinmainwindow.cpp dolphinviewcontainer.cpp dolphincontextmenu.cpp dolphintabbar.cpp dolphinplacesmodelsingleton.cpp dolphinrecenttabsmenu.cpp dolphintabpage.cpp dolphintabwidget.cpp trash/dolphintrash.cpp filterbar/filterbar.cpp panels/places/placespanel.cpp panels/places/placesitem.cpp panels/places/placesitemlistgroupheader.cpp panels/places/placesitemlistwidget.cpp panels/places/placesitemmodel.cpp panels/places/placesitemsignalhandler.cpp panels/places/placesview.cpp panels/panel.cpp panels/folders/foldersitemlistwidget.cpp panels/folders/treeviewcontextmenu.cpp panels/folders/folderspanel.cpp panels/terminal/terminalpanel.cpp search/dolphinfacetswidget.cpp + search/dolphinquery.cpp search/dolphinsearchbox.cpp settings/general/behaviorsettingspage.cpp settings/general/configurepreviewplugindialog.cpp settings/general/confirmationssettingspage.cpp settings/general/generalsettingspage.cpp settings/general/previewssettingspage.cpp settings/general/statusbarsettingspage.cpp settings/dolphinsettingsdialog.cpp settings/navigation/navigationsettingspage.cpp settings/services/servicessettingspage.cpp settings/settingspagebase.cpp settings/serviceitemdelegate.cpp settings/servicemodel.cpp settings/startup/startupsettingspage.cpp settings/trash/trashsettingspage.cpp settings/viewmodes/dolphinfontrequester.cpp settings/viewmodes/viewsettingspage.cpp settings/viewmodes/viewmodesettings.cpp settings/viewmodes/viewsettingstab.cpp statusbar/dolphinstatusbar.cpp statusbar/mountpointobserver.cpp statusbar/mountpointobservercache.cpp statusbar/spaceinfoobserver.cpp statusbar/statusbarspaceinfo.cpp views/zoomlevelinfo.cpp dolphindebug.cpp global.cpp ) if(HAVE_BALOO) set(dolphinstatic_SRCS ${dolphinstatic_SRCS} panels/information/informationpanel.cpp panels/information/informationpanelcontent.cpp panels/information/pixmapviewer.cpp panels/information/phononwidget.cpp ) endif() kconfig_add_kcfg_files(dolphinstatic_SRCS GENERATE_MOC panels/folders/dolphin_folderspanelsettings.kcfgc panels/information/dolphin_informationpanelsettings.kcfgc panels/places/dolphin_placespanelsettings.kcfgc settings/dolphin_compactmodesettings.kcfgc settings/dolphin_detailsmodesettings.kcfgc settings/dolphin_generalsettings.kcfgc settings/dolphin_iconsmodesettings.kcfgc search/dolphin_searchsettings.kcfgc settings/dolphin_versioncontrolsettings.kcfgc ) qt5_add_resources(dolphinstatic_SRCS dolphin.qrc) add_library(dolphinstatic STATIC ${dolphinstatic_SRCS}) target_include_directories(dolphinstatic SYSTEM PRIVATE ${PHONON_INCLUDES}) target_link_libraries(dolphinstatic dolphinprivate KF5::CoreAddons KF5::KCMUtils KF5::DBusAddons KF5::Notifications Phonon::phonon4qt5 ) if (HAVE_KACTIVITIES) target_link_libraries( dolphinstatic KF5::Activities ) endif() set(dolphin_SRCS dbusinterface.cpp main.cpp ) # Sets the icon on Windows and OSX file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/icons/*system-file-manager.png") ecm_add_app_icon(dolphin_SRCS ICONS ${ICONS_SRCS}) kf5_add_kdeinit_executable(dolphin ${dolphin_SRCS}) target_link_libraries(kdeinit_dolphin PRIVATE dolphinstatic dolphinprivate KF5::Crash ) include(DbusInterfaceMacros) generate_and_install_dbus_interface( kdeinit_dolphin dbusinterface.h org.freedesktop.FileManager1.xml OPTIONS -a ) install(TARGETS kdeinit_dolphin ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(TARGETS dolphin ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) ########################################## set(kcm_dolphinviewmodes_PART_SRCS settings/kcm/kcmdolphinviewmodes.cpp settings/viewmodes/dolphinfontrequester.cpp settings/viewmodes/viewmodesettings.cpp settings/viewmodes/viewsettingstab.cpp views/zoomlevelinfo.cpp) set(kcm_dolphinnavigation_PART_SRCS settings/kcm/kcmdolphinnavigation.cpp settings/navigation/navigationsettingspage.cpp settings/settingspagebase.cpp) set(kcm_dolphinservices_PART_SRCS settings/kcm/kcmdolphinservices.cpp settings/services/servicessettingspage.cpp settings/settingspagebase.cpp settings/serviceitemdelegate.cpp settings/servicemodel.cpp) set(kcm_dolphingeneral_PART_SRCS settings/kcm/kcmdolphingeneral.cpp settings/general/behaviorsettingspage.cpp settings/general/previewssettingspage.cpp settings/general/configurepreviewplugindialog.cpp settings/general/confirmationssettingspage.cpp settings/settingspagebase.cpp settings/serviceitemdelegate.cpp settings/servicemodel.cpp) kconfig_add_kcfg_files(kcm_dolphinviewmodes_PART_SRCS settings/dolphin_compactmodesettings.kcfgc settings/dolphin_directoryviewpropertysettings.kcfgc settings/dolphin_detailsmodesettings.kcfgc settings/dolphin_iconsmodesettings.kcfgc settings/dolphin_generalsettings.kcfgc settings/dolphin_versioncontrolsettings.kcfgc ) kconfig_add_kcfg_files(kcm_dolphinnavigation_PART_SRCS settings/dolphin_generalsettings.kcfgc) kconfig_add_kcfg_files(kcm_dolphinservices_PART_SRCS settings/dolphin_generalsettings.kcfgc settings/dolphin_versioncontrolsettings.kcfgc) kconfig_add_kcfg_files(kcm_dolphingeneral_PART_SRCS settings/dolphin_generalsettings.kcfgc) add_library(kcm_dolphinviewmodes MODULE ${kcm_dolphinviewmodes_PART_SRCS}) add_library(kcm_dolphinnavigation MODULE ${kcm_dolphinnavigation_PART_SRCS}) add_library(kcm_dolphinservices MODULE ${kcm_dolphinservices_PART_SRCS}) add_library(kcm_dolphingeneral MODULE ${kcm_dolphingeneral_PART_SRCS}) target_link_libraries(kcm_dolphinviewmodes dolphinprivate) target_link_libraries(kcm_dolphinnavigation dolphinprivate) target_link_libraries(kcm_dolphinservices dolphinprivate) target_link_libraries(kcm_dolphingeneral dolphinprivate) install(TARGETS kcm_dolphinviewmodes DESTINATION ${KDE_INSTALL_PLUGINDIR} ) install(TARGETS kcm_dolphinnavigation DESTINATION ${KDE_INSTALL_PLUGINDIR} ) install(TARGETS kcm_dolphinservices DESTINATION ${KDE_INSTALL_PLUGINDIR} ) install(TARGETS kcm_dolphingeneral DESTINATION ${KDE_INSTALL_PLUGINDIR} ) add_subdirectory(settings/services/servicemenuinstaller) ########### install files ############### install( PROGRAMS org.kde.dolphin.desktop DESTINATION ${KDE_INSTALL_APPDIR} ) install( DIRECTORY DESTINATION "${KDE_INSTALL_FULL_DATAROOTDIR}/kglobalaccel" ) install( CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E create_symlink \"${KDE_INSTALL_FULL_APPDIR}/org.kde.dolphin.desktop\" \"\$ENV{DESTDIR}${KDE_INSTALL_FULL_DATAROOTDIR}/kglobalaccel/org.kde.dolphin.desktop\")" ) install( FILES settings/dolphin_directoryviewpropertysettings.kcfg settings/dolphin_generalsettings.kcfg settings/dolphin_compactmodesettings.kcfg settings/dolphin_iconsmodesettings.kcfg settings/dolphin_detailsmodesettings.kcfg settings/dolphin_versioncontrolsettings.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR} ) install( FILES org.kde.dolphin.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR} ) install( FILES settings/kcm/kcmdolphinviewmodes.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} ) install( FILES settings/kcm/kcmdolphinnavigation.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} ) install( FILES settings/kcm/kcmdolphinservices.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} ) install( FILES settings/kcm/kcmdolphingeneral.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} ) install( FILES settings/services/servicemenu.knsrc DESTINATION ${KDE_INSTALL_CONFDIR} ) if(BUILD_TESTING) find_package(Qt5Test ${QT_MIN_VERSION} CONFIG REQUIRED) add_subdirectory(tests) endif() diff --git a/src/search/dolphinquery.cpp b/src/search/dolphinquery.cpp new file mode 100644 index 000000000..09a841859 --- /dev/null +++ b/src/search/dolphinquery.cpp @@ -0,0 +1,98 @@ +/*************************************************************************** + * Copyright (C) 2019 by Ismael Asensio * + * * + * 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 "dolphinquery.h" + +#include +#ifdef HAVE_BALOO +#include +#endif + +namespace { + /** Checks if a given term in the Baloo::Query::searchString() is a special search term. + * This is a copy of `DolphinFacetsWidget::isRatingTerm()` method. + */ + bool isSearchTerm(const QString& term) + { + static const QLatin1String searchTokens[] { + QLatin1String("modified>="), + QLatin1String("rating>=") + }; + + for (const auto &searchToken : searchTokens) { + if (term.startsWith(searchToken)) { + return true; + } + } + return false; + } +} + +DolphinQuery DolphinQuery::fromBalooSearchUrl(const QUrl& searchUrl) +{ + DolphinQuery model; + model.m_searchUrl = searchUrl; + +#ifdef HAVE_BALOO + const Baloo::Query query = Baloo::Query::fromSearchUrl(searchUrl); + + model.m_includeFolder = query.includeFolder(); + + model.m_searchText = query.searchString(); + + const QStringList types = query.types(); + model.m_fileType = types.isEmpty() ? QString() : types.first(); + + const QStringList subTerms = query.searchString().split(' ', QString::SkipEmptyParts); + foreach (const QString& subTerm, subTerms) { + if (subTerm.startsWith(QLatin1String("filename:"))) { + const QString value = subTerm.mid(9); + model.m_searchText = value; + } else if (isSearchTerm(subTerm)) { + model.m_searchTerms << subTerm; + } + } +#endif + return model; +} + +QUrl DolphinQuery::searchUrl() const +{ + return m_searchUrl; +} + +QString DolphinQuery::text() const +{ + return m_searchText; +} + +QString DolphinQuery::type() const +{ + return m_fileType; +} + +QStringList DolphinQuery::searchTerms() const +{ + return m_searchTerms; +} + +QString DolphinQuery::includeFolder() const +{ + return m_includeFolder; +} diff --git a/src/search/dolphinquery.h b/src/search/dolphinquery.h new file mode 100644 index 000000000..736abf66f --- /dev/null +++ b/src/search/dolphinquery.h @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 2019 by Ismael Asensio * + * * + * 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 * + ***************************************************************************/ + +#ifndef DOLPHINQUERY_H +#define DOLPHINQUERY_H + +#include "dolphin_export.h" + +#include +#include + +/** + * @brief Simple query model that parses a Baloo search Url and extracts its + * separate components to be displayed on dolphin search box. + */ +class DOLPHIN_EXPORT DolphinQuery +{ +public: + /** Calls Baloo::Query::fromSearchUrl() with the given @p searchUrl + * and parses the result to extract its separate components */ + static DolphinQuery fromBalooSearchUrl(const QUrl& searchUrl); + + /** @return the \a searchUrl passed to Baloo::Query::fromSearchUrl() */ + QUrl searchUrl() const; + /** @return the user text part of the query, to be shown in the searchbar */ + QString text() const; + /** @return the first of Baloo::Query::types(), or an empty string */ + QString type() const; + /** @return a list of the search terms of the Baloo::Query that act as a filter, + * such as \"rating>= value\" or \"modified>= date\"*/ + QStringList searchTerms() const; + /** @return Baloo::Query::includeFolder(), that is, the initial directory + * for the query or an empty string if its a global search" */ + QString includeFolder() const; + +private: + QUrl m_searchUrl; + QString m_searchText; + QString m_fileType; + QStringList m_searchTerms; + QString m_includeFolder; +}; + +#endif //DOLPHINQUERY_H diff --git a/src/search/dolphinsearchbox.cpp b/src/search/dolphinsearchbox.cpp index 751b23942..ee7cbe628 100644 --- a/src/search/dolphinsearchbox.cpp +++ b/src/search/dolphinsearchbox.cpp @@ -1,558 +1,544 @@ /*************************************************************************** * Copyright (C) 2010 by Peter Penz * * * * 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 "global.h" #include "dolphinsearchbox.h" #include "dolphin_searchsettings.h" #include "dolphinfacetswidget.h" +#include "dolphinquery.h" #include "panels/places/placesitemmodel.h" #include #include #include #include #ifdef HAVE_BALOO #include #include #endif #include #include #include #include #include #include #include #include #include #include #include DolphinSearchBox::DolphinSearchBox(QWidget* parent) : QWidget(parent), m_startedSearching(false), m_active(true), m_topLayout(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_facetsWidget(nullptr), m_searchPath(), m_startSearchTimer(nullptr) { } DolphinSearchBox::~DolphinSearchBox() { saveSettings(); } void DolphinSearchBox::setText(const QString& text) { m_searchInput->setText(text); } QString DolphinSearchBox::text() const { return m_searchInput->text(); } void DolphinSearchBox::setSearchPath(const QUrl& url) { if (url == m_searchPath) { return; } const QUrl cleanedUrl = url.adjusted(QUrl::RemoveUserInfo | QUrl::StripTrailingSlash); if (cleanedUrl.path() == QDir::homePath()) { m_fromHereButton->setChecked(false); m_everywhereButton->setChecked(true); if (!m_searchPath.isEmpty()) { return; } } else { m_everywhereButton->setChecked(false); m_fromHereButton->setChecked(true); } m_searchPath = url; QFontMetrics metrics(m_fromHereButton->font()); const int maxWidth = metrics.height() * 8; QString location = cleanedUrl.fileName(); if (location.isEmpty()) { location = cleanedUrl.toString(QUrl::PreferLocalFile); } const QString elidedLocation = metrics.elidedText(location, Qt::ElideMiddle, maxWidth); m_fromHereButton->setText(i18nc("action:button", "From Here (%1)", elidedLocation)); m_fromHereButton->setToolTip(i18nc("action:button", "Limit search to '%1' and its subfolders", cleanedUrl.toString(QUrl::PreferLocalFile))); } QUrl DolphinSearchBox::searchPath() const { return m_everywhereButton->isChecked() ? QUrl::fromLocalFile(QDir::homePath()) : m_searchPath; } QUrl DolphinSearchBox::urlForSearching() const { QUrl url; if (isIndexingEnabled()) { url = balooUrlForSearching(); } else { url.setScheme(QStringLiteral("filenamesearch")); QUrlQuery query; query.addQueryItem(QStringLiteral("search"), m_searchInput->text()); if (m_contentButton->isChecked()) { query.addQueryItem(QStringLiteral("checkContent"), QStringLiteral("yes")); } query.addQueryItem(QStringLiteral("url"), searchPath().url()); url.setQuery(query); } return url; } void DolphinSearchBox::fromSearchUrl(const QUrl& url) { if (url.scheme() == QLatin1String("baloosearch")) { - fromBalooSearchUrl(url); + const DolphinQuery query = DolphinQuery::fromBalooSearchUrl(url); + updateFromQuery(query); } else if (url.scheme() == QLatin1String("filenamesearch")) { const QUrlQuery query(url); setText(query.queryItemValue(QStringLiteral("search"))); if (m_searchPath.scheme() != url.scheme()) { m_searchPath = QUrl(); } setSearchPath(QUrl::fromUserInput(query.queryItemValue(QStringLiteral("url")), QString(), QUrl::AssumeLocalFile)); m_contentButton->setChecked(query.queryItemValue(QStringLiteral("checkContent")) == QLatin1String("yes")); } else { setText(QString()); m_searchPath = QUrl(); setSearchPath(url); } updateFacetsVisible(); } void DolphinSearchBox::selectAll() { m_searchInput->selectAll(); } void DolphinSearchBox::setActive(bool active) { if (active != m_active) { m_active = active; if (active) { emit activated(); } } } bool DolphinSearchBox::isActive() const { return m_active; } bool DolphinSearchBox::event(QEvent* event) { if (event->type() == QEvent::Polish) { init(); } return QWidget::event(event); } void DolphinSearchBox::showEvent(QShowEvent* event) { if (!event->spontaneous()) { m_searchInput->setFocus(); m_startedSearching = false; } } void DolphinSearchBox::hideEvent(QHideEvent* event) { Q_UNUSED(event) m_startedSearching = false; m_startSearchTimer->stop(); } void DolphinSearchBox::keyReleaseEvent(QKeyEvent* event) { QWidget::keyReleaseEvent(event); if (event->key() == Qt::Key_Escape) { if (m_searchInput->text().isEmpty()) { emit closeRequest(); } else { m_searchInput->clear(); } } } bool DolphinSearchBox::eventFilter(QObject* obj, QEvent* event) { switch (event->type()) { case QEvent::FocusIn: // #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: break; } return QObject::eventFilter(obj, event); } void DolphinSearchBox::emitSearchRequest() { m_startSearchTimer->stop(); m_startedSearching = true; m_saveSearchAction->setEnabled(true); emit searchRequest(); } void DolphinSearchBox::emitCloseRequest() { m_startSearchTimer->stop(); m_startedSearching = false; m_saveSearchAction->setEnabled(false); emit closeRequest(); } void DolphinSearchBox::slotConfigurationChanged() { saveSettings(); if (m_startedSearching) { emitSearchRequest(); } } void DolphinSearchBox::slotSearchTextChanged(const QString& text) { if (text.isEmpty()) { m_startSearchTimer->stop(); } else { m_startSearchTimer->start(); } emit searchTextChanged(text); } void DolphinSearchBox::slotReturnPressed() { emitSearchRequest(); emit returnPressed(); } void DolphinSearchBox::slotFacetChanged() { m_startedSearching = true; m_startSearchTimer->stop(); 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); button->setAutoExclusive(true); button->setAutoRaise(true); button->setCheckable(true); connect(button, &QToolButton::clicked, this, &DolphinSearchBox::slotConfigurationChanged); } void DolphinSearchBox::loadSettings() { if (SearchSettings::location() == QLatin1String("Everywhere")) { m_everywhereButton->setChecked(true); } else { m_fromHereButton->setChecked(true); } if (SearchSettings::what() == QLatin1String("Content")) { m_contentButton->setChecked(true); } else { m_fileNameButton->setChecked(true); } updateFacetsVisible(); } void DolphinSearchBox::saveSettings() { SearchSettings::setLocation(m_fromHereButton->isChecked() ? QStringLiteral("FromHere") : QStringLiteral("Everywhere")); SearchSettings::setWhat(m_fileNameButton->isChecked() ? QStringLiteral("FileName") : QStringLiteral("Content")); SearchSettings::self()->save(); } void DolphinSearchBox::init() { // Create close button QToolButton* closeButton = new QToolButton(this); closeButton->setAutoRaise(true); closeButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-close"))); closeButton->setToolTip(i18nc("@info:tooltip", "Quit searching")); connect(closeButton, &QToolButton::clicked, this, &DolphinSearchBox::emitCloseRequest); // Create search box m_searchInput = new QLineEdit(this); m_searchInput->setPlaceholderText(i18n("Search...")); m_searchInput->installEventFilter(this); m_searchInput->setClearButtonEnabled(true); m_searchInput->setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); connect(m_searchInput, &QLineEdit::returnPressed, this, &DolphinSearchBox::slotReturnPressed); 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(); searchInputLayout->setContentsMargins(0, 0, 0, 0); searchInputLayout->addWidget(closeButton); searchInputLayout->addWidget(m_searchInput); // Create "Filename" and "Content" button m_fileNameButton = new QToolButton(this); m_fileNameButton->setText(i18nc("action:button", "Filename")); initButton(m_fileNameButton); m_contentButton = new QToolButton(); m_contentButton->setText(i18nc("action:button", "Content")); initButton(m_contentButton); QButtonGroup* searchWhatGroup = new QButtonGroup(this); searchWhatGroup->addButton(m_fileNameButton); searchWhatGroup->addButton(m_contentButton); m_separator = new KSeparator(Qt::Vertical, this); // Create "From Here" and "Your files" buttons m_fromHereButton = new QToolButton(this); m_fromHereButton->setText(i18nc("action:button", "From Here")); initButton(m_fromHereButton); m_everywhereButton = new QToolButton(this); m_everywhereButton->setText(i18nc("action:button", "Your files")); m_everywhereButton->setToolTip(i18nc("action:button", "Search in your home directory")); m_everywhereButton->setIcon(QIcon::fromTheme(QStringLiteral("user-home"))); m_everywhereButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); initButton(m_everywhereButton); QButtonGroup* searchLocationGroup = new QButtonGroup(this); 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" widget m_facetsWidget = new DolphinFacetsWidget(this); m_facetsWidget->installEventFilter(this); m_facetsWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); m_facetsWidget->layout()->setSpacing(Dolphin::LAYOUT_SPACING_SMALL); connect(m_facetsWidget, &DolphinFacetsWidget::facetChanged, this, &DolphinSearchBox::slotFacetChanged); // Apply layout for the options QHBoxLayout* optionsLayout = new QHBoxLayout(); optionsLayout->setContentsMargins(0, 0, 0, 0); optionsLayout->setSpacing(Dolphin::LAYOUT_SPACING_SMALL); optionsLayout->addWidget(m_fileNameButton); optionsLayout->addWidget(m_contentButton); optionsLayout->addWidget(m_separator); optionsLayout->addWidget(m_fromHereButton); optionsLayout->addWidget(m_everywhereButton); optionsLayout->addWidget(new KSeparator(Qt::Vertical, this)); 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. QWidget* optionsContainer = new QWidget(this); optionsContainer->setLayout(optionsLayout); m_optionsScrollArea = new QScrollArea(this); m_optionsScrollArea->setFrameShape(QFrame::NoFrame); m_optionsScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_optionsScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_optionsScrollArea->setMaximumHeight(optionsContainer->sizeHint().height()); m_optionsScrollArea->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); m_optionsScrollArea->setWidget(optionsContainer); m_optionsScrollArea->setWidgetResizable(true); m_topLayout = new QVBoxLayout(this); m_topLayout->setContentsMargins(0, 0, 0, 0); m_topLayout->setSpacing(Dolphin::LAYOUT_SPACING_SMALL); m_topLayout->addLayout(searchInputLayout); m_topLayout->addWidget(m_optionsScrollArea); m_topLayout->addWidget(m_facetsWidget); loadSettings(); // The searching should be started automatically after the user did not change // the text within one second m_startSearchTimer = new QTimer(this); m_startSearchTimer->setSingleShot(true); m_startSearchTimer->setInterval(1000); connect(m_startSearchTimer, &QTimer::timeout, this, &DolphinSearchBox::emitSearchRequest); } QUrl DolphinSearchBox::balooUrlForSearching() const { #ifdef HAVE_BALOO const QString text = m_searchInput->text(); Baloo::Query query; query.addType(m_facetsWidget->facetType()); QStringList queryStrings; QString ratingQuery = m_facetsWidget->ratingTerm(); if (!ratingQuery.isEmpty()) { queryStrings << ratingQuery; } if (m_contentButton->isChecked()) { queryStrings << text; } else if (!text.isEmpty()) { queryStrings << QStringLiteral("filename:\"%1\"").arg(text); } if (m_fromHereButton->isChecked()) { query.setIncludeFolder(m_searchPath.toLocalFile()); } query.setSearchString(queryStrings.join(QLatin1Char(' '))); 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 QUrl(); #endif } -void DolphinSearchBox::fromBalooSearchUrl(const QUrl& url) +void DolphinSearchBox::updateFromQuery(const DolphinQuery& query) { -#ifdef HAVE_BALOO - const Baloo::Query query = Baloo::Query::fromSearchUrl(url); - // Block all signals to avoid unnecessary "searchRequest" signals // while we adjust the search text and the facet widget. blockSignals(true); const QString customDir = query.includeFolder(); if (!customDir.isEmpty()) { setSearchPath(QUrl::fromLocalFile(customDir)); } else { setSearchPath(QUrl::fromLocalFile(QDir::homePath())); } - m_facetsWidget->resetOptions(); - - setText(query.searchString()); - - QStringList types = query.types(); - if (!types.isEmpty()) { - m_facetsWidget->setFacetType(types.first()); - } + setText(query.text()); - 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); - } + m_facetsWidget->resetOptions(); + m_facetsWidget->setFacetType(query.type()); + const QStringList searchTerms = query.searchTerms(); + for (const QString& searchTerm : searchTerms) { + m_facetsWidget->setRatingTerm(searchTerm); } m_startSearchTimer->stop(); blockSignals(false); -#else - Q_UNUSED(url) -#endif } void DolphinSearchBox::updateFacetsVisible() { const bool indexingEnabled = isIndexingEnabled(); m_facetsWidget->setEnabled(indexingEnabled); m_facetsWidget->setVisible(indexingEnabled); } bool DolphinSearchBox::isIndexingEnabled() const { #ifdef HAVE_BALOO const Baloo::IndexerConfig searchInfo; return searchInfo.fileIndexingEnabled() && searchInfo.shouldBeIndexed(searchPath().toLocalFile()); #else return false; #endif } diff --git a/src/search/dolphinsearchbox.h b/src/search/dolphinsearchbox.h index 241dc40c1..5fef4ec5a 100644 --- a/src/search/dolphinsearchbox.h +++ b/src/search/dolphinsearchbox.h @@ -1,186 +1,186 @@ /*************************************************************************** * Copyright (C) 2010 by Peter Penz * * * * 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 * ***************************************************************************/ #ifndef DOLPHINSEARCHBOX_H #define DOLPHINSEARCHBOX_H #include #include class DolphinFacetsWidget; +class DolphinQuery; class QLineEdit; class KSeparator; class QToolButton; class QScrollArea; class QLabel; class QVBoxLayout; class KMoreToolsMenuFactory; /** * @brief Input box for searching files with or without Baloo. * * The widget allows to specify: * - Where to search: Everywhere or below the current directory * - What to search: Filenames or content * * If Baloo is available and the current folder is indexed, further * options are offered. */ class DolphinSearchBox : public QWidget { Q_OBJECT public: explicit DolphinSearchBox(QWidget* parent = nullptr); ~DolphinSearchBox() override; /** * Sets the text that should be used as input for * searching. */ void setText(const QString& text); /** * Returns the text that should be used as input * for searching. */ QString text() const; /** * Sets the current path that is used as root for searching files. * If @url is the Home dir, "From Here" is selected instead. */ void setSearchPath(const QUrl& url); QUrl searchPath() const; /** @return URL that will start the searching of files. */ QUrl urlForSearching() const; /** * Extracts information from the given search \a url to * initialize the search box properly. */ void fromSearchUrl(const QUrl& url); /** * Selects the whole text of the search box. */ void selectAll(); /** * Set the search box to the active mode, if \a active * is true. The active mode is default. The inactive mode only differs * visually from the active mode, no change of the behavior is given. * * Using the search box in the inactive mode is useful when having split views, * where the inactive view is indicated by an search box visually. */ void setActive(bool active); /** * @return True, if the search box is in the active mode. * @see DolphinSearchBox::setActive() */ bool isActive() const; protected: bool event(QEvent* event) override; void showEvent(QShowEvent* event) override; void hideEvent(QHideEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override; bool eventFilter(QObject* obj, QEvent* event) override; signals: /** * Is emitted when a searching should be triggered. */ void searchRequest(); /** * Is emitted when the user has changed a character of * the text that should be used as input for searching. */ void searchTextChanged(const QString& text); void returnPressed(); /** * Emitted as soon as the search box should get closed. */ void closeRequest(); /** * Is emitted, if the searchbox has been activated by * an user interaction * @see DolphinSearchBox::setActive() */ void activated(); private slots: void emitSearchRequest(); void emitCloseRequest(); void slotConfigurationChanged(); void slotSearchTextChanged(const QString& text); void slotReturnPressed(); void slotFacetChanged(); void slotSearchSaved(); private: void initButton(QToolButton* button); void loadSettings(); void saveSettings(); void init(); /** * @return URL that represents the Baloo query for starting the search. */ QUrl balooUrlForSearching() const; /** - * Extracts information from the given Baloo search \a url to - * initialize the search box properly. + * Sets the searchbox UI with the parameters established by the \a query */ - void fromBalooSearchUrl(const QUrl& url); + void updateFromQuery(const DolphinQuery& query); void updateFacetsVisible(); bool isIndexingEnabled() const; private: bool m_startedSearching; bool m_active; QVBoxLayout* m_topLayout; QLineEdit* m_searchInput; QAction* m_saveSearchAction; QScrollArea* m_optionsScrollArea; QToolButton* m_fileNameButton; QToolButton* m_contentButton; KSeparator* m_separator; QToolButton* m_fromHereButton; QToolButton* m_everywhereButton; DolphinFacetsWidget* m_facetsWidget; QUrl m_searchPath; QScopedPointer m_menuFactory; QTimer* m_startSearchTimer; }; #endif