aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVitaly Fanaskov <vitaly.fanaskov@qt.io>2019-06-14 13:52:10 +0200
committerVitaly Fanaskov <vitaly.fanaskov@qt.io>2019-06-19 16:58:23 +0200
commitcb6a29b86acb9d7f163e32bda4a7d6aa7775d69d (patch)
tree4b7fe01731567d00c4dbe20f2551bc6f914e32e2
Create a plugin for collecting usage statistics
The following data might be collected: 1) Builds count 2) Used build systems 3) Opened examples 4) Used kits (detailed info) 5) Modes usage 6) QML designer usage time 7) License type Also all common data (system info, graphic, app version, etc.) might be collected as well. Plugin is built atop of KUserFeedback framework and uses its architecture and routines for collecting and sending data. KUserFeedback is not included to this repository and supposed to be built and installed separately by CI. Static build of KUserFeedback is used, so plugin doesn't depend on any 3rd-party dynamic libraries. URL for sending data and authentication key should be set during the build process. Change-Id: Ibf0cf4986031689b5f46925664cebadcb0fe3aef
-rw-r--r--.gitignore44
-rw-r--r--UsageStatistic.json.in11
-rw-r--r--common/scopedsettingsgroupsetter.cpp60
-rw-r--r--common/scopedsettingsgroupsetter.h63
-rw-r--r--common/utils.h37
-rw-r--r--datasources/buildcountsource.cpp92
-rw-r--r--datasources/buildcountsource.h69
-rw-r--r--datasources/buildsystemsource.cpp135
-rw-r--r--datasources/buildsystemsource.h81
-rw-r--r--datasources/examplesdatasource.cpp118
-rw-r--r--datasources/examplesdatasource.h69
-rw-r--r--datasources/kitsource.cpp192
-rw-r--r--datasources/kitsource.h84
-rw-r--r--datasources/modeusagetimesource.cpp153
-rw-r--r--datasources/modeusagetimesource.h88
-rw-r--r--datasources/qmldesignerusagetimesource.cpp102
-rw-r--r--datasources/qmldesignerusagetimesource.h49
-rw-r--r--datasources/qtclicensesource.cpp97
-rw-r--r--datasources/qtclicensesource.h55
-rw-r--r--datasources/timeusagesourcebase.cpp103
-rw-r--r--datasources/timeusagesourcebase.h79
-rw-r--r--services/datasubmitter.cpp62
-rw-r--r--services/datasubmitter.h43
-rw-r--r--ui/encouragementwidget.cpp99
-rw-r--r--ui/encouragementwidget.h68
-rw-r--r--ui/encouragementwidget.ui71
-rw-r--r--ui/outputpane.cpp119
-rw-r--r--ui/outputpane.h93
-rw-r--r--ui/usagestatisticpage.cpp90
-rw-r--r--ui/usagestatisticpage.h66
-rw-r--r--ui/usagestatisticwidget.cpp203
-rw-r--r--ui/usagestatisticwidget.h94
-rw-r--r--ui/usagestatisticwidget.ui161
-rw-r--r--usagestatistic.pro93
-rw-r--r--usagestatistic_global.h9
-rw-r--r--usagestatisticconstants.h41
-rw-r--r--usagestatisticplugin.cpp195
-rw-r--r--usagestatisticplugin.h71
38 files changed, 3359 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..235bada
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,44 @@
+
+# C++ objects and libs
+*.slo
+*.lo
+*.o
+*.a
+*.la
+*.lai
+*.so
+*.dll
+*.dylib
+
+# Qt-es
+object_script.*.Release
+object_script.*.Debug
+*_plugin_import.cpp
+/.qmake.cache
+/.qmake.stash
+*.pro.user
+*.pro.user.*
+*.qbs.user
+*.qbs.user.*
+*.moc
+moc_*.cpp
+moc_*.h
+qrc_*.cpp
+ui_*.h
+*.qmlc
+*.jsc
+Makefile*
+*build-*
+
+# Qt unit tests
+target_wrapper.*
+
+# QtCreator
+*.autosave
+
+# QtCreator Qml
+*.qmlproject.user
+*.qmlproject.user.*
+
+# QtCreator CMake
+CMakeLists.txt.user*
diff --git a/UsageStatistic.json.in b/UsageStatistic.json.in
new file mode 100644
index 0000000..9e7bde3
--- /dev/null
+++ b/UsageStatistic.json.in
@@ -0,0 +1,11 @@
+{
+ \"Name\" : \"UsageStatistic\",
+ \"Version\" : \"1.0.0\",
+ \"CompatVersion\" : \"1.0.0\",
+ \"Vendor\" : \"The Qt Company Ltd\",
+ \"Copyright\" : \"(C) The Qt Company Ltd\",
+ \"License\" : \"GNU GPL v3\",
+ \"Description\" : \"This plugin is used to collect usage statistic. All statistics are anonymous. You can switch off the plugin any time you want.\",
+ \"Url\" : \"https://www.qt.io/\",
+ $$dependencyList
+}
diff --git a/common/scopedsettingsgroupsetter.cpp b/common/scopedsettingsgroupsetter.cpp
new file mode 100644
index 0000000..472b6fd
--- /dev/null
+++ b/common/scopedsettingsgroupsetter.cpp
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "scopedsettingsgroupsetter.h"
+
+#include <QSettings>
+
+#include <KUserFeedback/AbstractDataSource>
+
+#include "usagestatisticconstants.h"
+
+namespace UsageStatistic {
+namespace Internal {
+
+ScopedSettingsGroupSetter::ScopedSettingsGroupSetter(QSettings &settings,
+ const std::initializer_list<QString> &prefixes)
+ : m_settings(settings)
+ , m_prefixesCount(int(prefixes.size()))
+{
+ for (auto &&prefix : prefixes) {
+ m_settings.beginGroup(prefix);
+ }
+}
+
+ScopedSettingsGroupSetter::~ScopedSettingsGroupSetter()
+{
+ while (m_prefixesCount-- > 0) {
+ m_settings.endGroup();
+ }
+}
+
+ScopedSettingsGroupSetter ScopedSettingsGroupSetter::forDataSource(
+ const KUserFeedback::AbstractDataSource &ds, QSettings &settings)
+{
+ return ScopedSettingsGroupSetter(settings, {Constants::DATA_SOURCES_SETTINGS_GROUP, ds.id()});
+}
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/common/scopedsettingsgroupsetter.h b/common/scopedsettingsgroupsetter.h
new file mode 100644
index 0000000..c66f318
--- /dev/null
+++ b/common/scopedsettingsgroupsetter.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include <memory>
+
+#include <QtCore/QtGlobal>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace KUserFeedback { class AbstractDataSource; }
+
+namespace UsageStatistic {
+namespace Internal {
+
+//! Used to set the specific set of group prefixes. Everything will be unset in the destructor
+class ScopedSettingsGroupSetter
+{
+public:
+ ScopedSettingsGroupSetter(QSettings &settings, const std::initializer_list<QString> &prefixes);
+
+ ScopedSettingsGroupSetter(const ScopedSettingsGroupSetter &) = delete;
+ ScopedSettingsGroupSetter(ScopedSettingsGroupSetter &&) = delete;
+
+ ScopedSettingsGroupSetter &operator =(const ScopedSettingsGroupSetter &) = delete;
+ ScopedSettingsGroupSetter &operator =(ScopedSettingsGroupSetter &&) = delete;
+
+ ~ScopedSettingsGroupSetter();
+
+ static ScopedSettingsGroupSetter forDataSource(const KUserFeedback::AbstractDataSource &ds,
+ QSettings &settings);
+
+private:
+ QSettings &m_settings;
+ int m_prefixesCount;
+};
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/common/utils.h b/common/utils.h
new file mode 100644
index 0000000..a2eb689
--- /dev/null
+++ b/common/utils.h
@@ -0,0 +1,37 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include <QtCore/QString>
+
+namespace UsageStatistic::Internal::Utils {
+
+//! Secret key for authentication defined during building
+constexpr auto secret() { return USP_AUTH_KEY; }
+
+//! Base server URL defined during building
+constexpr auto serverUrl() { return USP_SERVER_URL; }
+
+} // namespace UsageStatistic::Internal::Utils
diff --git a/datasources/buildcountsource.cpp b/datasources/buildcountsource.cpp
new file mode 100644
index 0000000..1a42305
--- /dev/null
+++ b/datasources/buildcountsource.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "buildcountsource.h"
+
+#include <QtCore/QSettings>
+
+#include "common/scopedsettingsgroupsetter.h"
+
+#include <projectexplorer/buildmanager.h>
+
+#include <KUserFeedback/Provider>
+
+namespace UsageStatistic {
+namespace Internal {
+
+using namespace KUserFeedback;
+
+BuildCountSource::BuildCountSource()
+ : AbstractDataSource(QStringLiteral("buildsCount"), Provider::DetailedUsageStatistics)
+{
+ QObject::connect(ProjectExplorer::BuildManager::instance(),
+ &ProjectExplorer::BuildManager::buildQueueFinished,
+ [&](bool success){ ++(success ? m_succeededBuildsCount : m_failedBuildsCount); });
+}
+
+QString BuildCountSource::name() const
+{
+ return tr("Builds count");
+}
+
+QString BuildCountSource::description() const
+{
+ return tr("Count of succeeded and failed builds.");
+}
+
+static QString succeededKey() { return QStringLiteral("succeeded"); }
+static QString failedKey() { return QStringLiteral("failed"); }
+static QString totalKey() { return QStringLiteral("total"); }
+
+QVariant BuildCountSource::data()
+{
+ return QVariantMap{{succeededKey(), m_succeededBuildsCount},
+ {failedKey(), m_failedBuildsCount},
+ {totalKey(), m_succeededBuildsCount + m_failedBuildsCount}};
+}
+
+void BuildCountSource::loadImpl(QSettings *settings)
+{
+ auto setter = ScopedSettingsGroupSetter::forDataSource(*this, *settings);
+ m_succeededBuildsCount = qvariant_cast<quint64>(settings->value(succeededKey(), succeededCountDflt()));
+ m_failedBuildsCount = qvariant_cast<quint64>(settings->value(failedKey(), failedCountDflt()));
+}
+
+void BuildCountSource::storeImpl(QSettings *settings)
+{
+ auto setter = ScopedSettingsGroupSetter::forDataSource(*this, *settings);
+ settings->setValue(succeededKey(), m_succeededBuildsCount);
+ settings->setValue(failedKey(), m_failedBuildsCount);
+}
+
+void BuildCountSource::resetImpl(QSettings *settings)
+{
+ m_succeededBuildsCount = succeededCountDflt();
+ m_failedBuildsCount = failedCountDflt();
+
+ storeImpl(settings);
+}
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/datasources/buildcountsource.h b/datasources/buildcountsource.h
new file mode 100644
index 0000000..0cee9c4
--- /dev/null
+++ b/datasources/buildcountsource.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include <QCoreApplication>
+
+#include <KUserFeedback/AbstractDataSource>
+
+namespace UsageStatistic {
+namespace Internal {
+
+//! Tracks succeeded, failed, and total builds count
+class BuildCountSource : public KUserFeedback::AbstractDataSource
+{
+ Q_DECLARE_TR_FUNCTIONS(BuildCountDataSource)
+
+public:
+ BuildCountSource();
+
+public: // AbstractDataSource interface
+ QString name() const override;
+ QString description() const override;
+
+ /*! The output data format is:
+ * {
+ * "succeeded": int,
+ * "failed" : int,
+ * "total" : int
+ * }
+ */
+ QVariant data() override;
+
+ void loadImpl(QSettings *settings) override;
+ void storeImpl(QSettings *settings) override;
+ void resetImpl(QSettings *settings) override;
+
+private:
+ static constexpr quint64 succeededCountDflt() { return 0; }
+ static constexpr quint64 failedCountDflt() { return 0; }
+
+private:
+ quint64 m_succeededBuildsCount = succeededCountDflt();
+ quint64 m_failedBuildsCount = failedCountDflt();
+};
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/datasources/buildsystemsource.cpp b/datasources/buildsystemsource.cpp
new file mode 100644
index 0000000..26433c0
--- /dev/null
+++ b/datasources/buildsystemsource.cpp
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "buildsystemsource.h"
+
+#include <QtCore/QSettings>
+
+#include <projectexplorer/project.h>
+#include <projectexplorer/session.h>
+
+#include <KUserFeedback/Provider>
+
+#include "common/scopedsettingsgroupsetter.h"
+
+namespace UsageStatistic {
+namespace Internal {
+
+using namespace KUserFeedback;
+
+// Keep synchronized with BuildSystemSource::BuildSystem {
+static const auto &buildSystemMarks()
+{
+ static const QString marks[] = {".qt4", ".cmake", ".qbs", ".autotools"};
+ return marks;
+}
+
+static const auto &buildSystemKeys()
+{
+ static const QString keys[] = {"qmake", "cmake", "qbs", "autotools", "other"};
+ return keys;
+}
+// }
+
+static BuildSystemSource::BuildSystem extractBuildSystemType(const QString &name)
+{
+ auto begin = std::begin(buildSystemMarks());
+ auto end = std::end(buildSystemMarks());
+
+ auto it = std::find_if(begin, end, [&](const QString &m){ return name.contains(m); });
+ return it != end ? BuildSystemSource::BuildSystem(std::distance(begin, it))
+ : BuildSystemSource::Other;
+}
+
+BuildSystemSource::BuildSystemSource()
+ : AbstractDataSource(QStringLiteral("buildSystem"), Provider::DetailedUsageStatistics)
+{
+ connect(ProjectExplorer::SessionManager::instance(),
+ &ProjectExplorer::SessionManager::projectAdded,
+ this, &BuildSystemSource::updateProjects);
+
+ connect(ProjectExplorer::SessionManager::instance(),
+ &ProjectExplorer::SessionManager::sessionLoaded,
+ this, &BuildSystemSource::updateProjects);
+}
+
+BuildSystemSource::~BuildSystemSource() = default;
+
+QString BuildSystemSource::name() const
+{
+ return tr("Build system type");
+}
+
+QString BuildSystemSource::description() const
+{
+ return tr("Count of each used build systems");
+}
+
+QVariant BuildSystemSource::data()
+{
+ QVariantMap result;
+ for (int i = QMake; i < Count; ++i) {
+ result[buildSystemKeys()[i]] = m_projectsByBuildSystem[size_t(i)].count();
+ }
+
+ return result;
+}
+
+void BuildSystemSource::loadImpl(QSettings *settings)
+{
+ auto setter = ScopedSettingsGroupSetter::forDataSource(*this, *settings);
+ for (int i = QMake; i < Count; ++i) {
+ m_projectsByBuildSystem[size_t(i)] =
+ settings->value(buildSystemKeys()[i]).toStringList().toSet();
+ }
+}
+
+void BuildSystemSource::storeImpl(QSettings *settings)
+{
+ auto setter = ScopedSettingsGroupSetter::forDataSource(*this, *settings);
+ for (int i = QMake; i < Count; ++i) {
+ settings->setValue(
+ buildSystemKeys()[i], QStringList(m_projectsByBuildSystem[size_t(i)].toList()));
+ }
+}
+
+void BuildSystemSource::resetImpl(QSettings *settings)
+{
+ ProjectsByBuildSystem().swap(m_projectsByBuildSystem);
+ storeImpl(settings);
+}
+
+void BuildSystemSource::updateProjects()
+{
+ for (auto project : ProjectExplorer::SessionManager::projects()) {
+ if (project) {
+ auto projectName = QString::fromUtf8(project->id().name()).toLower();
+ auto projectPath = project->projectFilePath().toString();
+ m_projectsByBuildSystem[extractBuildSystemType(projectName)] << projectPath;
+ }
+ }
+}
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/datasources/buildsystemsource.h b/datasources/buildsystemsource.h
new file mode 100644
index 0000000..d390c37
--- /dev/null
+++ b/datasources/buildsystemsource.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include <array>
+
+#include <QCoreApplication>
+#include <QSet>
+
+#include <KUserFeedback/AbstractDataSource>
+
+namespace UsageStatistic {
+namespace Internal {
+
+//! Tracks which build system is used for projects
+class BuildSystemSource : public QObject, public KUserFeedback::AbstractDataSource
+{
+ Q_OBJECT
+
+public: // Types
+ enum BuildSystem { QMake, CMake, Qbs, Autotools, Other, Count };
+
+public:
+ BuildSystemSource();
+ ~BuildSystemSource() override;
+
+public: // AbstractDataSource interface
+ QString name() const override;
+ QString description() const override;
+
+ /*! The output data format is (the value is projects count):
+ * {
+ * "autotools": int,
+ * "cmake" : int,
+ * "other" : int,
+ * "qbs" : int,
+ * "qmake" : int
+ * }
+ */
+ QVariant data() override;
+
+ void loadImpl(QSettings *settings) override;
+ void storeImpl(QSettings *settings) override;
+ void resetImpl(QSettings *settings) override;
+
+private:
+ void updateProjects();
+
+private:
+ // Index is build system type
+ // Element is a set of full project paths. Full project path is used
+ // as a permanent unique identifier. This identifier is only for
+ // storing locally on user machine and should never be sent!
+ using ProjectsByBuildSystem = std::array<QSet<QString>, Count>;
+ ProjectsByBuildSystem m_projectsByBuildSystem;
+};
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/datasources/examplesdatasource.cpp b/datasources/examplesdatasource.cpp
new file mode 100644
index 0000000..7d5e909
--- /dev/null
+++ b/datasources/examplesdatasource.cpp
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "examplesdatasource.h"
+
+#include <QtCore/QSettings>
+#include <QtCore/QRegularExpression>
+
+#include <projectexplorer/project.h>
+#include <projectexplorer/session.h>
+
+#include <common/scopedsettingsgroupsetter.h>
+
+namespace UsageStatistic {
+namespace Internal {
+
+using namespace KUserFeedback;
+
+ExamplesDataSource::ExamplesDataSource()
+ : AbstractDataSource(QStringLiteral("examplesData"), Provider::DetailedUsageStatistics)
+{
+ connect(ProjectExplorer::SessionManager::instance(),
+ &ProjectExplorer::SessionManager::startupProjectChanged,
+ this, &ExamplesDataSource::updateOpenedExamples);
+
+ connect(ProjectExplorer::SessionManager::instance(),
+ &ProjectExplorer::SessionManager::projectAdded,
+ this, &ExamplesDataSource::updateOpenedExamples);
+
+ connect(ProjectExplorer::SessionManager::instance(),
+ &ProjectExplorer::SessionManager::sessionLoaded,
+ this, &ExamplesDataSource::updateOpenedExamples);
+}
+
+ExamplesDataSource::~ExamplesDataSource() = default;
+
+QString ExamplesDataSource::name() const
+{
+ return tr("Examples");
+}
+
+QString ExamplesDataSource::description() const
+{
+ return tr("The list of examples openned by the user. "
+ "Only example paths are collected and sent, for example: "
+ "widgets/mainwindows/application/application.pro");
+}
+
+static QString examplesKey() { return QStringLiteral("examples"); }
+
+QVariant ExamplesDataSource::data()
+{
+ return QVariantMap{{examplesKey(), QVariant(m_examplePaths.toList())}};
+}
+
+void ExamplesDataSource::loadImpl(QSettings *settings)
+{
+ auto setter = ScopedSettingsGroupSetter::forDataSource(*this, *settings);
+ m_examplePaths = settings->value(examplesKey()).toStringList().toSet();
+}
+
+void ExamplesDataSource::storeImpl(QSettings *settings)
+{
+ auto setter = ScopedSettingsGroupSetter::forDataSource(*this, *settings);
+ settings->setValue(examplesKey(), QStringList(m_examplePaths.toList()));
+}
+
+void ExamplesDataSource::resetImpl(QSettings *settings)
+{
+ m_examplePaths.clear();
+ storeImpl(settings);
+}
+
+static QString examplePathGroupName() { return QStringLiteral("examplePathGroup"); }
+
+static QString examplePattern()
+{
+ return QStringLiteral("/Examples/Qt-(\\d+\\.*){1,3}/(?<%1>.*)$");
+}
+
+void ExamplesDataSource::updateOpenedExamples()
+{
+ QRegularExpression re(examplePattern().arg(examplePathGroupName()));
+ for (auto project : ProjectExplorer::SessionManager::projects()) {
+ if (project) {
+ auto projectPath = QDir::fromNativeSeparators(project->projectFilePath().toString());
+ if (auto match = re.match(projectPath); match.hasMatch()) {
+ m_examplePaths << match.captured(examplePathGroupName());
+ }
+ }
+ }
+}
+
+} // namespace Internal
+} // namespace UsageStatistic
+
+
diff --git a/datasources/examplesdatasource.h b/datasources/examplesdatasource.h
new file mode 100644
index 0000000..19b5779
--- /dev/null
+++ b/datasources/examplesdatasource.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include <QtCore/QSet>
+
+#include <KUserFeedback/AbstractDataSource>
+
+namespace UsageStatistic {
+namespace Internal {
+
+//! Tracks which examples were opened by the user
+class ExamplesDataSource : public QObject, public KUserFeedback::AbstractDataSource
+{
+ Q_OBJECT
+
+public:
+ ExamplesDataSource();
+ ~ExamplesDataSource() override;
+
+public: // AbstractDataSource interface
+ QString name() const override;
+ QString description() const override;
+
+ /*! The output data format is:
+ * {
+ * "examples": []
+ * }
+ *
+ * The array contains paths like "widgets/mainwindows/application/application.pro".
+ * Full paths aren't collected.
+ */
+ QVariant data() override;
+
+ void loadImpl(QSettings *settings) override;
+ void storeImpl(QSettings *settings) override;
+ void resetImpl(QSettings *settings) override;
+
+private: // Methods
+ void updateOpenedExamples();
+
+private: // Data
+ QSet<QString> m_examplePaths;
+};
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/datasources/kitsource.cpp b/datasources/kitsource.cpp
new file mode 100644
index 0000000..500e1ea
--- /dev/null
+++ b/datasources/kitsource.cpp
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "kitsource.h"
+
+#include <QtCore/QSettings>
+
+#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/kitmanager.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/gcctoolchain.h>
+#include <qtsupport/qtkitinformation.h>
+#include <debugger/debuggerkitinformation.h>
+#include <debugger/debuggeritem.h>
+
+#include "common/scopedsettingsgroupsetter.h"
+
+namespace UsageStatistic {
+namespace Internal {
+
+using namespace KUserFeedback;
+using namespace ProjectExplorer;
+
+KitSource::KitSource()
+ : AbstractDataSource(QStringLiteral("kits"), Provider::DetailedUsageStatistics)
+{
+}
+
+KitSource::~KitSource() = default;
+
+QString KitSource::name() const
+{
+ return tr("Kits");
+}
+
+QString KitSource::description() const
+{
+ return tr("Kits usage statistic: compilers, debuggers, target architecture etc.");
+}
+
+static QString kitsInfoKey() { return QStringLiteral("kitsInfo"); }
+
+static QString extractToolChainVersion(const ToolChain &toolChain)
+{
+ try {
+ return dynamic_cast<const GccToolChain &>(toolChain).version();
+ } catch (...) {
+ return {};
+ }
+}
+
+class KitInfo
+{
+public:
+ KitInfo &withQtVersionInfo()
+ {
+ static const QString qtKey = QStringLiteral("qt");
+ static const QString qtQmlDebuggingSupportKey = QStringLiteral("qmlDebugging");
+ static const QString qtQmlCompilerSupportKey = QStringLiteral("qmlCompiler");
+ static const QString qtAbisKey = QStringLiteral("abis");
+
+ if (auto qtVersion = QtSupport::QtKitInformation::qtVersion(&m_kit)) {
+ QVariantMap qtData;
+ qtData.insert(versionKey(), qtVersion->qtVersionString());
+ qtData.insert(qtQmlDebuggingSupportKey, qtVersion->isQmlDebuggingSupported());
+ qtData.insert(qtQmlCompilerSupportKey, qtVersion->isQtQuickCompilerSupported());
+ qtData.insert(qtAbisKey, abisToVarinatList(qtVersion->qtAbis()));
+
+ m_map.insert(qtKey, qtData);
+ }
+
+ return *this;
+ }
+
+ KitInfo &withCompilerInfo()
+ {
+ static const QString compilerKey = QStringLiteral("compiler");
+
+ if (auto toolChain = ToolChainKitInformation::toolChain(&m_kit, Constants::CXX_LANGUAGE_ID)) {
+ m_map.insert(compilerKey,
+ QVariantMap{{nameKey(), toolChain->typeDisplayName()},
+ {versionKey(), extractToolChainVersion(*toolChain)}});
+ }
+
+ return *this;
+ }
+
+ KitInfo &withDebuggerInfo()
+ {
+ static const QString debuggerKey = QStringLiteral("debugger");
+
+ if (auto debuggerInfo = Debugger::DebuggerKitInformation::debugger(&m_kit)) {
+ m_map.insert(debuggerKey,
+ QVariantMap{{nameKey(), debuggerInfo->engineTypeName()},
+ {versionKey(), debuggerInfo->version()}});
+ }
+
+ return *this;
+ }
+
+ QVariantMap extract() const { return m_map; }
+
+ static KitInfo forKit(Kit &kit) { return KitInfo(kit); }
+
+private: // Methods
+ KitInfo(Kit &kit) : m_kit(kit) { addKitInfo(); }
+
+ void addKitInfo()
+ {
+ static QString defaultKitKey = QStringLiteral("default");
+
+ m_map.insert(defaultKitKey, &m_kit == KitManager::defaultKit());
+ }
+
+ static QVariantMap abiToVariantMap(const Abi &abi)
+ {
+ static const QString archKey = QStringLiteral("arch");
+ static const QString osKey = QStringLiteral("os");
+ static const QString osFlavorKey = QStringLiteral("osFlavor");
+ static const QString binaryFormatKey = QStringLiteral("binaryFormat");
+ static const QString wordWidthKey = QStringLiteral("wordWidth");
+
+ return QVariantMap{{archKey , Abi::toString(abi.architecture())},
+ {osKey , Abi::toString(abi.os()) },
+ {osFlavorKey , Abi::toString(abi.osFlavor()) },
+ {binaryFormatKey, Abi::toString(abi.binaryFormat())},
+ {wordWidthKey , Abi::toString(abi.wordWidth()) }};
+ }
+
+ template <class Container>
+ QVariantList abisToVarinatList(const Container &abis)
+ {
+ QVariantList result;
+ for (auto &&abi : abis) {
+ result << abiToVariantMap(abi);
+ }
+
+ return result;
+ }
+
+ static QString versionKey() { return QStringLiteral("version"); }
+ static QString nameKey() { return QStringLiteral("name"); }
+
+private: // Data
+ Kit &m_kit;
+ QVariantMap m_map;
+};
+
+static QVariantList kitsInfo()
+{
+ QVariantList kitsInfoList;
+ for (auto &&kit : KitManager::instance()->kits()) {
+ if (kit && kit->isValid()) {
+ kitsInfoList << KitInfo::forKit(*kit)
+ .withCompilerInfo()
+ .withDebuggerInfo()
+ .withQtVersionInfo()
+ .extract();
+ }
+ }
+
+ return kitsInfoList;
+}
+
+QVariant KitSource::data()
+{
+ return QVariantMap{{kitsInfoKey(), kitsInfo()}};
+}
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/datasources/kitsource.h b/datasources/kitsource.h
new file mode 100644
index 0000000..4256c01
--- /dev/null
+++ b/datasources/kitsource.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include <QVariantMap>
+
+#include <KUserFeedback/AbstractDataSource>
+
+namespace UsageStatistic {
+namespace Internal {
+
+//! Tracks which toolkits are used
+class KitSource : public QObject, public KUserFeedback::AbstractDataSource
+{
+ Q_OBJECT
+
+public:
+ KitSource();
+ ~KitSource() override;
+
+public: // AbstractDataSource interface
+ QString name() const override;
+ QString description() const override;
+
+ /*! The output data format is:
+ * {
+ * "kitsInfo": [
+ * {
+ * "compiler": {
+ * "name" : string,
+ * "version": int
+ * },
+ * "debugger": {
+ * "name" : string,
+ * "version": string,
+ * },
+ * "default": bool,
+ * "qt": {
+ * "abis": [
+ * {
+ * "arch" : string,
+ * "binaryFormat": string,
+ * "os" : string,
+ * "osFlavor" : string,
+ * "wordWidth" : string
+ * }
+ * ],
+ * "qmlCompiler" : bool,
+ * "qmlDebugging": bool,
+ * "version" : string
+ * }
+ * },
+ * ]
+ * }
+ *
+ * The version format if "\d+.\d+.\d+".
+ */
+ QVariant data() override;
+};
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/datasources/modeusagetimesource.cpp b/datasources/modeusagetimesource.cpp
new file mode 100644
index 0000000..445e419
--- /dev/null
+++ b/datasources/modeusagetimesource.cpp
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "modeusagetimesource.h"
+
+#include <QtCore/QSettings>
+
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/modemanager.h>
+
+#include <KUserFeedback/Provider>
+
+#include "common/scopedsettingsgroupsetter.h"
+
+namespace UsageStatistic {
+namespace Internal {
+
+using namespace KUserFeedback;
+
+ModeUsageTimeSource::ModeUsageTimeSource()
+ : AbstractDataSource(QStringLiteral("modeUsageTime"), Provider::DetailedUsageStatistics)
+{
+ connect(Core::ModeManager::instance(), &Core::ModeManager::currentModeChanged,
+ this, &ModeUsageTimeSource::onCurrentModeIdChanged);
+ onCurrentModeIdChanged(Core::ModeManager::currentModeId());
+}
+
+ModeUsageTimeSource::~ModeUsageTimeSource() = default;
+
+QString ModeUsageTimeSource::name() const
+{
+ return tr("Modes usage time");
+}
+
+QString ModeUsageTimeSource::description() const
+{
+ return tr("How much time a user spent working in each mode (edit, debug, design, etc.)");
+}
+
+// Keep synced with ModeUsageTimeSource::Mode {
+static const auto &modeMarks()
+{
+ static const QString marks[] = {"welcome", "edit", "design", "debug", "project", "help", "other"};
+ return marks;
+}
+// }
+
+static ModeUsageTimeSource::Mode modeFromString(const QString &modeString)
+{
+ auto begin = std::begin(modeMarks());
+ auto end = std::end(modeMarks());
+
+ auto it = std::find_if(begin, end, [&](const QString &mark) { return modeString.contains(mark); });
+
+ return it != end ? ModeUsageTimeSource::Mode(std::distance(begin, it))
+ : ModeUsageTimeSource::Other;
+}
+
+QVariant ModeUsageTimeSource::data()
+{
+ QVariantMap result;
+
+ for (std::size_t i = Welcome; i < ModesCount; ++i) {
+ result[modeMarks()[i]] = m_timeByModes[i];
+ }
+
+ return result;
+}
+
+void ModeUsageTimeSource::loadImpl(QSettings *settings)
+{
+ auto setter = ScopedSettingsGroupSetter::forDataSource(*this, *settings);
+ for (std::size_t i = Welcome; i < ModesCount; ++i) {
+ m_timeByModes[i] = qvariant_cast<qint64>(settings->value(modeMarks()[i], timeDflt()));
+ }
+}
+
+void ModeUsageTimeSource::storeImpl(QSettings *settings)
+{
+ storeCurrentTimerValue();
+
+ auto setter = ScopedSettingsGroupSetter::forDataSource(*this, *settings);
+ for (std::size_t i = Welcome; i < ModesCount; ++i) {
+ settings->setValue(modeMarks()[i], m_timeByModes[i]);
+ }
+}
+
+void ModeUsageTimeSource::resetImpl(QSettings *settings)
+{
+ std::fill(std::begin(m_timeByModes), std::end(m_timeByModes), timeDflt());
+ storeImpl(settings);
+}
+
+void ModeUsageTimeSource::setCurrentMode(ModeUsageTimeSource::Mode mode)
+{
+ m_currentMode = mode;
+}
+
+ModeUsageTimeSource::Mode ModeUsageTimeSource::currentMode() const
+{
+ return m_currentMode;
+}
+
+void ModeUsageTimeSource::onCurrentModeIdChanged(const Core::Id &modeId)
+{
+ auto mode = modeFromString(QString::fromUtf8(modeId.name().toLower().simplified()));
+
+ if (m_currentMode == mode) {
+ return;
+ }
+
+ if (m_currentTimer.isValid() && m_currentMode < ModesCount) {
+ m_timeByModes[m_currentMode] += m_currentTimer.elapsed();
+ m_currentTimer.invalidate();
+ }
+
+ m_currentMode = mode;
+
+ if (m_currentMode != ModesCount) {
+ m_currentTimer.start();
+ }
+}
+
+void ModeUsageTimeSource::storeCurrentTimerValue()
+{
+ if (m_currentTimer.isValid() && m_currentMode < ModesCount) {
+ m_timeByModes[m_currentMode] += m_currentTimer.restart();
+ }
+}
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/datasources/modeusagetimesource.h b/datasources/modeusagetimesource.h
new file mode 100644
index 0000000..9094d1e
--- /dev/null
+++ b/datasources/modeusagetimesource.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include <QtCore/QElapsedTimer>
+
+#include <coreplugin/id.h>
+
+#include <KUserFeedback/AbstractDataSource>
+
+namespace UsageStatistic {
+namespace Internal {
+
+//! Tracks which modes were used and for how long
+class ModeUsageTimeSource : public QObject, public KUserFeedback::AbstractDataSource
+{
+ Q_OBJECT
+
+public: // Types
+ enum Mode {Welcome, Edit, Design, Debug, Projects, Help, Other, ModesCount};
+
+public:
+ ModeUsageTimeSource();
+ ~ModeUsageTimeSource() override;
+
+public: // AbstractDataSource interface
+ QString name() const override;
+ QString description() const override;
+
+ /*! The output data format is:
+ * {
+ * "debug" : int,
+ * "design" : int,
+ * "edit" : int,
+ * "help" : int,
+ * "other" : int,
+ * "project": int,
+ * "welcome": int
+ * }
+ *
+ * The value is duration in milliseconds.
+ */
+ QVariant data() override;
+
+ void loadImpl(QSettings *settings) override;
+ void storeImpl(QSettings *settings) override;
+ void resetImpl(QSettings *settings) override;
+
+private: // Data
+ Mode m_currentMode = ModesCount;
+ QElapsedTimer m_currentTimer;
+ std::array<qint64, ModesCount> m_timeByModes{};
+
+private: // Methods
+ void setCurrentMode(Mode mode);
+ Mode currentMode() const;
+
+ void onCurrentModeIdChanged(const Core::Id &modeId);
+
+ void storeCurrentTimerValue();
+
+ static constexpr qint64 timeDflt() { return 0; }
+};
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/datasources/qmldesignerusagetimesource.cpp b/datasources/qmldesignerusagetimesource.cpp
new file mode 100644
index 0000000..6f983e7
--- /dev/null
+++ b/datasources/qmldesignerusagetimesource.cpp
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "qmldesignerusagetimesource.h"
+
+#include <QtCore/QFileInfo>
+
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/editormanager/ieditor.h>
+#include <coreplugin/modemanager.h>
+#include <coreplugin/imode.h>
+
+namespace UsageStatistic {
+namespace Internal {
+
+static QString currentModeName()
+{
+ if (auto modeManager = Core::ModeManager::instance()) {
+ if (auto mode = modeManager->currentMode()) {
+ return mode->displayName().toLower();
+ }
+ }
+
+ return {};
+}
+
+QmlDesignerUsageTimeSource::QmlDesignerUsageTimeSource()
+ : TimeUsageSourceBase(QStringLiteral("qmlDesignerUsageTime"))
+{
+ connect(Core::ModeManager::instance(), &Core::ModeManager::currentModeChanged,
+ this, [this](auto &&modeId){
+ updateTrackingState(QString::fromUtf8(modeId.name().toLower())); });
+
+ connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged,
+ this, [this](){ updateTrackingState(currentModeName()); });
+}
+
+QmlDesignerUsageTimeSource::~QmlDesignerUsageTimeSource() = default;
+
+QString QmlDesignerUsageTimeSource::name() const
+{
+ return tr("QmlDesigner usage time");
+}
+
+QString QmlDesignerUsageTimeSource::description() const
+{
+ return tr("How long a user spent editing QML files in designer mode");
+}
+
+static bool isDesignMode(const QString &modeName)
+{
+ static const QString designModeName = QStringLiteral("design");
+ return modeName == designModeName;
+}
+
+static bool editingQmlFile()
+{
+ static const QSet<QString> validExtentions = {"qml", "qml.ui"};
+ static const QString validMimeType = "qml";
+
+ if (auto document = Core::EditorManager::currentDocument()) {
+ QString mimeType = document->mimeType().toLower();
+ QString extension = document->filePath().toFileInfo().completeSuffix().toLower();
+
+ return validExtentions.contains(extension) || mimeType.contains(validMimeType);
+ }
+
+ return false;
+}
+
+void QmlDesignerUsageTimeSource::updateTrackingState(const QString &modeName)
+{
+ if (isDesignMode(modeName) && editingQmlFile() && !isTimeTrackingActive()) {
+ Q_EMIT start();
+ } else {
+ Q_EMIT stop();
+ }
+}
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/datasources/qmldesignerusagetimesource.h b/datasources/qmldesignerusagetimesource.h
new file mode 100644
index 0000000..3cadf57
--- /dev/null
+++ b/datasources/qmldesignerusagetimesource.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include "timeusagesourcebase.h"
+
+namespace UsageStatistic {
+namespace Internal {
+
+//! Tracks time spent using QML Designer
+class QmlDesignerUsageTimeSource : public TimeUsageSourceBase
+{
+public:
+ QmlDesignerUsageTimeSource();
+ ~QmlDesignerUsageTimeSource() override;
+
+public: // AbstractDataSource interface
+ QString name() const override;
+ QString description() const override;
+
+private: // Methods
+ void updateTrackingState(const QString &modeName);
+};
+
+} // namespace Internal
+} // namespace UsageStatistic
+
diff --git a/datasources/qtclicensesource.cpp b/datasources/qtclicensesource.cpp
new file mode 100644
index 0000000..3bf7907
--- /dev/null
+++ b/datasources/qtclicensesource.cpp
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "qtclicensesource.h"
+
+#include <coreplugin/icore.h>
+#include <extensionsystem/iplugin.h>
+#include <extensionsystem/pluginmanager.h>
+#include <extensionsystem/pluginspec.h>
+
+#include <KUserFeedback/Provider>
+
+namespace UsageStatistic {
+namespace Internal {
+
+using namespace KUserFeedback;
+
+QtcLicenseSource::QtcLicenseSource()
+ : AbstractDataSource(QStringLiteral("qtcLicense"), Provider::DetailedUsageStatistics)
+{}
+
+QString QtcLicenseSource::description() const
+{
+ return tr("Qt Creator license type string: opensource, evaluation, commercial");
+}
+
+QString QtcLicenseSource::name() const
+{
+ return tr("Qt Creator license");
+}
+
+static const auto evaluationStr = QStringLiteral("evaluation");
+static const auto opensourceStr = QStringLiteral("opensource");
+static const auto commercialStr = QStringLiteral("commercial");
+
+static bool isLicenseChecker(const ExtensionSystem::PluginSpec *spec)
+{
+ if (!spec) {
+ return false;
+ }
+
+ static const auto pluginName = QStringLiteral("LicenseChecker");
+ return spec->name().contains(pluginName);
+}
+
+static bool hasEvaluationLicense(ExtensionSystem::IPlugin *plugin)
+{
+ if (!plugin) {
+ return false;
+ }
+
+ bool isEvaluation = false;
+
+ static const auto checkMethodName = "evaluationLicense";
+ QMetaObject::invokeMethod(plugin, checkMethodName, Q_RETURN_ARG(bool, isEvaluation));
+
+ return isEvaluation;
+}
+
+static QString licenseString()
+{
+ const auto plugins = ExtensionSystem::PluginManager::plugins();
+ if (auto it = std::find_if(plugins.begin(), plugins.end(), &isLicenseChecker); it != plugins.end()) {
+ return hasEvaluationLicense((*it)->plugin()) ? evaluationStr: commercialStr;
+ }
+
+ return opensourceStr;
+}
+
+QVariant QtcLicenseSource::data()
+{
+ return QVariantMap{{"value", licenseString()}};
+}
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/datasources/qtclicensesource.h b/datasources/qtclicensesource.h
new file mode 100644
index 0000000..80630d2
--- /dev/null
+++ b/datasources/qtclicensesource.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include <QCoreApplication>
+
+#include <KUserFeedback/AbstractDataSource>
+
+namespace UsageStatistic {
+namespace Internal {
+
+//! Tracks whether commercial or open source version is used
+class QtcLicenseSource : public KUserFeedback::AbstractDataSource
+{
+ Q_DECLARE_TR_FUNCTIONS(QtcLicenseSource)
+
+public:
+ QtcLicenseSource();
+
+public: // AbstractDataSource interface
+ QString description() const override;
+ QString name() const override;
+
+ /*! The output data format is:
+ * {
+ * "value": string
+ * }
+ */
+ QVariant data() override;
+};
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/datasources/timeusagesourcebase.cpp b/datasources/timeusagesourcebase.cpp
new file mode 100644
index 0000000..ab4c1e1
--- /dev/null
+++ b/datasources/timeusagesourcebase.cpp
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "timeusagesourcebase.h"
+
+#include <QtCore/QVariant>
+#include <QtCore/QSettings>
+
+#include <KUserFeedback/Provider>
+
+#include <common/scopedsettingsgroupsetter.h>
+
+namespace UsageStatistic {
+namespace Internal {
+
+using namespace KUserFeedback;
+
+TimeUsageSourceBase::TimeUsageSourceBase(const QString &id)
+ : AbstractDataSource(id, Provider::DetailedUsageStatistics)
+{
+ connect(this, &TimeUsageSourceBase::start, this, &TimeUsageSourceBase::onStarted);
+ connect(this, &TimeUsageSourceBase::stop, this, &TimeUsageSourceBase::onStopped);
+}
+
+void TimeUsageSourceBase::onStarted()
+{
+ // Restart if required
+ if (m_timer.isValid()) {
+ onStopped();
+ }
+
+ ++m_startCount;
+ m_timer.start();
+}
+
+void TimeUsageSourceBase::onStopped()
+{
+ if (m_timer.isValid()) {
+ m_usageTime += m_timer.elapsed();
+ }
+
+ m_timer.invalidate();
+}
+
+bool TimeUsageSourceBase::isTimeTrackingActive() const
+{
+ return m_timer.isValid();
+}
+
+static QString usageTimeKey() { return QStringLiteral("usageTime"); }
+static QString startCountKey() { return QStringLiteral("startCount"); }
+
+QVariant TimeUsageSourceBase::data()
+{
+ return QVariantMap{{usageTimeKey(), m_usageTime}, {startCountKey(), m_startCount}};
+}
+
+void TimeUsageSourceBase::loadImpl(QSettings *settings)
+{
+ auto setter = ScopedSettingsGroupSetter::forDataSource(*this, *settings);
+ m_usageTime = settings->value(usageTimeKey(), usageTimeDflt()).toLongLong();
+ m_startCount = settings->value(startCountKey(), startCountDflt()).toLongLong();
+}
+
+void TimeUsageSourceBase::storeImpl(QSettings *settings)
+{
+ auto setter = ScopedSettingsGroupSetter::forDataSource(*this, *settings);
+ settings->setValue(usageTimeKey(), m_usageTime);
+ settings->setValue(startCountKey(), m_startCount);
+}
+
+void TimeUsageSourceBase::resetImpl(QSettings *settings)
+{
+ m_usageTime = usageTimeDflt();
+ m_startCount = startCountDflt();
+ storeImpl(settings);
+}
+
+TimeUsageSourceBase::~TimeUsageSourceBase() = default;
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/datasources/timeusagesourcebase.h b/datasources/timeusagesourcebase.h
new file mode 100644
index 0000000..e3d3730
--- /dev/null
+++ b/datasources/timeusagesourcebase.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include <QtCore/QObject>
+#include <QtCore/QElapsedTimer>
+
+#include <KUserFeedback/AbstractDataSource>
+
+namespace UsageStatistic {
+namespace Internal {
+
+//! Base class for all time trackers
+class TimeUsageSourceBase : public QObject, public KUserFeedback::AbstractDataSource
+{
+ Q_OBJECT
+
+public:
+ ~TimeUsageSourceBase() override;
+
+public: // AbstractDataSource interface
+ /*! The output data format is:
+ * {
+ * "startCount": int,
+ * "usageTime" : int
+ * }
+ */
+ QVariant data() override;
+
+ void loadImpl(QSettings *settings) override;
+ void storeImpl(QSettings *settings) override;
+ void resetImpl(QSettings *settings) override;
+
+protected:
+ TimeUsageSourceBase(const QString &id);
+
+ void onStarted();
+ void onStopped();
+
+ bool isTimeTrackingActive() const;
+
+Q_SIGNALS:
+ void start();
+ void stop();
+
+private:
+ static constexpr qint64 usageTimeDflt() { return 0; }
+ static constexpr qint64 startCountDflt() { return 0; }
+
+private:
+ QElapsedTimer m_timer;
+ qint64 m_usageTime = usageTimeDflt();
+ qint64 m_startCount = startCountDflt();
+};
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/services/datasubmitter.cpp b/services/datasubmitter.cpp
new file mode 100644
index 0000000..ecdab32
--- /dev/null
+++ b/services/datasubmitter.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "datasubmitter.h"
+
+#include <QtCore/QCoreApplication>
+
+#include "common/utils.h"
+
+namespace UsageStatistic {
+namespace Internal {
+
+using namespace KUserFeedback;
+
+DataSubmitter::DataSubmitter() = default;
+
+static QString makeVersionString()
+{
+ return qApp ? qApp->applicationName().append("/").append(qApp->applicationVersion()) : "";
+}
+
+static QByteArray authHeaderName()
+{
+ return QByteArrayLiteral("Authorization");
+}
+
+QNetworkRequest DataSubmitter::dataRequest() const
+{
+ QNetworkRequest request(serverUrl());
+
+ if (auto versionString = makeVersionString(); !versionString.isEmpty()) {
+ request.setHeader(QNetworkRequest::UserAgentHeader, versionString);
+ }
+
+ request.setRawHeader(authHeaderName(), QByteArray(Utils::secret()));
+
+ return request;
+}
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/services/datasubmitter.h b/services/datasubmitter.h
new file mode 100644
index 0000000..1ae66ac
--- /dev/null
+++ b/services/datasubmitter.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include <KUserFeedback/AbstractJsonDataSubmitter>
+
+namespace UsageStatistic {
+namespace Internal {
+
+//! Data submitter which also sets authorization and version headers
+class DataSubmitter : public KUserFeedback::AbstractJsonDataSubmitter
+{
+public:
+ DataSubmitter();
+
+public: // AbstractDataSubmitter interface
+ QNetworkRequest dataRequest() const override;
+};
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/ui/encouragementwidget.cpp b/ui/encouragementwidget.cpp
new file mode 100644
index 0000000..b1a84bc
--- /dev/null
+++ b/ui/encouragementwidget.cpp
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "encouragementwidget.h"
+#include "ui_encouragementwidget.h"
+
+#include "coreplugin/icore.h"
+
+#include <KUserFeedback/FeedbackConfigUiController>
+
+#include "usagestatisticconstants.h"
+
+namespace UsageStatistic::Internal {
+
+using namespace KUserFeedback;
+
+EncouragementWidget::EncouragementWidget(QWidget *parent)
+ : QWidget(parent)
+ , ui(new Ui::EncouragementWidget)
+ , m_controller(std::make_unique<FeedbackConfigUiController>())
+{
+ ui->setupUi(this);
+
+ connect(this, &EncouragementWidget::providerChanged,
+ this, &EncouragementWidget::onProviderChanged);
+ connect(ui->pbOptions, &QPushButton::clicked,
+ this, &EncouragementWidget::showSettingsDialog);
+}
+
+std::shared_ptr<Provider> EncouragementWidget::provider() const
+{
+ return m_provider;
+}
+
+void EncouragementWidget::setProvider(std::shared_ptr<Provider> provider)
+{
+ m_provider = std::move(provider);
+
+ Q_EMIT providerChanged(m_provider);
+}
+
+void EncouragementWidget::showEvent(QShowEvent *event)
+{
+ updateMessage();
+ QWidget::showEvent(event);
+}
+
+void EncouragementWidget::showSettingsDialog()
+{
+ Core::ICore::showOptionsDialog(Constants::USAGE_STATISTIC_PAGE_ID, this);
+}
+
+void EncouragementWidget::updateMessage()
+{
+ if (m_provider) {
+ auto modeIndex = m_controller->telemetryModeToIndex(m_provider->telemetryMode());
+
+ auto description = m_controller->telemetryModeDescription(modeIndex);
+
+ auto modeName = m_controller->telemetryModeName(modeIndex);
+ description.prepend(tr("Telemetry mode: %1.\n").arg(modeName));
+
+ ui->lblMsg->setText(description);
+ }
+}
+
+void EncouragementWidget::onProviderChanged(const std::shared_ptr<Provider> &p)
+{
+ m_controller->setFeedbackProvider(p.get());
+
+ connect(m_provider.get(), &Provider::telemetryModeChanged,
+ this, &EncouragementWidget::updateMessage);
+ updateMessage();
+}
+
+EncouragementWidget::~EncouragementWidget() = default;
+
+} // namespace UsageStatistic::Internal
diff --git a/ui/encouragementwidget.h b/ui/encouragementwidget.h
new file mode 100644
index 0000000..6d299d0
--- /dev/null
+++ b/ui/encouragementwidget.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include <memory>
+
+#include <QWidget>
+
+namespace KUserFeedback {
+class Provider;
+class FeedbackConfigUiController;
+}
+
+namespace UsageStatistic::Internal {
+
+namespace Ui { class EncouragementWidget; }
+
+//! Widget for displaying current telemetry level at the output pane
+class EncouragementWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit EncouragementWidget(QWidget *parent = nullptr);
+ ~EncouragementWidget() override;
+
+ std::shared_ptr<KUserFeedback::Provider> provider() const;
+ void setProvider(std::shared_ptr<KUserFeedback::Provider> provider);
+
+protected: // QWidget interface
+ void showEvent(QShowEvent *event) override;
+
+Q_SIGNALS:
+ void providerChanged(const std::shared_ptr<KUserFeedback::Provider> &);
+
+private Q_SLOTS:
+ void showSettingsDialog();
+ void updateMessage();
+ void onProviderChanged(const std::shared_ptr<KUserFeedback::Provider> &p);
+
+private:
+ QScopedPointer<Ui::EncouragementWidget> ui;
+ std::shared_ptr<KUserFeedback::Provider> m_provider;
+ std::unique_ptr<KUserFeedback::FeedbackConfigUiController> m_controller;
+};
+
+} // namespace UsageStatistic::Internal
+
diff --git a/ui/encouragementwidget.ui b/ui/encouragementwidget.ui
new file mode 100644
index 0000000..19f24a1
--- /dev/null
+++ b/ui/encouragementwidget.ui
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UsageStatistic::Internal::EncouragementWidget</class>
+ <widget class="QWidget" name="UsageStatistic::Internal::EncouragementWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>572</width>
+ <height>70</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="lblMsg">
+ <property name="text">
+ <string>Message here...</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="pbOptions">
+ <property name="text">
+ <string>&amp;Adjust telemetry settings</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/ui/outputpane.cpp b/ui/outputpane.cpp
new file mode 100644
index 0000000..a635815
--- /dev/null
+++ b/ui/outputpane.cpp
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "outputpane.h"
+
+#include <QtWidgets/QPushButton>
+#include <QtWidgets/QHBoxLayout>
+#include <QtCore/QDebug>
+
+#include "encouragementwidget.h"
+
+namespace UsageStatistic::Internal {
+
+OutputPane::OutputPane() = default;
+
+OutputPane::~OutputPane() = default;
+
+QWidget *OutputPane::outputWidget(QWidget *parent)
+{
+ if (!m_outputPaneWidget) {
+ createEncouragementWidget(parent);
+ }
+
+ return m_outputPaneWidget;
+}
+
+QList<QWidget *> OutputPane::toolBarWidgets() const
+{
+ return {};
+}
+
+QString OutputPane::displayName() const
+{
+ return tr("Feedback");
+}
+
+int OutputPane::priorityInStatusBar() const
+{
+ return 1;
+}
+
+void OutputPane::clearContents() {}
+
+void OutputPane::visibilityChanged(bool /*visible*/)
+{
+}
+
+void OutputPane::setFocus() {}
+
+bool OutputPane::hasFocus() const
+{
+ return false;
+}
+
+bool OutputPane::canFocus() const
+{
+ return true;
+}
+
+bool OutputPane::canNavigate() const
+{
+ return false;
+}
+
+bool OutputPane::canNext() const
+{
+ return false;
+}
+
+bool OutputPane::canPrevious() const
+{
+ return false;
+}
+
+void OutputPane::goToNext() {}
+
+void OutputPane::goToPrev() {}
+
+void OutputPane::createEncouragementWidget(QWidget *parent)
+{
+ auto wgt = new EncouragementWidget(parent);
+ connect(this, &OutputPane::providerChanged, wgt, &EncouragementWidget::setProvider);
+
+ m_outputPaneWidget = wgt;
+}
+
+std::shared_ptr<KUserFeedback::Provider> OutputPane::provider() const
+{
+ return m_provider;
+}
+
+void OutputPane::setProvider(std::shared_ptr<KUserFeedback::Provider> provider)
+{
+ m_provider = std::move(provider);
+ Q_EMIT providerChanged(m_provider);
+}
+
+} // namespace UsageStatistic::Internal
diff --git a/ui/outputpane.h b/ui/outputpane.h
new file mode 100644
index 0000000..3965db6
--- /dev/null
+++ b/ui/outputpane.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include <memory>
+
+#include <QtCore/QPointer>
+#include <QtWidgets/QWidget>
+
+#include <coreplugin/ioutputpane.h>
+
+QT_BEGIN_NAMESPACE
+class QHBoxLayout;
+QT_END_NAMESPACE
+
+namespace KUserFeedback { class Provider; }
+
+namespace UsageStatistic::Internal {
+
+class EncouragementWidget;
+
+//! Output pane for displayed different different information (telemetry level, surveys, etc.)
+class OutputPane : public Core::IOutputPane
+{
+ Q_OBJECT
+
+public:
+ OutputPane();
+ ~OutputPane() override;
+
+public: // IOutputPane interface
+ QWidget *outputWidget(QWidget *parent) override;
+
+ QList<QWidget *> toolBarWidgets() const override;
+
+ QString displayName() const override;
+
+ int priorityInStatusBar() const override;
+
+ void clearContents() override;
+
+ void visibilityChanged(bool visible) override;
+
+ void setFocus() override;
+ bool hasFocus() const override;
+
+ bool canFocus() const override;
+ bool canNavigate() const override;
+ bool canNext() const override;
+ bool canPrevious() const override;
+
+ void goToNext() override;
+ void goToPrev() override;
+
+ std::shared_ptr<KUserFeedback::Provider> provider() const;
+ void setProvider(std::shared_ptr<KUserFeedback::Provider> provider);
+
+Q_SIGNALS:
+ void providerChanged(std::shared_ptr<KUserFeedback::Provider>);
+
+private: // Methods
+ void createEncouragementWidget(QWidget *parent);
+
+private: // Data
+ std::shared_ptr<KUserFeedback::Provider> m_provider;
+ QPointer<QWidget> m_outputPaneWidget;
+};
+
+} // namespace UsageStatistic::Internal
+
+Q_DECLARE_METATYPE(std::shared_ptr<KUserFeedback::Provider>)
diff --git a/ui/usagestatisticpage.cpp b/ui/usagestatisticpage.cpp
new file mode 100644
index 0000000..50fe5c1
--- /dev/null
+++ b/ui/usagestatisticpage.cpp
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "usagestatisticpage.h"
+
+#include <KUserFeedback/AbstractDataSource>
+
+#include "usagestatisticwidget.h"
+#include "usagestatisticconstants.h"
+
+namespace UsageStatistic {
+namespace Internal {
+
+UsageStatisticPage::UsageStatisticPage(std::shared_ptr<KUserFeedback::Provider> provider)
+ : m_provider(std::move(provider))
+{
+ configure();
+}
+
+UsageStatisticPage::~UsageStatisticPage() = default;
+
+QWidget *UsageStatisticPage::widget()
+{
+ if (!m_feedbackWidget) {
+ m_feedbackWidget = std::make_unique<UsageStatisticWidget>(m_provider);
+ m_feedbackWidget->updateSettings();
+ }
+
+ return m_feedbackWidget.get();
+}
+
+static void applyDataSourcesActiveStatuses(const QHash<QString, bool> &statuses,
+ const KUserFeedback::Provider &provider)
+{
+ for (auto &&ds : provider.dataSources()) {
+ if (ds) {
+ if (auto it = statuses.find(ds->id()); it != std::end(statuses)) {
+ ds->setActive(*it);
+ }
+ }
+ }
+}
+
+void UsageStatisticPage::apply()
+{
+ auto settings = m_feedbackWidget->settings();
+
+ m_provider->setTelemetryMode(settings.telemetryMode);
+ applyDataSourcesActiveStatuses(settings.activeStatusesById, *m_provider);
+
+ Q_EMIT settingsChanged();
+}
+
+void UsageStatisticPage::finish()
+{
+ m_feedbackWidget.reset();
+}
+
+void UsageStatisticPage::configure()
+{
+ setId(Constants::USAGE_STATISTIC_PAGE_ID);
+ setCategory(Constants::TELEMETRY_SETTINGS_CATEGORY_ID);
+
+ setDisplayName(tr("Usage Statistic"));
+ setDisplayCategory(tr("Telemetry"));
+}
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/ui/usagestatisticpage.h b/ui/usagestatisticpage.h
new file mode 100644
index 0000000..1052611
--- /dev/null
+++ b/ui/usagestatisticpage.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include <memory>
+
+#include <QtCore/QPointer>
+
+#include <coreplugin/dialogs/ioptionspage.h>
+
+namespace KUserFeedback { class Provider; }
+
+namespace UsageStatistic {
+namespace Internal {
+
+class UsageStatisticWidget;
+
+//! Settings page
+class UsageStatisticPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ UsageStatisticPage(std::shared_ptr<KUserFeedback::Provider> provider);
+ ~UsageStatisticPage() override;
+
+public: // IOptionsPage interface
+ QWidget *widget() override;
+ void apply() override;
+ void finish() override;
+
+Q_SIGNALS:
+ void settingsChanged();
+
+private: // Data
+ std::unique_ptr<UsageStatisticWidget> m_feedbackWidget;
+ std::shared_ptr<KUserFeedback::Provider> m_provider;
+
+private: // Methods
+ void configure();
+};
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/ui/usagestatisticwidget.cpp b/ui/usagestatisticwidget.cpp
new file mode 100644
index 0000000..5d9f692
--- /dev/null
+++ b/ui/usagestatisticwidget.cpp
@@ -0,0 +1,203 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "usagestatisticwidget.h"
+#include "ui_usagestatisticwidget.h"
+
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+#include <QtCore/QJsonDocument>
+
+#include <KUserFeedback/FeedbackConfigUiController>
+#include <KUserFeedback/AbstractDataSource>
+
+#include "usagestatisticconstants.h"
+
+namespace UsageStatistic {
+namespace Internal {
+
+using namespace KUserFeedback;
+
+UsageStatisticWidget::UsageStatisticWidget(std::shared_ptr<KUserFeedback::Provider> provider)
+ : ui(std::make_unique<Ui::UsageStatisticWidget>())
+ , m_provider(std::move(provider))
+ , m_controller(std::make_unique<FeedbackConfigUiController>())
+{
+ ui->setupUi(this);
+
+ configure();
+
+ addPrivacyPolicyLink();
+}
+
+void UsageStatisticWidget::updateSettings()
+{
+ setupActiveStatuses();
+ setupTelemetryModeUi();
+}
+
+UsageStatisticWidget::Settings UsageStatisticWidget::settings() const
+{
+ return {m_controller->telemetryIndexToMode(ui->cbMode->currentIndex()), m_activeStatusesById};
+}
+
+static constexpr int dataSourceIDRole = Qt::UserRole + 1;
+
+void UsageStatisticWidget::configure()
+{
+ m_controller->setFeedbackProvider(m_provider.get());
+
+ connect(ui->cbMode, qOverload<int>(&QComboBox::currentIndexChanged),
+ this, &UsageStatisticWidget::updateTelemetryModeDescription);
+ connect(ui->cbMode, qOverload<int>(&QComboBox::currentIndexChanged),
+ [this](int index) { preserveCurrentActiveStatuses(); updateDataSources(index); });
+
+ connect(ui->lvDataSources, &QListWidget::currentItemChanged,
+ this, &UsageStatisticWidget::updateDataSource);
+ connect(ui->lvDataSources, &QListWidget::itemChanged,
+ this, &UsageStatisticWidget::updateActiveStatus);
+}
+
+void UsageStatisticWidget::setupTelemetryModeUi()
+{
+ ui->cbMode->clear();
+ for (int i = 0; i < m_controller->telemetryModeCount(); ++i) {
+ ui->cbMode->addItem(QString("%1 - %2").arg(i).arg(m_controller->telemetryModeName(i)));
+ }
+
+ ui->cbMode->setCurrentIndex(m_controller->telemetryModeToIndex(m_provider->telemetryMode()));
+}
+
+void UsageStatisticWidget::updateTelemetryModeDescription(int modeIndex)
+{
+ ui->pteTelemetryLvlDescription->setPlainText(m_controller->telemetryModeDescription(modeIndex));
+}
+
+static auto dataSourceToItem(const AbstractDataSource &ds,
+ const UsageStatisticWidget::ActiveStatusesById &activeStatusesById)
+{
+ auto item = std::make_unique<QListWidgetItem>(ds.name());
+
+ item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
+ if (auto it = activeStatusesById.find(ds.id()); it != std::end(activeStatusesById)) {
+ item->setCheckState(*it ? Qt::Checked : Qt::Unchecked);
+ } else {
+ item->setCheckState(Qt::Checked);
+ }
+
+ item->setData(dataSourceIDRole, ds.id());
+
+ return item;
+}
+
+void UsageStatisticWidget::updateDataSources(int modeIndex)
+{
+ ui->lvDataSources->clear();
+
+ for (auto &&ds : m_provider->dataSources()) {
+ if (ds && ds->telemetryMode() <= m_controller->telemetryIndexToMode(modeIndex)) {
+ auto item = dataSourceToItem(*ds, m_activeStatusesById).release();
+ ui->lvDataSources->addItem(item);
+
+ if (m_currentItemId == ds->id()) {
+ ui->lvDataSources->setCurrentItem(item);
+ }
+ }
+ }
+}
+
+static QString collectedData(AbstractDataSource &ds)
+{
+ QByteArray result;
+ auto variantData = ds.data();
+
+ if (variantData.canConvert<QVariantMap>()) {
+ result = QJsonDocument(QJsonObject::fromVariantMap(variantData.toMap())).toJson();
+ }
+
+ if (variantData.canConvert<QVariantList>()) {
+ result = QJsonDocument(QJsonArray::fromVariantList(variantData.value<QVariantList>())).toJson();
+ }
+
+ return QString::fromUtf8(result);
+}
+
+void UsageStatisticWidget::updateDataSource(QListWidgetItem *item)
+{
+ if (item) {
+ m_currentItemId = item->data(dataSourceIDRole).toString();
+
+ if (auto ds = m_provider->dataSource(m_currentItemId)) {
+ ui->pteDataSourceDescription->setPlainText(ds->description());
+ ui->pteCollectedData->setPlainText(collectedData(*ds));
+ }
+ } else {
+ ui->pteDataSourceDescription->clear();
+ ui->pteCollectedData->clear();
+ }
+}
+
+void UsageStatisticWidget::updateActiveStatus(QListWidgetItem *item)
+{
+ if (item) {
+ auto id = item->data(dataSourceIDRole).toString();
+ m_activeStatusesById[id] = item->checkState() == Qt::Checked;
+ }
+}
+
+void UsageStatisticWidget::preserveCurrentActiveStatuses()
+{
+ for (int row = 0; row < ui->lvDataSources->count(); ++row) {
+ if (auto item = ui->lvDataSources->item(row)) {
+ auto id = item->data(dataSourceIDRole).toString();
+ m_activeStatusesById[id] = item->checkState() == Qt::Checked;
+ }
+ }
+}
+
+void UsageStatisticWidget::setupActiveStatuses()
+{
+ m_activeStatusesById.clear();
+
+ for (auto &&ds : m_provider->dataSources()) {
+ if (ds) {
+ m_activeStatusesById[ds->id()] = ds->isActive();
+ }
+ }
+}
+
+void UsageStatisticWidget::addPrivacyPolicyLink()
+{
+ const auto currentText = ui->lblPrivacyPolicy->text();
+ const auto linkTemplate = QString("<a href=\"%1\">%2<\\a>");
+ ui->lblPrivacyPolicy->setText(linkTemplate.arg(Constants::PRIVACY_POLICY_URL, currentText));
+
+ const auto tooltipTemplate = tr("Open %1");
+ ui->lblPrivacyPolicy->setToolTip(tooltipTemplate.arg(Constants::PRIVACY_POLICY_URL));
+}
+
+UsageStatisticWidget::~UsageStatisticWidget() = default;
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/ui/usagestatisticwidget.h b/ui/usagestatisticwidget.h
new file mode 100644
index 0000000..fb3341a
--- /dev/null
+++ b/ui/usagestatisticwidget.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include <memory>
+
+#include <QtWidgets/QWidget>
+#include <QtCore/QHash>
+
+#include <KUserFeedback/Provider>
+
+namespace KUserFeedback { class FeedbackConfigUiController; }
+
+QT_BEGIN_NAMESPACE
+class QListWidgetItem;
+QT_END_NAMESPACE
+
+namespace UsageStatistic {
+namespace Internal {
+
+namespace Ui { class UsageStatisticWidget; }
+
+//! Telemetry settings widget
+class UsageStatisticWidget : public QWidget
+{
+ Q_OBJECT
+
+public: // Types
+ using ActiveStatusesById = QHash<QString, bool>;
+
+ struct Settings
+ {
+ KUserFeedback::Provider::TelemetryMode telemetryMode;
+ ActiveStatusesById activeStatusesById;
+ };
+
+public:
+ explicit UsageStatisticWidget(std::shared_ptr<KUserFeedback::Provider> provider);
+ ~UsageStatisticWidget() override;
+
+ void updateSettings();
+
+ Settings settings() const;
+
+private: // Methods
+ void configure();
+
+ void setupTelemetryModeUi();
+ void updateTelemetryModeDescription(int modeIndex);
+
+ void updateDataSources(int modeIndex);
+
+ void updateDataSource(QListWidgetItem *item);
+ void updateActiveStatus(QListWidgetItem *item);
+
+ void preserveCurrentActiveStatuses();
+
+ void setupActiveStatuses();
+
+ void addPrivacyPolicyLink();
+
+private: // Data
+ std::unique_ptr<Ui::UsageStatisticWidget> ui;
+ std::shared_ptr<KUserFeedback::Provider> m_provider;
+ std::unique_ptr<KUserFeedback::FeedbackConfigUiController> m_controller;
+
+ QString m_currentItemId;
+ ActiveStatusesById m_activeStatusesById;
+};
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/ui/usagestatisticwidget.ui b/ui/usagestatisticwidget.ui
new file mode 100644
index 0000000..484b69a
--- /dev/null
+++ b/ui/usagestatisticwidget.ui
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UsageStatistic::Internal::UsageStatisticWidget</class>
+ <widget class="QWidget" name="UsageStatistic::Internal::UsageStatisticWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>676</width>
+ <height>527</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <item>
+ <widget class="QGroupBox" name="gbTelemetryMode">
+ <property name="title">
+ <string>&amp;Telemetry mode</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QComboBox" name="cbMode">
+ <property name="sizeAdjustPolicy">
+ <enum>QComboBox::AdjustToContents</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPlainTextEdit" name="pteTelemetryLvlDescription">
+ <property name="undoRedoEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="gbDataSources">
+ <property name="title">
+ <string>Data &amp;sources</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="3,7">
+ <item>
+ <widget class="QListWidget" name="lvDataSources"/>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_3" stretch="2,8">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="lblDataSourceDescription">
+ <property name="text">
+ <string>&amp;Description</string>
+ </property>
+ <property name="buddy">
+ <cstring>pteDataSourceDescription</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPlainTextEdit" name="pteDataSourceDescription">
+ <property name="undoRedoEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLabel" name="lblCollectedData">
+ <property name="text">
+ <string>&amp;Collected Data</string>
+ </property>
+ <property name="buddy">
+ <cstring>pteCollectedData</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPlainTextEdit" name="pteCollectedData">
+ <property name="undoRedoEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="lblPrivacyPolicy">
+ <property name="text">
+ <string>Legal Notice and Privacy Policy</string>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/usagestatistic.pro b/usagestatistic.pro
new file mode 100644
index 0000000..47216f5
--- /dev/null
+++ b/usagestatistic.pro
@@ -0,0 +1,93 @@
+DEFINES += USAGESTATISTIC_LIBRARY
+
+KUSERFEEDBACK_PATH = "$${PWD}/3rdparty/kuserfeedback"
+
+INCLUDEPATH *= "$${KUSERFEEDBACK_PATH}/include" "$${PWD}"
+LIBS *= -L"$${KUSERFEEDBACK_PATH}/lib" -lKUserFeedbackCore -lKUserFeedbackWidgets -lKUserFeedbackCommon
+
+CONFIG += c++1z
+QMAKE_CXXFLAGS *= -Wall -Wextra -pedantic
+
+DEFINES += $$shell_quote(USP_AUTH_KEY=\"$$(USP_AUTH_KEY)\")
+DEFINES += $$shell_quote(USP_SERVER_URL=\"$$(USP_SERVER_URL)\")
+
+# UsageStatistic files
+SOURCES += \
+ usagestatisticplugin.cpp \
+ datasources/qtclicensesource.cpp \
+ datasources/buildcountsource.cpp \
+ common/scopedsettingsgroupsetter.cpp \
+ datasources/buildsystemsource.cpp \
+ datasources/timeusagesourcebase.cpp \
+ datasources/modeusagetimesource.cpp \
+ datasources/examplesdatasource.cpp \
+ datasources/kitsource.cpp \
+ datasources/qmldesignerusagetimesource.cpp \
+ ui/usagestatisticpage.cpp \
+ ui/usagestatisticwidget.cpp \
+ ui/outputpane.cpp \
+ ui/encouragementwidget.cpp \
+ services/datasubmitter.cpp
+
+HEADERS += \
+ usagestatisticplugin.h \
+ usagestatistic_global.h \
+ usagestatisticconstants.h \
+ datasources/qtclicensesource.h \
+ datasources/buildcountsource.h \
+ common/scopedsettingsgroupsetter.h \
+ datasources/buildsystemsource.h \
+ datasources/timeusagesourcebase.h \
+ datasources/modeusagetimesource.h \
+ datasources/examplesdatasource.h \
+ datasources/kitsource.h \
+ datasources/qmldesignerusagetimesource.h \
+ ui/usagestatisticpage.h \
+ ui/usagestatisticwidget.h \
+ ui/outputpane.h \
+ ui/encouragementwidget.h \
+ services/datasubmitter.h \
+ common/utils.h
+
+# Qt Creator linking
+
+## Either set the IDE_SOURCE_TREE when running qmake,
+## or set the QTC_SOURCE environment variable, to override the default setting
+isEmpty(IDE_SOURCE_TREE): IDE_SOURCE_TREE = $$(QTC_SOURCE)
+
+## Either set the IDE_BUILD_TREE when running qmake,
+## or set the QTC_BUILD environment variable, to override the default setting
+isEmpty(IDE_BUILD_TREE): IDE_BUILD_TREE = $$(QTC_BUILD)
+
+## uncomment to build plugin into user config directory
+## <localappdata>/plugins/<ideversion>
+## where <localappdata> is e.g.
+## "%LOCALAPPDATA%\QtProject\qtcreator" on Windows Vista and later
+## "$XDG_DATA_HOME/data/QtProject/qtcreator" or "~/.local/share/data/QtProject/qtcreator" on Linux
+## "~/Library/Application Support/QtProject/Qt Creator" on macOS
+# USE_USER_DESTDIR = yes
+
+###### If the plugin can be depended upon by other plugins, this code needs to be outsourced to
+###### <dirname>_dependencies.pri, where <dirname> is the name of the directory containing the
+###### plugin's sources.
+
+QTC_PLUGIN_NAME = UsageStatistic
+QTC_LIB_DEPENDS += \
+ # nothing here at this time
+
+QTC_PLUGIN_DEPENDS += \
+ coreplugin \
+ debugger \
+ projectexplorer \
+ qtsupport
+
+QTC_PLUGIN_RECOMMENDS += \
+ # optional plugin dependencies. nothing here at this time
+
+###### End _dependencies.pri contents ######
+
+include($$IDE_SOURCE_TREE/src/qtcreatorplugin.pri)
+
+FORMS += \
+ ui/usagestatisticwidget.ui \
+ ui/encouragementwidget.ui
diff --git a/usagestatistic_global.h b/usagestatistic_global.h
new file mode 100644
index 0000000..094f51e
--- /dev/null
+++ b/usagestatistic_global.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <QtGlobal>
+
+#if defined(USAGESTATISTIC_LIBRARY)
+# define USAGESTATISTICSHARED_EXPORT Q_DECL_EXPORT
+#else
+# define USAGESTATISTICSHARED_EXPORT Q_DECL_IMPORT
+#endif
diff --git a/usagestatisticconstants.h b/usagestatisticconstants.h
new file mode 100644
index 0000000..0abde08
--- /dev/null
+++ b/usagestatisticconstants.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include <QString>
+
+namespace UsageStatistic {
+namespace Constants {
+
+static const QString DATA_SOURCES_SETTINGS_GROUP = QStringLiteral("DataSources");
+
+static constexpr char TELEMETRY_SETTINGS_CATEGORY_ID[] = "Telemetry";
+
+static constexpr char USAGE_STATISTIC_PAGE_ID[] = "UsageStatistic";
+
+static constexpr char PRIVACY_POLICY_URL[] = "https://www.qt.io/terms-conditions/#privacy";
+
+} // namespace UsageStatistic
+} // namespace Constants
diff --git a/usagestatisticplugin.cpp b/usagestatisticplugin.cpp
new file mode 100644
index 0000000..df09d74
--- /dev/null
+++ b/usagestatisticplugin.cpp
@@ -0,0 +1,195 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "usagestatisticplugin.h"
+#include "usagestatisticconstants.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/icontext.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/actionmanager/command.h>
+#include <coreplugin/actionmanager/actioncontainer.h>
+#include <coreplugin/coreconstants.h>
+
+#include <KUserFeedback/Provider>
+#include <KUserFeedback/ApplicationVersionSource>
+#include <KUserFeedback/CompilerInfoSource>
+#include <KUserFeedback/CpuInfoSource>
+#include <KUserFeedback/LocaleInfoSource>
+#include <KUserFeedback/OpenGLInfoSource>
+#include <KUserFeedback/PlatformInfoSource>
+#include <KUserFeedback/QPAInfoSource>
+#include <KUserFeedback/QtVersionSource>
+#include <KUserFeedback/ScreenInfoSource>
+#include <KUserFeedback/StartCountSource>
+#include <KUserFeedback/UsageTimeSource>
+#include <KUserFeedback/StyleInfoSource>
+
+#include "datasources/qtclicensesource.h"
+#include "datasources/buildcountsource.h"
+#include "datasources/buildsystemsource.h"
+#include "datasources/modeusagetimesource.h"
+#include "datasources/examplesdatasource.h"
+#include "datasources/kitsource.h"
+#include "datasources/qmldesignerusagetimesource.h"
+
+#include "services/datasubmitter.h"
+
+#include "ui/usagestatisticpage.h"
+#include "ui/outputpane.h"
+
+#include "common/utils.h"
+
+namespace UsageStatistic {
+namespace Internal {
+
+UsageStatisticPlugin::UsageStatisticPlugin() = default;
+
+UsageStatisticPlugin::~UsageStatisticPlugin() = default;
+
+bool UsageStatisticPlugin::initialize(const QStringList &arguments, QString *errorString)
+{
+ Q_UNUSED(arguments)
+ Q_UNUSED(errorString)
+
+ // We have to create a pane here because of OutputPaneManager internal initialization order
+ createOutputPane();
+
+ return true;
+}
+
+void UsageStatisticPlugin::extensionsInitialized()
+{
+}
+
+static void addDefaultDataSources(KUserFeedback::Provider &provider)
+{
+ provider.addDataSource(new KUserFeedback::ApplicationVersionSource);
+ provider.addDataSource(new KUserFeedback::CompilerInfoSource);
+ provider.addDataSource(new KUserFeedback::CpuInfoSource);
+ provider.addDataSource(new KUserFeedback::LocaleInfoSource);
+ provider.addDataSource(new KUserFeedback::OpenGLInfoSource);
+ provider.addDataSource(new KUserFeedback::PlatformInfoSource);
+ provider.addDataSource(new KUserFeedback::QPAInfoSource);
+ provider.addDataSource(new KUserFeedback::QtVersionSource);
+ provider.addDataSource(new KUserFeedback::ScreenInfoSource);
+ provider.addDataSource(new KUserFeedback::StartCountSource);
+ provider.addDataSource(new KUserFeedback::UsageTimeSource);
+ provider.addDataSource(new KUserFeedback::StyleInfoSource);
+}
+
+static void addQtCreatorDataSources(KUserFeedback::Provider &provider)
+{
+ provider.addDataSource(new QtcLicenseSource);
+ provider.addDataSource(new BuildCountSource);
+ provider.addDataSource(new BuildSystemSource);
+ provider.addDataSource(new ModeUsageTimeSource);
+ provider.addDataSource(new ExamplesDataSource);
+ provider.addDataSource(new KitSource);
+ provider.addDataSource(new QmlDesignerUsageTimeSource);
+}
+
+bool UsageStatisticPlugin::delayedInitialize()
+{
+ // We should create the provider only after everything else
+ // is initialised (e.g., setting organization name)
+ createProvider();
+
+ addDefaultDataSources(*m_provider);
+ addQtCreatorDataSources(*m_provider);
+
+ createUsageStatisticPage();
+
+ restoreSettings();
+
+ configureOutputPane();
+
+ return true;
+}
+
+ExtensionSystem::IPlugin::ShutdownFlag UsageStatisticPlugin::aboutToShutdown()
+{
+ storeSettings();
+
+ return SynchronousShutdown;
+}
+
+void UsageStatisticPlugin::createUsageStatisticPage()
+{
+ m_usageStatisticPage = std::make_unique<UsageStatisticPage>(m_provider);
+
+ connect(m_usageStatisticPage.get(), &UsageStatisticPage::settingsChanged,
+ this, &UsageStatisticPlugin::storeSettings);
+}
+
+void UsageStatisticPlugin::createOutputPane()
+{
+ m_outputPane = std::make_unique<OutputPane>();
+}
+
+void UsageStatisticPlugin::configureOutputPane()
+{
+ Q_ASSERT(m_outputPane);
+
+ m_outputPane->setProvider(m_provider);
+
+ connect(m_provider.get(), &KUserFeedback::Provider::showEncouragementMessage,
+ m_outputPane.get(), &OutputPane::flash);
+}
+
+void UsageStatisticPlugin::storeSettings()
+{
+ if (m_provider) {
+ m_provider->store();
+ }
+}
+
+void UsageStatisticPlugin::restoreSettings()
+{
+ if (m_provider) {
+ m_provider->load();
+ }
+}
+
+static constexpr int encouragementTimeSec() { return 1800; }
+static constexpr int encouragementIntervalDays() { return 1; }
+static constexpr int submissionIntervalDays() { return 10; }
+
+void UsageStatisticPlugin::createProvider()
+{
+ Q_ASSERT(!m_provider);
+ m_provider = std::make_shared<KUserFeedback::Provider>();
+
+ m_provider->setFeedbackServer(QString::fromUtf8(Utils::serverUrl()));
+ m_provider->setDataSubmitter(new DataSubmitter);
+
+ m_provider->setApplicationUsageTimeUntilEncouragement(encouragementTimeSec());
+ m_provider->setEncouragementDelay(encouragementTimeSec());
+ m_provider->setEncouragementInterval(encouragementIntervalDays());
+
+ m_provider->setSubmissionInterval(submissionIntervalDays());
+}
+
+} // namespace Internal
+} // namespace UsageStatistic
diff --git a/usagestatisticplugin.h b/usagestatisticplugin.h
new file mode 100644
index 0000000..139acc3
--- /dev/null
+++ b/usagestatisticplugin.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of UsageStatistic plugin for Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include <memory>
+
+#include "usagestatistic_global.h"
+
+#include <extensionsystem/iplugin.h>
+
+namespace KUserFeedback { class Provider; }
+
+namespace UsageStatistic {
+namespace Internal {
+
+class UsageStatisticPage;
+class OutputPane;
+
+//! Plugin for collecting and sending usage statistics
+class UsageStatisticPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "UsageStatistic.json")
+
+public:
+ UsageStatisticPlugin();
+ ~UsageStatisticPlugin() override;
+
+ bool initialize(const QStringList &arguments, QString *errorString) override;
+ void extensionsInitialized() override;
+ bool delayedInitialize() override;
+ ShutdownFlag aboutToShutdown() override;
+
+private:
+ void createUsageStatisticPage();
+ void createOutputPane();
+ void configureOutputPane();
+ void storeSettings();
+ void restoreSettings();
+ void createProvider();
+
+private:
+ std::shared_ptr<KUserFeedback::Provider> m_provider;
+ std::unique_ptr<UsageStatisticPage> m_usageStatisticPage;
+ std::unique_ptr<OutputPane> m_outputPane;
+};
+
+} // namespace Internal
+} // namespace UsageStatistic