Adds a persistent file used to store user settings (#2931)

* Enable the loading of settings
* Add a user interface for changing the settings in the launcher


Co-authored-by: Emma Broman <emma.broman@liu.se>
This commit is contained in:
Alexander Bock
2023-11-13 08:52:51 +01:00
committed by GitHub
parent 709cb24bbb
commit b62e604b2e
25 changed files with 1754 additions and 42 deletions

1
.gitignore vendored
View File

@@ -42,3 +42,4 @@ COMMIT.md
/modules/skybrowser/wwtimagedata
doc
config/schema/sgct.schema.json
settings.json

View File

@@ -27,6 +27,7 @@ include(${PROJECT_SOURCE_DIR}/support/cmake/set_openspace_compile_settings.cmake
set(HEADER_FILES
include/filesystemaccess.h
include/launcherwindow.h
include/settingsdialog.h
include/profile/actiondialog.h
include/profile/additionalscriptsdialog.h
include/profile/assetsdialog.h
@@ -55,6 +56,7 @@ set(HEADER_FILES
set(SOURCE_FILES
src/launcherwindow.cpp
src/filesystemaccess.cpp
src/settingsdialog.cpp
src/profile/actiondialog.cpp
src/profile/additionalscriptsdialog.cpp
src/profile/assetsdialog.cpp

View File

@@ -34,7 +34,7 @@
#include <QApplication>
#include <optional>
namespace openspace::configuration { struct Configuration; }
namespace openspace { struct Configuration; }
class QComboBox;
class QLabel;
@@ -54,8 +54,8 @@ public:
* in the tree structure.
*/
LauncherWindow(bool profileEnabled,
const openspace::configuration::Configuration& globalConfig,
bool sgctConfigEnabled, std::string sgctConfigName, QWidget* parent);
const openspace::Configuration& globalConfig, bool sgctConfigEnabled,
std::string sgctConfigName, QWidget* parent);
/**
* Returns bool for whether "start OpenSpace" was chosen when this window closed.

View File

@@ -0,0 +1,74 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___SETTINGSDIALOG___H__
#define __OPENSPACE_UI_LAUNCHER___SETTINGSDIALOG___H__
#include <QDialog>
#include <openspace/engine/settings.h>
class QCheckBox;
class QComboBox;
class QDialogButtonBox;
class QLabel;
class QLineEdit;
class SettingsDialog : public QDialog {
Q_OBJECT
public:
SettingsDialog(openspace::Settings settings,
QWidget* parent = nullptr);
signals:
void saveSettings(openspace::Settings settings);
private:
void createWidgets();
void loadFromSettings(const openspace::Settings& settings);
void updateSaveButton();
void save();
void reject();
QLineEdit* _configuration = nullptr;
QCheckBox* _rememberLastConfiguration = nullptr;
QLineEdit* _profile = nullptr;
QCheckBox* _rememberLastProfile = nullptr;
QComboBox* _propertyVisibility = nullptr;
QCheckBox* _bypassLauncher = nullptr;
QLabel* _bypassInformation = nullptr;
struct {
QCheckBox* isEnabled = nullptr;
QLineEdit* location = nullptr;
} _mrf;
QDialogButtonBox* _dialogButtons = nullptr;
// The set of settings that we have while editing
openspace::Settings _currentEdit;
};
#endif // __OPENSPACE_UI_LAUNCHER___SETTINGSDIALOG___H__

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@@ -92,6 +92,16 @@ LauncherWindow QPushButton#small:disabled {
background: rgb(160, 160, 160);
}
LauncherWindow QPushButton#settings {
border-image: url(:/images/cogwheel);
background-repeat: no-repeat;
}
LauncherWindow QPushButton#settings:hover {
border-image: url(:/images/cogwheel-highlight);
}
/*
* ProfileEdit
*/
@@ -209,3 +219,12 @@ WindowControl QLabel#notice {
font-weight: normal;
font-size: 11pt;
}
/*
* Settings
*/
SettingsWidget QLabel#information {
font-style: italic;
font-weight: normal;
font-size: 8pt;
}

View File

@@ -1,8 +1,10 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>qss/launcher.qss</file>
<file>images/openspace-horiz-logo-small.png</file>
<file>images/cogwheel.png</file>
<file>images/cogwheel-highlight.png</file>
<file>images/launcher-background.png</file>
<file>images/openspace-horiz-logo-small.png</file>
<file>images/outline_locked.png</file>
<file>images/outline_unlocked.png</file>
</qresource>

View File

@@ -25,6 +25,7 @@
#include "launcherwindow.h"
#include "profile/profileedit.h"
#include "settingsdialog.h"
#include <openspace/engine/configuration.h>
#include <openspace/openspace.h>
@@ -60,6 +61,8 @@ namespace {
constexpr int SmallItemWidth = 100;
constexpr int SmallItemHeight = SmallItemWidth / 4;
constexpr int SettingsIconSize = 35;
namespace geometry {
constexpr QRect BackgroundImage(0, 0, ScreenWidth, ScreenHeight);
constexpr QRect LogoImage(LeftRuler, TopRuler, ItemWidth, ItemHeight);
@@ -85,6 +88,12 @@ namespace {
constexpr QRect VersionString(
5, ScreenHeight - SmallItemHeight, ItemWidth, SmallItemHeight
);
constexpr QRect SettingsButton(
ScreenWidth - SettingsIconSize - 5,
ScreenHeight - SettingsIconSize - 5,
SettingsIconSize,
SettingsIconSize
);
} // geometry
std::optional<Profile> loadProfileFromFile(QWidget* parent, std::string filename) {
@@ -204,7 +213,7 @@ namespace {
using namespace openspace;
LauncherWindow::LauncherWindow(bool profileEnabled,
const configuration::Configuration& globalConfig,
const Configuration& globalConfig,
bool sgctConfigEnabled, std::string sgctConfigName,
QWidget* parent)
: QMainWindow(parent)
@@ -376,6 +385,31 @@ QWidget* LauncherWindow::createCentralWidget() {
versionLabel->setObjectName("version-info");
versionLabel->setGeometry(geometry::VersionString);
QPushButton* settingsButton = new QPushButton(centralWidget);
settingsButton->setObjectName("settings");
settingsButton->setGeometry(geometry::SettingsButton);
settingsButton->setIconSize(QSize(SettingsIconSize, SettingsIconSize));
connect(
settingsButton,
&QPushButton::released,
[this]() {
using namespace openspace;
Settings settings = loadSettings();
SettingsDialog dialog(std::move(settings), this);
connect(
&dialog,
&SettingsDialog::saveSettings,
[](Settings settings) {
saveSettings(settings, findSettings());
}
);
dialog.exec();
}
);
return centralWidget;
}

View File

@@ -0,0 +1,410 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "settingsdialog.h"
#include "profile/line.h"
#include <QCheckBox>
#include <QComboBox>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#include <QMessageBox>
#include <QPushButton>
SettingsDialog::SettingsDialog(openspace::Settings settings,
QWidget* parent)
: QDialog(parent)
, _currentEdit(settings)
{
setWindowTitle("Settings");
createWidgets();
loadFromSettings(settings);
// Setting the startup values for the control will have caused the Save button to be
// enabled, so we need to manually disable it again here
_dialogButtons->button(QDialogButtonBox::Save)->setEnabled(false);
}
void SettingsDialog::createWidgets() {
// Layout of this dialog:
//
// -------------------------------------------------------
// | Profile |
// | Starting Profile: | [oooooooooooooooooooo] |
// | [] Keep Last Profile |
// | Configuration |
// | Starting Configuration: | [oooooooooooooooooooo] |
// | [] Keep Last Configuration |
// | User Interface |
// | Property Visibility | DDDDDDDDDDDDDDDDDDDDD> |
// | [] Bypass Launcher |
// | Informational text about undoing the bypass setting |
// | MRF Caching |
// | [] Enable caching |
// | Cache location | [oooooooooooooooooooo] |
// | | <Save> <Cancel> |
// -------------------------------------------------------
QGridLayout* layout = new QGridLayout(this);
layout->setSizeConstraint(QLayout::SetFixedSize);
{
QLabel* label = new QLabel("Profile");
label->setObjectName("heading");
layout->addWidget(label, 0, 0, 1, 2);
QLabel* conf = new QLabel("Starting Profile");
conf->setToolTip(
"With this setting, you can choose a profile that will be loaded the next "
"time you start the application"
);
layout->addWidget(conf, 1, 0);
_profile = new QLineEdit;
_profile->setToolTip(conf->toolTip());
connect(
_profile,
&QLineEdit::textChanged,
[this]() {
std::string v = _profile->text().toStdString();
if (v.empty()) {
_currentEdit.profile = std::nullopt;
}
else {
_currentEdit.profile = v;
}
updateSaveButton();
}
);
layout->addWidget(_profile, 1, 1);
_rememberLastProfile = new QCheckBox("Keep Last Profile");
_rememberLastProfile->setToolTip(
"If this setting is checked, the application will remember the profile that "
"was loaded into OpenSpace and will use it at the next startup as well"
);
connect(
_rememberLastProfile,
&QCheckBox::stateChanged,
[this]() {
if (_rememberLastProfile->isChecked()) {
_currentEdit.rememberLastProfile = true;
}
else {
_currentEdit.rememberLastProfile = std::nullopt;
}
_profile->setDisabled(_rememberLastProfile->isChecked());
updateSaveButton();
}
);
layout->addWidget(_rememberLastProfile, 2, 0, 1, 2);
}
layout->addWidget(new Line(), 3, 0, 1, 2);
{
QLabel* label = new QLabel("Configuration");
label->setObjectName("heading");
layout->addWidget(label, 4, 0, 1, 2);
QLabel* conf = new QLabel("Starting Configuration");
conf->setToolTip(
"With this setting, you can choose a window configuration that will be "
"loaded the next time you start the application"
);
layout->addWidget(conf, 5, 0);
_configuration = new QLineEdit;
_configuration->setToolTip(conf->toolTip());
connect(
_configuration,
&QLineEdit::textChanged,
[this]() {
std::string v = _configuration->text().toStdString();
if (v.empty()) {
_currentEdit.configuration = std::nullopt;
}
else {
_currentEdit.configuration = v;
}
updateSaveButton();
}
);
layout->addWidget(_configuration, 5, 1);
_rememberLastConfiguration = new QCheckBox("Keep Last Configuration");
_rememberLastConfiguration->setToolTip(
"If this setting is checked, the application will remember the window "
"configuration and will use it at the next startup as well"
);
connect(
_rememberLastConfiguration,
&QCheckBox::stateChanged,
[this]() {
if (_rememberLastConfiguration->isChecked()) {
_currentEdit.rememberLastConfiguration = true;
}
else {
_currentEdit.rememberLastConfiguration = std::nullopt;
}
_configuration->setDisabled(_rememberLastConfiguration->isChecked());
updateSaveButton();
}
);
layout->addWidget(_rememberLastConfiguration, 6, 0, 1, 2);
}
layout->addWidget(new Line(), 7, 0, 1, 2);
{
QLabel* label = new QLabel("User Interface");
label->setObjectName("heading");
layout->addWidget(label, 8, 0, 1, 2);
QLabel* conf = new QLabel("Property Visibility");
conf->setToolTip(
"This setting sets the default visibility for properties in the application. "
"Note that these values are ordered, so all properties shown as a 'Novice "
"User' are also visible when selecting 'User', etc."
);
layout->addWidget(conf, 9, 0);
_propertyVisibility = new QComboBox;
_propertyVisibility->setToolTip(conf->toolTip());
_propertyVisibility->addItems({
"Novice User",
"User",
"Advanced User",
"Developer"
});
_propertyVisibility->setCurrentText("User");
connect(
_propertyVisibility,
&QComboBox::textActivated,
[this](const QString& value) {
using Visibility = openspace::properties::Property::Visibility;
if (value == "Novice User") {
_currentEdit.visibility = Visibility::NoviceUser;
}
else if (value == "User") {
// This is the default value
_currentEdit.visibility = std::nullopt;
}
else if (value == "Advanced User") {
_currentEdit.visibility = Visibility::AdvancedUser;
}
else if (value == "Developer") {
_currentEdit.visibility = Visibility::Developer;
}
else {
throw ghoul::MissingCaseException();
}
updateSaveButton();
}
);
layout->addWidget(_propertyVisibility, 9, 1);
_bypassLauncher = new QCheckBox("Bypass Launcher");
_bypassLauncher->setToolTip(
"If this value is selected, the Launcher will no longer be shown at startup. "
"Note that this also means that it will not be easy to get back to this "
"setting to reenable the Launcher either."
);
connect(
_bypassLauncher,
&QCheckBox::stateChanged,
[this]() {
if (_bypassLauncher->isChecked()) {
_currentEdit.bypassLauncher = _bypassLauncher->isChecked();
}
else {
_currentEdit.bypassLauncher = std::nullopt;
}
_bypassInformation->setVisible(_bypassLauncher->isChecked());
updateSaveButton();
}
);
layout->addWidget(_bypassLauncher, 10, 0, 1, 2);
_bypassInformation = new QLabel(
"Saving the settings with the bypass launcher enabled will cause this window "
"to not show up again, making it harder to undo this change. In case you "
"need to undo it, you need to open the settings.json and remove the line "
"that says '\"bypass\": true,'"
);
_bypassInformation->setObjectName("information");
_bypassInformation->setHidden(true);
_bypassInformation->setWordWrap(true);
layout->addWidget(_bypassInformation, 11, 0, 1, 2);
}
layout->addWidget(new Line(), 12, 0, 1, 2);
{
QLabel* label = new QLabel("MRF Caching");
label->setObjectName("heading");
layout->addWidget(label, 13, 0, 1, 2);
_mrf.isEnabled = new QCheckBox("Enable Caching");
_mrf.isEnabled->setToolTip(
"If this setting is checked, the MRF caching for globe layers will be "
"enabled. This means that all planetary images that are loaded over the "
"internet will also be cached locally and stored between application runs. "
"This will speedup the loading the second time at the expense of hard disk "
"space."
);
connect(
_mrf.isEnabled,
&QCheckBox::stateChanged,
[this]() {
if (_mrf.isEnabled->isChecked()) {
_currentEdit.mrf.isEnabled = _mrf.isEnabled->isChecked();
}
else {
_currentEdit.mrf.isEnabled = std::nullopt;
}
_mrf.location->setDisabled(!_mrf.isEnabled->isChecked());
updateSaveButton();
}
);
layout->addWidget(_mrf.isEnabled, 14, 0, 1, 2);
QLabel* conf = new QLabel("Cache Location");
conf->setToolTip(
"This is the place where the MRF cache files are located. Please note that "
"these files can potentially become quite large when using OpenSpace for a "
"long while and when visiting new places regularly. If this value is left "
"blank, the cached files will be stored in the 'mrf_cache' folder in the "
"OpenSpace base folder."
);
layout->addWidget(conf, 15, 0);
_mrf.location = new QLineEdit;
_mrf.location->setToolTip(conf->toolTip());
_mrf.location->setDisabled(true);
connect(
_mrf.location,
&QLineEdit::editingFinished,
[this]() {
if (_mrf.location->text().isEmpty()) {
_currentEdit.mrf.location = std::nullopt;
}
else {
_currentEdit.mrf.location = _mrf.location->text().toStdString();
}
updateSaveButton();
}
);
layout->addWidget(_mrf.location, 15, 1);
}
layout->addWidget(new Line(), 16, 0, 1, 2);
_dialogButtons = new QDialogButtonBox;
_dialogButtons->setStandardButtons(
QDialogButtonBox::Save | QDialogButtonBox::Cancel
);
QObject::connect(
_dialogButtons, &QDialogButtonBox::accepted,
this, &SettingsDialog::save
);
QObject::connect(
_dialogButtons, &QDialogButtonBox::rejected,
this, &SettingsDialog::reject
);
layout->addWidget(_dialogButtons, 17, 1, 1, 1, Qt::AlignRight);
}
void SettingsDialog::loadFromSettings(const openspace::Settings& settings) {
using namespace openspace;
if (settings.configuration.has_value()) {
_configuration->setText(QString::fromStdString(*settings.configuration));
}
if (settings.rememberLastConfiguration.has_value()) {
_rememberLastConfiguration->setChecked(*settings.rememberLastConfiguration);
}
if (settings.profile.has_value()) {
_profile->setText(QString::fromStdString(*settings.profile));
}
if (settings.rememberLastProfile.has_value()) {
_rememberLastProfile->setChecked(*settings.rememberLastProfile);
}
if (settings.visibility.has_value()) {
using Visibility = openspace::properties::Property::Visibility;
Visibility vis = *settings.visibility;
switch (vis) {
case Visibility::NoviceUser:
_propertyVisibility->setCurrentText("Novice User");
break;
case Visibility::User:
_propertyVisibility->setCurrentText("User");
break;
case Visibility::AdvancedUser:
_propertyVisibility->setCurrentText("Advanced User");
break;
case Visibility::Developer:
_propertyVisibility->setCurrentText("Developer");
break;
case Visibility::Always:
case Visibility::Hidden:
break;
}
}
if (settings.bypassLauncher.has_value()) {
_bypassLauncher->setChecked(*settings.bypassLauncher);
}
if (settings.mrf.isEnabled.has_value()) {
_mrf.isEnabled->setChecked(*settings.mrf.isEnabled);
}
if (settings.mrf.location.has_value()) {
_mrf.location->setText(QString::fromStdString(*settings.mrf.location));
}
}
void SettingsDialog::updateSaveButton() {
_dialogButtons->button(QDialogButtonBox::Save)->setEnabled(true);
}
void SettingsDialog::save() {
emit saveSettings(_currentEdit);
_dialogButtons->button(QDialogButtonBox::Save)->setEnabled(false);
QDialog::accept();
}
void SettingsDialog::reject() {
QDialog::reject();
}

View File

@@ -22,10 +22,11 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/engine/configuration.h>
#include <openspace/documentation/documentation.h>
#include <openspace/engine/configuration.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/settings.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/joystickinputstate.h>
#include <openspace/openspace.h>
@@ -288,7 +289,7 @@ void mainInitFunc(GLFWwindow*) {
// to them later in the RenderEngine
std::filesystem::path screenshotPath = absPath("${SCREENSHOTS}");
FileSys.registerPathToken("${STARTUP_SCREENSHOT}", screenshotPath);
Settings::instance().setCapturePath(screenshotPath.string());
sgct::Settings::instance().setCapturePath(screenshotPath.string());
LDEBUG("Initializing OpenSpace Engine started");
global::openSpaceEngine->initialize();
@@ -899,7 +900,7 @@ void setSgctDelegateFunctions() {
sgctDelegate.takeScreenshot = [](bool applyWarping, std::vector<int> windowIds) {
ZoneScoped;
Settings::instance().setCaptureFromBackBuffer(applyWarping);
sgct::Settings::instance().setCaptureFromBackBuffer(applyWarping);
Engine::instance().takeScreenshot(std::move(windowIds));
return Engine::instance().screenShotNumber();
};
@@ -976,7 +977,7 @@ void setSgctDelegateFunctions() {
return currentWindow->swapGroupFrameNumber();
};
sgctDelegate.setScreenshotFolder = [](std::string path) {
Settings::instance().setCapturePath(std::move(path));
sgct::Settings::instance().setCapturePath(std::move(path));
};
sgctDelegate.showStatistics = [](bool enabled) {
Engine::instance().setStatsGraphVisibility(enabled);
@@ -1049,7 +1050,7 @@ void checkCommandLineForSettings(int& argc, char** argv, bool& hasSGCT, bool& ha
std::string setWindowConfigPresetForGui(const std::string labelFromCfgFile,
bool haveCliSGCTConfig)
{
configuration::Configuration& config = *global::configuration;
openspace::Configuration& config = *global::configuration;
std::string preset;
bool sgctConfigFileSpecifiedByLuaFunction = !config.sgctConfigNameInitialized.empty();
@@ -1225,7 +1226,7 @@ int main(int argc, char* argv[]) {
}
else {
LDEBUG("Finding configuration");
configurationFilePath = configuration::findConfiguration();
configurationFilePath = findConfiguration();
}
if (!std::filesystem::is_regular_file(configurationFilePath)) {
@@ -1259,8 +1260,9 @@ int main(int argc, char* argv[]) {
// Loading configuration from disk
LDEBUG("Loading configuration from disk");
*global::configuration = configuration::loadConfigurationFromFile(
*global::configuration = loadConfigurationFromFile(
configurationFilePath.string(),
findSettings(),
size
);
@@ -1413,7 +1415,7 @@ int main(int argc, char* argv[]) {
LDEBUG("Creating SGCT Engine");
std::vector<std::string> arg(argv + 1, argv + argc);
Configuration config = parseArguments(arg);
sgct::Configuration config = parseArguments(arg);
config::Cluster cluster = loadCluster(absPath(windowConfiguration).string());
Engine::Callbacks callbacks;
@@ -1479,6 +1481,27 @@ int main(int argc, char* argv[]) {
// Only timeout after 15 minutes
Engine::instance().setSyncParameters(false, 15.f * 60.f);
{
openspace::Settings settings = loadSettings();
settings.hasStartedBefore = true;
if (settings.rememberLastProfile) {
std::filesystem::path p = global::configuration->profile;
std::filesystem::path reducedName = p.filename().replace_extension();
settings.profile = reducedName.string();
}
if (settings.rememberLastConfiguration &&
!global::configuration->sgctConfigNameInitialized.empty())
{
// We only want to store the window configuration if it was not a dynamically
// created one
settings.configuration = global::configuration->windowConfiguration;
}
saveSettings(settings, findSettings());
}
LINFO("Starting rendering loop");
Engine::instance().exec();
LINFO("Ending rendering loop");

View File

@@ -34,9 +34,9 @@
#include <string>
#include <vector>
namespace openspace::documentation { struct Documentation; }
namespace openspace {
namespace openspace::configuration {
namespace documentation { struct Documentation; }
struct Configuration {
Configuration() = default;
@@ -147,9 +147,10 @@ struct Configuration {
std::filesystem::path findConfiguration(const std::string& filename = "openspace.cfg");
Configuration loadConfigurationFromFile(const std::filesystem::path& filename,
Configuration loadConfigurationFromFile(const std::filesystem::path& configurationFile,
const std::filesystem::path& settingsFile,
const glm::ivec2& primaryMonitorResolution);
} // namespace openspace::configuration
} // namespace openspace
#endif // __OPENSPACE_CORE___CONFIGURATION___H__

View File

@@ -33,6 +33,7 @@ namespace ghoul::fontrendering { class FontManager; }
namespace openspace {
struct Configuration;
class Dashboard;
class DeferredcasterManager;
class DownloadManager;
@@ -50,7 +51,6 @@ class SyncEngine;
class TimeManager;
class VersionChecker;
struct WindowDelegate;
namespace configuration { struct Configuration; }
namespace interaction {
struct JoystickInputStates;
struct WebsocketInputStates;
@@ -88,7 +88,7 @@ inline SyncEngine* syncEngine;
inline TimeManager* timeManager;
inline VersionChecker* versionChecker;
inline WindowDelegate* windowDelegate;
inline configuration::Configuration* configuration;
inline Configuration* configuration;
inline interaction::ActionManager* actionManager;
inline interaction::InteractionMonitor* interactionMonitor;
inline interaction::JoystickInputStates* joystickInputStates;

View File

@@ -0,0 +1,62 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___SETTINGS___H__
#define __OPENSPACE_CORE___SETTINGS___H__
#include <openspace/properties/property.h>
#include <filesystem>
#include <optional>
namespace openspace {
struct Settings {
auto operator<=>(const Settings&) const = default;
std::optional<bool> hasStartedBefore;
std::optional<std::string> configuration;
std::optional<bool> rememberLastConfiguration;
std::optional<std::string> profile;
std::optional<bool> rememberLastProfile;
std::optional<properties::Property::Visibility> visibility;
std::optional<bool> bypassLauncher;
struct MRF {
auto operator<=>(const MRF&) const = default;
std::optional<bool> isEnabled;
std::optional<std::string> location;
};
MRF mrf;
};
std::filesystem::path findSettings(const std::string& filename = "settings.json");
Settings loadSettings(const std::filesystem::path& filename = findSettings());
void saveSettings(const Settings& settings, const std::filesystem::path& filename);
} // namespace openspace
#endif // __OPENSPACE_CORE___SETTINGS___H__

View File

@@ -161,19 +161,11 @@ ModuleConfigurations = {
}
}
},
WebBrowser = {
Enabled = true
},
WebGui = {
Address = "localhost",
HttpPort = 4680,
WebSocketInterface = "DefaultWebSocketInterface"
},
CefWebGui = {
-- GuiScale = 2.0,
Enabled = true,
Visible = true
},
Space = {
ShowExceptions = false
}

View File

@@ -40,6 +40,7 @@ set(OPENSPACE_SOURCE
engine/moduleengine_lua.inl
engine/openspaceengine.cpp
engine/openspaceengine_lua.inl
engine/settings.cpp
engine/syncengine.cpp
events/event.cpp
events/eventengine.cpp
@@ -221,6 +222,7 @@ set(OPENSPACE_HEADER
${PROJECT_SOURCE_DIR}/include/openspace/engine/moduleengine.h
${PROJECT_SOURCE_DIR}/include/openspace/engine/moduleengine.inl
${PROJECT_SOURCE_DIR}/include/openspace/engine/openspaceengine.h
${PROJECT_SOURCE_DIR}/include/openspace/engine/settings.h
${PROJECT_SOURCE_DIR}/include/openspace/engine/syncengine.h
${PROJECT_SOURCE_DIR}/include/openspace/engine/windowdelegate.h
${PROJECT_SOURCE_DIR}/include/openspace/events/event.h

View File

@@ -25,12 +25,14 @@
#include <openspace/engine/configuration.h>
#include <openspace/documentation/documentation.h>
#include <openspace/engine/settings.h>
#include <ghoul/filesystem/file.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/lua/ghoul_lua.h>
#include <ghoul/lua/lua_helper.h>
#include <ghoul/misc/assert.h>
#include <json/json.hpp>
#include <optional>
namespace {
@@ -309,7 +311,7 @@ namespace {
#include "configuration_codegen.cpp"
} // namespace
namespace openspace::configuration {
namespace openspace {
void parseLuaState(Configuration& configuration) {
using namespace ghoul::lua;
@@ -456,6 +458,38 @@ void parseLuaState(Configuration& configuration) {
c.bypassLauncher = p.bypassLauncher.value_or(c.bypassLauncher);
}
void patchConfiguration(Configuration& configuration, const Settings& settings) {
if (settings.configuration.has_value()) {
configuration.windowConfiguration = *settings.configuration;
configuration.sgctConfigNameInitialized.clear();
}
if (settings.profile.has_value()) {
configuration.profile = *settings.profile;
}
if (settings.visibility.has_value()) {
configuration.propertyVisibility = *settings.visibility;
}
if (settings.bypassLauncher.has_value()) {
configuration.bypassLauncher = *settings.bypassLauncher;
}
auto it = configuration.moduleConfigurations.find("GlobeBrowsing");
// Just in case we have a configuration file that does not specify anything
// about the globebrowsing module
if (it == configuration.moduleConfigurations.end()) {
configuration.moduleConfigurations["GlobeBrowsing"] = ghoul::Dictionary();
}
if (settings.mrf.isEnabled.has_value()) {
configuration.moduleConfigurations["GlobeBrowsing"].setValue(
"MRFCacheEnabled", *settings.mrf.isEnabled
);
}
if (settings.mrf.location.has_value()) {
configuration.moduleConfigurations["GlobeBrowsing"].setValue(
"MRFCacheLocation", *settings.mrf.location
);
}
}
documentation::Documentation Configuration::Documentation =
codegen::doc<Parameters>("core_configuration");
@@ -483,10 +517,11 @@ std::filesystem::path findConfiguration(const std::string& filename) {
}
}
Configuration loadConfigurationFromFile(const std::filesystem::path& filename,
Configuration loadConfigurationFromFile(const std::filesystem::path& configurationFile,
const std::filesystem::path& settingsFile,
const glm::ivec2& primaryMonitorResolution)
{
ghoul_assert(std::filesystem::is_regular_file(filename), "File must exist");
ghoul_assert(std::filesystem::is_regular_file(configurationFile), "File must exist");
Configuration result;
@@ -503,11 +538,17 @@ Configuration loadConfigurationFromFile(const std::filesystem::path& filename,
}
// Load the configuration file into the state
ghoul::lua::runScriptFile(result.state, filename.string());
ghoul::lua::runScriptFile(result.state, configurationFile.string());
parseLuaState(result);
if (std::filesystem::is_regular_file(settingsFile)) {
Settings settings = loadSettings(settingsFile);
patchConfiguration(result, settings);
}
return result;
}
} // namespace openspace::configuration
} // namespace openspace

View File

@@ -89,7 +89,7 @@ namespace {
sizeof(TimeManager) +
sizeof(VersionChecker) +
sizeof(WindowDelegate) +
sizeof(configuration::Configuration) +
sizeof(Configuration) +
sizeof(interaction::ActionManager) +
sizeof(interaction::InteractionMonitor) +
sizeof(interaction::WebsocketInputStates) +
@@ -266,11 +266,11 @@ void create() {
#endif // WIN32
#ifdef WIN32
configuration = new (currentPos) configuration::Configuration;
configuration = new (currentPos) Configuration;
ghoul_assert(configuration, "No configuration");
currentPos += sizeof(configuration::Configuration);
currentPos += sizeof(Configuration);
#else // ^^^ WIN32 / !WIN32 vvv
configuration = new configuration::Configuration;
configuration = new Configuration;
#endif // WIN32
#ifdef WIN32

View File

@@ -321,7 +321,7 @@ void OpenSpaceEngine::initialize() {
DocEng.addDocumentation(doc);
}
}
DocEng.addDocumentation(configuration::Configuration::Documentation);
DocEng.addDocumentation(Configuration::Documentation);
// Register the provided shader directories
ghoul::opengl::ShaderPreprocessor::addIncludePath(absPath("${SHADERS}"));
@@ -519,7 +519,7 @@ void OpenSpaceEngine::initializeGL() {
bool synchronous = global::configuration->openGLDebugContext.isSynchronous;
setDebugOutput(DebugOutput(debugActive), SynchronousOutput(synchronous));
for (const configuration::Configuration::OpenGLDebugContext::IdentifierFilter& f :
for (const Configuration::OpenGLDebugContext::IdentifierFilter& f :
global::configuration->openGLDebugContext.identifierFilters)
{
setDebugMessageControl(

184
src/engine/settings.cpp Normal file
View File

@@ -0,0 +1,184 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/engine/settings.h>
#include <openspace/engine/configuration.h>
namespace openspace {
namespace {
template <typename T>
std::optional<T> get_to(nlohmann::json& obj, const std::string& key)
{
auto it = obj.find(key);
if (it != obj.end()) {
return it->get<T>();
}
else {
return std::nullopt;
}
}
} // namespace
namespace version1 {
Settings parseSettings(nlohmann::json json) {
ghoul_assert(json.at("version").get<int>() == 1, "Wrong value");
Settings settings;
settings.hasStartedBefore = get_to<bool>(json, "started-before");
settings.configuration = get_to<std::string>(json, "config");
settings.rememberLastConfiguration = get_to<bool>(json, "config-remember");
settings.profile = get_to<std::string>(json, "profile");
settings.rememberLastProfile = get_to<bool>(json, "profile-remember");
std::optional<std::string> visibility = get_to<std::string>(json, "visibility");
if (visibility.has_value()) {
if (*visibility == "NoviceUser") {
settings.visibility = properties::Property::Visibility::NoviceUser;
}
else if (*visibility == "User") {
settings.visibility = properties::Property::Visibility::User;
}
else if (*visibility == "AdvancedUser") {
settings.visibility = properties::Property::Visibility::AdvancedUser;
}
else if (*visibility == "Developer") {
settings.visibility = properties::Property::Visibility::Developer;
}
else {
throw ghoul::RuntimeError(fmt::format(
"Unknown visibility value {}", *visibility
));
}
}
settings.bypassLauncher = get_to<bool>(json, "bypass");
if (auto it = json.find("mrf"); it != json.end()) {
if (!it->is_object()) {
throw ghoul::RuntimeError("'mrf' is not an object");
}
Settings::MRF mrf;
mrf.isEnabled = get_to<bool>(*it, "enabled");
mrf.location = get_to<std::string>(*it, "location");
if (mrf.isEnabled.has_value() || mrf.location.has_value()) {
settings.mrf = mrf;
}
}
return settings;
}
} // namespace version1
std::filesystem::path findSettings(const std::string& filename) {
// Right now the settings file lives next to the openspace.cfg file
std::filesystem::path path = findConfiguration();
std::filesystem::path result = path.parent_path() / filename;
return result;
}
Settings loadSettings(const std::filesystem::path& filename) {
if (!std::filesystem::is_regular_file(filename)) {
return Settings();
}
std::ifstream f(filename);
std::stringstream buffer;
buffer << f.rdbuf();
std::string contents = buffer.str();
nlohmann::json setting = nlohmann::json::parse(contents);
if (setting.empty()) {
return Settings();
}
int version = setting.at("version").get<int>();
if (version == 1) {
return version1::parseSettings(setting);
}
throw ghoul::RuntimeError(fmt::format(
"Unrecognized version for setting: {}", version
));
}
void saveSettings(const Settings& settings, const std::filesystem::path& filename) {
nlohmann::json json = nlohmann::json::object();
json["version"] = 1;
if (settings.hasStartedBefore.has_value()) {
json["started-before"] = *settings.hasStartedBefore;
}
if (settings.configuration.has_value()) {
json["config"] = *settings.configuration;
}
if (settings.rememberLastConfiguration.has_value()) {
json["config-remember"] = *settings.rememberLastConfiguration;
}
if (settings.profile.has_value()) {
json["profile"] = *settings.profile;
}
if (settings.rememberLastProfile.has_value()) {
json["profile-remember"] = *settings.rememberLastProfile;
}
if (settings.visibility.has_value()) {
switch (*settings.visibility) {
case properties::Property::Visibility::NoviceUser:
json["visibility"] = "NoviceUser";
break;
case properties::Property::Visibility::User:
json["visibility"] = "User";
break;
case properties::Property::Visibility::AdvancedUser:
json["visibility"] = "AdvancedUser";
break;
case properties::Property::Visibility::Developer:
json["visibility"] = "Developer";
break;
}
}
if (settings.bypassLauncher.has_value()) {
json["bypass"] = *settings.bypassLauncher;
}
nlohmann::json mrf = nlohmann::json::object();
if (settings.mrf.isEnabled.has_value()) {
mrf["enabled"] = *settings.mrf.isEnabled;
}
if (settings.mrf.location.has_value()) {
mrf["location"] = *settings.mrf.location;
}
if (!mrf.empty()) {
json["mrf"] = mrf;
}
std::string content = json.dump(2);
std::ofstream f(filename);
f << content;
}
} // namespace openspace

View File

@@ -523,7 +523,7 @@ void RenderEngine::initializeGL() {
// initialized window
_horizFieldOfView = static_cast<float>(global::windowDelegate->getHorizFieldOfView());
configuration::Configuration::FontSizes fontSize = global::configuration->fontSize;
Configuration::FontSizes fontSize = global::configuration->fontSize;
{
ZoneScopedN("Fonts");
TracyGpuZone("Fonts");

View File

@@ -38,6 +38,7 @@ add_executable(
test_profile.cpp
test_rawvolumeio.cpp
test_scriptscheduler.cpp
test_settings.cpp
test_sgctedit.cpp
test_spicemanager.cpp
test_timeconversion.cpp

View File

@@ -58,13 +58,14 @@ int main(int argc, char** argv) {
ghoul::filesystem::FileSystem::Override::Yes
);
std::filesystem::path configFile = configuration::findConfiguration();
std::filesystem::path configFile = findConfiguration();
// Register the base path as the directory where 'filename' lives
std::filesystem::path base = configFile.parent_path();
FileSys.registerPathToken("${BASE}", base);
*global::configuration = configuration::loadConfigurationFromFile(
*global::configuration = loadConfigurationFromFile(
configFile.string(),
"",
glm::ivec2(0)
);
global::openSpaceEngine->registerPathTokens();

863
tests/test_settings.cpp Normal file
View File

@@ -0,0 +1,863 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_exception.hpp>
#include <catch2/matchers/catch_matchers_string.hpp>
#include <openspace/engine/settings.h>
#include <json/json.hpp>
#include <filesystem>
#include <fstream>
using namespace openspace;
TEST_CASE("Settings Load: Empty", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_empty.json";
{
std::ofstream f(file);
f << Source;
}
Settings settings = loadSettings(file);
CHECK(!settings.hasStartedBefore.has_value());
CHECK(!settings.configuration.has_value());
CHECK(!settings.rememberLastConfiguration.has_value());
CHECK(!settings.profile.has_value());
CHECK(!settings.rememberLastProfile.has_value());
CHECK(!settings.visibility.has_value());
CHECK(!settings.bypassLauncher.has_value());
CHECK(!settings.mrf.isEnabled.has_value());
CHECK(!settings.mrf.location.has_value());
}
TEST_CASE("Settings Load: Really Empty", "[settings]") {
constexpr std::string_view Source = R"(
{
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_really-empty.json";
{
std::ofstream f(file);
f << Source;
}
Settings settings = loadSettings(file);
CHECK(!settings.hasStartedBefore.has_value());
CHECK(!settings.configuration.has_value());
CHECK(!settings.rememberLastConfiguration.has_value());
CHECK(!settings.profile.has_value());
CHECK(!settings.rememberLastProfile.has_value());
CHECK(!settings.visibility.has_value());
CHECK(!settings.bypassLauncher.has_value());
CHECK(!settings.mrf.isEnabled.has_value());
CHECK(!settings.mrf.location.has_value());
}
TEST_CASE("Settings Save: Empty", "[settings]") {
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_save_empty.json";
Settings srcSettings;
saveSettings(srcSettings, file);
Settings cmpSettings = loadSettings(file);
CHECK(srcSettings == cmpSettings);
}
TEST_CASE("Settings Load: Started Before", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"started-before": false
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_started-before.json";
{
std::ofstream f(file);
f << Source;
}
Settings settings = loadSettings(file);
REQUIRE(settings.hasStartedBefore.has_value());
CHECK(*settings.hasStartedBefore == false);
CHECK(!settings.configuration.has_value());
CHECK(!settings.rememberLastConfiguration.has_value());
CHECK(!settings.profile.has_value());
CHECK(!settings.rememberLastProfile.has_value());
CHECK(!settings.visibility.has_value());
CHECK(!settings.bypassLauncher.has_value());
CHECK(!settings.mrf.isEnabled.has_value());
CHECK(!settings.mrf.location.has_value());
}
TEST_CASE("Settings Save: Started Before", "[settings]") {
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_save_started-before.json";
Settings srcSettings = {
.hasStartedBefore = false
};
saveSettings(srcSettings, file);
Settings cmpSettings = loadSettings(file);
CHECK(srcSettings == cmpSettings);
}
TEST_CASE("Settings Load: Configuration", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"config": "abc"
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_config.json";
{
std::ofstream f(file);
f << Source;
}
Settings settings = loadSettings(file);
CHECK(!settings.hasStartedBefore.has_value());
REQUIRE(settings.configuration.has_value());
CHECK(*settings.configuration == "abc");
CHECK(!settings.rememberLastConfiguration.has_value());
CHECK(!settings.profile.has_value());
CHECK(!settings.rememberLastProfile.has_value());
CHECK(!settings.visibility.has_value());
CHECK(!settings.bypassLauncher.has_value());
CHECK(!settings.mrf.isEnabled.has_value());
CHECK(!settings.mrf.location.has_value());
}
TEST_CASE("Settings Save: Configuration", "[settings]") {
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_save_config.json";
Settings srcSettings = {
.configuration = "abc"
};
saveSettings(srcSettings, file);
Settings cmpSettings = loadSettings(file);
CHECK(srcSettings == cmpSettings);
}
TEST_CASE("Settings Load: Configuration Remember", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"config-remember": true
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_config_remember.json";
{
std::ofstream f(file);
f << Source;
}
Settings settings = loadSettings(file);
CHECK(!settings.hasStartedBefore.has_value());
CHECK(!settings.configuration.has_value());
REQUIRE(settings.rememberLastConfiguration.has_value());
CHECK(*settings.rememberLastConfiguration == true);
CHECK(!settings.profile.has_value());
CHECK(!settings.rememberLastProfile.has_value());
CHECK(!settings.visibility.has_value());
CHECK(!settings.bypassLauncher.has_value());
CHECK(!settings.mrf.isEnabled.has_value());
CHECK(!settings.mrf.location.has_value());
}
TEST_CASE("Settings Save: Configuration Remember", "[settings]") {
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_save_config_remember.json";
Settings srcSettings = {
.rememberLastConfiguration = true
};
saveSettings(srcSettings, file);
Settings cmpSettings = loadSettings(file);
CHECK(srcSettings == cmpSettings);
}
TEST_CASE("Settings Load: Profile", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"profile": "def"
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_profile.json";
{
std::ofstream f(file);
f << Source;
}
Settings settings = loadSettings(file);
CHECK(!settings.hasStartedBefore.has_value());
CHECK(!settings.configuration.has_value());
CHECK(!settings.rememberLastConfiguration.has_value());
REQUIRE(settings.profile.has_value());
CHECK(*settings.profile == "def");
CHECK(!settings.rememberLastProfile.has_value());
CHECK(!settings.visibility.has_value());
CHECK(!settings.bypassLauncher.has_value());
CHECK(!settings.mrf.isEnabled.has_value());
CHECK(!settings.mrf.location.has_value());
}
TEST_CASE("Settings Save: Profile", "[settings]") {
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_save_profile.json";
Settings srcSettings = {
.profile = "def"
};
saveSettings(srcSettings, file);
Settings cmpSettings = loadSettings(file);
CHECK(srcSettings == cmpSettings);
}
TEST_CASE("Settings Load: Profile Remember", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"profile-remember": false
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_profile_remember.json";
{
std::ofstream f(file);
f << Source;
}
Settings settings = loadSettings(file);
CHECK(!settings.hasStartedBefore.has_value());
CHECK(!settings.configuration.has_value());
CHECK(!settings.rememberLastConfiguration.has_value());
CHECK(!settings.profile.has_value());
REQUIRE(settings.rememberLastProfile.has_value());
CHECK(*settings.rememberLastProfile == false);
CHECK(!settings.visibility.has_value());
CHECK(!settings.bypassLauncher.has_value());
CHECK(!settings.mrf.isEnabled.has_value());
CHECK(!settings.mrf.location.has_value());
}
TEST_CASE("Settings Save: Profile Remember", "[settings]") {
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_save_profile.json";
Settings srcSettings = {
.rememberLastProfile = false
};
saveSettings(srcSettings, file);
Settings cmpSettings = loadSettings(file);
CHECK(srcSettings == cmpSettings);
}
TEST_CASE("Settings Load: Visibility/NoviceUser", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"visibility": "NoviceUser"
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_visibility_novice.json";
{
std::ofstream f(file);
f << Source;
}
Settings settings = loadSettings(file);
CHECK(!settings.hasStartedBefore.has_value());
CHECK(!settings.configuration.has_value());
CHECK(!settings.rememberLastConfiguration.has_value());
CHECK(!settings.profile.has_value());
CHECK(!settings.rememberLastProfile.has_value());
REQUIRE(settings.visibility.has_value());
CHECK(*settings.visibility == properties::Property::Visibility::NoviceUser);
CHECK(!settings.bypassLauncher.has_value());
CHECK(!settings.mrf.isEnabled.has_value());
CHECK(!settings.mrf.location.has_value());
}
TEST_CASE("Settings Save: Visibility/NoviceUser", "[settings]") {
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_save_noviceuser.json";
Settings srcSettings = {
.visibility = openspace::properties::Property::Visibility::NoviceUser
};
saveSettings(srcSettings, file);
Settings cmpSettings = loadSettings(file);
CHECK(srcSettings == cmpSettings);
}
TEST_CASE("Settings Load: Visibility/User", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"visibility": "User"
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_visibility_user.json";
{
std::ofstream f(file);
f << Source;
}
Settings settings = loadSettings(file);
CHECK(!settings.hasStartedBefore.has_value());
CHECK(!settings.configuration.has_value());
CHECK(!settings.rememberLastConfiguration.has_value());
CHECK(!settings.profile.has_value());
CHECK(!settings.rememberLastProfile.has_value());
REQUIRE(settings.visibility.has_value());
CHECK(*settings.visibility == properties::Property::Visibility::User);
CHECK(!settings.bypassLauncher.has_value());
CHECK(!settings.mrf.isEnabled.has_value());
CHECK(!settings.mrf.location.has_value());
}
TEST_CASE("Settings Save: Visibility/User", "[settings]") {
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_save_user.json";
Settings srcSettings = {
.visibility = openspace::properties::Property::Visibility::User
};
saveSettings(srcSettings, file);
Settings cmpSettings = loadSettings(file);
CHECK(srcSettings == cmpSettings);
}
TEST_CASE("Settings Load: Visibility/AdvancedUser", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"visibility": "AdvancedUser"
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_visibility_advanced.json";
{
std::ofstream f(file);
f << Source;
}
Settings settings = loadSettings(file);
CHECK(!settings.hasStartedBefore.has_value());
CHECK(!settings.configuration.has_value());
CHECK(!settings.rememberLastConfiguration.has_value());
CHECK(!settings.profile.has_value());
CHECK(!settings.rememberLastProfile.has_value());
REQUIRE(settings.visibility.has_value());
CHECK(*settings.visibility == properties::Property::Visibility::AdvancedUser);
CHECK(!settings.bypassLauncher.has_value());
CHECK(!settings.mrf.isEnabled.has_value());
CHECK(!settings.mrf.location.has_value());
}
TEST_CASE("Settings Save: Visibility/AdvancedUser", "[settings]") {
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_save_advanceduser.json";
Settings srcSettings = {
.visibility = openspace::properties::Property::Visibility::AdvancedUser
};
saveSettings(srcSettings, file);
Settings cmpSettings = loadSettings(file);
CHECK(srcSettings == cmpSettings);
}
TEST_CASE("Settings Load: Visibility/Developer", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"visibility": "Developer"
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_visibility_developer.json";
{
std::ofstream f(file);
f << Source;
}
Settings settings = loadSettings(file);
CHECK(!settings.hasStartedBefore.has_value());
CHECK(!settings.configuration.has_value());
CHECK(!settings.rememberLastConfiguration.has_value());
CHECK(!settings.profile.has_value());
CHECK(!settings.rememberLastProfile.has_value());
REQUIRE(settings.visibility.has_value());
CHECK(*settings.visibility == properties::Property::Visibility::Developer);
CHECK(!settings.bypassLauncher.has_value());
CHECK(!settings.mrf.isEnabled.has_value());
CHECK(!settings.mrf.location.has_value());
}
TEST_CASE("Settings Save: Visibility/Developer", "[settings]") {
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_save_developer.json";
Settings srcSettings = {
.visibility = openspace::properties::Property::Visibility::Developer
};
saveSettings(srcSettings, file);
Settings cmpSettings = loadSettings(file);
CHECK(srcSettings == cmpSettings);
}
TEST_CASE("Settings Load: Bypass Launcher", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"bypass": false
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_bypass.json";
{
std::ofstream f(file);
f << Source;
}
Settings settings = loadSettings(file);
CHECK(!settings.hasStartedBefore.has_value());
CHECK(!settings.configuration.has_value());
CHECK(!settings.rememberLastConfiguration.has_value());
CHECK(!settings.profile.has_value());
CHECK(!settings.rememberLastProfile.has_value());
CHECK(!settings.visibility.has_value());
REQUIRE(settings.bypassLauncher.has_value());
CHECK(*settings.bypassLauncher == false);
CHECK(!settings.mrf.isEnabled.has_value());
CHECK(!settings.mrf.location.has_value());
}
TEST_CASE("Settings Save: Bypass Launcher", "[settings]") {
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_save_bypass.json";
Settings srcSettings = {
.bypassLauncher = false
};
saveSettings(srcSettings, file);
Settings cmpSettings = loadSettings(file);
CHECK(srcSettings == cmpSettings);
}
TEST_CASE("Settings Load: MRF IsEnabled", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"mrf": {
"enabled": true
}
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_mrf_isenabled.json";
{
std::ofstream f(file);
f << Source;
}
Settings settings = loadSettings(file);
CHECK(!settings.hasStartedBefore.has_value());
CHECK(!settings.configuration.has_value());
CHECK(!settings.rememberLastConfiguration.has_value());
CHECK(!settings.profile.has_value());
CHECK(!settings.rememberLastProfile.has_value());
CHECK(!settings.visibility.has_value());
CHECK(!settings.bypassLauncher.has_value());
REQUIRE(settings.mrf.isEnabled.has_value());
CHECK(*settings.mrf.isEnabled == true);
CHECK(!settings.mrf.location.has_value());
}
TEST_CASE("Settings Save: MRF IsEnabled", "[settings]") {
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_save_mrf_isenabled.json";
Settings srcSettings = {
.mrf = Settings::MRF {
.isEnabled = true
}
};
saveSettings(srcSettings, file);
Settings cmpSettings = loadSettings(file);
CHECK(srcSettings == cmpSettings);
}
TEST_CASE("Settings Load: MRF Location", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"mrf": {
"location": "ghi"
}
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_mrf_location.json";
{
std::ofstream f(file);
f << Source;
}
Settings settings = loadSettings(file);
CHECK(!settings.hasStartedBefore.has_value());
CHECK(!settings.configuration.has_value());
CHECK(!settings.rememberLastConfiguration.has_value());
CHECK(!settings.profile.has_value());
CHECK(!settings.rememberLastProfile.has_value());
CHECK(!settings.visibility.has_value());
CHECK(!settings.bypassLauncher.has_value());
CHECK(!settings.mrf.isEnabled.has_value());
REQUIRE(settings.mrf.location.has_value());
CHECK(*settings.mrf.location == "ghi");
}
TEST_CASE("Settings Save: MRF Location", "[settings]") {
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_save_mrf_location.json";
Settings srcSettings = {
.mrf = Settings::MRF {
.location = "ghi"
}
};
saveSettings(srcSettings, file);
Settings cmpSettings = loadSettings(file);
CHECK(srcSettings == cmpSettings);
}
TEST_CASE("Settings Load: Full", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"started-before": false,
"config": "abc",
"config-remember": true,
"profile": "def",
"profile-remember": false,
"visibility": "NoviceUser",
"bypass": false,
"mrf": {
"enabled": true,
"location": "ghi"
}
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_full.json";
{
std::ofstream f(file);
f << Source;
}
Settings settings = loadSettings(file);
REQUIRE(settings.hasStartedBefore.has_value());
CHECK(*settings.hasStartedBefore == false);
REQUIRE(settings.configuration.has_value());
CHECK(*settings.configuration == "abc");
REQUIRE(settings.rememberLastConfiguration.has_value());
CHECK(*settings.rememberLastConfiguration == true);
REQUIRE(settings.profile.has_value());
CHECK(*settings.profile == "def");
REQUIRE(settings.rememberLastProfile.has_value());
CHECK(*settings.rememberLastProfile == false);
REQUIRE(settings.visibility.has_value());
CHECK(*settings.visibility == properties::Property::Visibility::NoviceUser);
REQUIRE(settings.bypassLauncher.has_value());
CHECK(*settings.bypassLauncher == false);
REQUIRE(settings.mrf.isEnabled.has_value());
CHECK(*settings.mrf.isEnabled == true);
REQUIRE(settings.mrf.location.has_value());
CHECK(*settings.mrf.location == "ghi");
}
TEST_CASE("Settings Save: Full", "[settings]") {
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_save_full.json";
Settings srcSettings = {
.hasStartedBefore = false,
.configuration = "abc",
.rememberLastConfiguration = true,
.profile = "def",
.rememberLastProfile = false,
.visibility = openspace::properties::Property::Visibility::NoviceUser,
.bypassLauncher = false,
.mrf = Settings::MRF {
.isEnabled = true,
.location = "ghi"
}
};
saveSettings(srcSettings, file);
Settings cmpSettings = loadSettings(file);
CHECK(srcSettings == cmpSettings);
}
TEST_CASE("Settings Load Fail: Illegal version", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": -1
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_fail_illegal_version.json";
{
std::ofstream f(file);
f << Source;
}
CHECK_THROWS(loadSettings(file));
}
TEST_CASE("Settings Load Fail: Started before", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"started-before": "abc"
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_fail_started-before.json";
{
std::ofstream f(file);
f << Source;
}
CHECK_THROWS(loadSettings(file));
}
TEST_CASE("Settings Load Fail: Config", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"config": 1
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_fail_config.json";
{
std::ofstream f(file);
f << Source;
}
CHECK_THROWS(loadSettings(file));
}
TEST_CASE("Settings Load Fail: Profile", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"profile": 1
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_fail_profile.json";
{
std::ofstream f(file);
f << Source;
}
CHECK_THROWS(loadSettings(file));
}
TEST_CASE("Settings Load Fail: Visibility type", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"visibility": 1
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_fail_visibility_type.json";
{
std::ofstream f(file);
f << Source;
}
CHECK_THROWS(loadSettings(file));
}
TEST_CASE("Settings Load Fail: Visibility value", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"visibility": "abc"
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_fail_visibility_value.json";
{
std::ofstream f(file);
f << Source;
}
CHECK_THROWS(loadSettings(file));
}
TEST_CASE("Settings Load Fail: Bypass Launcher", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"bypass": 1
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_fail_bypass.json";
{
std::ofstream f(file);
f << Source;
}
CHECK_THROWS(loadSettings(file));
}
TEST_CASE("Settings Load Fail: MRF", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"mrf": 1
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_fail_mrf.json";
{
std::ofstream f(file);
f << Source;
}
CHECK_THROWS(loadSettings(file));
}
TEST_CASE("Settings Load Fail: MRF/enabled", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"mrf": {
"enabled": 1
}
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_fail_mrf_enabled.json";
{
std::ofstream f(file);
f << Source;
}
CHECK_THROWS(loadSettings(file));
}
TEST_CASE("Settings Load Fail: MRF/location", "[settings]") {
constexpr std::string_view Source = R"(
{
"version": 1,
"mrf": {
"location": 1
}
}
)";
std::filesystem::path path = std::filesystem::temp_directory_path();
std::filesystem::path file = path / "test_settings_load_fail_mrf_location.json";
{
std::ofstream f(file);
f << Source;
}
CHECK_THROWS(loadSettings(file));
}

View File

@@ -34,7 +34,7 @@
#include <filesystem>
#include <fstream>
using namespace openspace::configuration;
using namespace openspace;
namespace {
std::string stringify(const std::string filename) {