Skip to content

Commit ed88383

Browse files
committed
WIP refactoring to make key handling clearer
1 parent 0cae34e commit ed88383

File tree

1 file changed

+92
-76
lines changed

1 file changed

+92
-76
lines changed

src/main/java/edu/umich/soar/visualsoar/components/AutocompletePopup.java

Lines changed: 92 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@
2525
import javax.swing.text.BadLocationException;
2626
import javax.swing.text.JTextComponent;
2727

28-
/**
29-
* Popup menu for auto-completing text in a document
30-
*/
28+
/** Popup menu for auto-completing text in a document */
3129
public class AutocompletePopup extends JPopupMenu {
3230

3331
private static final Set<Integer> CURSOR_MOVEMENT_PASSTHROUGH_KEYS =
@@ -42,7 +40,6 @@ public class AutocompletePopup extends JPopupMenu {
4240
private final AutocompleteContext autocompleteContext;
4341

4442
/**
45-
*
4643
* @param parent text component where completion will be performed
4744
* @param position position to perform completion at
4845
* @param inputSoFar text
@@ -57,7 +54,8 @@ public AutocompletePopup(
5754
@NotNull Consumer<String> onCompletion) {
5855
super();
5956
autocompleteContext = new AutocompleteContext(inputSoFar, suggestions);
60-
int maxVisibleRows = Math.min(autocompleteContext.unfilteredSuggestionsSize(), 10); // Limit to 10 rows max
57+
int maxVisibleRows =
58+
Math.min(autocompleteContext.unfilteredSuggestionsSize(), 10); // Limit to 10 rows max
6159
updateSuggestionList();
6260
suggestionList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
6361
suggestionList.setVisibleRowCount(maxVisibleRows);
@@ -67,12 +65,7 @@ public AutocompletePopup(
6765
new MouseAdapter() {
6866
@Override
6967
public void mouseClicked(MouseEvent e) {
70-
int index = suggestionList.locationToIndex(e.getPoint());
71-
if (index >= 0) {
72-
String selected = autocompleteContext.getCompletion(index);
73-
onCompletion.accept(selected);
74-
setVisible(false);
75-
}
68+
executeCompletion(suggestionList.locationToIndex(e.getPoint()), onCompletion);
7669
}
7770
});
7871

@@ -92,76 +85,13 @@ public void mouseMoved(MouseEvent e) {
9285
new KeyAdapter() {
9386
@Override
9487
public void keyPressed(KeyEvent e) {
95-
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
96-
setVisible(false);
97-
e.consume();
98-
return;
99-
}
100-
// Update auto-complete context and pass on to parent. Hide if nothing could be
101-
// deleted from the auto-complete context.
102-
if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
103-
if (autocompleteContext.canDelete()) {
104-
autocompleteContext.deleteInput();
105-
updateSuggestionList();
106-
} else{
107-
setVisible(false);
108-
}
109-
110-
parent.dispatchEvent(e);
111-
return;
112-
}
113-
// ENTER triggers the current selected completion
114-
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
115-
int index = suggestionList.getSelectedIndex();
116-
if (index >= 0) {
117-
String selected = autocompleteContext.getCompletion(index);
118-
onCompletion.accept(selected);
119-
setVisible(false);
120-
e.consume();
121-
return;
122-
}
123-
}
124-
// UP/DOWN keys navigate selection; custom handling here allows wrapping between
125-
// start/end of list
126-
if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_DOWN) {
127-
int index = suggestionList.getSelectedIndex();
128-
if (index == -1) {
129-
index = 0;
130-
} else {
131-
index += (e.getKeyCode() == KeyEvent.VK_UP) ? -1 : 1;
132-
}
133-
int numSuggestions = suggestionList.getModel().getSize();
134-
if (index < 0) {
135-
index = numSuggestions - 1;
136-
} else if (index >= numSuggestions) {
137-
index = 0;
138-
}
139-
suggestionList.setSelectedIndex(index);
140-
suggestionList.ensureIndexIsVisible(index);
141-
e.consume();
142-
return;
143-
}
144-
// Unambiguous cursor movement keys are passed through to parent after closing
145-
if (CURSOR_MOVEMENT_PASSTHROUGH_KEYS.contains(e.getKeyCode())) {
146-
setVisible(false);
147-
parent.dispatchEvent(e);
148-
return;
149-
}
88+
handleKeyPressed(e, parent, onCompletion);
15089
}
15190

15291
@Override
15392
public void keyTyped(KeyEvent e) {
15493
char typedChar = e.getKeyChar();
155-
if (Character.isDefined(typedChar) && !Character.isISOControl(typedChar)) {
156-
autocompleteContext.appendInput(typedChar);
157-
}
158-
if (autocompleteContext.filteredSuggestions().isEmpty()) {
159-
// Close the popup if no suggestions match
160-
setVisible(false);
161-
}
162-
updateSuggestionList();
163-
// enter the chars in the document
164-
parent.dispatchEvent(e);
94+
handleKeyTyped(e, typedChar, parent);
16595
}
16696
});
16797

@@ -196,6 +126,92 @@ public void keyTyped(KeyEvent e) {
196126
}
197127
}
198128

129+
private void handleKeyPressed(
130+
@NotNull KeyEvent e, @NotNull JTextComponent parent, @NotNull Consumer<String> onCompletion) {
131+
if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
132+
handleBackspace(e, parent);
133+
return;
134+
}
135+
// ENTER triggers the current selected completion
136+
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
137+
executeCompletion(suggestionList.getSelectedIndex(), onCompletion);
138+
e.consume();
139+
return;
140+
}
141+
if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_DOWN) {
142+
handleUpDownKeys(e);
143+
return;
144+
}
145+
// Unambiguous cursor movement keys are passed through to parent after closing
146+
if (CURSOR_MOVEMENT_PASSTHROUGH_KEYS.contains(e.getKeyCode())) {
147+
setVisible(false);
148+
parent.dispatchEvent(e);
149+
return;
150+
}
151+
parent.dispatchEvent(e);
152+
}
153+
154+
/**
155+
* When the user types, pass the typing through to the parent and update the suggestion list. If
156+
* no more suggestions are available, close this popup.
157+
*/
158+
private void handleKeyTyped(KeyEvent e, char typedChar, @NotNull JTextComponent parent) {
159+
if (Character.isDefined(typedChar) && !Character.isISOControl(typedChar)) {
160+
autocompleteContext.appendInput(typedChar);
161+
}
162+
if (autocompleteContext.filteredSuggestions().isEmpty()) {
163+
// Close the popup if no suggestions match
164+
setVisible(false);
165+
}
166+
updateSuggestionList();
167+
// enter the chars in the document
168+
parent.dispatchEvent(e);
169+
}
170+
171+
/**
172+
* Update auto-complete context and pass on to parent. Hide if nothing could be deleted from the
173+
* auto-complete context.
174+
*/
175+
private void handleBackspace(KeyEvent e, @NotNull JTextComponent parent) {
176+
if (autocompleteContext.canDelete()) {
177+
autocompleteContext.deleteInput();
178+
updateSuggestionList();
179+
} else {
180+
setVisible(false);
181+
}
182+
183+
parent.dispatchEvent(e);
184+
}
185+
186+
private void executeCompletion(int suggestionIndex, @NotNull Consumer<String> onCompletion) {
187+
if (suggestionIndex >= 0) {
188+
String selected = autocompleteContext.getCompletion(suggestionIndex);
189+
onCompletion.accept(selected);
190+
setVisible(false);
191+
}
192+
}
193+
194+
/**
195+
* UP/DOWN keys navigate selection; custom handling here allows wrapping between start/end of list
196+
*/
197+
private void handleUpDownKeys(KeyEvent e) {
198+
int index = suggestionList.getSelectedIndex();
199+
if (index == -1) {
200+
index = 0;
201+
} else {
202+
index += (e.getKeyCode() == KeyEvent.VK_UP) ? -1 : 1;
203+
}
204+
int numSuggestions = suggestionList.getModel().getSize();
205+
if (index < 0) {
206+
index = numSuggestions - 1;
207+
} else if (index >= numSuggestions) {
208+
index = 0;
209+
}
210+
suggestionList.setSelectedIndex(index);
211+
suggestionList.ensureIndexIsVisible(index);
212+
e.consume();
213+
}
214+
199215
private void updateSuggestionList() {
200216
suggestionList.setListData(new Vector<>(autocompleteContext.filteredSuggestions()));
201217
suggestionList.setSelectedIndex(0);

0 commit comments

Comments
 (0)