From 4d1b06e6c74650d207851b1b060aaf4acdca3b89 Mon Sep 17 00:00:00 2001 From: Oliver Hamlet Date: Tue, 19 Jan 2016 21:29:12 +0000 Subject: [PATCH] Warn if load order has not been sorted since opening LOOT. The warning is removed when the load order is sorted, but reinstated if sorting is cancelled. Closes #528. Note that if sorting is applied, then changes made so that another sort produces a new load order and this is cancelled, the message is not reinstated again, as its purposes is to remind users that simply launching LOOT is not enough, and not to tell them when another sort may be required. --- src/backend/game/game_cache.cpp | 17 +++++++++++--- src/backend/game/game_cache.h | 3 +++ src/backend/plugin_sorter.cpp | 1 + src/gui/handler.cpp | 5 +++- src/gui/html/js/events.js | 10 +++++--- src/tests/backend/game/test_game_cache.h | 30 ++++++++++++++++++++---- 6 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/backend/game/game_cache.cpp b/src/backend/game/game_cache.cpp index 3778e883..976e3ab8 100644 --- a/src/backend/game/game_cache.cpp +++ b/src/backend/game/game_cache.cpp @@ -39,13 +39,15 @@ namespace fs = boost::filesystem; namespace lc = boost::locale; namespace loot { - GameCache::GameCache() {} + GameCache::GameCache() : isLoadOrderSorted(false) {} + GameCache::GameCache(const GameCache& cache) : masterlist(cache.masterlist), userlist(cache.userlist), conditionCache(cache.conditionCache), plugins(cache.plugins), - messages(cache.messages) {} + messages(cache.messages), + isLoadOrderSorted(cache.isLoadOrderSorted) {} GameCache& GameCache::operator=(const GameCache& cache) { if (&cache != this) { @@ -54,6 +56,7 @@ namespace loot { conditionCache = cache.conditionCache; plugins = cache.plugins; messages = cache.messages; + isLoadOrderSorted = cache.isLoadOrderSorted; } return *this; @@ -111,7 +114,11 @@ namespace loot { } std::vector GameCache::GetMessages() const { - return messages; + vector output(messages); + if (!isLoadOrderSorted) + output.push_back(Message(Message::warn, "You have not sorted your load order this session.")); + + return output; } void GameCache::AppendMessage(const Message& message) { @@ -120,6 +127,10 @@ namespace loot { messages.push_back(message); } + void GameCache::SetLoadOrderSorted(bool isLoadOrderSorted) { + this->isLoadOrderSorted = isLoadOrderSorted; + } + void GameCache::ClearCachedConditions() { std::lock_guard guard(mutex); diff --git a/src/backend/game/game_cache.h b/src/backend/game/game_cache.h index 8eeae07a..3d797e98 100644 --- a/src/backend/game/game_cache.h +++ b/src/backend/game/game_cache.h @@ -55,6 +55,8 @@ namespace loot { std::vector GetMessages() const; void AppendMessage(const Message& message); + void SetLoadOrderSorted(bool isLoadOrderSorted); + void ClearCachedConditions(); void ClearCachedPlugins(); void ClearMessages(); @@ -64,6 +66,7 @@ namespace loot { std::unordered_map conditionCache; std::unordered_map plugins; std::vector messages; + bool isLoadOrderSorted; mutable std::mutex mutex; }; diff --git a/src/backend/plugin_sorter.cpp b/src/backend/plugin_sorter.cpp index 954fc01e..8014537b 100644 --- a/src/backend/plugin_sorter.cpp +++ b/src/backend/plugin_sorter.cpp @@ -156,6 +156,7 @@ namespace loot { // Clear any existing game-specific messages, as these only relate to // state that has been changed by sorting. game.ClearMessages(); + game.SetLoadOrderSorted(true); return plugins; } diff --git a/src/gui/handler.cpp b/src/gui/handler.cpp index 26ecf015..05297443 100644 --- a/src/gui/handler.cpp +++ b/src/gui/handler.cpp @@ -161,7 +161,10 @@ namespace loot { } else if (request == "cancelSort") { _lootState.decrementUnappliedChangeCounter(); - callback->Success(""); + _lootState.CurrentGame().SetLoadOrderSorted(false); + + YAML::Node node(GetGeneralMessages()); + callback->Success(JSON::stringify(node)); return true; } else if (request == "editorOpened") { diff --git a/src/gui/html/js/events.js b/src/gui/html/js/events.js index 7a044c41..3f81f923 100644 --- a/src/gui/html/js/events.js +++ b/src/gui/html/js/events.js @@ -102,13 +102,14 @@ function onSortPlugins() { if (!result) { return; } + + loot.game.globalMessages = result.globalMessages; + /* Check if sorted load order differs from current load order. */ const loadOrderIsUnchanged = result.plugins.every((plugin, index) => { return plugin.name === loot.game.plugins[index].name; }); if (loadOrderIsUnchanged) { - loot.game.globalMessages = result.globalMessages; - result.plugins.forEach((plugin) => { const existingPlugin = loot.game.plugins.find((item) => { return item.name === plugin.name; @@ -177,13 +178,16 @@ function onApplySort() { }).catch(handlePromiseError); } function onCancelSort() { - return loot.query('cancelSort').then(() => { + return loot.query('cancelSort').then(JSON.parse).then((messages) => { /* Sort UI elements again according to stored old load order. */ loot.game.plugins = loot.game.oldLoadOrder; filterPluginData(loot.game.plugins, loot.filters); delete loot.game.loadOrder; delete loot.game.oldLoadOrder; + /* Update general messages */ + loot.game.globalMessages = messages; + /* Now show the masterlist update buttons, and hide the accept and cancel sort buttons. */ loot.dom.show('updateMasterlistButton'); diff --git a/src/tests/backend/game/test_game_cache.h b/src/tests/backend/game/test_game_cache.h index 063a2c49..2a909fe5 100644 --- a/src/tests/backend/game/test_game_cache.h +++ b/src/tests/backend/game/test_game_cache.h @@ -45,6 +45,7 @@ namespace loot { cache.AddPlugin(loot::Plugin(game, "Blank.esm", true)); Message expectedMessage(Message::say, "1"); cache.AppendMessage(expectedMessage); + cache.SetLoadOrderSorted(true); loot::GameCache otherCache(cache); EXPECT_EQ(std::make_pair(true, true), otherCache.GetCachedCondition("true Condition")); @@ -62,6 +63,7 @@ namespace loot { cache.AddPlugin(loot::Plugin(game, "Blank.esm", true)); Message expectedMessage(Message::say, "1"); cache.AppendMessage(expectedMessage); + cache.SetLoadOrderSorted(true); loot::GameCache otherCache = cache; EXPECT_EQ(std::make_pair(true, true), otherCache.GetCachedCondition("true Condition")); @@ -165,8 +167,22 @@ namespace loot { EXPECT_TRUE(cache.GetPlugins().empty()); } - TEST_F(GameCache, noMessagesShouldBeStoredByDefault) { - EXPECT_TRUE(cache.GetMessages().empty()); + TEST_F(GameCache, aMessageShouldBeCachedByDefault) { + ASSERT_EQ(1, cache.GetMessages().size()); + } + + TEST_F(GameCache, settingLoadOrderSortedToTrueShouldSupressDefaultCachedMessage) { + cache.SetLoadOrderSorted(true); + + ASSERT_TRUE(cache.GetMessages().empty()); + } + + TEST_F(GameCache, settingLoadOrderSortedToFalseShouldReverseTheDefaultCachedMessageSuppression) { + auto expectedMessages = cache.GetMessages(); + cache.SetLoadOrderSorted(true); + cache.SetLoadOrderSorted(false); + + ASSERT_EQ(expectedMessages, cache.GetMessages()); } TEST_F(GameCache, appendingMessagesShouldStoreThemInTheGivenOrder) { @@ -177,10 +193,12 @@ namespace loot { for (const auto& message : messages) cache.AppendMessage(message); - EXPECT_EQ(messages, cache.GetMessages()); + ASSERT_EQ(3, cache.GetMessages().size()); + EXPECT_EQ(messages[0], cache.GetMessages()[0]); + EXPECT_EQ(messages[1], cache.GetMessages()[1]); } - TEST_F(GameCache, clearingMessagesShouldRemoveAllStoredMessages) { + TEST_F(GameCache, clearingMessagesShouldRemoveAllAppendedMessages) { std::vector messages({ Message(Message::say, "1"), Message(Message::error, "2"), @@ -188,9 +206,11 @@ namespace loot { for (const auto& message : messages) cache.AppendMessage(message); + auto previousSize = cache.GetMessages().size(); + cache.ClearMessages(); - EXPECT_TRUE(cache.GetMessages().empty()); + EXPECT_EQ(previousSize - messages.size(), cache.GetMessages().size()); } } }