Implemented plugin version extraction from description field and started to implement the metadata editor window.

This commit is contained in:
WrinklyNinja
2013-05-08 11:27:09 +01:00
parent 82d6d480a5
commit 3e106721ed
9 changed files with 342 additions and 20 deletions
+1 -1
View File
@@ -71,7 +71,7 @@ ENDIF ()
# More General Settings
##############################
set (BOSS_GUI_SRC ${BOSS_SRC} "${CMAKE_SOURCE_DIR}/src/gui/ids.cpp" "${CMAKE_SOURCE_DIR}/src/gui/main.cpp" "${CMAKE_SOURCE_DIR}/src/gui/settings.cpp")
set (BOSS_GUI_SRC ${BOSS_SRC} "${CMAKE_SOURCE_DIR}/src/gui/ids.cpp" "${CMAKE_SOURCE_DIR}/src/gui/main.cpp" "${CMAKE_SOURCE_DIR}/src/gui/settings.cpp" "${CMAKE_SOURCE_DIR}/src/gui/editor.cpp")
set (BOSS_API_SRC ${BOSS_SRC} "${CMAKE_SOURCE_DIR}/src/api.cpp")
+2 -2
View File
@@ -54,10 +54,10 @@ Roadmap/To Do
- Remove game detection override.
- Checks for cyclic dependencies and incompatibilities.
- Setting load order.
- Include libespm initialisation into Game constructor.
- Include libespm initialisation into Game constructor. DONE
- Optimisations to load ordering.
- Implement logging.
- Implement reading of plugin versions from their description field.
- Implement reading of plugin versions from their description field. DONE
Sorting Algorithm
+182
View File
@@ -0,0 +1,182 @@
/* BOSS
A plugin load order optimiser for games that use the esp/esm plugin system.
Copyright (C) 2013 WrinklyNinja
This file is part of BOSS.
BOSS is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
BOSS is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with BOSS. If not, see
<http://www.gnu.org/licenses/>.
*/
#include "editor.h"
#include <wx/statline.h>
Editor::Editor(const wxString title, wxFrame *parent) : wxFrame(parent, wxID_ANY, title) {
//Initialise child windows.
filesBook = new wxNotebook(this, wxID_ANY);
wxNotebook * messagesBook = new wxNotebook(this, wxID_ANY);
wxPanel * reqsTab = new wxPanel(filesBook);
wxPanel * incsTab = new wxPanel(filesBook);
wxPanel * loadAfterTab = new wxPanel(filesBook);
wxPanel * messagesTab = new wxPanel(messagesBook);
wxPanel * tagsTab = new wxPanel(messagesBook);
//Tie together notebooks and panels.
filesBook->AddPage(reqsTab, translate("Requirements"), true);
filesBook->AddPage(incsTab, translate("Incompatibilities"));
filesBook->AddPage(loadAfterTab, translate("Load After"));
messagesBook->AddPage(messagesTab, translate("Messages"), true);
messagesBook->AddPage(tagsTab, translate("Bash Tags"));
//Initialise controls.
pluginList = new wxListBox(this, LIST_Plugins);
pluginText = new wxStaticText(this, wxID_ANY, "");
prioritySpin = new wxSpinCtrl(this, SPIN_Priority, "0");
enableUserEditsBox = new wxCheckBox(this, wxID_ANY, translate("Enable User Changes"));
addFileBtn = new wxButton(this, BUTTON_AddFile, translate("Add File"));
editFileBtn = new wxButton(this, BUTTON_EditFile, translate("Edit File"));
removeFileBtn = new wxButton(this, BUTTON_RemoveFile, translate("Remove File"));
addMsgBtn = new wxButton(messagesTab, BUTTON_AddMessage, translate("Add Message"));
editMsgBtn = new wxButton(messagesTab, BUTTON_EditMessage, translate("Edit Message"));
removeMsgBtn = new wxButton(messagesTab, BUTTON_RemoveMessage, translate("Remove Message"));
addTagBtn = new wxButton(tagsTab, BUTTON_AddTag, translate("Add Tag"));
editTagBtn = new wxButton(tagsTab, BUTTON_EditTag, translate("Edit Tag"));
removeTagBtn = new wxButton(tagsTab, BUTTON_RemoveTag, translate("Remove Tag"));
saveEditsBtn = new wxButton(this, BUTTON_SaveEdits, translate("Save Edits"));
undoEditsBtn = new wxButton(this, BUTTON_UndoEdits, translate("Undo Edits"));
recalcBtn = new wxButton(this, BUTTON_Recalc, translate("Recalculate Load Order"));
applyBtn = new wxButton(this, BUTTON_Apply, translate("Apply Load Order"));
cancelBtn = new wxButton(this, BUTTON_Cancel, translate("Cancel"));
reqsList = new wxListCtrl(reqsTab, LIST_Reqs, wxDefaultPosition, wxDefaultSize, wxLC_REPORT);
incsList = new wxListCtrl(incsTab, LIST_Incs, wxDefaultPosition, wxDefaultSize, wxLC_REPORT);
loadAfterList = new wxListCtrl(loadAfterTab, LIST_LoadAfter, wxDefaultPosition, wxDefaultSize, wxLC_REPORT);
messageList = new wxListCtrl(messagesTab, LIST_Messages, wxDefaultPosition, wxDefaultSize, wxLC_REPORT);
tagsList = new wxListCtrl(tagsTab, LIST_BashTags, wxDefaultPosition, wxDefaultSize, wxLC_REPORT);
//Set up list columns.
reqsList->AppendColumn(translate("Filename"));
reqsList->AppendColumn(translate("Display Name"));
reqsList->AppendColumn(translate("Condition"));
incsList->AppendColumn(translate("Filename"));
incsList->AppendColumn(translate("Display Name"));
incsList->AppendColumn(translate("Condition"));
loadAfterList->AppendColumn(translate("Filename"));
loadAfterList->AppendColumn(translate("Display Name"));
loadAfterList->AppendColumn(translate("Condition"));
messageList->AppendColumn(translate("Type"));
messageList->AppendColumn(translate("Content"));
messageList->AppendColumn(translate("Condition"));
messageList->AppendColumn(translate("Language"));
tagsList->AppendColumn(translate("Add/Remove"));
tagsList->AppendColumn(translate("Bash Tag"));
tagsList->AppendColumn(translate("Condition"));
//Set up layout.
wxBoxSizer * bigBox = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer *vbox1 = new wxBoxSizer(wxVERTICAL);
vbox1->Add(new wxStaticText(this, wxID_ANY, translate("Plugins")), 0, wxALL, 5);
vbox1->Add(pluginList, 1, wxEXPAND|wxALL, 5);
bigBox->Add(vbox1, 0, wxEXPAND|wxALL, 5);
wxBoxSizer * mainBox = new wxBoxSizer(wxVERTICAL);
mainBox->Add(pluginText, 0, wxALL, 5);
wxBoxSizer * hbox1 = new wxBoxSizer(wxHORIZONTAL);
hbox1->Add(new wxStaticText(this, wxID_ANY, translate("Priority: ")), 0, wxALL, 5);
hbox1->Add(prioritySpin, 0, wxALL, 5);
mainBox->Add(hbox1);
wxBoxSizer * tabBox1 = new wxBoxSizer(wxVERTICAL);
tabBox1->Add(reqsList, 1, wxEXPAND);
reqsTab->SetSizer(tabBox1);
wxBoxSizer * tabBox2 = new wxBoxSizer(wxVERTICAL);
tabBox2->Add(incsList, 1, wxEXPAND);
incsTab->SetSizer(tabBox2);
wxBoxSizer * tabBox3 = new wxBoxSizer(wxVERTICAL);
tabBox3->Add(loadAfterList, 1, wxEXPAND);
loadAfterTab->SetSizer(tabBox3);
mainBox->Add(filesBook, 1, wxEXPAND);
wxBoxSizer * hbox2 = new wxBoxSizer(wxHORIZONTAL);
hbox2->Add(addFileBtn, 0, wxALL, 10);
hbox2->Add(editFileBtn, 0, wxALL, 10);
hbox2->Add(removeFileBtn, 0, wxALL, 10);
mainBox->Add(hbox2);
wxBoxSizer * tabBox4 = new wxBoxSizer(wxVERTICAL);
tabBox4->Add(messageList, 0, wxEXPAND|wxALL, 5);
wxBoxSizer * hbox3 = new wxBoxSizer(wxHORIZONTAL);
hbox3->Add(addMsgBtn, 0, wxALL, 10);
hbox3->Add(editMsgBtn, 0, wxALL, 10);
hbox3->Add(removeMsgBtn, 0, wxALL, 10);
tabBox4->Add(hbox3);
messagesTab->SetSizer(tabBox4);
wxBoxSizer * tabBox5 = new wxBoxSizer(wxVERTICAL);
tabBox5->Add(tagsList, 0, wxEXPAND|wxALL, 5);
wxBoxSizer * hbox4 = new wxBoxSizer(wxHORIZONTAL);
hbox4->Add(addTagBtn, 0, wxTOP|wxLEFT|wxRIGHT, 10);
hbox4->Add(editTagBtn, 0, wxTOP|wxLEFT|wxRIGHT, 10);
hbox4->Add(removeTagBtn, 0, wxTOP|wxLEFT|wxRIGHT, 10);
tabBox5->Add(hbox4);
tagsTab->SetSizer(tabBox5);
mainBox->Add(messagesBook, 1, wxEXPAND);
mainBox->AddSpacer(20);
wxBoxSizer * hbox5 = new wxBoxSizer(wxHORIZONTAL);
hbox5->Add(enableUserEditsBox, 0, wxALL, 5);
hbox5->Add(saveEditsBtn, 0, wxALL, 5);
hbox5->Add(undoEditsBtn, 0, wxALL, 5);
mainBox->Add(hbox5);
mainBox->AddSpacer(20);
wxBoxSizer * hbox6 = new wxBoxSizer(wxHORIZONTAL);
hbox6->Add(recalcBtn, 0, wxALL, 5);
hbox6->Add(applyBtn, 0, wxALL, 5);
hbox6->Add(cancelBtn, 0, wxALL, 5);
mainBox->Add(hbox6);
bigBox->Add(mainBox, 1, wxEXPAND|wxALL, 5);
SetBackgroundColour(wxColour(255,255,255));
SetSizerAndFit(bigBox);
}
+72
View File
@@ -0,0 +1,72 @@
/* BOSS
A plugin load order optimiser for games that use the esp/esm plugin system.
Copyright (C) 2013 WrinklyNinja
This file is part of BOSS.
BOSS is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
BOSS is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with BOSS. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef __BOSS_GUI_EDITOR__
#define __BOSS_GUI_EDITOR__
#include "ids.h"
#include "../metadata.h"
#include <vector>
#include <wx/spinctrl.h>
#include <wx/notebook.h>
#include <wx/listctrl.h>
class Editor : public wxFrame {
public:
Editor(const wxString title, wxFrame *parent);
private:
wxListBox * pluginList;
wxButton * addFileBtn;
wxButton * editFileBtn;
wxButton * removeFileBtn;
wxButton * addMsgBtn;
wxButton * editMsgBtn;
wxButton * removeMsgBtn;
wxButton * addTagBtn;
wxButton * editTagBtn;
wxButton * removeTagBtn;
wxButton * saveEditsBtn;
wxButton * undoEditsBtn;
wxButton * recalcBtn;
wxButton * applyBtn;
wxButton * cancelBtn;
wxCheckBox * enableUserEditsBox;
wxSpinCtrl * prioritySpin;
wxStaticText * pluginText;
wxNotebook * filesBook;
wxListCtrl * reqsList;
wxListCtrl * incsList;
wxListCtrl * loadAfterList;
wxListCtrl * messageList;
wxListCtrl * tagsList;
std::vector<boss::Plugin> plugins;
};
#endif
+23 -1
View File
@@ -53,7 +53,29 @@ enum {
MENU_FalloutNewVegas,
//Settings window.
OPTION_OKExitSettings,
OPTION_CancelExitSettings
OPTION_CancelExitSettings,
//Editor window.
LIST_Plugins,
LIST_Reqs,
LIST_Incs,
LIST_LoadAfter,
LIST_Messages,
LIST_BashTags,
SPIN_Priority,
BUTTON_AddFile,
BUTTON_EditFile,
BUTTON_RemoveFile,
BUTTON_AddMessage,
BUTTON_EditMessage,
BUTTON_RemoveMessage,
BUTTON_AddTag,
BUTTON_EditTag,
BUTTON_RemoveTag,
BUTTON_SaveEdits,
BUTTON_UndoEdits,
BUTTON_Recalc,
BUTTON_Apply,
BUTTON_Cancel
};
wxString translate(const std::string& str);
+48 -1
View File
@@ -26,6 +26,7 @@
#include "../parsers.h"
#include "main.h"
#include "settings.h"
#include "editor.h"
#include <ostream>
#include <algorithm>
@@ -490,7 +491,54 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
}
void Launcher::OnEditMetadata(wxCommandEvent& event) {
//Parse the userlist and masterlist and get a list of installed plugins.
list<boss::Plugin> plugins;
YAML::Node mlist, ulist;
list<boss::Plugin> mlist_plugins, ulist_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")) {
boss::Plugin plugin(it->path().filename().string());
plugins.push_back(plugin);
}
}
if (fs::exists(_game.MasterlistPath())) {
try {
mlist = YAML::LoadFile(_game.MasterlistPath().string());
} catch (YAML::ParserException& e) {
//LOG_ERROR("Error: %s", e.getString().c_str());
wxMessageBox(
FromUTF8(format(loc::translate("Error: Masterlist parsing failed. %1%")) % e.what()),
translate("BOSS: Error"),
wxOK | wxICON_ERROR,
NULL);
}
if (mlist["plugins"])
mlist_plugins = mlist["plugins"].as< list<boss::Plugin> >();
}
if (fs::exists(_game.UserlistPath())) {
try {
ulist = YAML::LoadFile(_game.UserlistPath().string());
} catch (YAML::ParserException& e) {
//LOG_ERROR("Error: %s", e.getString().c_str());
wxMessageBox(
FromUTF8(format(loc::translate("Error: Userlist parsing failed. %1%")) % e.what()),
translate("BOSS: Error"),
wxOK | wxICON_ERROR,
NULL);
}
if (ulist["plugins"])
ulist_plugins = ulist["plugins"].as< list<boss::Plugin> >();
}
Editor *editor = new Editor(translate("BOSS: Metadata Editor"), this);
editor->SetIcon(wxIconLocation("BOSS.exe"));
editor->Show();
}
void Launcher::OnViewLastReport(wxCommandEvent& event) {
@@ -498,7 +546,6 @@ void Launcher::OnViewLastReport(wxCommandEvent& event) {
}
void Launcher::OnOpenSettings(wxCommandEvent& event) {
//Tell the user that stuff is happenining.
SettingsFrame *settings = new SettingsFrame(translate("BOSS: Settings"), this, _settings);
settings->SetIcon(wxIconLocation("BOSS.exe"));
settings->Show();
+8 -9
View File
@@ -106,15 +106,14 @@ namespace boss {
/// Array used to try each of the expressions defined above using
/// an iteration for each of them.
boost::regex* version_checks[] = {
new boost::regex(regex1, boost::regex::icase),
new boost::regex(regex2, boost::regex::icase),
new boost::regex(regex3, boost::regex::icase),
new boost::regex(regex4, boost::regex::icase),
new boost::regex(regex5, boost::regex::icase), //This incorrectly identifies "OBSE v19" where 19 is any integer.
new boost::regex(regex6, boost::regex::icase), //This is responsible for metallicow's false positive.
new boost::regex(regex7, boost::regex::icase),
0
boost::regex version_checks[7] = {
boost::regex(regex1, boost::regex::icase),
boost::regex(regex2, boost::regex::icase),
boost::regex(regex3, boost::regex::icase),
boost::regex(regex4, boost::regex::icase),
boost::regex(regex5, boost::regex::icase), //This incorrectly identifies "OBSE v19" where 19 is any integer.
boost::regex(regex6, boost::regex::icase), //This is responsible for metallicow's false positive.
boost::regex(regex7, boost::regex::icase)
};
//////////////////////////////////////////////////////////////////////////
+1 -1
View File
@@ -39,7 +39,7 @@ namespace boss {
/// Array used to try each of the expressions defined using
/// an iteration for each of them.
extern boost::regex* version_checks[];
extern boost::regex version_checks[7];
//////////////////////////////////////////////////////////////////////////
// Helper functions
+5 -5
View File
@@ -29,7 +29,7 @@
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <iostream>
#include <fstream>
using namespace std;
@@ -217,9 +217,9 @@ namespace boss {
begin = text.begin();
end = text.end();
/* for(int j = 0; boost::regex* re = version_checks[j]; j++) {
for(int j = 0; j < 7 && version.empty(); j++) {
boost::smatch what;
while (boost::regex_search(begin, end, what, *re)) {
while (boost::regex_search(begin, end, what, version_checks[j])) {
if (what.empty())
continue;
@@ -228,9 +228,9 @@ namespace boss {
continue;
version = boost::trim_copy(string(match.first, match.second));
break;
}
cout << "Checking regex: " << j << endl;
}*/
}
size_t pos1 = text.find("{{BASH:");
if (pos1 == string::npos)