[autocomplete] 02/143: Initial population of AutoComplete and AutoCompleteDemo.
Benjamin Mesing
ben at alioth.debian.org
Sat Oct 19 12:53:06 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 85879faef43afdae839eeea0580108503989cb9a
Author: bobbylight <robert at fifesoft.com>
Date: Wed Dec 24 20:11:47 2008 +0000
Initial population of AutoComplete and AutoCompleteDemo.
---
.classpath | 8 +
.project | 17 +
build.xml | 94 +++
.../autocomplete/AutoCompleteDescWindow.properties | 1 +
img/localVar.png | Bin 0 -> 1026 bytes
img/method.png | Bin 0 -> 1024 bytes
.../fife/ui/autocomplete/AbstractCompletion.java | 111 ++++
.../autocomplete/AbstractCompletionProvider.java | 291 +++++++++
.../ui/autocomplete/AutoCompleteDescWindow.java | 450 ++++++++++++++
.../ui/autocomplete/AutoCompletePopupWindow.java | 617 ++++++++++++++++++++
src/org/fife/ui/autocomplete/AutoCompletion.java | 574 ++++++++++++++++++
src/org/fife/ui/autocomplete/Completion.java | 95 +++
.../fife/ui/autocomplete/CompletionListModel.java | 99 ++++
.../fife/ui/autocomplete/CompletionProvider.java | 104 ++++
.../ui/autocomplete/DelegatingCellRenderer.java | 60 ++
.../fife/ui/autocomplete/ExternalURLHandler.java | 51 ++
.../fife/ui/autocomplete/FunctionCompletion.java | 213 +++++++
.../ProceduralLanguageCellRenderer.java | 193 ++++++
.../ProceduralLanguageCompletionProvider.java | 347 +++++++++++
.../fife/ui/autocomplete/ShorthandCompletion.java | 81 +++
src/org/fife/ui/autocomplete/SizeGrip.java | 193 ++++++
src/org/fife/ui/autocomplete/Util.java | 153 +++++
.../fife/ui/autocomplete/VariableCompletion.java | 193 ++++++
src/org/fife/ui/autocomplete/WordCompletion.java | 73 +++
.../ui/autocomplete/WordCompletionProvider.java | 130 +++++
src/org/fife/ui/autocomplete/arrow_left.png | Bin 0 -> 345 bytes
src/org/fife/ui/autocomplete/arrow_right.png | Bin 0 -> 349 bytes
27 files changed, 4148 insertions(+)
diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..fe5be44
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="i18n"/>
+ <classpathentry kind="src" path="img"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/.project b/.project
new file mode 100644
index 0000000..f69cc1c
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>AutoComplete</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..211d6b9
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+
+<!--
+
+ This is the Ant build script for autocomplete.jar.
+ Available targets include:
+
+ 1. compile: Compiles all org.fife classes into ${class-dir}.
+ 2. make-jar: Creates the jar file.
+ 3. make-source-zip: Creates a source zip file.
+ 3. make-javadoc: Creates the javadoc for RSyntaxTextArea.
+
+ Author: Robert Futrell
+ Version: 0.1
+ Date: 12dec2008
+
+-->
+
+
+<project name="AutoComplete" default="make-jar" basedir=".">
+
+ <description>AutoComplete build file</description>
+
+
+ <!-- Set global properties for this build. -->
+ <property name="version" value="0.1"/>
+ <property name="source-dir" location="src"/>
+ <property name="class-dir" location="ant-classes"/>
+ <property name="dist-dir" location="dist"/>
+ <property name="doc-dir" location="javadoc"/>
+ <property name="debug" value="true"/>
+ <property name="debuglevel" value="lines,var,source"/>
+ <property name="java-level" value="1.4"/>
+
+
+ <!-- Compiles the classes. -->
+ <target name="compile" description="Compile the source">
+ <delete includeEmptyDirs="true" quiet="true" dir="${class-dir}"/>
+ <mkdir dir="${class-dir}"/>
+ <javac srcdir="${source-dir}" destdir="${class-dir}"
+ classpath="../RSyntaxTextArea/dist/rsyntaxtextarea.jar"
+ deprecation="yes" debug="${debug}" debuglevel="${debuglevel}"
+ source="${java-level}" target="${java-level}"/>
+ </target>
+
+
+ <!-- Creates the jar file. -->
+ <target name="make-jar" depends="compile" description="Create the jar file">
+ <delete includeEmptyDirs="true" quiet="true" dir="${dist-dir}"/>
+ <mkdir dir="${dist-dir}"/>
+ <jar destfile="${dist-dir}/autocomplete.jar">
+ <fileset dir="${class-dir}"/>
+ <fileset dir="${source-dir}">
+ <include name="**/*.png"/>
+ </fileset>
+ <fileset dir="i18n"/>
+ <manifest>
+ <attribute name="Class-Path" value="rsyntaxtextarea.jar"/>
+ <attribute name="Specification-Title" value="AutoComplete"/>
+ <attribute name="Specification-Version" value="${version}"/>
+ <attribute name="Implementation-Title" value="org.fife.ui"/>
+ <attribute name="Implementation-Version" value="${version}"/>
+ </manifest>
+ </jar>
+ <copy todir="${dist-dir}" file="../RSyntaxTextArea/dist/rsyntaxtextarea.jar"/>
+ </target>
+
+
+ <!-- Builds the source zip file. -->
+ <target name="make-source-zip" description="Builds the source zip file">
+ <zip destfile="autocomplete_${version}_Source.zip">
+ <fileset dir=".">
+ <include name="src/**"/>
+ <include name="distfiles/**"/>
+ <include name="i18n/**"/>
+ <include name="lang/**"/>
+ <include name="build.xml"/>
+ </fileset>
+ </zip>
+ </target>
+
+
+ <!-- Builds the javadoc. -->
+ <target name="make-javadoc" depends="compile">
+ <javadoc destdir="${doc-dir}" author="true" version="true"
+ breakiterator="yes">
+ <packageset dir="${source-dir}" defaultexcludes="yes">
+ <include name="org/**"/>
+ </packageset>
+ </javadoc>
+ </target>
+
+
+</project>
diff --git a/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow.properties b/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow.properties
new file mode 100644
index 0000000..cd199b3
--- /dev/null
+++ b/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow.properties
@@ -0,0 +1 @@
+NoDescAvailable=No description available
diff --git a/img/localVar.png b/img/localVar.png
new file mode 100644
index 0000000..a8e1cf1
Binary files /dev/null and b/img/localVar.png differ
diff --git a/img/method.png b/img/method.png
new file mode 100644
index 0000000..3308b72
Binary files /dev/null and b/img/method.png differ
diff --git a/src/org/fife/ui/autocomplete/AbstractCompletion.java b/src/org/fife/ui/autocomplete/AbstractCompletion.java
new file mode 100644
index 0000000..bc0dbd9
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/AbstractCompletion.java
@@ -0,0 +1,111 @@
+/*
+ * 12/21/2008
+ *
+ * AbstractCompletion.java - Base class for possible completions.
+ * 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 javax.swing.text.JTextComponent;
+
+
+/**
+ * Base class for possible completions.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+public abstract class AbstractCompletion implements Completion, Comparable {
+
+ /**
+ * The provider that created this completion;
+ */
+ private CompletionProvider provider;
+
+
+ /**
+ * Constructor.
+ *
+ * @param provider The provider that created this completion.
+ */
+ public AbstractCompletion(CompletionProvider provider) {
+ this.provider = provider;
+ }
+
+
+ /**
+ * Compares this completion to another one lexicograhically, ignoring
+ * case.
+ *
+ * @param o Another completion instance.
+ * @return How this completion compares to the other one.
+ */
+ public int compareTo(Object o) {
+ if (o==this) {
+ return 0;
+ }
+ else if (o instanceof Completion) {
+ Completion c2 = (Completion)o;
+ return toString().compareToIgnoreCase(c2.toString());
+ }
+ return -1;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getAlreadyEntered(JTextComponent comp) {
+ return provider.getAlreadyEnteredText(comp);
+ }
+
+
+ /**
+ * Returns the text the user has to (start) typing for this completion
+ * to be offered. The default implementation simply returns
+ * {@link #getReplacementText()}.
+ *
+ * @return The text the user has to (start) typing for this completion.
+ * @see #getReplacementText()
+ */
+ public String getInputText() {
+ return getReplacementText();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public CompletionProvider getProvider() {
+ return provider;
+ }
+
+
+ /**
+ * Returns a string representation of this completion. The default
+ * implementation returns {@link #getInputText()}.
+ *
+ * @return A string representation of this completion.
+ */
+ public String toString() {
+ return getInputText();
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/AbstractCompletionProvider.java b/src/org/fife/ui/autocomplete/AbstractCompletionProvider.java
new file mode 100644
index 0000000..e6bf206
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/AbstractCompletionProvider.java
@@ -0,0 +1,291 @@
+/*
+ * 12/21/2008
+ *
+ * AbstractCompletionProvider.java - Base class for completion providers.
+ * 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.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import javax.swing.ListCellRenderer;
+import javax.swing.text.JTextComponent;
+
+
+/**
+ * A base class for completion providers. {@link Completion}s are kept in
+ * a sorted list. To get the list of completions that match a given input,
+ * a binary search is done to find the first matching completion, then all
+ * succeeding completions that also match are also returned.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+public abstract class AbstractCompletionProvider implements CompletionProvider {
+
+ /**
+ * The parent completion provider.
+ */
+ private CompletionProvider parent;
+
+ /**
+ * The completions this provider is aware of. Subclasses should ensure
+ * that this list is sorted alphabetically (case-insensitively).
+ */
+ protected List completions;
+
+ /**
+ * The renderer to use for completions from this provider. If this is
+ * <code>null</code>, a default renderer is used.
+ */
+ private ListCellRenderer listCellRenderer;
+
+ /**
+ * The case-insensitive {@link Completion} comparator.
+ */
+ private Comparator comparator;
+
+ protected static final String EMPTY_STRING = "";
+
+
+ /**
+ * Constructor.
+ */
+ public AbstractCompletionProvider() {
+ comparator = new CaseInsensitiveComparator();
+ }
+
+
+ /**
+ * Adds a single completion to this provider. If you are adding multiple
+ * completions to this provider, for efficiency reasons please consider
+ * using {@link #addCompletions(List)} instead.
+ *
+ * @param c The completion to add.
+ * @throws IllegalArgumentException If the completion's provider isn't
+ * this <tt>CompletionProvider</tt>.
+ * @see #addCompletions(List)
+ * @see #removeCompletion(Completion)
+ * @see #clear()
+ */
+ public void addCompletion(Completion c) {
+ completions.add(c);
+ Collections.sort(completions);
+ }
+
+
+ /**
+ * Adds {@link Completion}s to this provider.
+ *
+ * @param completions The completions to add. This cannot be
+ * <code>null</code>.
+ * @throws IllegalArgumentException If the completion's provider isn't
+ * this <tt>CompletionProvider</tt>.
+ * @see #addCompletion(Completion)
+ * @see #removeCompletion(Completion)
+ * @see #clear()
+ */
+ public void addCompletions(List completions) {
+ this.completions.addAll(completions);
+ Collections.sort(this.completions);
+ }
+
+
+ /**
+ * Removes all completions from this provider. This does not affect
+ * the parent <tt>CompletionProvider</tt>, if there is one.
+ *
+ * @see #addCompletion(Completion)
+ * @see #addCompletions(List)
+ * @see #removeCompletion(Completion)
+ */
+ public void clear() {
+ completions.clear();
+ }
+
+
+ /**
+ * Returns the first <tt>Completion</tt> in this provider with the
+ * specified input text.
+ *
+ * @param inputText The input text to search for.
+ * @return The {@link Completion}, or <code>null</code> if there is no such
+ * <tt>Completion</tt>.
+ */
+ public Completion getCompletionByInputText(String inputText) {
+ // TODO: Do a binary search for performance
+ for (int i=0; i<completions.size(); i++) {
+ Completion c = (Completion)completions.get(i);
+ if (c.getInputText().equals(inputText)) {
+ return c;
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public final List getCompletions(JTextComponent comp) {
+ List completions = getCompletionsImpl(comp);
+ if (parent!=null) {
+ completions.addAll(parent.getCompletions(comp));
+ Collections.sort(completions);
+ }
+ return completions;
+ }
+
+
+ /**
+ * Does the dirty work of creating a list of completions.
+ *
+ * @param comp The text component to look in.
+ * @return The list of possible completions, or an empty list if there
+ * are none.
+ */
+ protected List getCompletionsImpl(JTextComponent comp) {
+
+ List retVal = new ArrayList();
+ String text = getAlreadyEnteredText(comp);
+
+ int index = Collections.binarySearch(completions, text, comparator);
+ System.out.println(index + "(" + completions.size() + ")");
+ if (index<0) {
+ index = -index - 1;
+ }
+
+ while (index<completions.size()) {
+ Completion c = (Completion)completions.get(index);
+ if (startsWithIgnoreCase(c.getInputText(), text)) {
+ retVal.add(c);
+ index++;
+ }
+ else {
+ break;
+ }
+ }
+
+ return retVal;
+
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ListCellRenderer getListCellRenderer() {
+ return listCellRenderer;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public CompletionProvider getParent() {
+ return parent;
+ }
+
+
+ /**
+ * Removes the specified completion from this provider. This method
+ * will not remove completions from the parent provider, if there is one.
+ *
+ * @param c The completion to remove.
+ * @return <code>true</code> if this provider contained the specified
+ * completion.
+ * @see #clear()
+ * @see #addCompletion(Completion)
+ * @see #addCompletions(List)
+ */
+ public boolean removeCompletion(Completion c) {
+ // Don't just call completions.remove(c) as it'll be a linear search.
+ int index = Collections.binarySearch(completions, c);
+ if (index<0) {
+ return false;
+ }
+ completions.remove(index);
+ return true;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setListCellRenderer(ListCellRenderer r) {
+ listCellRenderer = r;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setParent(CompletionProvider parent) {
+ this.parent = parent;
+ }
+
+
+ /**
+ * Returns whether <code>str</code> starts with <code>start</code>,
+ * ignoring case.
+ *
+ * @param str The string to check.
+ * @param start The prefix to check for.
+ * @return Whether <code>str</code> starts with <code>start</code>,
+ * ignoring case.
+ */
+ protected boolean startsWithIgnoreCase(String str, String start) {
+ int startLen = start.length();
+ if (str.length()>=startLen) {
+ for (int i=0; i<startLen; i++) {
+ char c1 = str.charAt(i);
+ char c2 = start.charAt(i);
+ if (Character.toLowerCase(c1)!=Character.toLowerCase(c2)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * A comparator that compares the input text of two {@link Completion}s
+ * lexicographically, ignoring case.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+ private static class CaseInsensitiveComparator implements Comparator,
+ Serializable {
+
+ public int compare(Object o1, Object o2) {
+ Completion c = (Completion)o1;
+ return String.CASE_INSENSITIVE_ORDER.compare(c.getInputText(), o2);
+ }
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/AutoCompleteDescWindow.java b/src/org/fife/ui/autocomplete/AutoCompleteDescWindow.java
new file mode 100644
index 0000000..60a63a5
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/AutoCompleteDescWindow.java
@@ -0,0 +1,450 @@
+/*
+ * 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.BorderLayout;
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Font;
+import java.awt.SystemColor;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ResourceBundle;
+import javax.imageio.ImageIO;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JEditorPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JToolBar;
+import javax.swing.JWindow;
+import javax.swing.UIManager;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+import javax.swing.text.html.HTMLDocument;
+
+
+/**
+ * The optional "description" window that describes the currently selected
+ * item in the auto-completion window.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+class AutoCompleteDescWindow extends JWindow implements HyperlinkListener {
+
+ /**
+ * The parent AutoCompletion instance.
+ */
+ private AutoCompletion ac;
+
+ /**
+ * Renders the HTML description.
+ */
+ private JEditorPane descArea;
+
+ /**
+ * The toolbar with "back" and "forward" buttons.
+ */
+ private JToolBar descWindowNavBar;
+
+ /**
+ * Action that goes to the previous description displayed.
+ */
+ private Action backAction;
+
+ /**
+ * Action that goes to the next description displayed.
+ */
+ private Action forwardAction;
+
+ /**
+ * History of descriptions displayed.
+ */
+ private List history;
+
+ /**
+ * The current position in {@link #history}.
+ */
+ private int historyPos;
+
+ /**
+ * Used on OS X, where non-editable JEditorPanes don't have their cursors
+ * made into hand cursors on hyperlink mouseover.
+ */
+ private Cursor prevCursor;
+
+ /**
+ * The resource bundle for this window.
+ */
+ private ResourceBundle bundle;
+
+ /**
+ * The resource bundle name.
+ */
+ private static final String MSG =
+ "org.fife.ui.autocomplete.AutoCompleteDescWindow";
+
+ private static final boolean IS_OS_X = System.getProperty("os.name").
+ indexOf("OS X")>-1;
+
+
+ /**
+ * Constructor.
+ *
+ * @param owner The parent window.
+ * @param ac The parent autocompletion.
+ */
+ public AutoCompleteDescWindow(Window owner, AutoCompletion ac) {
+
+ super(owner);
+ this.ac = ac;
+
+ JPanel cp = new JPanel(new BorderLayout());
+ cp.setBorder(BorderFactory.createLineBorder(Color.BLACK));
+
+ descArea = createDescArea();
+ JScrollPane sp = new JScrollPane(descArea);
+ sp.setViewportBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+ sp.setBackground(descArea.getBackground());
+ sp.getViewport().setBackground(descArea.getBackground());
+ cp.add(sp);
+
+ descWindowNavBar = new JToolBar();
+ backAction = new ToolBarBackAction();
+ forwardAction = new ToolBarForwardAction();
+ descWindowNavBar.setFloatable(false);
+ descWindowNavBar.add(new JButton(backAction));
+ descWindowNavBar.add(new JButton(forwardAction));
+
+ JPanel temp = new JPanel(new BorderLayout());
+ SizeGrip rp = new SizeGrip();
+ temp.add(descWindowNavBar, BorderLayout.LINE_START);
+ temp.add(rp, BorderLayout.LINE_END);
+ cp.add(temp, BorderLayout.SOUTH);
+
+ setContentPane(cp);
+
+ setFocusableWindowState(false);
+
+ history = new ArrayList(1); // Usually small
+ historyPos = -1;
+
+ }
+
+
+ /**
+ * Sets the currently displayed description and updates the history.
+ *
+ * @param html The new description.
+ */
+ private void addToHistory(String html) {
+ history.add(++historyPos, html);
+ clearHistoryAfterCurrentPos();
+ setActionStates();
+ }
+
+
+ /**
+ * Clears the history of viewed descriptions.
+ */
+ private void clearHistory() {
+ history.clear(); // Try to free some memory.
+ historyPos = -1;
+ if (descWindowNavBar!=null) {
+ setActionStates();
+ }
+ }
+
+
+ /**
+ * Makes the current history page the last one in the history.
+ */
+ private void clearHistoryAfterCurrentPos() {
+ for (int i=history.size()-1; i>historyPos; i--) {
+ history.remove(i);
+ }
+ setActionStates();
+ }
+
+
+ /**
+ * Creates the customized JEditorPane used to render HTML documentation.
+ *
+ * @return The JEditorPane.
+ */
+ private JEditorPane createDescArea() {
+
+ JEditorPane descArea = new JEditorPane("text/html", null);
+
+ // Jump through a few hoops to get things looking nice in Nimbus
+ if (UIManager.getLookAndFeel().getName().equals("Nimbus")) {
+ System.out.println("DEBUG: Creating Nimbus-specific changes");
+ Color selBG = descArea.getSelectionColor();
+ Color selFG = descArea.getSelectedTextColor();
+ descArea.setUI(new javax.swing.plaf.basic.BasicEditorPaneUI());
+ descArea.setSelectedTextColor(selFG);
+ descArea.setSelectionColor(selBG);
+ }
+
+ descArea.getCaret().setSelectionVisible(true);
+ descArea.setEditable(false);
+ descArea.addHyperlinkListener(this);
+
+ // Make it use "tooltip" background color.
+ descArea.setBackground(getDefaultBackground());
+
+ // Force JEditorPane to use a certain font even in HTML.
+ Font font = UIManager.getFont("Label.font");
+ HTMLDocument doc = (HTMLDocument)descArea.getDocument();
+ doc.getStyleSheet().addRule("body { font-family: " + font.getFamily() +
+ "; font-size: " + font.getSize() + "pt; }");
+
+ return descArea;
+
+ }
+
+
+ /**
+ * Returns the default background color to use for the description
+ * window.
+ *
+ * @return The default background color.
+ */
+ protected Color getDefaultBackground() {
+ System.out.println(UIManager.getColor("info"));
+ 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;
+ }
+
+
+ /**
+ * Returns the localized message for the specified key.
+ *
+ * @param key The key.
+ * @return The localized message.
+ */
+ private String getString(String key) {
+ if (bundle==null) {
+ bundle = ResourceBundle.getBundle(MSG);
+ }
+ return bundle.getString(key);
+ }
+
+
+ /**
+ * Called when a hyperlink is clicked.
+ *
+ * @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)) {
+ URL url = e.getURL();
+ if (url!=null) {
+ ExternalURLHandler handler = ac.getExternalURLHandler();
+ if (handler!=null) {
+ handler.urlClicked(url);
+ return;
+ }
+ // No handler - try loading in external browser (Java 6+ only).
+ try {
+ Util.browse(new URI(url.toString()));
+ //descArea.setText(null);
+ //descArea.read(url.openStream(), descArea.getDocument());
+ ////descArea.setPage(url);
+ ////descArea.setCaretPosition(0); // In case we scrolled
+ ////addToHistory(descArea.getText());
+ } catch (/*IO*/URISyntaxException ioe) {
+ UIManager.getLookAndFeel().provideErrorFeedback(descArea);
+ ioe.printStackTrace();
+// try {
+// descArea.read(url.openStream(), null);
+// } catch (IOException ioe2) {
+// ioe2.printStackTrace();
+// UIManager.getLookAndFeel().provideErrorFeedback(descArea);
+// }
+ }
+ }
+ else { // Simple function name text, like in c.xml
+ // FIXME: This is really a hack, and we assume we can find the
+ // linked-to item in the same CompletionProvider.
+ AutoCompletePopupWindow parent =
+ (AutoCompletePopupWindow)getParent();
+ CompletionProvider p = parent.getSelection().getProvider();
+ if (p instanceof AbstractCompletionProvider) {
+ String name = e.getDescription();
+ Completion c = ((AbstractCompletionProvider)p).
+ getCompletionByInputText(name);
+ setDescriptionFor(c, true);
+ }
+ }
+ }
+
+ // OS X needs a little push to use the hand cursor for links in a
+ // non-editable JEditorPane
+ else if (IS_OS_X) {
+ boolean entered = HyperlinkEvent.EventType.ENTERED.equals(type);
+ if (entered) {
+ prevCursor = descArea.getCursor();
+ descArea.setCursor(Cursor.getPredefinedCursor(
+ Cursor.HAND_CURSOR));
+ }
+ else {
+ descArea.setCursor(prevCursor);
+ }
+ }
+
+ }
+
+
+ /**
+ * Enables or disables the back and forward actions as appropriate.
+ */
+ private void setActionStates() {
+ backAction.setEnabled(historyPos>0);
+ forwardAction.setEnabled(historyPos>-1 && historyPos<history.size()-1);
+ }
+
+
+ /**
+ * Sets the description displayed in this window. This clears the
+ * history.
+ *
+ * @param item The item whose description you want to display.
+ */
+ public void setDescriptionFor(Completion item) {
+ setDescriptionFor(item, false);
+ }
+
+
+ /**
+ * Sets the description displayed in this window.
+ *
+ * @param item The item whose description you want to display.
+ * @param addToHistory Whether to add this page to the page history
+ * (as opposed to clearing it and starting anew).
+ */
+ protected void setDescriptionFor(Completion item, boolean addToHistory) {
+ String desc = item==null ? null : item.getSummary();
+ if (desc==null) {
+ desc = "<html><em>" + getString("NoDescAvailable") + "</em>";
+ }
+ descArea.setText(desc);
+ descArea.setCaretPosition(0); // In case of scrolling
+ if (!addToHistory) {
+ // Remove everything first if this is going to be the only
+ // thing in history.
+ clearHistory();
+ }
+ addToHistory(desc);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setVisible(boolean visible) {
+ if (!visible) {
+ clearHistory();
+ }
+ super.setVisible(visible);
+ }
+
+
+ /**
+ * Action that moves to the previous description displayed.
+ */
+ class ToolBarBackAction extends AbstractAction {
+
+ public ToolBarBackAction() {
+ ClassLoader cl = getClass().getClassLoader();
+ URL url = cl.getResource("org/fife/ui/autocomplete/arrow_left.png");
+ try {
+ Icon icon = new ImageIcon(ImageIO.read(url));
+ putValue(Action.SMALL_ICON, icon);
+ } catch (IOException ioe) { // Never happens
+ ioe.printStackTrace();
+ putValue(Action.SHORT_DESCRIPTION, "Back");
+ }
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (historyPos>0) {
+ descArea.setText((String)history.get(--historyPos));
+ descArea.setCaretPosition(0);
+ setActionStates();
+ }
+ }
+
+ }
+
+
+ /**
+ * Action that moves to the previous description displayed.
+ */
+ class ToolBarForwardAction extends AbstractAction {
+
+ public ToolBarForwardAction() {
+ ClassLoader cl = getClass().getClassLoader();
+ URL url = cl.getResource("org/fife/ui/autocomplete/arrow_right.png");
+ try {
+ Icon icon = new ImageIcon(ImageIO.read(url));
+ putValue(Action.SMALL_ICON, icon);
+ } catch (IOException ioe) { // Never happens
+ ioe.printStackTrace();
+ putValue(Action.SHORT_DESCRIPTION, "Forward");
+ }
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (history!=null && historyPos<history.size()-1) {
+ descArea.setText((String)history.get(++historyPos));
+ descArea.setCaretPosition(0);
+ setActionStates();
+ }
+ }
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/AutoCompletePopupWindow.java b/src/org/fife/ui/autocomplete/AutoCompletePopupWindow.java
new file mode 100644
index 0000000..d14c08d
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/AutoCompletePopupWindow.java
@@ -0,0 +1,617 @@
+/*
+ * 12/21/2008
+ *
+ * AutoCompletePopupWindow.java - A window containing a list of auto-complete
+ * choices.
+ * 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.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Rectangle;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JWindow;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+import javax.swing.event.CaretEvent;
+import javax.swing.event.CaretListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.text.Caret;
+import javax.swing.text.Keymap;
+import javax.swing.text.JTextComponent;
+
+
+/**
+ * The actual popup window of choices. When visible, this window intercepts
+ * certain keystrokes in the parent text component and uses them to navigate
+ * the completion choices instead. If Enter or Escape is pressed, the window
+ * hides itself and notifies the {@link AutoCompletion} to insert the selected
+ * text.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+class AutoCompletePopupWindow extends JWindow implements CaretListener,
+ ListSelectionListener, MouseListener {
+
+ private AutoCompletion ac;
+ private JList list;
+ private /*DefaultListModel*/CompletionListModel model;
+ private Action oldUpAction, oldDownAction, oldLeftAction, oldRightAction,
+ oldEnterAction, oldTabAction, oldEscapeAction, oldHomeAction,
+ oldEndAction, oldPageUpAction, oldPageDownAction;
+ private Action upAction, downAction, leftAction ,rightAction, enterAction,
+ escapeAction, homeAction, endAction, pageUpAction, pageDownAction;
+ private int lastLine;
+
+ private AutoCompleteDescWindow descWindow;
+ private boolean aboveCaret;
+
+ private static final boolean DEBUG = true;
+
+
+ public AutoCompletePopupWindow(Window parent, AutoCompletion ac) {
+
+ super(parent);
+
+ this.ac = ac;
+ model = new CompletionListModel();//DefaultListModel();
+ list = new JList(model);
+//list.setFixedCellWidth(300);
+//list.setFixedCellHeight(29);
+ list.setCellRenderer(new DelegatingCellRenderer());
+ list.addListSelectionListener(this);
+ list.addMouseListener(this);
+
+ JPanel contentPane = new JPanel(new BorderLayout());
+ JScrollPane sp = new JScrollPane(list, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
+ JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
+
+ // In 1.4, JScrollPane.setCorner() has a bug where it won't accept
+ // JScrollPane.LOWER_TRAILING_CORNER, even though that constant is
+ // defined. So we have to put the logic added in 1.5 to handle it
+ // here.
+ JPanel corner = new SizeGrip();
+ //sp.setCorner(JScrollPane.LOWER_TRAILING_CORNER, corner);
+ boolean isLeftToRight = getComponentOrientation().isLeftToRight();
+ String str = isLeftToRight ? JScrollPane.LOWER_RIGHT_CORNER :
+ JScrollPane.LOWER_LEFT_CORNER;
+ sp.setCorner(str, corner);
+
+ contentPane.add(sp);
+ setContentPane(contentPane);
+ pack();
+
+ setFocusableWindowState(false);
+
+ lastLine = -1;
+
+ }
+
+
+// public void addItem(Completion item) {
+// model.addElement(item);
+// }
+public void setCompletions(List completions) {
+ model.setContents(completions);
+}
+
+ public void caretUpdate(CaretEvent e) {
+ if (isVisible()) { // Should always be true
+ int line = ac.getLineOfCaret();
+ if (line!=lastLine) {
+lastLine = -1;
+ setVisible(false);
+ }
+ else {
+ doAutocomplete();
+ }
+ }
+ else if (DEBUG) {
+ Thread.dumpStack();
+ }
+ }
+
+
+// public void clear() {
+// model.clear();
+// }
+
+
+ private void createActions() {
+ escapeAction = new EscapeAction();
+ upAction = new UpAction();
+ downAction = new DownAction();
+ leftAction = new LeftAction();
+ rightAction = new RightAction();
+ enterAction = new EnterAction();
+ homeAction = new HomeAction();
+ endAction = new EndAction();
+ pageUpAction = new PageUpAction();
+ pageDownAction = new PageDownAction();
+ }
+
+
+ protected void doAutocomplete() {
+ lastLine = ac.refreshPopupWindow();
+ }
+
+
+ /**
+ * Returns the selected value, or <code>null</code> if nothing is selected.
+ *
+ * @return The selected value.
+ */
+ public Completion getSelection() {
+ return (Completion)list.getSelectedValue();
+ }
+
+
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount()==2) {
+ ac.doCompletion();
+ }
+ }
+
+
+ public void mouseEntered(MouseEvent e) {
+ }
+
+
+ public void mouseExited(MouseEvent e) {
+ }
+
+
+ public void mousePressed(MouseEvent e) {
+ }
+
+
+ public void mouseReleased(MouseEvent e) {
+ }
+
+
+ /**
+ * Positions the description window relative to the comletion choices
+ * window.
+ */
+ private void positionDescWindow() {
+
+ boolean showDescWindow = descWindow!=null && ac.getShowDescWindow();
+ if (!showDescWindow) {
+ return;
+ }
+
+ Dimension screenSize = getToolkit().getScreenSize();
+ //int totalH = Math.max(getHeight(), descWindow.getHeight());
+
+ // Try to position to the right first.
+ int x = getX() + getWidth() + 5;
+ if (x+descWindow.getWidth()>screenSize.width) { // doesn't fit
+ x = getX() - 5 - descWindow.getWidth();
+ }
+
+ int y = getY();
+ if (aboveCaret) {
+ y = y + getHeight() - descWindow.getHeight();
+ }
+
+ if (x!=descWindow.getX() || y!=descWindow.getY()) {
+ descWindow.setLocation(x, y);
+ }
+
+ }
+
+
+ /**
+ * Registers keyboard actions to listen for in the text component and
+ * intercept.
+ *
+ * @see #unregisterActions()
+ */
+ private void registerActions() {
+ System.err.println("Registering actions");
+
+ if (escapeAction == null) {
+ createActions();
+ }
+
+ JTextComponent comp = ac.getTextComponent();
+ Keymap km = comp.getKeymap();
+
+ KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
+ oldEscapeAction = km.getAction(ks);
+ if (DEBUG && oldEscapeAction==escapeAction) {
+ Thread.dumpStack();
+ return;
+ }
+ km.addActionForKeyStroke(ks, escapeAction);
+
+ oldUpAction = replaceAction(km, KeyEvent.VK_UP, upAction);
+ oldDownAction = replaceAction(km, KeyEvent.VK_DOWN, downAction);
+ oldLeftAction = replaceAction(km, KeyEvent.VK_LEFT, leftAction);
+ oldRightAction = replaceAction(km, KeyEvent.VK_RIGHT, rightAction);
+ oldEnterAction = replaceAction(km, KeyEvent.VK_ENTER, enterAction);
+ oldTabAction = replaceAction(km, KeyEvent.VK_TAB, enterAction);
+ oldHomeAction = replaceAction(km, KeyEvent.VK_HOME, homeAction);
+ oldEndAction = replaceAction(km, KeyEvent.VK_END, endAction);
+ oldPageUpAction = replaceAction(km, KeyEvent.VK_PAGE_UP, pageUpAction);
+ oldPageDownAction = replaceAction(km, KeyEvent.VK_PAGE_DOWN, pageDownAction);
+
+ comp.addCaretListener(this);
+
+ }
+
+
+ /**
+ * Replaces the action binded to a keystroke.
+ *
+ * @param km The map in which to replace the action.
+ * @param key The keystroke whose action to replace.
+ * @param a The action to associate with <code>key</code>. If this is
+ * <code>null</code>, no keystroke will be associated with the key.
+ * @return The previous action associated with the key, or <code>null</code>
+ * if there was none.
+ */
+ private Action replaceAction(Keymap km, int key, Action a) {
+ KeyStroke ks = KeyStroke.getKeyStroke(key, 0);
+ Action old = km.getAction(ks);
+ if (a!=null) {
+ km.addActionForKeyStroke(ks, a);
+ } else {
+ km.removeKeyStrokeBinding(ks);
+ }
+ return old;
+ }
+
+
+ public void selectFirstItem() {
+ if (model.getSize() > 0) {
+ list.setSelectedIndex(0);
+ list.ensureIndexIsVisible(0);
+ }
+ }
+
+
+ public void selectLastItem() {
+ int index = model.getSize() - 1;
+ if (index > -1) {
+ list.setSelectedIndex(index);
+ list.ensureIndexIsVisible(index);
+ }
+ }
+
+
+ public void selectNextItem() {
+ int index = list.getSelectedIndex();
+ if (index > -1) {
+ index = (index + 1) % model.getSize();
+ list.setSelectedIndex(index);
+ list.ensureIndexIsVisible(index);
+ }
+ }
+
+
+ public void selectPageDownItem() {
+ int visibleRowCount = list.getVisibleRowCount();
+ int i = Math.min(list.getModel().getSize()-1,
+ list.getSelectedIndex()+visibleRowCount);
+ list.setSelectedIndex(i);
+ list.ensureIndexIsVisible(i);
+ }
+
+
+ public void selectPageUpItem() {
+ int visibleRowCount = list.getVisibleRowCount();
+ int i = Math.max(0, list.getSelectedIndex()-visibleRowCount);
+ list.setSelectedIndex(i);
+ list.ensureIndexIsVisible(i);
+ }
+
+
+ public void selectPreviousItem() {
+ int index = list.getSelectedIndex();
+ switch (index) {
+ case 0:
+ index = list.getModel().getSize() - 1;
+ break;
+ case -1: // Check for an empty list (would be an error)
+ index = list.getModel().getSize() - 1;
+ if (index == -1) {
+ return;
+ }
+ break;
+ default:
+ index = index - 1;
+ break;
+ }
+ list.setSelectedIndex(index);
+ list.ensureIndexIsVisible(index);
+ }
+
+
+ public void setLocationRelativeTo(Rectangle r) {
+
+ boolean showDescWindow = descWindow!=null && ac.getShowDescWindow();
+ Dimension screenSize = getToolkit().getScreenSize();
+ int totalH = getHeight();
+ if (showDescWindow) {
+ totalH = Math.max(totalH, descWindow.getHeight());
+ }
+
+ // Try putting our stuff "below" the caret first. We assume that the
+ // entire height of our stuff fits on the screen one way or the other.
+ aboveCaret = false;
+ int y = r.y + r.height + 10;
+ if (y+totalH>screenSize.height) {
+ y = r.y - 10 - getHeight();
+ aboveCaret = true;
+ }
+
+ // 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+getWidth()>screenSize.width) { // completions don't fit
+ x = screenSize.width - getWidth();
+ }
+
+ setLocation(x, y);
+
+ // Position the description window, if neessary.
+ if (showDescWindow) {
+ positionDescWindow();
+ }
+
+ }
+
+
+ /**
+ * Toggles the visibility of this popup window.
+ *
+ * @param visible Whether this window should be visible.
+ */
+ public void setVisible(boolean visible) {
+ if (visible!=isVisible()) {
+ if (visible) {
+ registerActions();
+ lastLine = ac.getLineOfCaret();
+ selectFirstItem();
+ if (descWindow==null && ac.getShowDescWindow()) {
+ descWindow = new AutoCompleteDescWindow(this, ac);
+ descWindow.setSize(getSize());
+ descWindow.setLocation(getX()+getWidth()+5, getY());
+ // descWindow needs a kick-start the first time it's
+ // displayed.
+ Completion c = (Completion)list.getSelectedValue();
+ descWindow.setDescriptionFor(c);
+ }
+ }
+ else {
+ unregisterActions();
+ }
+ super.setVisible(visible);
+ if (descWindow!=null && ac.getShowDescWindow()) {
+ descWindow.setVisible(visible);
+ }
+ }
+ }
+
+
+ /**
+ * Stops intercepting certain keystrokes from the text component.
+ *
+ * @see #registerActions()
+ */
+ public void unregisterActions() {
+
+ System.err.println("Unregistering actions");
+ JTextComponent comp = ac.getTextComponent();
+ Keymap km = comp.getKeymap();
+
+ replaceAction(km, KeyEvent.VK_ESCAPE, oldEscapeAction);
+ replaceAction(km, KeyEvent.VK_UP, oldUpAction);
+ replaceAction(km, KeyEvent.VK_DOWN, oldDownAction);
+ replaceAction(km, KeyEvent.VK_LEFT, oldLeftAction);
+ replaceAction(km, KeyEvent.VK_RIGHT, oldRightAction);
+ replaceAction(km, KeyEvent.VK_ENTER, oldEnterAction);
+ replaceAction(km, KeyEvent.VK_TAB, oldTabAction);
+ replaceAction(km, KeyEvent.VK_HOME, oldHomeAction);
+ replaceAction(km, KeyEvent.VK_END, oldEndAction);
+ replaceAction(km, KeyEvent.VK_PAGE_UP, oldPageUpAction);
+ replaceAction(km, KeyEvent.VK_PAGE_DOWN, oldPageDownAction);
+
+ comp.removeCaretListener(this);
+
+ }
+
+
+ /**
+ * Updates the <tt>LookAndFeel</tt> of this window and the description
+ * window.
+ */
+ public void updateUI() {
+ SwingUtilities.updateComponentTreeUI(this);
+ if (descWindow!=null) {
+ SwingUtilities.updateComponentTreeUI(descWindow);
+ }
+ }
+
+
+ /**
+ * Called when a new item is selected in the popup list.
+ *
+ * @param e The event.
+ */
+ public void valueChanged(ListSelectionEvent e) {
+ if (!e.getValueIsAdjusting()) {
+ Object value = list.getSelectedValue();
+ if (value!=null && descWindow!=null) {
+ descWindow.setDescriptionFor((Completion)value);
+ positionDescWindow();
+ }
+ }
+ }
+
+
+ class DownAction extends AbstractAction {
+
+ public void actionPerformed(ActionEvent e) {
+ if (isVisible()) {
+ selectNextItem();
+ }
+ }
+
+ }
+
+
+ class EndAction extends AbstractAction {
+
+ public void actionPerformed(ActionEvent e) {
+ if (isVisible()) {
+ selectLastItem();
+ }
+ }
+
+ }
+
+
+ class EnterAction extends AbstractAction {
+
+ public void actionPerformed(ActionEvent e) {
+ if (isVisible()) {
+ ac.doCompletion();
+ }
+ }
+
+ }
+
+
+ class EscapeAction extends AbstractAction {
+
+ public void actionPerformed(ActionEvent e) {
+ if (isVisible()) {
+ setVisible(false);
+ }
+ }
+
+ }
+
+
+ class HomeAction extends AbstractAction {
+
+ public void actionPerformed(ActionEvent e) {
+ if (isVisible()) {
+ selectFirstItem();
+ }
+ }
+
+ }
+
+
+ class LeftAction extends AbstractAction {
+
+ public void actionPerformed(ActionEvent e) {
+ if (isVisible()) {
+ JTextComponent comp = ac.getTextComponent();
+ Caret c = comp.getCaret();
+ int dot = c.getDot();
+ if (dot > 0) {
+ c.setDot(--dot);
+ // Ensure moving left hasn't moved us up a line, thus
+ // hiding the popup window.
+ if (comp.isVisible()) {
+if (lastLine!=-1) doAutocomplete();
+ }
+ }
+ }
+ }
+
+ }
+
+
+ class PageDownAction extends AbstractAction {
+
+ public void actionPerformed(ActionEvent e) {
+ if (isVisible()) {
+ selectPageDownItem();
+ }
+ }
+
+ }
+
+
+ class PageUpAction extends AbstractAction {
+
+ public void actionPerformed(ActionEvent e) {
+ if (isVisible()) {
+ selectPageUpItem();
+ }
+ }
+
+ }
+
+
+ class RightAction extends AbstractAction {
+
+ public void actionPerformed(ActionEvent e) {
+ if (isVisible()) {
+ JTextComponent comp = ac.getTextComponent();
+ Caret c = comp.getCaret();
+ int dot = c.getDot();
+ if (dot < comp.getDocument().getLength()) {
+ c.setDot(++dot);
+ // Ensure moving right hasn't moved us up a line, thus
+ // hiding the popup window.
+ if (comp.isVisible()) {
+if (lastLine!=-1) doAutocomplete();
+ }
+ }
+ }
+ }
+
+ }
+
+
+ class UpAction extends AbstractAction {
+
+ public void actionPerformed(ActionEvent e) {
+ if (isVisible()) {
+ selectPreviousItem();
+ }
+ }
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/AutoCompletion.java b/src/org/fife/ui/autocomplete/AutoCompletion.java
new file mode 100644
index 0000000..88c693b
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/AutoCompletion.java
@@ -0,0 +1,574 @@
+/*
+ * 12/21/2008
+ *
+ * AutoCompletion.java - Handles auto-completion for a text component.
+ * 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.*;
+import java.awt.event.*;
+import java.util.List;
+import javax.swing.*;
+import javax.swing.text.*;
+
+
+/**
+ * Adds autocompletion to a text component. Provides a popup window with a
+ * list of autocomplete choices on a given keystroke, such as Crtrl+Space.<p>
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+/*
+ * This class handles intercepting window and hierarchy events from the text
+ * component, so the popup window is only visible when it should be visible.
+ * It also handles communication between the CompletionProvider and the actual
+ * popup Window.
+ */
+public class AutoCompletion implements HierarchyListener, ComponentListener {
+
+ /**
+ * The text component we're providing completion for.
+ */
+ private JTextComponent textComponent;
+
+ /**
+ * The parent window of {@link #textComponent}.
+ */
+ private Window parentWindow;
+
+ /**
+ * The popup window containing completion choices.
+ */
+ private AutoCompletePopupWindow popupWindow;
+
+ /**
+ * Provides the completion options relevant to the current caret position.
+ */
+ private CompletionProvider provider;
+
+ /**
+ * The handler to use when an external URL is clicked in the help
+ * documentation.
+ */
+ private ExternalURLHandler externalURLHandler;
+
+ /**
+ * Whether the description window should be displayed along with the
+ * completion choice window.
+ */
+ private boolean showDescWindow;
+
+ /**
+ * Whether autocomplete is enabled.
+ */
+ private boolean autoCompleteEnabled;
+
+ /**
+ * Whether or not, when there is only a single auto-complete option
+ * that maches the text at the current text position, that text should
+ * be auto-inserted, instead of the completion window displaying.
+ */
+ private boolean autoCompleteSingleChoices;
+
+ /**
+ * The keystroke that triggers the completion window.
+ */
+ private KeyStroke trigger;
+
+ /**
+ * The action previously assigned to {@link #trigger}, so we can reset it
+ * if the user disables auto-completion.
+ */
+ private Action oldTriggerAction;
+
+
+ /**
+ * Constructor.
+ *
+ * @param provider The completion provider. This cannot be
+ * <code>null</code>.
+ */
+ public AutoCompletion(CompletionProvider provider) {
+ setCompletionProvider(provider);
+ setTriggerKey(getDefaultTriggerKey());
+ setAutoCompleteEnabled(true);
+ setAutoCompleteSingleChoices(true);
+ setShowDescWindow(false);
+ }
+
+
+ public void componentHidden(ComponentEvent e) {
+ hidePopupWindow();
+ }
+
+
+ public void componentMoved(ComponentEvent e) {
+ hidePopupWindow();
+ }
+
+
+ public void componentResized(ComponentEvent e) {
+ hidePopupWindow();
+ }
+
+
+ public void componentShown(ComponentEvent e) {
+ }
+
+
+ public void doCompletion() {
+ Completion comp = popupWindow.getSelection();
+ doCompletionImpl(comp);
+ }
+
+
+ private void doCompletionImpl(Completion c) {
+
+ JTextComponent textComp = getTextComponent();
+ String alreadyEntered = c.getAlreadyEntered(textComp);
+ hidePopupWindow();
+ Caret caret = textComp.getCaret();
+
+ int dot = caret.getDot();
+ caret.setDot(dot - alreadyEntered.length());
+ caret.moveDot(dot);
+ textComp.replaceSelection(c.getReplacementText());
+/*
+ Document doc = textComp.getDocument();
+ int end = caret.getDot();
+ int start = end - alreadyEntered.length();
+try {
+ if (doc instanceof AbstractDocument) {
+ ((AbstractDocument)doc).replace(start, end-start, c.getReplacementText(), null);
+ }
+ else {
+ doc.remove(start, end-start);
+ doc.insertString(start, c.getReplacementText(), null);
+ }
+} catch (javax.swing.text.BadLocationException ble) { ble.printStackTrace(); }
+*/
+ }
+
+
+ /**
+ * Returns whether, if a single autocomplete choice is available, it should
+ * be automatically inserted, without displaying the popup menu.
+ *
+ * @return Whether to autocomplete single choices.
+ * @see #setAutoCompleteSingleChoices(boolean)
+ */
+ public boolean getAutoCompleteSingleChoices() {
+ return autoCompleteSingleChoices;
+ }
+
+
+ /**
+ * Returns the default autocomplete "trigger key" for this OS. For
+ * Windows, for example, it is Ctrl+Space.
+ *
+ * @return The default autocomplete trigger key.
+ */
+ public static KeyStroke getDefaultTriggerKey() {
+ // Default to CTRL, even on Mac, since Ctrl+Space activates Spotlight
+ int mask = Event.CTRL_MASK;
+ return KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, mask);
+ }
+
+
+ /**
+ * Returns the handler to use when an external URL is clicked in the
+ * description window.
+ *
+ * @return The handler.
+ * @see #setExternalURLHandler(ExternalURLHandler)
+ */
+ public ExternalURLHandler getExternalURLHandler() {
+ return externalURLHandler;
+ }
+
+
+ int getLineOfCaret() {
+ Document doc = textComponent.getDocument();
+ Element root = doc.getDefaultRootElement();
+ return root.getElementIndex(textComponent.getCaretPosition());
+ }
+
+
+ CompletionProvider getProviderAtCaretPosition() {
+ // TODO: Delegate to provider in case the provider itself delegates.
+ //return provider.getProviderAtCaretPosition(textComponent);
+ return provider;
+ }
+
+
+ /**
+ * Returns whether the "description window" should be shown alongside
+ * the completion window.
+ *
+ * @return Whether the description window should be shown.
+ * @see #setShowDescWindow(boolean)
+ */
+ public boolean getShowDescWindow() {
+ return showDescWindow;
+ }
+
+
+ /**
+ * Returns the text component for which autocompletion is enabled.
+ *
+ * @return The text component, or <code>null</code> if this
+ * {@link AutoCompletion} is not installed on any text component.
+ * @see #install(JTextComponent)
+ */
+ public JTextComponent getTextComponent() {
+ return textComponent;
+ }
+
+
+ /**
+ * Returns the "trigger key" used for autocomplete.
+ *
+ * @return The trigger key.
+ * @see #setTriggerKey(KeyStroke)
+ */
+ public KeyStroke getTriggerKey() {
+ return trigger;
+ }
+
+
+ /**
+ * Called when the component hierarchy for our text component changes.
+ * When the text component is added to a new {@link Window}, this method
+ * registers listeners on that <code>Window</code>.
+ *
+ * @param e The event.
+ */
+ public void hierarchyChanged(HierarchyEvent e) {
+
+ // NOTE: e many be null as we call this method at other times.
+ //System.out.println("Hierarchy changed! " + e);
+
+ Window oldParentWindow = parentWindow;
+ parentWindow = SwingUtilities.getWindowAncestor(textComponent);
+ if (parentWindow!=oldParentWindow) {
+ if (oldParentWindow!=null) {
+ oldParentWindow.removeComponentListener(this);
+ }
+ if (parentWindow!=null) {
+ parentWindow.addComponentListener(this);
+ }
+ }
+
+ }
+
+
+ private void hidePopupWindow() {
+ if (popupWindow!=null) {
+ if (popupWindow.isVisible()) {
+ popupWindow.setVisible(false);
+ }
+ }
+ }
+
+
+ /**
+ * Installs this autocompletion on a text component. If this
+ * {@link AutoCompletion} is already installed on another text component,
+ * it is uninstalled first.
+ *
+ * @param c The text component.
+ * @see #uninstall()
+ */
+ public void install(JTextComponent c) {
+
+ if (textComponent!=null) {
+ uninstall();
+ }
+
+ this.textComponent = c;
+ installTriggerKey(getTriggerKey());
+
+ this.textComponent.addHierarchyListener(this);
+ hierarchyChanged(null); // In case textComponent is already in a window
+
+ }
+
+
+ /**
+ * Installs a "trigger key" action onto the current text component.
+ *
+ * @param ks The keystroke that should trigger the action.
+ * @see #uninstallTriggerKey()
+ */
+ private void installTriggerKey(KeyStroke ks) {
+ Keymap km = textComponent.getKeymap();
+ oldTriggerAction = km.getAction(ks);
+ km.addActionForKeyStroke(ks, new AutoCompleteAction());
+ }
+
+
+ /**
+ * Returns whether autocompletion is enabled.
+ *
+ * @return Whether autocompletion is enabled.
+ * @see #setAutoCompleteEnabled(boolean)
+ */
+ public boolean isAutoCompleteEnabled() {
+ return autoCompleteEnabled;
+ }
+
+
+ private boolean isPopupVisible() {
+ return popupWindow!=null && popupWindow.isVisible();
+ }
+
+
+ /**
+ * Refreshes the popup window. First, this method gets the possible
+ * completions for the current caret position. If there are none, and the
+ * popup is visible, it is hidden. If there are some completions and the
+ * popup is hidden, it is made visible and made to display the completions.
+ * If there are some completions and the popup is visible, its list is
+ * updated to the current set of completions.
+ *
+ * @return The current line number of the caret.
+ */
+ protected int refreshPopupWindow() {
+
+ final List completions = provider.getCompletions(textComponent);
+ int count = completions.size();
+
+ if (count>1 || (count==1 && isPopupVisible()) ||
+ (count==1 && !getAutoCompleteSingleChoices())) {
+
+ if (popupWindow==null) {
+ popupWindow = new AutoCompletePopupWindow(parentWindow, this);
+ }
+
+ popupWindow.setCompletions(completions);
+// popupWindow.clear();
+// for (int i=0; i<completions.size(); i++) {
+//
+// popupWindow.addItem((Completion)completions.get(i));
+// }
+ popupWindow.selectFirstItem();
+
+ if (!popupWindow.isVisible()) {
+ Rectangle r = null;
+ try {
+ r = textComponent.modelToView(textComponent.
+ getCaretPosition());
+ } catch (BadLocationException ble) {
+ ble.printStackTrace();
+ return -1;
+ }
+ Point p = new Point(r.x, r.y);
+ SwingUtilities.convertPointToScreen(p, textComponent);
+ r.x = p.x;
+ r.y = p.y;
+ popupWindow.setLocationRelativeTo(r);
+ popupWindow.setVisible(true);
+ }
+
+ }
+
+ else if (count==1) { // !isPopupVisible && autoCompleteSingleChoices
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ doCompletionImpl((Completion)completions.get(0));
+ }
+ });
+ }
+
+ else {
+ hidePopupWindow();
+ }
+
+ return getLineOfCaret();
+
+ }
+
+
+ /**
+ * Sets whether autocompletion is enabled.
+ *
+ * @param enabled Whether autocompletion is enabled.
+ * @see #isAutoCompleteEnabled()
+ */
+ public void setAutoCompleteEnabled(boolean enabled) {
+ if (enabled!=autoCompleteEnabled) {
+ autoCompleteEnabled = enabled;
+ hidePopupWindow();
+ }
+ }
+
+
+ /**
+ * Sets whether, if a single autocomplete choice is available, it should
+ * be automatically inserted, without displaying the popup menu.
+ *
+ * @param autoComplete Whether to autocomplete single choices.
+ * @see #getAutoCompleteSingleChoices()
+ */
+ public void setAutoCompleteSingleChoices(boolean autoComplete) {
+ autoCompleteSingleChoices = autoComplete;
+ }
+
+
+ /**
+ * Sets the completion provider being used.
+ *
+ * @param provider The new completion provider. This cannot be
+ * <code>null</code>.
+ * @throws IllegalArgumentException If <code>provider</code> is
+ * <code>null</code>.
+ */
+ public void setCompletionProvider(CompletionProvider provider) {
+ if (provider==null) {
+ throw new IllegalArgumentException("provider cannot be null");
+ }
+ this.provider = provider;
+ hidePopupWindow(); // In case new choices should be displayed.
+ }
+
+
+ /**
+ * Sets the handler to use when an external URL is clicked in the
+ * description window. This handler can perform some action, such as
+ * open the URL in a web browser. The default implementation will open
+ * the URL in a browser, but only if running in Java 6. If you want
+ * browser support for Java 5 and below, you will have to install your own
+ * handler to do so.
+ *
+ * @param handler The new handler.
+ * @see #getExternalURLHandler()
+ */
+ public void setExternalURLHandler(ExternalURLHandler handler) {
+ this.externalURLHandler = handler;
+ }
+
+
+ /**
+ * Sets whether the "description window" should be shown beside the
+ * completion window.
+ *
+ * @param show Whether to show the description window.
+ * @see #getShowDescWindow()
+ */
+ public void setShowDescWindow(boolean show) {
+ showDescWindow = show;
+ }
+
+
+ /**
+ * Sets the keystroke that should be used to trigger the autocomplete
+ * popup window.
+ *
+ * @param ks The keystroke.
+ * @throws IllegalArgumentException If <code>ks</code> is <code>null</code>.
+ * @see #getTriggerKey()
+ */
+ public void setTriggerKey(KeyStroke ks) {
+ if (ks==null) {
+ throw new IllegalArgumentException("trigger key cannot be null");
+ }
+ if (!ks.equals(trigger)) {
+ if (textComponent!=null) {
+ // Put old trigger action back.
+ uninstallTriggerKey();
+ // Grab current action for new trigger and replace it.
+ installTriggerKey(ks);
+ }
+ trigger = ks;
+ }
+ }
+
+
+ /**
+ * Uninstalls this autocompletion from its text component. If it is not
+ * installed on any text component, nothing happens.
+ *
+ * @see #install(JTextComponent)
+ */
+ public void uninstall() {
+ if (textComponent!=null) {
+ hidePopupWindow(); // Unregisters listeners, actions, etc.
+ uninstallTriggerKey();
+ textComponent.removeHierarchyListener(this);
+ if (parentWindow!=null) {
+ parentWindow.removeComponentListener(this);
+ }
+ textComponent = null;
+ }
+ }
+
+
+ /**
+ * Replaces the "trigger key" action with the one that was there
+ * before autocompletion was installed.
+ *
+ * @see #installTriggerKey(KeyStroke)
+ */
+ private void uninstallTriggerKey() {
+ Keymap km = textComponent.getKeymap();
+ if (oldTriggerAction!=null) {
+ km.addActionForKeyStroke(trigger, oldTriggerAction);
+ }
+ else {
+ km.removeKeyStrokeBinding(trigger);
+ }
+ }
+
+
+ /**
+ * Updates the LookAndFeel of the popup window. Applications can call
+ * this method as appropriate if they support changing the LookAndFeel
+ * at runtime.
+ */
+ public void updateUI() {
+ if (popupWindow!=null) {
+ popupWindow.updateUI();
+ }
+ }
+
+
+ /**
+ * The <code>Action</code> that displays the popup window if autocompletion
+ * is enabled.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+ class AutoCompleteAction extends AbstractAction {
+
+ public void actionPerformed(ActionEvent e) {
+ if (isAutoCompleteEnabled()) {
+ refreshPopupWindow();
+ }
+ else if (oldTriggerAction!=null) {
+ oldTriggerAction.actionPerformed(e);
+ }
+ }
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/Completion.java b/src/org/fife/ui/autocomplete/Completion.java
new file mode 100644
index 0000000..2afebbe
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/Completion.java
@@ -0,0 +1,95 @@
+/*
+ * 12/21/2008
+ *
+ * Completion.java - Represents a single completion choice.
+ * 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 javax.swing.text.JTextComponent;
+
+
+/**
+ * Represents a completion choice.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ * @see AbstractCompletion
+ */
+public interface Completion {
+
+
+ /**
+ * Returns the portion of this completion that has already been entered
+ * into the text component. The match is case-insensitive.<p>
+ *
+ * This is a convenience method for:
+ * <code>getProvider().getAlreadyEntered(comp)</code>.
+ *
+ * @param comp The text component.
+ * @return The already-entered portion of this completion.
+ */
+ public String getAlreadyEntered(JTextComponent comp);
+
+
+ /**
+ * Returns the text that the user has to (start) typing for this completion
+ * to be offered. Note that this will usually be the same value as
+ * {@link #getReplacementText()}, but not always (a completion could be
+ * a way to implement shorthand, for example, "<code>sysout</code>" mapping
+ * to "<code>System.out.println(</code>").
+ *
+ * @return The text the user has to (start) typing for this completion to
+ * be offered.
+ * @see #getReplacementText()
+ */
+ public String getInputText();
+
+
+ /**
+ * Returns the provider that returned this completion.
+ *
+ * @return The provider.
+ */
+ public CompletionProvider getProvider();
+
+
+ /**
+ * Returns the text to insert as the result of this auto-completion. This
+ * is the "complete" text, including any text that replaces what the user
+ * has already typed.
+ *
+ * @return The replacement text.
+ * @see #getInputText()
+ */
+ public String getReplacementText();
+
+
+ /**
+ * Returns the description of this auto-complete choice. This can be
+ * used in a popup "description window."
+ *
+ * @return This item's description. This should be HTML. It may be
+ * <code>null</code> if there is no description for this
+ * completion.
+ */
+ public String getSummary();
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/CompletionListModel.java b/src/org/fife/ui/autocomplete/CompletionListModel.java
new file mode 100644
index 0000000..2363617
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/CompletionListModel.java
@@ -0,0 +1,99 @@
+/*
+ * 12/22/2008
+ *
+ * CompletionListModel.java - A model that allows bulk addition of elements.
+ * 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.util.ArrayList;
+import java.util.Collection;
+import javax.swing.AbstractListModel;
+
+
+/**
+ * A list model implementation that allows the bulk addition of elements.
+ * This is the only feature missing from <code>DefaultListModel</code> that
+ * we need.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+class CompletionListModel extends AbstractListModel {
+
+ /**
+ * Container for items in this model.
+ */
+ private ArrayList delegate;
+
+
+ /**
+ * Constructor.
+ */
+ public CompletionListModel() {
+ delegate = new ArrayList();
+ }
+
+
+ /**
+ * Removes all of the elements from this list. The list will
+ * be empty after this call returns (unless it throws an exception).
+ *
+ * @see #setContents(Collection)
+ */
+ public void clear() {
+ int end = delegate.size()-1;
+ delegate.clear();
+ if (end >= 0) {
+ fireIntervalRemoved(this, 0, end);
+ }
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getElementAt(int index) {
+ return delegate.get(index);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getSize() {
+ return delegate.size();
+ }
+
+
+ /**
+ * Sets the contents of this model. All previous contents are removed.
+ *
+ * @param contents The new contents of this model.
+ */
+ public void setContents(Collection contents) {
+ clear();
+ if (contents.size()>0) {
+ delegate.addAll(contents);
+ fireIntervalAdded(this, 0, contents.size());
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/CompletionProvider.java b/src/org/fife/ui/autocomplete/CompletionProvider.java
new file mode 100644
index 0000000..26b86ea
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/CompletionProvider.java
@@ -0,0 +1,104 @@
+/*
+ * 12/21/2008
+ *
+ * CompletionProvider.java - Provides autocompletion values based on the
+ * text currently in a text component.
+ * 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.util.List;
+
+import javax.swing.ListCellRenderer;
+import javax.swing.text.JTextComponent;
+
+
+/**
+ * Provides autocompletion values to an {@link AutoCompletion}.<p>
+ *
+ * Completion providers can have an optional parent. Parents are searched for
+ * completions when their children are. This allows for chaining of completion
+ * providers.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+public interface CompletionProvider {
+
+
+ /**
+ * Returns the text just before the current caret position that could be
+ * the start of something auto-completable.
+ *
+ * @param comp The text component.
+ * @return The text.
+ */
+ public String getAlreadyEnteredText(JTextComponent comp);
+
+
+ /**
+ * Gets the possible completions for the text component at the current
+ * caret position.
+ *
+ * @param comp The text component.
+ * @return The list of {@link Completion}s. If no completions are
+ * available, an empty list is returned.
+ */
+ public List getCompletions(JTextComponent comp);
+
+
+ /**
+ * Returns the cell renderer for completions returned from this provider.
+ *
+ * @return The cell renderer, or <code>null</code> if the default should
+ * be used.
+ * @see #setListCellRenderer(ListCellRenderer)
+ */
+ public ListCellRenderer getListCellRenderer();
+
+
+ /**
+ * Returns the parent completion provider.
+ *
+ * @return The parent completion provider.
+ * @see #setParent(CompletionProvider)
+ */
+ public CompletionProvider getParent();
+
+
+ /**
+ * Sets the renderer to use when displaying completion choices.
+ *
+ * @param r The renderer to use.
+ * @see #getListCellRenderer()
+ */
+ public void setListCellRenderer(ListCellRenderer r);
+
+
+ /**
+ * Sets the parent completion provider.
+ *
+ * @param parent The parent provider. <code>null</code> means there will
+ * be no parent provider.
+ * @see #getParent()
+ */
+ public void setParent(CompletionProvider parent);
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/DelegatingCellRenderer.java b/src/org/fife/ui/autocomplete/DelegatingCellRenderer.java
new file mode 100644
index 0000000..54a470c
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/DelegatingCellRenderer.java
@@ -0,0 +1,60 @@
+/*
+ * 12/22/2008
+ *
+ * DelegatingCellRenderer.java - A renderer for Completions that will delegate
+ * to the Completion's provider's renderer, if there is one.
+ * 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.Component;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JList;
+import javax.swing.ListCellRenderer;
+
+
+/**
+ * List cell renderer that delegates to a {@link CompletionProvider}'s
+ * renderer, if it has one. If it doesn't, it simply renders
+ * <code>(({@link Completion})value).toString()</code>.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+class DelegatingCellRenderer extends DefaultListCellRenderer {
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Component getListCellRendererComponent(JList list, Object value,
+ int index, boolean selected, boolean hasFocus) {
+ Completion c = (Completion)value;
+ CompletionProvider p = c.getProvider();
+ ListCellRenderer r = p.getListCellRenderer();
+ if (r!=null) {
+ return r.getListCellRendererComponent(list, value, index, selected,
+ hasFocus);
+ }
+ return super.getListCellRendererComponent(list, value, index, selected,
+ hasFocus);
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/ExternalURLHandler.java b/src/org/fife/ui/autocomplete/ExternalURLHandler.java
new file mode 100644
index 0000000..c8234d8
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/ExternalURLHandler.java
@@ -0,0 +1,51 @@
+/*
+ * 12/23/2008
+ *
+ * ExternalURLHandler.java - Implementations can be registered as a callback
+ * to handle the user clicking on external URL's.
+ * 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.net.URL;
+
+
+/**
+ * A callback for when an external URL is clicked in the description window.
+ * If no handler is installed, and if running in Java 6, the system default
+ * web browser is used to open the URL. If not running Java 6, nothing will
+ * happen. If you want browser support for pre-Java 6 JRE's, you will need
+ * to register one of these callbacks on your {@link AutoCompletion}.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ * @see AutoCompletion#setExternalURLHandler(ExternalURLHandler)
+ */
+public interface ExternalURLHandler {
+
+
+ /**
+ * Called when an external URL is clicked in the description window.
+ *
+ * @param url The URL.
+ */
+ public void urlClicked(URL url);
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/FunctionCompletion.java b/src/org/fife/ui/autocomplete/FunctionCompletion.java
new file mode 100644
index 0000000..74352f7
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/FunctionCompletion.java
@@ -0,0 +1,213 @@
+/*
+ * 12/22/2008
+ *
+ * FunctionCompletion.java - A completion representing a function.
+ * 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.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * A completion choice representing a function.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+public class FunctionCompletion extends VariableCompletion {
+
+ /**
+ * Parameters to the function.
+ */
+ private List params;
+
+
+ /**
+ * Constructor.
+ *
+ * @param provider The parent provider.
+ * @param name The name of this function.
+ * @param returnType The return type of this function.
+ */
+ public FunctionCompletion(CompletionProvider provider, String name,
+ String returnType) {
+ super(provider, name, returnType);
+ }
+
+
+ protected void addDefinitionString(StringBuffer sb) {
+
+ sb.append("<html><b>");
+
+ // Add the return type if applicable (C macros like NULL have no type).
+ if (getType()!=null) {
+ sb.append(getType());
+ 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);
+ sb.append(param.toString());
+ if (i<params.size()-1) {
+ sb.append(", ");
+ }
+ }
+ sb.append(')');
+
+ sb.append("</b>");
+
+ }
+
+
+ /**
+ * Adds HTML describing the parameters to this function to a buffer.
+ *
+ * @param sb The buffer to append to.
+ */
+ protected void addParameters(StringBuffer sb) {
+
+ if (params!=null && params.size()>0) {
+ sb.append("<b>Parameters:</b><br>"); // TODO: Localize me
+ for (int i=0; i<getParamCount(); i++) {
+ Parameter param = getParam(i);
+ sb.append(" <b>");
+ sb.append(param.getName()!=null ? param.getName() :
+ param.getType());
+ sb.append("</b> ");
+ String desc = param.getDescription();
+ if (desc!=null) {
+ sb.append(desc);
+ }
+ sb.append("<br>");
+ }
+ sb.append("<br><br>");
+ }
+
+ // TODO: Add description of return type.
+
+ }
+
+
+ /**
+ * Returns the specified {@link Parameter}.
+ *
+ * @param index The index of the parameter to retrieve.
+ * @return The parameter.
+ * @see #getParamCount()
+ */
+ public Parameter getParam(int index) {
+ return (Parameter)params.get(index);
+ }
+
+
+ /**
+ * Returns the number of parameters to this function.
+ *
+ * @return The number of parameters to this function.
+ * @see #getParam(int)
+ */
+ public int getParamCount() {
+ return params==null ? 0 : params.size();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getSummary() {
+ StringBuffer sb = new StringBuffer();
+ addDefinitionString(sb);
+ possiblyAddDescription(sb);
+ addParameters(sb);
+ possiblyAddDefinedIn(sb);
+ return sb.toString();
+ }
+
+
+ /**
+ * Sets the parameters to this function.
+ *
+ * @param params The parameters. This should be a list of
+ * {@link Parameter}s.
+ * @see #getParam(int)
+ */
+ public void setParams(List params) {
+ // Deep copy so parsing can re-use its array.
+ this.params = new ArrayList(params);
+ }
+
+
+ /**
+ * 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/ProceduralLanguageCellRenderer.java b/src/org/fife/ui/autocomplete/ProceduralLanguageCellRenderer.java
new file mode 100644
index 0000000..23f8479
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/ProceduralLanguageCellRenderer.java
@@ -0,0 +1,193 @@
+/*
+ * 12/23/2008
+ *
+ * ProceduralLanguageCellRenderer.java - Cell renderer for procedural
+ * languages.
+ * 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.Component;
+import java.awt.Font;
+
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JList;
+
+
+/**
+ * A cell renderer for {@link ProceduralLanguageCompletionProvider}.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+public class ProceduralLanguageCellRenderer extends DefaultListCellRenderer {
+
+ /**
+ * The alternating background color.
+ */
+ private Color altBG;
+
+ /**
+ * The font to use when rendering items.
+ */
+ private Font font;
+
+
+ /**
+ * Constructor.
+ */
+ public ProceduralLanguageCellRenderer() {
+ font = new Font("Monospaced", Font.PLAIN, 12);
+ altBG = new Color(248,248,248);
+ }
+
+
+ /**
+ * Returns the background color to use on alternating lines.
+ *
+ * @return The altnernate background color. If this is <code>null</code>,
+ * alternating colors are not used.
+ * @see #setAlternateBackground(Color)
+ */
+ public Color getAlternateBackground() {
+ return altBG;
+ }
+
+
+ /**
+ * Returns the font used when rendering completions.
+ *
+ * @return The font.
+ * @see #setDisplayFont(Font)
+ */
+ public Font getDisplayFont() {
+ return font;
+ }
+
+
+ /**
+ * Returns the renderer.
+ *
+ * @param list The list of choices being rendered.
+ * @param value The {@link Completion} being rendered.
+ * @param index The index into <code>list</code> being rendered.
+ * @param selected Whether the item is selected.
+ * @param hasFocus Whether the item has focus.
+ */
+ public Component getListCellRendererComponent(JList list, Object value,
+ int index, boolean selected, boolean hasFocus) {
+
+ super.getListCellRendererComponent(list,value,index,selected,hasFocus);
+// System.out.println(index);
+ setFont(font); // Overrides super's setFont(list.getFont()).
+
+ if (value instanceof FunctionCompletion) {
+ FunctionCompletion fc = (FunctionCompletion)value;
+ StringBuffer sb = new StringBuffer("<html><b><em>" + fc.getName() + "</em></b>");
+ sb.append('(');
+ int paramCount = fc.getParamCount();
+ for (int i=0; i<paramCount; i++) {
+ FunctionCompletion.Parameter param = fc.getParam(i);
+ String type = param.getType();
+ if (type!=null) {
+ if (!selected) {
+ sb.append("<font color='#aa0077'>");
+ }
+ sb.append(type);
+ if (!selected) {
+ sb.append("</font>");
+ }
+ }
+ String name = param.getName();
+ if (name!=null) {
+ if (type!=null) {
+ sb.append(' ');
+ sb.append(name);
+ }
+ }
+ if (i<paramCount-1) {
+ sb.append(", ");
+ }
+ }
+ sb.append(") : ");
+ if (!selected) {
+ sb.append("<font color='#a0a0ff'>");
+ }
+ sb.append(fc.getType());
+ if (!selected) {
+ sb.append("</font>");
+ }
+ setText(sb.toString());
+ }
+
+ else if (value instanceof VariableCompletion) {
+ VariableCompletion vc = (VariableCompletion)value;
+ StringBuffer sb = new StringBuffer("<html><b><em>" + vc.getName() + "</em></b>");
+ if (vc.getType()!=null) {
+ sb.append(" : ");
+ if (!selected) {
+ sb.append("<font color='#a0a0ff'>");
+ }
+ sb.append(vc.getType());
+ if (!selected) {
+ sb.append("</font>");
+ }
+ }
+ setText(sb.toString());
+ }
+
+ if (!selected && (index&1)==0 && altBG!=null) {
+ setBackground(altBG);
+ }
+
+// if (index==238) {
+// Thread.dumpStack();
+// }
+//setIcon(varIcon);
+ return this;
+
+ }
+
+
+ /**
+ * Sets the background color to use on alternating lines.
+ *
+ * @param altBG The new alternate background color. If this is
+ * <code>null</code>, alternating lines will not use different
+ * background colors.
+ * @see #getAlternateBackground()
+ */
+ public void setAlternateBackground(Color altBG) {
+ this.altBG = altBG;
+ }
+
+
+ /**
+ * Sets the font to use when rendering completion items.
+ *
+ * @param font The font to use.
+ * @see #getDisplayFont()
+ */
+ public void setDisplayFont(Font font) {
+ this.font = font;
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/ProceduralLanguageCompletionProvider.java b/src/org/fife/ui/autocomplete/ProceduralLanguageCompletionProvider.java
new file mode 100644
index 0000000..b9194f6
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/ProceduralLanguageCompletionProvider.java
@@ -0,0 +1,347 @@
+/*
+ * 12/21/2008
+ *
+ * ProceduralLanguageCompletionProvider.java - A provider useful for procedural
+ * languages, such as C.
+ * 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.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.ImageIcon;
+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;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.DefaultHandler;
+
+
+/**
+ * A completion provider that reads an XML file for a procedural language API
+ * (such as C). That XML file can define the following things:
+ *
+ * <ul>
+ * <li>Functions, their parameters, and return types</li>
+ * <li>Constants (such as <tt>#define</tt>s)</li>
+ * <li>(Global) variables</li>
+ * </ul>
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ *
+ */
+/*
+ * TODO: Make chars '(', ')' and ',' configurable.
+ */
+public class ProceduralLanguageCompletionProvider
+ extends AbstractCompletionProvider {
+
+ private Segment seg;
+
+ private String[] dataTypes;
+ private String dataTypeFG;
+ private boolean colorizeHeader;
+
+
+ public ProceduralLanguageCompletionProvider(String fileName) {
+
+ completions = new ArrayList();
+ seg = new Segment();
+
+ setColorizeHeader(false);
+
+ long start = System.currentTimeMillis();
+
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ XMLParser handler = new XMLParser();
+ try {
+ InputStream in = null;
+ File file = new File(fileName);
+ if (file.isFile()) {
+ in = new FileInputStream(file);
+ }
+ else {
+ ClassLoader cl = getClass().getClassLoader();
+ in = cl.getResourceAsStream(fileName);
+ }
+ try {
+ SAXParser saxParser = factory.newSAXParser();
+ saxParser.parse(in, handler);
+ this.completions = handler.getCompletions();
+ Collections.sort(this.completions);
+ } finally {
+ in.close();
+ }
+ } catch (Throwable err) {
+ err.printStackTrace ();
+ }
+
+ long time = System.currentTimeMillis() - start;
+ System.out.println("XML loaded in: " + time + "ms");
+
+ setListCellRenderer(new ProceduralLanguageCellRenderer());
+
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getAlreadyEnteredText(JTextComponent comp) {
+
+ Document doc = comp.getDocument();
+
+ int dot = comp.getCaretPosition();
+ Element root = doc.getDefaultRootElement();
+ int index = root.getElementIndex(dot);
+ Element elem = root.getElement(index);
+ int start = elem.getStartOffset();
+ int len = dot-start;
+ try {
+ doc.getText(start, len, seg);
+ } catch (BadLocationException ble) {
+ ble.printStackTrace();
+ return EMPTY_STRING;
+ }
+
+ int segEnd = seg.offset + len;
+ start = segEnd - 1;
+ while (start>=seg.offset && isValidChar(seg.array[start])) {
+ start--;
+ }
+ start++;
+
+ len = segEnd - start;
+ return len==0 ? EMPTY_STRING : new String(seg.array, start, len);
+
+ }
+
+
+ private String getColorFor(String text) {
+ int index = dataTypes==null ? -1 : Arrays.binarySearch(dataTypes, text);
+ return index>=0 ? dataTypeFG : null;
+ }
+
+
+ /**
+ * Returns whether the description area should have its header information
+ * syntax highlighted.
+ *
+ * @return Whether to color the description area's header.
+ * @see #setColorizeHeader(boolean)
+ */
+ public boolean getColorizeHeader() {
+ return colorizeHeader;
+ }
+
+
+ /**
+ * Sets whether the header text of the description area should be
+ * syntax highlighted.
+ *
+ * @param colorize Whether to colorize the header information in the
+ * description area.
+ * @see #getColorizeHeader()
+ */
+ public void setColorizeHeader(boolean colorize) {
+ colorizeHeader = colorize;
+ }
+
+
+ /**
+ * Sets the color to use for data types in the header of a description
+ * window.
+ *
+ * @param fg The foreground color to use.
+ * @see #setDataTypes(String[])
+ * @see #getColorizeHeader()
+ */
+ public void setDataTypeForeground(Color fg) {
+ dataTypeFG = Util.getHexString(fg);
+ }
+
+
+ /**
+ * Sets the identifiers to color as data types in the header of a
+ * description window.
+ *
+ * @param types The identifiers for data types. If this is
+ * <code>null</code>, nothing will be colorized as a data type.
+ * @see #setDataTypeForeground(Color)
+ * @see #getColorizeHeader()
+ */
+ public void setDataTypes(String[] types) {
+ if (types==null) {
+ dataTypes = null;
+ }
+ else {
+ dataTypes = (String[])types.clone();
+ Arrays.sort(dataTypes, String.CASE_INSENSITIVE_ORDER);
+ }
+ }
+
+
+ /**
+ * Returns whether the specified character is valid in an auto-completion.
+ * Subclasses can override this method if their language supports a
+ * different set of valid chars for auto-completable items.
+ *
+ * @param ch The character.
+ * @return Whether the character is valid.
+ */
+ protected boolean isValidChar(char ch) {
+ return Character.isLetterOrDigit(ch) || ch=='_';
+ }
+
+
+ /**
+ * Parser for an XMl file describing a procedural language such as C.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+ private class XMLParser extends DefaultHandler {
+
+ private List completions;
+
+ private String name;
+ private String type;
+ private String returnType;
+ private StringBuffer desc;
+ private List params;
+ private String definedIn;
+ private boolean doingKeywords;
+ private boolean inKeyword;
+ private boolean gettingDesc;
+ private boolean gettingParams;
+
+ public XMLParser() {
+ completions = new ArrayList();
+ params = new ArrayList(1);
+ desc = new StringBuffer();
+ }
+
+ public void characters(char[] ch, int start, int length) {
+ if (gettingDesc) {
+ desc.append(ch, start, length);
+ }
+ }
+
+ public void endElement(String uri, String localName, String qName) {
+
+ if ("keywords".equals(qName)) {
+ doingKeywords = false;
+ }
+
+ else if (doingKeywords) {
+
+ if ("keyword".equals(qName)) {
+ Completion c = null;
+ if ("function".equals(type)) {
+ FunctionCompletion fc = new FunctionCompletion(
+ ProceduralLanguageCompletionProvider.this, name, returnType);
+ fc.setDescription(desc.toString());
+ fc.setParams(params);
+ fc.setDefinedIn(definedIn);
+ c = fc;
+ }
+ else if ("constant".equals(type)) {
+ VariableCompletion vc = new VariableCompletion(
+ ProceduralLanguageCompletionProvider.this, name, returnType);
+ vc.setDescription(desc.toString());
+ vc.setDefinedIn(definedIn);
+ c = vc;
+ }
+ else {
+ throw new InternalError("Unexpected type: " + type);
+ }
+ completions.add(c);
+ inKeyword = false;
+ }
+ else if (inKeyword) {
+ if ("desc".equals(qName)) {
+ gettingDesc = false;
+ }
+ else if ("params".equals(qName)) {
+ gettingParams = false;
+ }
+ }
+
+ }
+
+ }
+
+ public List getCompletions() {
+ return completions;
+ }
+
+ public void startElement(String uri, String localName, String qName, Attributes attrs) {
+ if ("keywords".equals(qName)) {
+ doingKeywords = true;
+ }
+ else if (doingKeywords) {
+ if ("keyword".equals(qName)) {
+ name = attrs.getValue("name");
+ type = attrs.getValue("type");
+ returnType = attrs.getValue("returnType");
+ params.clear();
+ definedIn = attrs.getValue("definedIn");
+ inKeyword = true;
+ }
+ else if (inKeyword) {
+ if ("desc".equals(qName)) {
+ gettingDesc = true;
+ desc.setLength(0);
+ }
+ else if ("params".equals(qName)) {
+ gettingParams = true;
+ }
+ else if (gettingParams) {
+ if ("param".equals(qName)) {
+ String name = attrs.getValue("name");
+ String type = attrs.getValue("type");
+ FunctionCompletion.Parameter param =
+ new FunctionCompletion.Parameter(type, name);
+ // TODO: Get desc.
+ params.add(param);
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/ShorthandCompletion.java b/src/org/fife/ui/autocomplete/ShorthandCompletion.java
new file mode 100644
index 0000000..1070bd5
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/ShorthandCompletion.java
@@ -0,0 +1,81 @@
+/*
+ * 12/22/2008
+ *
+ * ShorhandCompletion.java - A completion that is shorthand for some other
+ * text.
+ * 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;
+
+
+/**
+ * A completion where the input text is shorthand for (really, just different
+ * than) the actual text to be inserted. For example, the input text
+ * "<code>sysout</code>" could be associated with the completion
+ * "<code>System.out.println(</code>" in Java.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+public class ShorthandCompletion extends WordCompletion {
+
+ /**
+ * The text the user can start typing that will match this completion.
+ */
+ private String inputText;
+
+
+ /**
+ * Constructor.
+ *
+ * @param provider The provider that returns this completion.
+ * @param inputText The text the user inputs to get this completion.
+ * @param replacementText The replacement text of the completion.
+ */
+ public ShorthandCompletion(CompletionProvider provider, String inputText,
+ String replacementText) {
+ super(provider, replacementText);
+ this.inputText = inputText;
+ }
+
+
+ /**
+ * Returns the replacement text. Subclasses can override this method to
+ * return a more detailed description.
+ *
+ * @return A description of this completion (the text that will be
+ * inserted).
+ * @see #getReplacementText()
+ */
+ public String getSummary() {
+ return "<html><body><tt>" + getReplacementText();
+ }
+
+
+ /**
+ * Returns the text the user must start typing to get this completion.
+ *
+ * @return The text the user must start to input.
+ */
+ public String getInputText() {
+ return inputText;
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/SizeGrip.java b/src/org/fife/ui/autocomplete/SizeGrip.java
new file mode 100644
index 0000000..0552b82
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/SizeGrip.java
@@ -0,0 +1,193 @@
+/*
+ * 12/23/2008
+ *
+ * SizeGrip.java - A size grip component that sits at the bottom of the window,
+ * allowing the user to easily resize that window.
+ * 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.ComponentOrientation;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.awt.Window;
+import java.awt.event.MouseEvent;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+
+
+/**
+ * A component that allows its parent window to be resizable, similar to the
+ * size grip seen on status bars.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+class SizeGrip extends JPanel {
+
+
+ public SizeGrip() {
+ MouseHandler adapter = new MouseHandler();
+ addMouseListener(adapter);
+ addMouseMotionListener(adapter);
+ possiblyFixCursor(ComponentOrientation.getOrientation(getLocale()));
+ setPreferredSize(new Dimension(16, 16));
+ }
+
+
+ /**
+ * Paints this panel.
+ *
+ * @param g The graphics context.
+ */
+ protected void paintComponent(Graphics g) {
+
+ super.paintComponent(g);
+
+ Dimension dim = getSize();
+ Color c1 = UIManager.getColor("Label.disabledShadow");
+ Color c2 = UIManager.getColor("Label.disabledForeground");
+
+ ComponentOrientation orientation = getComponentOrientation();
+
+ if (orientation.isLeftToRight()) {
+ int width = dim.width -= 3;
+ int height = dim.height -= 3;
+ g.setColor(c1);
+ g.fillRect(width-9,height-1, 3,3);
+ g.fillRect(width-5,height-1, 3,3);
+ g.fillRect(width-1,height-1, 3,3);
+ g.fillRect(width-5,height-5, 3,3);
+ g.fillRect(width-1,height-5, 3,3);
+ g.fillRect(width-1,height-9, 3,3);
+ g.setColor(c2);
+ g.fillRect(width-9,height-1, 2,2);
+ g.fillRect(width-5,height-1, 2,2);
+ g.fillRect(width-1,height-1, 2,2);
+ g.fillRect(width-5,height-5, 2,2);
+ g.fillRect(width-1,height-5, 2,2);
+ g.fillRect(width-1,height-9, 2,2);
+ }
+ else {
+ int height = dim.height -= 3;
+ g.setColor(c1);
+ g.fillRect(10,height-1, 3,3);
+ g.fillRect(6,height-1, 3,3);
+ g.fillRect(2,height-1, 3,3);
+ g.fillRect(6,height-5, 3,3);
+ g.fillRect(2,height-5, 3,3);
+ g.fillRect(2,height-9, 3,3);
+ g.setColor(c2);
+ g.fillRect(10,height-1, 2,2);
+ g.fillRect(6,height-1, 2,2);
+ g.fillRect(2,height-1, 2,2);
+ g.fillRect(6,height-5, 2,2);
+ g.fillRect(2,height-5, 2,2);
+ g.fillRect(2,height-9, 2,2);
+ }
+
+ }
+
+
+ /**
+ * Overridden to ensure that the cursor for this component is appropriate
+ * for the orientation.
+ *
+ * @param o The new orientation.
+ */
+ public void applyComponentOrientation(ComponentOrientation o) {
+ possiblyFixCursor(o);
+ super.applyComponentOrientation(o);
+ }
+
+
+ /**
+ * Ensures that the cursor for this component is appropriate for the
+ * orientation.
+ *
+ * @param o The new orientation.
+ */
+ protected void possiblyFixCursor(ComponentOrientation o) {
+ int cursor = Cursor.NE_RESIZE_CURSOR;
+ if (o.isLeftToRight()) {
+ cursor = Cursor.NW_RESIZE_CURSOR;
+ }
+ if (cursor!=getCursor().getType()) {
+ setCursor(Cursor.getPredefinedCursor(cursor));
+ }
+ }
+
+
+ /**
+ * Listens for mouse events on this panel and resizes the parent window
+ * appropriately.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+ /*
+ * NOTE: We use SwingUtilities.convertPointToScreen() instead of just using
+ * the locations relative to the corner component because the latter proved
+ * buggy - stretch the window too wide and some kind of arithmetic error
+ * started happening somewhere - our window would grow way too large.
+ */
+ private class MouseHandler extends javax.swing.event.MouseInputAdapter {
+
+ private Point origPos;
+
+ public void mouseDragged(MouseEvent e) {
+ Point newPos = e.getPoint();
+ SwingUtilities.convertPointToScreen(newPos, SizeGrip.this);
+ int xDelta = newPos.x - origPos.x;
+ int yDelta = newPos.y - origPos.y;
+ Window wind = SwingUtilities.getWindowAncestor(SizeGrip.this);
+ if (wind!=null) { // Should always be true
+ int w = wind.getWidth();
+ if (newPos.x>=wind.getX()) {
+ w += xDelta;
+ }
+ int h = wind.getHeight();
+ if (newPos.y>=wind.getY()) {
+ h += yDelta;
+ }
+ wind.setSize(w,h);
+ // invalidate()/revalidate() needed pre-1.6.
+ wind.invalidate();
+ wind.validate();
+ }
+ origPos.setLocation(newPos);
+ }
+
+ public void mousePressed(MouseEvent e) {
+ origPos = e.getPoint();
+ SwingUtilities.convertPointToScreen(origPos, SizeGrip.this);
+ }
+
+ public void mouseReleased(MouseEvent e) {
+ origPos = null;
+ }
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/Util.java b/src/org/fife/ui/autocomplete/Util.java
new file mode 100644
index 0000000..e23aa40
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/Util.java
@@ -0,0 +1,153 @@
+/*
+ * 12/21/2008
+ *
+ * Util.java - Utility methods for the autocompletion package.
+ * 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.lang.reflect.Method;
+import java.net.URI;
+
+
+/**
+ * Utility methods for the autocomplete framework.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+public class Util {
+
+ private static boolean desktopCreationAttempted;
+ private static Object desktop;
+ private static final Object LOCK_DESKTOP_CREATION = new Object();
+
+
+ /**
+ * Returns a hex string for the specified color, suitable for HTML.
+ *
+ * @param c The color.
+ * @return The string representation, in the form "<code>#rrggbb</code>",
+ * or <code>null</code> if <code>c</code> is <code>null</code>.
+ */
+ public static String getHexString(Color c) {
+
+ if (c==null) {
+ return null;
+ }
+
+ StringBuffer sb = new StringBuffer("#");
+ int r = c.getRed();
+ if (r<16) {
+ sb.append('0');
+ }
+ sb.append(Integer.toHexString(r));
+ int g = c.getGreen();
+ if (g<16) {
+ sb.append('0');
+ }
+ sb.append(Integer.toHexString(g));
+ int b = c.getBlue();
+ if (b<16) {
+ sb.append('0');
+ }
+ sb.append(Integer.toHexString(b));
+
+ return sb.toString();
+
+ }
+
+
+ /**
+ * Attempts to open a web browser to the specified URI.
+ *
+ * @param uri The URI to open. If this is <code>null</code>, nothing
+ happens and this method returns <code>false</code>.
+ * @return Whether the operation was successful. This will be
+ * <code>false</code> on JRE's older than 1.6.
+ */
+ public static boolean browse(URI uri) {
+
+ boolean success = false;
+
+ if (uri!=null) {
+ Object desktop = getDesktop();
+ if (desktop!=null) {
+ try {
+ Method m = desktop.getClass().getDeclaredMethod(
+ "browse", new Class[] { URI.class });
+ m.invoke(desktop, new Object[] { uri });
+ success = true;
+ } catch (RuntimeException re) {
+ throw re; // Keep FindBugs happy
+ } catch (Exception e) {
+ // Ignore, just return "false" below.
+ }
+ }
+ }
+
+ return success;
+
+ }
+
+
+ /**
+ * Returns the singleton <code>java.awt.Desktop</code> instance, or
+ * <code>null</code> if it is unsupported on this platform (or the JRE
+ * is older than 1.6).
+ *
+ * @return The desktop, as an {@link Object}.
+ */
+ private static Object getDesktop() {
+
+ synchronized (LOCK_DESKTOP_CREATION) {
+
+ if (!desktopCreationAttempted) {
+
+ desktopCreationAttempted = true;
+
+ try {
+ Class desktopClazz = Class.forName("java.awt.Desktop");
+ Method m = desktopClazz.
+ getDeclaredMethod("isDesktopSupported", null);
+
+ boolean supported = ((Boolean)m.invoke(null, null)).
+ booleanValue();
+ if (supported) {
+ m = desktopClazz.getDeclaredMethod("getDesktop", null);
+ desktop = m.invoke(null, null);
+ }
+
+ } catch (RuntimeException re) {
+ throw re; // Keep FindBugs happy
+ } catch (Exception e) {
+ // Ignore; keeps desktop as null.
+ }
+
+ }
+
+ }
+
+ return desktop;
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/VariableCompletion.java b/src/org/fife/ui/autocomplete/VariableCompletion.java
new file mode 100644
index 0000000..68e7d92
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/VariableCompletion.java
@@ -0,0 +1,193 @@
+/*
+ * 12/22/2008
+ *
+ * VariableCompletion.java - A completion for a variable.
+ * 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;
+
+
+/**
+ * A completion for a variable (or constant) in a programming language.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+public class VariableCompletion extends AbstractCompletion {
+
+ private String name;
+ private String type;
+ private String desc;
+ private String definedIn;
+
+
+ /**
+ * Constructor.
+ *
+ * @param provider The parent provider.
+ * @param name The name of this variable.
+ * @param type The type of this variable (e.g. "<code>int</code>",
+ * "<code>String</code>", etc.).
+ */
+ public VariableCompletion(CompletionProvider provider, String name,
+ String type) {
+ super(provider);
+ this.name = name;
+ this.type = type;
+ }
+
+
+ protected void addDefinitionString(StringBuffer sb) {
+
+ sb.append("<html><b>");
+
+ // Add the return type if applicable (C macros like NULL have no type).
+ if (type!=null) {
+ sb.append(type);
+ sb.append(' ');
+ }
+
+ // Add the item being described's name.
+ sb.append(name);
+
+ sb.append("</b>");
+
+ }
+
+
+ /**
+ * Returns where this variable is defined.
+ *
+ * @return Where this variable is defined.
+ * @see #setDefinedIn(String)
+ */
+ public String getDefinedIn() {
+ return definedIn;
+ }
+
+
+ /**
+ * Returns a short description of this variable. This should be an
+ * HTML snippet.
+ *
+ * @return A short description of this variable. This may be
+ * <code>null</code>.
+ * @see #setDescription(String)
+ */
+ public String getDescription() {
+ return desc;
+ }
+
+
+ /**
+ * Returns the name of this variable.
+ *
+ * @return The name.
+ */
+ public String getName() {
+ return name;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getSummary() {
+ StringBuffer sb = new StringBuffer();
+ addDefinitionString(sb);
+ possiblyAddDescription(sb);
+ possiblyAddDefinedIn(sb);
+ return sb.toString();
+ }
+
+
+ /**
+ * Returns the type of this variable.
+ *
+ * @return The type.
+ */
+ public String getType() {
+ return type;
+ }
+
+
+ /**
+ * Returns the name of this variable.
+ *
+ * @return The text to autocomplete with.
+ */
+ public String getReplacementText() {
+ return getName();
+ }
+
+
+ /**
+ * Adds some HTML describing where this variable is defined, if this
+ * information is known.
+ *
+ * @param sb The buffer to append to.
+ */
+ protected void possiblyAddDefinedIn(StringBuffer sb) {
+ if (definedIn!=null) {
+ sb.append("<hr>Defined in:"); // TODO: Localize me
+ sb.append(" <em>").append(definedIn).append("</em>");
+ }
+ }
+
+
+ /**
+ * Adds the description text as HTML to a buffer, if a description is
+ * defined.
+ *
+ * @param sb The buffer to append to.
+ */
+ protected void possiblyAddDescription(StringBuffer sb) {
+ if (desc!=null) {
+ sb.append("<hr><br>");
+ sb.append(desc);
+ sb.append("<br><br><br>");
+ }
+ }
+
+
+ /**
+ * Sets where this variable is defined.
+ *
+ * @param definedIn Where this variable is defined.
+ * @see #getDefinedIn()
+ */
+ public void setDefinedIn(String definedIn) {
+ this.definedIn = definedIn;
+ }
+
+
+ /**
+ * Sets the short description of this variable. This should be an
+ * HTML snippet.
+ *
+ * @param desc A short description of this variable. This may be
+ * <code>null</code>.
+ * @see #getDescription()
+ */
+ public void setDescription(String desc) {
+ this.desc = desc;
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/WordCompletion.java b/src/org/fife/ui/autocomplete/WordCompletion.java
new file mode 100644
index 0000000..a507d91
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/WordCompletion.java
@@ -0,0 +1,73 @@
+/*
+ * 12/21/2008
+ *
+ * WordCompletion.java - A completion for a single word.
+ * 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;
+
+
+/**
+ * A completion for a single word. Input that matches any number of the
+ * leading characters of this completion will match it.<p>
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+public class WordCompletion extends AbstractCompletion {
+
+ /**
+ * The word that can be auto-completed.
+ */
+ private String replacementText;
+
+
+ /**
+ * Constructor.
+ *
+ * @param provider The provider that returns this completion.
+ * @param replacementText The text to be made auto-completable.
+ */
+ public WordCompletion(CompletionProvider provider, String replacementText) {
+ super(provider);
+ this.replacementText = replacementText;
+ }
+
+
+ /**
+ * Returns <code>null</code> always. Subclasses can override this method
+ * if they wish to provide a description.
+ *
+ * @return This item's description. This will always be
+ * <code>null</code>.
+ */
+ public String getSummary() {
+ return null;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getReplacementText() {
+ return replacementText;
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/WordCompletionProvider.java b/src/org/fife/ui/autocomplete/WordCompletionProvider.java
new file mode 100644
index 0000000..70e68ad
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/WordCompletionProvider.java
@@ -0,0 +1,130 @@
+/*
+ * 12/21/2008
+ *
+ * WordCompletionProvider.java - A simple provider that lets the user choose
+ * from a list of words.
+ * 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.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+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;
+
+
+/**
+ * A completion provider that simply uses a list of words.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ */
+public class WordCompletionProvider extends AbstractCompletionProvider {
+
+ protected Segment seg;
+
+
+ /**
+ * Constructor.
+ *
+ * @param words The words to offer as completion suggestions. This
+ * cannot be <code>null</code>.
+ */
+ public WordCompletionProvider(String[] words) {
+ completions = createCompletions(words);
+ seg = new Segment();
+ }
+
+
+ /**
+ * Creates the completion array for an array of words.
+ *
+ * @param words The words.
+ * @return The <tt>Completion</tt> list. This will be sorted
+ * alphabetically.
+ */
+ protected List createCompletions(String[] words) {
+ List completions = new ArrayList(words.length);
+ for (int i=0; i<words.length; i++) {
+ completions.add(new WordCompletion(this, words[i]));
+ }
+ Collections.sort(completions);
+ return completions;
+ }
+
+
+ /**
+ * Returns the text just before the current caret position that could be
+ * the start of something auto-completable.<p>
+ *
+ * This method returns all characters before the caret that are metched
+ * by {@link #isValidChar(char)}.
+ *
+ * @param comp The text component.
+ * @return The text.
+ */
+ public String getAlreadyEnteredText(JTextComponent comp) {
+
+ Document doc = comp.getDocument();
+
+ int dot = comp.getCaretPosition();
+ Element root = doc.getDefaultRootElement();
+ int index = root.getElementIndex(dot);
+ Element elem = root.getElement(index);
+ int start = elem.getStartOffset();
+ int len = dot-start;
+ try {
+ doc.getText(start, len, seg);
+ } catch (BadLocationException ble) {
+ ble.printStackTrace();
+ return EMPTY_STRING;
+ }
+
+ int segEnd = seg.offset + len;
+ start = segEnd - 1;
+ while (start>=seg.offset && isValidChar(seg.array[start])) {
+ start--;
+ }
+ start++;
+
+ len = segEnd - start;
+ return len==0 ? EMPTY_STRING : new String(seg.array, start, len);
+
+ }
+
+
+ /**
+ * Returns whether the specified character is valid in an auto-completion.
+ * The default implementation is equivalent to
+ * "<code>Character.isLetterOrDigit(ch) || ch=='_'</code>". Subclasses
+ * can override this method to change what characters are matched.
+ *
+ * @param ch The character.
+ * @return Whether the character is valid.
+ */
+ protected boolean isValidChar(char ch) {
+ return Character.isLetterOrDigit(ch) || ch=='_';
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/arrow_left.png b/src/org/fife/ui/autocomplete/arrow_left.png
new file mode 100644
index 0000000..5dc6967
Binary files /dev/null and b/src/org/fife/ui/autocomplete/arrow_left.png differ
diff --git a/src/org/fife/ui/autocomplete/arrow_right.png b/src/org/fife/ui/autocomplete/arrow_right.png
new file mode 100644
index 0000000..b1a1819
Binary files /dev/null and b/src/org/fife/ui/autocomplete/arrow_right.png differ
--
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