diff --git a/CMakeLists.txt b/CMakeLists.txt index 1822b160..6a45d545 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ cmake_minimum_required (VERSION 2.8.9) project (boss) -set (BOSS_SRC "${CMAKE_SOURCE_DIR}/src/backend/metadata.cpp" "${CMAKE_SOURCE_DIR}/src/backend/game.cpp" "${CMAKE_SOURCE_DIR}/src/backend/helpers.cpp" "${CMAKE_SOURCE_DIR}/src/backend/network.cpp" "${PROJECT_LIBS_DIR}/pugixml/src/pugixml.cpp") +set (BOSS_SRC "${CMAKE_SOURCE_DIR}/src/backend/metadata.cpp" "${CMAKE_SOURCE_DIR}/src/backend/game.cpp" "${CMAKE_SOURCE_DIR}/src/backend/helpers.cpp" "${CMAKE_SOURCE_DIR}/src/backend/network.cpp" "${CMAKE_SOURCE_DIR}/src/backend/globals.cpp" "${PROJECT_LIBS_DIR}/pugixml/src/pugixml.cpp") # Include source and library directories. include_directories ("${PROJECT_LIBS_DIR}/alphanum" "${PROJECT_LIBS_DIR}/boost" "${PROJECT_LIBS_DIR}/yaml-cpp/include" "${CMAKE_SOURCE_DIR}/src" "${PROJECT_LIBS_DIR}/libloadorder/src" "${PROJECT_LIBS_DIR}/libespm" "${PROJECT_LIBS_DIR}/zlib" "${PROJECT_LIBS_DIR}/pugixml/src" "${PROJECT_LIBS_DIR}/wxWidgets/include") diff --git a/src/backend/game.cpp b/src/backend/game.cpp index 5e02c0cd..754c8397 100644 --- a/src/backend/game.cpp +++ b/src/backend/game.cpp @@ -57,7 +57,7 @@ namespace boss { return games; } - Game::Game() : id(0) {} + Game::Game() : id(GAME_AUTODETECT) {} Game::Game(const std::string& folder) : bossFolderName(folder) {} @@ -206,15 +206,15 @@ namespace boss { } fs::path Game::MasterlistPath() const { - return fs::path(bossFolderName) / "masterlist.yaml"; + return local_path / bossFolderName / "masterlist.yaml"; } fs::path Game::UserlistPath() const { - return fs::path(bossFolderName) / "userlist.yaml"; + return local_path / bossFolderName / "userlist.yaml"; } fs::path Game::ReportPath() const { - return fs::path(bossFolderName) / "report.html"; + return local_path / bossFolderName / "report.html"; } void Game::RefreshActivePluginsList() { @@ -329,8 +329,8 @@ namespace boss { void Game::CreateBOSSGameFolder() { //Make sure that the BOSS game path exists. try { - if (!fs::exists(bossFolderName)) - fs::create_directory(bossFolderName); + if (!fs::exists(local_path / bossFolderName)) + fs::create_directory(local_path / bossFolderName); } catch (fs::filesystem_error& e) { throw error(ERROR_PATH_WRITE_FAIL, "Could not create BOSS folder for game."); } diff --git a/src/backend/generators.h b/src/backend/generators.h index ac71d327..f4bbcd59 100644 --- a/src/backend/generators.h +++ b/src/backend/generators.h @@ -26,6 +26,7 @@ #include "helpers.h" #include "metadata.h" #include "globals.h" +#include "parsers.h" #include #include @@ -36,6 +37,8 @@ namespace boss { + //BOSS Report generation stuff. + struct xml_string_writer: pugi::xml_writer { std::string result; @@ -477,7 +480,38 @@ namespace boss { throw boss::error(ERROR_PATH_WRITE_FAIL, "Could not write BOSS report."); } + + //Default settings file generation. + + inline void GenerateDefaultSettingsFile(const std::string& file) { + + YAML::Node root; + std::vector games; + + root["Language"] = "eng"; + root["Game"] = "auto"; + root["Last Game"] = "auto"; + root["Debug Verbosity"] = 0; + root["Update Masterlist"] = true; + root["View Report Externally"] = false; + + games.push_back(Game(GAME_TES4)); + games.push_back(Game(GAME_TES5)); + games.push_back(Game(GAME_FO3)); + games.push_back(Game(GAME_FONV)); + games.push_back(Game(GAME_TES4, "Nehrim").SetDetails("Nehrim - At Fate's Edge", "Nehrim.esm", "http://better-oblivion-sorting-software.googlecode.com/svn/data/boss-nehrim/masterlist.yaml", "", "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Nehrim - At Fate's Edge_is1")); + + root["Games"] = games; + + //Save settings. + YAML::Emitter yout; + yout.SetIndent(2); + yout << root; + std::ofstream out(file.c_str()); + out << yout.c_str(); + out.close(); + } } #endif diff --git a/src/backend/globals.h b/src/backend/globals.h index 5e523bb5..fa7492b3 100644 --- a/src/backend/globals.h +++ b/src/backend/globals.h @@ -28,33 +28,34 @@ namespace boss { //Game values. - const unsigned int GAME_AUTODETECT = 0; - const unsigned int GAME_TES4 = 1; - const unsigned int GAME_TES5 = 2; - const unsigned int GAME_FO3 = 3; - const unsigned int GAME_FONV = 4; + extern const unsigned int GAME_AUTODETECT; + extern const unsigned int GAME_TES4; + extern const unsigned int GAME_TES5; + extern const unsigned int GAME_FO3; + extern const unsigned int GAME_FONV; //Message types. - const unsigned int MESSAGE_SAY = 0; - const unsigned int MESSAGE_WARN = 1; - const unsigned int MESSAGE_ERROR = 2; - const unsigned int MESSAGE_TAG = 3; + extern const unsigned int MESSAGE_SAY; + extern const unsigned int MESSAGE_WARN; + extern const unsigned int MESSAGE_ERROR; + extern const unsigned int MESSAGE_TAG; //Languages - const unsigned int LANG_AUTO = 0; - const unsigned int LANG_ENG = 1; + extern const unsigned int LANG_AUTO; + extern const unsigned int LANG_ENG; //Version numbers. - const unsigned int VERSION_MAJOR = 3; - const unsigned int VERSION_MINOR = 0; - const unsigned int VERSION_PATCH = 0; + extern const unsigned int VERSION_MAJOR; + extern const unsigned int VERSION_MINOR; + extern const unsigned int VERSION_PATCH; //Common paths. - const boost::filesystem::path readme_path = "Docs/BOSS Readme.html"; - const boost::filesystem::path settings_path = "resources/settings.yaml"; - const boost::filesystem::path libespm_options_path = "resources/libespm.yaml"; - const boost::filesystem::path svn_path = "resources/svn/svn.exe"; - const boost::filesystem::path log_path = "BOSSDebugLog.txt"; + extern const boost::filesystem::path local_path; + extern const boost::filesystem::path readme_path; + extern const boost::filesystem::path settings_path; + extern const boost::filesystem::path libespm_options_path; + extern const boost::filesystem::path svn_path; + extern const boost::filesystem::path log_path; } #endif diff --git a/src/backend/helpers.cpp b/src/backend/helpers.cpp index f6ba8890..4db36650 100644 --- a/src/backend/helpers.cpp +++ b/src/backend/helpers.cpp @@ -205,6 +205,22 @@ namespace boss { #endif } + boost::filesystem::path GetLocalAppDataPath() { +#if _WIN32 || _WIN64 + HWND owner; + TCHAR path[MAX_PATH]; + + HRESULT res = SHGetFolderPath(owner, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, path); + + if (res == S_OK) + return fs::path(path); + else + return fs::path(""); +#else + return fs::path(""); +#endif + } + ////////////////////////////// // Version Class Functions diff --git a/src/backend/helpers.h b/src/backend/helpers.h index 4a72872a..df8a073f 100644 --- a/src/backend/helpers.h +++ b/src/backend/helpers.h @@ -63,6 +63,9 @@ namespace boss { //Get registry subkey value string. std::string RegKeyStringValue(const std::string& keyStr, const std::string& subkey, const std::string& value); + //Get the local application data path. + boost::filesystem::path GetLocalAppDataPath(); + //Version class for more robust version comparisons. class Version { private: diff --git a/src/backend/network.cpp b/src/backend/network.cpp index 261f8335..27bc19df 100644 --- a/src/backend/network.cpp +++ b/src/backend/network.cpp @@ -112,17 +112,17 @@ namespace boss { string command, output; //First check if the working copy is set up or not. - command = svn_path.string() + " info " + game.MasterlistPath().parent_path().string(); + command = svn_path.string() + " info \"" + game.MasterlistPath().parent_path().string() + "\""; if (!RunCommand(command, output)) { //Working copy not set up, perform a checkout. - command = svn_path.string() + " co --depth empty " + game.URL().substr(0, game.URL().rfind('/')) + " " + game.MasterlistPath().parent_path().string() + "/."; + command = svn_path.string() + " co --depth empty " + game.URL().substr(0, game.URL().rfind('/')) + " \"" + game.MasterlistPath().parent_path().string() + "\\.\""; if (!RunCommand(command, output)) throw error(ERROR_SUBVERSION_ERROR, "Subversion could not perform a checkout. Details: " + output); } //Now update masterlist. - command = svn_path.string() + " update " + game.MasterlistPath().string(); + command = svn_path.string() + " update \"" + game.MasterlistPath().string() + "\""; if (!RunCommand(command, output)) throw error(ERROR_SUBVERSION_ERROR, "Subversion could not update the masterlist. Details: " + output); @@ -135,14 +135,14 @@ namespace boss { } catch (YAML::Exception& e) { //Roll back one revision if there's an error. parsingErrors.push_back(e.what()); - command = svn_path.string() + " update --revision PREV " + game.MasterlistPath().string(); + command = svn_path.string() + " update --revision PREV \"" + game.MasterlistPath().string() + "\""; if (!RunCommand(command, output)) throw error(ERROR_SUBVERSION_ERROR, "Subversion could not update the masterlist. Details: " + output); } } //Now get the masterlist revision. Can either create a pipe using the Win32 API (http://msdn.microsoft.com/en-us/library/ms682499.aspx), or output to a file, read it, then delete it. - command = svn_path.string() + " info " + game.MasterlistPath().string(); + command = svn_path.string() + " info \"" + game.MasterlistPath().string() + "\""; if (!RunCommand(command, output)) throw error(ERROR_SUBVERSION_ERROR, "Subversion could not read the masterlist revision number. Details: " + output); diff --git a/src/gui/main.cpp b/src/gui/main.cpp index f240804f..df50ce72 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -91,6 +91,19 @@ bool BossGUI::OnInit() { NULL); return false; } + } else { + try { + if (!fs::exists(settings_path.parent_path())) + fs::create_directory(settings_path.parent_path()); + } catch (fs::filesystem_error& e) { + wxMessageBox( + translate("Error: Could not create local app data BOSS folder."), + translate("BOSS: Error"), + wxOK | wxICON_ERROR, + NULL); + return false; + } + GenerateDefaultSettingsFile(settings_path.string()); } //Skip logging initialisation for tester. @@ -318,9 +331,11 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { time_t t0 = time(NULL); - ofstream out("out.txt"); + ofstream out((local_path / "out.txt").string().c_str()); out << "Updating masterlist..." << endl; + time_t start, end; + start = time(NULL); vector parsingErrors; string revision; @@ -336,8 +351,11 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { return; } + end = time(NULL); + out << "Time taken to update masterlist: " << (end - start) << " seconds." << endl; + start = time(NULL); + out << "Reading plugins in Data folder..." << endl; - time_t start, end; start = time(NULL); // Get a list of the plugins.