diff --git a/README.md b/README.md index 97cf41ad..e24fd401 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,6 @@ LOOT requires the following libraries (version numbers used in latest developmen * [Libgit2](http://libgit2.github.com/) v0.20.0 * [Libloadorder](http://github.com/WrinklyNinja/libloadorder) * [OpenSSL](https://www.openssl.org) - only if HTTPS support in libgit2 is required using compilers other than MSVC. -* [PugiXML](http://pugixml.org/) v1.4 * [wxWidgets](http://www.wxwidgets.org) v3.0.0 * [yaml-cpp](http://github.com/WrinklyNinja/yaml-cpp) * [zlib](http://zlib.net/) v1.2.8 diff --git a/src/backend/game.cpp b/src/backend/game.cpp index 947d0834..fd2646f7 100644 --- a/src/backend/game.cpp +++ b/src/backend/game.cpp @@ -229,8 +229,8 @@ namespace loot { return g_path_local / lootFolderName / "userlist.yaml"; } - fs::path Game::ReportPath() const { - return g_path_local / lootFolderName / "report.html"; + fs::path Game::ReportDataPath() const { + return g_path_local / lootFolderName / "reportdata.js"; } void Game::RefreshActivePluginsList() { diff --git a/src/backend/game.h b/src/backend/game.h index a398d40c..2574306a 100644 --- a/src/backend/game.h +++ b/src/backend/game.h @@ -79,7 +79,7 @@ namespace loot { boost::filesystem::path DataPath() const; boost::filesystem::path MasterlistPath() const; boost::filesystem::path UserlistPath() const; - boost::filesystem::path ReportPath() const; + boost::filesystem::path ReportDataPath() const; //Game plugin functions. diff --git a/src/backend/generators.cpp b/src/backend/generators.cpp index 81e57b8f..30a6a316 100644 --- a/src/backend/generators.cpp +++ b/src/backend/generators.cpp @@ -28,8 +28,6 @@ along with LOOT. If not, see #include "parsers.h" #include "streams.h" -#include - #include #include @@ -63,30 +61,14 @@ namespace loot { return ""; } - struct xml_string_writer : pugi::xml_writer { - std::string result; + void WriteMessage(YAML::Emitter& out, const Message& message) { - virtual void write(const void* data, size_t size) { - result += std::string(static_cast(data), size); - } - }; - - void WriteMessage(pugi::xml_node& listItem, unsigned int type, std::string content) { - - if (type == Message::say) - content = boost::locale::translate("Note:").str() + " " + content; - else if (type == Message::tag) { - content = boost::locale::translate("Bash Tag Suggestion(s):").str() + " " + content; - } - else if (type == Message::warn) - content = boost::locale::translate("Warning:").str() + " " + content; - else - content = boost::locale::translate("Error:").str() + " " + content; - - //Now look for Markdown URL syntax and convert any found. + //Look for Markdown URL syntax and convert any found. boost::regex regex("(\\[([^\\]]+)\\]\\s?\\(|<)((file|https?)://\\S+)(\\)|>)", boost::regex::perl | boost::regex::icase); // \2 is the label, \3 is the URL. boost::match_results results; + std::string content = message.Content().front().Str(); + std::string converted; std::string::iterator start, end; start = content.begin(); end = content.end(); @@ -103,459 +85,112 @@ namespace loot { label = url; //Insert normal text preceding hyperlink. - listItem.append_child(pugi::node_pcdata).set_value(std::string(results.prefix().first, results.prefix().second).c_str()); + converted += std::string(results.prefix().first, results.prefix().second); //Insert hyperlink. - pugi::xml_node a = listItem.append_child(); - a.set_name("a"); - a.append_attribute("href").set_value(url.c_str()); - a.text().set(label.c_str()); + converted += "" + label + ""; //Set string to end of matched section. start = results.suffix().first; } //Insert any leftover text. - listItem.append_child(pugi::node_pcdata).set_value(std::string(start, end).c_str()); + converted += std::string(start, end); + //Now emit as YAML. + out << YAML::BeginMap; + + if (message.Type() == Message::say) { + out << YAML::Key << "type" << YAML::Value << "say"; + converted = boost::locale::translate("Note:").str() + " " + converted; + } + else if (message.Type() == Message::warn) { + out << YAML::Key << "type" << YAML::Value << "warn"; + converted = boost::locale::translate("Warning:").str() + " " + converted; + } + else { + out << YAML::Key << "type" << YAML::Value << "error"; + converted = boost::locale::translate("Error:").str() + " " + converted; + } + + out << YAML::Key << "content" << YAML::Value << converted; + + out << YAML::EndMap; } - void GenerateHead(pugi::xml_document& doc) { - BOOST_LOG_TRIVIAL(trace) << "Creating LOOT report head."; + void WritePlugin(YAML::Emitter& out, const Plugin& plugin) { + out << YAML::BeginMap; - //Add DOCTYPE node. - doc.append_child(pugi::node_doctype).set_value("html"); + out << YAML::Key << "name" + << YAML::Value << plugin.Name(); - //Create 'head' node. - pugi::xml_node head = doc.append_child(); - head.set_name("head"); + if (plugin.Crc() != 0) { + out << YAML::Key << "crc" + << YAML::Value << IntToHexString(plugin.Crc()); + } - //Now add head elements. - pugi::xml_node node; + if (!plugin.Version().empty()) { + out << YAML::Key << "version" + << YAML::Value << plugin.Version(); + } - node = head.append_child(); - node.set_name("meta"); - node.append_attribute("http-equiv").set_value("X-UA-Compatible"); - node.append_attribute("content").set_value("IE=edge"); + std::set tags = plugin.Tags(); + std::set tagsAdd, tagsRemove; + if (!tags.empty()) { + for (std::set::const_iterator it = tags.begin(), endit = tags.end(); it != endit; ++it) { + if (it->IsAddition()) + tagsAdd.insert(*it); + else + tagsRemove.insert(*it); + } + if (!tagsAdd.empty()) { + out << YAML::Key << "tagsAdd" + << YAML::Value << tagsAdd; + } + if (!tagsRemove.empty()) { + out << YAML::Key << "tagsRemove" + << YAML::Value << tagsRemove; + } + } - node = head.append_child(); - node.set_name("meta"); - node.append_attribute("charset").set_value("utf-8"); + std::list messages = plugin.Messages(); + std::set dirtyInfo = plugin.DirtyInfo(); + for (std::set::const_iterator it = dirtyInfo.begin(), endit = dirtyInfo.end(); it != endit; ++it) { + boost::format f; + if (it->ITMs() > 0 && it->UDRs() > 0 && it->DeletedNavmeshes() > 0) + f = boost::format(boost::locale::translate("Contains %1% ITM records, %2% UDR records and %3% deleted navmeshes. Clean with %4%.")) % it->ITMs() % it->UDRs() % it->DeletedNavmeshes() % it->CleaningUtility(); + else if (it->ITMs() == 0 && it->UDRs() == 0 && it->DeletedNavmeshes() == 0) + f = boost::format(boost::locale::translate("Clean with %1%.")) % it->CleaningUtility(); - node = head.append_child(); - node.set_name("title"); - node.text().set(boost::locale::translate("LOOT Report").str().c_str()); - node = head.append_child(); - node.set_name("link"); - node.append_attribute("rel").set_value("stylesheet"); - node.append_attribute("href").set_value(ToFileURL(g_path_css).c_str()); + else if (it->ITMs() == 0 && it->UDRs() > 0 && it->DeletedNavmeshes() > 0) + f = boost::format(boost::locale::translate("Contains %1% UDR records and %2% deleted navmeshes. Clean with %3%.")) % it->UDRs() % it->DeletedNavmeshes() % it->CleaningUtility(); + else if (it->ITMs() == 0 && it->UDRs() == 0 && it->DeletedNavmeshes() > 0) + f = boost::format(boost::locale::translate("Contains %1% deleted navmeshes. Clean with %2%.")) % it->DeletedNavmeshes() % it->CleaningUtility(); + else if (it->ITMs() == 0 && it->UDRs() > 0 && it->DeletedNavmeshes() == 0) + f = boost::format(boost::locale::translate("Contains %1% UDR records. Clean with %2%.")) % it->UDRs() % it->CleaningUtility(); - node = head.append_child(); - node.set_name("script"); - node.append_attribute("src").set_value(ToFileURL(g_path_polyfill).c_str()); - node.text().set(" "); - } + else if (it->ITMs() > 0 && it->UDRs() == 0 && it->DeletedNavmeshes() > 0) + f = boost::format(boost::locale::translate("Contains %1% ITM records and %2% deleted navmeshes. Clean with %3%.")) % it->ITMs() % it->DeletedNavmeshes() % it->CleaningUtility(); + else if (it->ITMs() > 0 && it->UDRs() == 0 && it->DeletedNavmeshes() == 0) + f = boost::format(boost::locale::translate("Contains %1% ITM records. Clean with %2%.")) % it->ITMs() % it->CleaningUtility(); - void AppendNav(pugi::xml_node& body) { - BOOST_LOG_TRIVIAL(trace) << "Appending navigation bar to LOOT report."; + else if (it->ITMs() > 0 && it->UDRs() > 0 && it->DeletedNavmeshes() == 0) + f = boost::format(boost::locale::translate("Contains %1% ITM records and %2% UDR records. Clean with %3%.")) % it->ITMs() % it->UDRs() % it->CleaningUtility(); - pugi::xml_node nav, div; + messages.push_back(loot::Message(loot::Message::warn, f.str())); + } - nav = body.append_child(); - nav.set_name("div"); - nav.append_attribute("id").set_value("nav"); - - div = nav.append_child(); - div.set_name("div"); - div.append_attribute("class").set_value("button current"); - div.append_attribute("data-section").set_value("summary"); - div.text().set(boost::locale::translate("Summary").str().c_str()); - - div = nav.append_child(); - div.set_name("div"); - div.append_attribute("class").set_value("button"); - div.append_attribute("data-section").set_value("plugins"); - div.text().set(boost::locale::translate("Details").str().c_str()); - - div = nav.append_child(); - div.set_name("div"); - div.append_attribute("class").set_value("button hidden"); - div.append_attribute("id").set_value("filtersToggle"); - div.text().set(boost::locale::translate("Filters").str().c_str()); - } - - void AppendMessages(pugi::xml_node& parent, const std::list& messages, int& warnNo, int& errorNo) { if (!messages.empty()) { - pugi::xml_node list = parent.append_child(); - list.set_name("ul"); - + out << YAML::Key << "messages" + << YAML::Value << YAML::BeginSeq; for (std::list::const_iterator it = messages.begin(), endit = messages.end(); it != endit; ++it) { - - pugi::xml_node li = list.append_child(); - li.set_name("li"); - - if (it->Type() == Message::say) - li.append_attribute("class").set_value("say"); - else if (it->Type() == Message::tag) - li.append_attribute("class").set_value("tag"); - else if (it->Type() == Message::warn) { - li.append_attribute("class").set_value("warn"); - ++warnNo; - } - else { - li.append_attribute("class").set_value("error"); - ++errorNo; - } - - //Turn any urls into hyperlinks. - WriteMessage(li, it->Type(), it->Content().front().Str()); + WriteMessage(out, *it); } - } - } - - void AppendSummary(pugi::xml_node& main, - bool hasChanged, - const std::string& masterlistVersion, - bool masterlistUpdateEnabled, - int messageNo, - int warnNo, - int errorNo, - std::list& messages) { - - BOOST_LOG_TRIVIAL(trace) << "Appending summary tab to LOOT report."; - - pugi::xml_node summary = main.append_child(); - summary.set_name("div"); - summary.append_attribute("id").set_value("summary"); - - pugi::xml_node div = summary.append_child(); - div.set_name("div"); - - pugi::xml_node heading = div.append_child(); - heading.set_name("h2"); - heading.text().set(boost::locale::translate("Summary").str().c_str()); - - pugi::xml_node table = div.append_child(); - table.set_name("table"); - table = table.append_child(); - table.set_name("tbody"); - - pugi::xml_node row, cell; - - row = table.append_child(); - row.set_name("tr"); - cell = row.append_child(); - cell.set_name("td"); - cell.text().set(boost::locale::translate("LOOT Version").str().c_str()); - cell = row.append_child(); - cell.set_name("td"); - cell.text().set((IntToString(g_version_major) + "." + IntToString(g_version_minor) + "." + IntToString(g_version_patch)).c_str()); - - row = table.append_child(); - row.set_name("tr"); - cell = row.append_child(); - cell.set_name("td"); - cell.text().set(boost::locale::translate("Masterlist Version").str().c_str()); - cell = row.append_child(); - cell.set_name("td"); - cell.text().set(masterlistVersion.c_str()); - - row = table.append_child(); - row.set_name("tr"); - cell = row.append_child(); - cell.set_name("td"); - cell.text().set(boost::locale::translate("Masterlist Updating").str().c_str()); - cell = row.append_child(); - cell.set_name("td"); - if (masterlistUpdateEnabled) - cell.text().set(boost::locale::translate("Enabled").str().c_str()); - else - cell.text().set(boost::locale::translate("Disabled").str().c_str()); - - if (!hasChanged) { - BOOST_LOG_TRIVIAL(info) << "No changes in the LOOT report details tab since the last run."; - /*pugi::xml_node note = summary.append_child(); - note.set_name("div"); - note.append_attribute("id").set_value("noChanges"); - note.text().set(boost::locale::translate("No change in details since last run.").str().c_str()); - */ - messages.push_front(loot::Message(loot::Message::say, boost::locale::translate("There have been no changes in the Details tab since LOOT was last run for this game.").str())); + out << YAML::EndSeq; } - if (!messages.empty()) { - - div = summary.append_child(); - div.set_name("div"); - - heading = div.append_child(); - heading.set_name("h2"); - heading.text().set(boost::locale::translate("General Messages").str().c_str()); - - AppendMessages(div, messages, warnNo, errorNo); - messageNo += messages.size(); - } - - row = table.append_child(); - row.set_name("tr"); - cell = row.append_child(); - cell.set_name("td"); - cell.text().set(boost::locale::translate("Total Number of Messages").str().c_str()); - cell = row.append_child(); - cell.set_name("td"); - cell.text().set(IntToString(messageNo).c_str()); - - row = table.append_child(); - row.set_name("tr"); - cell = row.append_child(); - cell.set_name("td"); - cell.text().set(boost::locale::translate("Number of Warnings").str().c_str()); - cell = row.append_child(); - cell.set_name("td"); - cell.text().set(IntToString(warnNo).c_str()); - - row = table.append_child(); - row.set_name("tr"); - cell = row.append_child(); - cell.set_name("td"); - cell.text().set(boost::locale::translate("Number of Errors").str().c_str()); - cell = row.append_child(); - cell.set_name("td"); - cell.text().set(IntToString(errorNo).c_str()); - } - - bool AppendDetails(pugi::xml_node& main, const std::list& plugins, int& messageNo, int& warnNo, int& errorNo, const std::string& oldDetails) { - - BOOST_LOG_TRIVIAL(trace) << "Appending details tab to LOOT report."; - - pugi::xml_node details = main.append_child(); - details.set_name("div"); - details.append_attribute("id").set_value("plugins"); - details.append_attribute("class").set_value("hidden"); - - if (!plugins.empty()) { - - details = details.append_child(); - details.set_name("ul"); - - for (std::list::const_iterator it = plugins.begin(), endit = plugins.end(); it != endit; ++it) { - BOOST_LOG_TRIVIAL(trace) << "Appending details for plugin: " << it->Name(); - pugi::xml_node plugin = details.append_child(); - plugin.set_name("li"); - - pugi::xml_node node = plugin.append_child(); - node.set_name("span"); - node.append_attribute("class").set_value("mod"); - node.text().set(it->Name().c_str()); - - if (it->Crc() != 0) { - node = plugin.append_child(); - node.set_name("div"); - node.append_attribute("class").set_value("crc"); - node.text().set(("CRC: " + IntToHexString(it->Crc())).c_str()); - } - - if (!it->Version().empty()) { - node = plugin.append_child(); - node.set_name("div"); - node.append_attribute("class").set_value("version"); - node.text().set((boost::locale::translate("Version:").str() + " " + it->Version()).c_str()); - } - - std::list messages = it->Messages(); - messageNo += messages.size(); - - std::set tags = it->Tags(); - - if (!tags.empty()) { - std::string add, remove, content; - for (std::set::const_iterator jt = tags.begin(), endjt = tags.end(); jt != endjt; ++jt) { - if (jt->IsAddition()) - add += ", " + jt->Name(); - else - remove += ", " + jt->Name(); - } - if (!add.empty()) { - node = plugin.append_child(); - node.set_name("div"); - node.append_attribute("class").set_value("tag add"); - node.text().set((boost::locale::translate("Add:").str() + " " + add.substr(2)).c_str()); - } - if (!remove.empty()) { - node = plugin.append_child(); - node.set_name("div"); - node.append_attribute("class").set_value("tag remove"); - node.text().set((boost::locale::translate("Remove:").str() + " " + remove.substr(2)).c_str()); - } - } - - std::set dirtyInfo = it->DirtyInfo(); - for (std::set::const_iterator jt = dirtyInfo.begin(), endjt = dirtyInfo.end(); jt != endjt; ++jt) { - boost::format f; - if (jt->ITMs() > 0 && jt->UDRs() > 0 && jt->DeletedNavmeshes() > 0) - f = boost::format(boost::locale::translate("Contains %1% ITM records, %2% UDR records and %3% deleted navmeshes. Clean with %4%.")) % jt->ITMs() % jt->UDRs() % jt->DeletedNavmeshes() % jt->CleaningUtility(); - else if (jt->ITMs() == 0 && jt->UDRs() == 0 && jt->DeletedNavmeshes() == 0) - f = boost::format(boost::locale::translate("Clean with %1%.")) % jt->CleaningUtility(); - - - else if (jt->ITMs() == 0 && jt->UDRs() > 0 && jt->DeletedNavmeshes() > 0) - f = boost::format(boost::locale::translate("Contains %1% UDR records and %2% deleted navmeshes. Clean with %3%.")) % jt->UDRs() % jt->DeletedNavmeshes() % jt->CleaningUtility(); - else if (jt->ITMs() == 0 && jt->UDRs() == 0 && jt->DeletedNavmeshes() > 0) - f = boost::format(boost::locale::translate("Contains %1% deleted navmeshes. Clean with %2%.")) % jt->DeletedNavmeshes() % jt->CleaningUtility(); - else if (jt->ITMs() == 0 && jt->UDRs() > 0 && jt->DeletedNavmeshes() == 0) - f = boost::format(boost::locale::translate("Contains %1% UDR records. Clean with %2%.")) % jt->UDRs() % jt->CleaningUtility(); - - else if (jt->ITMs() > 0 && jt->UDRs() == 0 && jt->DeletedNavmeshes() > 0) - f = boost::format(boost::locale::translate("Contains %1% ITM records and %2% deleted navmeshes. Clean with %3%.")) % jt->ITMs() % jt->DeletedNavmeshes() % jt->CleaningUtility(); - else if (jt->ITMs() > 0 && jt->UDRs() == 0 && jt->DeletedNavmeshes() == 0) - f = boost::format(boost::locale::translate("Contains %1% ITM records. Clean with %2%.")) % jt->ITMs() % jt->CleaningUtility(); - - else if (jt->ITMs() > 0 && jt->UDRs() > 0 && jt->DeletedNavmeshes() == 0) - f = boost::format(boost::locale::translate("Contains %1% ITM records and %2% UDR records. Clean with %3%.")) % jt->ITMs() % jt->UDRs() % jt->CleaningUtility(); - - messages.push_back(loot::Message(loot::Message::warn, f.str())); - } - - AppendMessages(plugin, messages, warnNo, errorNo); - } - } - - xml_string_writer writer; - details.print(writer, "", pugi::format_default | pugi::format_no_declaration | pugi::format_raw); - - return writer.result != oldDetails; - } - - void AppendMain(pugi::xml_node& body, - const std::string& oldDetails, - const std::string& masterlistVersion, - bool masterlistUpdateEnabled, - std::list& messages, - const std::list& plugins, - int& pluginMessageNo - ) { - - BOOST_LOG_TRIVIAL(trace) << "Appending main content to LOOT report."; - - pugi::xml_node main = body.append_child(); - main.set_name("div"); - main.append_attribute("id").set_value("main"); - - pugi::xml_node noscript, div; - - noscript = main.append_child(); - noscript.set_name("noscript"); - div = noscript.append_child(); - div.set_name("div"); - div.text().set(boost::locale::translate("The LOOT Report requires Javascript to be enabled in order to function.").str().c_str()); - - int messageNo = 0, warnNo = 0, errorNo = 0; - bool hasChanged = AppendDetails(main, plugins, messageNo, warnNo, errorNo, oldDetails); - pluginMessageNo = messageNo; - - AppendSummary(main, hasChanged, masterlistVersion, masterlistUpdateEnabled, messageNo, warnNo, errorNo, messages); - } - - void AppendFilters(pugi::xml_node& body, int messageNo, int pluginNo) { - - BOOST_LOG_TRIVIAL(trace) << "Appending filters to LOOT report."; - - pugi::xml_node filters = body.append_child(); - filters.set_name("div"); - filters.append_attribute("id").set_value("filters"); - filters.append_attribute("class").set_value("hidden"); - - pugi::xml_node label, input; - - label = filters.append_child(); - label.set_name("label"); - input = label.append_child(); - input.set_name("input"); - input.append_attribute("type").set_value("checkbox"); - input.append_attribute("id").set_value("hideVersionNumbers"); - input.append_attribute("data-class").set_value("version"); - label.text().set(boost::locale::translate("Hide Version Numbers").str().c_str()); - - label = filters.append_child(); - label.set_name("label"); - input = label.append_child(); - input.set_name("input"); - input.append_attribute("type").set_value("checkbox"); - input.append_attribute("id").set_value("hideCRCs"); - input.append_attribute("data-class").set_value("crc"); - label.text().set(boost::locale::translate("Hide CRCs").str().c_str()); - - label = filters.append_child(); - label.set_name("label"); - input = label.append_child(); - input.set_name("input"); - input.append_attribute("type").set_value("checkbox"); - input.append_attribute("id").set_value("hideBashTags"); - input.append_attribute("data-class").set_value("tag"); - label.text().set(boost::locale::translate("Hide Bash Tag Suggestions").str().c_str()); - - label = filters.append_child(); - label.set_name("label"); - input = label.append_child(); - input.set_name("input"); - input.append_attribute("type").set_value("checkbox"); - input.append_attribute("id").set_value("hideNotes"); - label.text().set(boost::locale::translate("Hide Notes").str().c_str()); - - label = filters.append_child(); - label.set_name("label"); - input = label.append_child(); - input.set_name("input"); - input.append_attribute("type").set_value("checkbox"); - input.append_attribute("id").set_value("hideDoNotCleanMessages"); - label.text().set(boost::locale::translate("Hide 'Do Not Clean' Messages").str().c_str()); - - label = filters.append_child(); - label.set_name("label"); - input = label.append_child(); - input.set_name("input"); - input.append_attribute("type").set_value("checkbox"); - input.append_attribute("id").set_value("hideAllPluginMessages"); - label.text().set(boost::locale::translate("Hide All Plugin Messages").str().c_str()); - - label = filters.append_child(); - label.set_name("label"); - input = label.append_child(); - input.set_name("input"); - input.append_attribute("type").set_value("checkbox"); - input.append_attribute("id").set_value("hideMessagelessPlugins"); - label.text().set(boost::locale::translate("Hide Messageless Plugins").str().c_str()); - - pugi::xml_node span; - - label = filters.append_child(); - label.set_name("div"); - span = label.append_child(); - span.set_name("span"); - span.append_attribute("id").set_value("hiddenPluginNo"); - span.text().set("0"); - label.append_child(pugi::node_pcdata).set_value((boost::format(boost::locale::translate("%1% of %2% plugins hidden.")) % "" % IntToString(pluginNo)).str().c_str()); //Blank string is so that translators get full string format. - - label = filters.append_child(); - label.set_name("div"); - span = label.append_child(); - span.set_name("span"); - span.append_attribute("id").set_value("hiddenMessageNo"); - span.text().set("0"); - label.append_child(pugi::node_pcdata).set_value((boost::format(boost::locale::translate("%1% of %2% messages hidden.")) % "" % IntToString(messageNo)).str().c_str()); //Blank string is so that translators get full string format. - } - - void AppendScripts(pugi::xml_node& body) { - - BOOST_LOG_TRIVIAL(trace) << "Appending scripts to LOOT report."; - - pugi::xml_node node; - - node = body.append_child(); - node.set_name("script"); - node.append_attribute("src").set_value(ToFileURL(g_path_js).c_str()); - node.text().set(" "); - + out << YAML::EndMap; } void GenerateReport(const boost::filesystem::path& file, @@ -564,29 +199,55 @@ namespace loot { const std::string& masterlistVersion, const bool masterlistUpdateEnabled) { - pugi::xml_document doc; - GenerateHead(doc); + //messages.push_front(loot::Message(loot::Message::say, boost::locale::translate("There have been no changes in the Details tab since LOOT was last run for this game.").str())); + + //Need to output YAML as a JSON Javascript variable. + YAML::Emitter yout; + yout.SetOutputCharset(YAML::EscapeNonAscii); + yout.SetStringFormat(YAML::DoubleQuoted); + yout.SetBoolFormat(YAML::TrueFalseBool); + yout.SetSeqFormat(YAML::Flow); + yout.SetMapFormat(YAML::Flow); - pugi::xml_node body = doc.append_child(); - body.set_name("body"); + yout << YAML::BeginMap; - AppendNav(body); + yout << YAML::Key << "lootVersion" + << YAML::Value << IntToString(g_version_major) + "." + IntToString(g_version_minor) + "." + IntToString(g_version_patch); - int messageNo = 0; - //Read the details section of the previous report, if it exists. - std::string oldDetails = GetOldReportDetails(file); - AppendMain(body, oldDetails, masterlistVersion, masterlistUpdateEnabled, messages, plugins, messageNo); + yout << YAML::Key << "masterlist" + << YAML::BeginMap + << YAML::Key << "updaterEnabled" + << YAML::Value << masterlistUpdateEnabled + << YAML::Key << "revision" + << YAML::Value << masterlistVersion + << YAML::Key << "date" + << YAML::Value << "" + << YAML::EndMap; - AppendFilters(body, messageNo, plugins.size()); + if (!messages.empty()) { + yout << YAML::Key << "globalMessages" + << YAML::Value << YAML::BeginSeq; + for (std::list::const_iterator it = messages.begin(), endit = messages.end(); it != endit; ++it) { + WriteMessage(yout, *it); + } + yout << YAML::EndSeq; + } - AppendScripts(body); - //PugiXML's save_file doesn't handle Unicode paths right (it can't open them right), so use a stream instead. - boost::filesystem::path outpath(file); - loot::ofstream out(outpath); - doc.save(out, "\t", pugi::format_default | pugi::format_no_declaration | pugi::format_raw); + if (!plugins.empty()) { + yout << YAML::Key << "plugins" + << YAML::Value << YAML::BeginSeq; + for (std::list::const_iterator it = plugins.begin(), endit = plugins.end(); it != endit; ++it) { + WritePlugin(yout, *it); + } + yout << YAML::EndSeq; + } + + yout << YAML::EndMap; + + loot::ofstream out(file); + out << "var data = " << yout.c_str(); out.close(); - } //Default settings file generation. diff --git a/src/backend/globals.cpp b/src/backend/globals.cpp index 8468c2c6..8781f63b 100644 --- a/src/backend/globals.cpp +++ b/src/backend/globals.cpp @@ -33,12 +33,10 @@ namespace loot { const unsigned int g_version_patch = 0; //Common paths. - const boost::filesystem::path g_path_readme = boost::filesystem::current_path() / "docs" / "LOOT Readme.html"; - const boost::filesystem::path g_path_css = boost::filesystem::current_path() / "resources" / "style.css"; - const boost::filesystem::path g_path_js = boost::filesystem::current_path() / "resources" / "script.js"; - const boost::filesystem::path g_path_polyfill = boost::filesystem::current_path() / "resources" / "polyfill.js"; - const boost::filesystem::path g_path_l10n = boost::filesystem::current_path() / "resources" / "l10n"; - const boost::filesystem::path g_path_local = GetLocalAppDataPath() / "LOOT"; - const boost::filesystem::path g_path_settings = g_path_local / "settings.yaml"; - const boost::filesystem::path g_path_log = g_path_local / "LOOTDebugLog.txt"; + const boost::filesystem::path g_path_readme = boost::filesystem::current_path() / "docs" / "LOOT Readme.html"; + const boost::filesystem::path g_path_report = boost::filesystem::current_path() / "resources" / "report" / "report.html"; + const boost::filesystem::path g_path_l10n = boost::filesystem::current_path() / "resources" / "l10n"; + const boost::filesystem::path g_path_local = GetLocalAppDataPath() / "LOOT"; + const boost::filesystem::path g_path_settings = g_path_local / "settings.yaml"; + const boost::filesystem::path g_path_log = g_path_local / "LOOTDebugLog.txt"; } diff --git a/src/backend/globals.h b/src/backend/globals.h index 041c856d..ac39d0a4 100644 --- a/src/backend/globals.h +++ b/src/backend/globals.h @@ -34,14 +34,12 @@ namespace loot { extern const unsigned int g_version_patch; //Common paths. - extern const boost::filesystem::path g_path_local; extern const boost::filesystem::path g_path_readme; - extern const boost::filesystem::path g_path_settings; - extern const boost::filesystem::path g_path_css; - extern const boost::filesystem::path g_path_js; - extern const boost::filesystem::path g_path_polyfill; - extern const boost::filesystem::path g_path_log; + extern const boost::filesystem::path g_path_report; extern const boost::filesystem::path g_path_l10n; + extern const boost::filesystem::path g_path_local; + extern const boost::filesystem::path g_path_settings; + extern const boost::filesystem::path g_path_log; } #endif diff --git a/src/gui/main.cpp b/src/gui/main.cpp index de0a4647..ebe69506 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -467,7 +467,7 @@ Launcher::Launcher(const wxChar *title, YAML::Node& settings, Game * game, vecto //Set up initial state. SortButton->SetDefault(); - if (!fs::exists(_game->ReportPath())) + if (!fs::exists(g_path_report)) ViewButton->Enable(false); if (_game->Id() == loot::Game::tes5) @@ -516,12 +516,12 @@ void Launcher::OnClose(wxCloseEvent& event) { void Launcher::OnViewLastReport(wxCommandEvent& event) { if (_settings["View Report Externally"] && _settings["View Report Externally"].as()) { BOOST_LOG_TRIVIAL(debug) << "Opening report in external application..."; - wxLaunchDefaultBrowser(FromUTF8(ToFileURL(_game->ReportPath().string()))); + wxLaunchDefaultBrowser(FromUTF8(ToFileURL(g_path_report.string() + "?data=" + _game->ReportDataPath().string()))); } else { //Create viewer window. BOOST_LOG_TRIVIAL(debug) << "Opening viewer window..."; - Viewer *viewer = new Viewer(this, translate("LOOT: Report Viewer"), FromUTF8(ToFileURL(_game->ReportPath().string()))); + Viewer *viewer = new Viewer(this, translate("LOOT: Report Viewer"), FromUTF8(ToFileURL(g_path_report.string() + "?data=" + _game->ReportDataPath().string()))); viewer->Show(); } BOOST_LOG_TRIVIAL(debug) << "Report displayed."; @@ -912,7 +912,7 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { BOOST_LOG_TRIVIAL(debug) << "Generating report..."; try { - GenerateReport(_game->ReportPath(), + GenerateReport(_game->ReportDataPath(), messages, plugins, revision, @@ -933,10 +933,10 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { BOOST_LOG_TRIVIAL(debug) << "Displaying report..."; if (_settings["View Report Externally"] && _settings["View Report Externally"].as()) { - wxLaunchDefaultBrowser(FromUTF8(ToFileURL(_game->ReportPath().string()))); + wxLaunchDefaultBrowser(FromUTF8(ToFileURL(g_path_report.string() + "?data=" + _game->ReportDataPath().string()))); } else { //Create viewer window. - Viewer *viewer = new Viewer(this, translate("LOOT: Report Viewer"), FromUTF8(ToFileURL(_game->ReportPath().string()))); + Viewer *viewer = new Viewer(this, translate("LOOT: Report Viewer"), FromUTF8(ToFileURL(g_path_report.string() + "?data=" + _game->ReportDataPath().string()))); viewer->Show(); }