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;