diff --git a/src/global.h b/src/global.h index d1a3f4f52..f203615f1 100644 --- a/src/global.h +++ b/src/global.h @@ -1,58 +1,59 @@ /* * Copyright 2015 Ashish Bansal * * 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 GLOBAL_H #define GLOBAL_H #include #include +#include namespace Dolphin { QList validateUris(const QStringList& uriList); /** * Returns the home url which is defined in General Settings */ QUrl homeUrl(); enum class OpenNewWindowFlag { None = 0, Select = 1<<1 }; Q_DECLARE_FLAGS(OpenNewWindowFlags, OpenNewWindowFlag) /** * Opens a new Dolphin window */ void openNewWindow(const QList &urls = {}, QWidget *window = nullptr, const OpenNewWindowFlags &flags = OpenNewWindowFlag::None); /** * Attaches URLs to an existing Dolphin instance if possible. * Returns true if URLs were successfully attached */ bool attachToExistingInstance(const QList& inputUrls, bool openFiles, bool splitView, const QString& preferredService = QString()); /** * TODO: Move this somewhere global to all KDE apps, not just Dolphin */ const int VERTICAL_SPACER_HEIGHT = 18; const int LAYOUT_SPACING_SMALL = 2; } #endif //GLOBAL_H diff --git a/src/kitemviews/kstandarditem.h b/src/kitemviews/kstandarditem.h index ad3452d77..13e61a089 100644 --- a/src/kitemviews/kstandarditem.h +++ b/src/kitemviews/kstandarditem.h @@ -1,93 +1,94 @@ /*************************************************************************** * Copyright (C) 2012 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 KSTANDARDITEM_H #define KSTANDARDITEM_H #include "dolphin_export.h" #include #include #include +#include #include class KStandardItemModel; /** * @brief Represents and item of KStandardItemModel. * * Provides setter- and getter-methods for the most commonly * used roles. It is possible to assign values for custom * roles by using setDataValue(). */ class DOLPHIN_EXPORT KStandardItem : public QObject { Q_OBJECT public: explicit KStandardItem(KStandardItem* parent = nullptr); explicit KStandardItem(const QString& text, KStandardItem* parent = nullptr); KStandardItem(const QString& icon, const QString& text, KStandardItem* parent = nullptr); virtual ~KStandardItem(); /** * Sets the text for the "text"-role. */ void setText(const QString& text); QString text() const; /** * Sets the icon for the "iconName"-role. */ void setIcon(const QString& icon); QString icon() const; void setIconOverlays(const QStringList& overlays); QStringList iconOverlays() const; /** * Sets the group for the "group"-role. */ void setGroup(const QString& group); QString group() const; void setDataValue(const QByteArray& role, const QVariant& value); QVariant dataValue(const QByteArray& role) const; void setData(const QHash& values); QHash data() const; protected: virtual void onDataValueChanged(const QByteArray& role, const QVariant& current, const QVariant& previous); virtual void onDataChanged(const QHash& current, const QHash& previous); private: KStandardItemModel* m_model; QHash m_data; friend class KStandardItemModel; }; #endif diff --git a/src/search/dolphinsearchbox.cpp b/src/search/dolphinsearchbox.cpp index ee7cbe628..16f17bbcd 100644 --- a/src/search/dolphinsearchbox.cpp +++ b/src/search/dolphinsearchbox.cpp @@ -1,544 +1,546 @@ /*************************************************************************** * 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 #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")) { 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::updateFromQuery(const DolphinQuery& query) { // 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())); } setText(query.text()); 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); } 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/settings/dolphinsettingsdialog.cpp b/src/settings/dolphinsettingsdialog.cpp index 01cfd9f86..87bc95a7f 100644 --- a/src/settings/dolphinsettingsdialog.cpp +++ b/src/settings/dolphinsettingsdialog.cpp @@ -1,191 +1,192 @@ /*************************************************************************** * Copyright (C) 2006 by Peter Penz * * peter.penz@gmx.at * * * * 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 "dolphinsettingsdialog.h" #include "dolphin_generalsettings.h" #include "dolphinmainwindow.h" #include "general/generalsettingspage.h" #include "navigation/navigationsettingspage.h" #include "services/servicessettingspage.h" #include "startup/startupsettingspage.h" #include "trash/trashsettingspage.h" #include "viewmodes/viewsettingspage.h" #include #include #include #include +#include #include DolphinSettingsDialog::DolphinSettingsDialog(const QUrl& url, QWidget* parent) : KPageDialog(parent), m_pages(), m_unsavedChanges(false) { const QSize minSize = minimumSize(); setMinimumSize(QSize(540, minSize.height())); setFaceType(List); setWindowTitle(i18nc("@title:window", "Dolphin Preferences")); QDialogButtonBox* box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults); box->button(QDialogButtonBox::Apply)->setEnabled(false); box->button(QDialogButtonBox::Ok)->setDefault(true); setButtonBox(box); connect(box->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, this, &DolphinSettingsDialog::applySettings); connect(box->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, this, &DolphinSettingsDialog::applySettings); connect(box->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, this, &DolphinSettingsDialog::restoreDefaults); // General GeneralSettingsPage* generalSettingsPage = new GeneralSettingsPage(url, this); KPageWidgetItem* generalSettingsFrame = addPage(generalSettingsPage, i18nc("@title:group General settings", "General")); generalSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("system-file-manager"))); connect(generalSettingsPage, &GeneralSettingsPage::changed, this, &DolphinSettingsDialog::enableApply); // Startup StartupSettingsPage* startupSettingsPage = new StartupSettingsPage(url, this); KPageWidgetItem* startupSettingsFrame = addPage(startupSettingsPage, i18nc("@title:group", "Startup")); startupSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-launch-feedback"))); connect(startupSettingsPage, &StartupSettingsPage::changed, this, &DolphinSettingsDialog::enableApply); // View Modes ViewSettingsPage* viewSettingsPage = new ViewSettingsPage(this); KPageWidgetItem* viewSettingsFrame = addPage(viewSettingsPage, i18nc("@title:group", "View Modes")); viewSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-icons"))); connect(viewSettingsPage, &ViewSettingsPage::changed, this, &DolphinSettingsDialog::enableApply); // Navigation NavigationSettingsPage* navigationSettingsPage = new NavigationSettingsPage(this); KPageWidgetItem* navigationSettingsFrame = addPage(navigationSettingsPage, i18nc("@title:group", "Navigation")); navigationSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-navigation"))); connect(navigationSettingsPage, &NavigationSettingsPage::changed, this, &DolphinSettingsDialog::enableApply); // Services ServicesSettingsPage* servicesSettingsPage = new ServicesSettingsPage(this); KPageWidgetItem* servicesSettingsFrame = addPage(servicesSettingsPage, i18nc("@title:group", "Services")); servicesSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("preferences-system-services"))); connect(servicesSettingsPage, &ServicesSettingsPage::changed, this, &DolphinSettingsDialog::enableApply); // Trash auto* trashSettingsPage = createTrashSettingsPage(this); if (trashSettingsPage) { KPageWidgetItem* trashSettingsFrame = addPage(trashSettingsPage, i18nc("@title:group", "Trash")); trashSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("user-trash"))); connect(trashSettingsPage, &TrashSettingsPage::changed, this, &DolphinSettingsDialog::enableApply); } m_pages.append(generalSettingsPage); m_pages.append(startupSettingsPage); m_pages.append(viewSettingsPage); m_pages.append(navigationSettingsPage); m_pages.append(servicesSettingsPage); if (trashSettingsPage) { m_pages.append(trashSettingsPage); } const KConfigGroup dialogConfig(KSharedConfig::openConfig(QStringLiteral("dolphinrc")), "SettingsDialog"); KWindowConfig::restoreWindowSize(windowHandle(), dialogConfig); } DolphinSettingsDialog::~DolphinSettingsDialog() { KConfigGroup dialogConfig(KSharedConfig::openConfig(QStringLiteral("dolphinrc")), "SettingsDialog"); KWindowConfig::saveWindowSize(windowHandle(), dialogConfig); } void DolphinSettingsDialog::enableApply() { buttonBox()->button(QDialogButtonBox::Apply)->setEnabled(true); m_unsavedChanges = true; } void DolphinSettingsDialog::applySettings() { foreach (SettingsPageBase* page, m_pages) { page->applySettings(); } emit settingsChanged(); GeneralSettings* settings = GeneralSettings::self(); if (settings->modifiedStartupSettings()) { // Reset the modified startup settings hint. The changed startup settings // have been applied already due to emitting settingsChanged(). settings->setModifiedStartupSettings(false); settings->save(); } buttonBox()->button(QDialogButtonBox::Apply)->setEnabled(false); m_unsavedChanges = false; } void DolphinSettingsDialog::restoreDefaults() { foreach (SettingsPageBase* page, m_pages) { page->restoreDefaults(); } } void DolphinSettingsDialog::closeEvent(QCloseEvent* event) { if (!m_unsavedChanges) { event->accept(); return; } const auto response = KMessageBox::warningYesNoCancel(this, i18n("You have unsaved changes. Do you want to apply the changes or discard them?"), i18n("Warning"), KStandardGuiItem::save(), KStandardGuiItem::discard(), KStandardGuiItem::cancel()); switch (response) { case KMessageBox::Yes: applySettings(); Q_FALLTHROUGH(); case KMessageBox::No: event->accept(); break; case KMessageBox::Cancel: event->ignore(); break; default: break; } } SettingsPageBase *DolphinSettingsDialog::createTrashSettingsPage(QWidget *parent) { if (!KAuthorized::authorizeControlModule(QStringLiteral("kcmtrash.desktop"))) { return nullptr; } return new TrashSettingsPage(parent); } diff --git a/src/settings/general/previewssettingspage.cpp b/src/settings/general/previewssettingspage.cpp index 30d71ff54..90a4211c0 100644 --- a/src/settings/general/previewssettingspage.cpp +++ b/src/settings/general/previewssettingspage.cpp @@ -1,176 +1,177 @@ /*************************************************************************** * Copyright (C) 2006 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 "previewssettingspage.h" #include "dolphin_generalsettings.h" #include "configurepreviewplugindialog.h" #include "settings/serviceitemdelegate.h" #include "settings/servicemodel.h" #include #include #include #include #include #include #include +#include #include #include // default settings namespace { const int MaxRemotePreviewSize = 0; // 0 MB } PreviewsSettingsPage::PreviewsSettingsPage(QWidget* parent) : SettingsPageBase(parent), m_initialized(false), m_listView(nullptr), m_enabledPreviewPlugins(), m_remoteFileSizeBox(nullptr) { QVBoxLayout* topLayout = new QVBoxLayout(this); QLabel* showPreviewsLabel = new QLabel(i18nc("@title:group", "Show previews in the view for:"), this); m_listView = new QListView(this); ServiceItemDelegate* delegate = new ServiceItemDelegate(m_listView, m_listView); connect(delegate, &ServiceItemDelegate::requestServiceConfiguration, this, &PreviewsSettingsPage::configureService); ServiceModel* serviceModel = new ServiceModel(this); QSortFilterProxyModel* proxyModel = new QSortFilterProxyModel(this); proxyModel->setSourceModel(serviceModel); proxyModel->setSortRole(Qt::DisplayRole); proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); m_listView->setModel(proxyModel); m_listView->setItemDelegate(delegate); m_listView->setVerticalScrollMode(QListView::ScrollPerPixel); QLabel* remoteFileSizeLabel = new QLabel(i18nc("@label", "Skip previews for remote files above:"), this); m_remoteFileSizeBox = new QSpinBox(this); m_remoteFileSizeBox->setSingleStep(1); m_remoteFileSizeBox->setSuffix(QStringLiteral(" MB")); m_remoteFileSizeBox->setRange(0, 9999999); /* MB */ QHBoxLayout* fileSizeBoxLayout = new QHBoxLayout(); fileSizeBoxLayout->addWidget(remoteFileSizeLabel, 0, Qt::AlignRight); fileSizeBoxLayout->addWidget(m_remoteFileSizeBox); topLayout->addWidget(showPreviewsLabel); topLayout->addWidget(m_listView); topLayout->addLayout(fileSizeBoxLayout); loadSettings(); connect(m_listView, &QListView::clicked, this, &PreviewsSettingsPage::changed); connect(m_remoteFileSizeBox, QOverload::of(&QSpinBox::valueChanged), this, &PreviewsSettingsPage::changed); } PreviewsSettingsPage::~PreviewsSettingsPage() { } void PreviewsSettingsPage::applySettings() { const QAbstractItemModel* model = m_listView->model(); const int rowCount = model->rowCount(); if (rowCount > 0) { m_enabledPreviewPlugins.clear(); for (int i = 0; i < rowCount; ++i) { const QModelIndex index = model->index(i, 0); const bool checked = model->data(index, Qt::CheckStateRole).toBool(); if (checked) { const QString enabledPlugin = model->data(index, Qt::UserRole).toString(); m_enabledPreviewPlugins.append(enabledPlugin); } } } KConfigGroup globalConfig(KSharedConfig::openConfig(), QStringLiteral("PreviewSettings")); globalConfig.writeEntry("Plugins", m_enabledPreviewPlugins); const qulonglong maximumRemoteSize = static_cast(m_remoteFileSizeBox->value()) * 1024 * 1024; globalConfig.writeEntry("MaximumRemoteSize", maximumRemoteSize, KConfigBase::Normal | KConfigBase::Global); globalConfig.sync(); } void PreviewsSettingsPage::restoreDefaults() { m_remoteFileSizeBox->setValue(MaxRemotePreviewSize); } void PreviewsSettingsPage::showEvent(QShowEvent* event) { if (!event->spontaneous() && !m_initialized) { loadPreviewPlugins(); m_initialized = true; } SettingsPageBase::showEvent(event); } void PreviewsSettingsPage::configureService(const QModelIndex& index) { const QAbstractItemModel* model = index.model(); const QString pluginName = model->data(index).toString(); const QString desktopEntryName = model->data(index, ServiceModel::DesktopEntryNameRole).toString(); ConfigurePreviewPluginDialog* dialog = new ConfigurePreviewPluginDialog(pluginName, desktopEntryName, this); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->show(); } void PreviewsSettingsPage::loadPreviewPlugins() { QAbstractItemModel* model = m_listView->model(); const KService::List plugins = KServiceTypeTrader::self()->query(QStringLiteral("ThumbCreator")); foreach (const KService::Ptr& service, plugins) { const bool configurable = service->property(QStringLiteral("Configurable"), QVariant::Bool).toBool(); const bool show = m_enabledPreviewPlugins.contains(service->desktopEntryName()); model->insertRow(0); const QModelIndex index = model->index(0, 0); model->setData(index, show, Qt::CheckStateRole); model->setData(index, configurable, ServiceModel::ConfigurableRole); model->setData(index, service->name(), Qt::DisplayRole); model->setData(index, service->desktopEntryName(), ServiceModel::DesktopEntryNameRole); } model->sort(Qt::DisplayRole); } void PreviewsSettingsPage::loadSettings() { const KConfigGroup globalConfig(KSharedConfig::openConfig(), QStringLiteral("PreviewSettings")); m_enabledPreviewPlugins = globalConfig.readEntry("Plugins", KIO::PreviewJob::defaultPlugins()); const qulonglong defaultRemotePreview = static_cast(MaxRemotePreviewSize) * 1024 * 1024; const qulonglong maxRemoteByteSize = globalConfig.readEntry("MaximumRemoteSize", defaultRemotePreview); const int maxRemoteMByteSize = maxRemoteByteSize / (1024 * 1024); m_remoteFileSizeBox->setValue(maxRemoteMByteSize); } diff --git a/src/settings/services/servicessettingspage.cpp b/src/settings/services/servicessettingspage.cpp index 83672b556..1f8310dfc 100644 --- a/src/settings/services/servicessettingspage.cpp +++ b/src/settings/services/servicessettingspage.cpp @@ -1,280 +1,281 @@ /*************************************************************************** * Copyright (C) 2009-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 "servicessettingspage.h" #include "dolphin_generalsettings.h" #include "dolphin_versioncontrolsettings.h" #include "settings/serviceitemdelegate.h" #include "settings/servicemodel.h" #include #include #include #include #include #include #include #include #include #include #include +#include #include namespace { const bool ShowDeleteDefault = false; const char VersionControlServicePrefix[] = "_version_control_"; const char DeleteService[] = "_delete"; const char CopyToMoveToService[] ="_copy_to_move_to"; } ServicesSettingsPage::ServicesSettingsPage(QWidget* parent) : SettingsPageBase(parent), m_initialized(false), m_serviceModel(nullptr), m_sortModel(nullptr), m_listView(nullptr), m_enabledVcsPlugins() { QVBoxLayout* topLayout = new QVBoxLayout(this); QLabel* label = new QLabel(i18nc("@label:textbox", "Select which services should " "be shown in the context menu:"), this); label->setWordWrap(true); m_listView = new QListView(this); ServiceItemDelegate* delegate = new ServiceItemDelegate(m_listView, m_listView); m_serviceModel = new ServiceModel(this); m_sortModel = new QSortFilterProxyModel(this); m_sortModel->setSourceModel(m_serviceModel); m_sortModel->setSortRole(Qt::DisplayRole); m_listView->setModel(m_sortModel); m_listView->setItemDelegate(delegate); m_listView->setVerticalScrollMode(QListView::ScrollPerPixel); connect(m_listView, &QListView::clicked, this, &ServicesSettingsPage::changed); KNS3::Button* downloadButton = new KNS3::Button(i18nc("@action:button", "Download New Services..."), QStringLiteral("servicemenu.knsrc"), this); connect(downloadButton, &KNS3::Button::dialogFinished, this, &ServicesSettingsPage::loadServices); topLayout->addWidget(label); topLayout->addWidget(m_listView); topLayout->addWidget(downloadButton); m_enabledVcsPlugins = VersionControlSettings::enabledPlugins(); std::sort(m_enabledVcsPlugins.begin(), m_enabledVcsPlugins.end()); } ServicesSettingsPage::~ServicesSettingsPage() { } void ServicesSettingsPage::applySettings() { if (!m_initialized) { return; } KConfig config(QStringLiteral("kservicemenurc"), KConfig::NoGlobals); KConfigGroup showGroup = config.group("Show"); QStringList enabledPlugins; const QAbstractItemModel* model = m_listView->model(); for (int i = 0; i < model->rowCount(); ++i) { const QModelIndex index = model->index(i, 0); const QString service = model->data(index, ServiceModel::DesktopEntryNameRole).toString(); const bool checked = model->data(index, Qt::CheckStateRole).toBool(); if (service.startsWith(VersionControlServicePrefix)) { if (checked) { enabledPlugins.append(model->data(index, Qt::DisplayRole).toString()); } } else if (service == QLatin1String(DeleteService)) { KSharedConfig::Ptr globalConfig = KSharedConfig::openConfig(QStringLiteral("kdeglobals"), KConfig::NoGlobals); KConfigGroup configGroup(globalConfig, "KDE"); configGroup.writeEntry("ShowDeleteCommand", checked); configGroup.sync(); } else if (service == QLatin1String(CopyToMoveToService)) { GeneralSettings::setShowCopyMoveMenu(checked); GeneralSettings::self()->save(); } else { showGroup.writeEntry(service, checked); } } showGroup.sync(); if (m_enabledVcsPlugins != enabledPlugins) { VersionControlSettings::setEnabledPlugins(enabledPlugins); VersionControlSettings::self()->save(); KMessageBox::information(window(), i18nc("@info", "Dolphin must be restarted to apply the " "updated version control systems settings."), QString(), // default title QStringLiteral("ShowVcsRestartInformation")); } } void ServicesSettingsPage::restoreDefaults() { QAbstractItemModel* model = m_listView->model(); for (int i = 0; i < model->rowCount(); ++i) { const QModelIndex index = model->index(i, 0); const QString service = model->data(index, ServiceModel::DesktopEntryNameRole).toString(); const bool checked = !service.startsWith(VersionControlServicePrefix) && service != QLatin1String(DeleteService) && service != QLatin1String(CopyToMoveToService); model->setData(index, checked, Qt::CheckStateRole); } } void ServicesSettingsPage::showEvent(QShowEvent* event) { if (!event->spontaneous() && !m_initialized) { loadServices(); loadVersionControlSystems(); // Add "Show 'Delete' command" as service KSharedConfig::Ptr globalConfig = KSharedConfig::openConfig(QStringLiteral("kdeglobals"), KConfig::IncludeGlobals); KConfigGroup configGroup(globalConfig, "KDE"); addRow(QStringLiteral("edit-delete"), i18nc("@option:check", "Delete"), DeleteService, configGroup.readEntry("ShowDeleteCommand", ShowDeleteDefault)); // Add "Show 'Copy To' and 'Move To' commands" as service addRow(QStringLiteral("edit-copy"), i18nc("@option:check", "'Copy To' and 'Move To' commands"), CopyToMoveToService, GeneralSettings::showCopyMoveMenu()); m_sortModel->sort(Qt::DisplayRole); m_initialized = true; } SettingsPageBase::showEvent(event); } void ServicesSettingsPage::loadServices() { const KConfig config(QStringLiteral("kservicemenurc"), KConfig::NoGlobals); const KConfigGroup showGroup = config.group("Show"); // Load generic services const KService::List entries = KServiceTypeTrader::self()->query(QStringLiteral("KonqPopupMenu/Plugin")); foreach (const KService::Ptr& service, entries) { const QString file = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kservices5/" % service->entryPath()); const QList serviceActions = KDesktopFileActions::userDefinedServices(file, true); KDesktopFile desktopFile(file); const QString subMenuName = desktopFile.desktopGroup().readEntry("X-KDE-Submenu"); foreach (const KServiceAction& action, serviceActions) { const QString serviceName = action.name(); const bool addService = !action.noDisplay() && !action.isSeparator() && !isInServicesList(serviceName); if (addService) { const QString itemName = subMenuName.isEmpty() ? action.text() : i18nc("@item:inmenu", "%1: %2", subMenuName, action.text()); const bool checked = showGroup.readEntry(serviceName, true); addRow(action.icon(), itemName, serviceName, checked); } } } // Load service plugins that implement the KFileItemActionPlugin interface const KService::List pluginServices = KServiceTypeTrader::self()->query(QStringLiteral("KFileItemAction/Plugin")); foreach (const KService::Ptr& service, pluginServices) { const QString desktopEntryName = service->desktopEntryName(); if (!isInServicesList(desktopEntryName)) { const bool checked = showGroup.readEntry(desktopEntryName, true); addRow(service->icon(), service->name(), desktopEntryName, checked); } } // Load JSON-based plugins that implement the KFileItemActionPlugin interface const auto jsonPlugins = KPluginLoader::findPlugins(QStringLiteral("kf5/kfileitemaction"), [](const KPluginMetaData& metaData) { return metaData.serviceTypes().contains(QLatin1String("KFileItemAction/Plugin")); }); foreach (const auto& jsonMetadata, jsonPlugins) { const QString desktopEntryName = jsonMetadata.pluginId(); if (!isInServicesList(desktopEntryName)) { const bool checked = showGroup.readEntry(desktopEntryName, true); addRow(jsonMetadata.iconName(), jsonMetadata.name(), desktopEntryName, checked); } } m_sortModel->sort(Qt::DisplayRole); } void ServicesSettingsPage::loadVersionControlSystems() { const QStringList enabledPlugins = VersionControlSettings::enabledPlugins(); // Create a checkbox for each available version control plugin const KService::List pluginServices = KServiceTypeTrader::self()->query(QStringLiteral("FileViewVersionControlPlugin")); for (KService::List::ConstIterator it = pluginServices.constBegin(); it != pluginServices.constEnd(); ++it) { const QString pluginName = (*it)->name(); addRow(QStringLiteral("code-class"), pluginName, VersionControlServicePrefix + pluginName, enabledPlugins.contains(pluginName)); } m_sortModel->sort(Qt::DisplayRole); } bool ServicesSettingsPage::isInServicesList(const QString& service) const { for (int i = 0; i < m_serviceModel->rowCount(); ++i) { const QModelIndex index = m_serviceModel->index(i, 0); if (m_serviceModel->data(index, ServiceModel::DesktopEntryNameRole).toString() == service) { return true; } } return false; } void ServicesSettingsPage::addRow(const QString& icon, const QString& text, const QString& value, bool checked) { m_serviceModel->insertRow(0); const QModelIndex index = m_serviceModel->index(0, 0); m_serviceModel->setData(index, icon, Qt::DecorationRole); m_serviceModel->setData(index, text, Qt::DisplayRole); m_serviceModel->setData(index, value, ServiceModel::DesktopEntryNameRole); m_serviceModel->setData(index, checked, Qt::CheckStateRole); } diff --git a/src/views/draganddrophelper.cpp b/src/views/draganddrophelper.cpp index d437b877e..d248d00eb 100644 --- a/src/views/draganddrophelper.cpp +++ b/src/views/draganddrophelper.cpp @@ -1,77 +1,78 @@ /*************************************************************************** * Copyright (C) 2007-2011 by Peter Penz * * Copyright (C) 2007 by David Faure * * * * 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 "draganddrophelper.h" #include #include #include #include +#include #include QHash DragAndDropHelper::m_urlListMatchesUrlCache; bool DragAndDropHelper::urlListMatchesUrl(const QList& urls, const QUrl& destUrl) { auto iteratorResult = m_urlListMatchesUrlCache.constFind(destUrl); if (iteratorResult != m_urlListMatchesUrlCache.constEnd()) { return *iteratorResult; } const bool destUrlMatches = std::find_if(urls.constBegin(), urls.constEnd(), [destUrl](const QUrl& url) { return url.matches(destUrl, QUrl::StripTrailingSlash); }) != urls.constEnd(); return *m_urlListMatchesUrlCache.insert(destUrl, destUrlMatches); } KIO::DropJob* DragAndDropHelper::dropUrls(const QUrl& destUrl, QDropEvent* event, QWidget* window) { const QMimeData* mimeData = event->mimeData(); if (mimeData->hasFormat(QStringLiteral("application/x-kde-ark-dndextract-service")) && mimeData->hasFormat(QStringLiteral("application/x-kde-ark-dndextract-path"))) { const QString remoteDBusClient = mimeData->data(QStringLiteral("application/x-kde-ark-dndextract-service")); const QString remoteDBusPath = mimeData->data(QStringLiteral("application/x-kde-ark-dndextract-path")); QDBusMessage message = QDBusMessage::createMethodCall(remoteDBusClient, remoteDBusPath, QStringLiteral("org.kde.ark.DndExtract"), QStringLiteral("extractSelectedFilesTo")); message.setArguments({destUrl.toDisplayString(QUrl::PreferLocalFile)}); QDBusConnection::sessionBus().call(message); } else { if (urlListMatchesUrl(event->mimeData()->urls(), destUrl)) { return nullptr; } // Drop into a directory or a desktop-file KIO::DropJob *job = KIO::drop(event, destUrl); KJobWidgets::setWindow(job, window); return job; } return nullptr; } void DragAndDropHelper::clearUrlListMatchesUrlCache() { DragAndDropHelper::m_urlListMatchesUrlCache.clear(); }