Merge branch 'reimplement-app-settings' into dev

This commit is contained in:
Oliver Hamlet
2016-01-12 11:49:34 +00:00
16 changed files with 987 additions and 431 deletions
+8 -3
View File
@@ -132,6 +132,7 @@ set (LOOT_GUI_SRC ${LOOT_SRC}
"${CMAKE_SOURCE_DIR}/src/gui/handler.cpp"
"${CMAKE_SOURCE_DIR}/src/gui/loot_handler.cpp"
"${CMAKE_SOURCE_DIR}/src/gui/loot_app.cpp"
"${CMAKE_SOURCE_DIR}/src/gui/loot_settings.cpp"
"${CMAKE_SOURCE_DIR}/src/gui/loot_state.cpp"
"${CMAKE_SOURCE_DIR}/src/gui/scheme.cpp"
"${CMAKE_SOURCE_DIR}/src/resource.rc")
@@ -143,6 +144,7 @@ set (LOOT_GUI_HEADERS ${LOOT_HEADERS}
"${CMAKE_SOURCE_DIR}/src/gui/handler.h"
"${CMAKE_SOURCE_DIR}/src/gui/loot_handler.h"
"${CMAKE_SOURCE_DIR}/src/gui/loot_app.h"
"${CMAKE_SOURCE_DIR}/src/gui/loot_settings.h"
"${CMAKE_SOURCE_DIR}/src/gui/loot_state.h"
"${CMAKE_SOURCE_DIR}/src/gui/scheme.h"
"${CMAKE_SOURCE_DIR}/src/gui/resource.h")
@@ -160,7 +162,9 @@ set (LOOT_VALIDATOR_SRC ${LOOT_SRC}
set (LOOT_VALIDATOR_HEADERS ${LOOT_HEADERS})
set (LOOT_TESTS_SRC "${CMAKE_SOURCE_DIR}/src/api/loot_db.cpp"
set (LOOT_TESTS_SRC ${LOOT_SRC}
"${CMAKE_SOURCE_DIR}/src/api/loot_db.cpp"
"${CMAKE_SOURCE_DIR}/src/gui/loot_settings.cpp"
"${CMAKE_SOURCE_DIR}/src/tests/main.cpp")
set (LOOT_TESTS_HEADERS "${CMAKE_SOURCE_DIR}/src/tests/fixtures.h"
@@ -188,7 +192,8 @@ set (LOOT_TESTS_HEADERS "${CMAKE_SOURCE_DIR}/src/tests/fixtures.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/plugin/test_plugin.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/test_metadata_list.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/test_masterlist.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/test_plugin_sorter.h")
"${CMAKE_SOURCE_DIR}/src/tests/backend/test_plugin_sorter.h"
"${CMAKE_SOURCE_DIR}/src/tests/gui/test_loot_settings.h")
source_group("Header Files" FILES ${LOOT_HEADERS} ${LOOT_GUI_HEADERS} ${LOOT_API_HEADERS} ${LOOT_TESTS_HEADERS})
@@ -309,7 +314,7 @@ target_link_libraries (loot${PROJECT_ARCH} ${Boost_LIBRARIES} ${YAML_CPP_LIBRARI
IF (${GTEST_FOUND})
# Build tests.
add_executable(tests ${LOOT_TESTS_SRC} ${LOOT_SRC} ${LOOT_TESTS_HEADERS})
add_executable(tests ${LOOT_TESTS_SRC} ${LOOT_TESTS_HEADERS})
target_link_libraries(tests loot${PROJECT_ARCH} ${Boost_LIBRARIES} ${YAML_CPP_LIBRARIES} ${LOOT_LIBS} ${GTEST_BOTH_LIBRARIES})
ENDIF ()
-8
View File
@@ -191,12 +191,4 @@ namespace loot {
return LoadOrderHandler::IsPluginActive(pluginName);
}
}
std::list<Game> ToGames(const std::list<GameSettings>& settings) {
return list<Game>(settings.begin(), settings.end());
}
std::list<GameSettings> ToGameSettings(const std::list<Game>& games) {
return list<GameSettings>(games.begin(), games.end());
}
}
-3
View File
@@ -54,9 +54,6 @@ namespace loot {
private:
bool _pluginsFullyLoaded;
};
std::list<Game> ToGames(const std::list<GameSettings>& settings);
std::list<GameSettings> ToGameSettings(const std::list<Game>& games);
}
#endif
-27
View File
@@ -226,33 +226,6 @@ namespace loot {
_gamePath = path;
return *this;
}
std::list<GameSettings> GetGameSettings(YAML::Node& settings) {
list<GameSettings> games;
if (settings["games"])
games = settings["games"].as< list<GameSettings> >();
if (find(games.begin(), games.end(), GameSettings(GameSettings::tes4)) == games.end())
games.push_back(GameSettings(GameSettings::tes4));
if (find(games.begin(), games.end(), GameSettings(GameSettings::tes5)) == games.end())
games.push_back(GameSettings(GameSettings::tes5));
if (find(games.begin(), games.end(), GameSettings(GameSettings::fo3)) == games.end())
games.push_back(GameSettings(GameSettings::fo3));
if (find(games.begin(), games.end(), GameSettings(GameSettings::fonv)) == games.end())
games.push_back(GameSettings(GameSettings::fonv));
if (find(games.begin(), games.end(), GameSettings(GameSettings::fo4)) == games.end())
games.push_back(GameSettings(GameSettings::fo4));
// If there were any missing defaults, make sure they're in settings now.
settings["games"] = games;
return games;
}
}
namespace YAML {
-2
View File
@@ -85,8 +85,6 @@ namespace loot {
boost::filesystem::path _gamePath; //Path to the game's folder.
};
std::list<GameSettings> GetGameSettings(YAML::Node& settings);
}
namespace YAML {
+20 -53
View File
@@ -160,12 +160,12 @@ namespace loot {
return true;
}
else if (request == "cancelSort") {
--_lootState.numUnappliedChanges;
_lootState.decrementUnappliedChangeCounter();
callback->Success("");
return true;
}
else if (request == "editorOpened") {
++_lootState.numUnappliedChanges;
_lootState.incrementUnappliedChangeCounter();
callback->Success("");
return true;
}
@@ -173,7 +173,7 @@ namespace loot {
// This version of the editorClosed query has no arguments as it is
// sent when editing is cancelled. Just update the unapplied changes
// counter.
--_lootState.numUnappliedChanges;
_lootState.decrementUnappliedChangeCounter();
callback->Success("");
return true;
}
@@ -253,7 +253,7 @@ namespace loot {
// One argument, which is the plugin metadata that has changed (+ its name).
try {
callback->Success(ApplyUserEdits(request["args"][0]));
--_lootState.numUnappliedChanges;
_lootState.decrementUnappliedChangeCounter();
}
catch (loot::error &e) {
BOOST_LOG_TRIVIAL(error) << "Failed to apply plugin metadata. Details: " << e.what();
@@ -275,20 +275,16 @@ namespace loot {
else if (requestName == "closeSettings") {
BOOST_LOG_TRIVIAL(trace) << "Settings dialog closed and changes accepted, updating settings object.";
// Update the game details and settings.
_lootState.UpdateSettings(request["args"][0]);
// Update the settings.
_lootState.load(request["args"][0]);
// If the user has deleted a default game, we don't want to restore it now.
// It will be restored when LOOT is next loaded.
try {
BOOST_LOG_TRIVIAL(trace) << "Updating games object.";
list<GameSettings> games(request["args"][0]["games"].as< list<GameSettings> >());
_lootState.UpdateGames(games);
_lootState.UpdateGamesFromSettings();
// Also enable/disable debug logging as required.
if (request["args"][0]["enableDebugLogging"] && request["args"][0]["enableDebugLogging"].as<bool>())
boost::log::core::get()->set_logging_enabled(true);
else
boost::log::core::get()->set_logging_enabled(false);
boost::log::core::get()->set_logging_enabled(_lootState.isDebugLoggingEnabled());
// Now send back the new list of installed games to the UI.
BOOST_LOG_TRIVIAL(trace) << "Getting new list of installed games.";
@@ -301,7 +297,7 @@ namespace loot {
return true;
}
else if (requestName == "applySort") {
--_lootState.numUnappliedChanges;
_lootState.decrementUnappliedChangeCounter();
BOOST_LOG_TRIVIAL(trace) << "User has accepted sorted load order, applying it.";
try {
_lootState.CurrentGame().SetLoadOrder(request["args"][0].as<list<string>>());
@@ -381,11 +377,7 @@ namespace loot {
// Has two args: the first is the filter ID, the second is the value.
BOOST_LOG_TRIVIAL(trace) << "Saving filter states.";
try {
YAML::Node settings = _lootState.GetSettings();
settings["filters"][request["args"][0].as<string>()] = request["args"][1];
_lootState.UpdateSettings(settings);
_lootState.storeFilterState(request["args"][0].as<string>(), request["args"][1].as<bool>());
callback->Success("");
}
catch (exception &e) {
@@ -581,7 +573,7 @@ namespace loot {
std::string Handler::GetSettings() {
BOOST_LOG_TRIVIAL(info) << "Getting LOOT settings.";
return JSON::stringify(_lootState.GetSettings());
return JSON::stringify(_lootState.toYaml());
}
std::string Handler::GetLanguages() {
@@ -779,13 +771,7 @@ namespace loot {
}
SendProgressUpdate(frame, loc::translate("Loading general messages..."));
//Set language.
unsigned int language;
if (_lootState.GetSettings()["language"])
language = Language(_lootState.GetSettings()["language"].as<string>()).Code();
else
language = Language::any;
BOOST_LOG_TRIVIAL(info) << "Using message language: " << Language(language).Name();
BOOST_LOG_TRIVIAL(info) << "Using message language: " << _lootState.getLanguage().Name();
//Evaluate any conditions in the global messages.
BOOST_LOG_TRIVIAL(debug) << "Evaluating global message conditions.";
@@ -801,7 +787,7 @@ namespace loot {
try {
list<Message>::iterator it = messages.begin();
while (it != messages.end()) {
if (!it->EvalCondition(_lootState.CurrentGame(), language))
if (!it->EvalCondition(_lootState.CurrentGame(), _lootState.getLanguage().Code()))
it = messages.erase(it);
else
++it;
@@ -830,14 +816,7 @@ namespace loot {
void Handler::UpdateMasterlist(CefRefPtr<CefFrame> frame, CefRefPtr<Callback> callback) {
try {
BOOST_LOG_TRIVIAL(debug) << "Updating and parsing masterlist.";
//Set language.
unsigned int language;
if (_lootState.GetSettings()["language"])
language = Language(_lootState.GetSettings()["language"].as<string>()).Code();
else
language = Language::any;
BOOST_LOG_TRIVIAL(info) << "Using message language: " << Language(language).Name();
BOOST_LOG_TRIVIAL(info) << "Using message language: " << _lootState.getLanguage().Name();
// Update / parse masterlist.
bool wasChanged = true;
@@ -914,7 +893,7 @@ namespace loot {
try {
list<Message>::iterator it = messages.begin();
while (it != messages.end()) {
if (!it->EvalCondition(_lootState.CurrentGame(), language))
if (!it->EvalCondition(_lootState.CurrentGame(), _lootState.getLanguage().Code()))
it = messages.erase(it);
else
++it;
@@ -974,13 +953,7 @@ namespace loot {
void Handler::SortPlugins(CefRefPtr<CefFrame> frame, CefRefPtr<Callback> callback) {
BOOST_LOG_TRIVIAL(info) << "Beginning sorting operation.";
//Set language.
unsigned int language;
if (_lootState.GetSettings()["language"])
language = Language(_lootState.GetSettings()["language"].as<string>()).Code();
else
language = Language::any;
BOOST_LOG_TRIVIAL(info) << "Using message language: " << Language(language).Name();
BOOST_LOG_TRIVIAL(info) << "Using message language: " << _lootState.getLanguage().Name();
try {
// Always reload all the plugins.
@@ -989,7 +962,7 @@ namespace loot {
//Sort plugins into their load order.
PluginSorter sorter;
list<Plugin> plugins = sorter.Sort(_lootState.CurrentGame(), language, [this, frame](const string& message) {
list<Plugin> plugins = sorter.Sort(_lootState.CurrentGame(), _lootState.getLanguage().Code(), [this, frame](const string& message) {
this->SendProgressUpdate(frame, message);
});
@@ -1010,7 +983,7 @@ namespace loot {
node.push_back(pluginNode);
}
++_lootState.numUnappliedChanges;
_lootState.incrementUnappliedChangeCounter();
if (node.size() > 0)
callback->Success(JSON::stringify(node));
@@ -1024,13 +997,7 @@ namespace loot {
}
YAML::Node Handler::GenerateDerivedMetadata(const Plugin& file, const PluginMetadata& masterlist, const PluginMetadata& userlist) {
//Set language.
unsigned int language;
if (_lootState.GetSettings()["language"])
language = Language(_lootState.GetSettings()["language"].as<string>()).Code();
else
language = Language::any;
BOOST_LOG_TRIVIAL(info) << "Using message language: " << Language(language).Name();
BOOST_LOG_TRIVIAL(info) << "Using message language: " << _lootState.getLanguage().Name();
// Now rederive the displayed metadata from the masterlist and userlist.
Plugin tempPlugin(file);
@@ -1041,7 +1008,7 @@ namespace loot {
//Evaluate any conditions
BOOST_LOG_TRIVIAL(trace) << "Evaluate conditions for merged plugin data.";
try {
tempPlugin.EvalAllConditions(_lootState.CurrentGame(), language);
tempPlugin.EvalAllConditions(_lootState.CurrentGame(), _lootState.getLanguage().Code());
}
catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "\"" << tempPlugin.Name() << "\" contains a condition that could not be evaluated. Details: " << e.what();
+3 -5
View File
@@ -96,15 +96,13 @@ namespace loot {
// Need to set the global locale for this process so that messages will
// be translated.
BOOST_LOG_TRIVIAL(debug) << "Initialising language settings in UI thread.";
const YAML::Node& settings = lootState.GetSettings();
if (settings["language"] && settings["language"].as<string>() != Language(Language::english).Locale()) {
if (lootState.getLanguage().Code() != Language::english) {
boost::locale::generator gen;
gen.add_messages_path(g_path_l10n.string());
gen.add_messages_domain("loot");
loot::Language lang(settings["language"].as<string>());
BOOST_LOG_TRIVIAL(debug) << "Selected language: " << lang.Name();
locale::global(gen(lang.Locale() + ".UTF-8"));
BOOST_LOG_TRIVIAL(debug) << "Selected language: " << lootState.getLanguage().Name();
locale::global(gen(lootState.getLanguage().Locale() + ".UTF-8"));
boost::filesystem::path::imbue(locale());
}
+18 -17
View File
@@ -97,15 +97,13 @@ namespace loot {
#endif
// Set window size & position.
YAML::Node settings = _lootState.GetSettings();
if (settings["window"]["left"] && settings["window"]["top"] && settings["window"]["right"] && settings["window"]["bottom"]) {
if (_lootState.isWindowPositionStored()) {
#ifdef _WIN32
RECT rc;
rc.left = settings["window"]["left"].as<long>();
rc.top = settings["window"]["top"].as<long>();
rc.right = settings["window"]["right"].as<long>();
rc.bottom = settings["window"]["bottom"].as<long>();
rc.left = _lootState.getWindowPosition().left;
rc.top = _lootState.getWindowPosition().top;
rc.right = _lootState.getWindowPosition().right;
rc.bottom = _lootState.getWindowPosition().bottom;
// Fit the saved window size/position to the current monitor setup.
@@ -154,7 +152,7 @@ namespace loot {
assert(CefCurrentlyOn(TID_UI));
// Check if unapplied changes exist.
if (_lootState.numUnappliedChanges > 0) {
if (_lootState.hasUnappliedChanges()) {
browser->GetMainFrame()->ExecuteJavaScript("onQuit();", browser->GetMainFrame()->GetURL(), 0);
return true;
}
@@ -175,21 +173,24 @@ namespace loot {
void LootHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
assert(CefCurrentlyOn(TID_UI));
// Save window size & position.
YAML::Node settings = _lootState.GetSettings();
#ifdef _WIN32
RECT rc;
GetWindowRect(browser->GetHost()->GetWindowHandle(), &rc);
settings["window"]["left"] = rc.left;
settings["window"]["top"] = rc.top;
settings["window"]["right"] = rc.right;
settings["window"]["bottom"] = rc.bottom;
LootSettings::WindowPosition position;
position.top = rc.top;
position.bottom = rc.bottom;
position.left = rc.left;
position.right = rc.right;
_lootState.storeWindowPosition(position);
#endif
_lootState.UpdateSettings(settings);
_lootState.SaveSettings();
try {
_lootState.save(g_path_settings);
}
catch (std::exception &e) {
BOOST_LOG_TRIVIAL(error) << "Failed to save LOOT's settings. Error: " << e.what();
}
// Cancel any javascript callbacks.
browser_side_router_->OnBeforeClose(browser);
+295
View File
@@ -0,0 +1,295 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2014-2015 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<http://www.gnu.org/licenses/>.
*/
#include "loot_settings.h"
#include "backend/globals.h"
#include <thread>
#include <boost/filesystem/fstream.hpp>
using namespace std;
namespace loot {
LootSettings::WindowPosition::WindowPosition() : top(0), bottom(0), left(0), right(0) {}
LootSettings::LootSettings() :
gameSettings({
GameSettings(GameSettings::tes4),
GameSettings(GameSettings::tes5),
GameSettings(GameSettings::fo3),
GameSettings(GameSettings::fonv),
GameSettings(GameSettings::fo4),
GameSettings(GameSettings::tes4, "Nehrim")
.SetName("Nehrim - At Fate's Edge")
.SetMaster("Nehrim.esm")
.SetRegistryKey("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Nehrim - At Fate's Edge_is1\\InstallLocation"),
}),
enableDebugLogging(false),
updateMasterlist(true),
game("auto"),
language(Language(Language::english)),
lastGame("auto"),
lastVersion(std::to_string(g_version_major) + "." + std::to_string(g_version_minor) + "." + std::to_string(g_version_patch)) {}
void LootSettings::load(YAML::Node& settings) {
std::lock_guard<std::recursive_mutex> guard(mutex);
upgradeYaml(settings);
if (settings["enableDebugLogging"])
enableDebugLogging = settings["enableDebugLogging"].as<bool>();
if (settings["updateMasterlist"])
updateMasterlist = settings["updateMasterlist"].as<bool>();
if (settings["game"])
game = settings["game"].as<string>();
if (settings["language"])
language = Language(settings["language"].as<string>());
if (settings["lastGame"])
lastGame = settings["lastGame"].as<string>();
if (settings["lastVersion"])
lastVersion = settings["lastVersion"].as<string>();
if (settings["window"]
&& settings["window"]["top"] && settings["window"]["bottom"]
&& settings["window"]["left"] && settings["window"]["right"]) {
windowPosition.top = settings["window"]["top"].as<long>();
windowPosition.bottom = settings["window"]["bottom"].as<long>();
windowPosition.left = settings["window"]["left"].as<long>();
windowPosition.right = settings["window"]["right"].as<long>();
}
if (settings["games"]) {
gameSettings = settings["games"].as<vector<GameSettings>>();
// If a base game isn't in the settings, add it.
if (find(begin(gameSettings), end(gameSettings), GameSettings(GameSettings::tes4)) == end(gameSettings))
gameSettings.push_back(GameSettings(GameSettings::tes4));
if (find(begin(gameSettings), end(gameSettings), GameSettings(GameSettings::tes5)) == end(gameSettings))
gameSettings.push_back(GameSettings(GameSettings::tes5));
if (find(begin(gameSettings), end(gameSettings), GameSettings(GameSettings::fo3)) == end(gameSettings))
gameSettings.push_back(GameSettings(GameSettings::fo3));
if (find(begin(gameSettings), end(gameSettings), GameSettings(GameSettings::fonv)) == end(gameSettings))
gameSettings.push_back(GameSettings(GameSettings::fonv));
if (find(begin(gameSettings), end(gameSettings), GameSettings(GameSettings::fo4)) == end(gameSettings))
gameSettings.push_back(GameSettings(GameSettings::fo4));
}
if (settings["filters"])
filters = settings["filters"].as<map<string, bool>>();
}
void LootSettings::load(const boost::filesystem::path& file) {
boost::filesystem::ifstream in(file);
YAML::Node content = YAML::Load(in);
load(content);
}
void LootSettings::save(const boost::filesystem::path& file) {
std::lock_guard<std::recursive_mutex> guard(mutex);
YAML::Emitter yout;
yout.SetIndent(2);
yout << toYaml();
boost::filesystem::ofstream out(file);
out << yout.c_str();
}
bool LootSettings::isDebugLoggingEnabled() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
return enableDebugLogging;
}
bool LootSettings::isWindowPositionStored() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
return windowPosition.top != 0 || windowPosition.bottom != 0 || windowPosition.left != 0 || windowPosition.right != 0;
}
std::string LootSettings::getGame() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
return game;
}
std::string LootSettings::getLastGame() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
return lastGame;
}
std::string LootSettings::getLastVersion() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
return lastVersion;
}
const Language& LootSettings::getLanguage() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
return language;
}
const LootSettings::WindowPosition& LootSettings::getWindowPosition() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
return windowPosition;
}
std::vector<GameSettings> LootSettings::getGameSettings() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
return gameSettings;
}
void LootSettings::storeLastGame(const std::string& lastGame) {
std::lock_guard<std::recursive_mutex> guard(mutex);
this->lastGame = lastGame;
}
void LootSettings::storeWindowPosition(const WindowPosition& position) {
std::lock_guard<std::recursive_mutex> guard(mutex);
windowPosition = position;
}
void LootSettings::storeGameSettings(const std::vector<GameSettings>& gameSettings) {
std::lock_guard<std::recursive_mutex> guard(mutex);
this->gameSettings = gameSettings;
}
void LootSettings::storeFilterState(const std::string& filterId, bool enabled) {
std::lock_guard<std::recursive_mutex> guard(mutex);
filters[filterId] = enabled;
}
void LootSettings::updateLastVersion() {
std::lock_guard<std::recursive_mutex> guard(mutex);
lastVersion = std::to_string(g_version_major) + "." + std::to_string(g_version_minor) + "." + std::to_string(g_version_patch);
}
YAML::Node LootSettings::toYaml() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
YAML::Node node;
node["enableDebugLogging"] = enableDebugLogging;
node["updateMasterlist"] = updateMasterlist;
node["game"] = game;
node["language"] = language.Locale();
node["lastGame"] = lastGame;
node["lastVersion"] = lastVersion;
if (isWindowPositionStored()) {
node["window"]["top"] = windowPosition.top;
node["window"]["bottom"] = windowPosition.bottom;
node["window"]["left"] = windowPosition.left;
node["window"]["right"] = windowPosition.right;
}
node["games"] = gameSettings;
if (!filters.empty())
node["filters"] = filters;
return node;
}
void LootSettings::upgradeYaml(YAML::Node& yaml) {
// Upgrade YAML settings' keys and values from those used in earlier
// versions of LOOT.
if (yaml["Debug Verbosity"] && !yaml["enableDebugLogging"])
yaml["enableDebugLogging"] = yaml["Debug Verbosity"].as<unsigned int>() > 0;
if (yaml["Update Masterlist"] && !yaml["updateMasterlist"])
yaml["updateMasterlist"] = yaml["Update Masterlist"];
if (yaml["Game"] && !yaml["game"])
yaml["game"] = yaml["Game"];
if (yaml["Language"] && !yaml["language"])
yaml["language"] = yaml["Language"];
if (yaml["Last Game"] && !yaml["lastGame"])
yaml["lastGame"] = yaml["Last Game"];
if (yaml["Games"] && !yaml["games"]) {
yaml["games"] = yaml["Games"];
for (auto node : yaml["games"]) {
if (node["url"]) {
node["repo"] = node["url"];
node["branch"] = "v0.8";
}
}
}
if (yaml["games"]) {
const set<string> oldDefaultBranches({
"master",
"v0.7",
});
// Handle exception if YAML is invalid, eg. if an unrecognised
// game type is used (which can happen if downgrading from a
// later version of LOOT that supports more game types).
// However, can't remove elements from a sequence Node, so have to
// copy the valid elements into a new node then overwrite the
// original.
YAML::Node validGames;
for (auto node : yaml["games"]) {
try {
GameSettings settings(node.as<GameSettings>());
if (!yaml["Games"]) {
// Update existing default branch, if the default
// repositories are used.
if (settings.RepoURL() == GameSettings(settings.Id()).RepoURL()
&& oldDefaultBranches.count(settings.RepoBranch()) == 1) {
settings.SetRepoBranch("v0.8");
}
}
validGames.push_back(settings);
}
catch (...) {}
}
yaml["games"] = validGames;
}
if (yaml["filters"])
yaml["filters"].remove("contentFilter");
}
}
+90
View File
@@ -0,0 +1,90 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2014-2015 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef LOOT_GUI_LOOT_SETTINGS
#define LOOT_GUI_LOOT_SETTINGS
#include "backend/game/game_settings.h"
#include "backend/helpers/language.h"
#include <map>
#include <mutex>
#include <string>
#include <vector>
#include <boost/filesystem.hpp>
#include <yaml-cpp/yaml.h>
namespace loot {
class LootSettings {
public:
struct WindowPosition {
WindowPosition();
long top;
long bottom;
long left;
long right;
};
LootSettings();
void load(YAML::Node& settings);
void load(const boost::filesystem::path& file);
void save(const boost::filesystem::path& file);
bool isDebugLoggingEnabled() const;
bool isWindowPositionStored() const;
std::string getGame() const;
std::string getLastGame() const;
std::string getLastVersion() const;
const Language& getLanguage() const;
const WindowPosition& getWindowPosition() const;
std::vector<GameSettings> getGameSettings() const;
void storeLastGame(const std::string& lastGame);
void storeWindowPosition(const WindowPosition& position);
void storeGameSettings(const std::vector<GameSettings>& gameSettings);
void storeFilterState(const std::string& filterId, bool enabled);
void updateLastVersion();
YAML::Node toYaml() const;
private:
bool enableDebugLogging;
bool updateMasterlist;
std::string game;
std::string lastGame;
std::string lastVersion;
Language language;
WindowPosition windowPosition;
std::vector<GameSettings> gameSettings;
std::map<std::string, bool> filters;
mutable std::recursive_mutex mutex;
static void upgradeYaml(YAML::Node& yaml);
};
}
#endif
+56 -209
View File
@@ -39,6 +39,10 @@
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/support/date_time.hpp>
#ifdef _WIN32
#include <windows.h>
#endif
using namespace std;
using boost::locale::translate;
using boost::format;
@@ -46,7 +50,7 @@ using boost::format;
namespace fs = boost::filesystem;
namespace loot {
LootState::LootState() : numUnappliedChanges(0), _currentGame(_games.end()) {}
LootState::LootState() : unappliedChangeCounter(0), _currentGame(_games.end()) {}
void LootState::Init(const std::string& cmdLineGame) {
// Do some preliminary locale / UTF-8 support setup here, in case the settings file reading requires it.
@@ -71,39 +75,26 @@ namespace loot {
}
if (fs::exists(g_path_settings)) {
try {
fs::ifstream in(g_path_settings);
_settings = YAML::Load(in);
in.close();
load(g_path_settings);
}
catch (exception& e) {
_initErrors.push_back((format(translate("Error: Settings parsing failed. %1%")) % e.what()).str());
}
}
// Check if the settings are valid (or if they don't exist).
if (!AreSettingsValid()) {
_settings = GetDefaultSettings();
}
//Set up logging.
boost::log::add_file_log(
boost::log::keywords::file_name = g_path_log.string().c_str(),
boost::log::keywords::auto_flush = true,
boost::log::keywords::format = (
boost::log::expressions::stream
<< "[" << boost::log::expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "%H:%M:%S") << "]"
<< " [" << boost::log::trivial::severity << "]: "
<< boost::log::expressions::smessage
)
boost::log::expressions::stream
<< "[" << boost::log::expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "%H:%M:%S") << "]"
<< " [" << boost::log::trivial::severity << "]: "
<< boost::log::expressions::smessage
)
);
boost::log::add_common_attributes();
bool enableDebugLogging = false;
if (_settings["enableDebugLogging"]) {
enableDebugLogging = _settings["enableDebugLogging"].as<bool>();
}
if (enableDebugLogging)
boost::log::core::get()->set_logging_enabled(true);
else
boost::log::core::get()->set_logging_enabled(false);
boost::log::core::get()->set_logging_enabled(isDebugLoggingEnabled());
// Log some useful info.
BOOST_LOG_TRIVIAL(info) << "LOOT Version: " << g_version_major << "." << g_version_minor << "." << g_version_patch;
@@ -121,9 +112,9 @@ namespace loot {
fs::remove(g_path_local / "CEFDebugLog.txt");
// Now that settings have been loaded, set the locale again to handle translations.
if (_settings["language"] && _settings["language"].as<string>() != Language(Language::english).Locale()) {
if (getLanguage().Code() != Language::english) {
BOOST_LOG_TRIVIAL(debug) << "Initialising language settings.";
loot::Language lang(_settings["language"].as<string>());
loot::Language lang(getLanguage());
BOOST_LOG_TRIVIAL(debug) << "Selected language: " << lang.Name();
//Boost.Locale initialisation: Generate and imbue locales.
@@ -136,17 +127,7 @@ namespace loot {
//Detect installed games.
BOOST_LOG_TRIVIAL(debug) << "Detecting installed games.";
try {
_games = ToGames(GetGameSettings(_settings));
}
catch (YAML::Exception& e) {
BOOST_LOG_TRIVIAL(error) << "Games' settings parsing failed. " << e.what();
_initErrors.push_back((format(translate("Error: Games' settings parsing failed. %1%")) % e.what()).str());
// Now redo, but with no games settings, so only the hardcoded defaults get loaded. It means the user can
// at least still then edit them.
YAML::Node node;
_games = ToGames(GetGameSettings(node));
}
_games = ToGames(getGameSettings());
try {
BOOST_LOG_TRIVIAL(debug) << "Selecting game.";
@@ -154,7 +135,7 @@ namespace loot {
BOOST_LOG_TRIVIAL(debug) << "Initialising game-specific settings.";
_currentGame->Init(true);
// Update game path in settings object.
_settings["games"] = ToGameSettings(_games);
storeGameSettings(ToGameSettings(_games));
}
catch (loot::error &e) {
if (e.code() == loot::error::no_game_detected) {
@@ -172,15 +153,20 @@ namespace loot {
return _initErrors;
}
void LootState::UpdateGames(std::list<GameSettings>& games) {
// Acquire the lock for the scope of this method.
base::AutoLock lock_scope(_lock);
void LootState::save(const boost::filesystem::path & file) {
storeLastGame(_currentGame->FolderName());
updateLastVersion();
LootSettings::save(file);
}
void LootState::UpdateGamesFromSettings() {
std::lock_guard<std::mutex> guard(mutex);
unordered_set<string> newGameFolders;
// Update existing games, add new games.
BOOST_LOG_TRIVIAL(trace) << "Updating existing games and adding new games.";
for (auto &game : games) {
for (const auto &game : getGameSettings()) {
auto pos = find(_games.begin(), _games.end(), game);
if (pos != _games.end()) {
@@ -214,25 +200,23 @@ namespace loot {
// Re-initialise the current game in case the game path setting was changed.
_currentGame->Init(true);
// Update game path in settings object.
_settings["games"] = ToGameSettings(_games);
storeGameSettings(ToGameSettings(_games));
}
void LootState::ChangeGame(const std::string& newGameFolder) {
// Acquire the lock for the scope of this method.
base::AutoLock lock_scope(_lock);
std::lock_guard<std::mutex> guard(mutex);
BOOST_LOG_TRIVIAL(debug) << "Changing current game to that with folder: " << newGameFolder;
_currentGame = find(_games.begin(), _games.end(), Game(Game::autodetect, newGameFolder));
_currentGame->Init(true);
// Update game path in settings object.
_settings["games"] = ToGameSettings(_games);
storeGameSettings(ToGameSettings(_games));
BOOST_LOG_TRIVIAL(debug) << "New game is " << _currentGame->Name();
}
Game& LootState::CurrentGame() {
// Acquire the lock for the scope of this method.
base::AutoLock lock_scope(_lock);
std::lock_guard<std::mutex> guard(mutex);
return *_currentGame;
}
@@ -246,186 +230,49 @@ namespace loot {
return installedGames;
}
const YAML::Node& LootState::GetSettings() const {
return _settings;
bool LootState::hasUnappliedChanges() const {
return unappliedChangeCounter > 0;
}
void LootState::UpdateSettings(const YAML::Node& settings) {
// Acquire the lock for the scope of this method.
base::AutoLock lock_scope(_lock);
_settings = settings;
void LootState::incrementUnappliedChangeCounter() {
++unappliedChangeCounter;
}
void LootState::SaveSettings() {
// Acquire the lock for the scope of this method.
base::AutoLock lock_scope(_lock);
_settings["lastGame"] = _currentGame->FolderName();
_settings["lastVersion"] = to_string(g_version_major) + "." + to_string(g_version_minor) + "." + to_string(g_version_patch);
//Save settings.
try {
BOOST_LOG_TRIVIAL(debug) << "Saving LOOT settings.";
YAML::Emitter yout;
yout.SetIndent(2);
yout << _settings;
fs::ofstream out(loot::g_path_settings);
out << yout.c_str();
out.close();
}
catch (std::exception &e) {
BOOST_LOG_TRIVIAL(error) << "Failed to save LOOT's settings. Error: " << e.what();
}
void LootState::decrementUnappliedChangeCounter() {
--unappliedChangeCounter;
}
void LootState::SelectGame(std::string preferredGame) {
if (preferredGame.empty()) {
// Get preferred game from settings.
if (_settings["game"] && _settings["game"].as<string>() != "auto")
preferredGame = _settings["game"].as<string>();
else if (_settings["lastGame"] && _settings["lastGame"].as<string>() != "auto")
preferredGame = _settings["lastGame"].as<string>();
if (getGame() != "auto")
preferredGame = getGame();
else if (getLastGame() != "auto")
preferredGame = getLastGame();
}
// Get iterator to preferred game if there is one.
_currentGame = _games.end();
for (auto it = _games.begin(); it != _games.end(); ++it) {
if ((preferredGame.empty() && it->IsInstalled())
|| (!preferredGame.empty() && preferredGame == it->FolderName() && it->IsInstalled())) {
_currentGame = it;
return;
}
// Get iterator to preferred game.
_currentGame = find_if(begin(_games), end(_games), [&](auto& game) {
return (preferredGame.empty() || preferredGame == game.FolderName()) && game.IsInstalled();
});
// If the preferred game cannot be found, get the first installed game.
if (_currentGame == end(_games)) {
_currentGame = find_if(begin(_games), end(_games), [](auto& game) {
return game.IsInstalled();
});
}
// Preferred game not found, just pick the first installed one.
for (auto it = _games.begin(); it != _games.end(); ++it) {
if (it->IsInstalled()) {
_currentGame = it;
return;
}
// If no game can be selected, throw an exception.
if (_currentGame == end(_games)) {
BOOST_LOG_TRIVIAL(error) << "None of the supported games were detected.";
throw error(error::no_game_detected, translate("None of the supported games were detected."));
}
BOOST_LOG_TRIVIAL(error) << "None of the supported games were detected.";
throw error(error::no_game_detected, translate("None of the supported games were detected."));
}
bool LootState::AreSettingsValid() {
// Acquire the lock for the scope of this method.
base::AutoLock lock_scope(_lock);
if (!_settings["language"]) {
if (_settings["Language"]) {
// Conversion from 0.6 key.
_settings["language"] = _settings["Language"];
_settings.remove("Language");
}
else
return false;
}
if (!_settings["game"]) {
if (_settings["Game"]) {
// Conversion from 0.6 key.
_settings["game"] = _settings["Game"];
_settings.remove("Game");
}
else
return false;
}
if (!_settings["lastGame"]) {
if (_settings["Last Game"]) {
// Conversion from 0.6 key.
_settings["lastGame"] = _settings["Last Game"];
_settings.remove("Last Game");
}
else
return false;
}
if (!_settings["enableDebugLogging"]) {
if (_settings["Debug Verbosity"]) {
// Conversion from 0.6 key.
_settings["enableDebugLogging"] = (_settings["Debug Verbosity"].as<unsigned int>() > 0);
_settings.remove("Debug Verbosity");
}
else if (_settings["debugVerbosity"]) {
// Conversion from 0.7 alpha key
_settings["enableDebugLogging"] = (_settings["debugVerbosity"].as<unsigned int>() > 0);
_settings.remove("debugVerbosity");
}
else
return false;
}
if (!_settings["updateMasterlist"]) {
if (_settings["Update Masterlist"]) {
// Conversion from 0.6 key.
_settings["updateMasterlist"] = _settings["Update Masterlist"];
_settings.remove("Update Masterlist");
}
else
return false;
}
if (!_settings["games"]) {
if (_settings["Games"]) {
// Conversion from 0.6 key.
_settings["games"] = _settings["Games"];
for (auto node : _settings["games"]) {
if (node["url"]) {
node["repo"] = node["url"];
node["branch"] = "v0.8";
node.remove("url");
}
}
_settings.remove("Games");
}
else
return false;
}
else {
// Update existing default branches to new version default, if the
// default repositories are used.
for (auto node : _settings["games"]) {
GameSettings settings(node.as<GameSettings>());
set<string> oldDefaultBranches({
"master",
"v0.7",
});
if (settings.RepoURL() == GameSettings(settings.Id()).RepoURL()
&& oldDefaultBranches.count(settings.RepoBranch()) == 1) {
node["branch"] = "v0.8";
}
}
}
if (_settings["windows"])
_settings.remove("windows");
return true;
std::list<Game> LootState::ToGames(const std::vector<GameSettings>& settings) {
return list<Game>(settings.begin(), settings.end());
}
YAML::Node LootState::GetDefaultSettings() const {
YAML::Node root;
root["language"] = "en";
root["game"] = "auto";
root["lastGame"] = "auto";
root["enableDebugLogging"] = false;
root["updateMasterlist"] = true;
// Add base game definitions, and Nehrim.
GetGameSettings(root);
GameSettings settings(GameSettings::tes4, "Nehrim");
settings.SetName("Nehrim - At Fate's Edge")
.SetMaster("Nehrim.esm")
.SetRegistryKey("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Nehrim - At Fate's Edge_is1\\InstallLocation");
root["games"].push_back(settings);
return root;
std::vector<GameSettings> LootState::ToGameSettings(const std::list<Game>& games) {
return vector<GameSettings>(games.begin(), games.end());
}
}
+17 -21
View File
@@ -25,49 +25,45 @@
#ifndef __LOOT_GUI_LOOT_STATE__
#define __LOOT_GUI_LOOT_STATE__
#include "../backend/game/game.h"
#include <include/cef_app.h>
#include <include/base/cef_lock.h>
#include <yaml-cpp/yaml.h>
#include "loot_settings.h"
#include "backend/game/game.h"
namespace loot {
class LootState : public CefBase {
class LootState : public LootSettings {
public:
LootState();
void Init(const std::string& cmdLineGame);
const std::vector<std::string>& InitErrors() const;
void save(const boost::filesystem::path& file);
Game& CurrentGame();
void ChangeGame(const std::string& newGameFolder);
void UpdateGames(std::list<GameSettings>& games);
void UpdateGamesFromSettings();
// Get the folder names of the installed games.
std::vector<std::string> InstalledGames();
const YAML::Node& GetSettings() const;
void UpdateSettings(const YAML::Node& settings);
void SaveSettings();
// Used to check if LOOT has unaccepted sorting or metadata changes on quit.
int numUnappliedChanges;
bool hasUnappliedChanges() const;
void incrementUnappliedChangeCounter();
void decrementUnappliedChangeCounter();
private:
YAML::Node _settings;
std::list<Game> _games;
std::list<Game>::iterator _currentGame;
std::vector<std::string> _initErrors;
// Used to check if LOOT has unaccepted sorting or metadata changes on quit.
size_t unappliedChangeCounter;
// Select initial game.
void SelectGame(std::string cmdLineGame);
// Check if the settings file has the right root keys (doesn't check their values).
bool AreSettingsValid();
YAML::Node GetDefaultSettings() const;
static std::list<Game> ToGames(const std::vector<GameSettings>& settings);
static std::vector<GameSettings> ToGameSettings(const std::list<Game>& games);
// Lock used to protect access to member variables.
base::Lock _lock;
IMPLEMENT_REFCOUNTING(LootState);
// Mutex used to protect access to member variables.
std::mutex mutex;
};
}
-44
View File
@@ -655,48 +655,4 @@ TEST_F(Game, shouldShowBlankEspAsActiveIfItHasBeenFullyLoadedAndTheGameHasBeenIn
EXPECT_FALSE(game.IsPluginActive("Blank.esp"));
}
TEST(ToGames, EmptySettings) {
EXPECT_EQ(std::list<loot::Game>(), loot::ToGames(std::list<loot::GameSettings>()));
}
TEST(ToGames, NonEmptySettings) {
std::list<loot::GameSettings> settings({
loot::GameSettings(loot::GameSettings::tes4),
loot::GameSettings(loot::GameSettings::tes5),
loot::GameSettings(loot::GameSettings::fo3),
loot::GameSettings(loot::GameSettings::fonv),
});
std::list<loot::Game> expected({
loot::Game(loot::Game::tes4),
loot::Game(loot::Game::tes5),
loot::Game(loot::Game::fo3),
loot::Game(loot::Game::fonv),
});
EXPECT_EQ(expected, loot::ToGames(settings));
}
TEST(ToGameSettings, EmptyGames) {
EXPECT_EQ(std::list<loot::GameSettings>(), loot::ToGameSettings(std::list<loot::Game>()));
}
TEST(ToGameSettings, NonEmptyGames) {
std::list<loot::Game> games({
loot::Game(loot::Game::tes4),
loot::Game(loot::Game::tes5),
loot::Game(loot::Game::fo3),
loot::Game(loot::Game::fonv),
});
std::list<loot::GameSettings> expected({
loot::GameSettings(loot::GameSettings::tes4),
loot::GameSettings(loot::GameSettings::tes5),
loot::GameSettings(loot::GameSettings::fo3),
loot::GameSettings(loot::GameSettings::fonv),
});
EXPECT_EQ(expected, loot::ToGameSettings(games));
}
#endif
@@ -251,43 +251,4 @@ TEST_F(GameSettings, YamlDecode) {
EXPECT_EQ("branch1", game.RepoBranch());
EXPECT_EQ("", game.GamePath());
}
TEST(GetGameSettings, AllMissing) {
YAML::Node settings;
std::list<loot::GameSettings> expected = {
loot::GameSettings(loot::GameSettings::tes4),
loot::GameSettings(loot::GameSettings::tes5),
loot::GameSettings(loot::GameSettings::fo3),
loot::GameSettings(loot::GameSettings::fonv),
loot::GameSettings(loot::GameSettings::fo4)
};
EXPECT_FALSE(settings["games"]);
EXPECT_EQ(expected, loot::GetGameSettings(settings));
EXPECT_EQ(expected, settings["games"].as<std::list<loot::GameSettings>>());
}
TEST(GetGameSettings, MissingFallout3) {
std::list<loot::GameSettings> initial({
loot::GameSettings(loot::GameSettings::tes4, "folder1"),
loot::GameSettings(loot::GameSettings::tes5, "folder2"),
loot::GameSettings(loot::GameSettings::fonv, "folder3"),
loot::GameSettings(loot::GameSettings::fo4, "folder4")
});
YAML::Node settings;
settings["games"] = initial;
std::list<loot::GameSettings> expected = {
loot::GameSettings(loot::GameSettings::tes4, "folder1"),
loot::GameSettings(loot::GameSettings::tes5, "folder2"),
loot::GameSettings(loot::GameSettings::fonv, "folder3"),
loot::GameSettings(loot::GameSettings::fo4, "folder4"),
loot::GameSettings(loot::GameSettings::fo3)
};
EXPECT_EQ(expected, loot::GetGameSettings(settings));
EXPECT_EQ(expected, settings["games"].as<std::list<loot::GameSettings>>());
}
#endif
+479
View File
@@ -0,0 +1,479 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2014-2015 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef LOOT_TEST_GUI_LOOT_SETTINGS
#define LOOT_TEST_GUI_LOOT_SETTINGS
#include "gui/loot_settings.h"
#include "backend/globals.h"
#include "tests/fixtures.h"
namespace loot {
namespace test {
class LootSettings : public ::testing::Test {
protected:
LootSettings() : settingsFile("./settings.yaml") {}
~LootSettings() {
boost::filesystem::remove(settingsFile);
}
boost::filesystem::path settingsFile;
loot::LootSettings settings;
};
TEST_F(LootSettings, defaultConstructorShouldSetDefaultValues) {
const std::string currentVersion = std::to_string(g_version_major) + "." + std::to_string(g_version_minor) + "." + std::to_string(g_version_patch);
const std::vector<GameSettings> expectedGameSettings({
GameSettings(GameSettings::tes4),
GameSettings(GameSettings::tes5),
GameSettings(GameSettings::fo3),
GameSettings(GameSettings::fonv),
GameSettings(GameSettings::fo4),
GameSettings(GameSettings::tes4, "Nehrim")
.SetName("Nehrim - At Fate's Edge")
.SetMaster("Nehrim.esm")
.SetRegistryKey("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Nehrim - At Fate's Edge_is1\\InstallLocation"),
});
EXPECT_FALSE(settings.isDebugLoggingEnabled());
EXPECT_EQ("auto", settings.getGame());
EXPECT_EQ("en", settings.getLanguage().Locale());
EXPECT_EQ("auto", settings.getLastGame());
EXPECT_FALSE(settings.isWindowPositionStored());
const YAML::Node node = settings.toYaml();
EXPECT_TRUE(node["updateMasterlist"].as<bool>());
EXPECT_EQ(currentVersion, node["lastVersion"].as<std::string>());
EXPECT_FALSE(node["filters"]);
// GameSettings equality only checks name and folder, so check
// other settings individually.
const std::vector<GameSettings> actualGameSettings = settings.getGameSettings();
EXPECT_EQ(expectedGameSettings, actualGameSettings);
EXPECT_EQ(expectedGameSettings[0].Id(), actualGameSettings[0].Id());
EXPECT_EQ(expectedGameSettings[0].Master(), actualGameSettings[0].Master());
EXPECT_EQ(expectedGameSettings[0].RegistryKey(), actualGameSettings[0].RegistryKey());
EXPECT_EQ(expectedGameSettings[0].RepoURL(), actualGameSettings[0].RepoURL());
EXPECT_EQ(expectedGameSettings[0].RepoBranch(), actualGameSettings[0].RepoBranch());
EXPECT_EQ(expectedGameSettings[1].Id(), actualGameSettings[1].Id());
EXPECT_EQ(expectedGameSettings[1].Master(), actualGameSettings[1].Master());
EXPECT_EQ(expectedGameSettings[1].RegistryKey(), actualGameSettings[1].RegistryKey());
EXPECT_EQ(expectedGameSettings[1].RepoURL(), actualGameSettings[1].RepoURL());
EXPECT_EQ(expectedGameSettings[1].RepoBranch(), actualGameSettings[1].RepoBranch());
EXPECT_EQ(expectedGameSettings[2].Id(), actualGameSettings[2].Id());
EXPECT_EQ(expectedGameSettings[2].Master(), actualGameSettings[2].Master());
EXPECT_EQ(expectedGameSettings[2].RegistryKey(), actualGameSettings[2].RegistryKey());
EXPECT_EQ(expectedGameSettings[2].RepoURL(), actualGameSettings[2].RepoURL());
EXPECT_EQ(expectedGameSettings[2].RepoBranch(), actualGameSettings[2].RepoBranch());
EXPECT_EQ(expectedGameSettings[3].Id(), actualGameSettings[3].Id());
EXPECT_EQ(expectedGameSettings[3].Master(), actualGameSettings[3].Master());
EXPECT_EQ(expectedGameSettings[3].RegistryKey(), actualGameSettings[3].RegistryKey());
EXPECT_EQ(expectedGameSettings[3].RepoURL(), actualGameSettings[3].RepoURL());
EXPECT_EQ(expectedGameSettings[3].RepoBranch(), actualGameSettings[3].RepoBranch());
EXPECT_EQ(expectedGameSettings[4].Id(), actualGameSettings[4].Id());
EXPECT_EQ(expectedGameSettings[4].Master(), actualGameSettings[4].Master());
EXPECT_EQ(expectedGameSettings[4].RegistryKey(), actualGameSettings[4].RegistryKey());
EXPECT_EQ(expectedGameSettings[4].RepoURL(), actualGameSettings[4].RepoURL());
EXPECT_EQ(expectedGameSettings[4].RepoBranch(), actualGameSettings[4].RepoBranch());
EXPECT_EQ(expectedGameSettings[5].Id(), actualGameSettings[5].Id());
EXPECT_EQ(expectedGameSettings[5].Master(), actualGameSettings[5].Master());
EXPECT_EQ(expectedGameSettings[5].RegistryKey(), actualGameSettings[5].RegistryKey());
EXPECT_EQ(expectedGameSettings[5].RepoURL(), actualGameSettings[5].RepoURL());
EXPECT_EQ(expectedGameSettings[5].RepoBranch(), actualGameSettings[5].RepoBranch());
}
TEST_F(LootSettings, loadingFromFileShouldLoadContentAsYaml) {
boost::filesystem::ofstream out(settingsFile);
out << "enableDebugLogging: true" << std::endl;
out.close();
settings.load(settingsFile);
EXPECT_TRUE(settings.isDebugLoggingEnabled());
}
TEST_F(LootSettings, loadingFromYamlShouldStoreLoadedValues) {
const bool enableDebugLogging = true;
const bool updateMasterlist = true;
const std::string game = "Oblivion";
const std::string language = "fr";
const std::string lastGame = "Skyrim";
const std::string lastVersion = "0.7.1";
const std::map<std::string, long> window({
{"top", 1},
{"bottom", 2},
{"left", 3},
{"right", 4},
});
const std::vector<GameSettings> games({
GameSettings(GameSettings::tes4).SetName("Game Name"),
});
const std::map<std::string, bool> filters({
{"hideBashTags", false},
{"hideCRCs", true},
});
YAML::Node inputYaml;
inputYaml["enableDebugLogging"] = enableDebugLogging;
inputYaml["updateMasterlist"] = updateMasterlist;
inputYaml["game"] = game;
inputYaml["language"] = language;
inputYaml["lastGame"] = lastGame;
inputYaml["lastVersion"] = lastVersion;
inputYaml["window"] = window;
inputYaml["games"] = games;
inputYaml["filters"] = filters;
settings.load(inputYaml);
EXPECT_EQ(enableDebugLogging, settings.isDebugLoggingEnabled());
EXPECT_EQ(game, settings.getGame());
EXPECT_EQ(language, settings.getLanguage().Locale());
EXPECT_EQ(lastGame, settings.getLastGame());
EXPECT_EQ(1, settings.getWindowPosition().top);
EXPECT_EQ(2, settings.getWindowPosition().bottom);
EXPECT_EQ(3, settings.getWindowPosition().left);
EXPECT_EQ(4, settings.getWindowPosition().right);
const YAML::Node outputYaml = settings.toYaml();
EXPECT_EQ(updateMasterlist, outputYaml["updateMasterlist"].as<bool>());
EXPECT_EQ(lastVersion, outputYaml["lastVersion"].as<std::string>());
for (const auto& filter : filters) {
EXPECT_EQ(filter.second, outputYaml["filters"][filter.first].as<bool>());
}
EXPECT_EQ(games[0].Name(), settings.getGameSettings()[0].Name());
}
TEST_F(LootSettings, loadingFromEmptyYamlShouldNotThrow) {
YAML::Node yaml;
EXPECT_NO_THROW(settings.load(yaml));
}
TEST_F(LootSettings, loadingFromYamlShouldUpgradeFromVersion0Point6Format) {
const unsigned int DebugVerbosity = 3;
const bool UpdateMasterlist = true;
const std::string Game = "Oblivion";
const std::string Language = "fr";
const std::string LastGame = "Skyrim";
const std::vector<GameSettings> Games({
GameSettings(GameSettings::tes4).SetName("Game Name"),
});
YAML::Node inputYaml;
inputYaml["Debug Verbosity"] = DebugVerbosity;
inputYaml["Update Masterlist"] = UpdateMasterlist;
inputYaml["Game"] = Game;
inputYaml["Language"] = Language;
inputYaml["Last Game"] = LastGame;
inputYaml["Games"] = Games;
inputYaml["Games"][0]["url"] = inputYaml["Games"][0]["repo"];
inputYaml["Games"][0].remove("repo");
inputYaml["Games"][0].remove("branch");
settings.load(inputYaml);
const YAML::Node outputYaml = settings.toYaml();
EXPECT_TRUE(settings.isDebugLoggingEnabled());
EXPECT_EQ(UpdateMasterlist, outputYaml["updateMasterlist"].as<bool>());
EXPECT_EQ(Game, settings.getGame());
EXPECT_EQ(Language, settings.getLanguage().Locale());
EXPECT_EQ(LastGame, settings.getLastGame());
EXPECT_EQ(Games[0].Name(), settings.getGameSettings()[0].Name());
EXPECT_EQ(Games[0].RepoURL(), settings.getGameSettings()[0].RepoURL());
EXPECT_EQ(Games[0].RepoBranch(), settings.getGameSettings()[0].RepoBranch());
}
TEST_F(LootSettings, loadingFromYamlShouldNotUpgradeVersion0Point6SettingsIfEquivalentsAlreadyExist) {
const unsigned int DebugVerbosity = 3;
const bool enableDebugLogging = false;
const bool UpdateMasterlist = true;
const bool updateMasterlist = false;
const std::string Game = "Oblivion";
const std::string game = "auto";
const std::string Language = "fr";
const std::string language = "en";
const std::string LastGame = "Skyrim";
const std::string lastGame = "auto";
const std::vector<GameSettings> Games({
GameSettings(GameSettings::tes4).SetName("Old Game Name"),
});
const std::vector<GameSettings> games({
GameSettings(GameSettings::fo3).SetName("Game Name"),
});
YAML::Node inputYaml;
inputYaml["Debug Verbosity"] = DebugVerbosity;
inputYaml["enableDebugLogging"] = enableDebugLogging;
inputYaml["Update Masterlist"] = UpdateMasterlist;
inputYaml["updateMasterlist"] = updateMasterlist;
inputYaml["Game"] = Game;
inputYaml["game"] = game;
inputYaml["Language"] = Language;
inputYaml["language"] = language;
inputYaml["Last Game"] = LastGame;
inputYaml["lastGame"] = lastGame;
inputYaml["Games"] = Games;
inputYaml["Games"][0]["url"] = inputYaml["Games"][0]["repo"];
inputYaml["Games"][0].remove("repo");
inputYaml["Games"][0].remove("branch");
inputYaml["games"] = games;
settings.load(inputYaml);
const YAML::Node outputYaml = settings.toYaml();
EXPECT_EQ(enableDebugLogging, settings.isDebugLoggingEnabled());
EXPECT_EQ(updateMasterlist, outputYaml["updateMasterlist"].as<bool>());
EXPECT_EQ(game, settings.getGame());
EXPECT_EQ(language, settings.getLanguage().Locale());
EXPECT_EQ(lastGame, settings.getLastGame());
EXPECT_EQ(games[0].Name(), settings.getGameSettings()[0].Name());
}
TEST_F(LootSettings, loadingFromYamlShouldUpgradeOldDefaultGameRepositoryBranches) {
const std::vector<GameSettings> games({GameSettings(GameSettings::tes4)});
YAML::Node inputYaml;
inputYaml["games"] = games;
inputYaml["games"][0]["branch"] = "v0.7";
settings.load(inputYaml);
EXPECT_EQ(games[0].RepoBranch(), settings.getGameSettings()[0].RepoBranch());
}
TEST_F(LootSettings, loadingFromYamlShouldNotUpgradeNonDefaultGameRepositoryBranches) {
const std::vector<GameSettings> games({GameSettings(GameSettings::tes4)});
YAML::Node inputYaml;
inputYaml["games"] = games;
inputYaml["games"][0]["branch"] = "foo";
settings.load(inputYaml);
EXPECT_EQ("foo", settings.getGameSettings()[0].RepoBranch());
}
TEST_F(LootSettings, loadingFromYamlShouldAddMissingBaseGames) {
const std::vector<GameSettings> games({GameSettings(GameSettings::tes4)});
YAML::Node inputYaml;
inputYaml["games"] = games;
settings.load(inputYaml);
const std::vector<GameSettings> expectedGameSettings({
GameSettings(GameSettings::tes4),
GameSettings(GameSettings::tes5),
GameSettings(GameSettings::fo3),
GameSettings(GameSettings::fonv),
GameSettings(GameSettings::fo4),
});
EXPECT_EQ(expectedGameSettings, settings.getGameSettings());
}
TEST_F(LootSettings, loadingFromYamlShouldSkipUnrecognisedGames) {
YAML::Node inputYaml;
inputYaml["games"][0] = GameSettings(GameSettings::tes4);
inputYaml["games"][0]["type"] = "Foobar";
inputYaml["games"][0]["name"] = "Foobar";
inputYaml["games"][1] = GameSettings(GameSettings::tes5).SetName("Game Name");
settings.load(inputYaml);
EXPECT_EQ("Game Name", settings.getGameSettings()[0].Name());
}
TEST_F(LootSettings, loadingFromYamlShouldRemoveTheContentFilterSetting) {
YAML::Node inputYaml;
inputYaml["filters"]["contentFilter"] = "foo";
settings.load(inputYaml);
}
TEST_F(LootSettings, saveShouldWriteSettingsAsYamlToPassedFile) {
settings.storeLastGame("Skyrim");
settings.save(settingsFile);
settings.storeLastGame("auto");
settings.load(settingsFile);
EXPECT_EQ("Skyrim", settings.getLastGame());
}
TEST_F(LootSettings, getLanguageShouldReturnTheCurrentValue) {
YAML::Node inputYaml;
inputYaml["language"] = "fr";
settings.load(inputYaml);
EXPECT_EQ("fr", settings.getLanguage().Locale());
}
TEST_F(LootSettings, isWindowPositionStoredShouldReturnFalseIfAllPositionValuesAreZero) {
loot::LootSettings::WindowPosition position;
settings.storeWindowPosition(position);
EXPECT_FALSE(settings.isWindowPositionStored());
}
TEST_F(LootSettings, isWindowPositionStoredShouldReturnTrueIfTopPositionValueIsNonZero) {
loot::LootSettings::WindowPosition position;
position.top = 1;
settings.storeWindowPosition(position);
EXPECT_TRUE(settings.isWindowPositionStored());
}
TEST_F(LootSettings, isWindowPositionStoredShouldReturnTrueIfBottomPositionValueIsNonZero) {
loot::LootSettings::WindowPosition position;
position.bottom = 1;
settings.storeWindowPosition(position);
EXPECT_TRUE(settings.isWindowPositionStored());
}
TEST_F(LootSettings, isWindowPositionStoredShouldReturnTrueIfLeftPositionValueIsNonZero) {
loot::LootSettings::WindowPosition position;
position.left = 1;
settings.storeWindowPosition(position);
EXPECT_TRUE(settings.isWindowPositionStored());
}
TEST_F(LootSettings, isWindowPositionStoredShouldReturnTrueIfRightPositionValueIsNonZero) {
loot::LootSettings::WindowPosition position;
position.right = 1;
settings.storeWindowPosition(position);
EXPECT_TRUE(settings.isWindowPositionStored());
}
TEST_F(LootSettings, storeGameSettingsShouldReplaceExistingGameSettings) {
const std::vector<GameSettings> gameSettings({GameSettings(GameSettings::tes5)});
settings.storeGameSettings(gameSettings);
EXPECT_EQ(gameSettings, settings.getGameSettings());
}
TEST_F(LootSettings, storeLastGameShouldReplaceExistingValue) {
settings.storeLastGame("Fallout3");
EXPECT_EQ("Fallout3", settings.getLastGame());
}
TEST_F(LootSettings, storeWindowPositionShouldReplaceExistingValue) {
loot::LootSettings::WindowPosition expectedPosition;
expectedPosition.top = 1;
settings.storeWindowPosition(expectedPosition);
loot::LootSettings::WindowPosition actualPosition = settings.getWindowPosition();
EXPECT_EQ(expectedPosition.top, actualPosition.top);
EXPECT_EQ(expectedPosition.bottom, actualPosition.bottom);
EXPECT_EQ(expectedPosition.left, actualPosition.left);
EXPECT_EQ(expectedPosition.right, actualPosition.right);
}
TEST_F(LootSettings, updateLastVersionShouldSetValueToCurrentLootVersion) {
const std::string currentVersion = std::to_string(g_version_major) + "." + std::to_string(g_version_minor) + "." + std::to_string(g_version_patch);
YAML::Node inputYaml;
inputYaml["lastVersion"] = "v0.7.1";
settings.load(inputYaml);
settings.updateLastVersion();
EXPECT_EQ(currentVersion, settings.getLastVersion());
}
TEST_F(LootSettings, toYamlShouldOutputStoredSettings) {
const bool enableDebugLogging = true;
const bool updateMasterlist = true;
const std::string game = "Oblivion";
const std::string language = "fr";
const std::string lastGame = "Skyrim";
const std::string lastVersion = "0.7.1";
const std::map<std::string, long> window({
{"top", 1},
{"bottom", 2},
{"left", 3},
{"right", 4},
});
const std::vector<GameSettings> games({
GameSettings(GameSettings::tes4).SetName("Game Name"),
});
const std::map<std::string, bool> filters({
{"hideBashTags", false},
{"hideCRCs", true},
});
YAML::Node inputYaml;
inputYaml["enableDebugLogging"] = enableDebugLogging;
inputYaml["updateMasterlist"] = updateMasterlist;
inputYaml["game"] = game;
inputYaml["language"] = language;
inputYaml["lastGame"] = lastGame;
inputYaml["lastVersion"] = lastVersion;
inputYaml["window"] = window;
inputYaml["games"] = games;
inputYaml["filters"] = filters;
settings.load(inputYaml);
const YAML::Node outputYaml = settings.toYaml();
EXPECT_EQ(enableDebugLogging, outputYaml["enableDebugLogging"].as<bool>());
EXPECT_EQ(updateMasterlist, outputYaml["updateMasterlist"].as<bool>());
EXPECT_EQ(game, outputYaml["game"].as<std::string>());
EXPECT_EQ(language, outputYaml["language"].as<std::string>());
EXPECT_EQ(lastGame, outputYaml["lastGame"].as<std::string>());
EXPECT_EQ(lastVersion, outputYaml["lastVersion"].as<std::string>());
for (const auto& position : window) {
EXPECT_EQ(position.second, outputYaml["window"][position.first].as<long>());
}
for (const auto& filter : filters) {
EXPECT_EQ(filter.second, outputYaml["filters"][filter.first].as<bool>());
}
EXPECT_EQ(games[0].Name(), outputYaml["games"][0]["name"].as<std::string>());
}
}
}
#endif
+1
View File
@@ -51,6 +51,7 @@
#include "backend/test_metadata_list.h"
#include "backend/test_masterlist.h"
#include "backend/test_plugin_sorter.h"
#include "gui/test_loot_settings.h"
#include <boost/log/core.hpp>