QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
AppSettings.cc
Go to the documentation of this file.
1#include "AppSettings.h"
2#include "QGCFileHelper.h"
3#include "QGCPalette.h"
4#include "AppMessages.h"
5#include "QGCApplication.h"
6#include "QGCMAVLink.h"
7#include "LinkManager.h"
8
9#ifdef Q_OS_ANDROID
10#include "AndroidInterface.h"
11#endif
12
13#include <QtCore/QStandardPaths>
14#include <QtCore/QDir>
15#include <QtCore/QSettings>
16
17// Release languages are 90%+ complete
18QList<QLocale::Language> AppSettings::_rgReleaseLanguages = {
19 QLocale::English,
20 QLocale::Azerbaijani,
21 QLocale::Chinese,
22 QLocale::Japanese,
23 QLocale::Korean,
24 QLocale::Portuguese,
25 QLocale::Russian,
26};
27
28// Partial languages are 40%+ complete
29QList<QLocale::Language> AppSettings::_rgPartialLanguages = {
30 QLocale::Ukrainian,
31};
32
33AppSettings::LanguageInfo_t AppSettings::_rgLanguageInfo[] = {
34 { QLocale::AnyLanguage, "System" }, // Must be first
35 { QLocale::Azerbaijani, "Azerbaijani (Azerbaijani)" },
36 { QLocale::Bulgarian, "български (Bulgarian)" },
37 { QLocale::Chinese, "中文 (Chinese)" },
38 { QLocale::Dutch, "Nederlands (Dutch)" },
39 { QLocale::English, "English" },
40 { QLocale::Finnish, "Suomi (Finnish)" },
41 { QLocale::French, "Français (French)" },
42 { QLocale::German, "Deutsche (German)" },
43 { QLocale::Greek, "Ελληνικά (Greek)" },
44 { QLocale::Hebrew, "עברית (Hebrew)" },
45 { QLocale::Italian, "Italiano (Italian)" },
46 { QLocale::Japanese, "日本語 (Japanese)" },
47 { QLocale::Korean, "한국어 (Korean)" },
48 { QLocale::NorwegianBokmal, "Norsk (Norwegian)" },
49 { QLocale::Polish, "Polskie (Polish)" },
50 { QLocale::Portuguese, "Português (Portuguese)" },
51 { QLocale::Russian, "Pусский (Russian)" },
52 { QLocale::Spanish, "Español (Spanish)" },
53 { QLocale::Swedish, "Svenska (Swedish)" },
54 { QLocale::Turkish, "Türk (Turkish)" }
55};
56
58{
59 QGCPalette::setGlobalTheme(indoorPalette()->rawValue().toBool() ? QGCPalette::Dark : QGCPalette::Light);
60
61 // Instantiate savePath so we can check for override and setup default path if needed
62
63 SettingsFact* savePathFact = qobject_cast<SettingsFact*>(savePath());
64 QString appName = QCoreApplication::applicationName();
65#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
66 // Mobile builds always use the runtime generated location for savePath.
67 bool userHasModifiedSavePath = false;
68#else
69 bool userHasModifiedSavePath = !savePathFact->rawValue().toString().isEmpty() || !_nameToMetaDataMap[savePathName]->rawDefaultValue().toString().isEmpty();
70#endif
71
72 if (!userHasModifiedSavePath) {
73#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
74 #ifdef Q_OS_IOS
75 // This will expose the directories directly to the File iOs app
76 QDir rootDir = QDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
77 savePathFact->setRawValue(rootDir.absolutePath());
78 #else
79 QString rootDirPath;
80 #ifdef Q_OS_ANDROID
81 if (!androidDontSaveToSDCard()->rawValue().toBool()) {
82 rootDirPath = AndroidInterface::getSDCardPath();
83 qDebug() << "AndroidInterface::getSDCardPath();" << rootDirPath;
84 if (rootDirPath.isEmpty() || !QDir(rootDirPath).exists()) {
85 rootDirPath.clear();
86 qDebug() << "Save to SD card specified for application data. But no SD card present or permissions not granted. Using internal storage.";
87 } else if (!QFileInfo(rootDirPath).isWritable()) {
88 rootDirPath.clear();
89 QGC::showAppMessage(AppSettings::tr("Save to SD card specified for application data. But SD card is write protected. Using internal storage."));
90 }
91 }
92 #endif
93 if (rootDirPath.isEmpty()) {
94 rootDirPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
95 }
96 savePathFact->setRawValue(QDir(rootDirPath).filePath(appName));
97 #endif
98 savePathFact->setUserVisible(false);
99#else
100 QDir rootDir;
101 if (QGC::runningUnitTests() || qgcApp()->simpleBootTest()) {
102 rootDir = QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
103 } else {
104 rootDir = QDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
105 }
106 savePathFact->setRawValue(rootDir.filePath(appName));
107#endif
108 }
109
110 connect(savePathFact, &Fact::rawValueChanged, this, &AppSettings::savePathsChanged);
111 connect(savePathFact, &Fact::rawValueChanged, this, &AppSettings::_checkSavePathDirectories);
112
113 _checkSavePathDirectories();
114
115 // When a specific preferred firmware/vehicle is chosen, keep the offline editing settings in sync
116 connect(preferredFirmwareClass(), &Fact::rawValueChanged, this, [this](QVariant value) {
117 if (value.toUInt() != 0) {
118 offlineEditingFirmwareClass()->setRawValue(value);
119 }
120 });
121 connect(preferredVehicleClass(), &Fact::rawValueChanged, this, [this](QVariant value) {
122 if (value.toUInt() != 0) {
123 offlineEditingVehicleClass()->setRawValue(value);
124 }
125 });
126}
127
128DECLARE_SETTINGSFACT(AppSettings, preferredFirmwareClass)
129DECLARE_SETTINGSFACT(AppSettings, preferredVehicleClass)
130DECLARE_SETTINGSFACT(AppSettings, offlineEditingFirmwareClass)
131DECLARE_SETTINGSFACT(AppSettings, offlineEditingVehicleClass)
132DECLARE_SETTINGSFACT(AppSettings, offlineEditingCruiseSpeed)
133DECLARE_SETTINGSFACT(AppSettings, offlineEditingHoverSpeed)
134DECLARE_SETTINGSFACT(AppSettings, offlineEditingAscentSpeed)
135DECLARE_SETTINGSFACT(AppSettings, offlineEditingDescentSpeed)
136DECLARE_SETTINGSFACT(AppSettings, batteryPercentRemainingAnnounce)
137DECLARE_SETTINGSFACT(AppSettings, defaultMissionItemAltitude)
140DECLARE_SETTINGSFACT(AppSettings, virtualJoystick)
141DECLARE_SETTINGSFACT(AppSettings, virtualJoystickAutoCenterThrottle)
142DECLARE_SETTINGSFACT(AppSettings, virtualJoystickLeftHandedMode)
143DECLARE_SETTINGSFACT(AppSettings, uiScalePercent)
145DECLARE_SETTINGSFACT(AppSettings, androidDontSaveToSDCard)
147DECLARE_SETTINGSFACT(AppSettings, enforceChecklist)
148DECLARE_SETTINGSFACT(AppSettings, enableMultiVehiclePanel)
149DECLARE_SETTINGSFACT(AppSettings, tiandituToken)
151DECLARE_SETTINGSFACT(AppSettings, mapboxAccount)
157DECLARE_SETTINGSFACT(AppSettings, gstDebugLevel)
159DECLARE_SETTINGSFACT(AppSettings, clearSettingsNextBoot)
160DECLARE_SETTINGSFACT(AppSettings, disableAllPersistence)
161DECLARE_SETTINGSFACT(AppSettings, firstRunPromptIdsShown)
162DECLARE_SETTINGSFACT(AppSettings, favoriteParameters)
163DECLARE_SETTINGSFACT(AppSettings, showAppLogTimestampAsElapsedTime)
164
166{
167 if (!_indoorPaletteFact) {
168 _indoorPaletteFact = _createSettingsFact(indoorPaletteName);
169 connect(_indoorPaletteFact, &Fact::rawValueChanged, this, &AppSettings::_indoorPaletteChanged);
170 }
171 return _indoorPaletteFact;
172}
173
175{
176 if (!_qLocaleLanguageFact) {
177 _qLocaleLanguageFact = _createSettingsFact(qLocaleLanguageName);
178 connect(_qLocaleLanguageFact, &Fact::rawValueChanged, this, &AppSettings::_qLocaleLanguageChanged);
179
180 FactMetaData* metaData = _qLocaleLanguageFact->metaData();
181 QStringList rgEnumStrings;
182 QVariantList rgEnumValues;
183
184 // System is always an available selection
185 rgEnumStrings.append(_rgLanguageInfo[0].languageName);
186 rgEnumValues.append(_rgLanguageInfo[0].languageId);
187
188 for (const auto& languageInfo: _rgLanguageInfo) {
189 if (_rgReleaseLanguages.contains(languageInfo.languageId)) {
190 rgEnumStrings.append(languageInfo.languageName);
191 rgEnumValues.append(languageInfo.languageId);
192 }
193 }
194 for (const auto& languageInfo: _rgLanguageInfo) {
195 if (_rgPartialLanguages.contains(languageInfo.languageId)) {
196 rgEnumStrings.append(QString(languageInfo.languageName) + AppSettings::tr(" (Partial)"));
197 rgEnumValues.append(languageInfo.languageId);
198 }
199 }
200#ifdef QGC_DAILY_BUILD
201 // Only daily builds include full set of languages for testing purposes
202 for (const auto& languageInfo: _rgLanguageInfo) {
203 if (!_rgReleaseLanguages.contains(languageInfo.languageId) && !_rgPartialLanguages.contains(languageInfo.languageId)) {
204 rgEnumStrings.append(QString(languageInfo.languageName) + AppSettings::tr(" (Test Only)"));
205 rgEnumValues.append(languageInfo.languageId);
206 }
207 }
208#endif
209#ifdef QT_DEBUG
210 // Debug builds include pseudo-localization for UI layout testing
211 rgEnumStrings.append(AppSettings::tr("Pseudo Localization (Test Only)"));
212 rgEnumValues.append(QLocale::Esperanto);
213#endif
214 metaData->setEnumInfo(rgEnumStrings, rgEnumValues);
215
216 if (_qLocaleLanguageFact->enumIndex() == -1) {
217 _qLocaleLanguageFact->setRawValue(QLocale::AnyLanguage);
218 }
219 }
220 return _qLocaleLanguageFact;
221}
222
223void AppSettings::_qLocaleLanguageChanged()
224{
225 qgcApp()->setLanguage();
226}
227
228void AppSettings::_checkSavePathDirectories(void)
229{
230 const QString savePath = this->savePath()->rawValue().toString();
232 // Create all subdirectories
242 }
243}
244
245QString AppSettings::_childSavePath(const char* directory)
246{
247 const QString rootPath = savePath()->rawValue().toString();
248 if (rootPath.isEmpty()) {
249 return QString();
250 }
251
252 const QDir rootDir(rootPath);
253 if (!rootDir.exists()) {
254 return QString();
255 }
256
257 return rootDir.filePath(directory);
258}
259
260void AppSettings::_indoorPaletteChanged(void)
261{
262 QGCPalette::setGlobalTheme(indoorPalette()->rawValue().toBool() ? QGCPalette::Dark : QGCPalette::Light);
263}
264
266{
267 return _childSavePath(missionDirectory);
268}
269
271{
272 return _childSavePath(parameterDirectory);
273}
274
276{
277 return _childSavePath(telemetryDirectory);
278}
279
281{
282 return _childSavePath(logDirectory);
283}
284
286{
287 return _childSavePath(videoDirectory);
288}
289
291{
292 return _childSavePath(photoDirectory);
293}
294
296{
297 return _childSavePath(crashDirectory);
298}
299
301{
302 return _childSavePath(mavlinkActionsDirectory);
303}
304
306{
307 return _childSavePath(settingsDirectory);
308}
309
310QList<int> AppSettings::firstRunPromptsIdsVariantToList(const QVariant& firstRunPromptIds)
311{
312 QList<int> rgIds;
313
314 QStringList strIdList = firstRunPromptIds.toString().split(",", Qt::SkipEmptyParts);
315
316 for (const QString& strId: strIdList) {
317 rgIds.append(strId.toInt());
318 }
319 return rgIds;
320}
321
322QVariant AppSettings::firstRunPromptsIdsListToVariant(const QList<int>& rgIds)
323{
324 QStringList strList;
325 for (int id: rgIds) {
326 strList.append(QString::number(id));
327 }
328 return QVariant(strList.join(","));
329}
330
332{
333 QList<int> rgIds = firstRunPromptsIdsVariantToList(firstRunPromptIdsShown()->rawValue());
334 if (!rgIds.contains(id)) {
335 rgIds.append(id);
336 firstRunPromptIdsShown()->setRawValue(firstRunPromptsIdsListToVariant(rgIds));
337 }
338}
339
345QLocale::Language AppSettings::_qLocaleLanguageEarlyAccess(void)
346{
347 QSettings settings;
348
349 // Note that the AppSettings group has no group name
350 QLocale::Language localeLanguage = static_cast<QLocale::Language>(settings.value(qLocaleLanguageName).toInt());
351 for (auto& languageInfo: _rgLanguageInfo) {
352 if (languageInfo.languageId == localeLanguage) {
353 return localeLanguage;
354 }
355 }
356
357#ifdef QT_DEBUG
358 if (localeLanguage == QLocale::Esperanto) {
359 return localeLanguage;
360 }
361#endif
362
363 localeLanguage = QLocale::AnyLanguage;
364 settings.setValue(qLocaleLanguageName, localeLanguage);
365
366 return localeLanguage;
367}
#define qgcApp()
#define DECLARE_SETTINGSFACT_NO_FUNC(CLASS, NAME)
#define DECLARE_SETTINGSFACT(CLASS, NAME)
#define DECLARE_SETTINGGROUP(NAME, GROUP)
Application Settings.
Definition AppSettings.h:10
static QVariant firstRunPromptsIdsListToVariant(const QList< int > &rgIds)
QString videoSavePath()
QString logSavePath()
QString telemetrySavePath()
QString crashSavePath()
static constexpr const char * settingsDirectory
QString parameterSavePath()
static constexpr const char * photoDirectory
static constexpr const char * telemetryDirectory
Q_INVOKABLE void firstRunPromptIdsMarkIdAsShown(int id)
static constexpr const char * logDirectory
void savePathsChanged()
QString settingsSavePath()
static constexpr const char * videoDirectory
static QList< int > firstRunPromptsIdsVariantToList(const QVariant &firstRunPromptIds)
static constexpr const char * missionDirectory
static constexpr const char * mavlinkActionsDirectory
QString photoSavePath()
QString missionSavePath()
static constexpr const char * crashDirectory
QString mavlinkActionsSavePath()
static constexpr const char * parameterDirectory
Holds the meta data associated with a Fact.
void setEnumInfo(const QStringList &strings, const QVariantList &values)
void rawValueChanged(const QVariant &value)
QGCPalette is used in QML ui to expose color properties for the QGC palette.
Definition QGCPalette.h:83
static void setGlobalTheme(Theme newTheme)
A SettingsFact is Fact which holds a QSettings value.
bool ensureDirectoryExists(const QString &path)
QString joinPath(const QString &dir, const QString &name)
bool runningUnitTests()
void showAppMessage(const QString &message, const QString &title)
Modal application message. Queued if the UI isn't ready yet.
Definition AppMessages.cc:9