From 09053f2659b33deec8bfa3cccd183cae12c1eaab Mon Sep 17 00:00:00 2001 From: WrinklyNinja Date: Mon, 13 May 2013 11:17:47 +0100 Subject: [PATCH] Fixed script includes in report, made sorting progress dialog more responsive, added setting to choose whether to display report in a BOSS window or the default browser, and added a header-only plugin reading mode for the metadata editor. --- README.md | 10 ++--- examples/resource/style.css | 7 +-- examples/settings.yaml | 1 + src/generators.h | 28 ++++++------ src/gui/main.cpp | 87 +++++++++++++++++++++++++++++-------- src/gui/settings.cpp | 10 +++++ src/gui/settings.h | 1 + src/metadata.cpp | 8 +++- src/metadata.h | 2 +- 9 files changed, 108 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index c77d9956..6fcc6bee 100644 --- a/README.md +++ b/README.md @@ -49,21 +49,21 @@ BOSSv3 won't have a command line interface, to simplify things. It also allows B - [ ] Develop sorting algorithm. - [ ] Work out how to implement masterlist updating and write the code. - [x] Develop UI - metadata editor window. -- [ ] Develop UI - report viewer. -- [ ] Error handling. +- [x] Develop UI - report viewer. +- [x] Error handling. - [ ] Checks for cyclic dependencies and incompatibilities. - [ ] Setting load order. - [ ] Optimisations to load ordering. - [ ] Implement logging. -- [ ] Add a quick header-only plugin read for use when loading the metadata editor, so that existing Bash Tags can also be displayed. -- [ ] Make validity checks non-fatal. +- [x] Add a quick header-only plugin read for use when loading the metadata editor, so that existing Bash Tags can also be displayed. +- [x] Make validity checks non-fatal. - [ ] Add a massive "RUN THE GAME LAUNCHER IF YOUR GAME IS NOT DETECTED" message somewhere. - [ ] Generalise Total Conversion support, so that any TC for any of the supported 'base' games can be used with BOSS. - [x] Write XHTML report generator. - [ ] Write report CSS. - [ ] Write report Javascript. - [ ] Double-check ghosted file support. -- [ ] Add a setting that lets users choose whether to use the viewer window or their own browser when viewing BOSS's report. +- [x] Add a setting that lets users choose whether to use the viewer window or their own browser when viewing BOSS's report. - [x] Somehow implement filter settings memory for the BOSS report. - [ ] Implement checking of details part of report against previous report. diff --git a/examples/resource/style.css b/examples/resource/style.css index 7a1fdd6b..bec221ff 100755 --- a/examples/resource/style.css +++ b/examples/resource/style.css @@ -113,11 +113,6 @@ input[type='checkbox'] { ul {margin-top:0.5em; margin-bottom:1em;} li {margin:0.75em 0;} -.active { - display:block; - color:green; - margin-left:1.5em; -} #plugins > ul {list-style:none;} .hidden, #summary.hidden, #plugins.hidden { display:none; @@ -146,7 +141,7 @@ li.success{background:#90ff90;display:table;padding:0.3em 0.5em;border-radius:0. .crc{color:#BC8923;margin-right:1em;} -.active{color:#0A0;margin-right:1em;} +.active{color:green;margin-right:1em;} .tagPrefix{color:#CD5555;} diff --git a/examples/settings.yaml b/examples/settings.yaml index cf7c04aa..e7320062 100644 --- a/examples/settings.yaml +++ b/examples/settings.yaml @@ -7,6 +7,7 @@ Game: auto # auto, oblivion, nehrim, skyrim, fallout3, falloutn Last Game: auto # auto, oblivion, nehrim, skyrim, fallout3, falloutnv Debug Verbosity: 0 # 0, 1, 2, 3. Logging takes place if > 0. Update Masterlist: true +View Report Externally: false Masterlist URLs: Oblivion: http://better-oblivion-sorting-software.googlecode.com/svn/data/boss-oblivion/masterlist.yaml diff --git a/src/generators.h b/src/generators.h index 36eb5fcf..f9fb869f 100644 --- a/src/generators.h +++ b/src/generators.h @@ -115,6 +115,19 @@ namespace boss { node.set_name("link"); node.append_attribute("rel").set_value("stylesheet"); node.append_attribute("href").set_value("../resource/style.css"); + + node = head.append_child(); + node.set_name("script"); + node.append_attribute("src").set_value("../resource/polyfill.js"); + node.text().set(" "); + + node = head.append_child(); + node.set_name("script"); + node.append_attribute("src").set_value("../resource/storage.js"); + node.text().set(" "); + + node = head.append_child(pugi::node_comment); + node.set_value("[if IE 8]>path().filename().string(); out << "Reading plugin: " << filename << endl; - boss::Plugin plugin(_game, filename); - //boss::Plugin plugin(filename); + boss::Plugin plugin(_game, filename, false); plugins.push_back(plugin); progDia->Pulse(); @@ -424,6 +423,10 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { if (pos != ulist_plugins.end()) it->Merge(*pos); + + + + progDia->Pulse(); } end = time(NULL); @@ -447,6 +450,8 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { this); return; } + + progDia->Pulse(); } end = time(NULL); @@ -459,12 +464,17 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { for (list::iterator it=plugins.begin(), endIt = plugins.end(); it != endIt; ++it) { map issues = it->CheckInstallValidity(_game); + list messages = it->Messages(); for (map::const_iterator jt=issues.begin(), endJt=issues.end(); jt != endJt; ++jt) { if (jt->second) - out << "Error: Invalid install detected! \"" << jt->first << "\" is incompatible with \"" << it->Name() << "\" and is present." << endl; + messages.push_back(boss::Message("error", "\"" + jt->first + "\" is incompatible with \"" + it->Name() + "\" and is present.")); else - out << "Error: Invalid install detected! \"" << jt->first << "\" is required by \"" << it->Name() << "\" but is missing." << endl; + messages.push_back(boss::Message("error", "\"" + jt->first + "\" is required by \"" + it->Name() + "\" but is missing.")); } + if (!issues.empty()) + it->Messages(messages); + + progDia->Pulse(); } @@ -502,7 +512,12 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { if (overlap > 0) out << '\t' << '\t' << jt->Name() << " (" << overlap << " records)" << endl; } + + progDia->Pulse(); } + + + progDia->Pulse(); } progDia->Pulse(); @@ -516,22 +531,39 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { out << "Writing results file..." << endl; - GenerateReport(_game.ReportPath().string(), - messages, - plugins, - "4030 (2020-13-13)", - _settings["Update Masterlist"].as(), - true); + try { + GenerateReport(_game.ReportPath().string(), + messages, + plugins, + "4030 (2020-13-13)", + _settings["Update Masterlist"].as(), + true); + } catch (boss::error& e) { + wxMessageBox( + FromUTF8(format(loc::translate("Error: %1%")) % e.what()), + translate("BOSS: Error"), + wxOK | wxICON_ERROR, + this); + return; + } progDia->Pulse(); out << "Tester finished. Total time taken: " << time(NULL) - t0 << endl; out.close(); - progDia->Destroy(); - //Now a results report definitely exists. ViewButton->Enable(true); + + progDia->Destroy(); + + if (_settings["View Report Externally"] && _settings["View Report Externally"].as()) { + wxLaunchDefaultApplication(_game.ReportPath().string()); + } else { + //Create viewer window. + Viewer *viewer = new Viewer(this, translate("BOSS: Report Viewer"), _game); + viewer->Show(); + } } void Launcher::OnEditMetadata(wxCommandEvent& event) { @@ -539,10 +571,15 @@ void Launcher::OnEditMetadata(wxCommandEvent& event) { //Should probably check for masterlist updates before opening metadata editor. vector installed, mlist_plugins, ulist_plugins; + wxProgressDialog *progDia = new wxProgressDialog(translate("BOSS: Working..."),translate("BOSS working..."), 1000, this, wxPD_APP_MODAL|wxPD_AUTO_HIDE|wxPD_ELAPSED_TIME); + //Scan for installed plugins. for (fs::directory_iterator it(_game.DataPath()); it != fs::directory_iterator(); ++it) { if (fs::is_regular_file(it->status()) && (it->path().extension().string() == ".esp" || it->path().extension().string() == ".esm")) { - installed.push_back(boss::Plugin(it->path().filename().string())); + boss::Plugin plugin(_game, it->path().filename().string(), true); + installed.push_back(plugin); + + progDia->Pulse(); } } @@ -562,6 +599,8 @@ void Launcher::OnEditMetadata(wxCommandEvent& event) { if (mlist["plugins"]) mlist_plugins = mlist["plugins"].as< vector >(); } + + progDia->Pulse(); //Parse userlist. if (fs::exists(_game.UserlistPath())) { @@ -579,6 +618,8 @@ void Launcher::OnEditMetadata(wxCommandEvent& event) { if (ulist["plugins"]) ulist_plugins = ulist["plugins"].as< vector >(); } + + progDia->Pulse(); //Merge the masterlist down into the installed mods list. for (vector::const_iterator it=mlist_plugins.begin(), endit=mlist_plugins.end(); it != endit; ++it) { @@ -588,26 +629,38 @@ void Launcher::OnEditMetadata(wxCommandEvent& event) { pos->Merge(*it); } + + progDia->Pulse(); + //Add empty entries for any userlist entries that aren't installed. for (vector::const_iterator it=ulist_plugins.begin(), endit=ulist_plugins.end(); it != endit; ++it) { if (find(installed.begin(), installed.end(), *it) == installed.end()) installed.push_back(boss::Plugin(it->Name())); } + + progDia->Pulse(); //Sort into alphabetical order. std::sort(installed.begin(), installed.end(), AlphaSortPlugins); + + progDia->Pulse(); //Create editor window. Editor *editor = new Editor(this, translate("BOSS: Metadata Editor"), _game, installed, ulist_plugins); + progDia->Destroy(); + editor->Show(); } void Launcher::OnViewLastReport(wxCommandEvent& event) { - //Create viewer window. - Viewer *viewer = new Viewer(this, translate("BOSS: Report Viewer"), _game); - - viewer->Show(); + if (_settings["View Report Externally"] && _settings["View Report Externally"].as()) { + wxLaunchDefaultApplication(_game.ReportPath().string()); + } else { + //Create viewer window. + Viewer *viewer = new Viewer(this, translate("BOSS: Report Viewer"), _game); + viewer->Show(); + } } void Launcher::OnOpenSettings(wxCommandEvent& event) { diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index e7a019bc..c8dbbac0 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -70,6 +70,7 @@ SettingsFrame::SettingsFrame(wxWindow *parent, const wxString& title, YAML::Node FONVURL = new wxTextCtrl(this, wxID_ANY); UpdateMasterlistBox = new wxCheckBox(this, wxID_ANY, translate("Update masterlist before sorting.")); + reportViewBox = new wxCheckBox(this, wxID_ANY, translate("View reports externally in default browser.")); //Set up layout. wxSizerFlags leftItem(0); @@ -115,6 +116,8 @@ SettingsFrame::SettingsFrame(wxWindow *parent, const wxString& title, YAML::Node bigBox->Add(GridSizer, 0, wxEXPAND|wxALL, 10); bigBox->Add(UpdateMasterlistBox, wholeItem); + + bigBox->Add(reportViewBox, wholeItem); bigBox->AddSpacer(10); bigBox->AddStretchSpacer(1); @@ -174,6 +177,11 @@ void SettingsFrame::SetDefaultValues() { UpdateMasterlistBox->SetValue(update); } + if (_settings["View Report Externally"]) { + bool view = _settings["View Report Externally"].as(); + reportViewBox->SetValue(view); + } + if (_settings["Masterlist URLs"]) { YAML::Node urls = _settings["Masterlist URLs"]; @@ -228,6 +236,8 @@ void SettingsFrame::OnQuit(wxCommandEvent& event) { _settings["Update Masterlist"] = UpdateMasterlistBox->IsChecked(); + _settings["View Report Externally"] = reportViewBox->IsChecked(); + _settings["Masterlist URLs"]["Oblivion"] = string(OblivionURL->GetValue().ToUTF8()); _settings["Masterlist URLs"]["Nehrim"] = string(NehrimURL->GetValue().ToUTF8()); diff --git a/src/gui/settings.h b/src/gui/settings.h index 39fed569..89cb34fb 100644 --- a/src/gui/settings.h +++ b/src/gui/settings.h @@ -39,6 +39,7 @@ private: wxChoice *GameChoice; wxChoice *LanguageChoice; wxCheckBox *UpdateMasterlistBox; + wxCheckBox *reportViewBox; wxTextCtrl *OblivionURL; wxTextCtrl *NehrimURL; wxTextCtrl *SkyrimURL; diff --git a/src/metadata.cpp b/src/metadata.cpp index e602739c..a8ae5924 100644 --- a/src/metadata.cpp +++ b/src/metadata.cpp @@ -246,12 +246,16 @@ namespace boss { Plugin::Plugin() : enabled(true), priority(0), isMaster(false), isActive(false), crc(0) {} Plugin::Plugin(const std::string& n) : name(n), enabled(true), priority(0), isMaster(false), isActive(false), crc(0) {} - Plugin::Plugin(boss::Game& game, const std::string& n) + Plugin::Plugin(boss::Game& game, const std::string& n, const bool headerOnly) : name(n), enabled(true), priority(0) { // Get data from file contents using libespm. Assumes libespm has already been initialised. boost::filesystem::path filepath = game.DataPath() / n; - espm::File file(filepath.string(), game.espm_settings, false, false); + espm::File file; + if (headerOnly) + file = espm::File(filepath.string(), game.espm_settings, false, true); + else + file = espm::File(filepath.string(), game.espm_settings, false, false); isMaster = file.isMaster(game.espm_settings); masters = file.getMasters(); diff --git a/src/metadata.h b/src/metadata.h index 5bf03e5b..a454790c 100644 --- a/src/metadata.h +++ b/src/metadata.h @@ -131,7 +131,7 @@ namespace boss { public: Plugin(); Plugin(const std::string& name); - Plugin(boss::Game& game, const std::string& name); + Plugin(boss::Game& game, const std::string& name, const bool headerOnly); void Merge(const Plugin& plugin, bool ifdDisabled = false); Plugin DiffMetadata(const Plugin& plugin) const;