Merge remote-tracking branch 'origin/GP-2-dragonmacher-history-list-update'

This commit is contained in:
Ryan Kurtz
2026-05-29 05:31:47 -04:00
2 changed files with 89 additions and 7 deletions

View File

@@ -22,7 +22,7 @@ import java.util.function.Consumer;
import org.apache.commons.lang3.StringUtils;
import ghidra.util.Msg;
import ghidra.util.SystemUtilities;
import ghidra.util.Swing;
import ghidra.util.datastruct.FixedSizeStack;
/**
@@ -121,7 +121,7 @@ public class HistoryList<T> {
/**
* True signals that the client allows null items to be used. When this is true, a null
* value will be stored in this list <b>only as the last item</b>. See the javadoc for
* value will be stored in this list <b>only as the last item</b>. See the class javadoc for
* more info.
*
* @param allowNulls true to allow nulls; the default is false
@@ -133,9 +133,12 @@ public class HistoryList<T> {
/**
* Adds an item to this history list. <code>null</code> values are ignored.
*
* <p>After this call, the {@link #getCurrentHistoryItem() current history item} will be the
* newly added item.
*
* <p>Calls to this method during selection notification will have no effect. If you need
* to update the history during a notification, then you must do so at a later time, perhaps
* by using {@link SystemUtilities#runSwingLater(Runnable)}.
* by using {@link Swing#runLater(Runnable)}.
*
* @param t the item to add.
*/
@@ -152,7 +155,7 @@ public class HistoryList<T> {
dropNull();
// once we add a new item, any old history that was after this item needs to be
// removed, as that is old alternate timeline that no longer makes sense
// removed, as that old alternate timeline that no longer makes sense
trimHistoryToCurrentIndex();
handleDuplicate(t);
@@ -163,6 +166,35 @@ public class HistoryList<T> {
historyIndex = historyStack.size() - 1;
}
/**
* Performs an {@link #add(Object)} after removing the last item in the history, which is
* effectively a replace operation. This method is useful for clients that wish to keep the
* history from filling up with transient items as the user is navigating. The client may
* decide to replace the previous history marker with the newest history marker, such as when
* the navigations are frequent and not necessarily important, such as when using the down arrow
* key to cursor through a text file.
*
* <p>After this call, the {@link #getCurrentHistoryItem() current history item} will be the
* newly added item.
*
* <p>Calls to this method during selection notification will have no effect. If you need
* to update the history during a notification, then you must do so at a later time, perhaps
* by using {@link Swing#runLater(Runnable)}.
*
* @param t the item to add.
*/
public void addReplace(T t) {
if (isBroadcasting) {
return;
}
historyStack.pop();
historyIndex = historyStack.size() - 1;
add(t);
}
/**
* Returns true if this history list's current item pointer is not at the end of the list.
*

View File

@@ -19,8 +19,7 @@ import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.*;
import java.util.LinkedList;
import java.util.List;
import java.util.*;
import java.util.function.Consumer;
import org.junit.Test;
@@ -153,6 +152,52 @@ public class HistoryListTest {
assertCannotGoBack();
}
@Test
public void testAddReplace() {
addHistory(A);
addHistory(B);
addHistory(C);
replaceHistory(D); // C -> D
replaceHistory(E); // D -> E
assertHistory(A, B, E);
goBack();
assertNotified(B);
assertCurrentItem(B);
goBack();
assertNotified(A);
assertCannotGoBack();
goForward();
assertNotified(B);
goForward();
assertNotified(E);
}
@Test
public void testAddReplace_NotAtEnd() {
addHistory(A);
addHistory(B);
addHistory(C);
addHistory(D);
assertHistory(A, B, C, D);
goBack();
goBack();
assertNotified(B);
assertCurrentItem(B);
replaceHistory(E); // D -> E
assertHistory(A, B, C, E);
assertCurrentItem(E);
}
@Test
public void testNavigationMixedWithHistoryAddition() {
//
@@ -503,10 +548,15 @@ public class HistoryListTest {
historyList.add(item);
}
private void replaceHistory(String item) {
historyList.addReplace(item);
}
private void assertHistory(String... names) {
FixedSizeStack<String> stack = historyList.getHistoryStack();
assertEquals(names.length, stack.size());
assertEquals("History size is wrong: " + Arrays.toString(names) + " vs " + stack,
names.length, stack.size());
for (int i = 0; i < stack.size(); i++) {
assertEquals("Unexpected item in history", names[i], stack.get(i));
}