mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Finished implementing new editors.
* Fixed crash due to uninitialised mini editor content. * Sorting now rearranges rather than replaces the existing plugin list (yay lambda function!). * During the sorting process, plugin data is stored in the plugin list, as the graph is now a temporary object confined to the sorting loop. * Userlist merging, condition eval and validity checks are deferred to within the sorting loop.
This commit is contained in:
+14
-3
@@ -95,12 +95,23 @@ namespace loot {
|
||||
boost::topological_sort(graph, std::front_inserter(sortedVertices), boost::vertex_index_map(v_index_map));
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Calculated order: ";
|
||||
list<loot::Plugin> tempPlugins;
|
||||
list<string> tempPlugins;
|
||||
for (const auto &vertex: sortedVertices) {
|
||||
BOOST_LOG_TRIVIAL(info) << '\t' << graph[vertex].Name();
|
||||
tempPlugins.push_back(graph[vertex]);
|
||||
tempPlugins.push_back(graph[vertex].Name());
|
||||
}
|
||||
plugins.swap(tempPlugins);
|
||||
|
||||
//Now sort exist plugins list according to order in tempPlugins.
|
||||
plugins.sort([tempPlugins](const Plugin& first, const Plugin& second){
|
||||
//Find both plugins, and compare distances from beginning.
|
||||
auto fIt = find(tempPlugins.begin(), tempPlugins.end(), first);
|
||||
auto sIt = find(tempPlugins.begin(), tempPlugins.end(), second);
|
||||
|
||||
if (fIt == tempPlugins.end() || sIt == tempPlugins.end())
|
||||
return false;
|
||||
|
||||
return distance(tempPlugins.begin(), fIt) < distance(tempPlugins.begin(), sIt);
|
||||
});
|
||||
}
|
||||
|
||||
void CheckForCycles(const PluginGraph& graph) {
|
||||
|
||||
+9
-6
@@ -931,7 +931,8 @@ void EditorPanel::OnFilterToggle(wxCommandEvent& event) {
|
||||
list<loot::Plugin> plugins(_basePlugins);
|
||||
for (const auto &plugin : _editedPlugins) {
|
||||
list<loot::Plugin>::iterator pos = std::find(plugins.begin(), plugins.end(), plugin);
|
||||
pos->MergeMetadata(plugin);
|
||||
if (pos != plugins.end())
|
||||
pos->MergeMetadata(plugin);
|
||||
}
|
||||
|
||||
//Disable list selection.
|
||||
@@ -1040,7 +1041,7 @@ void EditorPanel::ApplyCurrentEdits() {
|
||||
ApplyEdits(currentPlugin);
|
||||
}
|
||||
|
||||
const std::list<loot::Plugin>& EditorPanel::GetEditedPlugins() const {
|
||||
const std::list<loot::Plugin>& EditorPanel::GetNewUserlist() const {
|
||||
return _editedPlugins;
|
||||
}
|
||||
|
||||
@@ -1153,7 +1154,9 @@ MiniEditor::MiniEditor(wxWindow *parent, const wxString& title, const std::list<
|
||||
//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.");
|
||||
descText = new wxStaticText(this, wxID_ANY, feedbackText);
|
||||
|
||||
//Set up event handling.
|
||||
Bind(wxEVT_BUTTON, &MiniEditor::OnApply, this, wxID_APPLY);
|
||||
@@ -1167,7 +1170,7 @@ MiniEditor::MiniEditor(wxWindow *parent, const wxString& title, const std::list<
|
||||
|
||||
//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);
|
||||
@@ -1191,8 +1194,8 @@ void MiniEditor::OnResize(wxSizeEvent& event) {
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
const std::list<loot::Plugin>& MiniEditor::GetEditedPlugins() const {
|
||||
return editorPanel->GetEditedPlugins();
|
||||
const std::list<loot::Plugin>& MiniEditor::GetNewUserlist() const {
|
||||
return editorPanel->GetNewUserlist();
|
||||
}
|
||||
|
||||
|
||||
@@ -1240,7 +1243,7 @@ void FullEditor::OnQuit(wxCommandEvent& event) {
|
||||
YAML::Emitter yout;
|
||||
yout.SetIndent(2);
|
||||
yout << YAML::BeginMap
|
||||
<< YAML::Key << "plugins" << YAML::Value << editorPanel->GetEditedPlugins()
|
||||
<< YAML::Key << "plugins" << YAML::Value << editorPanel->GetNewUserlist()
|
||||
<< YAML::EndMap;
|
||||
|
||||
boost::filesystem::path p(_userlistPath);
|
||||
|
||||
+2
-2
@@ -68,7 +68,7 @@ public:
|
||||
void SetSimpleView(bool on = true);
|
||||
void ApplyCurrentEdits();
|
||||
|
||||
const std::list<loot::Plugin>& GetEditedPlugins() const;
|
||||
const std::list<loot::Plugin>& GetNewUserlist() const;
|
||||
|
||||
void OnPluginSelect(wxListEvent& event);
|
||||
void OnPluginListRightClick(wxListEvent& event);
|
||||
@@ -133,7 +133,7 @@ public:
|
||||
void OnApply(wxCommandEvent& event);
|
||||
void OnResize(wxSizeEvent& event);
|
||||
|
||||
const std::list<loot::Plugin>& GetEditedPlugins() const;
|
||||
const std::list<loot::Plugin>& GetNewUserlist() const;
|
||||
private:
|
||||
EditorPanel * editorPanel;
|
||||
wxStaticText * descText;
|
||||
|
||||
+88
-86
@@ -87,18 +87,17 @@ struct plugin_loader {
|
||||
};
|
||||
|
||||
struct plugin_list_loader {
|
||||
plugin_list_loader(PluginGraph& graph, loot::Game& game) : _graph(graph), _game(game) {}
|
||||
plugin_list_loader(list<loot::Plugin>& plugins, loot::Game& game) : _plugins(plugins), _game(game) {}
|
||||
|
||||
void operator () () {
|
||||
loot::vertex_it vit, vitend;
|
||||
for (boost::tie(vit, vitend) = boost::vertices(_graph); vit != vitend; ++vit) {
|
||||
if (skipPlugins.find(_graph[*vit].Name()) == skipPlugins.end()) {
|
||||
_graph[*vit] = loot::Plugin(_game, _graph[*vit].Name(), false);
|
||||
for (auto &plugin : _plugins) {
|
||||
if (skipPlugins.find(plugin.Name()) == skipPlugins.end()) {
|
||||
plugin = loot::Plugin(_game, plugin.Name(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PluginGraph& _graph;
|
||||
list<loot::Plugin>& _plugins;
|
||||
loot::Game& _game;
|
||||
set<string> skipPlugins;
|
||||
};
|
||||
@@ -681,7 +680,6 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
|
||||
list<loot::Plugin> mlist_plugins, ulist_plugins;
|
||||
list<loot::Plugin> plugins;
|
||||
boost::thread_group group;
|
||||
loot::PluginGraph graph;
|
||||
string revision, date;
|
||||
|
||||
wxProgressDialog *progDia = new wxProgressDialog(translate("LOOT: Working..."),translate("LOOT working..."), 1000, this, wxPD_APP_MODAL|wxPD_AUTO_HIDE|wxPD_ELAPSED_TIME);
|
||||
@@ -704,22 +702,21 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
|
||||
meanFileSize += fileSize;
|
||||
|
||||
tempMap.emplace(it->path().filename().string(), fileSize);
|
||||
plugins.push_back(loot::Plugin(it->path().filename().string())); //Just in case there's an error with the graph.
|
||||
}
|
||||
}
|
||||
meanFileSize /= tempMap.size();
|
||||
|
||||
//Now load plugins.
|
||||
plugin_list_loader pll(graph, *_game);
|
||||
plugin_list_loader pll(plugins, *_game);
|
||||
for (const auto &pluginPair: tempMap) {
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Found plugin: " << pluginPair.first;
|
||||
|
||||
vertex_t v = boost::add_vertex(loot::Plugin(pluginPair.first), graph);
|
||||
plugins.push_back(loot::Plugin(pluginPair.first));
|
||||
|
||||
if (pluginPair.second > meanFileSize) {
|
||||
pll.skipPlugins.insert(pluginPair.first);
|
||||
plugin_loader pl(graph[v], *_game);
|
||||
plugin_loader pl(plugins.back(), *_game);
|
||||
group.create_thread(pl);
|
||||
}
|
||||
|
||||
@@ -753,14 +750,14 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
|
||||
// Merge & Check Metadata
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
if (fs::exists(_game->MasterlistPath()) || fs::exists(_game->UserlistPath())) {
|
||||
//Set language.
|
||||
unsigned int lang;
|
||||
if (_settings["Language"])
|
||||
lang = Language(_settings["Language"].as<string>()).Code();
|
||||
else
|
||||
lang = loot::Language::any;
|
||||
|
||||
//Set language.
|
||||
unsigned int lang;
|
||||
if (_settings["Language"])
|
||||
lang = Language(_settings["Language"].as<string>()).Code();
|
||||
else
|
||||
lang = loot::Language::any;
|
||||
if (fs::exists(_game->MasterlistPath()) || fs::exists(_game->UserlistPath())) {
|
||||
|
||||
|
||||
//Merge all global message lists.
|
||||
@@ -786,46 +783,19 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
|
||||
messages.push_back(loot::Message(loot::Message::error, (format(loc::translate("A global message contains a condition that could not be evaluated. Details: %1%")) % e.what()).str()));
|
||||
}
|
||||
|
||||
//Merge plugin list, masterlist and userlist plugin data.
|
||||
BOOST_LOG_TRIVIAL(debug) << "Merging plugin list, masterlist and userlist data, evaluating conditions and checking for install validity.";
|
||||
loot::vertex_it vit, vitend;
|
||||
for (boost::tie(vit, vitend) = boost::vertices(graph); vit != vitend; ++vit) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Merging for plugin \"" << graph[*vit].Name() << "\"";
|
||||
//Merge plugin list and masterlist.
|
||||
BOOST_LOG_TRIVIAL(debug) << "Merging plugin list and masterlist data.";
|
||||
for (auto &plugin : plugins) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Merging for plugin \"" << plugin.Name() << "\"";
|
||||
|
||||
//Check if there is a plugin entry in the masterlist. This will also find matching regex entries.
|
||||
list<loot::Plugin>::iterator pos = std::find(mlist_plugins.begin(), mlist_plugins.end(), graph[*vit]);
|
||||
list<loot::Plugin>::iterator pos = std::find(mlist_plugins.begin(), mlist_plugins.end(), plugin);
|
||||
|
||||
if (pos != mlist_plugins.end()) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Merging masterlist data down to plugin list data.";
|
||||
graph[*vit].MergeMetadata(*pos);
|
||||
plugin.MergeMetadata(*pos);
|
||||
}
|
||||
|
||||
//Check if there is a plugin entry in the userlist. This will also find matching regex entries.
|
||||
pos = std::find(ulist_plugins.begin(), ulist_plugins.end(), graph[*vit]);
|
||||
|
||||
if (pos != ulist_plugins.end() && pos->Enabled()) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Merging userlist data down to plugin list data.";
|
||||
graph[*vit].MergeMetadata(*pos);
|
||||
}
|
||||
|
||||
progDia->Pulse();
|
||||
|
||||
//Now that items are merged, evaluate any conditions they have.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Evaluate conditions for merged plugin data.";
|
||||
try {
|
||||
graph[*vit].EvalAllConditions(*_game, lang);
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "\"" << graph[*vit].Name() << "\" contains a condition that could not be evaluated. Details: " << e.what();
|
||||
messages.push_back(loot::Message(loot::Message::error, (format(loc::translate("\"%1%\" contains a condition that could not be evaluated. Details: %2%")) % graph[*vit].Name() % e.what()).str()));
|
||||
}
|
||||
|
||||
progDia->Pulse();
|
||||
|
||||
//Also check install validity.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Checking that the current install is valid according to this plugin's data.";
|
||||
graph[*vit].CheckInstallValidity(*_game);
|
||||
|
||||
progDia->Pulse();
|
||||
}
|
||||
}
|
||||
@@ -849,19 +819,60 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
|
||||
//Check for back-edges, then perform a topological sort.
|
||||
try {
|
||||
bool applyLoadOrder = false;
|
||||
|
||||
do {
|
||||
//Create a plugin graph containing the plugin and masterlist data.
|
||||
loot::PluginGraph graph;
|
||||
for (auto &plugin : plugins) {
|
||||
vertex_t v = boost::add_vertex(plugin, graph);
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Merging userlist into plugin list/masterlist, evaluating conditions and checking for install validity.";
|
||||
loot::vertex_it vit, vitend;
|
||||
for (boost::tie(vit, vitend) = boost::vertices(graph); vit != vitend; ++vit) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Merging for plugin \"" << graph[*vit].Name() << "\"";
|
||||
|
||||
//Check if there is a plugin entry in the userlist. This will also find matching regex entries.
|
||||
list<loot::Plugin>::iterator pos = std::find(ulist_plugins.begin(), ulist_plugins.end(), graph[*vit]);
|
||||
|
||||
if (pos != ulist_plugins.end() && pos->Enabled()) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Merging userlist data down to plugin list data.";
|
||||
graph[*vit].MergeMetadata(*pos);
|
||||
}
|
||||
|
||||
progDia->Pulse();
|
||||
|
||||
//Now that items are merged, evaluate any conditions they have.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Evaluate conditions for merged plugin data.";
|
||||
try {
|
||||
graph[*vit].EvalAllConditions(*_game, lang);
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "\"" << graph[*vit].Name() << "\" contains a condition that could not be evaluated. Details: " << e.what();
|
||||
messages.push_back(loot::Message(loot::Message::error, (format(loc::translate("\"%1%\" contains a condition that could not be evaluated. Details: %2%")) % graph[*vit].Name() % e.what()).str()));
|
||||
}
|
||||
|
||||
progDia->Pulse();
|
||||
|
||||
//Also check install validity.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Checking that the current install is valid according to this plugin's data.";
|
||||
graph[*vit].CheckInstallValidity(*_game);
|
||||
|
||||
progDia->Pulse();
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Building the plugin dependency graph...";
|
||||
|
||||
//Now add the interactions between plugins to the graph as edges.
|
||||
std::map<std::string, int> overriddenPriorities;
|
||||
BOOST_LOG_TRIVIAL(debug) << "Adding non-overlap edges.";
|
||||
AddSpecificEdges(graph, overriddenPriorities);
|
||||
loot::AddSpecificEdges(graph, overriddenPriorities);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Adding priority edges.";
|
||||
AddPriorityEdges(graph);
|
||||
loot::AddPriorityEdges(graph);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Adding overlap edges.";
|
||||
AddOverlapEdges(graph);
|
||||
loot::AddOverlapEdges(graph);
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Checking to see if the graph is cyclic.";
|
||||
loot::CheckForCycles(graph);
|
||||
@@ -885,13 +896,32 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
|
||||
MiniEditor editor(this, translate("LOOT: Calculated Load Order"), plugins, ulist_plugins, *_game);
|
||||
|
||||
long ret = editor.ShowModal();
|
||||
const std::list<loot::Plugin> edits = editor.GetEditedPlugins();
|
||||
const std::list<loot::Plugin>& newUserlist = editor.GetNewUserlist();
|
||||
|
||||
//Need to determine if any new edits have been made.
|
||||
bool haveNewEdits = false;
|
||||
if (newUserlist.size() != ulist_plugins.size())
|
||||
haveNewEdits = true;
|
||||
else {
|
||||
for (const auto& newEdit : newUserlist) {
|
||||
const auto it = std::find(ulist_plugins.begin(), ulist_plugins.end(), newEdit);
|
||||
if (it == ulist_plugins.end()) {
|
||||
haveNewEdits = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!it->DiffMetadata(newEdit).HasNameOnly()) {
|
||||
haveNewEdits = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret != wxID_APPLY) {
|
||||
applyLoadOrder = false;
|
||||
break;
|
||||
}
|
||||
else if (edits.empty()) {
|
||||
else if (!haveNewEdits) {
|
||||
applyLoadOrder = true;
|
||||
break;
|
||||
}
|
||||
@@ -900,35 +930,7 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
|
||||
progDia = new wxProgressDialog(translate("LOOT: Working..."), translate("Recalculating load order..."), 1000, this, wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_ELAPSED_TIME);
|
||||
|
||||
//User accepted edits, now apply them, then loop.
|
||||
//Apply edits to the graph vertices.
|
||||
loot::vertex_it vit, vitend;
|
||||
for (boost::tie(vit, vitend) = boost::vertices(graph); vit != vitend; ++vit) {
|
||||
std::list<loot::Plugin>::const_iterator pos = std::find(edits.begin(), edits.end(), graph[*vit]);
|
||||
|
||||
if (pos != edits.end()) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Merging edits down to plugin list data.";
|
||||
graph[*vit].MergeMetadata(*pos);
|
||||
}
|
||||
}
|
||||
|
||||
//Clear all existing edges from the graph.
|
||||
BOOST_LOG_TRIVIAL(debug) << "Clearing all existing edges from the plugin graph.";
|
||||
for (boost::tie(vit, vitend) = boost::vertices(graph); vit != vitend; ++vit) {
|
||||
boost::clear_vertex(*vit, graph);
|
||||
}
|
||||
|
||||
//Merge edits down to the userlist entries.
|
||||
BOOST_LOG_TRIVIAL(debug) << "Merging down edits to the userlist.";
|
||||
for (const auto &plugin: edits) {
|
||||
auto it = find(ulist_plugins.begin(), ulist_plugins.end(), plugin);
|
||||
|
||||
if (it != ulist_plugins.end()) {
|
||||
it->MergeMetadata(plugin);
|
||||
}
|
||||
else {
|
||||
ulist_plugins.push_back(plugin);
|
||||
}
|
||||
}
|
||||
ulist_plugins = newUserlist;
|
||||
|
||||
//Save edits to userlist.
|
||||
BOOST_LOG_TRIVIAL(info) << "Saving edited userlist.";
|
||||
@@ -947,7 +949,7 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
|
||||
} while (true);
|
||||
|
||||
if (applyLoadOrder) {
|
||||
//User doesn't want to make any changes. Just go straight to applying the load order.
|
||||
//Applying the load order.
|
||||
BOOST_LOG_TRIVIAL(debug) << "Setting load order.";
|
||||
try {
|
||||
_game->SetLoadOrder(plugins);
|
||||
|
||||
Reference in New Issue
Block a user