Forgot to add UI code to last commit, so all UI changes mentioned in its log are actually in this. Clicking on a plugin in the metadata editor now loads its values into the editor fields, with checks for edits and saving of edits when a new plugin is selected. Terminology is a bit confusing though, since edits aren't really 'saved' until the 'Apply Load Order' button is pressed. Maybe I should change that...

This commit is contained in:
WrinklyNinja
2013-05-09 08:11:09 +01:00
parent aa1c296296
commit 0c1dea158b
8 changed files with 401 additions and 132 deletions
+183 -40
View File
@@ -24,12 +24,20 @@
#include "editor.h"
#include <wx/statline.h>
#include <algorithm>
BEGIN_EVENT_TABLE( Editor, wxFrame )
EVT_LIST_ITEM_SELECTED( LIST_Plugins, Editor::OnPluginSelect )
EVT_SPINCTRL( SPIN_Priority, Editor::OnPriorityChange )
END_EVENT_TABLE()
using namespace std;
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);
messagesBook = new wxNotebook(this, wxID_ANY);
wxPanel * reqsTab = new wxPanel(filesBook);
wxPanel * incsTab = new wxPanel(filesBook);
@@ -43,36 +51,36 @@ Editor::Editor(const wxString title, wxFrame *parent) : wxFrame(parent, wxID_ANY
filesBook->AddPage(loadAfterTab, translate("Load After"));
messagesBook->AddPage(messagesTab, translate("Messages"), true);
messagesBook->AddPage(tagsTab, translate("Bash Tags"));
messagesBook->AddPage(tagsTab, translate("Bash Tag Suggestions"));
//Initialise controls.
pluginList = new wxListBox(this, LIST_Plugins);
pluginText = new wxStaticText(this, wxID_ANY, "");
prioritySpin = new wxSpinCtrl(this, SPIN_Priority, "0");
prioritySpin->SetRange(-10,10);
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"));
addMsgBtn = new wxButton(this, BUTTON_AddMessage, translate("Add Message"));
editMsgBtn = new wxButton(this, BUTTON_EditMessage, translate("Edit Message"));
removeMsgBtn = new wxButton(this, BUTTON_RemoveMessage, translate("Remove Message"));
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);
pluginList = new wxListCtrl(this, LIST_Plugins, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxLC_SINGLE_SEL);
reqsList = new wxListCtrl(reqsTab, LIST_Reqs, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxLC_SINGLE_SEL);
incsList = new wxListCtrl(incsTab, LIST_Incs, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxLC_SINGLE_SEL);
loadAfterList = new wxListCtrl(loadAfterTab, LIST_LoadAfter, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxLC_SINGLE_SEL);
messageList = new wxListCtrl(messagesTab, LIST_Messages, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxLC_SINGLE_SEL);
tagsList = new wxListCtrl(tagsTab, LIST_BashTags, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxLC_SINGLE_SEL);
//Set up list columns.
pluginList->AppendColumn(translate("Plugins"));
reqsList->AppendColumn(translate("Filename"));
reqsList->AppendColumn(translate("Display Name"));
reqsList->AppendColumn(translate("Condition"));
@@ -101,7 +109,7 @@ Editor::Editor(const wxString title, wxFrame *parent) : wxFrame(parent, wxID_ANY
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);
bigBox->Add(vbox1, 1, wxEXPAND|wxALL, 5);
wxBoxSizer * mainBox = new wxBoxSizer(wxVERTICAL);
@@ -135,48 +143,183 @@ Editor::Editor(const wxString title, wxFrame *parent) : wxFrame(parent, wxID_ANY
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);
tabBox4->Add(messageList, 0, wxEXPAND);
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);
tabBox5->Add(tagsList, 0, wxEXPAND);
tagsTab->SetSizer(tabBox5);
mainBox->Add(messagesBook, 1, wxEXPAND);
wxBoxSizer * hbox3 = new wxBoxSizer(wxHORIZONTAL);
hbox3->Add(addMsgBtn, 0, wxTOP|wxLEFT|wxRIGHT, 10);
hbox3->Add(editMsgBtn, 0, wxTOP|wxLEFT|wxRIGHT, 10);
hbox3->Add(removeMsgBtn, 0, wxTOP|wxLEFT|wxRIGHT, 10);
mainBox->Add(hbox3);
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->Add(hbox5, 0, wxBOTTOM, 20);
mainBox->AddSpacer(20);
sortingButtons = new wxBoxSizer(wxHORIZONTAL);
sortingButtons->Add(recalcBtn, 0, wxALL, 5);
sortingButtons->Add(applyBtn, 0, wxALL, 5);
sortingButtons->Add(cancelBtn, 0, wxALL, 5);
mainBox->Add(sortingButtons);
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);
bigBox->Add(mainBox, 2, wxEXPAND|wxALL, 5);
SetBackgroundColour(wxColour(255,255,255));
SetSizerAndFit(bigBox);
}
void Editor::SetList(const std::vector<boss::Plugin>& basePlugins, const std::vector<boss::Plugin>& editedPlugins) {
_basePlugins = basePlugins;
_editedPlugins = editedPlugins;
//Fill pluginList with the contents of basePlugins.
for (int i=0, max=_basePlugins.size(); i < max; ++i) {
pluginList->InsertItem(i, _basePlugins[i].Name());
}
pluginList->SetColumnWidth(0, wxLIST_AUTOSIZE);
Layout();
}
void Editor::IsSorted(bool sorted) {
sortingButtons->ShowItems(sorted);
Layout();
}
void Editor::OnPluginSelect(wxListEvent& event) {
//Create Plugin object for selected plugin.
boss::Plugin plugin = boss::Plugin(string(pluginList->GetItemText(event.GetIndex()).ToUTF8()));
//Check if the selected plugin is the same as the current plugin.
if (currentPlugin != plugin) {
//Check if there are edits made to the current plugin compared to its original.
if (IsCurrentPluginEdited()) {
//Ask if changes should be saved.
wxMessageDialog *dlg = new wxMessageDialog(this,
translate("The current edits are not saved. Do you want to save them?"),
translate("BOSS: Metadata Editor"), wxYES_NO);
if (dlg->ShowModal() == wxID_YES) {
//Save changes.
boss::Plugin diff = currentPlugin.DiffMetadata(GetOriginal(currentPlugin, false));
vector<boss::Plugin>::iterator it = std::find(_editedPlugins.begin(), _editedPlugins.end(), diff);
if (it != _editedPlugins.end())
*it = diff;
else
_editedPlugins.push_back(diff);
}
}
plugin = GetOriginal(plugin, true);
//Now fill editor fields with new plugin's info.
pluginText->SetLabelText(wxString(plugin.Name().c_str(), wxConvUTF8));
prioritySpin->SetValue(plugin.Priority());
enableUserEditsBox->SetValue(plugin.Enabled());
loadAfterList->DeleteAllItems();
reqsList->DeleteAllItems();
incsList->DeleteAllItems();
messageList->DeleteAllItems();
tagsList->DeleteAllItems();
set<boss::File> files = plugin.LoadAfter();
int i=0;
for (set<boss::File>::const_iterator it=files.begin(), endit=files.end(); it != endit; ++it) {
loadAfterList->InsertItem(i, wxString(it->Name().c_str(), wxConvUTF8));
loadAfterList->SetItem(i, 1, wxString(it->DisplayName().c_str(), wxConvUTF8));
loadAfterList->SetItem(i, 2, wxString(it->Condition().c_str(), wxConvUTF8));
++i;
}
files = plugin.Reqs();
i=0;
for (set<boss::File>::const_iterator it=files.begin(), endit=files.end(); it != endit; ++it) {
reqsList->InsertItem(i, wxString(it->Name().c_str(), wxConvUTF8));
reqsList->SetItem(i, 1, wxString(it->DisplayName().c_str(), wxConvUTF8));
reqsList->SetItem(i, 2, wxString(it->Condition().c_str(), wxConvUTF8));
++i;
}
files = plugin.Incs();
i=0;
for (set<boss::File>::const_iterator it=files.begin(), endit=files.end(); it != endit; ++it) {
incsList->InsertItem(i, wxString(it->Name().c_str(), wxConvUTF8));
incsList->SetItem(i, 1, wxString(it->DisplayName().c_str(), wxConvUTF8));
incsList->SetItem(i, 2, wxString(it->Condition().c_str(), wxConvUTF8));
++i;
}
list<boss::Message> messages = plugin.Messages();
i=0;
for (list<boss::Message>::const_iterator it=messages.begin(), endit=messages.end(); it != endit; ++it) {
messageList->InsertItem(i, wxString(it->Type().c_str(), wxConvUTF8));
messageList->SetItem(i, 1, wxString(it->Content().c_str(), wxConvUTF8));
messageList->SetItem(i, 2, wxString(it->Condition().c_str(), wxConvUTF8));
messageList->SetItem(i, 2, wxString(it->Language().c_str(), wxConvUTF8));
++i;
}
set<boss::Tag> tags = plugin.Tags();
i=0;
for (set<boss::Tag>::const_iterator it=tags.begin(), endit=tags.end(); it != endit; ++it) {
if (it->IsAddition())
tagsList->InsertItem(i, translate("Add"));
else
tagsList->InsertItem(i, translate("Remove"));
tagsList->SetItem(i, 1, wxString(it->Name().c_str(), wxConvUTF8));
tagsList->SetItem(i, 2, wxString(it->Condition().c_str(), wxConvUTF8));
++i;
}
currentPlugin = plugin;
}
}
void Editor::OnPriorityChange(wxSpinEvent& event) {
currentPlugin.Priority(event.GetPosition());
}
bool Editor::IsCurrentPluginEdited() const {
boss::Plugin original = GetOriginal(currentPlugin, true);
return (original.Priority() != currentPlugin.Priority()
|| original.Enabled() != currentPlugin.Enabled()
|| original.LoadAfter() != currentPlugin.LoadAfter()
|| original.Reqs() != currentPlugin.Reqs()
|| original.Incs() != currentPlugin.Incs()
|| original.Messages() != currentPlugin.Messages()
|| original.Tags() != currentPlugin.Tags());
}
boss::Plugin Editor::GetOriginal(const boss::Plugin& plugin, bool withEdits) const {
//Merges together the base and (saved) edited plugin info.
boss::Plugin p;
vector<boss::Plugin>::const_iterator it = std::find(_basePlugins.begin(), _basePlugins.end(), plugin);
if (it != _basePlugins.end())
p = *it;
if (withEdits) {
it = std::find(_editedPlugins.begin(), _editedPlugins.end(), plugin);
if (it != _editedPlugins.end())
p.Merge(*it, true);
}
return p;
}
+22 -10
View File
@@ -35,8 +35,16 @@ class Editor : public wxFrame {
public:
Editor(const wxString title, wxFrame *parent);
void SetList(const std::vector<boss::Plugin>& basePlugins, const std::vector<boss::Plugin>& editedPlugins);
void IsSorted(bool sorted);
void OnPluginSelect(wxListEvent& event);
void OnPriorityChange(wxSpinEvent& event);
DECLARE_EVENT_TABLE()
private:
wxListBox * pluginList;
bool IsCurrentPluginEdited() const;
boss::Plugin GetOriginal(const boss::Plugin& plugin, bool withEdits) const;
wxButton * addFileBtn;
wxButton * editFileBtn;
@@ -46,27 +54,31 @@ private:
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 * pluginList;
wxListCtrl * reqsList;
wxListCtrl * incsList;
wxListCtrl * loadAfterList;
wxListCtrl * messageList;
wxListCtrl * tagsList;
wxNotebook * filesBook;
wxNotebook * messagesBook;
wxCheckBox * enableUserEditsBox;
wxSpinCtrl * prioritySpin;
wxStaticText * pluginText;
std::vector<boss::Plugin> plugins;
wxBoxSizer * sortingButtons;
std::vector<boss::Plugin> _basePlugins, _editedPlugins;
boss::Plugin currentPlugin;
};
#endif
-3
View File
@@ -68,9 +68,6 @@ enum {
BUTTON_AddMessage,
BUTTON_EditMessage,
BUTTON_RemoveMessage,
BUTTON_AddTag,
BUTTON_EditTag,
BUTTON_RemoveTag,
BUTTON_SaveEdits,
BUTTON_UndoEdits,
BUTTON_Recalc,
+86 -34
View File
@@ -181,20 +181,8 @@ bool BossGUI::OnInit() {
break;
}
}
} else {
if (Game(GAME_NEHRIM, false).IsInstalledLocally()) //Before Oblivion because Nehrim installs can have Oblivion.esm for porting mods.
targetGame = GAME_NEHRIM;
else if (Game(GAME_TES4, false).IsInstalledLocally())
targetGame = GAME_TES4;
else if (Game(GAME_TES5, false).IsInstalledLocally())
targetGame = GAME_TES5;
else if (Game(GAME_FONV, false).IsInstalledLocally()) //Before Fallout 3 because some mods for New Vegas require Fallout3.esm.
targetGame = GAME_FONV;
else if (Game(GAME_FO3, false).IsInstalledLocally())
targetGame = GAME_FO3;
else
targetGame = detected[0];
}
} else
targetGame = detected[0];
targetGame = GAME_TES5;
Game game(targetGame);
@@ -210,30 +198,37 @@ bool BossGUI::OnInit() {
Launcher::Launcher(const wxChar *title, const YAML::Node& settings, const Game& game, const vector<unsigned int>& detectedGames) : wxFrame(NULL, wxID_ANY, title), _game(game), _detectedGames(detectedGames), _settings(settings) {
//Set up menu bar first.
MenuBar = new wxMenuBar();
// File Menu
FileMenu = new wxMenu();
//Initialise menu items.
wxMenuBar * MenuBar = new wxMenuBar();
wxMenu * FileMenu = new wxMenu();
wxMenu * EditMenu = new wxMenu();
GameMenu = new wxMenu();
wxMenu * HelpMenu = new wxMenu();
//Initialise controls.
wxButton * EditButton = new wxButton(this,OPTION_EditMetadata, translate("Edit Metadata"));
wxButton * SortButton = new wxButton(this,OPTION_SortPlugins, translate("Sort Plugins"));
ViewButton = new wxButton(this,OPTION_ViewLastReport, translate("View Last Report"));
//Construct menus.
//File Menu
FileMenu->Append(OPTION_ViewLastReport, translate("&View Last Report"), translate("Opens your last report."));
FileMenu->Append(OPTION_SortPlugins, translate("&Sort Plugins"), translate("Sorts your installed plugins."));
FileMenu->AppendSeparator();
FileMenu->Append(MENU_Quit, translate("&Quit"), translate("Quit BOSS."));
MenuBar->Append(FileMenu, translate("&File"));
//Edit Menu
EditMenu = new wxMenu();
EditMenu->Append(OPTION_EditMetadata, translate("&Metadata..."), translate("Opens a window where you can edit plugin metadata."));
EditMenu->Append(MENU_ShowSettings, translate("&Settings..."), translate("Opens the Settings window."));
MenuBar->Append(EditMenu, translate("&Edit"));
//Game menu
GameMenu = new wxMenu();
GameMenu->AppendRadioItem(MENU_Oblivion, wxT("&Oblivion"), translate("Switch to running BOSS for Oblivion."));
GameMenu->AppendRadioItem(MENU_Nehrim, wxT("&Nehrim"), translate("Switch to running BOSS for Nehrim."));
GameMenu->AppendRadioItem(MENU_Skyrim, wxT("&Skyrim"), translate("Switch to running BOSS for Skyrim."));
GameMenu->AppendRadioItem(MENU_Fallout3, wxT("&Fallout 3"), translate("Switch to running BOSS for Fallout 3."));
GameMenu->AppendRadioItem(MENU_FalloutNewVegas, wxT("&Fallout: New Vegas"), translate("Switch to running BOSS for Fallout: New Vegas."));
MenuBar->Append(GameMenu, translate("&Active Game"));
// About menu
HelpMenu = new wxMenu();
//About menu
HelpMenu->Append(MENU_OpenMainReadMe, translate("Open &Main Readme"), translate("Opens the main BOSS readme in your default web browser."));
HelpMenu->Append(MENU_OpenSyntaxReadMe, translate("Open &Metadata File Syntax Doc"), translate("Opens the BOSS metadata file syntax documentation in your default web browser."));
HelpMenu->Append(MENU_OpenAPIReadMe, translate("&Open API Readme"), translate("Opens the BOSS API readme in your default web browser."));
@@ -242,17 +237,14 @@ Launcher::Launcher(const wxChar *title, const YAML::Node& settings, const Game&
HelpMenu->AppendSeparator();
HelpMenu->Append(MENU_ShowAbout, translate("&About BOSS..."), translate("Shows information about BOSS."));
MenuBar->Append(HelpMenu, translate("&Help"));
SetMenuBar(MenuBar);
//Set up stuff in the frame.
SetBackgroundColour(wxColour(255,255,255));
//Add the three buttons.
//Set up layout.
wxBoxSizer *buttonBox = new wxBoxSizer(wxVERTICAL);
buttonBox->Add(EditButton = new wxButton(this,OPTION_EditMetadata, translate("Edit Metadata")), 1, wxEXPAND|wxALIGN_CENTRE|wxALL, 10);
buttonBox->Add(SortButton = new wxButton(this,OPTION_SortPlugins, translate("Sort Plugins")), 1, wxEXPAND|wxALIGN_CENTRE|wxLEFT|wxRIGHT, 10);
buttonBox->Add(ViewButton = new wxButton(this,OPTION_ViewLastReport, translate("View Last Report")), 1, wxEXPAND|wxALIGN_CENTRE|wxALL, 10);
buttonBox->Add(EditButton, 1, wxEXPAND|wxALIGN_CENTRE|wxALL, 10);
buttonBox->Add(SortButton, 1, wxEXPAND|wxALIGN_CENTRE|wxLEFT|wxRIGHT, 10);
buttonBox->Add(ViewButton, 1, wxEXPAND|wxALIGN_CENTRE|wxALL, 10);
//Set up initial state.
SortButton->SetDefault();
if (_game.Id() == GAME_TES4)
@@ -265,10 +257,15 @@ Launcher::Launcher(const wxChar *title, const YAML::Node& settings, const Game&
GameMenu->FindItem(MENU_Fallout3)->Check();
else if (_game.Id() == GAME_FONV)
GameMenu->FindItem(MENU_FalloutNewVegas)->Check();
if (!fs::exists(_game.ResultsPath()))
ViewButton->Enable(false);
DisableUndetectedGames();
//Now set the layout and sizes.
SetMenuBar(MenuBar);
SetBackgroundColour(wxColour(255,255,255));
SetSizerAndFit(buttonBox);
SetSize(wxSize(250, 200));
}
@@ -488,14 +485,41 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
out.close();
progDia->Destroy();
//Create editor window.
Editor *editor = new Editor(translate("BOSS: Metadata Editor"), this);
editor->SetIcon(wxIconLocation("BOSS.exe"));
//The 'plugins' list contains the merged plugin info, but we want to pass a vector of plugins with only masterlist info in its place, so have to construct that.
vector<boss::Plugin> pluginVec;
for (list<boss::Plugin>::const_iterator it=plugins.begin(), endit=plugins.end(); it != endit; ++it) {
boss::Plugin p = *it;
list<boss::Plugin>::iterator pos = std::find(mlist_plugins.begin(), mlist_plugins.end(), *it);
if (pos != mlist_plugins.end())
p.Merge(*pos);
pluginVec.push_back(p);
}
vector<boss::Plugin> ulistPluginVec(ulist_plugins.begin(), ulist_plugins.end());
//Pass plugin lists to editor window.
editor->SetList(pluginVec, ulistPluginVec);
//Tell the editor that it's not being shown as part of the load order sort process.
editor->IsSorted(true);
editor->Show();
ViewButton->Enable(true);
}
void Launcher::OnEditMetadata(wxCommandEvent& event) {
//Parse the userlist and masterlist and get a list of installed plugins.
list<boss::Plugin> plugins;
vector<boss::Plugin> plugins;
YAML::Node mlist, ulist;
list<boss::Plugin> mlist_plugins, ulist_plugins;
vector<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")) {
@@ -517,7 +541,7 @@ void Launcher::OnEditMetadata(wxCommandEvent& event) {
NULL);
}
if (mlist["plugins"])
mlist_plugins = mlist["plugins"].as< list<boss::Plugin> >();
mlist_plugins = mlist["plugins"].as< vector<boss::Plugin> >();
}
if (fs::exists(_game.UserlistPath())) {
@@ -532,12 +556,36 @@ void Launcher::OnEditMetadata(wxCommandEvent& event) {
NULL);
}
if (ulist["plugins"])
ulist_plugins = ulist["plugins"].as< list<boss::Plugin> >();
ulist_plugins = ulist["plugins"].as< vector<boss::Plugin> >();
}
//Cut out any plugins in the masterlist that aren't installed or in the userlist.
//Merge down to the plugin list so that it holds all uneditable metadata.
list<boss::Plugin> slim_mlist;
for (vector<boss::Plugin>::const_iterator it=mlist_plugins.begin(), endit=mlist_plugins.end(); it != endit; ++it) {
vector<boss::Plugin>::iterator pos = std::find(plugins.begin(), plugins.end(), *it);
if (pos != plugins.end())
pos->Merge(*it);
else if (std::find(ulist_plugins.begin(), ulist_plugins.end(), *it) != ulist_plugins.end())
plugins.push_back(*it);
}
//Sort into alphabetical order.
std::sort(plugins.begin(), plugins.end(), AlphaSortPlugins);
std::sort(ulist_plugins.begin(), ulist_plugins.end(), AlphaSortPlugins);
//Create editor window.
Editor *editor = new Editor(translate("BOSS: Metadata Editor"), this);
editor->SetIcon(wxIconLocation("BOSS.exe"));
//Pass plugin lists to editor window.
editor->SetList(plugins, ulist_plugins);
//Tell the editor that it's not being shown as part of the load order sort process.
editor->IsSorted(false);
editor->Show();
}
@@ -648,3 +696,7 @@ void Launcher::DisableUndetectedGames() {
SetTitle(wxT("BOSS - " + _game.Name())); //Don't need to convert name, known to be only ASCII chars.
}
bool Launcher::AlphaSortPlugins(const boss::Plugin& lhs, const boss::Plugin& rhs) {
return boost::to_lower_copy(lhs.Name()) < boost::to_lower_copy(rhs.Name());
}
+4 -8
View File
@@ -54,20 +54,16 @@ public:
DECLARE_EVENT_TABLE()
private:
wxMenuBar *MenuBar;
wxMenu *FileMenu;
wxMenu *EditMenu;
wxMenu *GameMenu;
wxMenu *HelpMenu;
wxButton *SortButton;
wxButton *ViewButton;
wxButton *EditButton;
wxMenu * GameMenu;
wxButton * ViewButton;
std::vector<unsigned int> _detectedGames;
boss::Game _game;
YAML::Node _settings; //BOSS Settings.
void DisableUndetectedGames();
static bool AlphaSortPlugins(const boss::Plugin& lhs, const boss::Plugin& rhs);
};
#endif
+34 -24
View File
@@ -34,6 +34,7 @@ using namespace std;
SettingsFrame::SettingsFrame(const wxString title, wxFrame *parent, YAML::Node& settings) : wxFrame(parent, wxID_ANY, title), _settings(settings) {
//Initialise drop-down list contents.
wxString DebugVerbosity[] = {
translate("None"),
translate("Low"),
@@ -58,9 +59,24 @@ SettingsFrame::SettingsFrame(const wxString title, wxFrame *parent, YAML::Node&
wxString("简体中文", wxConvUTF8)*/
};
//Set up stuff in the frame.
SetBackgroundColour(wxColour(255,255,255));
//Initialise controls.
GameChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 6, Game);
LanguageChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 1, Language);
LanguageChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 1, Language);
DebugVerbosityChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 4, DebugVerbosity);
OblivionURL = new wxTextCtrl(this, wxID_ANY);
NehrimURL = new wxTextCtrl(this, wxID_ANY);
SkyrimURL = new wxTextCtrl(this, wxID_ANY);
FO3URL = new wxTextCtrl(this, wxID_ANY);
FONVURL = new wxTextCtrl(this, wxID_ANY);
UpdateMasterlistBox = new wxCheckBox(this, wxID_ANY, translate("Update masterlist before sorting."));
wxButton * okBtn = new wxButton(this, OPTION_OKExitSettings, translate("OK"), wxDefaultPosition, wxSize(70, 30));
wxButton * cancelBtn = new wxButton(this, OPTION_CancelExitSettings, translate("Cancel"), wxDefaultPosition, wxSize(70, 30));
//Set up layout.
wxSizerFlags leftItem(1);
leftItem.Border(wxALL, 10).Expand().Left();
@@ -70,45 +86,44 @@ SettingsFrame::SettingsFrame(const wxString title, wxFrame *parent, YAML::Node&
wxSizerFlags wholeItem(1);
wholeItem.Border(wxALL, 10).Expand();
wxBoxSizer *bigBox = new wxBoxSizer(wxVERTICAL);
wxBoxSizer * bigBox = new wxBoxSizer(wxVERTICAL);
wxFlexGridSizer *GridSizer = new wxFlexGridSizer(2, 5, 5);
wxFlexGridSizer * GridSizer = new wxFlexGridSizer(2, 5, 5);
GridSizer->Add(new wxStaticText(this, wxID_ANY, translate("Default Game:")), leftItem);
GridSizer->Add(GameChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 6, Game), rightItem);
GridSizer->Add(GameChoice, rightItem);
GridSizer->Add(new wxStaticText(this, wxID_ANY, translate("Language:")), leftItem);
GridSizer->Add(LanguageChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 1, Language), rightItem);
GridSizer->Add(LanguageChoice, rightItem);
GridSizer->Add(new wxStaticText(this, wxID_ANY, translate("Debug Verbosity:")), leftItem);
GridSizer->Add(DebugVerbosityChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 4, DebugVerbosity), rightItem);
GridSizer->Add(DebugVerbosityChoice, rightItem);
GridSizer->Add(new wxStaticText(this, wxID_ANY, translate("Oblivion Masterlist URL:")), leftItem);
GridSizer->Add(OblivionURL = new wxTextCtrl(this, wxID_ANY), rightItem);
GridSizer->Add(OblivionURL, rightItem);
GridSizer->Add(new wxStaticText(this, wxID_ANY, translate("Nehrim Masterlist URL:")), leftItem);
GridSizer->Add(NehrimURL = new wxTextCtrl(this, wxID_ANY), rightItem);
GridSizer->Add(NehrimURL, rightItem);
GridSizer->Add(new wxStaticText(this, wxID_ANY, translate("Skyrim Masterlist URL:")), leftItem);
GridSizer->Add(SkyrimURL = new wxTextCtrl(this, wxID_ANY), rightItem);
GridSizer->Add(SkyrimURL, rightItem);
GridSizer->Add(new wxStaticText(this, wxID_ANY, translate("Fallout 3 Masterlist URL:")), leftItem);
GridSizer->Add(FO3URL = new wxTextCtrl(this, wxID_ANY), rightItem);
GridSizer->Add(FO3URL, rightItem);
GridSizer->Add(new wxStaticText(this, wxID_ANY, translate("Fallout: New Vegas Masterlist URL:")), leftItem);
GridSizer->Add(FONVURL = new wxTextCtrl(this, wxID_ANY), rightItem);
GridSizer->Add(FONVURL, rightItem);
bigBox->Add(GridSizer);
bigBox->Add(UpdateMasterlistBox = new wxCheckBox(this, wxID_ANY, translate("Update masterlist before sorting.")), wholeItem);
bigBox->Add(UpdateMasterlistBox, wholeItem);
wxString text = translate("Language settings will be applied after the BOSS GUI is restarted.");
bigBox->Add(new wxStaticText(this, wxID_ANY, text), wholeItem);
bigBox->Add(new wxStaticText(this, wxID_ANY, translate("Settings are applied after BOSS is restarted.")), wholeItem);
//Need to add 'OK' and 'Cancel' buttons.
wxBoxSizer *hbox = new wxBoxSizer(wxHORIZONTAL);
hbox->Add(new wxButton(this, OPTION_OKExitSettings, translate("OK"), wxDefaultPosition, wxSize(70, 30)));
hbox->Add(new wxButton(this, OPTION_CancelExitSettings, translate("Cancel"), wxDefaultPosition, wxSize(70, 30)), 0, wxLEFT, 20);
wxBoxSizer * hbox = new wxBoxSizer(wxHORIZONTAL);
hbox->Add(okBtn);
hbox->Add(cancelBtn, 0, wxLEFT, 20);
//Now add TabHolder and OK button to window sizer.
bigBox->Add(hbox, 0, wxCENTER|wxALL, 10);
@@ -120,6 +135,7 @@ SettingsFrame::SettingsFrame(const wxString title, wxFrame *parent, YAML::Node&
DebugVerbosityChoice->SetToolTip(translate("The output is logged to the BOSSDebugLog.txt file"));
//Now set the layout and sizes.
SetBackgroundColour(wxColour(255,255,255));
SetSizerAndFit(bigBox);
}
@@ -221,12 +237,6 @@ void SettingsFrame::OnQuit(wxCommandEvent& event) {
_settings["Masterlist URLs"]["Fallout New Vegas"] = string(FONVURL->GetValue().ToUTF8());
//Also set the logger settings now.
/* g_logger.setOriginTracking(gl_debug_with_source);
g_logger.setVerbosity(static_cast<LogVerbosity>(LV_WARN + gl_debug_verbosity));
if (gl_log_debug_output)
g_logger.setStream(debug_log_path.string().c_str());*/
YAML::Emitter yout;
yout.SetIndent(2);
yout << _settings;
+64 -13
View File
@@ -52,7 +52,7 @@ namespace boss {
}
bool FormID::operator == (const FormID& rhs) const {
return (plugin == rhs.Plugin() && id == rhs.Id());
return (boost::iequals(plugin, rhs.Plugin()) && id == rhs.Id());
}
bool FormID::operator != (const FormID& rhs) const {
@@ -114,6 +114,14 @@ namespace boss {
Message::Message(const std::string& t, const std::string& cont,
const std::string& cond, const std::string& l)
: type(t), language(l), ConditionalData(cond, cont) {}
bool Message::operator < (const Message& rhs) const {
return (Content() < rhs.Content());
}
bool Message::operator == (const Message& rhs) const {
return (boost::iequals(Type(), rhs.Type()) && boost::iequals(Content(), rhs.Content()));
}
std::string Message::Type() const {
return type;
@@ -136,6 +144,10 @@ namespace boss {
return (Name() < rhs.Name());
}
bool File::operator == (const File& rhs) const {
return boost::iequals(Name(), rhs.Name());
}
std::string File::Name() const {
return Data();
}
@@ -174,6 +186,10 @@ namespace boss {
return (PrefixedName() < rhs.PrefixedName());
}
bool Tag::operator == (const Tag& rhs) const {
return boost::iequals(PrefixedName(), rhs.PrefixedName());
}
bool Tag::IsAddition() const {
return addTag;
}
@@ -260,6 +276,7 @@ namespace boss {
return;
//The following should be replaced.
enabled = plugin.Enabled();
priority = plugin.Priority();
masters = plugin.Masters();
formIDs = plugin.FormIDs();
@@ -285,6 +302,42 @@ namespace boss {
return;
}
Plugin Plugin::DiffMetadata(const Plugin& plugin) const {
Plugin p(name);
p.Priority(priority);
//Compare this plugin against the given plugin.
set<File> files = plugin.LoadAfter();
set<File> filesDiff;
set_difference(files.begin(), files.end(), loadAfter.begin(), loadAfter.end(), inserter(filesDiff, filesDiff.begin()));
p.LoadAfter(filesDiff);
filesDiff.clear();
files = plugin.Reqs();
set_difference(files.begin(), files.end(), requirements.begin(), requirements.end(), inserter(filesDiff, filesDiff.begin()));
p.Reqs(filesDiff);
filesDiff.clear();
files = plugin.Incs();
set_difference(files.begin(), files.end(), incompatibilities.begin(), incompatibilities.end(), inserter(filesDiff, filesDiff.begin()));
p.Incs(filesDiff);
list<Message> msgs1 = plugin.Messages();
list<Message> msgs2 = messages;
msgs1.sort();
msgs2.sort();
list<Message> mDiff;
set_difference(msgs1.begin(), msgs1.end(), msgs2.begin(), msgs2.end(), inserter(mDiff, mDiff.begin()));
p.Messages(mDiff);
set<Tag> bashTags = plugin.Tags();
set<Tag> tagDiff;
set_difference(bashTags.begin(), bashTags.end(), tags.begin(), tags.end(), inserter(tagDiff, tagDiff.begin()));
p.Tags(tagDiff);
return p;
}
std::string Plugin::Name() const {
return name;
@@ -454,10 +507,8 @@ namespace boss {
boost::unordered_set<FormID,FormID_hash> Plugin::OverlapFormIDs(const Plugin& plugin) const {
boost::unordered_set<FormID,FormID_hash> otherFormIDs = plugin.FormIDs();
boost::unordered_set<FormID,FormID_hash> overlap;
for (boost::unordered_set<FormID,FormID_hash>::const_iterator it=formIDs.begin(), endIt=formIDs.end(); it != endIt; ++it) {
if (otherFormIDs.find(*it) != otherFormIDs.end())
overlap.insert(*it);
}
set_intersection(formIDs.begin(), formIDs.end(), otherFormIDs.begin(), otherFormIDs.end(), inserter(overlap, overlap.begin()));
return overlap;
}
@@ -479,14 +530,10 @@ namespace boss {
if (boost::iequals(*it, plugin.Name()))
return true;
}
for (set<File>::const_iterator it=requirements.begin(), endIt=requirements.end(); it != endIt; ++it) {
if (boost::iequals(it->Name(), plugin.Name()))
return true;
}
for (set<File>::const_iterator it=loadAfter.begin(), endIt=loadAfter.end(); it != endIt; ++it) {
if (boost::iequals(it->Name(), plugin.Name()))
return true;
}
if (find(requirements.begin(), requirements.end(), plugin) != requirements.end())
return true;
if (find(loadAfter.begin(), loadAfter.end(), plugin) != requirements.end())
return true;
return false;
}
@@ -508,4 +555,8 @@ namespace boss {
}
return issues;
}
bool operator == (const File& lhs, const Plugin& rhs) {
return boost::iequals(lhs.Name(), rhs.Name());
}
}
+8
View File
@@ -96,6 +96,9 @@ namespace boss {
Message(const std::string& type, const std::string& content);
Message(const std::string& type, const std::string& content,
const std::string& condition, const std::string& language);
bool operator < (const Message& rhs) const;
bool operator == (const Message& rhs) const;
std::string Type() const;
std::string Language() const;
@@ -113,6 +116,7 @@ namespace boss {
const std::string& condition);
bool operator < (const File& rhs) const;
bool operator == (const File& rhs) const;
std::string Name() const;
std::string DisplayName() const;
@@ -127,6 +131,7 @@ namespace boss {
Tag(const std::string& tag, const std::string& condition);
bool operator < (const Tag& rhs) const;
bool operator == (const Tag& rhs) const;
bool IsAddition() const;
std::string Name() const;
@@ -142,6 +147,7 @@ namespace boss {
Plugin(const boss::Game& game, const std::string& name);
void Merge(const Plugin& plugin, bool ifdDisabled = false);
Plugin DiffMetadata(const Plugin& plugin) const;
std::string Name() const;
bool Enabled() const;
@@ -201,6 +207,8 @@ namespace boss {
std::string version; //Obtained from description field.
bool isMaster;
};
bool operator == (const File& lhs, const Plugin& rhs);
}
#endif