From 83607f1335ef2d3d658606a5073561fc4e49a4e4 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 1 Jul 2020 19:18:30 -0400 Subject: [PATCH] infobox manager: keep infoboxes in order of insertion Collections.binarySearch() does not guarantee which element is found if there are multiple that compare equal, leaving the order of infoboxes not necessarily in insertion order. This was an unintended side effect of ba9ffb1d600d314100a128db503d10b97a6cbef5 and 406c2bc7dbb8b9db70e8e525fb51aad5f3f56e0d. --- .../ui/overlay/infobox/InfoBoxManager.java | 39 ++++++++++++++++++- .../overlay/infobox/InfoBoxManagerTest.java | 3 ++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxManager.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxManager.java index 766b34c57c..efda12a992 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxManager.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxManager.java @@ -29,6 +29,7 @@ import com.google.common.collect.ComparisonChain; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Predicate; @@ -71,12 +72,12 @@ public class InfoBoxManager synchronized (this) { - int idx = Collections.binarySearch(infoBoxes, infoBox, (b1, b2) -> ComparisonChain + int idx = findInsertionIndex(infoBoxes, infoBox, (b1, b2) -> ComparisonChain .start() .compare(b1.getPriority(), b2.getPriority()) .compare(b1.getPlugin().getName(), b2.getPlugin().getName()) .result()); - infoBoxes.add(idx < 0 ? -idx - 1 : idx, infoBox); + infoBoxes.add(idx, infoBox); } BufferedImage image = infoBox.getImage(); @@ -150,4 +151,38 @@ public class InfoBoxManager infoBox.setScaledImage(resultImage); } + + /** + * Find insertion point for the given key into the given sorted list. If key already exists in the list, + * return the index after the last occurrence. + * @param list + * @param key + * @param c + * @param + * @return + */ + private static int findInsertionIndex(List list, T key, Comparator c) + { + int idx = Collections.binarySearch(list, key, c); + + if (idx < 0) + { + // key isn't found in the list + return -idx - 1; + } + + // list(idx) is equal to key, so it is not necessary to recheck it + for (int i = idx + 1; i < list.size(); ++i) + { + T cur = list.get(i); + int cmp = c.compare(cur, key); + if (cmp > 0) + { + // this is the first element which is greater + return i; + } + } + + return list.size(); + } } diff --git a/runelite-client/src/test/java/net/runelite/client/ui/overlay/infobox/InfoBoxManagerTest.java b/runelite-client/src/test/java/net/runelite/client/ui/overlay/infobox/InfoBoxManagerTest.java index e0ce1e6a6e..49c9c2c484 100644 --- a/runelite-client/src/test/java/net/runelite/client/ui/overlay/infobox/InfoBoxManagerTest.java +++ b/runelite-client/src/test/java/net/runelite/client/ui/overlay/infobox/InfoBoxManagerTest.java @@ -114,5 +114,8 @@ public class InfoBoxManagerTest infoBoxManager.addInfoBox(new TestInfobox(InfoBoxPriority.MED, "three")); assertEquals(3, infoBoxManager.getInfoBoxes().size()); + assertEquals("one", infoBoxManager.getInfoBoxes().get(0).getText()); + assertEquals("two", infoBoxManager.getInfoBoxes().get(1).getText()); + assertEquals("three", infoBoxManager.getInfoBoxes().get(2).getText()); } } \ No newline at end of file