diff --git a/resources/report/js/script.js b/resources/report/js/script.js
index 18c10f24..76bee270 100644
--- a/resources/report/js/script.js
+++ b/resources/report/js/script.js
@@ -624,87 +624,113 @@ function setupEventHandlers() {
document.body.addEventListener('mouseover', toggleHoverText, false);
}
-function initUI() {
- if (typeof loot == 'undefined') {
- console.log('loot is not defined.');
- return;
- }
-
- document.getElementById('LOOTVersion').textContent = loot.version;
- /* Fill in languages, games, settings values. */
-
- /* Fill in game row template's game type options. */
- var select = document.getElementById('gameRow').content.querySelector('select');
- for (var j = 0; j < loot.gameTypes.length; ++j) {
- var option = document.createElement('option');
- option.value = loot.gameTypes[j];
- option.textContent = loot.gameTypes[j];
- select.appendChild(option);
- }
-
- /* Now fill game lists/table. */
- var gameSelect = document.getElementById('defaultGameSelect');
- var gameMenu = document.getElementById('gameMenu').firstElementChild;
- var gameTableBody = document.getElementById('gameTable').getElementsByTagName('tbody')[0];
- /* Add "auto" value for default game. */
- var option = document.createElement('option');
- option.value = 'auto';
- option.textContent = 'Autodetect';
- gameSelect.appendChild(option);
- /* Add row for creating new rows. */
- setupTable(gameTableBody);
- for (var i = 0; i < loot.settings.games.length; ++i) {
- var option = document.createElement('option');
- option.value = loot.settings.games[i].folder;
- option.textContent = loot.settings.games[i].name;
- gameSelect.appendChild(option);
-
- var li = document.createElement('li');
- li.setAttribute('data-action', 'change-game');
- li.setAttribute('data-target', loot.settings.games[i].folder);
- li.textContent = loot.settings.games[i].name;
- gameMenu.appendChild(li);
-
- addTableRow(gameTableBody, loot.settings.games[i]);
- }
-
- /* Now fill in language options. */
- var settingsLangSelect = document.getElementById('languageSelect');
- var messageLangSelect = document.getElementById('messageRow').content.querySelector('.language');
- for (var i = 0; i < loot.languages.length; ++i) {
- var option = document.createElement('option');
- option.value = loot.languages[i];
- option.textContent = loot.languages[i];
- settingsLangSelect.appendChild(option);
- messageLangSelect.appendChild(option.cloneNode(true));
- }
-
- /* Now fill in settings values. */
- gameSelect.value = loot.settings.game;
- settingsLangSelect.value = loot.settings.language;
- debugVerbositySelect.value = loot.settings.debugVerbosity;
+function processCefError(errorCode, errorMessage) {
+ showMessageBox('error', "Error", "Error code: " + error_code + "; " + error_message);
}
function initGlobalVars() {
// Create and send a new query.
var request_id = window.cefQuery({
- request: 'initGlobalVars',
+ request: 'getVersion',
persistent: false,
onSuccess: function(response) {
try {
- var temp = JSON.parse(response);
- loot.version = temp.version;
- loot.settings = temp.settings;
- loot.gameTypes = temp.gameTypes;
- loot.languages = temp.languages;
+ loot.version = JSON.parse(response);
+
+ document.getElementById('LOOTVersion').textContent = loot.version;
} catch (e) {
console.log(e);
console.log('Response: ' + response);
}
- initUI();
},
- onFailure: function(error_code, error_message) {
- showMessageBox('error', "Error", "Error code: " + error_code + "; " + error_message);
- }
+ onFailure: processCefError
+ });
+ var request_id = window.cefQuery({
+ request: 'getLanguages',
+ persistent: false,
+ onSuccess: function(response) {
+ try {
+ loot.languages = JSON.parse(response);
+
+ /* Now fill in language options. */
+ var settingsLangSelect = document.getElementById('languageSelect');
+ var messageLangSelect = document.getElementById('messageRow').content.querySelector('.language');
+ for (var i = 0; i < loot.languages.length; ++i) {
+ var option = document.createElement('option');
+ option.value = loot.languages[i].locale;
+ option.textContent = loot.languages[i].name;
+ settingsLangSelect.appendChild(option);
+ messageLangSelect.appendChild(option.cloneNode(true));
+ }
+ } catch (e) {
+ console.log(e);
+ console.log('Response: ' + response);
+ }
+ },
+ onFailure: processCefError
+ });
+ var request_id = window.cefQuery({
+ request: 'getGameTypes',
+ persistent: false,
+ onSuccess: function(response) {
+ try {
+ loot.gameTypes = JSON.parse(response);
+
+ /* Fill in game row template's game type options. */
+ var select = document.getElementById('gameRow').content.querySelector('select');
+ for (var j = 0; j < loot.gameTypes.length; ++j) {
+ var option = document.createElement('option');
+ option.value = loot.gameTypes[j];
+ option.textContent = loot.gameTypes[j];
+ select.appendChild(option);
+ }
+ } catch (e) {
+ console.log(e);
+ console.log('Response: ' + response);
+ }
+
+ // Settings depend on having the game types filled, so now send the CEF query for the settings.
+ var request_id = window.cefQuery({
+ request: 'getSettings',
+ persistent: false,
+ onSuccess: function(response) {
+ try {
+ loot.settings = JSON.parse(response);
+
+
+ /* Now fill game lists/table. */
+ var gameSelect = document.getElementById('defaultGameSelect');
+ var gameMenu = document.getElementById('gameMenu').firstElementChild;
+ var gameTableBody = document.getElementById('gameTable').getElementsByTagName('tbody')[0];
+ /* Add row for creating new rows. */
+ setupTable(gameTableBody);
+ for (var i = 0; i < loot.settings.games.length; ++i) {
+ var option = document.createElement('option');
+ option.value = loot.settings.games[i].folder;
+ option.textContent = loot.settings.games[i].name;
+ gameSelect.appendChild(option);
+
+ var li = document.createElement('li');
+ li.setAttribute('data-action', 'change-game');
+ li.setAttribute('data-target', loot.settings.games[i].folder);
+ li.textContent = loot.settings.games[i].name;
+ gameMenu.appendChild(li);
+
+ addTableRow(gameTableBody, loot.settings.games[i]);
+ }
+
+ gameSelect.value = loot.settings.game;
+ document.getElementById('languageSelect').value = loot.settings.language;
+ document.getElementById('debugVerbositySelect').value = loot.settings.debugVerbosity;
+ } catch (e) {
+ console.log(e);
+ console.log('Response: ' + response);
+ }
+
+ },
+ onFailure: processCefError
+ });
+ },
+ onFailure: processCefError
});
}
function updateInterfaceWithGameInfo(response) {
@@ -860,10 +886,10 @@ function updateInterfaceWithGameInfo(response) {
// Now set up event handlers, as they depend on the plugin cards having been created.
setupEventHandlers();
}
-function initGameVars() {
+function getGameData() {
// Create and send a new query.
var request_id = window.cefQuery({
- request: 'initGameVars',
+ request: 'getGameData',
persistent: false,
onSuccess: updateInterfaceWithGameInfo,
onFailure: function(error_code, error_message) {
@@ -873,7 +899,7 @@ function initGameVars() {
}
initGlobalVars();
-initGameVars();
+getGameData();
if (isStorageSupported()) {
loadSettings();
}
diff --git a/resources/report/report.html b/resources/report/report.html
index d2e2d540..f576a3e7 100644
--- a/resources/report/report.html
+++ b/resources/report/report.html
@@ -283,6 +283,7 @@ along with LOOT. If not, see <http://www.gnu.org/licenses/>.
Settings
diff --git a/resources/settings.yaml b/resources/settings.yaml
index 8363bbe7..8311c432 100644
--- a/resources/settings.yaml
+++ b/resources/settings.yaml
@@ -1,15 +1,15 @@
# Example Default LOOT Settings File
# This file is written in YAML .
-Language: eng # One of 'eng', 'spa', 'rus' or ''.
+language: eng # One of 'eng', 'spa', 'rus' or ''.
-Game: auto # auto, or one of the 'folder' values below.
-Last Game: auto # auto, or one of the 'folder' values below.
-Debug Verbosity: 0 # 0, 1, 2, 3. Logging takes place if > 0.
-Update Masterlist: true
+game: auto # auto, or one of the 'folder' values below.
+lastGame: auto # auto, or one of the 'folder' values below.
+debugVerbosity: 0 # 0, 1, 2, 3. Logging takes place if > 0.
+updateMasterlist: true
# Games. The four types are 'Oblivion', 'Skyrim', 'Fallout3' and 'FalloutNV'. They correspond to each base game's libespm and libloadorder settings.
-Games:
+games:
- folder: Oblivion
name: "TES IV: Oblivion"
type: Oblivion
diff --git a/src/backend/game.cpp b/src/backend/game.cpp
index b40ffd56..8bfbfbdb 100644
--- a/src/backend/game.cpp
+++ b/src/backend/game.cpp
@@ -44,8 +44,8 @@ namespace loot {
std::vector GetGames(const YAML::Node& settings) {
vector games;
- if (settings["Games"])
- games = settings["Games"].as< vector >();
+ if (settings["games"])
+ games = settings["games"].as< vector >();
if (find(games.begin(), games.end(), Game(Game::tes4)) == games.end())
games.push_back(Game(Game::tes4));
@@ -66,10 +66,10 @@ namespace loot {
string preferredGame(cmdLineGame);
if (preferredGame.empty()) {
// Get preferred game from settings.
- if (settings["Game"] && settings["Game"].as() != "auto")
- preferredGame = settings["Game"].as();
- else if (settings["Last Game"] && settings["Last Game"].as() != "auto")
- preferredGame = settings["Last Game"].as();
+ if (settings["game"] && settings["game"].as() != "auto")
+ preferredGame = settings["game"].as();
+ else if (settings["lastGame"] && settings["lastGame"].as() != "auto")
+ preferredGame = settings["lastGame"].as();
}
// Get index of preferred game if there is one.
diff --git a/src/backend/generators.cpp b/src/backend/generators.cpp
index c45c1a3c..b66ca267 100644
--- a/src/backend/generators.cpp
+++ b/src/backend/generators.cpp
@@ -412,11 +412,11 @@ namespace loot {
YAML::Node root;
std::vector games;
- root["Language"] = "en";
- root["Game"] = "auto";
- root["Last Game"] = "auto";
- root["Debug Verbosity"] = 0;
- root["Update Masterlist"] = true;
+ root["language"] = "en";
+ root["game"] = "auto";
+ root["lastGame"] = "auto";
+ root["debugVerbosity"] = 0;
+ root["updateMasterlist"] = true;
games.push_back(Game(Game::tes4));
games.push_back(Game(Game::tes5));
@@ -424,7 +424,7 @@ namespace loot {
games.push_back(Game(Game::fonv));
games.push_back(Game(Game::tes4, "Nehrim").SetDetails("Nehrim - At Fate's Edge", "Nehrim.esm", "https://github.com/loot/oblivion.git", "master", "", "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Nehrim - At Fate's Edge_is1\\InstallLocation"));
- root["Games"] = games;
+ root["games"] = games;
//Save settings.
YAML::Emitter yout;
diff --git a/src/backend/json.h b/src/backend/json.h
index f6cbb256..b7252d02 100644
--- a/src/backend/json.h
+++ b/src/backend/json.h
@@ -38,7 +38,7 @@ namespace loot {
return YAML::Load(json);
}
- inline static std::string stringify(YAML::Node& yaml) {
+ inline static std::string stringify(const YAML::Node& yaml) {
YAML::Emitter out;
out.SetOutputCharset(YAML::EscapeNonAscii);
diff --git a/src/gui/app.cpp b/src/gui/app.cpp
index 33c302f4..c37df9fb 100644
--- a/src/gui/app.cpp
+++ b/src/gui/app.cpp
@@ -170,8 +170,8 @@ namespace loot {
);
boost::log::add_common_attributes();
unsigned int verbosity;
- if (_settings["Debug Verbosity"]) {
- verbosity = _settings["Debug Verbosity"].as();
+ if (_settings["debugVerbosity"]) {
+ verbosity = _settings["debugVerbosity"].as();
}
if (verbosity == 0)
boost::log::core::get()->set_logging_enabled(false);
@@ -191,8 +191,8 @@ namespace loot {
BOOST_LOG_TRIVIAL(debug) << "Initialising language settings.";
//Defaults in case language string is empty or setting is missing.
string localeId = loot::Language(loot::Language::any).Locale() + ".UTF-8";
- if (_settings["Language"]) {
- loot::Language lang(_settings["Language"].as());
+ if (_settings["language"]) {
+ loot::Language lang(_settings["language"].as());
BOOST_LOG_TRIVIAL(debug) << "Selected language: " << lang.Name();
localeId = lang.Locale() + ".UTF-8";
}
@@ -249,4 +249,11 @@ namespace loot {
Game& LootState::CurrentGame() {
return _games[_currentGame];
}
+
+ const YAML::Node& LootState::GetSettings() const {
+ return _settings;
+ }
+ const YAML::Node& LootState::GetSetting(const std::string& setting) const {
+ return _settings[setting];
+ }
}
\ No newline at end of file
diff --git a/src/gui/app.h b/src/gui/app.h
index 56a4baf4..8bed8f4a 100644
--- a/src/gui/app.h
+++ b/src/gui/app.h
@@ -75,8 +75,13 @@ namespace loot {
LootState();
void Init(const std::string& cmdLineGame);
+
Game& CurrentGame();
+ const YAML::Node& GetSettings() const;
+ const YAML::Node& GetSetting(const std::string& setting) const;
+
+ private:
YAML::Node _settings;
std::vector _games;
size_t _currentGame;
diff --git a/src/gui/handler.cpp b/src/gui/handler.cpp
index f8de31a1..57c91b9b 100644
--- a/src/gui/handler.cpp
+++ b/src/gui/handler.cpp
@@ -69,179 +69,196 @@ namespace loot {
CefRefPtr callback) {
if (request == "openReadme") {
- // Open readme in default application.
- HINSTANCE ret = ShellExecute(0, NULL, ToWinWide(ToFileURL(g_path_readme)).c_str(), NULL, NULL, SW_SHOWNORMAL);
- if ((int)ret > 32)
- callback->Success(request);
- else
- callback->Failure((int)ret, "Shell execute failed.");
+ try {
+ OpenReadme();
+ callback->Success("");
+ }
+ catch (error &e) {
+ callback->Failure(e.code(), e.what());
+ }
+ catch (exception &e) {
+ callback->Failure(-1, e.what());
+ }
return true;
}
else if (request == "openLogLocation") {
- //Open debug log folder.
- HINSTANCE ret = ShellExecute(NULL, L"open", ToWinWide(g_path_log.parent_path().string()).c_str(), NULL, NULL, SW_SHOWNORMAL);
- if ((int)ret > 32)
- callback->Success(request);
- else
- callback->Failure((int)ret, "Shell execute failed.");
- return true;
- }
- else if (request == "initGlobalVars") {
- // Convert the _settings YAML object to a JSON string, and also add members for the LOOT version, game types and languages.
-
- if (g_app_state._games.empty()) {
- BOOST_LOG_TRIVIAL(warning) << "Application state not yet initialised, initialising now...";
- g_app_state.Init("");
- BOOST_LOG_TRIVIAL(info) << "Application state initialised.";
- }
-
- YAML::Node temp;
-
- // LOOT Version
- //-------------
-
- temp["version"] = to_string(g_version_major) + "." + to_string(g_version_minor) + "." + to_string(g_version_patch);
-
- // LOOT Settings
- //--------------
-
- //temp["settings"] = g_app_state._settings;
-
- // Do a bit of translation of key names into more javascript-friendly names.
- // Consider instead making the settings file use the more friendly names itself.
-
- temp["settings"]["debugVerbosity"] = g_app_state._settings["Debug Verbosity"];
- temp["settings"]["game"] = g_app_state._settings["Game"];
- temp["settings"]["games"] = g_app_state._settings["Games"];
- temp["settings"]["language"] = Language(g_app_state._settings["Language"].as()).Name();
- temp["settings"]["lastGame"] = g_app_state._settings["Last Game"];
-
- // LOOT Game Types
- //-----------------
-
- vector gameTypes;
- gameTypes.push_back(Game(Game::tes4).FolderName());
- gameTypes.push_back(Game(Game::tes5).FolderName());
- gameTypes.push_back(Game(Game::fo3).FolderName());
- gameTypes.push_back(Game(Game::fonv).FolderName());
-
- temp["gameTypes"] = gameTypes;
-
- // LOOT Languages
- //---------------
-
- BOOST_LOG_TRIVIAL(debug) << "Setting GUI values for LOOT's languages.";
-
- temp["languages"] = Language::Names();
-
- // Now output as JSON
- //-------------------
-
- callback->Success(JSON::stringify(temp));
-
- return true;
- }
- else if (request == "initGameVars") {
- // Get masterlist revision info and parse if it exists. Also get plugin headers info and parse userlist if it exists.
-
- if (g_app_state._games.empty()) {
- BOOST_LOG_TRIVIAL(warning) << "Application state not yet initialised, initialising now...";
- g_app_state.Init("");
- BOOST_LOG_TRIVIAL(info) << "Application state initialised.";
- }
-
- g_app_state.CurrentGame().LoadPlugins(true);
-
- //Sort plugins into their load order.
- list installed;
- list loadOrder;
- g_app_state.CurrentGame().GetLoadOrder(loadOrder);
- for (const auto &pluginName : loadOrder) {
- const auto pos = g_app_state.CurrentGame().plugins.find(pluginName);
-
- if (pos != g_app_state.CurrentGame().plugins.end())
- installed.push_back(pos->second);
- }
-
- //Parse masterlist, don't update it.
- if (fs::exists(g_app_state.CurrentGame().MasterlistPath())) {
- BOOST_LOG_TRIVIAL(debug) << "Parsing masterlist.";
- g_app_state.CurrentGame().masterlist.MetadataList::Load(g_app_state.CurrentGame().MasterlistPath());
- }
-
- //Parse userlist.
- if (fs::exists(g_app_state.CurrentGame().UserlistPath())) {
- BOOST_LOG_TRIVIAL(debug) << "Parsing userlist.";
- g_app_state.CurrentGame().userlist.Load(g_app_state.CurrentGame().UserlistPath());
- }
-
- // Now convert to a single object that can be turned into a JSON string
- //---------------------------------------------------------------------
-
- // The data structure is to be set as 'loot.game'.
- YAML::Node gameNode;
-
- // ID the game using its folder value.
- gameNode["folder"] = g_app_state.CurrentGame().FolderName();
-
- // Store the masterlist revision and date.
- gameNode["masterlist"]["revision"] = g_app_state.CurrentGame().masterlist.GetRevision(g_app_state.CurrentGame().MasterlistPath());
- gameNode["masterlist"]["date"] = g_app_state.CurrentGame().masterlist.GetDate(g_app_state.CurrentGame().MasterlistPath());
-
- // Now store plugin data.
- for (const auto& plugin : g_app_state.CurrentGame().plugins) {
- // Test data has 'hasUserEdits', and 'tagsAdd', 'tagsRemove' keys, but
- // the first will be handled by userlist lookups, and the other two are probably
- // going to get moved around, haven't decided how best to handle the split between masterlist, userlist and plugin-sourced metadata.
- YAML::Node pluginNode;
- pluginNode["name"] = plugin.second.Name();
- pluginNode["isActive"] = g_app_state.CurrentGame().IsActive(plugin.first);
- pluginNode["isDummy"] = (plugin.second.FormIDs().size() == 0);
- pluginNode["loadsBSA"] = plugin.second.LoadsBSA(g_app_state.CurrentGame());
- pluginNode["crc"] = IntToHexString(plugin.second.Crc());
- pluginNode["version"] = plugin.second.Version();
-
- gameNode["plugins"].push_back(pluginNode);
- }
-
- //Set language.
- unsigned int language;
- if (g_app_state._settings["Language"])
- language = Language(g_app_state._settings["Language"].as()).Code();
- else
- language = loot::Language::any;
-
- BOOST_LOG_TRIVIAL(info) << "Using message language: " << Language(language).Name();
-
- //Evaluate any conditions in the global messages.
- BOOST_LOG_TRIVIAL(debug) << "Evaluating global message conditions.";
try {
- list::iterator it = g_app_state.CurrentGame().masterlist.messages.begin();
- while (it != g_app_state.CurrentGame().masterlist.messages.end()) {
- if (!it->EvalCondition(g_app_state.CurrentGame(), language))
- it = g_app_state.CurrentGame().masterlist.messages.erase(it);
- else
- ++it;
- }
+ OpenLogLocation();
+ callback->Success("");
}
- catch (std::exception& e) {
- BOOST_LOG_TRIVIAL(error) << "A global message contains a condition that could not be evaluated. Details: " << e.what();
- g_app_state.CurrentGame().masterlist.messages.push_back(loot::Message(loot::Message::error, (format(loc::translate("A global message contains a condition that could not be evaluated. Details: %1%")) % e.what()).str()));
+ catch (error &e) {
+ callback->Failure(e.code(), e.what());
+ }
+ catch (exception &e) {
+ callback->Failure(-1, e.what());
}
-
- // Now store global messages from masterlist.
- gameNode["globalMessages"] = g_app_state.CurrentGame().masterlist.messages;
-
- callback->Success(JSON::stringify(gameNode));
-
return true;
-
+ }
+ else if (request == "getVersion") {
+ callback->Success(GetVersion());
+ return true;
+ }
+ else if (request == "getSettings") {
+ callback->Success(GetSettings());
+ return true;
+ }
+ else if (request == "getLanguages") {
+ callback->Success(GetLanguages());
+ return true;
+ }
+ else if (request == "getGameTypes") {
+ callback->Success(GetGameTypes());
+ return true;
+ }
+ else if (request == "getGameData") {
+ callback->Success(GetGameData());
+ return true;
}
return false;
}
+ void Handler::OpenReadme() {
+ BOOST_LOG_TRIVIAL(info) << "Opening LOOT readme.";
+ // Open readme in default application.
+ HINSTANCE ret = ShellExecute(0, NULL, ToWinWide(ToFileURL(g_path_readme)).c_str(), NULL, NULL, SW_SHOWNORMAL);
+ if ((int)ret <= 32)
+ throw error(error::windows_error, "Shell execute failed.");
+ }
+
+ void Handler::OpenLogLocation() {
+ BOOST_LOG_TRIVIAL(info) << "Opening LOOT local appdata folder.";
+ //Open debug log folder.
+ HINSTANCE ret = ShellExecute(NULL, L"open", ToWinWide(g_path_log.parent_path().string()).c_str(), NULL, NULL, SW_SHOWNORMAL);
+ if ((int)ret <= 32)
+ throw error(error::windows_error, "Shell execute failed.");
+ }
+
+ std::string Handler::GetVersion() {
+ BOOST_LOG_TRIVIAL(info) << "Getting LOOT version.";
+ YAML::Node version(to_string(g_version_major) + "." + to_string(g_version_minor) + "." + to_string(g_version_patch));
+ return JSON::stringify(version);
+ }
+
+ std::string Handler::GetSettings() {
+ BOOST_LOG_TRIVIAL(info) << "Getting LOOT settings.";
+ return JSON::stringify(g_app_state.GetSettings());
+ }
+
+ std::string Handler::GetLanguages() {
+ BOOST_LOG_TRIVIAL(info) << "Getting LOOT's supported languages.";
+ // Need to get an array of language names and their corresponding codes.
+ YAML::Node temp;
+ vector names = Language::Names();
+ for (const auto& name : names) {
+ YAML::Node lang;
+ lang["name"] = name;
+ lang["locale"] = Language(name).Locale();
+ temp.push_back(lang);
+ }
+ return JSON::stringify(temp);
+ }
+
+ std::string Handler::GetGameTypes() {
+ BOOST_LOG_TRIVIAL(info) << "Getting LOOT's supported game types.";
+ YAML::Node temp;
+ temp.push_back(Game(Game::tes4).FolderName());
+ temp.push_back(Game(Game::tes5).FolderName());
+ temp.push_back(Game(Game::fo3).FolderName());
+ temp.push_back(Game(Game::fonv).FolderName());
+ return JSON::stringify(temp);
+ }
+
+ std::string Handler::GetGameData() {
+ BOOST_LOG_TRIVIAL(info) << "Getting data specific to LOOT's active game.";
+ // Get masterlist revision info and parse if it exists. Also get plugin headers info and parse userlist if it exists.
+
+ g_app_state.CurrentGame().LoadPlugins(true);
+
+ //Sort plugins into their load order.
+ list installed;
+ list loadOrder;
+ g_app_state.CurrentGame().GetLoadOrder(loadOrder);
+ for (const auto &pluginName : loadOrder) {
+ const auto pos = g_app_state.CurrentGame().plugins.find(pluginName);
+
+ if (pos != g_app_state.CurrentGame().plugins.end())
+ installed.push_back(pos->second);
+ }
+
+ //Parse masterlist, don't update it.
+ if (fs::exists(g_app_state.CurrentGame().MasterlistPath())) {
+ BOOST_LOG_TRIVIAL(debug) << "Parsing masterlist.";
+ g_app_state.CurrentGame().masterlist.MetadataList::Load(g_app_state.CurrentGame().MasterlistPath());
+ }
+
+ //Parse userlist.
+ if (fs::exists(g_app_state.CurrentGame().UserlistPath())) {
+ BOOST_LOG_TRIVIAL(debug) << "Parsing userlist.";
+ g_app_state.CurrentGame().userlist.Load(g_app_state.CurrentGame().UserlistPath());
+ }
+
+ // Now convert to a single object that can be turned into a JSON string
+ //---------------------------------------------------------------------
+
+ // The data structure is to be set as 'loot.game'.
+ YAML::Node gameNode;
+
+ // ID the game using its folder value.
+ gameNode["folder"] = g_app_state.CurrentGame().FolderName();
+
+ // Store the masterlist revision and date.
+ gameNode["masterlist"]["revision"] = g_app_state.CurrentGame().masterlist.GetRevision(g_app_state.CurrentGame().MasterlistPath());
+ gameNode["masterlist"]["date"] = g_app_state.CurrentGame().masterlist.GetDate(g_app_state.CurrentGame().MasterlistPath());
+
+ // Now store plugin data.
+ for (const auto& plugin : g_app_state.CurrentGame().plugins) {
+ // Test data has 'hasUserEdits', and 'tagsAdd', 'tagsRemove' keys, but
+ // the first will be handled by userlist lookups, and the other two are probably
+ // going to get moved around, haven't decided how best to handle the split between masterlist, userlist and plugin-sourced metadata.
+ YAML::Node pluginNode;
+ pluginNode["name"] = plugin.second.Name();
+ pluginNode["isActive"] = g_app_state.CurrentGame().IsActive(plugin.first);
+ pluginNode["isDummy"] = (plugin.second.FormIDs().size() == 0);
+ pluginNode["loadsBSA"] = plugin.second.LoadsBSA(g_app_state.CurrentGame());
+ pluginNode["crc"] = IntToHexString(plugin.second.Crc());
+ pluginNode["version"] = plugin.second.Version();
+
+ gameNode["plugins"].push_back(pluginNode);
+ }
+
+ //Set language.
+ unsigned int language;
+ if (g_app_state.GetSetting("language"))
+ language = Language(g_app_state.GetSetting("language").as()).Code();
+ else
+ language = loot::Language::any;
+
+ BOOST_LOG_TRIVIAL(info) << "Using message language: " << Language(language).Name();
+
+ //Evaluate any conditions in the global messages.
+ BOOST_LOG_TRIVIAL(debug) << "Evaluating global message conditions.";
+ try {
+ list::iterator it = g_app_state.CurrentGame().masterlist.messages.begin();
+ while (it != g_app_state.CurrentGame().masterlist.messages.end()) {
+ if (!it->EvalCondition(g_app_state.CurrentGame(), language))
+ it = g_app_state.CurrentGame().masterlist.messages.erase(it);
+ else
+ ++it;
+ }
+ }
+ catch (std::exception& e) {
+ BOOST_LOG_TRIVIAL(error) << "A global message contains a condition that could not be evaluated. Details: " << e.what();
+ g_app_state.CurrentGame().masterlist.messages.push_back(loot::Message(loot::Message::error, (format(loc::translate("A global message contains a condition that could not be evaluated. Details: %1%")) % e.what()).str()));
+ }
+
+ // Now store global messages from masterlist.
+ gameNode["globalMessages"] = g_app_state.CurrentGame().masterlist.messages;
+
+ return JSON::stringify(gameNode);
+ }
+
// LootHandler methods
//--------------------
diff --git a/src/gui/handler.h b/src/gui/handler.h
index 17874814..b4cf3a85 100644
--- a/src/gui/handler.h
+++ b/src/gui/handler.h
@@ -46,6 +46,14 @@ namespace loot {
const CefString& request,
bool persistent,
CefRefPtr callback) OVERRIDE;
+ private:
+ void OpenReadme();
+ void OpenLogLocation();
+ std::string GetVersion();
+ std::string GetSettings();
+ std::string GetLanguages();
+ std::string GetGameTypes();
+ std::string GetGameData();
};
class LootHandler : public CefClient,
diff --git a/src/gui/main_win.cpp b/src/gui/main_win.cpp
index 38553f03..8071159c 100644
--- a/src/gui/main_win.cpp
+++ b/src/gui/main_win.cpp
@@ -51,14 +51,14 @@ CefSettings GetCefSettings() {
// Don't set CEF locale, as it tries to load resources and crashes
// if they can't be found.
- /*if (_settings["Language"]) {
- loot::Language lang(_settings["Language"].as());
+ /*if (_settings["language"]) {
+ loot::Language lang(_settings["language"].as());
CefString(&cef_settings.locale).FromString(lang.Locale());
}*/
// Set CEF logging.
CefString(&cef_settings.log_file).FromString("CEFDebugLog.txt");
- /*if (!_settings["Debug Verbosity"] || _settings["Debug Verbosity"].as() == 0)
+ /*if (!_settings["debugVerbosity"] || _settings["debugVerbosity"].as() == 0)
cef_settings.log_severity = LOGSEVERITY_DISABLE;
*/
// Enable remote debugging.