Test fixes

This commit is contained in:
dragonmacher 2025-03-20 14:25:03 -04:00
parent 22f36c2769
commit c02a321aef
5 changed files with 91 additions and 25 deletions

View file

@ -39,6 +39,7 @@ import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.ProgramContext;
import ghidra.util.Msg;
import ghidra.util.Swing;
class VarnodeLocationCellEditor extends AbstractCellEditor
implements TableCellEditor, FocusableEditor {
@ -193,6 +194,9 @@ class VarnodeLocationCellEditor extends AbstractCellEditor
registerEntryTextField = new DropDownSelectionTextField<>(registerModel);
registerEntryTextField.setBorder(null);
// this allows us to show the matching list when there is no text in the editor
registerEntryTextField.setShowMatchingListOnEmptyText(true);
AtomicReference<Register> currentReg = new AtomicReference<>();
Address address = varnode.getAddress();
@ -219,7 +223,12 @@ class VarnodeLocationCellEditor extends AbstractCellEditor
registerEntryTextField.addActionListener(e -> stopCellEditing());
// Note: need to do this later. At the time of construction, this text field is not yet
// showing. The text field has checks to avoid showing the list if it is not showing. By
// running later, this call will happen once the widget has been added to the table.
Swing.runLater(() -> {
registerEntryTextField.showMatchingList();
});
return registerEntryTextField;
}

View file

@ -151,14 +151,8 @@ public class IconPropertyEditor extends PropertyEditorSupport {
private Component buildTopPanel() {
JPanel panel = new JPanel(new BorderLayout());
dataModel = new IconDropDownDataModel();
dropDown = new DropDownSelectionTextField<>(dataModel) {
protected List<Icon> getMatchingData(String searchText) {
if (searchText.isBlank()) {
return ((IconDropDownDataModel) dataModel).getData();
}
return super.getMatchingData(searchText);
}
};
dropDown = new DropDownSelectionTextField<>(dataModel);
dropDown.setShowMatchingListOnEmptyText(true);
dropDown.addDropDownSelectionChoiceListener(choiceListener);
panel.add(dropDown, BorderLayout.CENTER);
JButton browseButton = new BrowseButton();

View file

@ -91,6 +91,7 @@ public class DropDownTextField<T> extends JTextField implements GComponent {
private boolean consumeEnterKeyPress = true; // consume Enter presses by default
private boolean ignoreEnterKeyPress = false; // do not ignore enter by default
private boolean ignoreCaretChanges;
private boolean showMachingListOnEmptyText;
// We use an update manager to buffer requests to update the matches. This allows us to be
// more responsive when the user is attempting to type multiple characters
@ -354,6 +355,12 @@ public class DropDownTextField<T> extends JTextField implements GComponent {
return Collections.emptyList();
}
// By default we do not show the matches list is empty. This seems less noisy. Some
// clients would rather have empty text show all available choices.
if (searchText.isEmpty() && !showMachingListOnEmptyText) {
return Collections.emptyList();
}
// get the sublist of matches--this may take a while
Cursor previousCursor = getCursor();
try {
@ -377,8 +384,22 @@ public class DropDownTextField<T> extends JTextField implements GComponent {
* text.
*/
public void showMatchingList() {
String text = pendingTextUpdate != null ? pendingTextUpdate : getText();
updateDisplayContents(text);
//
// We temporarily enable this list to show for empty text, even if the text is not empty.
// This handles the default setting, which has this feature off. We can refactor this class
// to allow us to make a direct call instead of using this temporary setting. This seems
// simple enough for now.
//
boolean restore = showMachingListOnEmptyText;
try {
showMachingListOnEmptyText = true;
pendingTextUpdate = pendingTextUpdate != null ? pendingTextUpdate : getText();
updateManager.updateNow();
}
finally {
showMachingListOnEmptyText = restore;
}
}
/**
@ -414,6 +435,15 @@ public class DropDownTextField<T> extends JTextField implements GComponent {
this.ignoreEnterKeyPress = ignore;
}
/**
* Allows this text field to show all potential matches when the text of the field is empty.
* The default is false.
* @param show true to allow the list to be shown
*/
public void setShowMatchingListOnEmptyText(boolean show) {
this.showMachingListOnEmptyText = show;
}
/**
* Sets the height of the matching window. The default value is {@value #MIN_HEIGHT}.
*

View file

@ -30,7 +30,6 @@ import org.junit.After;
import org.junit.Before;
import docking.test.AbstractDockingTest;
import ghidra.util.Msg;
public abstract class AbstractDropDownTextFieldTest<T> extends AbstractDockingTest {
@ -234,10 +233,10 @@ public abstract class AbstractDropDownTextFieldTest<T> extends AbstractDockingTe
protected void hideWindowPressKeyThenValidate(int keyCode) {
JWindow matchingWindow = textField.getActiveMatchingWindow();
matchingWindow.setVisible(false);
runSwing(() -> matchingWindow.setVisible(false));
waitForSwing();
assertTrue("The completion window is showing after a call to setVisible(false).",
!matchingWindow.isShowing());
assertFalse("The completion window is showing after a call to setVisible(false).",
matchingWindow.isShowing());
tpyeActionKey(keyCode);
assertTrue("The completion window is not showing after being trigger by a navigation key.",
matchingWindow.isShowing());
@ -309,10 +308,6 @@ public abstract class AbstractDropDownTextFieldTest<T> extends AbstractDockingTe
return;
}
if (!matchingWindow.isShowing()) {
Msg.debug(this, "");
}
assertTrue("Window is not showing when it should be", matchingWindow.isShowing());
}

View file

@ -435,4 +435,42 @@ public class DropDownTextFieldTest extends AbstractDropDownTextFieldTest<String>
Dimension windowSize = matchingWindow.getSize();
assertEquals(newSize, windowSize.height);
}
@Test
public void testShowMatchingListOnEmptyText() {
runSwing(() -> textField.setShowMatchingListOnEmptyText(false));
// insert some text and make sure the window is created
typeText("d", true);
assertMatchingWindowShowing();
// with this setting off, the list stays visible on empty text
clearText();
assertMatchingWindowHidden();
// even with this setting off, this method should always force the list to show
showMatchingList();
assertMatchingWindowShowing();
runSwing(() -> textField.setShowMatchingListOnEmptyText(true));
showMatchingList();
assertMatchingWindowShowing();
typeText("d", true);
assertMatchingWindowShowing();
// with this setting on, the list stays visible on empty text
clearText();
assertMatchingWindowShowing();
// with this setting on, this method should always force the list to show
showMatchingList();
assertMatchingWindowShowing();
}
private void showMatchingList() {
runSwing(() -> textField.showMatchingList());
}
}