diff --git a/resources/report/js/script.js b/resources/report/js/script.js
index 9100a0e9..ee23c87d 100644
--- a/resources/report/js/script.js
+++ b/resources/report/js/script.js
@@ -277,7 +277,7 @@ function addNewTableRow(evt) {
/* Add deletion listener. */
row.getElementsByClassName('fa-trash-o')[0].addEventListener('click', removeTableRow, false);
}
-function addTableRow(tableBody, data) {
+function addTableRow(tableBody, tableData) {
var rowTemplateId = tableBody.getAttribute('data-template');
var content = document.getElementById(rowTemplateId).content;
var row = document.importNode(content, true);
@@ -285,8 +285,8 @@ function addTableRow(tableBody, data) {
row = tableBody.lastElementChild.previousElementSibling;
/* Data is an object with keys that match element class names. */
- for (var key in data) {
- row.getElementsByClassName(key)[0].value = data[key];
+ for (var key in tableData) {
+ row.getElementsByClassName(key)[0].value = tableData[key];
}
/* Enable row editing. */
@@ -624,6 +624,12 @@ 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. */
@@ -677,6 +683,26 @@ function initUI() {
settingsLangSelect.value = loot.settings.language;
debugVerbositySelect.value = loot.settings.debugVerbosity;
}
+var loot;
+function initJavascriptVars() {
+ // Create and send a new query.
+ var request_id = window.cefQuery({
+ request: 'initJavascriptVars',
+ persistent: false,
+ onSuccess: function(response) {
+ try {
+ loot = JSON.parse(response);
+ } 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);
+ }
+ });
+}
function processURLParams() {
/* Get the data path from the URL and load it. */
/*var pos = document.URL.indexOf("?data=");*/
@@ -691,7 +717,6 @@ function processURLParams() {
var activePluginNo = 0;
var dirtyPluginNo = 0;
/* Fill report with data. */
- document.getElementById('LOOTVersion').textContent = loot.version;
document.getElementById('masterlistRevision').textContent = data.masterlist.revision.substr(0, 9);
document.getElementById('masterlistDate').textContent = data.masterlist.date;
var generalMessagesList = document.getElementById('generalMessages').getElementsByTagName('ul')[0];
@@ -829,7 +854,7 @@ function processURLParams() {
}
/* Now initialise the rest of the report. */
- initUI();
+ initJavascriptVars();
setupEventHandlers();
if (isStorageSupported()) {
loadSettings();
diff --git a/resources/report/report.html b/resources/report/report.html
index 6f0a69e0..d2e2d540 100644
--- a/resources/report/report.html
+++ b/resources/report/report.html
@@ -55,11 +55,11 @@
- |
- |
+ |
+ |
|
|
- |
+ |
|
diff --git a/src/gui/app.cpp b/src/gui/app.cpp
index d39cfd61..dec06baf 100644
--- a/src/gui/app.cpp
+++ b/src/gui/app.cpp
@@ -51,11 +51,90 @@ namespace fs = boost::filesystem;
namespace loot {
+ LootState g_app_state = LootState();
+
LootApp::LootApp() {}
- void LootApp::Init(std::string& cmdLineGame) {
- string initError;
+ CefRefPtr LootApp::GetBrowserProcessHandler() {
+ return this;
+ }
+
+ CefRefPtr LootApp::GetRenderProcessHandler() {
+ return this;
+ }
+
+ void LootApp::OnContextInitialized() {
+ //Make sure this is running in the UI thread.
+ assert(CefCurrentlyOn(TID_UI));
+
+ // Information used when creating the native window.
+ CefWindowInfo window_info;
+
+#if _WIN32 || _WIN64
+ // On Windows we need to specify certain flags that will be passed to CreateWindowEx().
+ window_info.SetAsPopup(NULL, "LOOT");
+#endif
+
+ // Set the handler for browser-level callbacks.
+ CefRefPtr handler(new LootHandler());
+
+ // Specify CEF browser settings here.
+ CefBrowserSettings browser_settings;
+
+ // Set URL to load. Ignore any command line values.
+ std::string url = ToFileURL(g_path_report);
+
+ // Create the first browser window.
+ CefBrowserHost::CreateBrowser(window_info, handler.get(), url, browser_settings, NULL);
+ }
+
+ void LootApp::OnWebKitInitialized() {
+ // Create the renderer-side router for query handling.
+ CefMessageRouterConfig config;
+ message_router_ = CefMessageRouterRendererSide::Create(config);
+ }
+
+ bool LootApp::OnProcessMessageReceived(
+ CefRefPtr browser,
+ CefProcessId source_process,
+ CefRefPtr message) {
+ // Handle IPC messages from the browser process...
+ return message_router_->OnProcessMessageReceived(browser, source_process, message);
+ }
+
+
+ void LootApp::OnContextCreated(CefRefPtr browser,
+ CefRefPtr frame,
+ CefRefPtr context) {
+
+ _context = context;
+
+ // Register javascript functions.
+ message_router_->OnContextCreated(browser, frame, context);
+ }
+
+ void LootApp::OnContextReleased(CefRefPtr browser,
+ CefRefPtr frame,
+ CefRefPtr context) {
+
+ _context = NULL;
+ }
+
+ void LootApp::InitJSVars() {
+ BOOST_LOG_TRIVIAL(debug) << "Populating JS object variable initial values.";
+
+ if (_context == NULL)
+ return;
+
+ }
+
+ // LootState member functions
+ //---------------------------
+
+ void LootState::Init(const std::string& cmdLineGame) {
+ string initError;
+
//Load settings.
if (!fs::exists(g_path_settings)) {
try {
@@ -126,10 +205,8 @@ namespace loot {
cout.imbue(locale());
boost::filesystem::path::imbue(locale());
- // Detect Games
- //-------------
-
- int gameIndex = -1;
+ // Detect games & select startup game
+ //-----------------------------------
//Detect installed games.
BOOST_LOG_TRIVIAL(debug) << "Detecting installed games.";
@@ -149,200 +226,23 @@ namespace loot {
BOOST_LOG_TRIVIAL(debug) << "Selecting game.";
- if (cmdLineGame.empty()) {
- if (_settings["Game"] && _settings["Game"].as() != "auto")
- cmdLineGame = _settings["Game"].as();
- else if (_settings["Last Game"] && _settings["Last Game"].as() != "auto")
- cmdLineGame = _settings["Last Game"].as();
+ size_t gameIndex(0);
+ try {
+ gameIndex = SelectGame(_settings, _games, cmdLineGame);
}
-
- if (!cmdLineGame.empty()) {
- for (size_t i = 0, max = _games.size(); i < max; ++i) {
- if (cmdLineGame == _games[i].FolderName() && _games[i].IsInstalled())
- gameIndex = i;
- }
+ catch (exception &) {
+ BOOST_LOG_TRIVIAL(error) << "None of the supported games were detected.";
}
- if (gameIndex < 0) {
- //Set gameIndex to the first installed game.
- for (size_t i = 0, max = _games.size(); i < max; ++i) {
- if (_games[i].IsInstalled()) {
- gameIndex = i;
- break;
- }
- }
- if (gameIndex < 0) {
- BOOST_LOG_TRIVIAL(error) << "None of the supported games were detected.";
- initError = translate("Error: None of the supported games were detected.").str();
- return;
- }
- }
- loot::Game& game(_games[gameIndex]);
- BOOST_LOG_TRIVIAL(debug) << "Game selected is " << game.Name();
+ BOOST_LOG_TRIVIAL(debug) << "Game selected is " << _games[gameIndex].Name();
//Now that game is selected, initialise it.
BOOST_LOG_TRIVIAL(debug) << "Initialising game-specific settings.";
try {
- game.Init();
- *find(_games.begin(), _games.end(), game) = game; //Sync changes.
+ _games[gameIndex].Init();
}
catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "Game-specific settings could not be initialised. " << e.what();
- initError = (format(translate("Error: Game-specific settings could not be initialised. %1%")) % e.what()).str();
- return;
}
}
- CefRefPtr LootApp::GetBrowserProcessHandler() {
- return this;
- }
-
- CefRefPtr LootApp::GetRenderProcessHandler() {
- return this;
- }
-
- void LootApp::OnContextInitialized() {
- //Make sure this is running in the UI thread.
- assert(CefCurrentlyOn(TID_UI));
-
- // Information used when creating the native window.
- CefWindowInfo window_info;
-
-#if _WIN32 || _WIN64
- // On Windows we need to specify certain flags that will be passed to CreateWindowEx().
- window_info.SetAsPopup(NULL, "LOOT");
-#endif
-
- // Set the handler for browser-level callbacks.
- CefRefPtr handler(new LootHandler());
-
- // Specify CEF browser settings here.
- CefBrowserSettings browser_settings;
-
- // Set URL to load. Ignore any command line values.
- std::string url = ToFileURL(g_path_report);
-
- // Create the first browser window.
- CefBrowserHost::CreateBrowser(window_info, handler.get(), url, browser_settings, NULL);
- }
-
- void LootApp::OnWebKitInitialized() {
- // Create the renderer-side router for query handling.
- CefMessageRouterConfig config;
- message_router_ = CefMessageRouterRendererSide::Create(config);
- }
-
- bool LootApp::OnProcessMessageReceived(
- CefRefPtr browser,
- CefProcessId source_process,
- CefRefPtr message) {
- // Handle IPC messages from the browser process...
- return message_router_->OnProcessMessageReceived(browser, source_process, message);
- }
-
-
- void LootApp::OnContextCreated(CefRefPtr browser,
- CefRefPtr frame,
- CefRefPtr context) {
-
- // Register javascript functions.
- message_router_->OnContextCreated(browser, frame, context);
-
- _context = context;
- }
-
- void LootApp::OnContextReleased(CefRefPtr browser,
- CefRefPtr frame,
- CefRefPtr context) {
-
- _context = NULL;
- }
-
- void LootApp::InitJSVars() {
- BOOST_LOG_TRIVIAL(debug) << "Populating JS object variable initial values.";
-
- if (_context == NULL)
- return;
-
- // Retrieve the context's window object.
- CefRefPtr object = _context->GetGlobal();
-
- // Here the initialisation values should be set.
-
- CefRefPtr lootObj = CefV8Value::CreateObject(NULL);
-
- // LOOT Version
- //-------------
-
- lootObj->SetValue("version", CefV8Value::CreateString(to_string(g_version_major) + "." + to_string(g_version_minor) + "." + to_string(g_version_patch)), V8_PROPERTY_ATTRIBUTE_NONE);
-
- // LOOT Settings
- //--------------
-
- BOOST_LOG_TRIVIAL(debug) << "Setting GUI values for LOOT's settings.";
-
- CefRefPtr settingsObj = CefV8Value::CreateObject(NULL);
-
- if (_settings["Language"])
- settingsObj->SetValue("language", CefV8Value::CreateString(Language(_settings["Language"].as()).Name()), V8_PROPERTY_ATTRIBUTE_NONE);
-
- if (_settings["Update Masterlist"])
- settingsObj->SetValue("updateMasterlist", CefV8Value::CreateBool(_settings["Update Masterlist"].as()), V8_PROPERTY_ATTRIBUTE_NONE);
-
- if (_settings["Debug Verbosity"])
- settingsObj->SetValue("debugVerbosity", CefV8Value::CreateInt(_settings["Debug Verbosity"].as()), V8_PROPERTY_ATTRIBUTE_NONE);
-
- if (_settings["Game"])
- settingsObj->SetValue("game", CefV8Value::CreateString(_settings["Game"].as()), V8_PROPERTY_ATTRIBUTE_NONE);
-
- vector games = GetGames(_settings);
- CefRefPtr gamesArr = CefV8Value::CreateArray(games.size());
- for (int i = 0; i < games.size(); ++i) {
- CefRefPtr gameObj = CefV8Value::CreateObject(NULL);
-
- gameObj->SetValue("type", CefV8Value::CreateString(loot::Game(games[i].Id()).FolderName()), V8_PROPERTY_ATTRIBUTE_NONE);
- gameObj->SetValue("name", CefV8Value::CreateString(games[i].Name()), V8_PROPERTY_ATTRIBUTE_NONE);
- gameObj->SetValue("folder", CefV8Value::CreateString(games[i].FolderName()), V8_PROPERTY_ATTRIBUTE_NONE);
- gameObj->SetValue("masterFile", CefV8Value::CreateString(games[i].Master()), V8_PROPERTY_ATTRIBUTE_NONE);
- gameObj->SetValue("url", CefV8Value::CreateString(games[i].RepoURL()), V8_PROPERTY_ATTRIBUTE_NONE);
- gameObj->SetValue("branch", CefV8Value::CreateString(games[i].RepoBranch()), V8_PROPERTY_ATTRIBUTE_NONE);
- gameObj->SetValue("path", CefV8Value::CreateString(games[i].GamePath().string()), V8_PROPERTY_ATTRIBUTE_NONE);
- gameObj->SetValue("registryKey", CefV8Value::CreateString(games[i].RegistryKey()), V8_PROPERTY_ATTRIBUTE_NONE);
-
- gamesArr->SetValue(i, gameObj);
- }
- settingsObj->SetValue("games", gamesArr, V8_PROPERTY_ATTRIBUTE_NONE);
-
- lootObj->SetValue("settings", settingsObj, V8_PROPERTY_ATTRIBUTE_NONE);
-
- // LOOT Game Types
- //----------------
-
- BOOST_LOG_TRIVIAL(debug) << "Setting GUI values for LOOT's game types.";
-
- CefRefPtr gameTypesArr = CefV8Value::CreateArray(4);
- gameTypesArr->SetValue(0, CefV8Value::CreateString(Game(Game::tes4).FolderName()));
- gameTypesArr->SetValue(1, CefV8Value::CreateString(Game(Game::tes5).FolderName()));
- gameTypesArr->SetValue(2, CefV8Value::CreateString(Game(Game::fo3).FolderName()));
- gameTypesArr->SetValue(3, CefV8Value::CreateString(Game(Game::fonv).FolderName()));
-
- lootObj->SetValue("gameTypes", gameTypesArr, V8_PROPERTY_ATTRIBUTE_NONE);
-
- // LOOT Languages
- //---------------
-
- BOOST_LOG_TRIVIAL(debug) << "Setting GUI values for LOOT's languages.";
-
- vector langs = Language::Names();
- CefRefPtr langsArr = CefV8Value::CreateArray(langs.size());
- for (int i = 0; i < langs.size(); ++i) {
- langsArr->SetValue(i, CefV8Value::CreateString(langs[i]));
- }
-
- lootObj->SetValue("languages", langsArr, V8_PROPERTY_ATTRIBUTE_NONE);
-
- // Load Order
- //-----------
-
- object->SetValue("loot", lootObj, V8_PROPERTY_ATTRIBUTE_NONE);
- }
}
\ No newline at end of file
diff --git a/src/gui/app.h b/src/gui/app.h
index 2ce350ef..c5bf8f7b 100644
--- a/src/gui/app.h
+++ b/src/gui/app.h
@@ -40,8 +40,6 @@ namespace loot {
public:
LootApp();
- void Init(std::string& cmdLineGame);
-
// Override CefApp methods.
virtual CefRefPtr GetBrowserProcessHandler() OVERRIDE;
virtual CefRefPtr GetRenderProcessHandler() OVERRIDE;
@@ -69,12 +67,19 @@ namespace loot {
CefRefPtr _context;
- YAML::Node _settings;
- std::vector _games;
-
IMPLEMENT_REFCOUNTING(LootApp);
};
+ class LootState {
+ public:
+
+ void Init(const std::string& cmdLineGame);
+
+ YAML::Node _settings;
+ std::vector _games;
+ };
+
+ extern LootState g_app_state;
}
#endif
\ No newline at end of file
diff --git a/src/gui/handler.cpp b/src/gui/handler.cpp
index d6adfca8..cc413984 100644
--- a/src/gui/handler.cpp
+++ b/src/gui/handler.cpp
@@ -24,23 +24,28 @@
#include "handler.h"
#include "resource.h"
+#include "app.h"
#include
#include
#include
+#include
+
#include
#include
#include
+using namespace std;
+
namespace loot {
namespace {
LootHandler * g_instance = NULL;
}
- // Handler methods
- //----------------
+ // WinHandler methods
+ //-------------------
Handler::Handler() {}
@@ -52,8 +57,7 @@ namespace loot {
bool persistent,
CefRefPtr callback) {
- const std::string& message_name = request;
- if (message_name == "openReadme") {
+ 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)
@@ -62,7 +66,7 @@ namespace loot {
callback->Failure((int)ret, "Shell execute failed.");
return true;
}
- else if (message_name == "openLogLocation") {
+ 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)
@@ -71,10 +75,84 @@ namespace loot {
callback->Failure((int)ret, "Shell execute failed.");
return true;
}
+ else if (request == "initJavascriptVars") {
+ // 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.
+
+ YAML::Emitter tempout;
+ tempout.SetOutputCharset(YAML::EscapeNonAscii);
+ tempout.SetStringFormat(YAML::DoubleQuoted);
+ tempout.SetBoolFormat(YAML::TrueFalseBool);
+ tempout.SetSeqFormat(YAML::Flow);
+ tempout.SetMapFormat(YAML::Flow);
+
+ tempout << temp;
+
+ // yaml-cpp produces `!` artifacts in its output, so remove them.
+ std::string json = tempout.c_str();
+ boost::replace_all(json, "!", "");
+ // There's also a bit of weirdness where there are some \x escapes and some \u escapes.
+ // They should all be \u, so transform them.
+ boost::replace_all(json, "\\x", "\\u00");
+
+ callback->Success(json);
+
+ return true;
+ }
return false;
}
+
+ // LootHandler methods
+ //--------------------
+
LootHandler::LootHandler() : is_closing_(false) {
assert(!g_instance);
g_instance = this;
diff --git a/src/gui/main_win.cpp b/src/gui/main_win.cpp
index e3354ee4..38553f03 100644
--- a/src/gui/main_win.cpp
+++ b/src/gui/main_win.cpp
@@ -121,6 +121,8 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmd
gameStr = command_line->GetSwitchValue("game");
}
+ loot::g_app_state.Init(gameStr);
+
// Back to CEF
//------------
@@ -133,8 +135,6 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmd
// Do application init
//--------------------
- app.get()->Init(gameStr);
-
// Run the CEF message loop. This will block until CefQuitMessageLoop() is called.
CefRunMessageLoop();
|