Launcher can save/load configs to disk
Aircraft state is also persisted to configs and on flying
This commit is contained in:
parent
c013eb74ab
commit
5ebee55632
15 changed files with 290 additions and 103 deletions
|
@ -7,12 +7,52 @@
|
||||||
|
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QIODevice>
|
||||||
|
#include <QDataStream>
|
||||||
|
|
||||||
static bool static_enableDownloadDirUI = true;
|
static bool static_enableDownloadDirUI = true;
|
||||||
|
static QSettings::Format static_binaryFormat = QSettings::InvalidFormat;
|
||||||
|
|
||||||
|
static bool binaryReadFunc(QIODevice &device, QSettings::SettingsMap &map)
|
||||||
|
{
|
||||||
|
QDataStream ds(&device);
|
||||||
|
int count;
|
||||||
|
ds >> count;
|
||||||
|
for (int i=0; i < count; ++i) {
|
||||||
|
QString k;
|
||||||
|
QVariant v;
|
||||||
|
ds >> k >> v;
|
||||||
|
map.insert(k, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool binaryWriteFunc(QIODevice &device, const QSettings::SettingsMap &map)
|
||||||
|
{
|
||||||
|
QDataStream ds(&device);
|
||||||
|
|
||||||
|
ds << map.size();
|
||||||
|
Q_FOREACH(QString key, map.keys()) {
|
||||||
|
ds << key << map.value(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
LaunchConfig::LaunchConfig(QObject* parent) :
|
LaunchConfig::LaunchConfig(QObject* parent) :
|
||||||
QObject(parent)
|
QObject(parent)
|
||||||
{
|
{
|
||||||
|
if (static_binaryFormat == QSettings::InvalidFormat) {
|
||||||
|
static_binaryFormat = QSettings::registerFormat("fglaunch",
|
||||||
|
&binaryReadFunc,
|
||||||
|
&binaryWriteFunc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchConfig::~LaunchConfig()
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaunchConfig::reset()
|
void LaunchConfig::reset()
|
||||||
|
@ -130,11 +170,59 @@ QString LaunchConfig::htmlForCommandLine()
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LaunchConfig::saveConfigToINI()
|
||||||
|
{
|
||||||
|
// create settings using default type (INI) and path (inside FG_HOME),
|
||||||
|
// as setup in initQSettings()
|
||||||
|
m_loadSaveSettings.reset(new QSettings);
|
||||||
|
emit save();
|
||||||
|
m_loadSaveSettings->sync();
|
||||||
|
m_loadSaveSettings.reset();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LaunchConfig::loadConfigFromINI()
|
||||||
|
{
|
||||||
|
// create settings using default type (INI) and path (inside FG_HOME),
|
||||||
|
// as setup in initQSettings()
|
||||||
|
m_loadSaveSettings.reset(new QSettings);
|
||||||
|
emit restore();
|
||||||
|
emit postRestore();
|
||||||
|
m_loadSaveSettings.reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LaunchConfig::saveConfigToFile(QString path)
|
||||||
|
{
|
||||||
|
m_loadSaveSettings.reset(new QSettings(path, static_binaryFormat));
|
||||||
|
emit save();
|
||||||
|
m_loadSaveSettings.reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LaunchConfig::loadConfigFromFile(QString path)
|
||||||
|
{
|
||||||
|
m_loadSaveSettings.reset(new QSettings(path, static_binaryFormat));
|
||||||
|
emit restore();
|
||||||
|
// some things have an ordering dependency, give them a chance to run
|
||||||
|
// after other settings have been restored (eg, location or aircraft)
|
||||||
|
emit postRestore();
|
||||||
|
m_loadSaveSettings.reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
QVariant LaunchConfig::getValueForKey(QString group, QString key, QVariant defaultValue) const
|
QVariant LaunchConfig::getValueForKey(QString group, QString key, QVariant defaultValue) const
|
||||||
{
|
{
|
||||||
QSettings settings;
|
if (!m_loadSaveSettings) {
|
||||||
settings.beginGroup(group);
|
// becuase we load settings on component completion, we need
|
||||||
auto v = settings.value(key, defaultValue);
|
// to create the default implementation (using the INI file)
|
||||||
|
// on demand
|
||||||
|
m_loadSaveSettings.reset(new QSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_loadSaveSettings->beginGroup(group);
|
||||||
|
auto v = m_loadSaveSettings->value(key, defaultValue);
|
||||||
bool convertedOk = v.convert(defaultValue.type());
|
bool convertedOk = v.convert(defaultValue.type());
|
||||||
if (!convertedOk) {
|
if (!convertedOk) {
|
||||||
qWarning() << "type forcing on loaded value failed:" << key << v << v.typeName() << defaultValue;
|
qWarning() << "type forcing on loaded value failed:" << key << v << v.typeName() << defaultValue;
|
||||||
|
@ -145,11 +233,11 @@ QVariant LaunchConfig::getValueForKey(QString group, QString key, QVariant defau
|
||||||
|
|
||||||
void LaunchConfig::setValueForKey(QString group, QString key, QVariant var)
|
void LaunchConfig::setValueForKey(QString group, QString key, QVariant var)
|
||||||
{
|
{
|
||||||
QSettings settings;
|
Q_ASSERT(m_loadSaveSettings);
|
||||||
settings.beginGroup(group);
|
m_loadSaveSettings->beginGroup(group);
|
||||||
// qInfo() << "saving" << key << "with value" << var << var.typeName();
|
// qInfo() << "saving" << key << "with value" << var << var.typeName();
|
||||||
settings.setValue(key, var);
|
m_loadSaveSettings->setValue(key, var);
|
||||||
settings.endGroup();
|
m_loadSaveSettings->endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString LaunchConfig::defaultDownloadDir() const
|
QString LaunchConfig::defaultDownloadDir() const
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
#include <QScopedPointer>
|
||||||
|
|
||||||
|
// forwards decls
|
||||||
|
class QSettings;
|
||||||
|
|
||||||
namespace flightgear { class Options; }
|
namespace flightgear { class Options; }
|
||||||
|
|
||||||
|
@ -34,6 +38,7 @@ public:
|
||||||
|
|
||||||
|
|
||||||
LaunchConfig(QObject* parent = nullptr);
|
LaunchConfig(QObject* parent = nullptr);
|
||||||
|
~LaunchConfig();
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
void applyToOptions() const;
|
void applyToOptions() const;
|
||||||
|
@ -52,10 +57,12 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE QString htmlForCommandLine();
|
Q_INVOKABLE QString htmlForCommandLine();
|
||||||
|
|
||||||
|
bool saveConfigToINI();
|
||||||
|
bool loadConfigFromINI();
|
||||||
|
|
||||||
// ensure a property is /not/ set?
|
Q_INVOKABLE bool saveConfigToFile(QString path);
|
||||||
|
|
||||||
// save and restore API?
|
Q_INVOKABLE bool loadConfigFromFile(QString path);
|
||||||
|
|
||||||
Q_INVOKABLE QVariant getValueForKey(QString group, QString key, QVariant defaultValue = QVariant()) const;
|
Q_INVOKABLE QVariant getValueForKey(QString group, QString key, QVariant defaultValue = QVariant()) const;
|
||||||
Q_INVOKABLE void setValueForKey(QString group, QString key, QVariant var);
|
Q_INVOKABLE void setValueForKey(QString group, QString key, QVariant var);
|
||||||
|
@ -72,11 +79,17 @@ public:
|
||||||
signals:
|
signals:
|
||||||
void collect();
|
void collect();
|
||||||
|
|
||||||
|
void save();
|
||||||
|
|
||||||
|
void restore();
|
||||||
|
|
||||||
|
void postRestore();
|
||||||
private:
|
private:
|
||||||
std::set<std::string> extraArgNames() const;
|
std::set<std::string> extraArgNames() const;
|
||||||
|
|
||||||
std::vector<Arg> m_values;
|
std::vector<Arg> m_values;
|
||||||
QString m_defaultDownloadDir;
|
QString m_defaultDownloadDir;
|
||||||
|
mutable QScopedPointer<QSettings> m_loadSaveSettings;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <QQuickWindow>
|
#include <QQuickWindow>
|
||||||
#include <QQmlComponent>
|
#include <QQmlComponent>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#include <QFileDialog>
|
||||||
|
|
||||||
// simgear headers
|
// simgear headers
|
||||||
#include <simgear/package/Install.hxx>
|
#include <simgear/package/Install.hxx>
|
||||||
|
@ -61,6 +62,8 @@ LauncherController::LauncherController(QObject *parent, QWindow* window) :
|
||||||
|
|
||||||
m_config = new LaunchConfig(this);
|
m_config = new LaunchConfig(this);
|
||||||
connect(m_config, &LaunchConfig::collect, this, &LauncherController::collectAircraftArgs);
|
connect(m_config, &LaunchConfig::collect, this, &LauncherController::collectAircraftArgs);
|
||||||
|
connect(m_config, &LaunchConfig::save, this, &LauncherController::saveAircraft);
|
||||||
|
connect(m_config, &LaunchConfig::restore, this, &LauncherController::restoreAircraft);
|
||||||
|
|
||||||
m_location->setLaunchConfig(m_config);
|
m_location->setLaunchConfig(m_config);
|
||||||
connect(m_location, &LocationController::descriptionChanged,
|
connect(m_location, &LocationController::descriptionChanged,
|
||||||
|
@ -165,7 +168,7 @@ bool LauncherController::inAppResult() const
|
||||||
return m_appModeResult;
|
return m_appModeResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LauncherController::restoreSettings()
|
void LauncherController::initialRestoreSettings()
|
||||||
{
|
{
|
||||||
m_selectedAircraft = m_aircraftHistory->mostRecent();
|
m_selectedAircraft = m_aircraftHistory->mostRecent();
|
||||||
if (m_selectedAircraft.isEmpty()) {
|
if (m_selectedAircraft.isEmpty()) {
|
||||||
|
@ -179,8 +182,7 @@ void LauncherController::restoreSettings()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_location->restoreSearchHistory();
|
||||||
m_location->restoreSettings();
|
|
||||||
QVariantMap currentLocation = m_locationHistory->mostRecent();
|
QVariantMap currentLocation = m_locationHistory->mostRecent();
|
||||||
if (currentLocation.isEmpty()) {
|
if (currentLocation.isEmpty()) {
|
||||||
// use the default
|
// use the default
|
||||||
|
@ -193,19 +195,22 @@ void LauncherController::restoreSettings()
|
||||||
}
|
}
|
||||||
m_location->restoreLocation(currentLocation);
|
m_location->restoreLocation(currentLocation);
|
||||||
|
|
||||||
|
emit selectedAircraftChanged(m_selectedAircraft);
|
||||||
|
|
||||||
updateSelectedAircraft();
|
updateSelectedAircraft();
|
||||||
m_serversModel->requestRestore();
|
m_serversModel->requestRestore();
|
||||||
|
m_aircraftState = m_config->getValueForKey("", "selected-aircraft-state", QString()).toString();
|
||||||
|
emit selectedAircraftStateChanged();
|
||||||
|
|
||||||
emit summaryChanged();
|
emit summaryChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LauncherController::saveSettings()
|
void LauncherController::saveSettings()
|
||||||
{
|
{
|
||||||
emit requestSaveState();
|
|
||||||
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.setValue("window-geometry", m_window->geometry());
|
settings.setValue("window-geometry", m_window->geometry());
|
||||||
|
|
||||||
|
m_config->saveConfigToINI();
|
||||||
m_aircraftHistory->saveToSettings();
|
m_aircraftHistory->saveToSettings();
|
||||||
m_locationHistory->saveToSettings();
|
m_locationHistory->saveToSettings();
|
||||||
}
|
}
|
||||||
|
@ -230,6 +235,18 @@ void LauncherController::collectAircraftArgs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_selectedAircraftInfo->hasStates() && !m_aircraftState.isEmpty()) {
|
||||||
|
QString state = m_aircraftState;
|
||||||
|
if ((m_aircraftState == "auto") && !m_selectedAircraftInfo->haveExplicitAutoState()) {
|
||||||
|
state = selectAircraftStateAutomatically();
|
||||||
|
qInfo() << "doing launcher auto state selection, picked:" + state;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!state.isEmpty()) {
|
||||||
|
m_config->setArg("state", state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// scenery paths
|
// scenery paths
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
Q_FOREACH(QString path, settings.value("scenery-paths").toStringList()) {
|
Q_FOREACH(QString path, settings.value("scenery-paths").toStringList()) {
|
||||||
|
@ -242,6 +259,23 @@ void LauncherController::collectAircraftArgs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LauncherController::saveAircraft()
|
||||||
|
{
|
||||||
|
m_config->setValueForKey("", "selected-aircraft", m_selectedAircraft);
|
||||||
|
if (!m_aircraftState.isEmpty()) {
|
||||||
|
m_config->setValueForKey("", "selected-aircraft-state", m_aircraftState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LauncherController::restoreAircraft()
|
||||||
|
{
|
||||||
|
m_selectedAircraft = m_config->getValueForKey("", "selected-aircraft", QUrl()).toUrl();
|
||||||
|
m_aircraftState = m_config->getValueForKey("", "selected-aircraft-state", QString()).toString();
|
||||||
|
emit selectedAircraftChanged(m_selectedAircraft);
|
||||||
|
updateSelectedAircraft();
|
||||||
|
emit selectedAircraftStateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void LauncherController::doRun()
|
void LauncherController::doRun()
|
||||||
{
|
{
|
||||||
flightgear::Options* opt = flightgear::Options::sharedInstance();
|
flightgear::Options* opt = flightgear::Options::sharedInstance();
|
||||||
|
@ -318,8 +352,13 @@ QString LauncherController::selectAircraftStateAutomatically()
|
||||||
if (!m_selectedAircraftInfo)
|
if (!m_selectedAircraftInfo)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (m_location->isAirborneLocation() && m_selectedAircraftInfo->hasState("approach"))
|
if (m_location->isAirborneLocation() && m_selectedAircraftInfo->hasState("cruise")) {
|
||||||
{
|
if (m_location->altitudeFt() > 6000) {
|
||||||
|
return "cruise";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_location->isAirborneLocation() && m_selectedAircraftInfo->hasState("approach")) {
|
||||||
return "approach";
|
return "approach";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,8 +491,11 @@ void LauncherController::setSelectedAircraft(QUrl selectedAircraft)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_selectedAircraft = selectedAircraft;
|
m_selectedAircraft = selectedAircraft;
|
||||||
|
m_aircraftState.clear();
|
||||||
|
|
||||||
updateSelectedAircraft();
|
updateSelectedAircraft();
|
||||||
emit selectedAircraftChanged(m_selectedAircraft);
|
emit selectedAircraftChanged(m_selectedAircraft);
|
||||||
|
emit selectedAircraftStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LauncherController::setSettingsSearchTerm(QString settingsSearchTerm)
|
void LauncherController::setSettingsSearchTerm(QString settingsSearchTerm)
|
||||||
|
@ -708,5 +750,24 @@ void LauncherController::requestChangeDataPath()
|
||||||
settings.setValue("fg-root", "!ask");
|
settings.setValue("fg-root", "!ask");
|
||||||
} // scope the ensure settings are written nicely
|
} // scope the ensure settings are written nicely
|
||||||
|
|
||||||
flightgear::restartTheApp();
|
flightgear::restartTheApp();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LauncherController::openConfig()
|
||||||
|
{
|
||||||
|
QString file = QFileDialog::getOpenFileName(nullptr, tr("Choose a saved configuration"),
|
||||||
|
{}, "*.fglaunch");
|
||||||
|
if (file.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_config->loadConfigFromFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LauncherController::saveConfigAs()
|
||||||
|
{
|
||||||
|
QString file = QFileDialog::getSaveFileName(nullptr, tr("Save the current configuration"),
|
||||||
|
{}, "*.fglaunch");
|
||||||
|
if (file.isEmpty())
|
||||||
|
return;
|
||||||
|
m_config->saveConfigToFile(file);
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,8 @@ class LauncherController : public QObject
|
||||||
|
|
||||||
Q_PROPERTY(QmlAircraftInfo* selectedAircraftInfo READ selectedAircraftInfo NOTIFY selectedAircraftChanged)
|
Q_PROPERTY(QmlAircraftInfo* selectedAircraftInfo READ selectedAircraftInfo NOTIFY selectedAircraftChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(QString selectedAircraftState MEMBER m_aircraftState NOTIFY selectedAircraftStateChanged)
|
||||||
|
|
||||||
Q_PROPERTY(bool isSearchActive READ isSearchActive NOTIFY searchChanged)
|
Q_PROPERTY(bool isSearchActive READ isSearchActive NOTIFY searchChanged)
|
||||||
Q_PROPERTY(QString settingsSearchTerm READ settingsSearchTerm WRITE setSettingsSearchTerm NOTIFY searchChanged)
|
Q_PROPERTY(QString settingsSearchTerm READ settingsSearchTerm WRITE setSettingsSearchTerm NOTIFY searchChanged)
|
||||||
|
|
||||||
|
@ -131,7 +133,6 @@ public:
|
||||||
Q_INVOKABLE QVariantList defaultSplashUrls() const;
|
Q_INVOKABLE QVariantList defaultSplashUrls() const;
|
||||||
|
|
||||||
|
|
||||||
Q_INVOKABLE QString selectAircraftStateAutomatically();
|
|
||||||
|
|
||||||
LaunchConfig* config() const
|
LaunchConfig* config() const
|
||||||
{ return m_config; }
|
{ return m_config; }
|
||||||
|
@ -144,7 +145,7 @@ public:
|
||||||
AircraftItemModel* baseAircraftModel() const
|
AircraftItemModel* baseAircraftModel() const
|
||||||
{ return m_aircraftModel; }
|
{ return m_aircraftModel; }
|
||||||
|
|
||||||
void restoreSettings();
|
void initialRestoreSettings();
|
||||||
void saveSettings();
|
void saveSettings();
|
||||||
|
|
||||||
LocationController* location() const
|
LocationController* location() const
|
||||||
|
@ -169,18 +170,13 @@ public:
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void selectedAircraftChanged(QUrl selectedAircraft);
|
void selectedAircraftChanged(QUrl selectedAircraft);
|
||||||
|
void selectedAircraftStateChanged();
|
||||||
|
|
||||||
void searchChanged();
|
void searchChanged();
|
||||||
void summaryChanged();
|
void summaryChanged();
|
||||||
|
|
||||||
void canFlyChanged();
|
void canFlyChanged();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief requestSaveState - signal to request QML settings to save their
|
|
||||||
* state to persistent storage
|
|
||||||
*/
|
|
||||||
void requestSaveState();
|
|
||||||
|
|
||||||
void viewCommandLine();
|
void viewCommandLine();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -198,11 +194,16 @@ public slots:
|
||||||
void requestRestoreDefaults();
|
void requestRestoreDefaults();
|
||||||
|
|
||||||
void requestChangeDataPath();
|
void requestChangeDataPath();
|
||||||
|
|
||||||
|
void openConfig();
|
||||||
|
void saveConfigAs();
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void onAircraftInstalledCompleted(QModelIndex index);
|
void onAircraftInstalledCompleted(QModelIndex index);
|
||||||
void onAircraftInstallFailed(QModelIndex index, QString errorMessage);
|
void onAircraftInstallFailed(QModelIndex index, QString errorMessage);
|
||||||
|
|
||||||
|
void saveAircraft();
|
||||||
|
void restoreAircraft();
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Check if the passed index is the selected aircraft, and if so, refresh
|
* Check if the passed index is the selected aircraft, and if so, refresh
|
||||||
|
@ -220,6 +221,8 @@ private:
|
||||||
|
|
||||||
void collectAircraftArgs();
|
void collectAircraftArgs();
|
||||||
|
|
||||||
|
QString selectAircraftStateAutomatically();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QWindow* m_window = nullptr;
|
QWindow* m_window = nullptr;
|
||||||
|
|
||||||
|
@ -231,6 +234,7 @@ private:
|
||||||
LocationController* m_location = nullptr;
|
LocationController* m_location = nullptr;
|
||||||
|
|
||||||
QUrl m_selectedAircraft;
|
QUrl m_selectedAircraft;
|
||||||
|
QString m_aircraftState;
|
||||||
AircraftType m_aircraftType = Airplane;
|
AircraftType m_aircraftType = Airplane;
|
||||||
int m_ratingFilters[4] = {3, 3, 3, 3};
|
int m_ratingFilters[4] = {3, 3, 3, 3};
|
||||||
LaunchConfig* m_config = nullptr;
|
LaunchConfig* m_config = nullptr;
|
||||||
|
|
|
@ -39,6 +39,15 @@ LauncherMainWindow::LauncherMainWindow() :
|
||||||
#if defined(Q_OS_MAC)
|
#if defined(Q_OS_MAC)
|
||||||
QMenuBar* mb = new QMenuBar();
|
QMenuBar* mb = new QMenuBar();
|
||||||
|
|
||||||
|
QMenu* fileMenu = mb->addMenu(tr("File"));
|
||||||
|
QAction* openAction = fileMenu->addAction(tr("Open saved configuration..."));
|
||||||
|
connect(openAction, &QAction::triggered,
|
||||||
|
m_controller, &LauncherController::openConfig);
|
||||||
|
|
||||||
|
QAction* saveAction = fileMenu->addAction(tr("Save configuration as..."));
|
||||||
|
connect(saveAction, &QAction::triggered,
|
||||||
|
m_controller, &LauncherController::saveConfigAs);
|
||||||
|
|
||||||
QMenu* toolsMenu = mb->addMenu(tr("Tools"));
|
QMenu* toolsMenu = mb->addMenu(tr("Tools"));
|
||||||
QAction* restoreDefaultsAction = toolsMenu->addAction(tr("Restore defaults..."));
|
QAction* restoreDefaultsAction = toolsMenu->addAction(tr("Restore defaults..."));
|
||||||
connect(restoreDefaultsAction, &QAction::triggered,
|
connect(restoreDefaultsAction, &QAction::triggered,
|
||||||
|
@ -57,7 +66,7 @@ LauncherMainWindow::LauncherMainWindow() :
|
||||||
qa->setShortcut(QKeySequence("Ctrl+Q"));
|
qa->setShortcut(QKeySequence("Ctrl+Q"));
|
||||||
connect(qa, &QAction::triggered, m_controller, &LauncherController::quit);
|
connect(qa, &QAction::triggered, m_controller, &LauncherController::quit);
|
||||||
|
|
||||||
m_controller->restoreSettings();
|
m_controller->initialRestoreSettings();
|
||||||
flightgear::launcherSetSceneryPaths();
|
flightgear::launcherSetSceneryPaths();
|
||||||
|
|
||||||
auto addOnsCtl = new AddOnsController(this);
|
auto addOnsCtl = new AddOnsController(this);
|
||||||
|
|
|
@ -391,14 +391,32 @@ void LocationController::setLaunchConfig(LaunchConfig *config)
|
||||||
{
|
{
|
||||||
m_config = config;
|
m_config = config;
|
||||||
connect(m_config, &LaunchConfig::collect, this, &LocationController::onCollectConfig);
|
connect(m_config, &LaunchConfig::collect, this, &LocationController::onCollectConfig);
|
||||||
|
|
||||||
|
connect(m_config, &LaunchConfig::save, this, &LocationController::onSaveCurrentLocation);
|
||||||
|
connect(m_config, &LaunchConfig::restore, this, &LocationController::onRestoreCurrentLocation);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocationController::restoreSettings()
|
void LocationController::restoreSearchHistory()
|
||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
m_recentLocations = loadPositionedList(settings.value("recent-locations"));
|
m_recentLocations = loadPositionedList(settings.value("recent-locations"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LocationController::onRestoreCurrentLocation()
|
||||||
|
{
|
||||||
|
QVariantMap vm = m_config->getValueForKey("", "current-location", QVariantMap()).toMap();
|
||||||
|
if (vm.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
restoreLocation(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocationController::onSaveCurrentLocation()
|
||||||
|
{
|
||||||
|
m_config->setValueForKey("", "current-location", saveLocation());
|
||||||
|
}
|
||||||
|
|
||||||
bool LocationController::isParkedLocation() const
|
bool LocationController::isParkedLocation() const
|
||||||
{
|
{
|
||||||
if (m_airportLocation) {
|
if (m_airportLocation) {
|
||||||
|
@ -417,24 +435,25 @@ bool LocationController::isAirborneLocation() const
|
||||||
const bool altIsPositive = (m_altitudeFt > 0);
|
const bool altIsPositive = (m_altitudeFt > 0);
|
||||||
|
|
||||||
if (m_locationIsLatLon) {
|
if (m_locationIsLatLon) {
|
||||||
return altIsPositive;
|
return (m_altitudeType != AltitudeType::Off) && altIsPositive;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_airportLocation) {
|
if (m_airportLocation) {
|
||||||
const bool onRunway = (m_detailLocation && (m_detailLocation->type() == FGPositioned::RUNWAY));
|
const bool onRunway =
|
||||||
if (onRunway && m_offsetEnabled) {
|
(m_detailLocation && (m_detailLocation->type() == FGPositioned::RUNWAY)) ||
|
||||||
|
m_useActiveRunway;
|
||||||
|
|
||||||
|
if (onRunway && m_onFinal) {
|
||||||
// in this case no altitude might be set, but we assume
|
// in this case no altitude might be set, but we assume
|
||||||
// it's still an airborne pos
|
// it's still an airborne position
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this allows for people using offsets from a parking position or
|
return false;
|
||||||
// similar weirdness :)
|
|
||||||
return altIsPositive;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// relative to a navaid or fix - base off altitude.
|
// relative to a navaid or fix - base off altitude.
|
||||||
return altIsPositive;
|
return (m_altitudeType != AltitudeType::Off) && altIsPositive;
|
||||||
}
|
}
|
||||||
|
|
||||||
int LocationController::offsetRadial() const
|
int LocationController::offsetRadial() const
|
||||||
|
@ -709,7 +728,7 @@ void LocationController::restoreLocation(QVariantMap l)
|
||||||
|
|
||||||
if (l.contains("location-apt-runway")) {
|
if (l.contains("location-apt-runway")) {
|
||||||
QString runway = l.value("location-apt-runway").toString().toUpper();
|
QString runway = l.value("location-apt-runway").toString().toUpper();
|
||||||
if (runway == "ACTIVE") {
|
if (runway == QStringLiteral("ACTIVE")) {
|
||||||
m_useActiveRunway = true;
|
m_useActiveRunway = true;
|
||||||
} else {
|
} else {
|
||||||
m_detailLocation = m_airportLocation->getRunwayByIdent(runway.toStdString());
|
m_detailLocation = m_airportLocation->getRunwayByIdent(runway.toStdString());
|
||||||
|
|
|
@ -101,7 +101,7 @@ public:
|
||||||
void restoreLocation(QVariantMap l);
|
void restoreLocation(QVariantMap l);
|
||||||
QVariantMap saveLocation() const;
|
QVariantMap saveLocation() const;
|
||||||
|
|
||||||
void restoreSettings();
|
void restoreSearchHistory();
|
||||||
|
|
||||||
/// used to automatically select aircraft state
|
/// used to automatically select aircraft state
|
||||||
bool isParkedLocation() const;
|
bool isParkedLocation() const;
|
||||||
|
@ -170,6 +170,10 @@ public:
|
||||||
return m_locationIsLatLon;
|
return m_locationIsLatLon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int altitudeFt() const
|
||||||
|
{
|
||||||
|
return m_altitudeFt;
|
||||||
|
}
|
||||||
public slots:
|
public slots:
|
||||||
void setOffsetRadial(int offsetRadial);
|
void setOffsetRadial(int offsetRadial);
|
||||||
|
|
||||||
|
@ -192,6 +196,8 @@ Q_SIGNALS:
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void onCollectConfig();
|
void onCollectConfig();
|
||||||
|
void onRestoreCurrentLocation();
|
||||||
|
void onSaveCurrentLocation();
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void onSearchComplete();
|
void onSearchComplete();
|
||||||
|
|
|
@ -155,7 +155,6 @@ class StatesModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(bool hasExplicitAuto READ hasExplicitAuto CONSTANT)
|
|
||||||
public:
|
public:
|
||||||
StatesModel()
|
StatesModel()
|
||||||
{
|
{
|
||||||
|
@ -181,11 +180,15 @@ public:
|
||||||
// we will not run our own selection logic
|
// we will not run our own selection logic
|
||||||
_explicitAutoState = true;
|
_explicitAutoState = true;
|
||||||
} else {
|
} else {
|
||||||
// disabling this code for 2018.1, since it needs more testing
|
|
||||||
_data.insert(_data.begin(), {{"auto"}, {}, tr("Select state based on startup position.")});
|
_data.insert(_data.begin(), {{"auto"}, {}, tr("Select state based on startup position.")});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Q_INVOKABLE int indexForTag(QString s) const
|
||||||
|
{
|
||||||
|
return indexForTag(s.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
int indexForTag(const std::string &tag) const
|
int indexForTag(const std::string &tag) const
|
||||||
{
|
{
|
||||||
auto it = std::find_if(_data.begin(), _data.end(), [tag](const StateInfo& i) {
|
auto it = std::find_if(_data.begin(), _data.end(), [tag](const StateInfo& i) {
|
||||||
|
@ -684,6 +687,11 @@ bool QmlAircraftInfo::hasState(QString name) const
|
||||||
return _statesModel->hasState(name);
|
return _statesModel->hasState(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QmlAircraftInfo::haveExplicitAutoState() const
|
||||||
|
{
|
||||||
|
return _statesModel->hasExplicitAuto();
|
||||||
|
}
|
||||||
|
|
||||||
StatesModel *QmlAircraftInfo::statesModel()
|
StatesModel *QmlAircraftInfo::statesModel()
|
||||||
{
|
{
|
||||||
return _statesModel.data();
|
return _statesModel.data();
|
||||||
|
|
|
@ -107,6 +107,8 @@ public:
|
||||||
|
|
||||||
bool hasState(QString name) const;
|
bool hasState(QString name) const;
|
||||||
|
|
||||||
|
bool haveExplicitAutoState() const;
|
||||||
|
|
||||||
static const int StateTagRole;
|
static const int StateTagRole;
|
||||||
static const int StateDescriptionRole;
|
static const int StateDescriptionRole;
|
||||||
static const int StateExplicitRole;
|
static const int StateExplicitRole;
|
||||||
|
|
|
@ -9,14 +9,6 @@ Item {
|
||||||
value: timeOfDay.summary().concat(weatherSettings.summary());
|
value: timeOfDay.summary().concat(weatherSettings.summary());
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: _launcher
|
|
||||||
onRequestSaveState: {
|
|
||||||
timeOfDaySettings.saveState();
|
|
||||||
weatherSettings.saveState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Flickable {
|
Flickable {
|
||||||
contentHeight: sectionColumn.childrenRect.height
|
contentHeight: sectionColumn.childrenRect.height
|
||||||
flickableDirection: Flickable.VerticalFlick
|
flickableDirection: Flickable.VerticalFlick
|
||||||
|
|
|
@ -131,8 +131,8 @@ Item {
|
||||||
z: 100
|
z: 100
|
||||||
|
|
||||||
items: [
|
items: [
|
||||||
MenuItem { text:qsTr("Open saved configuration..."); enabled: false },
|
MenuItem { text:qsTr("Open saved configuration..."); onTriggered: _launcher.openConfig(); },
|
||||||
MenuItem { text:qsTr("Save configuration..."); enabled: false },
|
MenuItem { text:qsTr("Save configuration as..."); onTriggered: _launcher.saveConfigAs(); },
|
||||||
MenuDivider {},
|
MenuDivider {},
|
||||||
MenuItem { text:qsTr("View command line"); onTriggered: _launcher.viewCommandLine(); },
|
MenuItem { text:qsTr("View command line"); onTriggered: _launcher.viewCommandLine(); },
|
||||||
MenuItem { text:qsTr("Select data files location..."); onTriggered: _launcher.requestChangeDataPath(); },
|
MenuItem { text:qsTr("Select data files location..."); onTriggered: _launcher.requestChangeDataPath(); },
|
||||||
|
|
|
@ -13,8 +13,6 @@ Item {
|
||||||
property bool enabled: true
|
property bool enabled: true
|
||||||
property int currentIndex: 0
|
property int currentIndex: 0
|
||||||
property bool __dummy: false
|
property bool __dummy: false
|
||||||
|
|
||||||
property alias header: choicesHeader.sourceComponent
|
|
||||||
property string headerText: ""
|
property string headerText: ""
|
||||||
|
|
||||||
implicitHeight: Math.max(label.implicitHeight, currentChoiceFrame.height)
|
implicitHeight: Math.max(label.implicitHeight, currentChoiceFrame.height)
|
||||||
|
@ -166,20 +164,11 @@ Item {
|
||||||
width: menuWidth
|
width: menuWidth
|
||||||
|
|
||||||
// optional header component:
|
// optional header component:
|
||||||
Loader {
|
StyledText {
|
||||||
id: choicesHeader
|
text: root.headerText
|
||||||
active: root.haveHeader()
|
visible: root.haveHeader();
|
||||||
|
height: implicitHeight + Style.margin
|
||||||
// default component is just a plain text element, same as
|
width: choicesColumn.width
|
||||||
// normal items
|
|
||||||
sourceComponent: StyledText {
|
|
||||||
text: root.headerText
|
|
||||||
height: implicitHeight + Style.margin
|
|
||||||
width: choicesColumn.width
|
|
||||||
}
|
|
||||||
|
|
||||||
height: item ? item.height : 0
|
|
||||||
width: item ? item.width : 0
|
|
||||||
|
|
||||||
// essentially the same mouse area as normal items
|
// essentially the same mouse area as normal items
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
@ -191,7 +180,7 @@ Item {
|
||||||
root.select(-1);
|
root.select(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // of header loader
|
}
|
||||||
|
|
||||||
function calculateMenuWidth()
|
function calculateMenuWidth()
|
||||||
{
|
{
|
||||||
|
|
|
@ -43,6 +43,12 @@ Item {
|
||||||
onCollect: apply();
|
onCollect: apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: _config
|
||||||
|
onRestore: root.restoreState();
|
||||||
|
onSave: root.saveState();
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
// this is the 'search hit highlight effect'
|
// this is the 'search hit highlight effect'
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
|
@ -20,26 +20,8 @@ Item {
|
||||||
renderSection.summary());
|
renderSection.summary());
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Flickable
|
||||||
target: _launcher
|
|
||||||
onRequestSaveState: settings.saveState();
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onDestruction: {
|
|
||||||
settings.saveState();
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveState()
|
|
||||||
{
|
{
|
||||||
mpSettings.saveState();
|
|
||||||
downloadSettings.saveState();
|
|
||||||
generalSettings.saveState();
|
|
||||||
renderSection.saveState();
|
|
||||||
extraArgsSection.saveState();
|
|
||||||
windowSettings.saveState();
|
|
||||||
}
|
|
||||||
|
|
||||||
Flickable {
|
|
||||||
id: settingsFlick
|
id: settingsFlick
|
||||||
contentHeight: sectionColumn.childrenRect.height
|
contentHeight: sectionColumn.childrenRect.height
|
||||||
flickableDirection: Flickable.VerticalFlick
|
flickableDirection: Flickable.VerticalFlick
|
||||||
|
|
|
@ -86,7 +86,7 @@ Item {
|
||||||
// dynamic text sizing, so bind it manually
|
// dynamic text sizing, so bind it manually
|
||||||
y: logoText.y + Style.margin + logoText.contentHeight
|
y: logoText.y + Style.margin + logoText.contentHeight
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: "Licenced under the GNU Public License (GPL)- click for more info"
|
text: "Licenced under the GNU Public License (GPL) - click for more info"
|
||||||
baseTextColor: "white"
|
baseTextColor: "white"
|
||||||
style: Text.Outline
|
style: Text.Outline
|
||||||
styleColor: "black"
|
styleColor: "black"
|
||||||
|
@ -216,12 +216,29 @@ Item {
|
||||||
width: summaryGrid.middleColumnWidth
|
width: summaryGrid.middleColumnWidth
|
||||||
spacing: Style.margin
|
spacing: Style.margin
|
||||||
|
|
||||||
|
Component.onCompleted: updateComboFromController();
|
||||||
|
|
||||||
|
function updateComboFromController()
|
||||||
|
{
|
||||||
|
stateSelectionCombo.currentIndex = _launcher.selectedAircraftInfo.statesModel.indexForTag(_launcher.selectedAircraftState)
|
||||||
|
}
|
||||||
|
|
||||||
PopupChoice {
|
PopupChoice {
|
||||||
id: stateSelectionCombo
|
id: stateSelectionCombo
|
||||||
model: _launcher.selectedAircraftInfo.statesModel
|
model: _launcher.selectedAircraftInfo.statesModel
|
||||||
displayRole: "name"
|
displayRole: "name"
|
||||||
label: qsTr("State:")
|
label: qsTr("State:")
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
headerText: qsTr("Default state")
|
||||||
|
|
||||||
|
function select(index)
|
||||||
|
{
|
||||||
|
if (index === -1) {
|
||||||
|
_launcher.selectedAircraftState = "";
|
||||||
|
} else {
|
||||||
|
_launcher.selectedAircraftState = model.tagForState(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
|
@ -234,22 +251,13 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: _config
|
target: _launcher.selectedAircraftInfo
|
||||||
onCollect: {
|
onInfoChanged: stateSelectionGroup.updateComboFromController()
|
||||||
if (!_launcher.selectedAircraftInfo.hasStates)
|
}
|
||||||
return;
|
|
||||||
|
|
||||||
var state = _launcher.selectedAircraftInfo.statesModel.tagForState(stateSelectionCombo.currentIndex);
|
Connections {
|
||||||
if (state === "auto" && !_launcher.selectedAircraftInfo.statesModel.hasExplicitAuto) {
|
target: _launcher
|
||||||
// auto state selection if not handled by aircraft
|
onSelectedAircraftStateChanged: stateSelectionGroup.updateComboFromController()
|
||||||
state = _launcher.selectAircraftStateAutomatically();
|
|
||||||
console.info("launcher auto state selection, picked:" + state)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state !== "__default__") { // don't set arg in default case
|
|
||||||
_config.setArg("state", state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // of connections
|
} // of connections
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue