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