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 "QGCApplication.h"
5#include "QGCMAVLink.h"
6#include "LinkManager.h"
7
8#ifdef Q_OS_ANDROID
9#include "AndroidInterface.h"
10#endif
11
12#include <QtCore/QStandardPaths>
13#include <QtCore/QDir>
14#include <QtCore/QSettings>
15
16// Release languages are 90%+ complete
17QList<QLocale::Language> AppSettings::_rgReleaseLanguages = {
18 QLocale::English,
19 QLocale::Azerbaijani,
20 QLocale::Chinese,
21 QLocale::Japanese,
22 QLocale::Korean,
23 QLocale::Portuguese,
24 QLocale::Russian,
25};
26
27// Partial languages are 40%+ complete
28QList<QLocale::Language> AppSettings::_rgPartialLanguages = {
29 QLocale::Ukrainian,
30};
31
32AppSettings::LanguageInfo_t AppSettings::_rgLanguageInfo[] = {
33 { QLocale::AnyLanguage, "System" }, // Must be first
34 { QLocale::Azerbaijani, "Azerbaijani (Azerbaijani)" },
35 { QLocale::Bulgarian, "български (Bulgarian)" },
36 { QLocale::Chinese, "中文 (Chinese)" },
37 { QLocale::Dutch, "Nederlands (Dutch)" },
38 { QLocale::English, "English" },
39 { QLocale::Finnish, "Suomi (Finnish)" },
40 { QLocale::French, "Français (French)" },
41 { QLocale::German, "Deutsche (German)" },
42 { QLocale::Greek, "Ελληνικά (Greek)" },
43 { QLocale::Hebrew, "עברית (Hebrew)" },
44 { QLocale::Italian, "Italiano (Italian)" },
45 { QLocale::Japanese, "日本語 (Japanese)" },
46 { QLocale::Korean, "한국어 (Korean)" },
47 { QLocale::NorwegianBokmal, "Norsk (Norwegian)" },
48 { QLocale::Polish, "Polskie (Polish)" },
49 { QLocale::Portuguese, "Português (Portuguese)" },
50 { QLocale::Russian, "Pусский (Russian)" },
51 { QLocale::Spanish, "Español (Spanish)" },
52 { QLocale::Swedish, "Svenska (Swedish)" },
53 { QLocale::Turkish, "Türk (Turkish)" }
54};
55
57{
58 QGCPalette::setGlobalTheme(indoorPalette()->rawValue().toBool() ? QGCPalette::Dark : QGCPalette::Light);
59
60 // Instantiate savePath so we can check for override and setup default path if needed
61
62 SettingsFact* savePathFact = qobject_cast<SettingsFact*>(savePath());
63 QString appName = QCoreApplication::applicationName();
64#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
65 // Mobile builds always use the runtime generated location for savePath.
66 bool userHasModifiedSavePath = false;
67#else
68 bool userHasModifiedSavePath = !savePathFact->rawValue().toString().isEmpty() || !_nameToMetaDataMap[savePathName]->rawDefaultValue().toString().isEmpty();
69#endif
70
71 if (!userHasModifiedSavePath) {
72#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
73 #ifdef Q_OS_IOS
74 // This will expose the directories directly to the File iOs app
75 QDir rootDir = QDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
76 savePathFact->setRawValue(rootDir.absolutePath());
77 #else
78 QString rootDirPath;
79 #ifdef Q_OS_ANDROID
80 if (!androidDontSaveToSDCard()->rawValue().toBool()) {
81 rootDirPath = AndroidInterface::getSDCardPath();
82 qDebug() << "AndroidInterface::getSDCardPath();" << rootDirPath;
83 if (rootDirPath.isEmpty() || !QDir(rootDirPath).exists()) {
84 rootDirPath.clear();
85 qDebug() << "Save to SD card specified for application data. But no SD card present or permissions not granted. Using internal storage.";
86 } else if (!QFileInfo(rootDirPath).isWritable()) {
87 rootDirPath.clear();
88 qgcApp()->showAppMessage(AppSettings::tr("Save to SD card specified for application data. But SD card is write protected. Using internal storage."));
89 }
90 }
91 #endif
92 if (rootDirPath.isEmpty()) {
93 rootDirPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
94 }
95 savePathFact->setRawValue(QDir(rootDirPath).filePath(appName));
96 #endif
97 savePathFact->setVisible(false);
98#else
99 QDir rootDir = QDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
100 savePathFact->setRawValue(rootDir.filePath(appName));
101#endif
102 }
103
104 connect(savePathFact, &Fact::rawValueChanged, this, &AppSettings::savePathsChanged);
105 connect(savePathFact, &Fact::rawValueChanged, this, &AppSettings::_checkSavePathDirectories);
106
107 _checkSavePathDirectories();
108}
109
110DECLARE_SETTINGSFACT(AppSettings, offlineEditingFirmwareClass)
111DECLARE_SETTINGSFACT(AppSettings, offlineEditingVehicleClass)
112DECLARE_SETTINGSFACT(AppSettings, offlineEditingCruiseSpeed)
113DECLARE_SETTINGSFACT(AppSettings, offlineEditingHoverSpeed)
114DECLARE_SETTINGSFACT(AppSettings, offlineEditingAscentSpeed)
115DECLARE_SETTINGSFACT(AppSettings, offlineEditingDescentSpeed)
116DECLARE_SETTINGSFACT(AppSettings, batteryPercentRemainingAnnounce)
117DECLARE_SETTINGSFACT(AppSettings, defaultMissionItemAltitude)
120DECLARE_SETTINGSFACT(AppSettings, virtualJoystickAutoCenterThrottle)
121DECLARE_SETTINGSFACT(AppSettings, virtualJoystickLeftHandedMode)
124DECLARE_SETTINGSFACT(AppSettings, androidDontSaveToSDCard)
127DECLARE_SETTINGSFACT(AppSettings, enableMultiVehiclePanel)
138DECLARE_SETTINGSFACT(AppSettings, disableAllPersistence)
139DECLARE_SETTINGSFACT(AppSettings, firstRunPromptIdsShown)
140
142{
143 if (!_indoorPaletteFact) {
144 _indoorPaletteFact = _createSettingsFact(indoorPaletteName);
145 connect(_indoorPaletteFact, &Fact::rawValueChanged, this, &AppSettings::_indoorPaletteChanged);
146 }
147 return _indoorPaletteFact;
148}
149
151{
152 if (!_qLocaleLanguageFact) {
153 _qLocaleLanguageFact = _createSettingsFact(qLocaleLanguageName);
154 connect(_qLocaleLanguageFact, &Fact::rawValueChanged, this, &AppSettings::_qLocaleLanguageChanged);
155
156 FactMetaData* metaData = _qLocaleLanguageFact->metaData();
157 QStringList rgEnumStrings;
158 QVariantList rgEnumValues;
159
160 // System is always an available selection
161 rgEnumStrings.append(_rgLanguageInfo[0].languageName);
162 rgEnumValues.append(_rgLanguageInfo[0].languageId);
163
164 for (const auto& languageInfo: _rgLanguageInfo) {
165 if (_rgReleaseLanguages.contains(languageInfo.languageId)) {
166 rgEnumStrings.append(languageInfo.languageName);
167 rgEnumValues.append(languageInfo.languageId);
168 }
169 }
170 for (const auto& languageInfo: _rgLanguageInfo) {
171 if (_rgPartialLanguages.contains(languageInfo.languageId)) {
172 rgEnumStrings.append(QString(languageInfo.languageName) + AppSettings::tr(" (Partial)"));
173 rgEnumValues.append(languageInfo.languageId);
174 }
175 }
176#ifdef QGC_DAILY_BUILD
177 // Only daily builds include full set of languages for testing purposes
178 for (const auto& languageInfo: _rgLanguageInfo) {
179 if (!_rgReleaseLanguages.contains(languageInfo.languageId) && !_rgPartialLanguages.contains(languageInfo.languageId)) {
180 rgEnumStrings.append(QString(languageInfo.languageName) + AppSettings::tr(" (Test Only)"));
181 rgEnumValues.append(languageInfo.languageId);
182 }
183 }
184#endif
185 metaData->setEnumInfo(rgEnumStrings, rgEnumValues);
186
187 if (_qLocaleLanguageFact->enumIndex() == -1) {
188 _qLocaleLanguageFact->setRawValue(QLocale::AnyLanguage);
189 }
190 }
191 return _qLocaleLanguageFact;
192}
193
194void AppSettings::_qLocaleLanguageChanged()
195{
196 qgcApp()->setLanguage();
197}
198
199void AppSettings::_checkSavePathDirectories(void)
200{
201 const QString savePath = this->savePath()->rawValue().toString();
203 // Create all subdirectories
213 }
214}
215
216QString AppSettings::_childSavePath(const char* directory)
217{
218 const QString rootPath = savePath()->rawValue().toString();
219 if (rootPath.isEmpty()) {
220 return QString();
221 }
222
223 const QDir rootDir(rootPath);
224 if (!rootDir.exists()) {
225 return QString();
226 }
227
228 return rootDir.filePath(directory);
229}
230
231void AppSettings::_indoorPaletteChanged(void)
232{
233 QGCPalette::setGlobalTheme(indoorPalette()->rawValue().toBool() ? QGCPalette::Dark : QGCPalette::Light);
234}
235
236QString AppSettings::missionSavePath(void)
237{
238 return _childSavePath(missionDirectory);
239}
240
242{
243 return _childSavePath(parameterDirectory);
244}
245
247{
248 return _childSavePath(telemetryDirectory);
249}
250
252{
253 return _childSavePath(logDirectory);
254}
255
257{
258 return _childSavePath(videoDirectory);
259}
260
262{
263 return _childSavePath(photoDirectory);
264}
265
267{
268 return _childSavePath(crashDirectory);
269}
270
272{
273 return _childSavePath(mavlinkActionsDirectory);
274}
275
277{
278 return _childSavePath(settingsDirectory);
279}
280
281QList<int> AppSettings::firstRunPromptsIdsVariantToList(const QVariant& firstRunPromptIds)
282{
283 QList<int> rgIds;
284
285 QStringList strIdList = firstRunPromptIds.toString().split(",", Qt::SkipEmptyParts);
286
287 for (const QString& strId: strIdList) {
288 rgIds.append(strId.toInt());
289 }
290 return rgIds;
291}
292
293QVariant AppSettings::firstRunPromptsIdsListToVariant(const QList<int>& rgIds)
294{
295 QStringList strList;
296 for (int id: rgIds) {
297 strList.append(QString::number(id));
298 }
299 return QVariant(strList.join(","));
300}
301
303{
304 QList<int> rgIds = firstRunPromptsIdsVariantToList(firstRunPromptIdsShown()->rawValue());
305 if (!rgIds.contains(id)) {
306 rgIds.append(id);
308 }
309}
310
316QLocale::Language AppSettings::_qLocaleLanguageEarlyAccess(void)
317{
318 QSettings settings;
319
320 // Note that the AppSettings group has no group name
321 QLocale::Language localeLanguage = static_cast<QLocale::Language>(settings.value(qLocaleLanguageName).toInt());
322 for (auto& languageInfo: _rgLanguageInfo) {
323 if (languageInfo.languageId == localeLanguage) {
324 return localeLanguage;
325 }
326 }
327
328 localeLanguage = QLocale::AnyLanguage;
329 settings.setValue(qLocaleLanguageName, localeLanguage);
330
331 return localeLanguage;
332}
#define qgcApp()
#define DECLARE_SETTINGSFACT_NO_FUNC(CLASS, NAME)
#define DECLARE_SETTINGSFACT(CLASS, NAME)
#define DECLARE_SETTINGGROUP(NAME, GROUP)
Application Settings.
Definition AppSettings.h:9
static QVariant firstRunPromptsIdsListToVariant(const QList< int > &rgIds)
QString videoSavePath()
QString logSavePath()
QString telemetrySavePath()
Fact *firstRunPromptIdsShown READ firstRunPromptIdsShown CONSTANT Fact * firstRunPromptIdsShown()
QString crashSavePath()
static constexpr const char * settingsDirectory
QString parameterSavePath()
static constexpr const char * photoDirectory
Fact *indoorPalette READ indoorPalette CONSTANT Fact * indoorPalette()
static constexpr const char * telemetryDirectory
void firstRunPromptIdsMarkIdAsShown(int id)
static constexpr const char * logDirectory
void savePathsChanged()
QString settingsSavePath()
static const char * qLocaleLanguageName
Definition AppSettings.h:47
static constexpr const char * videoDirectory
Fact *savePath READ savePath CONSTANT Fact * savePath()
static QList< int > firstRunPromptsIdsVariantToList(const QVariant &firstRunPromptIds)
static constexpr const char * missionDirectory
static constexpr const char * mavlinkActionsDirectory
QString photoSavePath()
static constexpr const char * crashDirectory
QString mavlinkActionsSavePath()
static constexpr const char * parameterDirectory
Definition AppSettings.h:99
void setEnumInfo(const QStringList &strings, const QVariantList &values)
void rawValueChanged(const QVariant &value)
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)