[autocomplete] 08/143: Adding parameter support when typing a function or method. Like Eclipse, arguments are pre-filled in and you can tab through them, and there is a tooltip listing the parameters to enter.
Benjamin Mesing
ben at alioth.debian.org
Sat Oct 19 12:53:08 UTC 2013
This is an automated email from the git hooks/post-receive script.
ben pushed a commit to branch master
in repository autocomplete.
commit aa4fa8ef4ea7391c9f68506d7140d1999eedd0a0
Author: bobbylight <robert at fifesoft.com>
Date: Fri Jan 9 23:41:35 2009 +0000
Adding parameter support when typing a function or method. Like Eclipse, arguments are pre-filled in and you can tab through them, and there is a tooltip listing the parameters to enter.
---
.../autocomplete/AbstractCompletionProvider.java | 46 ++
.../ui/autocomplete/AutoCompleteDescWindow.java | 2 +-
src/org/fife/ui/autocomplete/AutoCompletion.java | 81 +++
.../fife/ui/autocomplete/CCompletionProvider.java | 11 +
.../ui/autocomplete/CompletionCellRenderer.java | 7 +-
.../fife/ui/autocomplete/CompletionProvider.java | 47 ++
.../ui/autocomplete/DefaultCompletionProvider.java | 57 ++
.../fife/ui/autocomplete/FunctionCompletion.java | 136 ++--
.../ui/autocomplete/JarCompletionProvider.java | 8 +
.../fife/ui/autocomplete/MarkupTagCompletion.java | 2 +-
.../ui/autocomplete/OutlineHighlightPainter.java | 133 ++++
.../ui/autocomplete/ParameterizedCompletion.java | 92 +++
.../ParameterizedCompletionDescriptionToolTip.java | 721 ++++++++++++++++++++
13 files changed, 1253 insertions(+), 90 deletions(-)
diff --git a/src/org/fife/ui/autocomplete/AbstractCompletionProvider.java b/src/org/fife/ui/autocomplete/AbstractCompletionProvider.java
index 3d9f5fe..0e930ff 100644
--- a/src/org/fife/ui/autocomplete/AbstractCompletionProvider.java
+++ b/src/org/fife/ui/autocomplete/AbstractCompletionProvider.java
@@ -28,7 +28,11 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.swing.ListCellRenderer;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
import javax.swing.text.JTextComponent;
+import javax.swing.text.Segment;
/**
@@ -64,6 +68,21 @@ public abstract class AbstractCompletionProvider implements CompletionProvider {
*/
private Comparator comparator;
+ /**
+ * Text that marks the beginning of a parameter list, for example, "(".
+ */
+ private String paramListStart;
+
+ /**
+ * Text that marks the end of a parameter list, for example, ")".
+ */
+ private String paramListEnd;
+
+ /**
+ * Text that separates items in a parameter list, for example, ", ".
+ */
+ private String paramListSeparator;
+
protected static final String EMPTY_STRING = "";
@@ -72,6 +91,9 @@ public abstract class AbstractCompletionProvider implements CompletionProvider {
*/
public AbstractCompletionProvider() {
comparator = new CaseInsensitiveComparator();
+ paramListStart = "(";
+ paramListEnd = ")";
+ paramListSeparator = ", ";
}
@@ -228,6 +250,30 @@ public abstract class AbstractCompletionProvider implements CompletionProvider {
/**
* {@inheritDoc}
*/
+ public String getParameterListEnd() {
+ return paramListEnd;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getParameterListSeparator() {
+ return paramListSeparator;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getParameterListStart() {
+ return paramListStart;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
public CompletionProvider getParent() {
return parent;
}
diff --git a/src/org/fife/ui/autocomplete/AutoCompleteDescWindow.java b/src/org/fife/ui/autocomplete/AutoCompleteDescWindow.java
index 17bd894..2e30837 100644
--- a/src/org/fife/ui/autocomplete/AutoCompleteDescWindow.java
+++ b/src/org/fife/ui/autocomplete/AutoCompleteDescWindow.java
@@ -267,7 +267,7 @@ class AutoCompleteDescWindow extends JWindow implements HyperlinkListener {
* @param e The event.
*/
public void hyperlinkUpdate(HyperlinkEvent e) {
-System.out.println(descArea.isEnabled() + ", " + e);
+
HyperlinkEvent.EventType type = e.getEventType();
if (type.equals(HyperlinkEvent.EventType.ACTIVATED)) {
diff --git a/src/org/fife/ui/autocomplete/AutoCompletion.java b/src/org/fife/ui/autocomplete/AutoCompletion.java
index e2f3677..a7d7ac9 100644
--- a/src/org/fife/ui/autocomplete/AutoCompletion.java
+++ b/src/org/fife/ui/autocomplete/AutoCompletion.java
@@ -60,6 +60,11 @@ public class AutoCompletion implements HierarchyListener {
private AutoCompletePopupWindow popupWindow;
/**
+ * A "tooltip" describing a function just entered.
+ */
+ private ParameterizedCompletionDescriptionToolTip descToolTip;
+
+ /**
* Provides the completion options relevant to the current caret position.
*/
private CompletionProvider provider;
@@ -140,6 +145,47 @@ public class AutoCompletion implements HierarchyListener {
/**
+ * Displays a "tooltip" detailing the inputs to the function just entered.
+ *
+ * @param pc The completion.
+ * @param addParamListStart Whether or not
+ * {@link CompletionProvider#getParameterListStart()} should be
+ * added to the text component.
+ */
+ private void displayDescriptionToolTip(ParameterizedCompletion pc,
+ boolean addParamListStart) {
+
+ // Get rid of the previous tooltip window, if there is one.
+ hideToolTipWindow();
+
+ // Don't bother with a tooltip if there are no parameters.
+ if (pc.getParamCount()==0) {
+ CompletionProvider p = pc.getProvider();
+ textComponent.replaceSelection(p.getParameterListStart() +
+ p.getParameterListEnd());
+ return;
+ }
+
+ descToolTip = new ParameterizedCompletionDescriptionToolTip(
+ parentWindow, this, pc);
+ try {
+ int dot = textComponent.getCaretPosition();
+ Rectangle r = textComponent.modelToView(dot);
+ Point p = new Point(r.x, r.y);
+ SwingUtilities.convertPointToScreen(p, textComponent);
+ r.x = p.x;
+ r.y = p.y;
+ descToolTip.setLocationRelativeTo(r);
+ descToolTip.setVisible(true, addParamListStart);
+ } catch (BadLocationException ble) { // Should never happen
+ UIManager.getLookAndFeel().provideErrorFeedback(textComponent);
+ ble.printStackTrace();
+ }
+
+ }
+
+
+ /**
* Displays the popup window. Hosting applications can call this method
* to programmatically begin an auto-completion operation.
*/
@@ -306,6 +352,14 @@ public class AutoCompletion implements HierarchyListener {
}
+ private void hideToolTipWindow() {
+ if (descToolTip!=null) {
+ descToolTip.setVisible(false, false);
+ descToolTip = null;
+ }
+ }
+
+
/**
* Inserts a completion.
*
@@ -327,6 +381,11 @@ public class AutoCompletion implements HierarchyListener {
caret.setDot(start);
caret.moveDot(dot);
textComp.replaceSelection(replacement);
+
+ if (c instanceof ParameterizedCompletion) {
+ ParameterizedCompletion pc = (ParameterizedCompletion)c;
+ displayDescriptionToolTip(pc, true);
+ }
/*
Document doc = textComp.getDocument();
try {
@@ -359,6 +418,24 @@ try {
this.textComponent = c;
installTriggerKey(getTriggerKey());
+ InputMap im = c.getInputMap();
+ ActionMap am = c.getActionMap();
+ KeyStroke ks = KeyStroke.getKeyStroke('(');
+ Object oldParenKey = im.get(ks);
+ im.put(ks, "AutoCompletion.FunctionStart");
+ Action oldParenAction = am.get("AutoCompletion.FunctionStart");
+ am.put("AutoCompletion.FunctionStart", new javax.swing.AbstractAction() {
+ public void actionPerformed(java.awt.event.ActionEvent e) {
+ textComponent.replaceSelection("(");
+ List completions = provider.getParameterizedCompletionsAt(textComponent);
+ if (completions!=null && completions.size()>0) {
+ // TODO: Have tooltip let you select between multiple, like VS
+ ParameterizedCompletion pc = (ParameterizedCompletion)completions.get(0);
+ displayDescriptionToolTip(pc, false);
+ }
+ }
+ });
+
this.textComponent.addHierarchyListener(this);
hierarchyChanged(null); // In case textComponent is already in a window
@@ -662,14 +739,17 @@ try {
public void componentHidden(ComponentEvent e) {
hidePopupWindow();
+ hideToolTipWindow();
}
public void componentMoved(ComponentEvent e) {
hidePopupWindow();
+ hideToolTipWindow();
}
public void componentResized(ComponentEvent e) {
hidePopupWindow();
+ hideToolTipWindow();
}
public void removeFrom(Window w) {
@@ -682,6 +762,7 @@ try {
public void windowLostFocus(WindowEvent e) {
hidePopupWindow();
+ hideToolTipWindow();
}
}
diff --git a/src/org/fife/ui/autocomplete/CCompletionProvider.java b/src/org/fife/ui/autocomplete/CCompletionProvider.java
index 4fcea1a..258422e 100644
--- a/src/org/fife/ui/autocomplete/CCompletionProvider.java
+++ b/src/org/fife/ui/autocomplete/CCompletionProvider.java
@@ -147,6 +147,16 @@ public class CCompletionProvider extends AbstractCompletionProvider{
}
+ /**
+ * {@inheritDoc}
+ */
+ public List getParameterizedCompletionsAt(JTextComponent tc) {
+ CompletionProvider provider = getProviderFor(tc);
+ return provider!=null ? provider.getParameterizedCompletionsAt(tc) :
+ null;
+ }
+
+
private CompletionProvider getProviderFor(JTextComponent comp) {
RSyntaxTextArea rsta = (RSyntaxTextArea)comp;
@@ -201,6 +211,7 @@ public class CCompletionProvider extends AbstractCompletionProvider{
return getCommentCompletionProvider();
case Token.COMMENT_DOCUMENTATION:
return getDocCommentCompletionProvider();
+ case Token.NULL:
case Token.WHITESPACE:
case Token.IDENTIFIER:
case Token.VARIABLE:
diff --git a/src/org/fife/ui/autocomplete/CompletionCellRenderer.java b/src/org/fife/ui/autocomplete/CompletionCellRenderer.java
index 92401bf..6df1ad1 100644
--- a/src/org/fife/ui/autocomplete/CompletionCellRenderer.java
+++ b/src/org/fife/ui/autocomplete/CompletionCellRenderer.java
@@ -148,7 +148,7 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
sb.append(fc.getName());
sb.append("</em></b>");
- sb.append('(');
+ sb.append(fc.getProvider().getParameterListStart());
int paramCount = fc.getParamCount();
for (int i=0; i<paramCount; i++) {
FunctionCompletion.Parameter param = fc.getParam(i);
@@ -170,10 +170,11 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
sb.append(name);
}
if (i<paramCount-1) {
- sb.append(", ");
+ sb.append(fc.getProvider().getParameterListSeparator());
}
}
- sb.append(") : ");
+ sb.append(fc.getProvider().getParameterListEnd());
+ sb.append(" : ");
if (!selected) {
sb.append("<font color='#a0a0ff'>");
}
diff --git a/src/org/fife/ui/autocomplete/CompletionProvider.java b/src/org/fife/ui/autocomplete/CompletionProvider.java
index 26b86ea..f5ebcab 100644
--- a/src/org/fife/ui/autocomplete/CompletionProvider.java
+++ b/src/org/fife/ui/autocomplete/CompletionProvider.java
@@ -74,6 +74,53 @@ public interface CompletionProvider {
/**
+ * Returns a list of parameterized completions that have been entered
+ * at the current caret position of a text component (and thus can have
+ * their completion choices displayed).
+ *
+ * @param tc The text component.
+ * @return The list of {@link ParameterizedCompletion}s. If no completions
+ * are available, this may be <code>null</code>.
+ */
+ public List getParameterizedCompletionsAt(JTextComponent tc);
+
+
+ /**
+ * Returns the text that marks the end of a list of parameters to a
+ * function or method.
+ *
+ * @return The text for a parameter list end, for example,
+ * "<code>)</code>".
+ * @see #getParameterListStart()
+ * @see #getParameterListSeparator()
+ */
+ public String getParameterListEnd();
+
+
+ /**
+ * Returns the text that separates parameters to a function or method.
+ *
+ * @return The text that separates parameters, for example,
+ * "<code>, </code>".
+ * @see #getParameterListStart()
+ * @see #getParameterListEnd()
+ */
+ public String getParameterListSeparator();
+
+
+ /**
+ * Returns the text that marks the start of a list of parameters to a
+ * function or method.
+ *
+ * @return The text for a parameter list start, for example,
+ * "<code>(</code>".
+ * @see #getParameterListEnd()
+ * @see #getParameterListSeparator()
+ */
+ public String getParameterListStart();
+
+
+ /**
* Returns the parent completion provider.
*
* @return The parent completion provider.
diff --git a/src/org/fife/ui/autocomplete/DefaultCompletionProvider.java b/src/org/fife/ui/autocomplete/DefaultCompletionProvider.java
index 4a0dfc9..f1737ce 100644
--- a/src/org/fife/ui/autocomplete/DefaultCompletionProvider.java
+++ b/src/org/fife/ui/autocomplete/DefaultCompletionProvider.java
@@ -119,6 +119,63 @@ public class DefaultCompletionProvider extends AbstractCompletionProvider {
/**
+ * {@inheritDoc}
+ */
+ public List getParameterizedCompletionsAt(JTextComponent tc) {
+
+ List list = null;
+
+ String paramListStart = getParameterListStart();
+ if (paramListStart==null) {
+ return list; // null
+ }
+
+ int dot = tc.getCaretPosition();
+ Segment s = new Segment();
+ Document doc = tc.getDocument();
+ Element root = doc.getDefaultRootElement();
+ int line = root.getElementIndex(dot);
+ Element elem = root.getElement(line);
+ int offs = elem.getStartOffset();
+ int len = dot - offs - paramListStart.length();
+ if (len<=0) { // Not enough chars on line for a method.
+ return list; // null
+ }
+
+ try {
+
+ doc.getText(offs, len, s);
+ offs = s.offset + len - 1;
+ while (offs>=s.offset && Character.isWhitespace(s.array[offs])) {
+ offs--;
+ }
+ int end = offs;
+ while (offs>=s.offset && isValidChar(s.array[offs])) {
+ System.out.println("... Examining '" + s.array[offs] + "'");
+ offs--;
+ }
+
+ String text = new String(s.array, offs+1, end-offs);
+ System.out.println("... ... \"" + text + "\"");
+
+ Completion c = getCompletionByInputText(text);
+ if (c instanceof ParameterizedCompletion) {
+ if (list==null) {
+ list = new ArrayList(1);
+ }
+ list.add(c);
+ }
+
+ } catch (BadLocationException ble) {
+ ble.printStackTrace(); // Never happens
+ }
+
+ return list;
+
+ }
+
+
+ /**
* Initializes this completion provider.
*/
protected void init() {
diff --git a/src/org/fife/ui/autocomplete/FunctionCompletion.java b/src/org/fife/ui/autocomplete/FunctionCompletion.java
index ff5c05d..31ccfaf 100644
--- a/src/org/fife/ui/autocomplete/FunctionCompletion.java
+++ b/src/org/fife/ui/autocomplete/FunctionCompletion.java
@@ -32,7 +32,8 @@ import java.util.List;
* @author Robert Futrell
* @version 1.0
*/
-public class FunctionCompletion extends VariableCompletion {
+public class FunctionCompletion extends VariableCompletion
+ implements ParameterizedCompletion {
/**
* Parameters to the function.
@@ -54,42 +55,9 @@ public class FunctionCompletion extends VariableCompletion {
protected void addDefinitionString(StringBuffer sb) {
-
sb.append("<html><b>");
-
- // Add the return type if applicable (C macros like NULL have no type).
- String type = getType();
- if (type!=null) {
- appendPossibleDataType(sb, type);
- sb.append(' ');
- }
-
- // Add the item being described's name.
- sb.append(getName());
-
- // Add parameters for functions.
- sb.append('(');
- for (int i=0; i<getParamCount(); i++) {
- Parameter param = getParam(i);
- type = param.getType();
- String name = param.getName();
- if (type!=null) {
- appendPossibleDataType(sb, type);
- if (name!=null) {
- sb.append(' ');
- }
- }
- if (name!=null) {
- sb.append(name);
- }
- if (i<params.size()-1) {
- sb.append(", ");
- }
- }
- sb.append(')');
-
+ sb.append(getDefinitionString());
sb.append("</b>");
-
}
@@ -123,6 +91,54 @@ public class FunctionCompletion extends VariableCompletion {
/**
+ * Returns the "definition string" for this function completion. For
+ * example, for the C "<code>printf</code>" function, this would return
+ * "<code>int printf(const char *, ...)</code>".
+ *
+ * @return The definition string.
+ */
+ public String getDefinitionString() {
+
+ StringBuffer sb = new StringBuffer();
+
+ // Add the return type if applicable (C macros like NULL have no type).
+ String type = getType();
+ if (type!=null) {
+ appendPossibleDataType(sb, type);
+ sb.append(' ');
+ }
+
+ // Add the item being described's name.
+ sb.append(getName());
+
+ // Add parameters for functions.
+ CompletionProvider provider = getProvider();
+ sb.append(provider.getParameterListStart());
+ for (int i=0; i<getParamCount(); i++) {
+ Parameter param = getParam(i);
+ type = param.getType();
+ String name = param.getName();
+ if (type!=null) {
+ appendPossibleDataType(sb, type);
+ if (name!=null) {
+ sb.append(' ');
+ }
+ }
+ if (name!=null) {
+ sb.append(name);
+ }
+ if (i<params.size()-1) {
+ sb.append(provider.getParameterListSeparator());
+ }
+ }
+ sb.append(provider.getParameterListEnd());
+
+ return sb.toString();
+
+ }
+
+
+ /**
* Returns the specified {@link Parameter}.
*
* @param index The index of the parameter to retrieve.
@@ -172,54 +188,4 @@ public class FunctionCompletion extends VariableCompletion {
}
- /**
- * A parameter passed to a function.
- *
- * @author Robert Futrell
- * @version 1.0
- */
- public static class Parameter {
-
- private String name;
- private String type;
- private String desc;
-
- public Parameter(String type, String name) {
- this.name = name;
- this.type = type;
- }
-
- public String getDescription() {
- return desc;
- }
-
- public String getName() {
- return name;
- }
-
- public String getType() {
- return type;
- }
-
- public void setDescription(String desc) {
- this.desc = desc;
- }
-
- public String toString() {
- StringBuffer sb = new StringBuffer();
- if (type!=null) {
- sb.append(type);
- }
- if (name!=null) {
- if (type!=null) {
- sb.append(' ');
- sb.append(name);
- }
- }
- return sb.toString();
- }
-
- }
-
-
}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/JarCompletionProvider.java b/src/org/fife/ui/autocomplete/JarCompletionProvider.java
index 92a6dfd..b6a0839 100644
--- a/src/org/fife/ui/autocomplete/JarCompletionProvider.java
+++ b/src/org/fife/ui/autocomplete/JarCompletionProvider.java
@@ -149,6 +149,14 @@ public class JarCompletionProvider extends AbstractCompletionProvider {
/**
+ * {@inheritDoc}
+ */
+ public List getParameterizedCompletionsAt(JTextComponent tc) {
+ return null; // This provider knows no functions or methods.
+ }
+
+
+ /**
* Returns whether the specified character is valid in an auto-completion.
*
* @param ch The character.
diff --git a/src/org/fife/ui/autocomplete/MarkupTagCompletion.java b/src/org/fife/ui/autocomplete/MarkupTagCompletion.java
index c9ad95b..113c970 100644
--- a/src/org/fife/ui/autocomplete/MarkupTagCompletion.java
+++ b/src/org/fife/ui/autocomplete/MarkupTagCompletion.java
@@ -26,7 +26,7 @@ package org.fife.ui.autocomplete;
import java.util.ArrayList;
import java.util.List;
-import org.fife.ui.autocomplete.FunctionCompletion.Parameter;
+import org.fife.ui.autocomplete.ParameterizedCompletion.Parameter;
/**
diff --git a/src/org/fife/ui/autocomplete/OutlineHighlightPainter.java b/src/org/fife/ui/autocomplete/OutlineHighlightPainter.java
new file mode 100644
index 0000000..1e3b3ee
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/OutlineHighlightPainter.java
@@ -0,0 +1,133 @@
+package org.fife.ui.autocomplete;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.io.Serializable;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.DefaultHighlighter;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.Position;
+import javax.swing.text.View;
+
+
+/**
+ * Highlight painter that draws an outline around the text. This is used to
+ * draw bounds around function/method parameters.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+/*
+ * NOTE: Whenever you see text like "Workaround for Java Highlight issues",
+ * this is because highlighted text in a JTextComponent gets "pushed" forward
+ * when the caret is at the Highlight's start, when we need it to instead get
+ * prepended to. For this reason, the autocomplete package adds its Highlights
+ * 1 char too long (1 char earlier than where it should really start), but only
+ * paint the Highlight from the 2nd char on.
+ */
+class OutlineHighlightPainter extends
+ DefaultHighlighter.DefaultHighlightPainter implements Serializable {
+
+ /**
+ * DefaultHighlightPainter doesn't allow changing color, so we must cache
+ * ours here.
+ */
+ private Color color;
+
+
+ /**
+ * Constructor.
+ *
+ * @param color The color to draw the bounding boxes with. This cannot
+ * be <code>null</code>.
+ */
+ public OutlineHighlightPainter(Color color) {
+ super(color);
+ setColor(color);
+ }
+
+
+ /**
+ * Returns the color to paint bounding boxes with.
+ *
+ * @return The color.
+ * @see #setColor(Color)
+ */
+ public Color getColor() {
+ return color;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Shape paintLayer(Graphics g, int p0, int p1, Shape viewBounds,
+ JTextComponent c, View view) {
+
+ g.setColor(getColor());
+ p0++; // Workaround for Java Highlight issues.
+
+ // This special case isn't needed for most standard Swing Views (which
+ // always return a width of 1 for modelToView() calls), but it is
+ // needed for RSTA views, which actually return the width of chars for
+ // modelToView calls. But this should be faster anyway, as we
+ // short-circuit and do only one modelToView() for one offset.
+ if (p0==p1) {
+ try {
+ Shape s = view.modelToView(p0, viewBounds,
+ Position.Bias.Forward);
+ Rectangle r = s.getBounds();
+ g.drawLine(r.x, r.y, r.x, r.y+r.height);
+ return r;
+ } catch (BadLocationException ble) {
+ ble.printStackTrace(); // Never happens
+ return null;
+ }
+ }
+
+ if (p0 == view.getStartOffset() && p1 == view.getEndOffset()) {
+ // Contained in view, can just use bounds.
+ Rectangle alloc;
+ if (viewBounds instanceof Rectangle) {
+ alloc = (Rectangle) viewBounds;
+ } else {
+ alloc = viewBounds.getBounds();
+ }
+ g.drawRect(alloc.x, alloc.y, alloc.width - 1, alloc.height - 1);
+ return alloc;
+ }
+
+ // Should only render part of View.
+ try {
+ // --- determine locations ---
+ Shape shape = view.modelToView(p0, Position.Bias.Forward, p1,
+ Position.Bias.Backward, viewBounds);
+ Rectangle r = (shape instanceof Rectangle) ? (Rectangle) shape
+ : shape.getBounds();
+ g.drawRect(r.x, r.y, r.width - 1, r.height - 1);
+ return r;
+ } catch (BadLocationException e) { // Never happens
+ e.printStackTrace();
+ return null;
+ }
+
+ }
+
+
+ /**
+ * Sets the color to paint the bounding boxes with.
+ *
+ * @param color The new color. This cannot be <code>null</code>.
+ * @see #getColor()
+ */
+ public void setColor(Color color) {
+ if (color==null) {
+ throw new IllegalArgumentException("color cannot be null");
+ }
+ this.color = color;
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/ParameterizedCompletion.java b/src/org/fife/ui/autocomplete/ParameterizedCompletion.java
new file mode 100644
index 0000000..30ee1f2
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/ParameterizedCompletion.java
@@ -0,0 +1,92 @@
+package org.fife.ui.autocomplete;
+
+
+/**
+ * A completion option that takes parameters, such as a function or method.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+public interface ParameterizedCompletion extends Completion {
+
+
+ /**
+ * Returns the "definition string" for this completion. For examle,
+ * for the C "<code>printf</code>" function, this would return
+ * "<code>int printf(const char *, ...)</code>".
+ *
+ * @return The definition string.
+ */
+ public String getDefinitionString();
+
+
+ /**
+ * Returns the specified {@link Parameter}.
+ *
+ * @param index The index of the parameter to retrieve.
+ * @return The parameter.
+ * @see #getParamCount()
+ */
+ public Parameter getParam(int index);
+
+
+ /**
+ * Returns the number of parameters this completion takes.
+ *
+ * @return The number of parameters this completion takes.
+ * @see #getParam(int)
+ */
+ public int getParamCount();
+
+
+ /**
+ * A parameter passed to a parameterized {@link Completion}.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+ public static class Parameter {
+
+ private String name;
+ private String type;
+ private String desc;
+
+ public Parameter(String type, String name) {
+ this.name = name;
+ this.type = type;
+ }
+
+ public String getDescription() {
+ return desc;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setDescription(String desc) {
+ this.desc = desc;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ if (type!=null) {
+ sb.append(type);
+ }
+ if (name!=null) {
+ if (type!=null) {
+ sb.append(' ');
+ }
+ sb.append(name);
+ }
+ return sb.toString();
+ }
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/ParameterizedCompletionDescriptionToolTip.java b/src/org/fife/ui/autocomplete/ParameterizedCompletionDescriptionToolTip.java
new file mode 100644
index 0000000..9a43069
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/ParameterizedCompletionDescriptionToolTip.java
@@ -0,0 +1,721 @@
+/*
+ * 12/21/2008
+ *
+ * AutoCompleteDescWindow.java - A window containing a description of the
+ * currently selected completion.
+ * Copyright (C) 2008 Robert Futrell
+ * robert_futrell at users.sourceforge.net
+ * http://fifesoft.com/rsyntaxtextarea
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+package org.fife.ui.autocomplete;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.SystemColor;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
+import javax.swing.BorderFactory;
+import javax.swing.InputMap;
+import javax.swing.JLabel;
+import javax.swing.JWindow;
+import javax.swing.KeyStroke;
+import javax.swing.UIManager;
+import javax.swing.event.CaretEvent;
+import javax.swing.event.CaretListener;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Highlighter;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.Position;
+import javax.swing.text.Highlighter.Highlight;
+
+
+/**
+ * A "tooltip" that displays information on the function or method currently
+ * being entered.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+class ParameterizedCompletionDescriptionToolTip {
+
+ /**
+ * The actual tooltip.
+ */
+ private JWindow tooltip;
+
+ /**
+ * The painter to paint borders around the variables.
+ */
+ Highlighter.HighlightPainter p;
+
+ /**
+ * The tags for the highlights around parameters.
+ */
+ List tags;
+
+ /**
+ * The parent AutoCompletion instance.
+ */
+ private AutoCompletion ac;
+
+ /**
+ * The label that holds the description.
+ */
+ private JLabel descLabel;
+
+ /**
+ * The completion being described.
+ */
+ private ParameterizedCompletion pc;
+
+ /**
+ * Listens for events in the text component while this window is vislble.
+ */
+ private Listener listener;
+
+ /**
+ * The minimum offset into the document that the caret can move to
+ * before this tooltip disappears.
+ */
+ private int minPos;
+
+ /**
+ * The maximum offset into the document that the caret can move to
+ * before this tooltip disappears.
+ */
+ private Position maxPos; // Moves with text inserted.
+
+ /**
+ * The currently "selected" parameter in the displayed text.
+ */
+ private int lastSelectedParam;
+
+ private Object oldTabKey;
+ private Action oldTabAction;
+ private Object oldShiftTabKey;
+ private Action oldShiftTabAction;
+ private Object oldEscapeKey;
+ private Action oldEscapeAction;
+ private Object oldClosingKey;
+ private Action oldClosingAction;
+
+ private static final String IM_KEY_TAB = "ParamCompDescToolTip.Tab";
+ private static final String IM_KEY_SHIFT_TAB = "ParamCompDescToolTip.ShiftTab";
+ private static final String IM_KEY_ESCAPE = "ParamCompDescToolTip.Escape";
+ private static final String IM_KEY_CLOSING = "ParamCompDescToolTip.Closing";
+
+
+ /**
+ * Constructor.
+ *
+ * @param owner The parent window.
+ * @param ac The parent autocompletion.
+ * @param pc The completion being described.
+ */
+ public ParameterizedCompletionDescriptionToolTip(Window owner,
+ AutoCompletion ac, ParameterizedCompletion pc) {
+
+ tooltip = new JWindow(owner);
+ this.ac = ac;
+ this.pc = pc;
+
+ descLabel = new JLabel();
+ descLabel.setOpaque(true);
+ descLabel.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createLineBorder(Color.BLACK),
+ BorderFactory.createEmptyBorder(2, 5, 2, 5)));
+ descLabel.setBackground(getDefaultBackground());
+ tooltip.setContentPane(descLabel);
+
+ lastSelectedParam = -1;
+ updateText(0);
+
+ tooltip.setFocusableWindowState(false);
+ listener = new Listener();
+
+ p = new OutlineHighlightPainter(Color.GRAY);
+ tags = new ArrayList(1); // Usually small
+
+ }
+
+
+ /**
+ * Returns the default background color to use for the description
+ * window.
+ *
+ * @return The default background color.
+ */
+ protected Color getDefaultBackground() {
+ Color c = UIManager.getColor("ToolTip.background");
+ if (c==null) { // Some LookAndFeels like Nimbus
+ c = UIManager.getColor("info"); // Used by Nimbus (and others)
+ if (c==null) {
+ c = SystemColor.infoText; // System default
+ }
+ }
+ return c;
+ }
+
+
+ private List getParameterHighlights() {
+ List paramHighlights = new ArrayList(1);
+ JTextComponent tc = ac.getTextComponent();
+ Highlight[] highlights = tc.getHighlighter().getHighlights();
+ for (int i=0; i<highlights.length; i++) {
+ if (highlights[i].getPainter()==p) {
+ paramHighlights.add(highlights[i]);
+ }
+ }
+ return paramHighlights;
+ }
+
+
+ /**
+ * Installs key bindings on the text component that facilitate the user
+ * editing this completion's parameters.
+ *
+ * @see #uninstallKeyBindings()
+ */
+ private void installKeyBindings() {
+
+ JTextComponent tc = ac.getTextComponent();
+ InputMap im = tc.getInputMap();
+ ActionMap am = tc.getActionMap();
+
+ KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
+ oldTabKey = im.get(ks);
+ im.put(ks, IM_KEY_TAB);
+ oldTabAction = am.get(IM_KEY_TAB);
+ am.put(IM_KEY_TAB, new NextParamAction());
+
+ ks = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK);
+ oldShiftTabKey = im.get(ks);
+ im.put(ks, IM_KEY_SHIFT_TAB);
+ oldShiftTabAction = am.get(IM_KEY_SHIFT_TAB);
+ am.put(IM_KEY_SHIFT_TAB, new PrevParamAction());
+
+ ks = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
+ oldEscapeKey = im.get(ks);
+ im.put(ks, IM_KEY_ESCAPE);
+ oldEscapeAction = am.get(IM_KEY_ESCAPE);
+ am.put(IM_KEY_ESCAPE, new HideAction());
+
+ String end = pc.getProvider().getParameterListEnd();
+ if (end.length()==1) { // Practically always true, usually ')'
+ char ch = end.charAt(0);
+ ks = KeyStroke.getKeyStroke(ch);
+ oldClosingKey = im.get(ks);
+ im.put(ks, IM_KEY_CLOSING);
+ oldClosingAction = am.get(IM_KEY_CLOSING);
+ am.put(IM_KEY_CLOSING, new ClosingAction());
+ }
+ }
+
+
+ /**
+ * Moves to and selects the next parameter.
+ *
+ * @see #moveToPreviousParam()
+ */
+ private void moveToNextParam() {
+
+ JTextComponent tc = ac.getTextComponent();
+ int dot = tc.getCaretPosition();
+
+ int tagCount = tags.size();
+ if (tagCount==0) {
+ tc.setCaretPosition(maxPos.getOffset());
+ tooltip.setVisible(false);
+ }
+
+ Highlight currentNext = null;
+ int pos = -1;
+ List highlights = getParameterHighlights();
+ for (int i=0; i<highlights.size(); i++) {
+ Highlight hl = (Highlight)highlights.get(i);
+ if (currentNext==null || currentNext.getStartOffset()<=dot ||
+ (hl.getStartOffset()>dot &&
+ hl.getStartOffset()<=currentNext.getStartOffset())) {
+ currentNext = hl;
+ pos = i;
+ }
+ }
+
+ if (currentNext!=null && dot<currentNext.getStartOffset()) {
+ // "+1" is a workaround for Java Highlight issues.
+ tc.setSelectionStart(currentNext.getStartOffset()+1);
+ tc.setSelectionEnd(currentNext.getEndOffset());
+ updateText(pos);
+ }
+ else {
+ tc.setCaretPosition(maxPos.getOffset());
+ tooltip.setVisible(false);
+ }
+
+ }
+
+
+ /**
+ * Moves to and selects the previous parameter.
+ *
+ * @see #moveToNextParam()
+ */
+ private void moveToPreviousParam() {
+
+ JTextComponent tc = ac.getTextComponent();
+
+ int tagCount = tags.size();
+ if (tagCount==0) { // Should never happen
+ tc.setCaretPosition(maxPos.getOffset());
+ tooltip.setVisible(false);
+ }
+
+ int dot = tc.getCaretPosition();
+ int selStart = tc.getSelectionStart()-1; // Workaround for Java Highlight issues.
+ Highlight currentPrev = null;
+ int pos = 0;
+ Highlighter h = tc.getHighlighter();
+ Highlight[] highlights = h.getHighlights();
+ for (int i=0; i<highlights.length; i++) {
+ Highlight hl = highlights[i];
+ if (hl.getPainter()==p) { // Only way to identify our own higlights
+ if (currentPrev==null || currentPrev.getStartOffset()>=dot ||
+ (hl.getStartOffset()<selStart &&
+ hl.getStartOffset()>currentPrev.getStartOffset())) {
+ currentPrev = hl;
+ pos = i;
+ }
+ }
+ }
+
+ if (currentPrev!=null && dot>currentPrev.getStartOffset()) {
+ // "+1" is a workaround for Java Highlight issues.
+ tc.setSelectionStart(currentPrev.getStartOffset()+1);
+ tc.setSelectionEnd(currentPrev.getEndOffset());
+ updateText(pos);
+ }
+ else {
+ tc.setCaretPosition(maxPos.getOffset());
+ tooltip.setVisible(false);
+ }
+
+ }
+
+
+ /**
+ * Removes the bounding boxes around parameters.
+ */
+ private void removeParameterHighlights() {
+ JTextComponent tc = ac.getTextComponent();
+ Highlighter h = tc.getHighlighter();
+ for (int i=0; i<tags.size(); i++) {
+ h.removeHighlight(tags.get(i));
+ }
+ tags.clear();
+ }
+
+
+ /**
+ * Sets the location of this tooltip relative to the given rectangle.
+ *
+ * @param r The visual position of the caret (in screen coordinates).
+ */
+ public void setLocationRelativeTo(Rectangle r) {
+
+ Dimension screenSize = tooltip.getToolkit().getScreenSize();
+
+ // Try putting our stuff "above" the caret first.
+ int y = r.y - 5 - tooltip.getHeight();
+ if (y<0) {
+ y = r.y + r.height + 5;
+ }
+
+ // Get x-coordinate of completions. Try to align left edge with the
+ // caret first.
+ int x = r.x;
+ if (x<0) {
+ x = 0;
+ }
+ else if (x+tooltip.getWidth()>screenSize.width) { // completions don't fit
+ x = screenSize.width - tooltip.getWidth();
+ }
+
+ tooltip.setLocation(x, y);
+
+ }
+
+
+ /**
+ * Toggles the visibility of this tooltip.
+ *
+ * @param visible Whether the tooltip should be visible.
+ * @param addParamListStart Whether or not
+ * {@link CompletionProvider#getParameterListStart()} should be
+ * added to the text component. If <code>visible</code> is
+ * <code>false</code>, this parameter is ignored.
+ */
+ public void setVisible(boolean visible, boolean addParamListStart) {
+ if (visible!=tooltip.isVisible()) {
+ JTextComponent tc = ac.getTextComponent();
+ if (visible) {
+ listener.install(tc, addParamListStart);
+ }
+ else {
+ listener.uninstall();
+ }
+ tooltip.setVisible(visible);
+ }
+ }
+
+
+ /**
+ * Removes the key bindings we installed.
+ *
+ * @see #installKeyBindings()
+ */
+ private void uninstallKeyBindings() {
+
+ JTextComponent tc = ac.getTextComponent();
+ InputMap im = tc.getInputMap();
+ ActionMap am = tc.getActionMap();
+
+ KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
+ im.put(ks, oldTabKey);
+ am.put(IM_KEY_TAB, oldTabAction);
+
+ ks = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK);
+ im.put(ks, oldShiftTabKey);
+ am.put(IM_KEY_SHIFT_TAB, oldShiftTabAction);
+
+ ks = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
+ im.put(ks, oldEscapeKey);
+ am.put(IM_KEY_ESCAPE, oldEscapeAction);
+
+ String end = pc.getProvider().getParameterListEnd();
+ if (end.length()==1) { // Practically always true, usually ')'
+ char ch = end.charAt(0);
+ ks = KeyStroke.getKeyStroke(ch);
+ im.put(ks, oldClosingKey);
+ am.put(IM_KEY_CLOSING, oldClosingAction);
+ }
+
+ }
+
+
+ /**
+ * Updates the text in the tooltip to have the current parameter
+ * disiplayed in bold. The "current parameter" is determined from the
+ * current caret position.
+ */
+ private void updateText() {
+
+ JTextComponent tc = ac.getTextComponent();
+ int dot = tc.getCaretPosition();
+ if (dot>0) {
+ dot--; // Workaround for Java Highlight issues
+ }
+ int index = -1;
+
+ List paramHighlights = getParameterHighlights();
+ for (int i=0; i<paramHighlights.size(); i++) {
+ Highlight h = (Highlight)paramHighlights.get(i);
+ if (dot>=h.getStartOffset() && dot<h.getEndOffset()) {
+ index = i;
+ break;
+ }
+ }
+
+ updateText(index);
+
+ }
+
+
+ /**
+ * Updates the text in the tooltip to have the current parameter
+ * displayed in bold.
+ *
+ * @param selectedParam The index of the selected parameter.
+ */
+ private void updateText(int selectedParam) {
+
+ // Don't redo everything if they're just using the arrow keys to move
+ // through each char of a single parameter, for example.
+ if (selectedParam==lastSelectedParam) {
+ return;
+ }
+ lastSelectedParam = selectedParam;
+
+ StringBuffer sb = new StringBuffer("<html>");
+ int paramCount = pc.getParamCount();
+ for (int i=0; i<paramCount; i++) {
+ if (i==selectedParam) {
+ sb.append("<b>");
+ }
+ sb.append(pc.getParam(i).toString());
+ if (i==selectedParam) {
+ sb.append("</b>");
+ }
+ if (i<paramCount-1) {
+ sb.append(pc.getProvider().getParameterListSeparator());
+ }
+ }
+
+ descLabel.setText(sb.toString());
+ tooltip.pack();
+
+ }
+
+
+ /**
+ * Called when the user types the character marking the closing of the
+ * parameter list, such as '<code>)</code>'.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+ private class ClosingAction extends AbstractAction {
+
+ public void actionPerformed(ActionEvent e) {
+ JTextComponent tc = ac.getTextComponent();
+ tc.setCaretPosition(maxPos.getOffset());
+ tooltip.setVisible(false);
+ }
+
+ }
+
+
+ /**
+ * Action performed when the user hits the escape key.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+ private class HideAction extends AbstractAction {
+
+ public void actionPerformed(ActionEvent e) {
+ tooltip.setVisible(false);
+ }
+
+ }
+
+
+ /**
+ * Listens for various events in the text component while this tooltip
+ * is visible.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+ private class Listener implements FocusListener, CaretListener {
+
+ /**
+ * Called when the text component's caret moves.
+ *
+ * @param e The event.
+ */
+ public void caretUpdate(CaretEvent e) {
+ if (maxPos==null) { // Sanity check
+ tooltip.setVisible(false);
+ }
+ int dot = e.getDot();
+ if (dot<minPos || dot>maxPos.getOffset()) {
+ tooltip.setVisible(false);
+ }
+ updateText();
+ }
+
+
+ /**
+ * Called when the text component gains focus.
+ *
+ * @param e The event.
+ */
+ public void focusGained(FocusEvent e) {
+ // Do nothing
+ }
+
+
+ /**
+ * Called when the text component loses focus.
+ *
+ * @param e The event.
+ */
+ public void focusLost(FocusEvent e) {
+ tooltip.setVisible(false);
+ }
+
+
+ /**
+ * Returns the text to insert for a parameter.
+ *
+ * @param param The parameter.
+ * @return The text.
+ */
+ private String getParamText(ParameterizedCompletion.Parameter param) {
+ String text = param.getName();
+ if (text==null) {
+ text = param.getType();
+ if (text==null) { // Shouldn't ever happen
+ text = "arg";
+ }
+ }
+ return text;
+ }
+
+
+ /**
+ * Installs this listener onto a text component.
+ *
+ * @param tc The text component to install onto.
+ * @param addParamListStart Whether or not
+ * {@link CompletionProvider#getParameterListStart()} should be
+ * added to the text component.
+ * @see #uninstall()
+ */
+ public void install(JTextComponent tc, boolean addParamStartList) {
+
+ // Add listeners to the text component.
+ tc.addCaretListener(this);
+ tc.addFocusListener(this);
+ installKeyBindings();
+
+ StringBuffer sb = new StringBuffer();
+ if (addParamStartList) {
+ sb.append(pc.getProvider().getParameterListStart());
+ }
+ int dot = tc.getCaretPosition() + sb.length();
+ int paramCount = pc.getParamCount();
+ List paramLocs = null;
+ if (paramCount>0) {
+ paramLocs = new ArrayList(paramCount);
+ }
+ Highlighter h = tc.getHighlighter();
+
+ try {
+
+ // Get the range in which the caret can move before we hide
+ // this tooltip.
+ minPos = dot;
+ maxPos = tc.getDocument().createPosition(dot-sb.length());
+ int firstParamLen = 0;
+
+ // Create the text to insert (keep it one completion for
+ // performance and simplicity of undo/redo).
+ int start = dot;
+ for (int i=0; i<paramCount; i++) {
+ FunctionCompletion.Parameter param = pc.getParam(i);
+ String paramText = getParamText(param);
+ if (i==0) {
+ firstParamLen = paramText.length();
+ }
+ sb.append(paramText);
+ int end = start + paramText.length();
+ paramLocs.add(new Point(start, end));
+ if (i<paramCount-1) {
+ sb.append(pc.getProvider().getParameterListSeparator());
+ start = end + 2;
+ }
+ }
+ sb.append(pc.getProvider().getParameterListEnd());
+
+ // Insert the parameter text and add highlights around the
+ // parameters.
+ tc.replaceSelection(sb.toString());
+ for (int i=0; i<paramCount; i++) {
+ Point pt = (Point)paramLocs.get(i);
+ // "-1" is a workaround for Java Highlight issues.
+ tags.add(h.addHighlight(pt.x-1, pt.y, p));
+ }
+
+ // Go back and start at the first parameter.
+ tc.setCaretPosition(dot);
+ if (pc.getParamCount()>0) {
+ tc.moveCaretPosition(dot+firstParamLen);
+ }
+
+ } catch (BadLocationException ble) {
+ ble.printStackTrace(); // Never happens
+ }
+
+ }
+
+
+ /**
+ * Uninstalls this listener from the current text component.
+ *
+ */
+ public void uninstall() {
+
+ JTextComponent tc = ac.getTextComponent();
+ tc.removeCaretListener(this);
+ tc.removeFocusListener(this);
+ uninstallKeyBindings();
+
+ // Remove WeakReferences in javax.swing.text.
+ maxPos = null;
+ minPos = -1;
+ removeParameterHighlights();
+
+ }
+
+
+ }
+
+
+ /**
+ * Action performed when the user hits the tab key.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+ private class NextParamAction extends AbstractAction {
+
+ public void actionPerformed(ActionEvent e) {
+ moveToNextParam();
+ }
+
+ }
+
+
+ /**
+ * Action performed when the user hits shift+tab.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+ private class PrevParamAction extends AbstractAction {
+
+ public void actionPerformed(ActionEvent e) {
+ moveToPreviousParam();
+ }
+
+ }
+
+
+}
\ No newline at end of file
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/autocomplete.git
More information about the pkg-java-commits
mailing list