1 /*
2     Copyright (C) 2017 Volker Krause <vkrause@kde.org>
3 
4     Permission is hereby granted, free of charge, to any person obtaining
5     a copy of this software and associated documentation files (the
6     "Software"), to deal in the Software without restriction, including
7     without limitation the rights to use, copy, modify, merge, publish,
8     distribute, sublicense, and/or sell copies of the Software, and to
9     permit persons to whom the Software is furnished to do so, subject to
10     the following conditions:
11 
12     The above copyright notice and this permission notice shall be included
13     in all copies or substantial portions of the Software.
14 
15     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18     IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19     CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20     TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23 
24 #include "feedbackconfiguicontroller.h"
25 #include "abstractdatasource.h"
26 
27 #include <QGuiApplication>
28 #include <QSet>
29 #include <QVector>
30 
31 #include <algorithm>
32 #include <vector>
33 
34 using namespace KUserFeedback;
35 
36 namespace KUserFeedback {
37 class FeedbackConfigUiControllerPrivate {
38 public:
39     FeedbackConfigUiControllerPrivate();
40 
41     Provider *provider;
42     std::vector<Provider::TelemetryMode> telemetryModeMap;
43     QString m_appName;
44 };
45 }
46 
FeedbackConfigUiControllerPrivate()47 FeedbackConfigUiControllerPrivate::FeedbackConfigUiControllerPrivate() :
48     provider(nullptr),
49     m_appName(QGuiApplication::applicationDisplayName())
50 {
51 }
52 
FeedbackConfigUiController(QObject * parent)53 FeedbackConfigUiController::FeedbackConfigUiController(QObject* parent)
54     : QObject(parent)
55     , d(new FeedbackConfigUiControllerPrivate)
56 {
57 }
58 
~FeedbackConfigUiController()59 FeedbackConfigUiController::~FeedbackConfigUiController()
60 {
61 }
62 
feedbackProvider() const63 Provider* FeedbackConfigUiController::feedbackProvider() const
64 {
65     return d->provider;
66 }
67 
setFeedbackProvider(Provider * provider)68 void FeedbackConfigUiController::setFeedbackProvider(Provider* provider)
69 {
70     if (d->provider == provider)
71         return;
72     d->provider = provider;
73 
74     d->telemetryModeMap.clear();
75     d->telemetryModeMap.reserve(5);
76     d->telemetryModeMap.push_back(Provider::NoTelemetry);
77     d->telemetryModeMap.push_back(Provider::BasicSystemInformation);
78     d->telemetryModeMap.push_back(Provider::BasicUsageStatistics);
79     d->telemetryModeMap.push_back(Provider::DetailedSystemInformation);
80     d->telemetryModeMap.push_back(Provider::DetailedUsageStatistics);
81 
82     QSet<Provider::TelemetryMode> supportedModes;
83     supportedModes.reserve(d->telemetryModeMap.size());
84     supportedModes.insert(Provider::NoTelemetry);
85     foreach (const auto &src, provider->dataSources())
86         supportedModes.insert(src->telemetryMode());
87     for (auto it = d->telemetryModeMap.begin(); it != d->telemetryModeMap.end();) {
88         if (!supportedModes.contains(*it))
89             it = d->telemetryModeMap.erase(it);
90         else
91             ++it;
92     }
93 
94     emit providerChanged();
95 }
96 
telemetryModeCount() const97 int FeedbackConfigUiController::telemetryModeCount() const
98 {
99     return d->telemetryModeMap.size();
100 }
101 
surveyModeCount() const102 int FeedbackConfigUiController::surveyModeCount() const
103 {
104     return 3;
105 }
106 
telemetryIndexToMode(int index) const107 Provider::TelemetryMode FeedbackConfigUiController::telemetryIndexToMode(int index) const
108 {
109     if (index < 0 || index >= telemetryModeCount())
110         return Provider::NoTelemetry;
111     return d->telemetryModeMap[index];
112 }
113 
telemetryModeToIndex(Provider::TelemetryMode mode) const114 int FeedbackConfigUiController::telemetryModeToIndex(Provider::TelemetryMode mode) const
115 {
116     const auto it = std::lower_bound(d->telemetryModeMap.begin(), d->telemetryModeMap.end(), mode);
117     if (it == d->telemetryModeMap.end())
118         return 0;
119     return std::distance(d->telemetryModeMap.begin(), it);
120 }
121 
telemetryModeName(int telemetryIndex) const122 QString FeedbackConfigUiController::telemetryModeName(int telemetryIndex) const
123 {
124     return telemetryName(telemetryIndexToMode(telemetryIndex));
125 }
126 
telemetryModeDescription(int telemetryIndex) const127 QString FeedbackConfigUiController::telemetryModeDescription(int telemetryIndex) const
128 {
129     return telemetryDescription(telemetryIndexToMode(telemetryIndex));
130 }
131 
telemetryName(KUserFeedback::Provider::TelemetryMode mode) const132 QString FeedbackConfigUiController::telemetryName(KUserFeedback::Provider::TelemetryMode mode) const
133 {
134     switch (mode) {
135         case Provider::NoTelemetry:
136             return tr("Disabled");
137         case Provider::BasicSystemInformation:
138             return tr("Basic system information");
139         case Provider::BasicUsageStatistics:
140             return tr("Basic system information and usage statistics");
141         case Provider::DetailedSystemInformation:
142             return tr("Detailed system information and basic usage statistics");
143         case Provider::DetailedUsageStatistics:
144             return tr("Detailed system information and usage statistics");
145     }
146 
147     return {};
148 }
149 
telemetryDescription(KUserFeedback::Provider::TelemetryMode mode) const150 QString FeedbackConfigUiController::telemetryDescription(KUserFeedback::Provider::TelemetryMode mode) const
151 {
152     const auto name = applicationName();
153     if (name.isEmpty()) {
154         switch (mode) {
155             case Provider::NoTelemetry:
156                 return tr(
157                     "Don't share anything"
158                 );
159             case Provider::BasicSystemInformation:
160                 return tr(
161                     "Share basic system information such as the version of the application and the operating system"
162                 );
163             case Provider::BasicUsageStatistics:
164                 return tr(
165                     "Share basic system information and basic statistics on how often you use the application"
166                 );
167             case Provider::DetailedSystemInformation:
168                 return tr(
169                     "Share basic statistics on how often you use the application, as well as more detailed information about your system"
170                 );
171             case Provider::DetailedUsageStatistics:
172                 return tr(
173                     "Share detailed system information and statistics on how often individual features of the application are used."
174                 );
175         }
176     } else {
177         switch (mode) {
178             case Provider::NoTelemetry:
179                 return tr(
180                     "Don't share anything"
181                 );
182             case Provider::BasicSystemInformation:
183                 return tr(
184                     "Share basic system information such as the version of %1 and and the operating system"
185                 ).arg(name);
186             case Provider::BasicUsageStatistics:
187                 return tr(
188                     "Share basic system information and basic statistics on how often you use %1"
189                 ).arg(name);
190             case Provider::DetailedSystemInformation:
191                 return tr(
192                     "Share basic statistics on how often you use %1, as well as more detailed information about your system"
193                 ).arg(name);
194             case Provider::DetailedUsageStatistics:
195                 return tr(
196                     "Share detailed system information and statistics on how often individual features of %1 are used."
197                 ).arg(name);
198         }
199     }
200 
201     return QString();
202 }
203 
telemetryModeDetails(int telemetryIndex) const204 QString FeedbackConfigUiController::telemetryModeDetails(int telemetryIndex) const
205 {
206     if (telemetryIndex <= 0 || telemetryIndex >= telemetryModeCount())
207         return QString();
208 
209     auto srcs = d->provider->dataSources();
210     std::stable_sort(srcs.begin(), srcs.end(), [](AbstractDataSource *lhs, AbstractDataSource *rhs) {
211         return lhs->telemetryMode() < rhs->telemetryMode();
212     });
213 
214     auto detailsStr = QStringLiteral("<ul>");
215     foreach (const auto *src, srcs) {
216         if (telemetryIndex >= telemetryModeToIndex(src->telemetryMode()) && !src->description().isEmpty())
217             detailsStr += QStringLiteral("<li>") + src->description() + QStringLiteral("</li>");
218     }
219     return detailsStr + QStringLiteral("</ul>");
220 }
221 
surveyIndexToInterval(int index) const222 int FeedbackConfigUiController::surveyIndexToInterval(int index) const
223 {
224     switch (index) {
225         case 0: return -1;
226         case 1: return 90;
227         case 2: return 0;
228     }
229     return -1;
230 }
231 
surveyIntervalToIndex(int interval) const232 int FeedbackConfigUiController::surveyIntervalToIndex(int interval) const
233 {
234     if (interval < 0)
235         return 0;
236     else if (interval >= 90)
237         return 1;
238     else
239         return 2;
240 }
241 
surveyModeDescription(int surveyIndex) const242 QString FeedbackConfigUiController::surveyModeDescription(int surveyIndex) const
243 {
244     const auto name = applicationName();
245     if (name.isEmpty()) {
246         switch (surveyIndex) {
247             case 0:
248                 return tr(
249                     "Don't participate in usability surveys"
250                 );
251             case 1:
252                 return tr(
253                     "Participate in surveys about the application not more than four times a year"
254                 );
255             case 2:
256                 return tr(
257                     "Participate in surveys about the application whenever one is available (they can be deferred or skipped)"
258                 );
259         }
260     } else {
261         switch (surveyIndex) {
262             case 0:
263                 return tr(
264                     "Don't participate in usability surveys about %1"
265                 ).arg(name);
266             case 1:
267                 return tr(
268                     "Participate in surveys about %1 not more than four times a year"
269                 ).arg(name);
270             case 2:
271                 return tr(
272                     "Participate in surveys about %1 whenever one is available (they can be deferred or skipped)"
273                 ).arg(name);
274         }
275     }
276 
277     return QString();
278 }
279 
applicationName() const280 QString FeedbackConfigUiController::applicationName() const
281 {
282     return d->m_appName;
283 }
284 
setApplicationName(const QString & appName)285 void FeedbackConfigUiController::setApplicationName(const QString& appName)
286 {
287     if (appName == d->m_appName)
288         return;
289 
290     d->m_appName = appName;
291     Q_EMIT applicationNameChanged(appName);
292 }
293