diff --git a/src/gui/editor.cpp b/src/gui/editor.cpp index 875e5bd0..8b52dbea 100644 --- a/src/gui/editor.cpp +++ b/src/gui/editor.cpp @@ -52,457 +52,10 @@ bool TextDropTarget::OnDropText(wxCoord x, wxCoord y, const wxString &data) { } /////////////////////////////////// -// Common Editor Class +// EditorPanel Class /////////////////////////////////// -CommonEditor::CommonEditor(const std::list& plugins, const loot::Game& game) : _basePlugins(plugins), _game(game) {} - -CommonEditor::CommonEditor(const std::list& plugins, const loot::Game& game, std::list& editedPlugins) : _basePlugins(plugins), _game(game), _editedPlugins(editedPlugins) {} - -loot::Plugin CommonEditor::GetMasterData(const wxString& plugin) const { - BOOST_LOG_TRIVIAL(debug) << "Getting hardcoded and masterlist metadata for plugin: " << plugin.ToUTF8(); - loot::Plugin p; - loot::Plugin p_in(string(plugin.ToUTF8())); - - list::const_iterator it = std::find(_basePlugins.begin(), _basePlugins.end(), p_in); - - if (it != _basePlugins.end()) - p = *it; - - return p; -} - -loot::Plugin CommonEditor::GetUserData(const wxString& plugin) const { - BOOST_LOG_TRIVIAL(debug) << "Getting userlist metadata for plugin: " << plugin.ToUTF8(); - loot::Plugin p(string(plugin.ToUTF8())); - - list::const_iterator it = std::find(_editedPlugins.begin(), _editedPlugins.end(), p); - - if (it != _editedPlugins.end()) - p = *it; - - return p; -} - -void CommonEditor::ApplyEdits(const wxString& plugin, wxListView * wxList) { - BOOST_LOG_TRIVIAL(debug) << "Applying edits to plugin: " << plugin.ToUTF8(); - - //Get recorded data. - loot::Plugin master(GetMasterData(plugin)); - loot::Plugin edited(GetNewData(plugin)); - - loot::Plugin diff = master.DiffMetadata(edited); - - list::iterator pos = std::find(_editedPlugins.begin(), _editedPlugins.end(), diff); - long i = wxList->FindItem(-1, plugin); - - if (!diff.HasNameOnly()) { - wxList->SetItemFont(i, wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold()); - if (pos != _editedPlugins.end()) - *pos = diff; - else - _editedPlugins.push_back(diff); - } - else { - wxList->SetItemFont(i, wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - if (pos != _editedPlugins.end()) - _editedPlugins.erase(pos); //Prevents unnecessary writes. - } -} - -loot::File CommonEditor::RowToFile(wxListView * list, long row) const { - return loot::File( - string(list->GetItemText(row, 0).ToUTF8()), - string(list->GetItemText(row, 1).ToUTF8()), - string(list->GetItemText(row, 2).ToUTF8()) - ); -} - -loot::Tag CommonEditor::RowToTag(wxListView * list, long row) const { - string name = string(list->GetItemText(row, 1).ToUTF8()); - - if (list->GetItemText(row, 0) == State[1]) - return loot::Tag( - name, - false, - string(list->GetItemText(row, 2).ToUTF8()) - ); - else - return loot::Tag( - name, - true, - string(list->GetItemText(row, 2).ToUTF8()) - ); -} - -loot::PluginDirtyInfo CommonEditor::RowToPluginDirtyInfo(wxListView * list, long row) const { - string text(list->GetItemText(row, 0).ToUTF8()); - uint32_t crc = strtoul(text.c_str(), nullptr, 16); - return loot::PluginDirtyInfo( - crc, - atoi(string(list->GetItemText(row, 1).ToUTF8()).c_str()), - atoi(string(list->GetItemText(row, 2).ToUTF8()).c_str()), - atoi(string(list->GetItemText(row, 3).ToUTF8()).c_str()), - string(list->GetItemText(row, 4).ToUTF8())); -} - - -/////////////////////////////////// -// Mini Editor Class -/////////////////////////////////// - - -MiniEditor::MiniEditor(wxWindow *parent, const wxString& title, const std::list& plugins, const loot::Game& game) : wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), CommonEditor(plugins, game) { - //Initialise editing panel. - editingPanel = new wxPanel(this, wxID_ANY); - - //Initialise controls. - feedbackText = translate("If LOOT has gotten something wrong, please let the team know. See the Contributing To LOOT section of the readme for details."); - pluginText = new wxStaticText(editingPanel, wxID_ANY, ""); - descText = new wxStaticText(this, wxID_ANY, feedbackText); - prioritySpin = new wxSpinCtrl(editingPanel, wxID_ANY, "0"); - prioritySpin->SetRange(-999999, 999999); - priorityCheckbox = new wxCheckBox(editingPanel, wxID_ANY, translate("Compare priority against all other plugins.")); - filterCheckbox = new wxCheckBox(editingPanel, CHECKBOX_Filter, translate("Show only conflicting plugins")); - - pluginList = new wxListView(this, LIST_Plugins, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL); - loadAfterList = new wxListView(editingPanel, LIST_LoadAfter, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL); - loadAfterList->SetDropTarget(new TextDropTarget(loadAfterList, pluginText)); - - removeBtn = new wxButton(editingPanel, BUTTON_RemoveRow, translate("Remove Plugin")); - - //Set up list columns. - pluginList->AppendColumn(translate("Plugin")); - pluginList->AppendColumn(translate("Priority")); - pluginList->AppendColumn(translate("Global Priority")); - - loadAfterList->AppendColumn(translate("Filename")); - loadAfterList->AppendColumn(translate("Display Name")); - loadAfterList->AppendColumn(translate("Condition")); - loadAfterList->SetColumnWidth(0, wxLIST_AUTOSIZE_USEHEADER); - loadAfterList->SetColumnWidth(1, 0); //Hide this from the user. - loadAfterList->SetColumnWidth(2, 0); //Hide this from the user. - - //Initialise control states. - removeBtn->Enable(false); - prioritySpin->Enable(false); - filterCheckbox->Enable(false); - - //Make plugin name bold text. - pluginText->SetFont(pluginText->GetFont().Bold()); - - //Set up event handling. - Bind(wxEVT_LIST_ITEM_SELECTED, &MiniEditor::OnPluginSelect, this, LIST_Plugins); - Bind(wxEVT_LIST_BEGIN_DRAG, &MiniEditor::OnDragStart, this, LIST_Plugins); - Bind(wxEVT_LIST_ITEM_SELECTED, &MiniEditor::OnRowSelect, this, LIST_LoadAfter); - Bind(wxEVT_BUTTON, &MiniEditor::OnRemoveRow, this, BUTTON_RemoveRow); - Bind(wxEVT_CHECKBOX, &MiniEditor::OnFilterToggle, this, CHECKBOX_Filter); - Bind(wxEVT_BUTTON, &MiniEditor::OnApply, this, wxID_APPLY); - Bind(wxEVT_SIZE, &MiniEditor::OnResize, this); - - //Set up tooltips. - pluginList->SetToolTip(translate("Select a plugin to edit its load order metadata.")); - loadAfterList->SetToolTip(translate("Drag and drop a plugin here to make the selected plugin load after it. The \"Show only conflicting plugins\" checkbox must be checked.")); - prioritySpin->SetToolTip(translate("Plugins with higher priorities will load after plugins with smaller priorities that they conflict with, unless one must explicitly load after the other.")); - filterCheckbox->SetToolTip(translate("Filters the plugin list to only display plugins which can be loaded after the currently selected plugin, and which either conflict with it, or, if it loads a BSA, also load BSAs. Also enables drag and drop of plugins into the Load After box.")); - removeBtn->SetToolTip(translate("Only newly-added plugins may be removed here. Use the metadata editor to remove other user-added plugins.")); - priorityCheckbox->SetToolTip(translate("Otherwise, priorities are only compared between conflicting plugins.")); - - //Set up editing panel layout. - wxBoxSizer * mainBox = new wxBoxSizer(wxVERTICAL); - mainBox->Add(pluginText, 0, wxTOP | wxBOTTOM, 10); - mainBox->Add(filterCheckbox, 0, wxTOP | wxBOTTOM, 10); - - wxBoxSizer * hbox2 = new wxBoxSizer(wxHORIZONTAL); - hbox2->Add(new wxStaticText(editingPanel, wxID_ANY, translate("Priority: ")), 0, wxRIGHT, 5); - hbox2->Add(prioritySpin, 0, wxRIGHT, 5); - mainBox->Add(hbox2, 0, wxEXPAND | wxBOTTOM, 10); - mainBox->Add(priorityCheckbox, 0, wxEXPAND | wxBOTTOM, 10); - - wxStaticBoxSizer * staticBox = new wxStaticBoxSizer(wxVERTICAL, editingPanel, translate("Load After")); - staticBox->Add(loadAfterList, 1, wxEXPAND); - staticBox->Add(removeBtn, 0, wxEXPAND | wxALIGN_RIGHT | wxTOP, 5); - mainBox->Add(staticBox, 1, wxEXPAND); - - editingPanel->SetSizerAndFit(mainBox); - editingPanel->Layout(); - - //Set up rest of layout. - wxBoxSizer * bigBox = new wxBoxSizer(wxVERTICAL); - - wxBoxSizer * hBox = new wxBoxSizer(wxHORIZONTAL); - hBox->Add(pluginList, 1, wxEXPAND | wxALL, 10); - hBox->Add(editingPanel, 0, wxEXPAND | wxTOP | wxBOTTOM | wxRIGHT, 10); - bigBox->Add(hBox, 1, wxEXPAND | wxALL, 5); - - bigBox->Add(descText, 0, wxEXPAND|wxLEFT|wxRIGHT|wxBOTTOM, 15); - - //Need to add 'Yes' and 'No' buttons. - wxSizer * sizer = CreateSeparatedButtonSizer(wxAPPLY | wxCANCEL); - - //Now add buttons to window sizer. - if (sizer != nullptr) - bigBox->Add(sizer, 0, wxEXPAND | wxLEFT | wxBOTTOM | wxRIGHT, 15); - - //Fill pluginList with the contents of basePlugins. - int i = 0; - for (const auto &plugin: _basePlugins) { - pluginList->InsertItem(i, FromUTF8(plugin.Name())); - pluginList->SetItem(i, 1, FromUTF8(to_string(loot::modulo(plugin.Priority(), loot::max_priority)))); - if (abs(plugin.Priority()) >= loot::max_priority) - pluginList->SetItem(i, 2, FromUTF8("\xE2\x9C\x93")); - else - pluginList->SetItem(i, 2, FromUTF8("\xE2\x9C\x97")); - if (plugin.FormIDs().empty()) { - pluginList->SetItemTextColour(i, wxColour(122, 122, 122)); - } - else if (plugin.LoadsBSA(_game)) { - pluginList->SetItemTextColour(i, wxColour(0, 142, 219)); - } - ++i; - } - pluginList->SetColumnWidth(0, wxLIST_AUTOSIZE); - pluginList->SetColumnWidth(1, 0); - pluginList->SetColumnWidth(2, 0); - descText->Wrap(pluginList->GetClientSize().GetWidth()); - - SetBackgroundColour(wxColour(255, 255, 255)); - SetIcon(wxIconLocation("LOOT.exe")); - - editingPanel->Hide(); - SetSizerAndFit(bigBox); -} - -void MiniEditor::OnPluginSelect(wxListEvent& event) { - //Create Plugin object for selected plugin. - wxString selectedPlugin = pluginList->GetItemText(event.GetIndex()); - wxString currentPlugin = pluginText->GetLabelText(); - - //Check if the selected plugin is the same as the current plugin. - if (selectedPlugin != currentPlugin) { - BOOST_LOG_TRIVIAL(debug) << "User selected plugin: " << selectedPlugin.ToUTF8(); - - //Apply any current edits. - if (!currentPlugin.empty()) { - ApplyEdits(currentPlugin, pluginList); - //Also update the item's priority value in the plugins list in case it has changed. - pluginList->SetItem(pluginList->FindItem(-1, currentPlugin), 1, FromUTF8(to_string(prioritySpin->GetValue()))); - if (priorityCheckbox->IsChecked()) - pluginList->SetItem(pluginList->FindItem(-1, currentPlugin), 2, FromUTF8("\xE2\x9C\x93")); - else - pluginList->SetItem(pluginList->FindItem(-1, currentPlugin), 2, FromUTF8("\xE2\x9C\x97")); - } - - //Merge metadata. - loot::Plugin plugin = GetMasterData(selectedPlugin); - plugin.MergeMetadata(GetUserData(selectedPlugin)); - - //Now fill editor fields with new plugin's info and update control states. - BOOST_LOG_TRIVIAL(debug) << "Filling editor fields with plugin info."; - pluginText->SetLabelText(FromUTF8(plugin.Name())); - - prioritySpin->SetValue(loot::modulo(plugin.Priority(), loot::max_priority)); - - if (abs(plugin.Priority()) >= loot::max_priority) - priorityCheckbox->SetValue(true); - else - priorityCheckbox->SetValue(false); - - loadAfterList->DeleteAllItems(); - set files = plugin.LoadAfter(); - int i = 0; - for (const auto &file: files) { - loadAfterList->InsertItem(i, FromUTF8(file.Name())); - ++i; - } - if (loadAfterList->GetItemCount() == 0) - loadAfterList->SetColumnWidth(0, wxLIST_AUTOSIZE_USEHEADER); - else - loadAfterList->SetColumnWidth(0, wxLIST_AUTOSIZE); - - //Set control states. - prioritySpin->Enable(true); - filterCheckbox->Enable(true); - removeBtn->Enable(false); - } - - //Change layout. - if (pluginList->GetColumnWidth(1) == 0) { - pluginList->SetColumnWidth(1, wxLIST_AUTOSIZE_USEHEADER); - pluginList->SetColumnWidth(2, wxLIST_AUTOSIZE_USEHEADER); - } - if (!editingPanel->IsShown()) - editingPanel->Show(); - - //Window may need to be resized. - //Layout() doesn't do anything extra, it automatically gets called by the windows. - //InvalidateBestSize() doesn't do anything useful for the panel or the window. - pluginList->InvalidateBestSize(); //Makes the priority column visible without scrolling. - loadAfterList->InvalidateBestSize(); //Fixes long plugin filenames being cut off. - editingPanel->Fit(); //Fits the editing panel to the pluginText length. - editingPanel->SetMinSize(editingPanel->GetSize()); //Makes sure that the editing panel is not cut off when Fit() is called below. - descText->SetLabel(""); //If this isn't cleared, it'll stop the window resizing properly sometimes. - if (GetBestSize().GetHeight() > GetSize().GetHeight() || GetBestSize().GetWidth() > GetSize().GetWidth()) { - Fit(); - } - else { - descText->SetLabel(feedbackText); - descText->Wrap(GetClientSize().GetWidth() - 30); - } -} - -void MiniEditor::OnFilterToggle(wxCommandEvent& event) { - //First need to merge the base and edited plugin lists so that the right priority values get displayed. - - list plugins(_basePlugins); - for (const auto &plugin: _editedPlugins) { - list::iterator pos = std::find(plugins.begin(), plugins.end(), plugin); - pos->MergeMetadata(plugin); - } - - //Disable list selection. - if (event.IsChecked()) - Unbind(wxEVT_LIST_ITEM_SELECTED, &MiniEditor::OnPluginSelect, this, LIST_Plugins); - else - Bind(wxEVT_LIST_ITEM_SELECTED, &MiniEditor::OnPluginSelect, this, LIST_Plugins); - - pluginList->Freeze(); - if (event.IsChecked()) { - loot::Plugin plugin(string(pluginText->GetLabelText().ToUTF8())); - list::const_iterator pos = std::find(plugins.begin(), plugins.end(), plugin); - - if (pos != plugins.end()) { - pluginList->DeleteAllItems(); - - bool loadsBSA = pos->LoadsBSA(_game); - - int i = 0; - for (const auto &plugin: plugins) { - //Want to filter to show only those the selected plugin can load after validly, and which also either conflict with it, - //or which load a BSA (if the selected plugin loads a BSA). - if (plugin == *pos || !plugin.MustLoadAfter(*pos) && (pos->DoFormIDsOverlap(plugin) || (loadsBSA && plugin.LoadsBSA(_game)))) { - pluginList->InsertItem(i, FromUTF8(plugin.Name())); - pluginList->SetItem(i, 1, FromUTF8(to_string(plugin.Priority()))); - if (plugin.FormIDs().empty()) { - pluginList->SetItemTextColour(i, wxColour(122, 122, 122)); - } - else if (plugin.LoadsBSA(_game)) { - pluginList->SetItemTextColour(i, wxColour(0, 142, 219)); - } - if (std::find(_editedPlugins.begin(), _editedPlugins.end(), plugin) != _editedPlugins.end()) { - pluginList->SetItemFont(i, wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold()); - } - ++i; - } - } - } - } - else { - pluginList->DeleteAllItems(); - int i = 0; - for (const auto &plugin: plugins) { - pluginList->InsertItem(i, FromUTF8(plugin.Name())); - pluginList->SetItem(i, 1, FromUTF8(to_string(plugin.Priority()))); - if (plugin.FormIDs().empty()) { - pluginList->SetItemTextColour(i, wxColour(122, 122, 122)); - } - else if (plugin.LoadsBSA(_game)) { - pluginList->SetItemTextColour(i, wxColour(0, 142, 219)); - } - if (std::find(_editedPlugins.begin(), _editedPlugins.end(), plugin) != _editedPlugins.end()) { - pluginList->SetItemFont(i, wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold()); - } - ++i; - } - } - - //Now re-select the current plugin in the list. - pluginList->Select(pluginList->FindItem(-1, pluginText->GetLabelText())); - pluginList->Thaw(); - Refresh(); -} - -void MiniEditor::OnRowSelect(wxListEvent& event) { - loot::File file(string(loadAfterList->GetItemText(event.GetIndex(), 0).ToUTF8())); - loot::Plugin plugin(string(pluginText->GetLabelText().ToUTF8())); - - list::const_iterator it = std::find(_basePlugins.begin(), _basePlugins.end(), plugin); - - if (it != _basePlugins.end()) - plugin = *it; - else - BOOST_LOG_TRIVIAL(warning) << "Could not find plugin in base list: " << plugin.Name(); - - set loadAfter = plugin.LoadAfter(); - - if (loadAfter.find(file) == loadAfter.end()) { - BOOST_LOG_TRIVIAL(trace) << "File \"" << file.Name() << "\" was not found in base plugin metadata. Removal enabled."; - removeBtn->Enable(true); - } - else { - BOOST_LOG_TRIVIAL(trace) << "File \"" << file.Name() << "\" was found in base plugin metadata. Removal disabled."; - removeBtn->Enable(false); - } -} - -void MiniEditor::OnRemoveRow(wxCommandEvent& event) { - loadAfterList->DeleteItem(loadAfterList->GetFirstSelected()); - removeBtn->Enable(false); -} - -void MiniEditor::OnDragStart(wxListEvent& event) { - wxTextDataObject data(pluginList->GetItemText(event.GetItem())); - wxDropSource dropSource(pluginList); - dropSource.SetData(data); - wxDragResult result = dropSource.DoDragDrop(); -} - -void MiniEditor::OnApply(wxCommandEvent& event) { - //Apply any current edits. - wxString currentPlugin = pluginText->GetLabelText(); - if (!currentPlugin.empty()) - ApplyEdits(currentPlugin, pluginList); - - EndModal(event.GetId()); -} - -const std::list& MiniEditor::GetEditedPlugins() const { - return _editedPlugins; -} - -loot::Plugin MiniEditor::GetNewData(const wxString& plugin) const { - //Get new data. Because most of it is missing in the MiniEditor, start with the existing data. - loot::Plugin edited(GetMasterData(plugin)); - - int priority = prioritySpin->GetValue(); - if (priorityCheckbox->IsChecked()) { - if (priority < 0) - priority -= loot::max_priority; - else - priority += loot::max_priority; - } - edited.Priority(priority); - - set files; - for (int i = 0, max = loadAfterList->GetItemCount(); i < max; ++i) { - files.insert(RowToFile(loadAfterList, i)); - } - edited.LoadAfter(files); - - return edited; -} - -void MiniEditor::OnResize(wxSizeEvent& event) { - descText->SetLabel(feedbackText); - descText->Wrap(GetClientSize().GetWidth()-30); - event.Skip(); -} - -/////////////////////////////////// -// Editor Class -/////////////////////////////////// - -Editor::Editor(wxWindow *parent, const wxString& title, const std::string userlistPath, const std::list& basePlugins, std::list& editedPlugins, const unsigned int language, const loot::Game& game) : wxFrame(parent, wxID_ANY, title), _userlistPath(userlistPath), CommonEditor(basePlugins, game, editedPlugins) { +EditorPanel::EditorPanel(wxWindow *parent, const std::list& basePlugins, std::list& editedPlugins, const unsigned int language, const loot::Game& game) : wxPanel(parent, wxID_ANY), _basePlugins(basePlugins), _game(game), _editedPlugins(editedPlugins) { //Initialise child windows. listBook = new wxNotebook(this, BOOK_Lists); @@ -524,15 +77,13 @@ Editor::Editor(wxWindow *parent, const wxString& title, const std::string userli addBtn = new wxButton(this, BUTTON_AddRow, translate("Add File")); editBtn = new wxButton(this, BUTTON_EditRow, translate("Edit File")); removeBtn = new wxButton(this, BUTTON_RemoveRow, translate("Remove File")); - applyBtn = new wxButton(this, BUTTON_Apply, translate("Save Changes")); - cancelBtn = new wxButton(this, BUTTON_Cancel, translate("Cancel")); - pluginList = new wxListView(this, LIST_Plugins, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxLC_SINGLE_SEL); - reqsList = new wxListView(reqsTab, LIST_Reqs, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxLC_SINGLE_SEL); - incsList = new wxListView(incsTab, LIST_Incs, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxLC_SINGLE_SEL); - loadAfterList = new wxListView(loadAfterTab, LIST_LoadAfter, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxLC_SINGLE_SEL); - tagsList = new wxListView(tagsTab, LIST_BashTags, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxLC_SINGLE_SEL); - dirtyList = new wxListView(dirtyTab, LIST_DirtyInfo, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxLC_SINGLE_SEL); + pluginList = new wxListView(this, LIST_Plugins, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL); + reqsList = new wxListView(reqsTab, LIST_Reqs, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL); + incsList = new wxListView(incsTab, LIST_Incs, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL); + loadAfterList = new wxListView(loadAfterTab, LIST_LoadAfter, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL); + tagsList = new wxListView(tagsTab, LIST_BashTags, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL); + dirtyList = new wxListView(dirtyTab, LIST_DirtyInfo, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL); messageList = new MessageList(messagesTab, LIST_Messages, language); pluginMenu = new wxMenu(); @@ -595,26 +146,24 @@ Editor::Editor(wxWindow *parent, const wxString& title, const std::string userli pluginCheckbox->SetFont(font); //Set up event handling. - Bind(wxEVT_LIST_ITEM_SELECTED, &Editor::OnPluginSelect, this, LIST_Plugins); - Bind(wxEVT_LIST_ITEM_SELECTED, &Editor::OnRowSelect, this, LIST_Reqs); - Bind(wxEVT_LIST_ITEM_SELECTED, &Editor::OnRowSelect, this, LIST_Incs); - Bind(wxEVT_LIST_ITEM_SELECTED, &Editor::OnRowSelect, this, LIST_LoadAfter); - Bind(wxEVT_LIST_ITEM_SELECTED, &Editor::OnRowSelect, this, LIST_Messages); - Bind(wxEVT_LIST_ITEM_SELECTED, &Editor::OnRowSelect, this, LIST_BashTags); - Bind(wxEVT_LIST_ITEM_SELECTED, &Editor::OnRowSelect, this, LIST_DirtyInfo); - Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &Editor::OnListBookChange, this, BOOK_Lists); - Bind(wxEVT_BUTTON, &Editor::OnQuit, this, BUTTON_Apply); - Bind(wxEVT_BUTTON, &Editor::OnQuit, this, BUTTON_Cancel); - Bind(wxEVT_BUTTON, &Editor::OnAddRow, this, BUTTON_AddRow); - Bind(wxEVT_BUTTON, &Editor::OnEditRow, this, BUTTON_EditRow); - Bind(wxEVT_BUTTON, &Editor::OnRemoveRow, this, BUTTON_RemoveRow); - Bind(wxEVT_LIST_ITEM_RIGHT_CLICK, &Editor::OnPluginListRightClick, this); - Bind(wxEVT_MENU, &Editor::OnPluginCopyName, this, MENU_CopyName); - Bind(wxEVT_MENU, &Editor::OnPluginCopyMetadata, this, MENU_CopyMetadata); - Bind(wxEVT_MENU, &Editor::OnPluginClearMetadata, this, MENU_ClearPluginMetadata); - Bind(wxEVT_MENU, &Editor::OnClearAllMetadata, this, MENU_ClearAllMetadata); - Bind(wxEVT_LIST_BEGIN_DRAG, &Editor::OnDragStart, this, LIST_Plugins); - Bind(wxEVT_CHECKBOX, &Editor::OnFilterToggle, this, CHECKBOX_Filter); + Bind(wxEVT_LIST_ITEM_SELECTED, &EditorPanel::OnPluginSelect, this, LIST_Plugins); + Bind(wxEVT_LIST_ITEM_SELECTED, &EditorPanel::OnRowSelect, this, LIST_Reqs); + Bind(wxEVT_LIST_ITEM_SELECTED, &EditorPanel::OnRowSelect, this, LIST_Incs); + Bind(wxEVT_LIST_ITEM_SELECTED, &EditorPanel::OnRowSelect, this, LIST_LoadAfter); + Bind(wxEVT_LIST_ITEM_SELECTED, &EditorPanel::OnRowSelect, this, LIST_Messages); + Bind(wxEVT_LIST_ITEM_SELECTED, &EditorPanel::OnRowSelect, this, LIST_BashTags); + Bind(wxEVT_LIST_ITEM_SELECTED, &EditorPanel::OnRowSelect, this, LIST_DirtyInfo); + Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &EditorPanel::OnListBookChange, this, BOOK_Lists); + Bind(wxEVT_BUTTON, &EditorPanel::OnAddRow, this, BUTTON_AddRow); + Bind(wxEVT_BUTTON, &EditorPanel::OnEditRow, this, BUTTON_EditRow); + Bind(wxEVT_BUTTON, &EditorPanel::OnRemoveRow, this, BUTTON_RemoveRow); + Bind(wxEVT_LIST_ITEM_RIGHT_CLICK, &EditorPanel::OnPluginListRightClick, this); + Bind(wxEVT_MENU, &EditorPanel::OnPluginCopyName, this, MENU_CopyName); + Bind(wxEVT_MENU, &EditorPanel::OnPluginCopyMetadata, this, MENU_CopyMetadata); + Bind(wxEVT_MENU, &EditorPanel::OnPluginClearMetadata, this, MENU_ClearPluginMetadata); + Bind(wxEVT_MENU, &EditorPanel::OnClearAllMetadata, this, MENU_ClearAllMetadata); + Bind(wxEVT_LIST_BEGIN_DRAG, &EditorPanel::OnDragStart, this, LIST_Plugins); + Bind(wxEVT_CHECKBOX, &EditorPanel::OnFilterToggle, this, CHECKBOX_Filter); //Set up drag 'n' drop. reqsList->SetDropTarget(new TextDropTarget(reqsList, pluginCheckbox)); @@ -644,12 +193,12 @@ Editor::Editor(wxWindow *parent, const wxString& title, const std::string userli wxBoxSizer * hbox1 = new wxBoxSizer(wxHORIZONTAL); - hbox1->Add(filterCheckbox, 0, wxALIGN_LEFT|wxRIGHT, 10); + hbox1->Add(filterCheckbox, 0, wxALIGN_LEFT | wxRIGHT, 10); hbox1->AddStretchSpacer(1); - hbox1->Add(new wxStaticText(this, wxID_ANY, translate("Priority: ")), 0, wxALIGN_RIGHT|wxLEFT|wxRIGHT, 5); + hbox1->Add(new wxStaticText(this, wxID_ANY, translate("Priority: ")), 0, wxALIGN_RIGHT | wxLEFT | wxRIGHT, 5); hbox1->Add(prioritySpin, 0, wxALIGN_RIGHT); - mainBox->Add(hbox1, 0, wxEXPAND|wxALIGN_RIGHT|wxTOP|wxBOTTOM, 5); + mainBox->Add(hbox1, 0, wxEXPAND | wxALIGN_RIGHT | wxTOP | wxBOTTOM, 5); mainBox->Add(priorityCheckbox, 0, wxALIGN_RIGHT | wxBOTTOM, 10); wxBoxSizer * tabBox1 = new wxBoxSizer(wxVERTICAL); @@ -676,26 +225,19 @@ Editor::Editor(wxWindow *parent, const wxString& title, const std::string userli tabBox6->Add(dirtyList, 1, wxEXPAND); dirtyTab->SetSizer(tabBox6); - mainBox->Add(listBook, 1, wxEXPAND|wxTOP|wxBOTTOM, 10); + mainBox->Add(listBook, 1, wxEXPAND | wxTOP | wxBOTTOM, 10); wxBoxSizer * hbox2 = new wxBoxSizer(wxHORIZONTAL); hbox2->Add(addBtn, 0, wxRIGHT, 5); - hbox2->Add(editBtn, 0, wxLEFT|wxRIGHT, 5); + hbox2->Add(editBtn, 0, wxLEFT | wxRIGHT, 5); hbox2->Add(removeBtn, 0, wxLEFT, 5); mainBox->Add(hbox2, 0, wxALIGN_RIGHT); - mainBox->AddSpacer(30); - - wxBoxSizer * hbox6 = new wxBoxSizer(wxHORIZONTAL); - hbox6->Add(applyBtn, 0, wxRIGHT, 5); - hbox6->Add(cancelBtn, 0, wxLEFT, 5); - mainBox->Add(hbox6, 0, wxALIGN_RIGHT); - - bigBox->Add(mainBox, 1, wxEXPAND|wxTOP|wxBOTTOM|wxRIGHT, 10); + bigBox->Add(mainBox, 1, wxEXPAND | wxTOP | wxBOTTOM | wxRIGHT, 10); //Fill pluginList with the contents of basePlugins. int i = 0; - for (const auto &plugin: _basePlugins) { + for (const auto &plugin : _basePlugins) { AddPluginToList(plugin, i); ++i; } @@ -704,14 +246,13 @@ Editor::Editor(wxWindow *parent, const wxString& title, const std::string userli pluginList->SetColumnWidth(2, wxLIST_AUTOSIZE_USEHEADER); pluginList->SetColumnWidth(3, wxLIST_AUTOSIZE_USEHEADER); - SetBackgroundColour(wxColour(255,255,255)); - SetIcon(wxIconLocation("LOOT.exe")); + SetBackgroundColour(wxColour(255, 255, 255)); SetSizerAndFit(bigBox); Layout(); } -void Editor::OnPluginSelect(wxListEvent& event) { +void EditorPanel::OnPluginSelect(wxListEvent& event) { //Create Plugin object for selected plugin. wxString selectedPlugin = pluginList->GetItemText(event.GetIndex(), 1); wxString currentPlugin = pluginCheckbox->GetLabelText(); @@ -722,21 +263,22 @@ void Editor::OnPluginSelect(wxListEvent& event) { //Apply any current edits. if (!currentPlugin.empty()) { - ApplyEdits(currentPlugin, pluginList); + ApplyEdits(currentPlugin); //Also update plugin list UI. + long position = FindPlugin(currentPlugin); loot::Plugin userEdits = GetUserData(currentPlugin); if (!userEdits.HasNameOnly()) { if (userEdits.Enabled()) - pluginList->SetItem(pluginList->FindItem(-1, currentPlugin), 0, FromUTF8("\xE2\x9C\x93")); + pluginList->SetItem(position, 0, FromUTF8("\xE2\x9C\x93")); else - pluginList->SetItem(pluginList->FindItem(-1, currentPlugin), 0, FromUTF8("\xE2\x9C\x97")); + pluginList->SetItem(position, 0, FromUTF8("\xE2\x9C\x97")); } //Also update the item's priority value in the plugins list in case it has changed. - pluginList->SetItem(pluginList->FindItem(-1, currentPlugin), 2, FromUTF8(to_string(prioritySpin->GetValue()))); + pluginList->SetItem(position, 2, FromUTF8(to_string(prioritySpin->GetValue()))); if (priorityCheckbox->IsChecked()) - pluginList->SetItem(pluginList->FindItem(-1, currentPlugin), 3, FromUTF8("\xE2\x9C\x93")); + pluginList->SetItem(position, 3, FromUTF8("\xE2\x9C\x93")); else - pluginList->SetItem(pluginList->FindItem(-1, currentPlugin), 3, FromUTF8("\xE2\x9C\x97")); + pluginList->SetItem(position, 3, FromUTF8("\xE2\x9C\x97")); } //Merge metadata. @@ -764,8 +306,8 @@ void Editor::OnPluginSelect(wxListEvent& event) { dirtyList->DeleteAllItems(); set files = plugin.LoadAfter(); - int i=0; - for (const auto &file: files) { + int i = 0; + for (const auto &file : files) { loadAfterList->InsertItem(i, FromUTF8(file.Name())); loadAfterList->SetItem(i, 1, FromUTF8(file.DisplayName())); loadAfterList->SetItem(i, 2, FromUTF8(file.Condition())); @@ -774,10 +316,10 @@ void Editor::OnPluginSelect(wxListEvent& event) { if (loadAfterList->GetItemCount() == 0) loadAfterList->SetColumnWidth(0, wxLIST_AUTOSIZE_USEHEADER); else - loadAfterList->SetColumnWidth(0, wxLIST_AUTOSIZE); + loadAfterList->SetColumnWidth(0, wxLIST_AUTOSIZE); files = plugin.Reqs(); - i=0; + i = 0; for (const auto &file : files) { reqsList->InsertItem(i, FromUTF8(file.Name())); reqsList->SetItem(i, 1, FromUTF8(file.DisplayName())); @@ -790,7 +332,7 @@ void Editor::OnPluginSelect(wxListEvent& event) { reqsList->SetColumnWidth(0, wxLIST_AUTOSIZE); files = plugin.Incs(); - i=0; + i = 0; for (const auto &file : files) { incsList->InsertItem(i, FromUTF8(file.Name())); incsList->SetItem(i, 1, FromUTF8(file.DisplayName())); @@ -807,8 +349,8 @@ void Editor::OnPluginSelect(wxListEvent& event) { messageList->SetItems(vec); set tags = plugin.Tags(); - i=0; - for (const auto &tag: tags) { + i = 0; + for (const auto &tag : tags) { if (tag.IsAddition()) tagsList->InsertItem(i, State[0]); else @@ -823,8 +365,8 @@ void Editor::OnPluginSelect(wxListEvent& event) { tagsList->SetColumnWidth(0, wxLIST_AUTOSIZE); set dirtyInfo = plugin.DirtyInfo(); - i=0; - for (const auto &element: dirtyInfo) { + i = 0; + for (const auto &element : dirtyInfo) { dirtyList->InsertItem(i, FromUTF8(loot::IntToHexString(element.CRC()))); dirtyList->SetItem(i, 1, FromUTF8(to_string(element.ITMs()))); dirtyList->SetItem(i, 2, FromUTF8(to_string(element.UDRs()))); @@ -852,18 +394,18 @@ void Editor::OnPluginSelect(wxListEvent& event) { } } -void Editor::OnPluginListRightClick(wxListEvent& event) { +void EditorPanel::OnPluginListRightClick(wxListEvent& event) { PopupMenu(pluginMenu); } -void Editor::OnPluginCopyName(wxCommandEvent& event) { +void EditorPanel::OnPluginCopyName(wxCommandEvent& event) { if (wxTheClipboard->Open()) { wxTheClipboard->SetData(new wxTextDataObject(pluginList->GetItemText(pluginList->GetFirstSelected(), 1))); wxTheClipboard->Close(); } } -void Editor::OnPluginCopyMetadata(wxCommandEvent& event) { +void EditorPanel::OnPluginCopyMetadata(wxCommandEvent& event) { wxString selectedPlugin = pluginList->GetItemText(pluginList->GetFirstSelected(), 1); loot::Plugin plugin = GetUserData(selectedPlugin); @@ -878,18 +420,18 @@ void Editor::OnPluginCopyMetadata(wxCommandEvent& event) { } BOOST_LOG_TRIVIAL(info) << "Exported userlist metadata text for \"" << selectedPlugin.ToUTF8() << "\": " << text; - + if (!text.empty() && wxTheClipboard->Open()) { wxTheClipboard->SetData(new wxTextDataObject(FromUTF8(text))); wxTheClipboard->Close(); } } -void Editor::OnPluginClearMetadata(wxCommandEvent& event) { - wxMessageDialog dialog(this, - translate("Are you sure you want to clear all existing user-added metadata from this plugin?"), - translate("LOOT: Warning"), - wxYES_NO | wxCANCEL | wxICON_EXCLAMATION); +void EditorPanel::OnPluginClearMetadata(wxCommandEvent& event) { + wxMessageDialog dialog(this, + translate("Are you sure you want to clear all existing user-added metadata from this plugin?"), + translate("LOOT: Warning"), + wxYES_NO | wxCANCEL | wxICON_EXCLAMATION); if (dialog.ShowModal() == wxID_YES) { long i = pluginList->GetFirstSelected(); @@ -912,7 +454,7 @@ void Editor::OnPluginClearMetadata(wxCommandEvent& event) { } } -void Editor::OnClearAllMetadata(wxCommandEvent& event) { +void EditorPanel::OnClearAllMetadata(wxCommandEvent& event) { wxMessageDialog dialog(this, translate("Are you sure you want to clear all existing user-added metadata from all plugins?"), translate("LOOT: Warning"), @@ -933,25 +475,29 @@ void Editor::OnClearAllMetadata(wxCommandEvent& event) { } } -void Editor::OnListBookChange(wxBookCtrlEvent& event) { +void EditorPanel::OnListBookChange(wxBookCtrlEvent& event) { BOOST_LOG_TRIVIAL(trace) << "Changed list tab."; if (listBook->GetPageCount() == 1 || event.GetSelection() == 2) { //First check is for simple view mode. addBtn->SetLabel(translate("Add Plugin")); editBtn->SetLabel(translate("Edit Plugin")); removeBtn->SetLabel(translate("Remove Plugin")); - } else if (event.GetSelection() == 0 || event.GetSelection() == 1) { + } + else if (event.GetSelection() == 0 || event.GetSelection() == 1) { addBtn->SetLabel(translate("Add File")); editBtn->SetLabel(translate("Edit File")); removeBtn->SetLabel(translate("Remove File")); - } else if (event.GetSelection() == 3) { + } + else if (event.GetSelection() == 3) { addBtn->SetLabel(translate("Add Message")); editBtn->SetLabel(translate("Edit Message")); removeBtn->SetLabel(translate("Remove Message")); - } else if (event.GetSelection() == 4) { + } + else if (event.GetSelection() == 4) { addBtn->SetLabel(translate("Add Bash Tag")); editBtn->SetLabel(translate("Edit Bash Tag")); removeBtn->SetLabel(translate("Remove Bash Tag")); - } else if (event.GetSelection() == 5) { + } + else if (event.GetSelection() == 5) { addBtn->SetLabel(translate("Add Dirty Info")); editBtn->SetLabel(translate("Edit Dirty Info")); removeBtn->SetLabel(translate("Remove Dirty Info")); @@ -968,7 +514,7 @@ void Editor::OnListBookChange(wxBookCtrlEvent& event) { Layout(); } -void Editor::OnAddRow(wxCommandEvent& event) { +void EditorPanel::OnAddRow(wxCommandEvent& event) { if (listBook->GetSelection() < 3) { BOOST_LOG_TRIVIAL(debug) << "Adding new file row."; @@ -991,7 +537,8 @@ void Editor::OnAddRow(wxCommandEvent& event) { list->InsertItem(i, rowDialog->GetName()); list->SetItem(i, 1, rowDialog->GetDisplayName()); list->SetItem(i, 2, rowDialog->GetCondition()); - } else if (listBook->GetSelection() == 3) { + } + else if (listBook->GetSelection() == 3) { BOOST_LOG_TRIVIAL(debug) << "Adding new message row."; MessageEditDialog * rowDialog = new MessageEditDialog(this, translate("LOOT: Add Message")); @@ -1012,7 +559,8 @@ void Editor::OnAddRow(wxCommandEvent& event) { } messageList->AppendItem(rowDialog->GetMessage()); - } else if (listBook->GetSelection() == 4) { + } + else if (listBook->GetSelection() == 4) { BOOST_LOG_TRIVIAL(debug) << "Adding new tag row."; TagEditDialog * rowDialog = new TagEditDialog(this, translate("LOOT: Add Tag")); @@ -1026,7 +574,8 @@ void Editor::OnAddRow(wxCommandEvent& event) { tagsList->InsertItem(i, rowDialog->GetState()); tagsList->SetItem(i, 1, rowDialog->GetName()); tagsList->SetItem(i, 2, rowDialog->GetCondition()); - } else if (listBook->GetSelection() == 5) { + } + else if (listBook->GetSelection() == 5) { BOOST_LOG_TRIVIAL(debug) << "Adding new dirty info row."; DirtInfoEditDialog * rowDialog = new DirtInfoEditDialog(this, translate("LOOT: Add Dirty Info")); @@ -1045,7 +594,7 @@ void Editor::OnAddRow(wxCommandEvent& event) { } } -void Editor::OnEditRow(wxCommandEvent& event) { +void EditorPanel::OnEditRow(wxCommandEvent& event) { if (listBook->GetSelection() < 3) { BOOST_LOG_TRIVIAL(debug) << "Editing file row."; FileEditDialog * rowDialog = new FileEditDialog(this, translate("LOOT: Edit File/Plugin")); @@ -1070,7 +619,8 @@ void Editor::OnEditRow(wxCommandEvent& event) { list->SetItem(i, 0, rowDialog->GetName()); list->SetItem(i, 1, rowDialog->GetDisplayName()); list->SetItem(i, 2, rowDialog->GetCondition()); - } else if (listBook->GetSelection() == 3) { + } + else if (listBook->GetSelection() == 3) { BOOST_LOG_TRIVIAL(debug) << "Editing message row."; MessageEditDialog * rowDialog = new MessageEditDialog(this, translate("LOOT: Edit Message")); @@ -1094,7 +644,8 @@ void Editor::OnEditRow(wxCommandEvent& event) { } messageList->SetItem(i, rowDialog->GetMessage()); - } else if (listBook->GetSelection() == 4) { + } + else if (listBook->GetSelection() == 4) { BOOST_LOG_TRIVIAL(debug) << "Editing tag row."; TagEditDialog * rowDialog = new TagEditDialog(this, translate("LOOT: Edit Tag")); @@ -1116,17 +667,18 @@ void Editor::OnEditRow(wxCommandEvent& event) { tagsList->SetItem(i, 0, rowDialog->GetState()); tagsList->SetItem(i, 1, rowDialog->GetName()); tagsList->SetItem(i, 2, rowDialog->GetCondition()); - } else if (listBook->GetSelection() == 5) { + } + else if (listBook->GetSelection() == 5) { BOOST_LOG_TRIVIAL(debug) << "Editing dirty info row."; DirtInfoEditDialog * rowDialog = new DirtInfoEditDialog(this, translate("LOOT: Edit Dirty Info")); long i = tagsList->GetFirstSelected(); rowDialog->SetValues(tagsList->GetItemText(i, 0), - atoi(string(tagsList->GetItemText(i, 1)).c_str()), - atoi(string(tagsList->GetItemText(i, 2)).c_str()), - atoi(string(tagsList->GetItemText(i, 3)).c_str()), - tagsList->GetItemText(i, 4)); + atoi(string(tagsList->GetItemText(i, 1)).c_str()), + atoi(string(tagsList->GetItemText(i, 2)).c_str()), + atoi(string(tagsList->GetItemText(i, 3)).c_str()), + tagsList->GetItemText(i, 4)); if (rowDialog->ShowModal() != wxID_OK) { BOOST_LOG_TRIVIAL(debug) << "Cancelled editing tag row."; @@ -1141,7 +693,7 @@ void Editor::OnEditRow(wxCommandEvent& event) { } } -void Editor::OnRemoveRow(wxCommandEvent& event) { +void EditorPanel::OnRemoveRow(wxCommandEvent& event) { BOOST_LOG_TRIVIAL(debug) << "Removing row."; wxListView * list; if (listBook->GetPageCount() == 1 || listBook->GetSelection() == 2) @@ -1163,7 +715,7 @@ void Editor::OnRemoveRow(wxCommandEvent& event) { removeBtn->Enable(false); } -void Editor::OnRowSelect(wxListEvent& event) { +void EditorPanel::OnRowSelect(wxListEvent& event) { if (event.GetId() == LIST_Reqs) { //Create File object, search the masterlist vector for the plugin and search its reqs for this object. @@ -1183,13 +735,15 @@ void Editor::OnRowSelect(wxListEvent& event) { BOOST_LOG_TRIVIAL(trace) << "File \"" << file.Name() << "\" was not found in base plugin metadata. Editing enabled."; editBtn->Enable(true); removeBtn->Enable(true); - } else { + } + else { BOOST_LOG_TRIVIAL(trace) << "File \"" << file.Name() << "\" was found in base plugin metadata. Editing disabled."; editBtn->Enable(false); removeBtn->Enable(false); } - } else if (event.GetId() == LIST_Incs) { + } + else if (event.GetId() == LIST_Incs) { loot::File file = RowToFile(incsList, event.GetIndex()); loot::Plugin plugin(string(pluginCheckbox->GetLabelText().ToUTF8())); @@ -1207,13 +761,15 @@ void Editor::OnRowSelect(wxListEvent& event) { BOOST_LOG_TRIVIAL(trace) << "File \"" << file.Name() << "\" was not found in base plugin metadata. Editing enabled."; editBtn->Enable(true); removeBtn->Enable(true); - } else { + } + else { BOOST_LOG_TRIVIAL(trace) << "File \"" << file.Name() << "\" was found in base plugin metadata. Editing disabled."; editBtn->Enable(false); removeBtn->Enable(false); } - } else if (event.GetId() == LIST_LoadAfter) { + } + else if (event.GetId() == LIST_LoadAfter) { loot::File file = RowToFile(loadAfterList, event.GetIndex()); loot::Plugin plugin(string(pluginCheckbox->GetLabelText().ToUTF8())); @@ -1231,13 +787,15 @@ void Editor::OnRowSelect(wxListEvent& event) { BOOST_LOG_TRIVIAL(trace) << "File \"" << file.Name() << "\" was not found in base plugin metadata. Editing enabled."; editBtn->Enable(true); removeBtn->Enable(true); - } else { + } + else { BOOST_LOG_TRIVIAL(trace) << "File \"" << file.Name() << "\" was found in base plugin metadata. Editing disabled."; editBtn->Enable(false); removeBtn->Enable(false); } - } else if (event.GetId() == LIST_Messages) { + } + else if (event.GetId() == LIST_Messages) { loot::Message message = messageList->GetItem(event.GetIndex()); loot::Plugin plugin(string(pluginCheckbox->GetLabelText().ToUTF8())); @@ -1255,13 +813,15 @@ void Editor::OnRowSelect(wxListEvent& event) { BOOST_LOG_TRIVIAL(trace) << "Message \"" << message.ChooseContent(loot::Language::any).Str() << "\" was not found in base plugin metadata. Editing enabled."; editBtn->Enable(true); removeBtn->Enable(true); - } else { + } + else { BOOST_LOG_TRIVIAL(trace) << "Message \"" << message.ChooseContent(loot::Language::any).Str() << "\" was found in base plugin metadata. Editing disabled."; editBtn->Enable(false); removeBtn->Enable(false); } - } else if (event.GetId() == LIST_BashTags) { + } + else if (event.GetId() == LIST_BashTags) { loot::Tag tag = RowToTag(tagsList, event.GetIndex()); loot::Plugin plugin(string(pluginCheckbox->GetLabelText().ToUTF8())); @@ -1279,13 +839,15 @@ void Editor::OnRowSelect(wxListEvent& event) { BOOST_LOG_TRIVIAL(trace) << "Bash Tag \"" << tag.Name() << "\" was not found in base plugin metadata. Editing enabled."; editBtn->Enable(true); removeBtn->Enable(true); - } else { + } + else { BOOST_LOG_TRIVIAL(trace) << "Bash Tag \"" << tag.Name() << "\" was found in base plugin metadata. Editing disabled."; editBtn->Enable(false); removeBtn->Enable(false); } - } else { + } + else { loot::PluginDirtyInfo dirtyData = RowToPluginDirtyInfo(dirtyList, event.GetIndex()); loot::Plugin plugin(string(pluginCheckbox->GetLabelText().ToUTF8())); @@ -1302,7 +864,8 @@ void Editor::OnRowSelect(wxListEvent& event) { BOOST_LOG_TRIVIAL(trace) << "Dirty info for CRC \"" << dirtyData.CRC() << "\" was not found in base plugin metadata. Editing enabled."; editBtn->Enable(true); removeBtn->Enable(true); - } else { + } + else { BOOST_LOG_TRIVIAL(trace) << "Dirty info for CRC \"" << dirtyData.CRC() << "\" was found in base plugin metadata. Editing disabled."; editBtn->Enable(false); removeBtn->Enable(false); @@ -1310,33 +873,7 @@ void Editor::OnRowSelect(wxListEvent& event) { } } -void Editor::OnQuit(wxCommandEvent& event) { - BOOST_LOG_TRIVIAL(debug) << "Exiting metadata editor."; - if (event.GetId() == BUTTON_Apply) { - - //Apply any current edits. - wxString currentPlugin = pluginCheckbox->GetLabelText(); - if (!currentPlugin.empty()) - ApplyEdits(currentPlugin, pluginList); - - BOOST_LOG_TRIVIAL(debug) << "Saving metadata edits to userlist."; - - //Save edits to userlist. - YAML::Emitter yout; - yout.SetIndent(2); - yout << YAML::BeginMap - << YAML::Key << "plugins" << YAML::Value << _editedPlugins - << YAML::EndMap; - - boost::filesystem::path p(_userlistPath); - loot::ofstream out(p); - out << yout.c_str(); - out.close(); - } - Close(); -} - -loot::Plugin Editor::GetNewData(const wxString& plugin) const { +loot::Plugin EditorPanel::GetNewData(const wxString& plugin) const { BOOST_LOG_TRIVIAL(debug) << "Getting metadata from editor fields for plugin: " << plugin.ToUTF8(); loot::Plugin p(string(plugin.ToUTF8())); @@ -1352,31 +889,31 @@ loot::Plugin Editor::GetNewData(const wxString& plugin) const { p.Priority(priority); set files; - for (int i=0,max=reqsList->GetItemCount(); i < max; ++i) { + for (int i = 0, max = reqsList->GetItemCount(); i < max; ++i) { files.insert(RowToFile(reqsList, i)); } p.Reqs(files); files.clear(); - for (int i=0,max=incsList->GetItemCount(); i < max; ++i) { + for (int i = 0, max = incsList->GetItemCount(); i < max; ++i) { files.insert(RowToFile(incsList, i)); } p.Incs(files); files.clear(); - for (int i=0,max=loadAfterList->GetItemCount(); i < max; ++i) { + for (int i = 0, max = loadAfterList->GetItemCount(); i < max; ++i) { files.insert(RowToFile(loadAfterList, i)); } p.LoadAfter(files); set tags; - for (int i=0,max=tagsList->GetItemCount(); i < max; ++i) { + for (int i = 0, max = tagsList->GetItemCount(); i < max; ++i) { tags.insert(RowToTag(tagsList, i)); } p.Tags(tags); set dirtyInfo; - for (int i=0,max=dirtyList->GetItemCount(); i < max; ++i) { + for (int i = 0, max = dirtyList->GetItemCount(); i < max; ++i) { dirtyInfo.insert(RowToPluginDirtyInfo(dirtyList, i)); } p.DirtyInfo(dirtyInfo); @@ -1388,20 +925,20 @@ loot::Plugin Editor::GetNewData(const wxString& plugin) const { return p; } -void Editor::OnFilterToggle(wxCommandEvent& event) { +void EditorPanel::OnFilterToggle(wxCommandEvent& event) { //First need to merge the base and edited plugin lists so that the right priority values get displayed. list plugins(_basePlugins); - for (const auto &plugin: _editedPlugins) { + for (const auto &plugin : _editedPlugins) { list::iterator pos = std::find(plugins.begin(), plugins.end(), plugin); pos->MergeMetadata(plugin); } //Disable list selection. if (event.IsChecked()) - Unbind(wxEVT_LIST_ITEM_SELECTED, &Editor::OnPluginSelect, this, LIST_Plugins); + Unbind(wxEVT_LIST_ITEM_SELECTED, &EditorPanel::OnPluginSelect, this, LIST_Plugins); else - Bind(wxEVT_LIST_ITEM_SELECTED, &Editor::OnPluginSelect, this, LIST_Plugins); + Bind(wxEVT_LIST_ITEM_SELECTED, &EditorPanel::OnPluginSelect, this, LIST_Plugins); pluginList->Freeze(); if (event.IsChecked()) { @@ -1414,7 +951,7 @@ void Editor::OnFilterToggle(wxCommandEvent& event) { bool loadsBSA = pos->LoadsBSA(_game); int i = 0; - for (const auto &plugin: plugins) { + for (const auto &plugin : plugins) { //Want to filter to show only those the selected plugin can load after validly, and which also either conflict with it, //or which load a BSA (if the selected plugin loads a BSA). if (plugin == *pos || !plugin.MustLoadAfter(*pos) && (pos->DoFormIDsOverlap(plugin) || (loadsBSA && plugin.LoadsBSA(_game)))) { @@ -1427,27 +964,27 @@ void Editor::OnFilterToggle(wxCommandEvent& event) { else { pluginList->DeleteAllItems(); int i = 0; - for (const auto &plugin: plugins) { + for (const auto &plugin : plugins) { AddPluginToList(plugin, i); ++i; } } //Now re-select the current plugin in the list. - pluginList->Select(pluginList->FindItem(-1, pluginCheckbox->GetLabelText())); + pluginList->Select(FindPlugin(pluginCheckbox->GetLabelText())); pluginList->Thaw(); Refresh(); } -void Editor::OnDragStart(wxListEvent& event) { +void EditorPanel::OnDragStart(wxListEvent& event) { wxTextDataObject data(pluginList->GetItemText(event.GetItem(), 1)); wxDropSource dropSource(pluginList); dropSource.SetData(data); wxDragResult result = dropSource.DoDragDrop(); } -void Editor::AddPluginToList(const loot::Plugin& plugin, int position) { - loot::Plugin userEdits = GetUserData(plugin.Name()); +void EditorPanel::AddPluginToList(const loot::Plugin& plugin, int position) { + loot::Plugin userEdits = GetUserData(FromUTF8(plugin.Name())); if (!userEdits.HasNameOnly()) { if (userEdits.Enabled()) pluginList->InsertItem(position, FromUTF8("\xE2\x9C\x93")); @@ -1468,7 +1005,7 @@ void Editor::AddPluginToList(const loot::Plugin& plugin, int position) { } } -void Editor::SetSimpleView(bool on) { +void EditorPanel::SetSimpleView(bool on) { if (on) { listBook->RemovePage(5); listBook->RemovePage(4); @@ -1491,4 +1028,222 @@ void Editor::SetSimpleView(bool on) { loadAfterList->SetColumnWidth(1, wxLIST_AUTOSIZE); loadAfterList->SetColumnWidth(2, wxLIST_AUTOSIZE); } -} \ No newline at end of file +} + +void EditorPanel::ApplyCurrentEdits() { + //Apply any current edits. + wxString currentPlugin = pluginCheckbox->GetLabelText(); + if (!currentPlugin.empty()) + ApplyEdits(currentPlugin); +} + +const std::list& EditorPanel::GetEditedPlugins() const { + return _editedPlugins; +} + +loot::Plugin EditorPanel::GetMasterData(const wxString& plugin) const { + BOOST_LOG_TRIVIAL(debug) << "Getting hardcoded and masterlist metadata for plugin: " << plugin.ToUTF8(); + loot::Plugin p; + loot::Plugin p_in(string(plugin.ToUTF8())); + + list::const_iterator it = std::find(_basePlugins.begin(), _basePlugins.end(), p_in); + + if (it != _basePlugins.end()) + p = *it; + + return p; +} + +loot::Plugin EditorPanel::GetUserData(const wxString& plugin) const { + BOOST_LOG_TRIVIAL(debug) << "Getting userlist metadata for plugin: " << plugin.ToUTF8(); + loot::Plugin p(string(plugin.ToUTF8())); + + list::const_iterator it = std::find(_editedPlugins.begin(), _editedPlugins.end(), p); + + if (it != _editedPlugins.end()) + p = *it; + + return p; +} + +void EditorPanel::ApplyEdits(const wxString& plugin) { + BOOST_LOG_TRIVIAL(debug) << "Applying edits to plugin: " << plugin.ToUTF8(); + + //Get recorded data. + loot::Plugin master(GetMasterData(plugin)); + loot::Plugin edited(GetNewData(plugin)); + + loot::Plugin diff = master.DiffMetadata(edited); + + list::iterator pos = std::find(_editedPlugins.begin(), _editedPlugins.end(), diff); + long i = FindPlugin(plugin); + + if (!diff.HasNameOnly()) { + if (pos != _editedPlugins.end()) { + if (!pos->DiffMetadata(edited).HasNameOnly()) + pluginList->SetItemFont(i, wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold()); + *pos = diff; + } + else { + _editedPlugins.push_back(diff); + pluginList->SetItemFont(i, wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold()); + } + } + else { + pluginList->SetItemFont(i, wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + if (pos != _editedPlugins.end()) + _editedPlugins.erase(pos); //Prevents unnecessary writes. + } +} + +long EditorPanel::FindPlugin(const wxString& plugin) { + for (int i = 0, max = pluginList->GetItemCount(); i < max; ++i) { + if (pluginList->GetItemText(i, 1) == plugin) + return i; + } + return -1; +} + +loot::File EditorPanel::RowToFile(wxListView * list, long row) const { + return loot::File( + string(list->GetItemText(row, 0).ToUTF8()), + string(list->GetItemText(row, 1).ToUTF8()), + string(list->GetItemText(row, 2).ToUTF8()) + ); +} + +loot::Tag EditorPanel::RowToTag(wxListView * list, long row) const { + string name = string(list->GetItemText(row, 1).ToUTF8()); + + if (list->GetItemText(row, 0) == State[1]) + return loot::Tag( + name, + false, + string(list->GetItemText(row, 2).ToUTF8()) + ); + else + return loot::Tag( + name, + true, + string(list->GetItemText(row, 2).ToUTF8()) + ); +} + +loot::PluginDirtyInfo EditorPanel::RowToPluginDirtyInfo(wxListView * list, long row) const { + string text(list->GetItemText(row, 0).ToUTF8()); + uint32_t crc = strtoul(text.c_str(), nullptr, 16); + return loot::PluginDirtyInfo( + crc, + atoi(string(list->GetItemText(row, 1).ToUTF8()).c_str()), + atoi(string(list->GetItemText(row, 2).ToUTF8()).c_str()), + atoi(string(list->GetItemText(row, 3).ToUTF8()).c_str()), + string(list->GetItemText(row, 4).ToUTF8())); +} + + +/////////////////////////////////// +// Mini Editor Class +/////////////////////////////////// + +MiniEditor::MiniEditor(wxWindow *parent, const wxString& title, const std::list& basePlugins, std::list& editedPlugins, const loot::Game& game) : wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) { + + //Initialise content. + editorPanel = new EditorPanel(this, basePlugins, editedPlugins, loot::Language::any, game); + editorPanel->SetSimpleView(true); + feedbackText = translate("If LOOT has gotten something wrong, please let the team know. See the Contributing To LOOT section of the readme for details."); + + //Set up event handling. + Bind(wxEVT_BUTTON, &MiniEditor::OnApply, this, wxID_APPLY); + Bind(wxEVT_SIZE, &MiniEditor::OnResize, this); + + //Set up layout. + wxBoxSizer * bigBox = new wxBoxSizer(wxVERTICAL); + + bigBox->Add(editorPanel, 1, wxEXPAND | wxALL, 10); + bigBox->Add(descText, 0, wxEXPAND|wxLEFT|wxRIGHT|wxBOTTOM, 15); + + //Need to add 'Yes' and 'No' buttons. + wxSizer * sizer = CreateSeparatedButtonSizer(wxAPPLY | wxCANCEL); + + //Now add buttons to window sizer. + if (sizer != nullptr) + bigBox->Add(sizer, 0, wxEXPAND | wxLEFT | wxBOTTOM | wxRIGHT, 15); + + descText->Wrap(editorPanel->GetClientSize().GetWidth()); + + SetBackgroundColour(wxColour(255, 255, 255)); + SetIcon(wxIconLocation("LOOT.exe")); + + SetSizerAndFit(bigBox); +} + +void MiniEditor::OnApply(wxCommandEvent& event) { + editorPanel->ApplyCurrentEdits(); + EndModal(event.GetId()); +} + +void MiniEditor::OnResize(wxSizeEvent& event) { + descText->SetLabel(feedbackText); + descText->Wrap(GetClientSize().GetWidth()-30); + event.Skip(); +} + +const std::list& MiniEditor::GetEditedPlugins() const { + return editorPanel->GetEditedPlugins(); +} + + +/////////////////////////////////// +// Full Editor Class +/////////////////////////////////// + +FullEditor::FullEditor(wxWindow *parent, const wxString& title, const std::string userlistPath, const std::list& basePlugins, std::list& editedPlugins, const unsigned int language, const loot::Game& game) : wxFrame(parent, wxID_ANY, title), _userlistPath(userlistPath) { + //Set up content. + editorPanel = new EditorPanel(this, basePlugins, editedPlugins, language, game); + applyBtn = new wxButton(this, BUTTON_Apply, translate("Save Changes")); + cancelBtn = new wxButton(this, BUTTON_Cancel, translate("Cancel")); + + //Set up event handling. + Bind(wxEVT_BUTTON, &FullEditor::OnQuit, this, BUTTON_Apply); + Bind(wxEVT_BUTTON, &FullEditor::OnQuit, this, BUTTON_Cancel); + + //Set up layout. + wxBoxSizer * bigBox = new wxBoxSizer(wxVERTICAL); + + bigBox->Add(editorPanel, 1, wxEXPAND | wxALL, 10); + + wxBoxSizer * hbox6 = new wxBoxSizer(wxHORIZONTAL); + hbox6->Add(applyBtn, 0, wxRIGHT, 10); + hbox6->Add(cancelBtn); + bigBox->Add(hbox6, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxALIGN_RIGHT, 10); + + SetBackgroundColour(wxColour(255, 255, 255)); + SetIcon(wxIconLocation("LOOT.exe")); + + SetSizerAndFit(bigBox); + Layout(); +} + +void FullEditor::OnQuit(wxCommandEvent& event) { + BOOST_LOG_TRIVIAL(debug) << "Exiting metadata editor."; + if (event.GetId() == BUTTON_Apply) { + + //Apply any current edits. + editorPanel->ApplyCurrentEdits(); + + BOOST_LOG_TRIVIAL(debug) << "Saving metadata edits to userlist."; + + //Save edits to userlist. + YAML::Emitter yout; + yout.SetIndent(2); + yout << YAML::BeginMap + << YAML::Key << "plugins" << YAML::Value << editorPanel->GetEditedPlugins() + << YAML::EndMap; + + boost::filesystem::path p(_userlistPath); + loot::ofstream out(p); + out << yout.c_str(); + out.close(); + } + Close(); +} diff --git a/src/gui/editor.h b/src/gui/editor.h index 81ae0725..d49eb9a6 100644 --- a/src/gui/editor.h +++ b/src/gui/editor.h @@ -61,60 +61,14 @@ private: wxControl * targetName; }; -class CommonEditor { +class EditorPanel : public wxPanel { public: - CommonEditor(const std::list& plugins, const loot::Game& game); - CommonEditor(const std::list& plugins, const loot::Game& game, std::list& editedPlugins); -protected: - const loot::Game& _game; - const std::list _basePlugins; - std::list _editedPlugins; - - loot::Plugin GetMasterData(const wxString& plugin) const; - loot::Plugin GetUserData(const wxString& plugin) const; - virtual loot::Plugin GetNewData(const wxString& plugin) const = 0; - - void ApplyEdits(const wxString& plugin, wxListView * list); - - loot::File RowToFile(wxListView * list, long row) const; - loot::Tag RowToTag(wxListView * list, long row) const; - loot::PluginDirtyInfo RowToPluginDirtyInfo(wxListView * list, long row) const; -}; - -class MiniEditor : public wxDialog, public CommonEditor { -public: - MiniEditor(wxWindow *parent, const wxString& title, const std::list& plugins, const loot::Game& game); - - void OnPluginSelect(wxListEvent& event); - void OnRowSelect(wxListEvent& event); - void OnRemoveRow(wxCommandEvent& event); - void OnFilterToggle(wxCommandEvent& event); - void OnDragStart(wxListEvent& event); - void OnApply(wxCommandEvent& event); - void OnResize(wxSizeEvent& event); - - const std::list& GetEditedPlugins() const; -private: - wxListView * pluginList; - wxPanel * editingPanel; - wxButton * removeBtn; - wxListView * loadAfterList; - wxCheckBox * filterCheckbox; - wxSpinCtrl * prioritySpin; - wxCheckBox * priorityCheckbox; - wxStaticText * pluginText; - wxStaticText * descText; - - wxString feedbackText; - - loot::Plugin GetNewData(const wxString& plugin) const; -}; - -class Editor : public wxFrame, public CommonEditor { -public: - Editor(wxWindow *parent, const wxString& title, const std::string userlistPath, const std::list& basePlugins, std::list& editedPlugins, const unsigned int language, const loot::Game& game); + EditorPanel(wxWindow *parent, const std::list& basePlugins, std::list& editedPlugins, const unsigned int language, const loot::Game& game); void SetSimpleView(bool on = true); + void ApplyCurrentEdits(); + + const std::list& GetEditedPlugins() const; void OnPluginSelect(wxListEvent& event); void OnPluginListRightClick(wxListEvent& event); @@ -129,14 +83,11 @@ public: void OnRowSelect(wxListEvent& event); void OnFilterToggle(wxCommandEvent& event); void OnDragStart(wxListEvent& event); - void OnQuit(wxCommandEvent& event); private: wxMenu * pluginMenu; wxButton * addBtn; wxButton * editBtn; wxButton * removeBtn; - wxButton * applyBtn; - wxButton * cancelBtn; wxListView * pluginList; wxListView * reqsList; wxListView * incsList; @@ -157,9 +108,49 @@ private: wxPanel * tagsTab; wxPanel * dirtyTab; - const std::string _userlistPath; - - loot::Plugin GetNewData(const wxString& plugin) const; void AddPluginToList(const loot::Plugin& plugin, int position); +protected: + const loot::Game& _game; + const std::list _basePlugins; + std::list _editedPlugins; + + loot::Plugin GetMasterData(const wxString& plugin) const; + loot::Plugin GetUserData(const wxString& plugin) const; + loot::Plugin GetNewData(const wxString& plugin) const; + + void ApplyEdits(const wxString& plugin); + long FindPlugin(const wxString& plugin); + + loot::File RowToFile(wxListView * list, long row) const; + loot::Tag RowToTag(wxListView * list, long row) const; + loot::PluginDirtyInfo RowToPluginDirtyInfo(wxListView * list, long row) const; +}; + +class MiniEditor : public wxDialog { +public: + MiniEditor(wxWindow *parent, const wxString& title, const std::list& basePlugins, std::list& editedPlugins, const loot::Game& game); + + void OnApply(wxCommandEvent& event); + void OnResize(wxSizeEvent& event); + + const std::list& GetEditedPlugins() const; +private: + EditorPanel * editorPanel; + wxStaticText * descText; + + wxString feedbackText; +}; + +class FullEditor : public wxFrame { +public: + FullEditor(wxWindow *parent, const wxString& title, const std::string userlistPath, const std::list& basePlugins, std::list& editedPlugins, const unsigned int language, const loot::Game& game); + + void OnQuit(wxCommandEvent& event); +private: + EditorPanel * editorPanel; + wxButton * applyBtn; + wxButton * cancelBtn; + + const std::string _userlistPath; }; #endif diff --git a/src/gui/main.cpp b/src/gui/main.cpp index 0ef30437..4b249fd1 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -882,7 +882,7 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { progDia = nullptr; BOOST_LOG_TRIVIAL(info) << "Displaying load order preview."; - MiniEditor editor(this, translate("LOOT: Calculated Load Order"), plugins, *_game); + MiniEditor editor(this, translate("LOOT: Calculated Load Order"), plugins, ulist_plugins, *_game); long ret = editor.ShowModal(); const std::list edits = editor.GetEditedPlugins(); @@ -1102,7 +1102,7 @@ void Launcher::OnEditMetadata(wxCommandEvent& event) { //Create editor window. BOOST_LOG_TRIVIAL(debug) << "Opening editor window."; - Editor *editor = new Editor(this, translate("LOOT: Metadata Editor"), _game->UserlistPath().string(), installed, ulist_plugins, lang, *_game); + FullEditor *editor = new FullEditor(this, translate("LOOT: Metadata Editor"), _game->UserlistPath().string(), installed, ulist_plugins, lang, *_game); progDia->Destroy();