QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
SettingsManager.cc
Go to the documentation of this file.
1#include "SettingsManager.h"
2#include "AppMessages.h"
6#include "AppSettings.h"
11#include "FlightMapSettings.h"
12#include "FlightModeSettings.h"
13#include "FlyViewSettings.h"
14#include "GeoViewSettings.h"
16#include "MapsSettings.h"
17#include "OfflineMapsSettings.h"
18#include "PlanViewSettings.h"
19#include "RemoteIDSettings.h"
20#include "RTKSettings.h"
21#include "UnitsSettings.h"
22#include "NTRIPSettings.h"
23#include "VideoSettings.h"
24#include "MavlinkSettings.h"
26#include "LogManagerSettings.h"
27#include "LogViewerSettings.h"
28#include "Viewer3DSettings.h"
29#include "JsonParsing.h"
30#include "QGCCorePlugin.h"
31
32#include <QtCore/QApplicationStatic>
33
34QGC_LOGGING_CATEGORY(SettingsManagerLog, "Utilities.SettingsManager")
35
36Q_APPLICATION_STATIC(SettingsManager, _settingsManagerInstance);
37
39 : QObject(parent)
40{
41 qCDebug(SettingsManagerLog) << this;
42}
43
45{
46 qCDebug(SettingsManagerLog) << this;
47}
48
50{
51 return _settingsManagerInstance();
52}
53
55{
56 _unitsSettings = new UnitsSettings(this); // Must be first since AppSettings references it
57
58 _appSettings = new AppSettings(this);
59 _loadSettingsFiles();
60
61 _autoConnectSettings = new AutoConnectSettings(this);
62 _batteryIndicatorSettings = new BatteryIndicatorSettings(this);
63 _mavlinkActionsSettings = new MavlinkActionsSettings(this);
64 _firmwareUpgradeSettings = new FirmwareUpgradeSettings(this);
65 _flightMapSettings = new FlightMapSettings(this);
66 _flightModeSettings = new FlightModeSettings(this);
67 _flyViewSettings = new FlyViewSettings(this);
68 _geoViewSettings = new GeoViewSettings(this);
69 _gimbalControllerSettings = new GimbalControllerSettings(this);
70 _mapsSettings = new MapsSettings(this);
71 _offlineMapsSettings = new OfflineMapsSettings(this);
72 _planViewSettings = new PlanViewSettings(this);
73 _remoteIDSettings = new RemoteIDSettings(this);
74 _rtkSettings = new RTKSettings(this);
75 _ntripSettings = new NTRIPSettings(this);
76 _videoSettings = new VideoSettings(this);
77 _mavlinkSettings = new MavlinkSettings(this);
78 _joystickManagerSettings = new JoystickManagerSettings(this);
79 _logManagerSettings = new LogManagerSettings(this);
80 _logViewerSettings = new LogViewerSettings(this);
81 _viewer3DSettings = new Viewer3DSettings(this);
82 _adsbVehicleManagerSettings = new ADSBVehicleManagerSettings(this);
83 _apmMavlinkStreamRateSettings = new APMMavlinkStreamRateSettings(this);
84}
85
86ADSBVehicleManagerSettings *SettingsManager::adsbVehicleManagerSettings() const { return _adsbVehicleManagerSettings; }
87APMMavlinkStreamRateSettings *SettingsManager::apmMavlinkStreamRateSettings() const { return _apmMavlinkStreamRateSettings; }
88AppSettings *SettingsManager::appSettings() const { return _appSettings; }
89AutoConnectSettings *SettingsManager::autoConnectSettings() const { return _autoConnectSettings; }
90BatteryIndicatorSettings *SettingsManager::batteryIndicatorSettings() const { return _batteryIndicatorSettings; }
91MavlinkActionsSettings *SettingsManager::mavlinkActionsSettings() const { return _mavlinkActionsSettings; }
92FirmwareUpgradeSettings *SettingsManager::firmwareUpgradeSettings() const { return _firmwareUpgradeSettings; }
93FlightMapSettings *SettingsManager::flightMapSettings() const { return _flightMapSettings; }
94FlightModeSettings *SettingsManager::flightModeSettings() const { return _flightModeSettings; }
95FlyViewSettings *SettingsManager::flyViewSettings() const { return _flyViewSettings; }
96GeoViewSettings *SettingsManager::geoViewSettings() const { return _geoViewSettings; }
97GimbalControllerSettings *SettingsManager::gimbalControllerSettings() const { return _gimbalControllerSettings; }
98MapsSettings *SettingsManager::mapsSettings() const { return _mapsSettings; }
99OfflineMapsSettings *SettingsManager::offlineMapsSettings() const { return _offlineMapsSettings; }
100PlanViewSettings *SettingsManager::planViewSettings() const { return _planViewSettings; }
101RemoteIDSettings *SettingsManager::remoteIDSettings() const { return _remoteIDSettings; }
102RTKSettings *SettingsManager::rtkSettings() const { return _rtkSettings; }
103UnitsSettings *SettingsManager::unitsSettings() const { return _unitsSettings; }
104NTRIPSettings *SettingsManager::ntripSettings() const { return _ntripSettings; }
105VideoSettings *SettingsManager::videoSettings() const { return _videoSettings; }
106MavlinkSettings *SettingsManager::mavlinkSettings() const { return _mavlinkSettings; }
107JoystickManagerSettings *SettingsManager::joystickManagerSettings() const { return _joystickManagerSettings; }
108LogManagerSettings *SettingsManager::logManagerSettings() const { return _logManagerSettings; }
109LogViewerSettings *SettingsManager::logViewerSettings() const { return _logViewerSettings; }
110Viewer3DSettings *SettingsManager::viewer3DSettings() const { return _viewer3DSettings; }
111
112void SettingsManager::_loadSettingsFiles()
113{
114 // Settings files can be found in the settingsSavePath() directory
115 // Settings files are json files which end in the settingsFileExtension extension
116 // The format for a settings file is:
117 // {
118 // "version": 1,
119 // "fileType": "Settings",
120 // "groups": {
121 // "groupName": {
122 // "settingName": {
123 // "forceRawValue": <value>, // Forces the rawValue for this setting to the specific value
124 // any FactMetaData json keys except for name and type,
125 // ...
126 // },
127 // "groupName": {
128 // ...
129 // }
130 // }
131 // }
132
133 QDir settingsDir(_appSettings->settingsSavePath());
134 if (!settingsDir.exists()) {
135 qCWarning(SettingsManagerLog) << "Settings directory does not exist:" << settingsDir.absolutePath();
136 return;
137 }
138
139 QStringList settingsFiles = settingsDir.entryList(QStringList() << QString("*.%1").arg(_appSettings->settingsFileExtension), QDir::Files);
140 for (const QString &fileName : settingsFiles) {
141 QFileInfo fileInfo(settingsDir, fileName);
142 if (!fileInfo.isFile()) continue;
143
144 // Load the settings file
145 qCDebug(SettingsManagerLog) << "Loading settings file:" << fileInfo.absoluteFilePath();
146
147 QJsonDocument jsonDoc;
148 QString errorString;
149 if (!JsonParsing::isJsonFile(fileInfo.absoluteFilePath(), jsonDoc, errorString)) {
150 qCWarning(SettingsManagerLog) << "Failed to load settings file:" << fileInfo.absoluteFilePath() << errorString;
151 continue;
152 }
153
154 QJsonObject jsonObject = jsonDoc.object();
155
156 // Validate the settings file
157 int version;
158 if (!JsonParsing::validateInternalQGCJsonFile(jsonObject, "Settings", 1, 1, version, errorString)) {
159 qCWarning(SettingsManagerLog) << "Settings file failed validation:" << fileInfo.absoluteFilePath() << errorString;
160 continue;
161 }
162
163 // Validate the remainder of the file
164
165 // groups key is an object
166 static const QList<JsonParsing::KeyValidateInfo> keyInfoList = {
167 { kJsonGroupsObjectKey, QJsonValue::Object, true },
168 };
169 if (!JsonParsing::validateKeys(jsonObject, keyInfoList, errorString)) {
170 qCWarning(SettingsManagerLog) << "Settings file incorrect format:" << fileInfo.absoluteFilePath() << errorString;
171 continue;
172 }
173
174 auto groupsObject = jsonObject[kJsonGroupsObjectKey].toObject();
175 for (const QString &groupName : groupsObject.keys()) {
176 qCDebug(SettingsManagerLog) << " Loading settings group:" << groupName;
177
178 const QJsonValue &groupValue = groupsObject[groupName];
179 if (!groupValue.isObject()) {
180 qCWarning(SettingsManagerLog) << "Settings file incorrect format, group is not an object:" << fileInfo.absoluteFilePath()
181 << groupName;
182 continue;
183 }
184
185 auto groupObject = groupValue.toObject();
186 for (const QString &settingName : groupObject.keys()) {
187 qCDebug(SettingsManagerLog) << " Loading settings:" << groupName << settingName;
188
189 if (!groupObject[settingName].isObject()) {
190 qCWarning(SettingsManagerLog) << "Settings file incorrect format, setting is not an object:" << fileInfo.absoluteFilePath()
191 << groupName << settingName;
192 continue;
193 }
194
195 // Store the setting overrides. Note that last one wins if there are multiple settings files with the same setting.
196 QJsonObject metaDataObject = groupObject[settingName].toObject();
197 _settingsFileOverrides[groupName][settingName] = metaDataObject;
198 }
199 }
200 }
201}
202
203void SettingsManager::adjustSettingMetaData(const QString &settingsGroup, FactMetaData &metaData, bool &userVisible)
204{
205 userVisible = true; // By default all settings are visible
206
207 SettingsManager *settingsManager = SettingsManager::instance();
208 if (!settingsManager) {
209 qCWarning(SettingsManagerLog) << "SettingsManager instance not available";
210 return;
211 }
212
213 if (!QGC::runningUnitTests()) {
214 // Apply settings file overrides
215 const auto &groupOverrides = settingsManager->_settingsFileOverrides;
216 if (groupOverrides.contains(settingsGroup) && groupOverrides[settingsGroup].contains(metaData.name())) {
217 QJsonObject settingOverrideJsonObject = groupOverrides[settingsGroup][metaData.name()];
218
219 // We need to stuff in name and type so settingOverrideJsonObject can parse properly
220 settingOverrideJsonObject["name"] = metaData.name();
221 settingOverrideJsonObject["type"] = FactMetaData::typeToString(metaData.type());
222
223 qCDebug(SettingsManagerLog) << "Applying settings file override for" << settingsGroup << metaData.name();
224
225 // Strip SettingsManager-level keys which are not valid Fact metadata keys. Otherwise strict key
226 // validation in createFromJsonObject fails and returns default metadata, corrupting the overrides below.
227 QJsonObject factMetaDataJsonObject = settingOverrideJsonObject;
228 factMetaDataJsonObject.remove(kJsonVisibleKey);
229 factMetaDataJsonObject.remove(kJsonForceRawValueKey);
230
231 QScopedPointer<FactMetaData> overrideMetaData(FactMetaData::createFromJsonObject(factMetaDataJsonObject, {}, nullptr));
232
233 if (settingOverrideJsonObject.contains(kJsonForceRawValueKey) && settingOverrideJsonObject.contains(kJsonVisibleKey)) {
234 // A visible setting reads its value from QSettings which defeats forceRawValue
235 qCWarning(SettingsManagerLog) << "Ignoring settings file override which combines 'forceRawValue' and 'visible' keys:" << settingsGroup << metaData.name();
236 } else if (overrideMetaData->name() != metaData.name()) {
237 // createFromJsonObject failed validation (it already logged why) and returned default metadata.
238 // Don't apply any part of a bad override.
239 qCWarning(SettingsManagerLog) << "Ignoring settings file override which failed validation:" << settingsGroup << metaData.name();
240 } else {
241 // Apply Fact metadata overrides
242 for (const QString &metaDataName : factMetaDataJsonObject.keys()) {
243 if (metaDataName == FactMetaData::_defaultValueJsonKey) {
244 qCDebug(SettingsManagerLog) << " Setting default to" << overrideMetaData->rawDefaultValue();
245 metaData.setRawDefaultValue(overrideMetaData->rawDefaultValue());
246 } else if (metaDataName == FactMetaData::_minJsonKey) {
247 qCDebug(SettingsManagerLog) << " Setting min to" << overrideMetaData->rawMin();
248 metaData.setRawMin(overrideMetaData->rawMin());
249 } else if (metaDataName == FactMetaData::_maxJsonKey) {
250 qCDebug(SettingsManagerLog) << " Setting max to" << overrideMetaData->rawMax();
251 metaData.setRawMax(overrideMetaData->rawMax());
252 } else if (metaDataName == FactMetaData::_decimalPlacesJsonKey) {
253 qCDebug(SettingsManagerLog) << " Setting decimalPlaces to" << overrideMetaData->decimalPlaces();
254 metaData.setDecimalPlaces(overrideMetaData->decimalPlaces());
255 } else if (metaDataName == FactMetaData::_enumValuesJsonKey) {
256 qCDebug(SettingsManagerLog) << " Setting enumInfo to" << overrideMetaData->enumValues() << overrideMetaData->enumStrings();
257 metaData.setEnumInfo(overrideMetaData->enumStrings(), overrideMetaData->enumValues());
258 } else if (metaDataName == FactMetaData::_enumBitmaskArrayJsonKey) {
259 qCDebug(SettingsManagerLog) << " Setting bitmaskInfo to" << overrideMetaData->bitmaskValues() << overrideMetaData->bitmaskStrings();
260 metaData.setBitmaskInfo(overrideMetaData->bitmaskStrings(), overrideMetaData->bitmaskValues());
261 } else if (metaDataName == FactMetaData::_longDescriptionJsonKey) {
262 qCDebug(SettingsManagerLog) << " Setting longDesc to" << overrideMetaData->longDescription();
263 metaData.setLongDescription(overrideMetaData->longDescription());
264 } else if (metaDataName == FactMetaData::_shortDescriptionJsonKey) {
265 qCDebug(SettingsManagerLog) << " Setting shortDesc to" << overrideMetaData->shortDescription();
266 metaData.setShortDescription(overrideMetaData->shortDescription());
267 }
268 }
269
270 // Apply SettingsManager-level overrides last so forceRawValue wins over a default override
271 if (settingOverrideJsonObject.contains(kJsonForceRawValueKey)) {
272 qCDebug(SettingsManagerLog) << " Setting forceRawValue to" << settingOverrideJsonObject[kJsonForceRawValueKey];
273 metaData.setRawDefaultValue(settingOverrideJsonObject[kJsonForceRawValueKey].toVariant());
274 userVisible = false;
275 }
276 if (settingOverrideJsonObject.contains(kJsonVisibleKey)) {
277 qCDebug(SettingsManagerLog) << " Setting visibility to" << settingOverrideJsonObject[kJsonVisibleKey].toBool();
278 userVisible = settingOverrideJsonObject[kJsonVisibleKey].toBool();
279 }
280 }
281 }
282 }
283
284 // Give QGCCorePlugin a whack at it too
285 QGCCorePlugin::instance()->adjustSettingMetaData(settingsGroup, metaData, userVisible);
286}
QString errorString
#define QGC_LOGGING_CATEGORY(name, categoryStr)
Q_APPLICATION_STATIC(SettingsManager, _settingsManagerInstance)
Application Settings.
Definition AppSettings.h:10
QString settingsSavePath()
static constexpr const char * settingsFileExtension
Auto connect settings.
Holds the meta data associated with a Fact.
static FactMetaData * createFromJsonObject(const QJsonObject &json, const QMap< QString, QString > &defineMap, QObject *metaDataParent)
void setDecimalPlaces(int decimalPlaces)
void setShortDescription(const QString &shortDescription)
static QString typeToString(ValueType_t type)
void setLongDescription(const QString &longDescription)
void setRawMin(const QVariant &rawMin)
void setRawDefaultValue(const QVariant &rawDefaultValue)
void setEnumInfo(const QStringList &strings, const QVariantList &values)
void setBitmaskInfo(const QStringList &strings, const QVariantList &values)
void setRawMax(const QVariant &rawMax)
QString name() const
ValueType_t type() const
Settings for the experimental GeoView 2D/3D map engine (preview feature)
Application Settings.
virtual void adjustSettingMetaData(const QString &settingsGroup, FactMetaData &metaData, bool &userVisible)
static QGCCorePlugin * instance()
Provides access to all app settings.
AutoConnectSettings * autoConnectSettings() const
Viewer3DSettings * viewer3DSettings() const
JoystickManagerSettings * joystickManagerSettings() const
MapsSettings * mapsSettings() const
FlightMapSettings * flightMapSettings() const
ADSBVehicleManagerSettings * adsbVehicleManagerSettings() const
PlanViewSettings * planViewSettings() const
UnitsSettings * unitsSettings() const
RTKSettings * rtkSettings() const
LogViewerSettings * logViewerSettings() const
BatteryIndicatorSettings * batteryIndicatorSettings() const
FirmwareUpgradeSettings * firmwareUpgradeSettings() const
FlightModeSettings * flightModeSettings() const
static SettingsManager * instance()
APMMavlinkStreamRateSettings * apmMavlinkStreamRateSettings() const
LogManagerSettings * logManagerSettings() const
VideoSettings * videoSettings() const
static void adjustSettingMetaData(const QString &settingsGroup, FactMetaData &metaData, bool &userVisible)
AppSettings * appSettings() const
OfflineMapsSettings * offlineMapsSettings() const
RemoteIDSettings * remoteIDSettings() const
GeoViewSettings * geoViewSettings() const
MavlinkActionsSettings * mavlinkActionsSettings() const
FlyViewSettings * flyViewSettings() const
GimbalControllerSettings * gimbalControllerSettings() const
MavlinkSettings * mavlinkSettings() const
NTRIPSettings * ntripSettings() const
bool validateInternalQGCJsonFile(const QJsonObject &jsonObject, const QString &expectedFileType, int minSupportedVersion, int maxSupportedVersion, int &version, QString &errorString)
bool validateKeys(const QJsonObject &jsonObject, const QList< KeyValidateInfo > &keyInfo, QString &errorString)
Validates that all required keys are present and that listed keys have the expected type.
bool isJsonFile(const QByteArray &bytes, QJsonDocument &jsonDoc, QString &errorString)
Determines whether an in-memory byte buffer contains parseable JSON content.
bool runningUnitTests()