diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/autocomplete/TextFieldAutocompleter.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/autocomplete/TextFieldAutocompleter.java index fef873e6a6..d45552dfef 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/autocomplete/TextFieldAutocompleter.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/autocomplete/TextFieldAutocompleter.java @@ -36,7 +36,7 @@ import ghidra.util.task.SwingUpdateManager; /** * An autocompleter that may be attached to one or more {@link JTextField}. - * + * *
* Each autocompleter instance has one associated window (displaying the list of suggestions) and * one associated model (generating the list of suggestions). Thus, the list can only be active on @@ -44,7 +44,7 @@ import ghidra.util.task.SwingUpdateManager; * for one autocompleter to be reused on many fields. Behavior is undefined when multiple * autocompleters are attached to the same text field. More likely, you should implement a composite * model if you wish to present completions from multiple models on a single text field. - * + * *
* By default, the autocompleter is activated when the user presses CTRL-SPACE, at which point, the * model is queried for possible suggestions. The completer gives the model all the text preceding @@ -56,7 +56,7 @@ import ghidra.util.task.SwingUpdateManager; * positioning behavior can be modified by overriding the {@link #getCompletionWindowPosition()} * method. As a convenience, the {@link #getCaretPositionOnScreen(JTextField)} method is available * to compute the default position. - * + * *
* Whether or not the list is currently displayed, when the user presses CTRL-SPACE, if only one * completion is possible, it is automatically activated. This logic is applied again and again, @@ -65,20 +65,20 @@ import ghidra.util.task.SwingUpdateManager; * by overriding the {@link #getCompletionCanDefault(Object) getCompletionCanDefault(T)} method. * This same behavior can be activated by calling the {@link #startCompletion(JTextField)} method, * which may be useful, e.g., to bind a different key sequence to start autocompletion. - * + * *
* The appearance of each item in the suggestion list can be modified by overriding the various * {@code getCompletion...} methods. Note that it's possible for an item to be displayed one way, * but cause the insertion of different text. In any case, it is best to ensure any modification * produces an intuitive behavior. - * + * *
* The simplest use case is to create a text field, create an autocompleter with a custom model, and * then attach and show. - * + * *
* JTextField field = new JTextField(); - * + * * AutocompletionModel- * + * * @parammodel = new AutocompletionModel () { * @Override * public Collection computeCompletions(String text) { @@ -88,9 +88,9 @@ import ghidra.util.task.SwingUpdateManager; * TextFieldAutocompleter completer = new TextFieldAutocompleter (model); * completer.attachTo(field); * // ... Add the field to, e.g., a dialog, and show. - * + * *
* This is useful, e.g., when the window containing the associated text field(s) moves.
*/
@@ -288,7 +288,7 @@ public class TextFieldAutocompleter
* This entails taking the prefix, querying the model, and rendering the list.
*/
@@ -336,6 +336,11 @@ public class TextFieldAutocompleter
* If it is visible, this implies that the user is actively using the autocompleter.
- *
+ *
* @return true if shown, false if hidden.
*/
public boolean isCompletionListVisible() {
@@ -388,12 +393,14 @@ public class TextFieldAutocompleter
* Typically, this is a location near the focused field. Ideally, it is positioned such that the
* displayed suggestions coincide with the applicable text in the focused field. For example, if
* the suggestions display some portion of the prefix, the window could be positioned such that
* the portion in the suggestion appears directly below the same portion in the field.
- *
+ *
* @return the point giving the top-left corner of the completion window
*/
protected Point getCompletionWindowPosition() {
@@ -423,24 +430,31 @@ public class TextFieldAutocompleter
* Typically, this is the width of the focused field.
- *
+ *
* @return the dimension giving the preferred height and width. A value can be -1 to indicate no
* preference.
*/
protected Dimension getDefaultCompletionWindowDimension() {
+ if (focus == null) {
+ return new Dimension(-1, -1);
+ }
return new Dimension(focus.getWidth(), -1);
}
/**
* A convenience function that returns the bottom on-screen position of the given field's caret.
- *
+ *
* @param field the field, typically the one having focus
- * @return the on-screen position of the caret's bottom.
+ * @return the on-screen position of the caret's bottom; null if the given field is null
*/
protected Point getCaretPositionOnScreen(JTextField field) {
+ if (focus == null) {
+ return null;
+ }
+
FontMetrics metrics = field.getFontMetrics(field.getFont());
Caret c = field.getCaret();
Point p = c.getMagicCaretPosition(); // returns a shared reference
@@ -457,14 +471,14 @@ public class TextFieldAutocompleter
* A programmer may override this if the various {@code getCompletion...} methods prove
* insufficient for customizing the display of the suggestions. Please remember that
* {@link JLabel}s can render HTML, so {@link #getCompletionDisplay(Object)
* getCompletionDisplay(T)} is quite powerful with the default
* {@link AutocompletionCellRenderer}.
- *
+ *
* @return a list cell renderer for the completion list.
*/
protected ListCellRenderer super T> buildListCellRenderer() {
@@ -473,10 +487,10 @@ public class TextFieldAutocompleter
* If this method is never called, then the autocompleter can never appear.
- *
+ *
* @param field the field that will gain this autocompletion feature
* @return true, if this field is not already attached
*/
@@ -502,7 +516,7 @@ public class TextFieldAutocompleter
* By default, this is called when the user presses ENTER or clicks a suggestion.
*/
@@ -535,12 +549,12 @@ public class TextFieldAutocompleter
* Each registered listener is invoked in order of registration. If any listener consumes the
* event, then later-registered listeners will not be notified of the event. If any listener
* cancels the event, then the suggested text will not be inserted.
- *
+ *
* @param ev the event
* @return true, if no listener cancelled the event
*/
@@ -555,14 +569,18 @@ public class TextFieldAutocompleter
* When autocompletion is started (via {@link #startCompletion(JTextField)}) or when the user
* presses CTRL-SPACE, if there is only a single suggestion, it is taken automatically, and the
@@ -692,7 +710,7 @@ public class TextFieldAutocompleter
* First, this repeatedly attempts auto-activation. When there are many suggestions, or when
* auto-activation is prevented (see {@link #getCompletionCanDefault(Object)
* getCompletionCanDefault(T)}), a list is displayed (usually below the caret) containing the
* suggestions given the fields current contents. The list remains open until either the user
* cancels it (usually via ESC) or the user activates a suggestion.
- *
+ *
*
* NOTE: The text field must already be attached.
- *
+ *
* @param field the field on which to start autocompletion.
*/
public void startCompletion(JTextField field) {
@@ -765,7 +783,7 @@ public class TextFieldAutocompleter
* The autocompleter offers the tails from a list of strings that start with the text before the
* caret.
@@ -1056,7 +1074,7 @@ public class TextFieldAutocompleter
* This demo was designed to test whether the autocompleter and the {@link TextFieldLinker}
* could be composed correctly.