|
|
|
@ -8,17 +8,17 @@
|
|
|
|
|
*/ |
|
|
|
|
package com.fr.design.gui.autocomplete; |
|
|
|
|
|
|
|
|
|
import java.awt.*; |
|
|
|
|
import java.awt.event.*; |
|
|
|
|
import java.beans.PropertyChangeEvent; |
|
|
|
|
import java.beans.PropertyChangeListener; |
|
|
|
|
import java.util.List; |
|
|
|
|
import javax.swing.*; |
|
|
|
|
import javax.swing.event.CaretEvent; |
|
|
|
|
import javax.swing.event.CaretListener; |
|
|
|
|
import javax.swing.event.DocumentEvent; |
|
|
|
|
import javax.swing.event.DocumentListener; |
|
|
|
|
import javax.swing.text.*; |
|
|
|
|
import java.awt.*; |
|
|
|
|
import java.awt.event.*; |
|
|
|
|
import java.beans.PropertyChangeEvent; |
|
|
|
|
import java.beans.PropertyChangeListener; |
|
|
|
|
import java.util.List; |
|
|
|
|
|
|
|
|
|
import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; |
|
|
|
|
|
|
|
|
@ -26,10 +26,10 @@ import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_M
|
|
|
|
|
/** |
|
|
|
|
* Adds auto-completion to a text component. Provides a popup window with a |
|
|
|
|
* list of auto-complete choices on a given keystroke, such as Crtrl+Space.<p> |
|
|
|
|
* |
|
|
|
|
* <p> |
|
|
|
|
* Depending on the {@link CompletionProvider} installed, the following |
|
|
|
|
* auto-completion features may be enabled: |
|
|
|
|
* |
|
|
|
|
* <p> |
|
|
|
|
* <ul> |
|
|
|
|
* <li>An auto-complete choices list made visible via e.g. Ctrl+Space</li> |
|
|
|
|
* <li>A "description" window displayed alongside the choices list that |
|
|
|
@ -214,7 +214,7 @@ public class AutoCompletion {
|
|
|
|
|
* Stores how to render auto-completion-specific highlights in text |
|
|
|
|
* components. |
|
|
|
|
*/ |
|
|
|
|
private static final AutoCompletionStyleContext styleContext = |
|
|
|
|
private static final AutoCompletionStyleContext STYLE_CONTEXT = |
|
|
|
|
new AutoCompletionStyleContext(); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -297,7 +297,7 @@ public class AutoCompletion {
|
|
|
|
|
* |
|
|
|
|
* @return Whether debug is enabled. |
|
|
|
|
*/ |
|
|
|
|
static boolean getDebug() { |
|
|
|
|
static boolean isDebug() { |
|
|
|
|
return DEBUG; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -398,7 +398,7 @@ public class AutoCompletion {
|
|
|
|
|
* @return Whether the description window should be shown. |
|
|
|
|
* @see #setShowDescWindow(boolean) |
|
|
|
|
*/ |
|
|
|
|
public boolean getShowDescWindow() { |
|
|
|
|
public boolean isShowDescWindow() { |
|
|
|
|
return showDescWindow; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -410,7 +410,7 @@ public class AutoCompletion {
|
|
|
|
|
* @return The style context. |
|
|
|
|
*/ |
|
|
|
|
public static AutoCompletionStyleContext getStyleContext() { |
|
|
|
|
return styleContext; |
|
|
|
|
return STYLE_CONTEXT; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -681,60 +681,32 @@ public class AutoCompletion {
|
|
|
|
|
* @return The current line number of the caret. |
|
|
|
|
*/ |
|
|
|
|
protected int refreshPopupWindow() { |
|
|
|
|
|
|
|
|
|
// A return value of null => don't suggest completions
|
|
|
|
|
String text = provider.getAlreadyEnteredText(textComponent); |
|
|
|
|
if (text == null && !isPopupVisible()) { |
|
|
|
|
return getLineOfCaret(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// If the popup is currently visible, and they type a space (or any
|
|
|
|
|
// character that resets the completion list to "all completions"),
|
|
|
|
|
// the popup window should be hidden instead of being reset to show
|
|
|
|
|
// everything.
|
|
|
|
|
int textLen = text == null ? 0 : text.length(); |
|
|
|
|
if (textLen==0) { |
|
|
|
|
if (isPopupVisible()) { |
|
|
|
|
if (textLen == 0 && isPopupVisible()) { |
|
|
|
|
hidePopupWindow(); |
|
|
|
|
return getLineOfCaret(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
final List<Completion> completions = provider. |
|
|
|
|
getCompletions(textComponent); |
|
|
|
|
final List<Completion> completions = provider.getCompletions(textComponent); |
|
|
|
|
int count = completions.size(); |
|
|
|
|
|
|
|
|
|
if (count>1 || (count==1 && (isPopupVisible() || textLen==0)) || |
|
|
|
|
(count==1 && !getAutoCompleteSingleChoices())) { |
|
|
|
|
|
|
|
|
|
if (needSetPopupWindow(count, textLen)) { |
|
|
|
|
if (popupWindow == null) { |
|
|
|
|
popupWindow = new AutoCompletePopupWindow(parentWindow, this); |
|
|
|
|
// Completion is usually done for code, which is always done
|
|
|
|
|
// LTR, so make completion stuff RTL only if text component is
|
|
|
|
|
// also RTL.
|
|
|
|
|
popupWindow.applyComponentOrientation( |
|
|
|
|
getTextComponentOrientation()); |
|
|
|
|
if (renderer!=null) { |
|
|
|
|
popupWindow.setListCellRenderer(renderer); |
|
|
|
|
} |
|
|
|
|
if (preferredChoicesWindowSize!=null) { |
|
|
|
|
popupWindow.setSize(preferredChoicesWindowSize); |
|
|
|
|
} |
|
|
|
|
if (preferredDescWindowSize!=null) { |
|
|
|
|
popupWindow.setDescriptionWindowSize( |
|
|
|
|
preferredDescWindowSize); |
|
|
|
|
} |
|
|
|
|
popupWindow = createAutoCompletePopupWindow(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
popupWindow.setCompletions(completions); |
|
|
|
|
|
|
|
|
|
if (!popupWindow.isVisible()) { |
|
|
|
|
Rectangle r = null; |
|
|
|
|
try { |
|
|
|
|
r = textComponent.modelToView(textComponent. |
|
|
|
|
getCaretPosition()); |
|
|
|
|
r = textComponent.modelToView(textComponent.getCaretPosition()); |
|
|
|
|
} catch (BadLocationException ble) { |
|
|
|
|
|
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
Point p = new Point(r.x, r.y); |
|
|
|
@ -744,25 +716,43 @@ public class AutoCompletion {
|
|
|
|
|
popupWindow.setLocationRelativeTo(r); |
|
|
|
|
popupWindow.setVisible(true); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
else if (count==1) { // !isPopupVisible && autoCompleteSingleChoices
|
|
|
|
|
} else if (count == 1) { // !isPopupVisible && autoCompleteSingleChoices
|
|
|
|
|
SwingUtilities.invokeLater(new Runnable() { |
|
|
|
|
public void run() { |
|
|
|
|
insertCompletion(completions.get(0)); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
else { |
|
|
|
|
} else { |
|
|
|
|
hidePopupWindow(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return getLineOfCaret(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private boolean needSetPopupWindow(int count, int textLen) { |
|
|
|
|
return (count == 1 && (isPopupVisible() || textLen == 0)) |
|
|
|
|
|| (count == 1 && !getAutoCompleteSingleChoices()) |
|
|
|
|
|| count > 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private AutoCompletePopupWindow createAutoCompletePopupWindow() { |
|
|
|
|
AutoCompletePopupWindow popupWindow = new AutoCompletePopupWindow(parentWindow, this); |
|
|
|
|
// Completion is usually done for code, which is always done
|
|
|
|
|
// LTR, so make completion stuff RTL only if text component is
|
|
|
|
|
// also RTL.
|
|
|
|
|
popupWindow.applyComponentOrientation( |
|
|
|
|
getTextComponentOrientation()); |
|
|
|
|
if (renderer != null) { |
|
|
|
|
popupWindow.setListCellRenderer(renderer); |
|
|
|
|
} |
|
|
|
|
if (preferredChoicesWindowSize != null) { |
|
|
|
|
popupWindow.setSize(preferredChoicesWindowSize); |
|
|
|
|
} |
|
|
|
|
if (preferredDescWindowSize != null) { |
|
|
|
|
popupWindow.setDescriptionWindowSize( |
|
|
|
|
preferredDescWindowSize); |
|
|
|
|
} |
|
|
|
|
return popupWindow; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Sets the delay between when the user types a character and when the |
|
|
|
@ -792,8 +782,7 @@ public class AutoCompletion {
|
|
|
|
|
if (textComponent != null) { |
|
|
|
|
if (autoActivationEnabled) { |
|
|
|
|
autoActivationListener.addTo(textComponent); |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
} else { |
|
|
|
|
autoActivationListener.removeFrom(textComponent); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -957,7 +946,7 @@ public class AutoCompletion {
|
|
|
|
|
* completion window. |
|
|
|
|
* |
|
|
|
|
* @param show Whether to show the description window. |
|
|
|
|
* @see #getShowDescWindow() |
|
|
|
|
* @see #isShowDescWindow() |
|
|
|
|
*/ |
|
|
|
|
public void setShowDescWindow(boolean show) { |
|
|
|
|
hidePopupWindow(); // Needed to force it to take effect
|
|
|
|
@ -1013,8 +1002,7 @@ public class AutoCompletion {
|
|
|
|
|
textComponent.replaceSelection(Character.toString(p.getParameterListStart())); |
|
|
|
|
TemplateCompletion tc = new TemplateCompletion(p, null, null, template); |
|
|
|
|
pc = tc; |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
} else { |
|
|
|
|
text = p.getParameterListStart() + text; |
|
|
|
|
textComponent.replaceSelection(text); |
|
|
|
|
return; |
|
|
|
@ -1131,8 +1119,7 @@ public class AutoCompletion {
|
|
|
|
|
public void caretUpdate(CaretEvent e) { |
|
|
|
|
if (justInserted) { |
|
|
|
|
justInserted = false; |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
} else { |
|
|
|
|
timer.stop(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1154,12 +1141,10 @@ public class AutoCompletion {
|
|
|
|
|
if (provider.isAutoActivateOkay(textComponent)) { |
|
|
|
|
timer.restart(); |
|
|
|
|
justInserted = true; |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
} else { |
|
|
|
|
timer.stop(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
} else { |
|
|
|
|
timer.stop(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1188,8 +1173,7 @@ public class AutoCompletion {
|
|
|
|
|
public void actionPerformed(ActionEvent e) { |
|
|
|
|
if (isAutoCompleteEnabled()) { |
|
|
|
|
refreshPopupWindow(); |
|
|
|
|
} |
|
|
|
|
else if (oldTriggerAction!=null) { |
|
|
|
|
} else if (oldTriggerAction != null) { |
|
|
|
|
oldTriggerAction.actionPerformed(e); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|