From 465e06138e8baaefb967d32a2eaccf67daef8285 Mon Sep 17 00:00:00 2001 From: Elvis Angelaccio Date: Tue, 18 Aug 2020 23:47:53 +0200 Subject: [PATCH] Add support for KUserFeedback This commit introduces KUserFeedback in dolphin with some basic data sources and with a settings page to configure the telemetry values. There are also a couple custom data sources as proof of concept: a bunch of settings and the count of available network shares as listed by Solid. The settings page is shown only if the user feedback framework is enabled, but currently in Plasma we don't have a global kill switch to disable it. At the moment we never show an encouragement message. We need to connect to the `Provider::showEncouragementMessage()` signal, but first we should agree to a common way to show a non-annoying message to the users. --- CMakeLists.txt | 11 +++ src/CMakeLists.txt | 20 +++++ src/config-kuserfeedback.h.cmake | 1 + src/dolphinmainwindow.cpp | 10 +++ src/dolphinmainwindow.h | 3 + src/main.cpp | 9 +++ src/settings/dolphinsettingsdialog.cpp | 21 +++++ .../userfeedback/userfeedbacksettingspage.cpp | 47 ++++++++++++ .../userfeedback/userfeedbacksettingspage.h | 37 +++++++++ src/userfeedback/dolphinfeedbackprovider.cpp | 41 ++++++++++ src/userfeedback/dolphinfeedbackprovider.h | 28 +++++++ src/userfeedback/placesdatasource.cpp | 76 +++++++++++++++++++ src/userfeedback/placesdatasource.h | 25 ++++++ src/userfeedback/settingsdatasource.cpp | 55 ++++++++++++++ src/userfeedback/settingsdatasource.h | 27 +++++++ 15 files changed, 411 insertions(+) create mode 100644 src/config-kuserfeedback.h.cmake create mode 100644 src/settings/userfeedback/userfeedbacksettingspage.cpp create mode 100644 src/settings/userfeedback/userfeedbacksettingspage.h create mode 100644 src/userfeedback/dolphinfeedbackprovider.cpp create mode 100644 src/userfeedback/dolphinfeedbackprovider.h create mode 100644 src/userfeedback/placesdatasource.cpp create mode 100644 src/userfeedback/placesdatasource.h create mode 100644 src/userfeedback/settingsdatasource.cpp create mode 100644 src/userfeedback/settingsdatasource.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c1b1a7b846..49842bd4c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,17 @@ find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Crash WindowSystem ) + +find_package(KUserFeedback 1.0.0) +set_package_properties(KUserFeedback + PROPERTIES TYPE OPTIONAL + PURPOSE "Used for submission of telemetry data" + ) + +if(KUserFeedback_FOUND) + set(HAVE_KUSERFEEDBACK TRUE) +endif() + find_package(KF5 ${KF5_MIN_VERSION} OPTIONAL_COMPONENTS Activities ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c74855df62..bff52cf0f1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,6 +8,8 @@ configure_file(config-packagekit.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-pack configure_file(config-terminal.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-terminal.h) +configure_file(config-kuserfeedback.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kuserfeedback.h) + add_definitions( -DTRANSLATION_DOMAIN=\"dolphin\" ) @@ -261,6 +263,16 @@ if(HAVE_BALOO) ) endif() +if(HAVE_KUSERFEEDBACK) + set(dolphinstatic_SRCS + ${dolphinstatic_SRCS} + userfeedback/dolphinfeedbackprovider.cpp + userfeedback/settingsdatasource.cpp + userfeedback/placesdatasource.cpp + settings/userfeedback/userfeedbacksettingspage.cpp + ) +endif() + kconfig_add_kcfg_files(dolphinstatic_SRCS GENERATE_MOC panels/folders/dolphin_folderspanelsettings.kcfgc panels/information/dolphin_informationpanelsettings.kcfgc @@ -299,6 +311,14 @@ if (HAVE_KACTIVITIES) ) endif() +if (HAVE_KUSERFEEDBACK) + target_link_libraries( + dolphinstatic + KUserFeedbackCore + KUserFeedbackWidgets + ) +endif() + set(dolphin_SRCS dbusinterface.cpp main.cpp diff --git a/src/config-kuserfeedback.h.cmake b/src/config-kuserfeedback.h.cmake new file mode 100644 index 0000000000..1e79cc74bb --- /dev/null +++ b/src/config-kuserfeedback.h.cmake @@ -0,0 +1 @@ +#cmakedefine HAVE_KUSERFEEDBACK diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index e755e72817..97ced73b49 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -245,6 +245,16 @@ void DolphinMainWindow::openFiles(const QList& files, bool splitView) m_tabWidget->openFiles(files, splitView); } +bool DolphinMainWindow::isFoldersPanelEnabled() const +{ + return actionCollection()->action(QStringLiteral("show_folders_panel"))->isChecked(); +} + +bool DolphinMainWindow::isInformationPanelEnabled() const +{ + return actionCollection()->action(QStringLiteral("show_information_panel"))->isChecked(); +} + void DolphinMainWindow::openFiles(const QStringList& files, bool splitView) { openFiles(QUrl::fromStringList(files), splitView); diff --git a/src/dolphinmainwindow.h b/src/dolphinmainwindow.h index faf428c033..a56215fa7d 100644 --- a/src/dolphinmainwindow.h +++ b/src/dolphinmainwindow.h @@ -108,6 +108,9 @@ public: */ void setViewsWithInvalidPathsToHome(); + bool isFoldersPanelEnabled() const; + bool isInformationPanelEnabled() const; + public slots: /** * Opens each directory in \p dirs in a separate tab. If \a splitView is set, diff --git a/src/main.cpp b/src/main.cpp index d557f2ea03..ef2905d776 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,6 +12,10 @@ #include "dolphindebug.h" #include "dolphinmainwindow.h" #include "global.h" +#include "config-kuserfeedback.h" +#ifdef HAVE_KUSERFEEDBACK +#include "userfeedback/dolphinfeedbackprovider.h" +#endif #include #include @@ -210,5 +214,10 @@ extern "C" Q_DECL_EXPORT int kdemain(int argc, char **argv) } } +#ifdef HAVE_KUSERFEEDBACK + auto feedbackProvider = DolphinFeedbackProvider::instance(); + Q_UNUSED(feedbackProvider) +#endif + return app.exec(); // krazy:exclude=crash; } diff --git a/src/settings/dolphinsettingsdialog.cpp b/src/settings/dolphinsettingsdialog.cpp index 8e129e2419..9d8fb032a7 100644 --- a/src/settings/dolphinsettingsdialog.cpp +++ b/src/settings/dolphinsettingsdialog.cpp @@ -14,6 +14,11 @@ #include "startup/startupsettingspage.h" #include "trash/trashsettingspage.h" #include "viewmodes/viewsettingspage.h" +#include "config-kuserfeedback.h" +#ifdef HAVE_KUSERFEEDBACK +#include "userfeedback/dolphinfeedbackprovider.h" +#include "userfeedback/userfeedbacksettingspage.h" +#endif #include #include @@ -91,6 +96,17 @@ DolphinSettingsDialog::DolphinSettingsDialog(const QUrl& url, QWidget* parent) : connect(trashSettingsPage, &TrashSettingsPage::changed, this, &DolphinSettingsDialog::enableApply); } +#ifdef HAVE_KUSERFEEDBACK + // User Feedback + UserFeedbackSettingsPage* feedbackSettingsPage = nullptr; + if (DolphinFeedbackProvider::instance()->isEnabled()) { + feedbackSettingsPage = new UserFeedbackSettingsPage(this); + auto feedbackSettingsFrame = addPage(feedbackSettingsPage, i18nc("@title:group", "User Feedback")); + feedbackSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-locale"))); + connect(feedbackSettingsPage, &UserFeedbackSettingsPage::changed, this, &DolphinSettingsDialog::enableApply); + } +#endif + m_pages.append(generalSettingsPage); m_pages.append(startupSettingsPage); m_pages.append(viewSettingsPage); @@ -99,6 +115,11 @@ DolphinSettingsDialog::DolphinSettingsDialog(const QUrl& url, QWidget* parent) : if (trashSettingsPage) { m_pages.append(trashSettingsPage); } +#ifdef HAVE_KUSERFEEDBACK + if (feedbackSettingsPage) { + m_pages.append(feedbackSettingsPage); + } +#endif const KConfigGroup dialogConfig(KSharedConfig::openConfig(QStringLiteral("dolphinrc")), "SettingsDialog"); KWindowConfig::restoreWindowSize(windowHandle(), dialogConfig); diff --git a/src/settings/userfeedback/userfeedbacksettingspage.cpp b/src/settings/userfeedback/userfeedbacksettingspage.cpp new file mode 100644 index 0000000000..479c462265 --- /dev/null +++ b/src/settings/userfeedback/userfeedbacksettingspage.cpp @@ -0,0 +1,47 @@ +/* + * SPDX-FileCopyrightText: 2020 Elvis Angelaccio +#include + +#include + +UserFeedbackSettingsPage::UserFeedbackSettingsPage(QWidget* parent) : + SettingsPageBase(parent) +{ + auto layout = new QVBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + + m_feedbackWidget = new KUserFeedback::FeedbackConfigWidget(this); + m_feedbackWidget->setFeedbackProvider(DolphinFeedbackProvider::instance()); + + layout->addWidget(m_feedbackWidget); + + connect(m_feedbackWidget, &KUserFeedback::FeedbackConfigWidget::configurationChanged, this, &UserFeedbackSettingsPage::changed); +} + +UserFeedbackSettingsPage::~UserFeedbackSettingsPage() +{ +} + +void UserFeedbackSettingsPage::applySettings() +{ + auto feedbackProvider = DolphinFeedbackProvider::instance(); + feedbackProvider->setTelemetryMode(m_feedbackWidget->telemetryMode()); + feedbackProvider->setSurveyInterval(m_feedbackWidget->surveyInterval()); +} + +void UserFeedbackSettingsPage::restoreDefaults() +{ + auto feedbackProvider = DolphinFeedbackProvider::instance(); + feedbackProvider->setTelemetryMode(KUserFeedback::Provider::NoTelemetry); + feedbackProvider->setSurveyInterval(-1); +} + + diff --git a/src/settings/userfeedback/userfeedbacksettingspage.h b/src/settings/userfeedback/userfeedbacksettingspage.h new file mode 100644 index 0000000000..d9b6086152 --- /dev/null +++ b/src/settings/userfeedback/userfeedbacksettingspage.h @@ -0,0 +1,37 @@ +/* + * SPDX-FileCopyrightText: 2020 Elvis Angelaccio +#include +#include +#include +#include +#include +#include + +DolphinFeedbackProvider *DolphinFeedbackProvider::instance() +{ + static DolphinFeedbackProvider s_self; + return &s_self; +} + +DolphinFeedbackProvider::DolphinFeedbackProvider() + : KUserFeedback::Provider() +{ + setProductIdentifier(QStringLiteral("org.kde.dolphin")); + setFeedbackServer(QUrl(QStringLiteral("https://telemetry.kde.org"))); + setSubmissionInterval(7); + + addDataSource(new KUserFeedback::ApplicationVersionSource); + addDataSource(new KUserFeedback::LocaleInfoSource); + addDataSource(new KUserFeedback::PlatformInfoSource); + addDataSource(new KUserFeedback::QtVersionSource); + addDataSource(new KUserFeedback::ScreenInfoSource); + addDataSource(new KUserFeedback::StartCountSource); + addDataSource(new KUserFeedback::UsageTimeSource); + addDataSource(new PlacesDataSource); + addDataSource(new SettingsDataSource); +} diff --git a/src/userfeedback/dolphinfeedbackprovider.h b/src/userfeedback/dolphinfeedbackprovider.h new file mode 100644 index 0000000000..f6575d49fd --- /dev/null +++ b/src/userfeedback/dolphinfeedbackprovider.h @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2020 Elvis Angelaccio + +class DolphinFeedbackProvider : public KUserFeedback::Provider +{ + Q_OBJECT + +public: + static DolphinFeedbackProvider *instance(); + + DolphinFeedbackProvider(const DolphinFeedbackProvider&) = delete; + DolphinFeedbackProvider(DolphinFeedbackProvider&&) = delete; + DolphinFeedbackProvider& operator=(const DolphinFeedbackProvider&) = delete; + DolphinFeedbackProvider& operator=(DolphinFeedbackProvider&&) = delete; + +private: + DolphinFeedbackProvider(); +}; + +#endif // DOLPHINFEEDBACKPROVIDER_H diff --git a/src/userfeedback/placesdatasource.cpp b/src/userfeedback/placesdatasource.cpp new file mode 100644 index 0000000000..6db89636d0 --- /dev/null +++ b/src/userfeedback/placesdatasource.cpp @@ -0,0 +1,76 @@ +/* + * SPDX-FileCopyrightText: 2020 Elvis Angelaccio +#include +#include +#include +#include +#include + +#include + +PlacesDataSource::PlacesDataSource() + : KUserFeedback::AbstractDataSource(QStringLiteral("places"), KUserFeedback::Provider::DetailedSystemInformation) +{} + +QString PlacesDataSource::name() const +{ + return i18nc("name of kuserfeedback data source provided by dolphin", "Places"); +} + +QString PlacesDataSource::description() const +{ + // TODO: add count of remote places grouped by protocol type. + return i18nc("description of kuserfeedback data source provided by dolphin", "Count of available Network Shares"); +} + +QVariant PlacesDataSource::data() +{ + QVariantMap map; + + bool hasSSHFS = false; + bool hasSambaShare = false; + bool hasNfsShare = false; + + const auto devices = Solid::Device::listFromType(Solid::DeviceInterface::NetworkShare); + for (const auto &device : devices) { + if (!hasSSHFS && device.vendor() == QLatin1String("fuse.sshfs")) { + // Ignore kdeconnect SSHFS mounts, we already know that people have those. + auto storageAccess = device.as(); + if (storageAccess) { + auto mountPoint = KMountPoint::currentMountPoints().findByPath(storageAccess->filePath()); + if (!mountPoint->mountedFrom().startsWith(QLatin1String("kdeconnect@"))) { + hasSSHFS = true; + continue; + } + } + } + + if (!device.is()) { + continue; + } + + switch (device.as()->type()) { + case Solid::NetworkShare::Cifs: + hasSambaShare = true; + continue; + case Solid::NetworkShare::Nfs: + hasNfsShare = true; + continue; + default: + continue; + } + } + + map.insert(QStringLiteral("hasSSHFSMount"), hasSSHFS); + map.insert(QStringLiteral("hasSambaShare"), hasSambaShare); + map.insert(QStringLiteral("hasNfsShare"), hasNfsShare); + + return map; +} diff --git a/src/userfeedback/placesdatasource.h b/src/userfeedback/placesdatasource.h new file mode 100644 index 0000000000..f25f1067ca --- /dev/null +++ b/src/userfeedback/placesdatasource.h @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2020 Elvis Angelaccio + +class DolphinMainWindow; + +class PlacesDataSource : public KUserFeedback::AbstractDataSource +{ +public: + PlacesDataSource(); + + QString name() const override; + QString description() const override; + QVariant data() override; + +}; + +#endif // PLACESDATASOURCE_H diff --git a/src/userfeedback/settingsdatasource.cpp b/src/userfeedback/settingsdatasource.cpp new file mode 100644 index 0000000000..03a25ff750 --- /dev/null +++ b/src/userfeedback/settingsdatasource.cpp @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: 2020 Elvis Angelaccio +#include + +#include +#include + +SettingsDataSource::SettingsDataSource() + : KUserFeedback::AbstractDataSource(QStringLiteral("settings"), KUserFeedback::Provider::DetailedSystemInformation) +{} + +QString SettingsDataSource::name() const +{ + return i18nc("name of kuserfeedback data source provided by dolphin", "Settings"); +} + +QString SettingsDataSource::description() const +{ + return i18nc("description of kuserfeedback data source provided by dolphin", "A subset of Dolphin settings."); +} + +QVariant SettingsDataSource::data() +{ + if (!m_mainWindow) { + // This assumes there is only one DolphinMainWindow per process. + const auto topLevelWidgets = QApplication::topLevelWidgets(); + for (const auto widget : topLevelWidgets) { + if (qobject_cast(widget)) { + m_mainWindow = static_cast(widget); + break; + } + } + } + + QVariantMap map; + + if (m_mainWindow) { + map.insert(QStringLiteral("informationPanelEnabled"), m_mainWindow->isInformationPanelEnabled()); + map.insert(QStringLiteral("foldersPanelEnabled"), m_mainWindow->isFoldersPanelEnabled()); + } + + map.insert(QStringLiteral("tooltipsEnabled"), GeneralSettings::showToolTips()); + map.insert(QStringLiteral("browseArchivesEnable"), GeneralSettings::browseThroughArchives()); + + return map; +} diff --git a/src/userfeedback/settingsdatasource.h b/src/userfeedback/settingsdatasource.h new file mode 100644 index 0000000000..9804c78a79 --- /dev/null +++ b/src/userfeedback/settingsdatasource.h @@ -0,0 +1,27 @@ +/* + * SPDX-FileCopyrightText: 2020 Elvis Angelaccio + +class DolphinMainWindow; + +class SettingsDataSource : public KUserFeedback::AbstractDataSource +{ +public: + SettingsDataSource(); + + QString name() const override; + QString description() const override; + QVariant data() override; + +private: + DolphinMainWindow *m_mainWindow = nullptr; +}; + +#endif // SETTINGSDATASOURCE_H