pax_global_header00006660000000000000000000000064122070010230014475gustar00rootroot0000000000000052 comment=0c05e045b675dcf2daa1488ee95ec12c7c433d47 autocomplete-2.5.0/000077500000000000000000000000001220700102300142025ustar00rootroot00000000000000autocomplete-2.5.0/.classpath000066400000000000000000000005451220700102300161710ustar00rootroot00000000000000 autocomplete-2.5.0/.gitignore000066400000000000000000000000761220700102300161750ustar00rootroot00000000000000ant-classes bin dist javadoc autocomplete_*_Source.zip autocomplete-2.5.0/.project000066400000000000000000000006041220700102300156510ustar00rootroot00000000000000 AutoComplete org.eclipse.jdt.core.javabuilder org.eclipse.jdt.core.javanature autocomplete-2.5.0/README.md000066400000000000000000000133141220700102300154630ustar00rootroot00000000000000AutoComplete is a code completion library for Swing JTextComponents, with enhanced functionality available when used with its sister project [RSyntaxTextArea](https://github.com/bobbylight/RSyntaxTextArea). Features include a completion choices list that updates as the user types, a "documentation" companion window for displaying documentation about the currently selected completion choice, and parameter assistance (e.g. tabbing through function/method parameters, with tool tip assistance for each argument and a possible list of valid variable completions for each). AutoComplete is available under a [modified BSD license](https://github.com/bobbylight/AutoComplete/blob/master/distfiles/AutoComplete.License.txt). For more information, visit [http://fifesoft.com/autocomplete](http://fifesoft.com/autocomplete). # Example Usage The examle below shows how to add code completion for simple keywords to RSyntaxTextArea. ```java import java.awt.*; import javax.swing.*; import org.fife.ui.autocomplete.*; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.fife.ui.rtextarea.RTextScrollPane; public class AutoCompleteDemo extends JFrame { public AutoCompleteDemo() { JPanel contentPane = new JPanel(new BorderLayout()); RSyntaxTextArea textArea = new RSyntaxTextArea(20, 60); textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); textArea.setCodeFoldingEnabled(true); contentPane.add(new RTextScrollPane(textArea)); // A CompletionProvider is what knows of all possible completions, and // analyzes the contents of the text area at the caret position to // determine what completion choices should be presented. Most instances // of CompletionProvider (such as DefaultCompletionProvider) are designed // so that they can be shared among multiple text components. CompletionProvider provider = createCompletionProvider(); // An AutoCompletion acts as a "middle-man" between a text component // and a CompletionProvider. It manages any options associated with // the auto-completion (the popup trigger key, whether to display a // documentation window along with completion choices, etc.). Unlike // CompletionProviders, instances of AutoCompletion cannot be shared // among multiple text components. AutoCompletion ac = new AutoCompletion(provider); ac.install(textArea); setContentPane(contentPane); setTitle("AutoComplete Demo"); setDefaultCloseOperation(EXIT_ON_CLOSE); pack(); setLocationRelativeTo(null); } /** * Create a simple provider that adds some Java-related completions. */ private CompletionProvider createCompletionProvider() { // A DefaultCompletionProvider is the simplest concrete implementation // of CompletionProvider. This provider has no understanding of // language semantics. It simply checks the text entered up to the // caret position for a match against known completions. This is all // that is needed in the majority of cases. DefaultCompletionProvider provider = new DefaultCompletionProvider(); // Add completions for all Java keywords. A BasicCompletion is just // a straightforward word completion. provider.addCompletion(new BasicCompletion(provider, "abstract")); provider.addCompletion(new BasicCompletion(provider, "assert")); provider.addCompletion(new BasicCompletion(provider, "break")); provider.addCompletion(new BasicCompletion(provider, "case")); // ... etc ... provider.addCompletion(new BasicCompletion(provider, "transient")); provider.addCompletion(new BasicCompletion(provider, "try")); provider.addCompletion(new BasicCompletion(provider, "void")); provider.addCompletion(new BasicCompletion(provider, "volatile")); provider.addCompletion(new BasicCompletion(provider, "while")); // Add a couple of "shorthand" completions. These completions don't // require the input text to be the same thing as the replacement text. provider.addCompletion(new ShorthandCompletion(provider, "sysout", "System.out.println(", "System.out.println(")); provider.addCompletion(new ShorthandCompletion(provider, "syserr", "System.err.println(", "System.err.println(")); return provider; } public static void main(String[] args) { // Instantiate GUI on the EDT. SwingUtilities.invokeLater(new Runnable() { public void run() { try { String laf = UIManager.getSystemLookAndFeelClassName(); UIManager.setLookAndFeel(laf); } catch (Exception e) { /* Never happens */ } new AutoCompleteDemo().setVisible(true); } }); } } ``` # Sister Projects * [RSyntaxTextArea](https://github.com/bobbylight/RSyntaxTextArea) provides syntax highlighting, code folding, and many other features out-of-the-box. * [RSTALanguageSupport](https://github.com/bobbylight/RSTALanguageSupport) - Code completion for RSTA for the following languages: Java, JavaScript, HTML, PHP, JSP, Perl, C, Unix Shell. Built on both RSTA and AutoComplete. * [SpellChecker](https://github.com/bobbylight/SpellChecker) - Adds squiggle-underline spell checking to RSyntaxTextArea. * [RSTAUI](https://github.com/bobbylight/RSTAUI) - Common dialogs needed by text editing applications: Find, Replace, Go to Line, File Properties. # Getting Help * Add an issue on GitHub * Ask in the [project forum](http://fifesoft.com/forum/) * Check the project's [home page](http://fifesoft.com/autocomplete) autocomplete-2.5.0/build.xml000066400000000000000000000064621220700102300160330ustar00rootroot00000000000000 AutoComplete build file autocomplete-2.5.0/distfiles/000077500000000000000000000000001220700102300161705ustar00rootroot00000000000000autocomplete-2.5.0/distfiles/AutoComplete.License.txt000066400000000000000000000027531220700102300227220ustar00rootroot00000000000000Copyright (c) 2012, Robert Futrell All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.autocomplete-2.5.0/distfiles/readme.txt000066400000000000000000000102021220700102300201610ustar00rootroot00000000000000AutoComplete Readme ------------------- Please contact me if you are using AutoComplete in your project! I like to know when people are finding it useful. Please send mail to: robert -at- fifesoft dot com. * About AutoComplete AutoComplete is a Swing library that facilitates adding auto-completion (aka "code completion, "Intellisense") to any JTextComponent. Special integration is added for RSyntaxTextArea (a programmer's text editor, see http://fifesoft.com/rsyntaxtextarea/ for more information), since this feature is commonly needed when editing source code. * Example Usage See the AutoComplete example(s) on the RSyntaxTextArea examples page here: http://fifesoft.com/rsyntaxtextarea/examples/index.php They provide a good example of basic usage of the library, showing how to auto-complete a simple, fixed set of words (function names). Also see the AutoCompleteDemo project, which lives here in SVN: http://svn.fifesoft.com/svn/RSyntaxTextArea/ It provides an example of loading completions from an XML file. It demonstrates a code editor with completion support for the C Standard library, and demos the parameter assistance feature. * Compiling If you wish to compile AutoComplete from source, the easiest way to do so is via the included Ant build script. The default target builds the jar. This project depends on its sister RSyntaxTextArea project. It is recommended that you check the two projects out side by side. Then, to build: cd RSyntaxTextArea ant cd ../AutoComplete ant * License AutoComplete is licensed under a modified BSD license. Please see the included AutoComplete.License.txt file. * Feedback I hope you find AutoComplete useful. Bug reports, feature requests, and just general questions are always welcome. Ways you can submit feedback: * http://forum.fifesoft.com (preferred) Has a forum for AutoComplete and related projects, where you can ask questions and get feedback quickly. * https://github.com/bobbylight/AutoComplete Here you can submit bug reports or enhancement requests, peruse the Wiki, etc. * Other Links * http://fifesoft.com/autocomplete Project home page, which contains general information and example source code. * http://fifesoft.com/rsyntaxtextarea The source code editor you're (probably) already using if you're using this AutoComplete library. * http://javadoc.fifesoft.com/rsyntaxtextarea/ * http://javadoc.fifesoft.com/autocomplete/ API documentation for the package. Note that this *will* change as the library matures. * Thanks The left and right arrow icons in the Help "tooltip" window are from the "Silk" icon set, under the Creative Commons 3.0 License. This is a wonderful icon set, found here: http://famfamfam.com/lab/icons/silk/ The "bullet_black.png" icon is an edited version of "bullet_black.png" in the Silk icon set noted above. It can be considered to be distributed under the same Creative Commons 3.0 License. "osx_sizegrip.png" is a reproduction of the size grip used on native OS X windows. It is distributed under the same modified BSD license as the meat of the AutoComplete library. * Translators Arabic: Mawaheb, Linostar Chinese: Terrance, peter_barnes, Sunquan, sonyichi, zvest Chinese (Traditional): kin Por Fok, liou xiao Dutch: Roel, Sebastiaan, lovepuppy French: Pat, PivWan German: Domenic, bikerpete Hungarian: Zityi, flatron Indonesian: azis, Sonny Italian: Luca, stepagweb Japanese: Josh, izumi, tomoM Korean: Changkyoon, sbrownii Polish: Chris, Maciej Mrug Portuguese (Brazil): Pat, Marcos Parmeggiani, Leandro Russian: Nadiya, Vladimir Spanish: Leonardo, phrodo, daloporhecho Turkish: Cahit, Burak autocomplete-2.5.0/i18n/000077500000000000000000000000001220700102300147615ustar00rootroot00000000000000autocomplete-2.5.0/i18n/org/000077500000000000000000000000001220700102300155505ustar00rootroot00000000000000autocomplete-2.5.0/i18n/org/fife/000077500000000000000000000000001220700102300164615ustar00rootroot00000000000000autocomplete-2.5.0/i18n/org/fife/ui/000077500000000000000000000000001220700102300170765ustar00rootroot00000000000000autocomplete-2.5.0/i18n/org/fife/ui/autocomplete/000077500000000000000000000000001220700102300215775ustar00rootroot00000000000000autocomplete-2.5.0/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow.properties000066400000000000000000000000521220700102300303020ustar00rootroot00000000000000NoDescAvailable=No description available autocomplete-2.5.0/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow_ar.properties000066400000000000000000000001431220700102300307650ustar00rootroot00000000000000NoDescAvailable=\u0644\u0627 \u064a\u0648\u062c\u062f \u0634\u0631\u062d \u0645\u062a\u0627\u062d autocomplete-2.5.0/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow_de.properties000066400000000000000000000000631220700102300307540ustar00rootroot00000000000000NoDescAvailable=Keine Beschreibung verf\u00fcgbar autocomplete-2.5.0/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow_es.properties000066400000000000000000000000641220700102300307740ustar00rootroot00000000000000NoDescAvailable=No hay descripci\u00f3n disponible autocomplete-2.5.0/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow_fr.properties000066400000000000000000000000571220700102300307760ustar00rootroot00000000000000NoDescAvailable=Aucune description disponible autocomplete-2.5.0/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow_hu.properties000066400000000000000000000000731220700102300310010ustar00rootroot00000000000000NoDescAvailable=Nincs el\u00e9rhet\u0151 le\u00edr\u00e1s autocomplete-2.5.0/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow_in.properties000066400000000000000000000000521220700102300307700ustar00rootroot00000000000000NoDescAvailable=No description available autocomplete-2.5.0/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow_it.properties000066400000000000000000000000611220700102300307760ustar00rootroot00000000000000NoDescAvailable=Nessuna descrizione disponibile autocomplete-2.5.0/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow_ja.properties000066400000000000000000000000741220700102300307600ustar00rootroot00000000000000NoDescAvailable=\u8a18\u8ff0\u306f\u4e0d\u660e\u3067\u3059 autocomplete-2.5.0/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow_ko.properties000066400000000000000000000000701220700102300307730ustar00rootroot00000000000000NoDescAvailable=\ud574\ub2f9 \uc124\uba85 \uc5c6\uc74c autocomplete-2.5.0/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow_nl.properties000066400000000000000000000000521220700102300307730ustar00rootroot00000000000000NoDescAvailable=No description available autocomplete-2.5.0/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow_pl.properties000066400000000000000000000000551220700102300310000ustar00rootroot00000000000000NoDescAvailable=Opis nie jest dost\u0119pny autocomplete-2.5.0/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow_pt_BR.properties000066400000000000000000000000731220700102300313730ustar00rootroot00000000000000NoDescAvailable=Nenhuma descri\u00e7\u00e3o dispon\u00edvelautocomplete-2.5.0/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow_ru.properties000066400000000000000000000001251220700102300310110ustar00rootroot00000000000000NoDescAvailable=\u041d\u0435\u0442 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f autocomplete-2.5.0/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow_tr.properties000066400000000000000000000000661220700102300310140ustar00rootroot00000000000000NoDescAvailable=A\u00e7\u0131klama mevcut de\u011fil autocomplete-2.5.0/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow_zh_CN.properties000066400000000000000000000000521220700102300313630ustar00rootroot00000000000000NoDescAvailable=\u6ca1\u6709\u63cf\u8ff0 autocomplete-2.5.0/i18n/org/fife/ui/autocomplete/AutoCompleteDescWindow_zh_TW.properties000066400000000000000000000000521220700102300314150ustar00rootroot00000000000000NoDescAvailable=No description available autocomplete-2.5.0/src/000077500000000000000000000000001220700102300147715ustar00rootroot00000000000000autocomplete-2.5.0/src/org/000077500000000000000000000000001220700102300155605ustar00rootroot00000000000000autocomplete-2.5.0/src/org/fife/000077500000000000000000000000001220700102300164715ustar00rootroot00000000000000autocomplete-2.5.0/src/org/fife/ui/000077500000000000000000000000001220700102300171065ustar00rootroot00000000000000autocomplete-2.5.0/src/org/fife/ui/autocomplete/000077500000000000000000000000001220700102300216075ustar00rootroot00000000000000autocomplete-2.5.0/src/org/fife/ui/autocomplete/AbstractCompletion.java000066400000000000000000000071041220700102300262510ustar00rootroot00000000000000/* * 12/21/2008 * * AbstractCompletion.java - Base class for possible completions. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import javax.swing.Icon; import javax.swing.text.JTextComponent; /** * Base class for possible completions. Most, if not all, {@link Completion} * implementations can extend this class. It remembers the * CompletionProvider that returns this completion, and also implements * Comparable, allowing such completions to be compared * lexicographically (ignoring case).

* * This implementation assumes the input text and replacement text are the * same value. It also returns the input text from its {@link #toString()} * method (which is what DefaultListCellRenderer uses to render * objects). Subclasses that wish to override any of this behavior can simply * override the corresponding method(s) needed to do so. * * @author Robert Futrell * @version 1.0 */ public abstract class AbstractCompletion implements Completion { /** * The provider that created this completion; */ private CompletionProvider provider; /** * The relevance of this completion. Completion instances with higher * "relevance" values are inserted higher into the list of possible * completions than those with lower values. Completion instances with * equal relevance values are sorted alphabetically. */ private int relevance; /** * Constructor. * * @param provider The provider that created this completion. */ public AbstractCompletion(CompletionProvider provider) { this.provider = provider; } /** * {@inheritDoc} */ public int compareTo(Completion c2) { if (c2==this) { return 0; } else if (c2!=null) { return toString().compareToIgnoreCase(c2.toString()); } return -1; } /** * {@inheritDoc} */ public String getAlreadyEntered(JTextComponent comp) { return provider.getAlreadyEnteredText(comp); } /** * The default implementation returns null. Subclasses * who wish to display an icon can override this method. * * @return The icon for this completion. */ public Icon getIcon() { return null; } /** * 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; } /** * {@inheritDoc} */ public int getRelevance() { return relevance; } /** * The default implementation returns null. Subclasses * can override this method. * * @return The tool tip text. */ public String getToolTipText() { return null; } /** * Sets the relevance of this completion. * * @param relevance The new relevance of this completion. * @see #getRelevance() */ public void setRelevance(int relevance) { this.relevance = relevance; } /** * Returns a string representation of this completion. The default * implementation returns {@link #getInputText()}. * * @return A string representation of this completion. */ @Override public String toString() { return getInputText(); } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/AbstractCompletionProvider.java000066400000000000000000000150731220700102300277700ustar00rootroot00000000000000/* * 12/21/2008 * * AbstractCompletionProvider.java - Base class for completion providers. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ 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.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 extends CompletionProviderBase { /** * The completions this provider is aware of. Subclasses should ensure * that this list is sorted alphabetically (case-insensitively). */ protected List completions; /** * Compares a {@link Completion} against a String. */ protected CaseInsensitiveComparator comparator; /** * Constructor. */ public AbstractCompletionProvider() { comparator = new CaseInsensitiveComparator(); clearParameterizedCompletionParams(); } /** * 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 CompletionProvider. * @see #addCompletions(List) * @see #removeCompletion(Completion) * @see #clear() */ public void addCompletion(Completion c) { checkProviderAndAdd(c); Collections.sort(completions); } /** * Adds {@link Completion}s to this provider. * * @param completions The completions to add. This cannot be * null. * @throws IllegalArgumentException If a completion's provider isn't * this CompletionProvider. * @see #addCompletion(Completion) * @see #removeCompletion(Completion) * @see #clear() */ public void addCompletions(List completions) { //this.completions.addAll(completions); for (Completion c : completions) { checkProviderAndAdd(c); } Collections.sort(this.completions); } /** * Adds simple completions for a list of words. * * @param words The words. * @see BasicCompletion */ protected void addWordCompletions(String[] words) { int count = words==null ? 0 : words.length; for (int i=0; iCompletionProvider, if there is one. * * @see #addCompletion(Completion) * @see #addCompletions(List) * @see #removeCompletion(Completion) */ public void clear() { completions.clear(); } /** * Returns a list of Completions in this provider with the * specified input text. * * @param inputText The input text to search for. * @return A list of {@link Completion}s, or null if there * are no matching Completions. */ @SuppressWarnings("unchecked") public List getCompletionByInputText(String inputText) { // Find any entry that matches this input text (there may be > 1). int end = Collections.binarySearch(completions, inputText, comparator); if (end<0) { return null; } // There might be multiple entries with the same input text. int start = end; while (start>0 && comparator.compare(completions.get(start-1), inputText)==0) { start--; } int count = completions.size(); while (++end getCompletionsImpl(JTextComponent comp) { List retVal = new ArrayList(); String text = getAlreadyEnteredText(comp); if (text!=null) { int index = Collections.binarySearch(completions, text, comparator); if (index<0) { // No exact match index = -index - 1; } else { // If there are several overloads for the function being // completed, Collections.binarySearch() will return the index // of one of those overloads, but we must return all of them, // so search backward until we find the first one. int pos = index - 1; while (pos>0 && comparator.compare(completions.get(pos), text)==0) { retVal.add(completions.get(pos)); pos--; } } while (indextrue 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; } /** * A comparator that compares the input text of a {@link Completion} * against a String lexicographically, ignoring case. */ @SuppressWarnings("rawtypes") protected static class CaseInsensitiveComparator implements Comparator, Serializable { public int compare(Object o1, Object o2) { Completion c = (Completion)o1; // o2.toString() needed to help compile with 1.5+. return String.CASE_INSENSITIVE_ORDER.compare( c.getInputText(), o2.toString()); } } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/AutoCompleteDescWindow.java000066400000000000000000000365271220700102300270570ustar00rootroot00000000000000/* * 12/21/2008 * * AutoCompleteDescWindow.java - A window containing a description of the * currently selected completion. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.awt.BorderLayout; import java.awt.Component; import java.awt.ComponentOrientation; import java.awt.Graphics; import java.awt.Insets; import java.awt.Window; import java.awt.event.ActionEvent; 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.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.SwingUtilities; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.border.AbstractBorder; import javax.swing.border.Border; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import org.fife.ui.rsyntaxtextarea.PopupWindowDecorator; /** * 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, DescWindowCallback { /** * The parent AutoCompletion instance. */ private AutoCompletion ac; /** * Renders the HTML description. */ private JEditorPane descArea; /** * The scroll pane that {@link #descArea} is in. */ private JScrollPane scrollPane; /** * The bottom panel, containing the toolbar and size grip. */ private JPanel bottomPanel; /** * 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; /** * Provides a slight delay between asking to set a description and actually * displaying it, so that if the user is scrolling quickly through * completions, those with slow-to-calculate summaries won't bog down the * scrolling. */ private Timer timer; /** * The action that listens for the timer to fire. */ private TimerAction timerAction; /** * The resource bundle for this window. */ private ResourceBundle bundle; /** * The amount of time to wait after the user changes the selected * completion to refresh the description. This delay is in place to help * performance for {@link Completion}s that may be slow to compute their * summary text. */ private static final int INITIAL_TIMER_DELAY = 120; /** * The resource bundle name. */ private static final String MSG = "org.fife.ui.autocomplete.AutoCompleteDescWindow"; /** * Constructor. * * @param owner The parent window. * @param ac The parent auto-completion. */ public AutoCompleteDescWindow(Window owner, AutoCompletion ac) { super(owner); this.ac = ac; ComponentOrientation o = ac.getTextComponentOrientation(); JPanel cp = new JPanel(new BorderLayout()); cp.setBorder(TipUtil.getToolTipBorder()); descArea = new JEditorPane("text/html", null); TipUtil.tweakTipEditorPane(descArea); descArea.addHyperlinkListener(this); scrollPane = new JScrollPane(descArea); Border b = BorderFactory.createEmptyBorder(); scrollPane.setBorder(b); scrollPane.setViewportBorder(b); scrollPane.setBackground(descArea.getBackground()); scrollPane.getViewport().setBackground(descArea.getBackground()); cp.add(scrollPane); descWindowNavBar = new JToolBar(); backAction = new ToolBarBackAction(o.isLeftToRight()); forwardAction = new ToolBarForwardAction(o.isLeftToRight()); descWindowNavBar.setFloatable(false); descWindowNavBar.add(new JButton(backAction)); descWindowNavBar.add(new JButton(forwardAction)); bottomPanel = new JPanel(new BorderLayout()); b = new AbstractBorder() { @Override public Insets getBorderInsets(Component c) { return new Insets(1, 0, 0, 0); } @Override public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) { g.setColor(UIManager.getColor("controlDkShadow")); g.drawLine(x,y, x+w-1,y); } }; bottomPanel.setBorder(b); SizeGrip rp = new SizeGrip(); bottomPanel.add(descWindowNavBar, BorderLayout.LINE_START); bottomPanel.add(rp, BorderLayout.LINE_END); cp.add(bottomPanel, BorderLayout.SOUTH); setContentPane(cp); applyComponentOrientation(o); setFocusableWindowState(false); // Give apps a chance to decorate us with drop shadows, etc. if (Util.getShouldAllowDecoratingMainAutoCompleteWindows()) { PopupWindowDecorator decorator = PopupWindowDecorator.get(); if (decorator!=null) { decorator.decorate(this); } } history = new ArrayList(1); // Usually small historyPos = -1; timerAction = new TimerAction(); timer = new Timer(INITIAL_TIMER_DELAY, timerAction); timer.setRepeats(false); } /** * Sets the currently displayed description and updates the history. * * @param historyItem The item to add to the history. */ private void addToHistory(HistoryEntry historyItem) { history.add(++historyPos, historyItem); 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(); } /** * Copies from the description text area, if it is visible and there is * a selection. * * @return Whether a copy occurred. */ public boolean copy() { if (isVisible() && descArea.getSelectionStart()!=descArea.getSelectionEnd()) { descArea.copy(); return true; } return false; } /** * 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) { HyperlinkEvent.EventType type = e.getEventType(); if (!type.equals(HyperlinkEvent.EventType.ACTIVATED)) { return; } // Users can redirect URL's, perhaps to a local copy of documentation. URL url = e.getURL(); if (url!=null) { LinkRedirector redirector = AutoCompletion.getLinkRedirector(); if (redirector!=null) { URL newUrl = redirector.possiblyRedirect(url); if (newUrl!=null && newUrl!=url) { url = newUrl; e = new HyperlinkEvent(e.getSource(), e.getEventType(), newUrl, e.getDescription(), e.getSourceElement()); } } } // Custom hyperlink handler for this completion type ExternalURLHandler handler = ac.getExternalURLHandler(); if (handler!=null) { HistoryEntry current = history.get(historyPos); handler.urlClicked(e, current.completion, this); return; } // No custom handler... if (url!=null) { // Try loading in external browser (Java 6+ only). try { Util.browse(new URI(url.toString())); } catch (/*IO*/URISyntaxException ioe) { UIManager.getLookAndFeel().provideErrorFeedback(descArea); ioe.printStackTrace(); } } else { // Assume 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(); List l = ((AbstractCompletionProvider)p). getCompletionByInputText(name); if (l!=null && !l.isEmpty()) { // Just use the 1st one if there's more than 1 Completion c = l.get(0); setDescriptionFor(c, true); } else { UIManager.getLookAndFeel().provideErrorFeedback(descArea); } } } } /** * Enables or disables the back and forward actions as appropriate. */ private void setActionStates() { // TODO: Localize this text! String desc = null; if (historyPos>0) { backAction.setEnabled(true); desc = "Back to " + history.get(historyPos-1); } else { backAction.setEnabled(false); } backAction.putValue(Action.SHORT_DESCRIPTION, desc); if (historyPos>-1 && historyPosnull if none. * @param addToHistory Whether to add this page to the page history * (as opposed to clearing it and starting anew). */ protected void setDescriptionFor(Completion item, String anchor, boolean addToHistory) { timer.stop(); timerAction.setCompletion(item, anchor, addToHistory); timer.start(); } private void setDisplayedDesc(Completion completion, final String anchor, boolean addToHistory) { String desc = completion==null ? null : completion.getSummary(); if (desc==null) { desc = "" + getString("NoDescAvailable") + ""; } descArea.setText(desc); if (anchor!=null) { SwingUtilities.invokeLater(new Runnable() { public void run() { descArea.scrollToReference(anchor); } }); } else { 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(new HistoryEntry(completion, desc, null)); } /** * {@inheritDoc} */ @Override public void setVisible(boolean visible) { if (!visible) { clearHistory(); } super.setVisible(visible); } /** * Callback for custom ExternalURLHandlers. * * @param completion The completion to display. * @param anchor The anchor in the HTML to jump to, or null * if none. */ public void showSummaryFor(Completion completion, String anchor) { setDescriptionFor(completion, anchor, true); } /** * Called by the parent completion popup window the LookAndFeel is updated. */ public void updateUI() { SwingUtilities.updateComponentTreeUI(this); // Update editor pane for new font, bg, selection colors, etc. TipUtil.tweakTipEditorPane(descArea); scrollPane.setBackground(descArea.getBackground()); scrollPane.getViewport().setBackground(descArea.getBackground()); ((JPanel)getContentPane()).setBorder(TipUtil.getToolTipBorder()); } /** * A completion and its cached summary text. */ private static class HistoryEntry { public Completion completion; public String summary; public String anchor; public HistoryEntry(Completion completion, String summary, String anchor) { this.completion = completion; this.summary = summary; this.anchor = anchor; } /** * Overridden to display a short name for the completion, since it's * used in the tool tips for the "back" and "forward" buttons. * * @return A string representation of this history entry. */ @Override public String toString() { return completion.getInputText(); } } /** * Action that actually updates the summary text displayed. */ private class TimerAction extends AbstractAction { private Completion completion; private String anchor; private boolean addToHistory; /** * Called when the timer is fired. */ public void actionPerformed(ActionEvent e) { setDisplayedDesc(completion, anchor, addToHistory); } public void setCompletion(Completion c, String anchor, boolean addToHistory) { this.completion = c; this.anchor = anchor; this.addToHistory = addToHistory; } } /** * Action that moves to the previous description displayed. */ class ToolBarBackAction extends AbstractAction { public ToolBarBackAction(boolean ltr) { String img = "org/fife/ui/autocomplete/arrow_" + (ltr ? "left.png" : "right.png"); ClassLoader cl = getClass().getClassLoader(); Icon icon = new ImageIcon(cl.getResource(img)); putValue(Action.SMALL_ICON, icon); } public void actionPerformed(ActionEvent e) { if (historyPos>0) { HistoryEntry pair = history.get(--historyPos); descArea.setText(pair.summary); if (pair.anchor!=null) { //System.out.println("Scrolling to: " + pair.anchor); descArea.scrollToReference(pair.anchor); } else { descArea.setCaretPosition(0); } setActionStates(); } } } /** * Action that moves to the previous description displayed. */ class ToolBarForwardAction extends AbstractAction { public ToolBarForwardAction(boolean ltr) { String img = "org/fife/ui/autocomplete/arrow_" + (ltr ? "right.png" : "left.png"); ClassLoader cl = getClass().getClassLoader(); Icon icon = new ImageIcon(cl.getResource(img)); putValue(Action.SMALL_ICON, icon); } public void actionPerformed(ActionEvent e) { if (history!=null && historyPosnull if nothing is selected. * * @return The selected value. */ public Completion getSelection() { return isShowing() ? (Completion)list.getSelectedValue():lastSelection; } /** * Inserts the currently selected completion. * * @see #getSelection() */ private void insertSelectedCompletion() { Completion comp = getSelection(); ac.insertCompletion(comp); } /** * Registers keyboard actions to listen for in the text component and * intercept. * * @see #uninstallKeyBindings() */ private void installKeyBindings() { if (AutoCompletion.getDebug()) { System.out.println("PopupWindow: Installing keybindings"); } if (escapeKap==null) { // Lazily create actions. createKeyActionPairs(); } JTextComponent comp = ac.getTextComponent(); InputMap im = comp.getInputMap(); ActionMap am = comp.getActionMap(); replaceAction(im, am, KeyEvent.VK_ESCAPE, escapeKap, oldEscape); if (AutoCompletion.getDebug() && oldEscape.action==escapeKap.action) { Thread.dumpStack(); } replaceAction(im, am, KeyEvent.VK_UP, upKap, oldUp); replaceAction(im, am, KeyEvent.VK_LEFT, leftKap, oldLeft); replaceAction(im, am, KeyEvent.VK_DOWN, downKap, oldDown); replaceAction(im, am, KeyEvent.VK_RIGHT, rightKap, oldRight); replaceAction(im, am, KeyEvent.VK_ENTER, enterKap, oldEnter); replaceAction(im, am, KeyEvent.VK_TAB, tabKap, oldTab); replaceAction(im, am, KeyEvent.VK_HOME, homeKap, oldHome); replaceAction(im, am, KeyEvent.VK_END, endKap, oldEnd); replaceAction(im, am, KeyEvent.VK_PAGE_UP, pageUpKap, oldPageUp); replaceAction(im, am, KeyEvent.VK_PAGE_DOWN, pageDownKap, oldPageDown); // Make Ctrl+C copy from description window. This isn't done // automagically because the desc. window is not focusable, and copying // from text components can only be done from focused components. KeyStroke ks = getCopyKeyStroke(); oldCtrlC.key = im.get(ks); im.put(ks, ctrlCKap.key); oldCtrlC.action = am.get(ctrlCKap.key); am.put(ctrlCKap.key, ctrlCKap.action); comp.addCaretListener(this); } public void mouseClicked(MouseEvent e) { if (e.getClickCount()==2) { insertSelectedCompletion(); } } 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 completion choices * window. We assume there is room on one side of the other for this * entire window to fit. */ private void positionDescWindow() { boolean showDescWindow = descWindow!=null && ac.getShowDescWindow(); if (!showDescWindow) { return; } // Don't use getLocationOnScreen() as this throws an exception if // window isn't visible yet, but getLocation() doesn't, and is in // screen coordinates! Point p = getLocation(); Rectangle screenBounds = Util.getScreenBoundsForPoint(p.x, p.y); //Dimension screenSize = getToolkit().getScreenSize(); //int totalH = Math.max(getHeight(), descWindow.getHeight()); // Try to position to the right first (LTR) int x; if (ac.getTextComponentOrientation().isLeftToRight()) { x = getX() + getWidth() + 5; if (x+descWindow.getWidth()>screenBounds.x+screenBounds.width) { // doesn't fit x = getX() - 5 - descWindow.getWidth(); } } else { // RTL x = getX() - 5 - descWindow.getWidth(); if (xkey. * @param old A buffer in which to place the old key/Action pair. * @see #putBackAction(InputMap, ActionMap, int, KeyActionPair) */ private void replaceAction(InputMap im, ActionMap am, int key, KeyActionPair kap, KeyActionPair old) { KeyStroke ks = KeyStroke.getKeyStroke(key, 0); old.key = im.get(ks); im.put(ks, kap.key); old.action = am.get(kap.key); am.put(kap.key, kap.action); } /** * Selects the first item in the completion list. * * @see #selectLastItem() */ private void selectFirstItem() { if (model.getSize() > 0) { list.setSelectedIndex(0); list.ensureIndexIsVisible(0); } } /** * Selects the last item in the completion list. * * @see #selectFirstItem() */ private void selectLastItem() { int index = model.getSize() - 1; if (index > -1) { list.setSelectedIndex(index); list.ensureIndexIsVisible(index); } } /** * Selects the next item in the completion list. * * @see #selectPreviousItem() */ private void selectNextItem() { int index = list.getSelectedIndex(); if (index > -1) { index = (index + 1) % model.getSize(); list.setSelectedIndex(index); list.ensureIndexIsVisible(index); } } /** * Selects the completion item one "page down" from the currently selected * one. * * @see #selectPageUpItem() */ private void selectPageDownItem() { int visibleRowCount = list.getVisibleRowCount(); int i = Math.min(list.getModel().getSize()-1, list.getSelectedIndex()+visibleRowCount); list.setSelectedIndex(i); list.ensureIndexIsVisible(i); } /** * Selects the completion item one "page up" from the currently selected * one. * * @see #selectPageDownItem() */ private void selectPageUpItem() { int visibleRowCount = list.getVisibleRowCount(); int i = Math.max(0, list.getSelectedIndex()-visibleRowCount); list.setSelectedIndex(i); list.ensureIndexIsVisible(i); } /** * Selects the previous item in the completion list. * * @see #selectNextItem() */ private 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); } /** * Sets the completions to display in the choices list. The first * completion is selected. * * @param completions The completions to display. */ public void setCompletions(List completions) { model.setContents(completions); selectFirstItem(); } /** * Sets the size of the description window. * * @param size The new size. This cannot be null. */ public void setDescriptionWindowSize(Dimension size) { if (descWindow!=null) { descWindow.setSize(size); } else { preferredDescWindowSize = size; } } /** * Sets the default list cell renderer to use when a completion provider * does not supply its own. * * @param renderer The renderer to use. If this is null, * a default renderer is used. * @see #getListCellRenderer() */ public void setListCellRenderer(ListCellRenderer renderer) { DelegatingCellRenderer dcr = (DelegatingCellRenderer)list. getCellRenderer(); dcr.setFallbackCellRenderer(renderer); } /** * Sets the location of this window to be "good" relative to the specified * rectangle. That rectangle should be the location of the text * component's caret, in screen coordinates. * * @param r The text component's caret position, in screen coordinates. */ public void setLocationRelativeTo(Rectangle r) { // Multi-monitor support - make sure the completion window (and // description window, if applicable) both fit in the same window in // a multi-monitor environment. To do this, we decide which monitor // the rectangle "r" is in, and use that one (just pick top-left corner // as the defining point). Rectangle screenBounds = Util.getScreenBoundsForPoint(r.x, r.y); //Dimension screenSize = getToolkit().getScreenSize(); boolean showDescWindow = descWindow!=null && ac.getShowDescWindow(); 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 + VERTICAL_SPACE; if (y+totalH>screenBounds.height) { y = r.y - VERTICAL_SPACE - getHeight(); aboveCaret = true; } // Get x-coordinate of completions. Try to align left edge with the // caret first. int x = r.x; if (!ac.getTextComponentOrientation().isLeftToRight()) { x -= getWidth(); // RTL => align right edge } if (xscreenBounds.x+screenBounds.width) { // completions don't fit x = screenBounds.x + screenBounds.width - getWidth(); } setLocation(x, y); // Position the description window, if necessary. if (showDescWindow) { positionDescWindow(); } } /** * Toggles the visibility of this popup window. * * @param visible Whether this window should be visible. */ @Override public void setVisible(boolean visible) { if (visible!=isVisible()) { if (visible) { installKeyBindings(); lastLine = ac.getLineOfCaret(); selectFirstItem(); if (descWindow==null && ac.getShowDescWindow()) { descWindow = createDescriptionWindow(); positionDescWindow(); } // descWindow needs a kick-start the first time it's displayed. // Also, the newly-selected item in the choices list is // probably different from the previous one anyway. if (descWindow!=null) { Completion c = (Completion)list.getSelectedValue(); if (c!=null) { descWindow.setDescriptionFor(c); } } } else { uninstallKeyBindings(); } super.setVisible(visible); // Some languages, such as Java, can use quite a lot of memory // when displaying hundreds of completion choices. We pro-actively // clear our list model here to make them available for GC. // Otherwise, they stick around, and consider the following: a // user starts code-completion for Java 5 SDK classes, then hides // the dialog, then changes the "class path" to use a Java 6 SDK // instead. On pressing Ctrl+space, a new array of Completions is // created. If this window holds on to the previous Completions, // you're getting roughly 2x the necessary Completions in memory // until the Completions are actually passed to this window. if (!visible) { // Do after super.setVisible(false) lastSelection = (Completion)list.getSelectedValue(); model.clear(); } // Must set descWindow's visibility one way or the other each time, // because of the way child JWindows' visibility is handled - in // some ways it's dependent on the parent, in other ways it's not. if (descWindow!=null) { descWindow.setVisible(visible && ac.getShowDescWindow()); } } } /** * Stops intercepting certain keystrokes from the text component. * * @see #installKeyBindings() */ private void uninstallKeyBindings() { if (AutoCompletion.getDebug()) { System.out.println("PopupWindow: Removing keybindings"); } JTextComponent comp = ac.getTextComponent(); InputMap im = comp.getInputMap(); ActionMap am = comp.getActionMap(); putBackAction(im, am, KeyEvent.VK_ESCAPE, oldEscape); putBackAction(im, am, KeyEvent.VK_UP, oldUp); putBackAction(im, am, KeyEvent.VK_DOWN, oldDown); putBackAction(im, am, KeyEvent.VK_LEFT, oldLeft); putBackAction(im, am, KeyEvent.VK_RIGHT, oldRight); putBackAction(im, am, KeyEvent.VK_ENTER, oldEnter); putBackAction(im, am, KeyEvent.VK_TAB, oldTab); putBackAction(im, am, KeyEvent.VK_HOME, oldHome); putBackAction(im, am, KeyEvent.VK_END, oldEnd); putBackAction(im, am, KeyEvent.VK_PAGE_UP, oldPageUp); putBackAction(im, am, KeyEvent.VK_PAGE_DOWN, oldPageDown); // Ctrl+C KeyStroke ks = getCopyKeyStroke(); am.put(im.get(ks), oldCtrlC.action); // Original action im.put(ks, oldCtrlC.key); // Original key comp.removeCaretListener(this); } /** * Updates the LookAndFeel of this window and the description * window. */ public void updateUI() { SwingUtilities.updateComponentTreeUI(this); if (descWindow!=null) { descWindow.updateUI(); } } /** * 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 CopyAction extends AbstractAction { public void actionPerformed(ActionEvent e) { boolean doNormalCopy = false; if (descWindow!=null && descWindow.isVisible()) { doNormalCopy = !descWindow.copy(); } if (doNormalCopy) { ac.getTextComponent().copy(); } } } 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()) { insertSelectedCompletion(); } } } 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(); } } } /** * A mapping from a key (an Object) to an Action. */ private static class KeyActionPair { public Object key; public Action action; public KeyActionPair() { } public KeyActionPair(Object key, Action a) { this.key = key; this.action = a; } } 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(); } } } /** * The actual list of completion choices in this popup window. */ private class PopupList extends JList { public PopupList(CompletionListModel model) { super(model); } @Override public void setUI(ListUI ui) { if (Util.getUseSubstanceRenderers() && SUBSTANCE_LIST_UI.equals(ui.getClass().getName())) { // Substance requires its special ListUI be installed for // its renderers to actually render (!), but long completion // lists (e.g. PHPCompletionProvider in RSTALanguageSupport) // will simply populate too slowly on initial display (when // calculating preferred size of all items), so in this case // we give a prototype cell value. CompletionProvider p = ac.getCompletionProvider(); BasicCompletion bc = new BasicCompletion(p, "Hello world"); setPrototypeCellValue(bc); } else { // Our custom UI that is faster for long HTML completion // lists. ui = new FastListUI(); setPrototypeCellValue(null); } super.setUI(ui); } } 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(); } } } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/AutoCompletion.java000066400000000000000000001111451220700102300254170ustar00rootroot00000000000000/* * 12/21/2008 * * AutoCompletion.java - Handles auto-completion for a text component. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.awt.*; import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.List; import javax.swing.*; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.*; /** * Adds auto-completion to a text component. Provides a popup window with a * list of auto-complete choices on a given keystroke, such as Crtrl+Space.

* * Depending on the {@link CompletionProvider} installed, the following * auto-completion features may be enabled: * *

* * @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 { /** * 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; /** * The preferred size of the completion choices window. This field exists * because the user will likely set the preferred size of the window * before it is actually created. */ private Dimension preferredChoicesWindowSize; /** * The preferred size of the optional description window. This field * only exists because the user may (and usually will) set the size of * the description window before it exists (it must be parented to a * Window). */ private Dimension preferredDescWindowSize; /** * Manages any parameterized completions that are inserted. */ private ParameterizedCompletionContext pcc; /** * Provides the completion options relevant to the current caret position. */ private CompletionProvider provider; /** * The renderer to use for the completion choices. If this is * null, then a default renderer is used. */ private ListCellRenderer renderer; /** * The handler to use when an external URL is clicked in the help * documentation. */ private ExternalURLHandler externalURLHandler; /** * An optional redirector that converts URL's to some other location before * being handed over to externalURLHandler. */ private static LinkRedirector linkRedirector; /** * Whether the description window should be displayed along with the * completion choice window. */ private boolean showDescWindow; /** * Whether auto-complete is enabled. */ private boolean autoCompleteEnabled; /** * Whether the auto-activation of auto-complete (after a delay, after the * user types an appropriate character) is enabled. */ private boolean autoActivationEnabled; /** * Whether or not, when there is only a single auto-complete option * that matches the text at the current text position, that text should * be auto-inserted, instead of the completion window displaying. */ private boolean autoCompleteSingleChoices; /** * Whether parameter assistance is enabled. */ private boolean parameterAssistanceEnabled; /** * A renderer used for {@link Completion}s in the optional parameter * choices popup window (displayed when a {@link ParameterizedCompletion} * is code-completed). If this isn't set, a default renderer is used. */ private ListCellRenderer paramChoicesRenderer; /** * The keystroke that triggers the completion window. */ private KeyStroke trigger; /** * The previous key in the text component's InputMap for the * trigger key. */ private Object oldTriggerKey; /** * The action previously assigned to {@link #trigger}, so we can reset it * if the user disables auto-completion. */ private Action oldTriggerAction; /** * The previous key in the text component's InputMap for the * parameter completion trigger key. */ private Object oldParenKey; /** * The action previously assigned to the parameter completion key, so we * can reset it when we uninstall. */ private Action oldParenAction; /** * Listens for events in the parent window that affect the visibility of * the popup windows. */ private ParentWindowListener parentWindowListener; /** * Listens for events from the text component that affect the visibility * of the popup windows. */ private TextComponentListener textComponentListener; /** * Listens for events in the text component that cause the popup windows * to automatically activate. */ private AutoActivationListener autoActivationListener; /** * Listens for LAF changes so the auto-complete windows automatically * update themselves accordingly. */ private LookAndFeelChangeListener lafListener; /** * The key used in the input map for the AutoComplete action. */ private static final String PARAM_TRIGGER_KEY = "AutoComplete"; /** * Key used in the input map for the parameter completion action. */ private static final String PARAM_COMPLETE_KEY = "AutoCompletion.FunctionStart"; /** * Stores how to render auto-completion-specific highlights in text * components. */ private static final AutoCompletionStyleContext styleContext = new AutoCompletionStyleContext(); /** * Whether debug messages should be printed to stdout as AutoCompletion * runs. */ private static final boolean DEBUG = initDebug(); /** * Constructor. * * @param provider The completion provider. This cannot be * null. */ public AutoCompletion(CompletionProvider provider) { setChoicesWindowSize(350, 200); setDescriptionWindowSize(350, 250); setCompletionProvider(provider); setTriggerKey(getDefaultTriggerKey()); setAutoCompleteEnabled(true); setAutoCompleteSingleChoices(true); setAutoActivationEnabled(false); setShowDescWindow(false); parentWindowListener = new ParentWindowListener(); textComponentListener = new TextComponentListener(); autoActivationListener = new AutoActivationListener(); lafListener = new LookAndFeelChangeListener(); } /** * Displays the popup window. Hosting applications can call this method * to programmatically begin an auto-completion operation. */ public void doCompletion() { refreshPopupWindow(); } /** * Returns the delay between when the user types a character and when the * code completion popup should automatically appear (if applicable). * * @return The delay, in milliseconds. * @see #setAutoActivationDelay(int) */ public int getAutoActivationDelay() { return autoActivationListener.timer.getDelay(); } /** * Returns whether, if a single auto-complete choice is available, it * should be automatically inserted, without displaying the popup menu. * * @return Whether to auto-complete single choices. * @see #setAutoCompleteSingleChoices(boolean) */ public boolean getAutoCompleteSingleChoices() { return autoCompleteSingleChoices; } /** * Returns the completion provider. * * @return The completion provider. */ public CompletionProvider getCompletionProvider() { return provider; } /** * Returns whether debug is enabled for AutoCompletion. * * @return Whether debug is enabled. */ static boolean getDebug() { return DEBUG; } /** * Returns the default auto-complete "trigger key" for this OS. For * Windows, for example, it is Ctrl+Space. * * @return The default auto-complete trigger key. */ public static KeyStroke getDefaultTriggerKey() { // Default to CTRL, even on Mac, since Ctrl+Space activates Spotlight int mask = InputEvent.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) * @see #getLinkRedirector() */ public ExternalURLHandler getExternalURLHandler() { return externalURLHandler; } int getLineOfCaret() { Document doc = textComponent.getDocument(); Element root = doc.getDefaultRootElement(); return root.getElementIndex(textComponent.getCaretPosition()); } /** * Returns the link redirector, if any. * * @return The link redirector, or null if none. * @see #setLinkRedirector(LinkRedirector) */ public static LinkRedirector getLinkRedirector() { return linkRedirector; } /** * Returns the default list cell renderer used when a completion provider * does not supply its own. * * @return The default list cell renderer. * @see #setListCellRenderer(ListCellRenderer) */ public ListCellRenderer getListCellRenderer() { return renderer; } /** * Returns the renderer to use for {@link Completion}s in the optional * parameter choices popup window (displayed when a * {@link ParameterizedCompletion} is code-completed). If this returns * null, a default renderer is used. * * @return The renderer to use. * @see #setParamChoicesRenderer(ListCellRenderer) * @see #isParameterAssistanceEnabled() */ public ListCellRenderer getParamChoicesRenderer() { return paramChoicesRenderer; } /** * Returns the text to replace with in the document. This is a * "last-chance" hook for subclasses to make special modifications to the * completion text inserted. The default implementation simply returns * c.getReplacementText(). You usually will not need to modify * this method. * * @param c The completion being inserted. * @param doc The document being modified. * @param start The start of the text being replaced. * @param len The length of the text being replaced. * @return The text to replace with. */ protected String getReplacementText(Completion c, Document doc, int start, int len) { return c.getReplacementText(); } /** * 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 style context describing how auto-completion related * highlights in the editor are rendered. * * @return The style context. */ public static AutoCompletionStyleContext getStyleContext() { return styleContext; } /** * Returns the text component for which auto-completion is enabled. * * @return The text component, or null if this * {@link AutoCompletion} is not installed on any text component. * @see #install(JTextComponent) */ public JTextComponent getTextComponent() { return textComponent; } /** * Returns the orientation of the text component we're installed to. * * @return The orientation of the text component, or null if * we are not installed on one. */ ComponentOrientation getTextComponentOrientation() { return textComponent==null ? null : textComponent.getComponentOrientation(); } /** * Returns the "trigger key" used for auto-complete. * * @return The trigger key. * @see #setTriggerKey(KeyStroke) */ public KeyStroke getTriggerKey() { return trigger; } /** * Hides any child windows being displayed by the auto-completion system. * * @return Whether any windows were visible. */ public boolean hideChildWindows() { //return hidePopupWindow() || hideToolTipWindow(); boolean res = hidePopupWindow(); res |= hideParameterCompletionPopups(); return res; } /** * Hides and disposes of any parameter completion-related popups. * * @return Whether any such windows were visible (and thus hidden). */ private boolean hideParameterCompletionPopups() { if (pcc!=null) { pcc.deactivate(); pcc = null; return true; } return false; } /** * Hides the popup window, if it is visible. * * @return Whether the popup window was visible. */ private boolean hidePopupWindow() { if (popupWindow!=null) { if (popupWindow.isVisible()) { popupWindow.setVisible(false); return true; } } return false; } /** * Determines whether debug should be enabled for the AutoCompletion * library. This method checks a system property, but takes care of * {@link SecurityException}s in case we're in an applet or WebStart. * * @return Whether debug should be enabled. */ private static final boolean initDebug() { boolean debug = false; try { debug = Boolean.getBoolean("AutoCompletion.debug"); } catch (SecurityException se) { // We're in an applet or WebStart. debug = false; } return debug; } /** * Inserts a completion. Any time a code completion event occurs, the * actual text insertion happens through this method. * * @param c A completion to insert. This cannot be null. */ protected final void insertCompletion(Completion c) { insertCompletion(c, false); } /** * Inserts a completion. Any time a code completion event occurs, the * actual text insertion happens through this method. * * @param c A completion to insert. This cannot be null. * @param typedParamListStartChar Whether the parameterized completion * start character was typed (typically '('). */ protected void insertCompletion(Completion c, boolean typedParamListStartChar) { JTextComponent textComp = getTextComponent(); String alreadyEntered = c.getAlreadyEntered(textComp); hidePopupWindow(); Caret caret = textComp.getCaret(); int dot = caret.getDot(); int len = alreadyEntered.length(); int start = dot-len; String replacement = getReplacementText(c, textComp.getDocument(), start, len); caret.setDot(start); caret.moveDot(dot); textComp.replaceSelection(replacement); if (isParameterAssistanceEnabled() && (c instanceof ParameterizedCompletion)) { ParameterizedCompletion pc = (ParameterizedCompletion)c; startParameterizedCompletionAssistance(pc, typedParamListStartChar); } } /** * Installs this auto-completion 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()); // Install the function completion key, if there is one. // NOTE: We cannot do this if the start char is ' ' (e.g. just a space // between the function name and parameters) because it overrides // RSTA's special space action. It seems KeyStorke.getKeyStroke(' ') // hoses ctrl+space, shift+space, etc., even though I think it // shouldn't... char start = provider.getParameterListStart(); if (start!=0 && start!=' ') { InputMap im = c.getInputMap(); ActionMap am = c.getActionMap(); KeyStroke ks = KeyStroke.getKeyStroke(start); oldParenKey = im.get(ks); im.put(ks, PARAM_COMPLETE_KEY); oldParenAction = am.get(PARAM_COMPLETE_KEY); am.put(PARAM_COMPLETE_KEY, new ParameterizedCompletionStartAction(start)); } textComponentListener.addTo(this.textComponent); // In case textComponent is already in a window... textComponentListener.hierarchyChanged(null); if (isAutoActivationEnabled()) { autoActivationListener.addTo(this.textComponent); } UIManager.addPropertyChangeListener(lafListener); updateUI(); // In case there have been changes since we uninstalled } /** * 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) { InputMap im = textComponent.getInputMap(); oldTriggerKey = im.get(ks); im.put(ks, PARAM_TRIGGER_KEY); ActionMap am = textComponent.getActionMap(); oldTriggerAction = am.get(PARAM_TRIGGER_KEY); am.put(PARAM_TRIGGER_KEY, new AutoCompleteAction()); } /** * Returns whether auto-activation is enabled (that is, whether the * completion popup will automatically appear after a delay when the user * types an appropriate character). Note that this parameter will be * ignored if auto-completion is disabled. * * @return Whether auto-activation is enabled. * @see #setAutoActivationEnabled(boolean) * @see #getAutoActivationDelay() * @see #isAutoCompleteEnabled() */ public boolean isAutoActivationEnabled() { return autoActivationEnabled; } /** * Returns whether auto-completion is enabled. * * @return Whether auto-completion is enabled. * @see #setAutoCompleteEnabled(boolean) */ public boolean isAutoCompleteEnabled() { return autoCompleteEnabled; } /** * Returns whether parameter assistance is enabled. * * @return Whether parameter assistance is enabled. * @see #setParameterAssistanceEnabled(boolean) */ public boolean isParameterAssistanceEnabled() { return parameterAssistanceEnabled; } /** * Returns whether the popup window is visible. * * @return Whether the popup window is visible. */ 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() { // A return value of null => don't suggest completions String text = provider.getAlreadyEnteredText(textComponent); if (text==null && !isPopupVisible()) { return getLineOfCaret(); } // If the popup is currently visible, and they type a space (or any // character that resets the completion list to "all completions"), // the popup window should be hidden instead of being reset to show // everything. int textLen = text==null ? 0 : text.length(); if (textLen==0) { if (isPopupVisible()) { hidePopupWindow(); return getLineOfCaret(); } } final List completions = provider. getCompletions(textComponent); int count = completions.size(); if (count>1 || (count==1 && (isPopupVisible() || textLen==0)) || (count==1 && !getAutoCompleteSingleChoices())) { if (popupWindow==null) { popupWindow = new AutoCompletePopupWindow(parentWindow, this); // Completion is usually done for code, which is always done // LTR, so make completion stuff RTL only if text component is // also RTL. popupWindow.applyComponentOrientation( getTextComponentOrientation()); if (renderer!=null) { popupWindow.setListCellRenderer(renderer); } if (preferredChoicesWindowSize!=null) { popupWindow.setSize(preferredChoicesWindowSize); } if (preferredDescWindowSize!=null) { popupWindow.setDescriptionWindowSize( preferredDescWindowSize); } } popupWindow.setCompletions(completions); 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() { insertCompletion(completions.get(0)); } }); } else { hidePopupWindow(); } return getLineOfCaret(); } /** * Sets the delay between when the user types a character and when the * code completion popup should automatically appear (if applicable). * * @param ms The delay, in milliseconds. This should be greater than zero. * @see #getAutoActivationDelay() */ public void setAutoActivationDelay(int ms) { ms = Math.max(0, ms); autoActivationListener.timer.stop(); autoActivationListener.timer.setInitialDelay(ms); } /** * Toggles whether auto-activation is enabled. Note that auto-activation * also depends on auto-completion itself being enabled. * * @param enabled Whether auto-activation is enabled. * @see #isAutoActivationEnabled() * @see #setAutoActivationDelay(int) */ public void setAutoActivationEnabled(boolean enabled) { if (enabled!=autoActivationEnabled) { autoActivationEnabled = enabled; if (textComponent!=null) { if (autoActivationEnabled) { autoActivationListener.addTo(textComponent); } else { autoActivationListener.removeFrom(textComponent); } } } } /** * Sets whether auto-completion is enabled. * * @param enabled Whether auto-completion is enabled. * @see #isAutoCompleteEnabled() */ public void setAutoCompleteEnabled(boolean enabled) { if (enabled!=autoCompleteEnabled) { autoCompleteEnabled = enabled; hidePopupWindow(); } } /** * Sets whether, if a single auto-complete choice is available, it should * be automatically inserted, without displaying the popup menu. * * @param autoComplete Whether to auto-complete 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 * null. * @throws IllegalArgumentException If provider is * null. */ 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 size of the completion choices window. * * @param w The new width. * @param h The new height. * @see #setDescriptionWindowSize(int, int) */ public void setChoicesWindowSize(int w, int h) { preferredChoicesWindowSize = new Dimension(w, h); if (popupWindow!=null) { popupWindow.setSize(preferredChoicesWindowSize); } } /** * Sets the size of the description window. * * @param w The new width. * @param h The new height. * @see #setChoicesWindowSize(int, int) */ public void setDescriptionWindowSize(int w, int h) { preferredDescWindowSize = new Dimension(w, h); if (popupWindow!=null) { popupWindow.setDescriptionWindowSize(preferredDescWindowSize); } } /** * 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, or otherwise want to respond to * hyperlink clicks, 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 the redirector for external URL's found in code completion * documentation. When a non-local link in completion popups is clicked, * this redirector is given the chance to modify the URL fetched and * displayed. * * @param linkRedirector The link redirector, or null for * none. * @see #getLinkRedirector() */ public static void setLinkRedirector(LinkRedirector linkRedirector) { AutoCompletion.linkRedirector = linkRedirector; } /** * Sets the default list cell renderer to use when a completion provider * does not supply its own. * * @param renderer The renderer to use. If this is null, * a default renderer is used. * @see #getListCellRenderer() */ public void setListCellRenderer(ListCellRenderer renderer) { this.renderer = renderer; if (popupWindow!=null) { popupWindow.setListCellRenderer(renderer); hidePopupWindow(); } } /** * Sets the renderer to use for {@link Completion}s in the optional * parameter choices popup window (displayed when a * {@link ParameterizedCompletion} is code-completed). If this isn't set, * a default renderer is used. * * @param r The renderer to use. * @see #getParamChoicesRenderer() * @see #setParameterAssistanceEnabled(boolean) */ public void setParamChoicesRenderer(ListCellRenderer r) { paramChoicesRenderer = r; } /** * Sets whether parameter assistance is enabled. If parameter assistance * is enabled, and a "parameterized" completion (such as a function or * method) is inserted, the user will get "assistance" in inserting the * parameters in the form of a popup window with documentation and easy * tabbing through the arguments (as seen in Eclipse and NetBeans). * * @param enabled Whether parameter assistance should be enabled. * @see #isParameterAssistanceEnabled() */ public void setParameterAssistanceEnabled(boolean enabled) { parameterAssistanceEnabled = enabled; } /** * 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) { hidePopupWindow(); // Needed to force it to take effect showDescWindow = show; } /** * Sets the keystroke that should be used to trigger the auto-complete * popup window. * * @param ks The keystroke. * @throws IllegalArgumentException If ks is null. * @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; } } /** * Displays a "tool tip" detailing the inputs to the function just entered. * * @param pc The completion. * @param typedParamListStartChar Whether the parameterized completion list * starting character was typed. */ private void startParameterizedCompletionAssistance( ParameterizedCompletion pc, boolean typedParamListStartChar) { // Get rid of the previous tool tip window, if there is one. hideParameterCompletionPopups(); // Don't bother with a tool tip if there are no parameters, but if // they typed e.g. the opening '(', make them overtype the ')'. if (pc.getParamCount()==0 && !(pc instanceof TemplateCompletion)) { CompletionProvider p = pc.getProvider(); char end = p.getParameterListEnd(); // Might be '\0' String text = end=='\0' ? "" : Character.toString(end); if (typedParamListStartChar) { String template = "${}" + text + "${cursor}"; textComponent.replaceSelection(Character.toString(p.getParameterListStart())); TemplateCompletion tc = new TemplateCompletion(p, null, null, template); pc = tc; } else { text = p.getParameterListStart() + text; textComponent.replaceSelection(text); return; } } pcc = new ParameterizedCompletionContext(parentWindow, this, pc); pcc.activate(); } /** * Uninstalls this auto-completion 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(); // Uninstall the function completion key. char start = provider.getParameterListStart(); if (start!=0) { KeyStroke ks = KeyStroke.getKeyStroke(start); InputMap im = textComponent.getInputMap(); im.put(ks, oldParenKey); ActionMap am = textComponent.getActionMap(); am.put(PARAM_COMPLETE_KEY, oldParenAction); } textComponentListener.removeFrom(textComponent); if (parentWindow!=null) { parentWindowListener.removeFrom(parentWindow); } if (isAutoActivationEnabled()) { autoActivationListener.removeFrom(textComponent); } UIManager.removePropertyChangeListener(lafListener); textComponent = null; popupWindow = null; } } /** * Replaces the "trigger key" action with the one that was there * before auto-completion was installed. * * @see #installTriggerKey(KeyStroke) */ private void uninstallTriggerKey() { InputMap im = textComponent.getInputMap(); im.put(trigger, oldTriggerKey); ActionMap am = textComponent.getActionMap(); am.put(PARAM_TRIGGER_KEY, oldTriggerAction); } /** * Updates the LookAndFeel of the popup window. Applications can call * this method as appropriate if they support changing the LookAndFeel * at runtime. */ private void updateUI() { if (popupWindow!=null) { popupWindow.updateUI(); } if (pcc!=null) { pcc.updateUI(); } // Will practically always be a JComponent (a JLabel) if (paramChoicesRenderer instanceof JComponent) { ((JComponent)paramChoicesRenderer).updateUI(); } } /** * Listens for events in the text component to auto-activate the code * completion popup. */ private class AutoActivationListener extends FocusAdapter implements DocumentListener, CaretListener, ActionListener { private Timer timer; private boolean justInserted; public AutoActivationListener() { timer = new Timer(200, this); timer.setRepeats(false); } public void actionPerformed(ActionEvent e) { doCompletion(); } public void addTo(JTextComponent tc) { tc.addFocusListener(this); tc.getDocument().addDocumentListener(this); tc.addCaretListener(this); } public void caretUpdate(CaretEvent e) { if (justInserted) { justInserted = false; } else { timer.stop(); } } public void changedUpdate(DocumentEvent e) { // Ignore } @Override public void focusLost(FocusEvent e) { timer.stop(); //hideChildWindows(); Other listener will do this } public void insertUpdate(DocumentEvent e) { justInserted = false; if (isAutoCompleteEnabled() && isAutoActivationEnabled() && e.getLength()==1) { if (provider.isAutoActivateOkay(textComponent)) { timer.restart(); justInserted = true; } else { timer.stop(); } } else { timer.stop(); } } public void removeFrom(JTextComponent tc) { tc.removeFocusListener(this); tc.getDocument().removeDocumentListener(this); tc.removeCaretListener(this); timer.stop(); justInserted = false; } public void removeUpdate(DocumentEvent e) { timer.stop(); } } /** * The Action that displays the popup window if * auto-completion is enabled. */ private class AutoCompleteAction extends AbstractAction { public void actionPerformed(ActionEvent e) { if (isAutoCompleteEnabled()) { refreshPopupWindow(); } else if (oldTriggerAction!=null) { oldTriggerAction.actionPerformed(e); } } } /** * Listens for LookAndFeel changes and updates the various popup windows * involved in auto-completion accordingly. */ private class LookAndFeelChangeListener implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent e) { String name = e.getPropertyName(); if ("lookAndFeel".equals(name)) { updateUI(); } } } /** * Action that starts a parameterized completion, e.g. after '(' is * typed. */ private class ParameterizedCompletionStartAction extends AbstractAction { private String start; public ParameterizedCompletionStartAction(char ch) { this.start = Character.toString(ch); } public void actionPerformed(ActionEvent e) { // Prevents keystrokes from messing up boolean wasVisible = hidePopupWindow(); // Only proceed if they were selecting a completion if (!wasVisible || !isParameterAssistanceEnabled()) { textComponent.replaceSelection(start); return; } Completion c = popupWindow.getSelection(); if (c instanceof ParameterizedCompletion) { // Should always be true // Fixes capitalization of the entered text. insertCompletion(c, true); } } } /** * Listens for events in the parent window of the text component with * auto-completion enabled. */ private class ParentWindowListener extends ComponentAdapter implements WindowFocusListener { public void addTo(Window w) { w.addComponentListener(this); w.addWindowFocusListener(this); } @Override public void componentHidden(ComponentEvent e) { hideChildWindows(); } @Override public void componentMoved(ComponentEvent e) { hideChildWindows(); } @Override public void componentResized(ComponentEvent e) { hideChildWindows(); } public void removeFrom(Window w) { w.removeComponentListener(this); w.removeWindowFocusListener(this); } public void windowGainedFocus(WindowEvent e) { } public void windowLostFocus(WindowEvent e) { hideChildWindows(); } } /** * Listens for events from the text component we're installed on. */ private class TextComponentListener extends FocusAdapter implements HierarchyListener { void addTo(JTextComponent tc) { tc.addFocusListener(this); tc.addHierarchyListener(this); } /** * Hide the auto-completion windows when the text component loses * focus. */ @Override public void focusLost(FocusEvent e) { hideChildWindows(); } /** * 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 Window. * * @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) { parentWindowListener.removeFrom(oldParentWindow); } if (parentWindow!=null) { parentWindowListener.addTo(parentWindow); } } } public void removeFrom(JTextComponent tc) { tc.removeFocusListener(this); tc.removeHierarchyListener(this); } } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/AutoCompletionStyleContext.java000066400000000000000000000057141220700102300300110ustar00rootroot00000000000000/* * 06/24/2012 * * AutoCompletionStyleContext.java - Manages styles related to auto-completion. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.awt.Color; /** * Manages the colors shared across the library. * * @author Robert Futrell * @version 1.0 */ public class AutoCompletionStyleContext { /** * The color used to denote the ending caret position for parameterized * completions. */ private Color parameterizedCompletionCursorPositionColor; /** * The color used to highlight copies of editable parameters in * parameterized completions. */ private Color parameterCopyColor; /** * The color of the outline highlight used to denote editable parameters * in parameterized completions. */ private Color parameterOutlineColor; public AutoCompletionStyleContext() { setParameterOutlineColor(Color.gray); setParameterCopyColor(new Color(0xb4d7ff)); setParameterizedCompletionCursorPositionColor(new Color(0x00b400)); } /** * Returns the color of the highlight painted on copies of editable * parameters in parameterized completions. * * @return The color used. * @see #setParameterCopyColor(Color) */ public Color getParameterCopyColor() { return parameterCopyColor; } /** * Returns the color used to denote the ending caret position for * parameterized completions. * * @return The color used. * @see #setParameterizedCompletionCursorPositionColor(Color) */ public Color getParameterizedCompletionCursorPositionColor() { return parameterizedCompletionCursorPositionColor; } /** * Returns the color of the outline highlight used to denote editable * parameters in parameterized completions. * * @return The color used. * @see #setParameterOutlineColor(Color) */ public Color getParameterOutlineColor() { return parameterOutlineColor; } /** * Sets the color of the highlight painted on copies of editable * parameters in parameterized completions. * * @param color The color to use. * @see #setParameterCopyColor(Color) */ public void setParameterCopyColor(Color color) { this.parameterCopyColor = color; } /** * Sets the color used to denote the ending caret position for * parameterized completions. * * @param color The color to use. * @see #getParameterizedCompletionCursorPositionColor() */ public void setParameterizedCompletionCursorPositionColor(Color color) { this.parameterizedCompletionCursorPositionColor = color; } /** * Sets the color of the outline highlight used to denote editable * parameters in parameterized completions. * * @param color The color to use. * @see #getParameterOutlineColor() */ public void setParameterOutlineColor(Color color) { this.parameterOutlineColor = color; } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/BasicCompletion.java000066400000000000000000000072111220700102300255260ustar00rootroot00000000000000/* * 01/03/2009 * * BasicCompletion.java - A straightforward Completion implementation. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; /** * A straightforward {@link Completion} implementation. This implementation * can be used if you have a relatively short number of static completions * with no (or short) summaries.

* * This implementation uses the replacement text as the input text. It also * includes a "short description" field, which (if non-null), is * used in the completion choices list. * * @author Robert Futrell * @version 1.0 */ public class BasicCompletion extends AbstractCompletion { private String replacementText; private String shortDesc; private String summary; /** * Constructor. * * @param provider The parent completion provider. * @param replacementText The text to replace. */ public BasicCompletion(CompletionProvider provider, String replacementText){ this(provider, replacementText, null); } /** * Constructor. * * @param provider The parent completion provider. * @param replacementText The text to replace. * @param shortDesc A short description of the completion. This will be * displayed in the completion list. This may be null. */ public BasicCompletion(CompletionProvider provider, String replacementText, String shortDesc) { this(provider, replacementText, shortDesc, null); } /** * Constructor. * * @param provider The parent completion provider. * @param replacementText The text to replace. * @param shortDesc A short description of the completion. This will be * displayed in the completion list. This may be null. * @param summary The summary of this completion. This should be HTML. * This may be null. */ public BasicCompletion(CompletionProvider provider, String replacementText, String shortDesc, String summary) { super(provider); this.replacementText = replacementText; this.shortDesc = shortDesc; this.summary = summary; } /** * {@inheritDoc} */ public String getReplacementText() { return replacementText; } /** * Returns the short description of this completion, usually used in * the completion choices list. * * @return The short description, or null if there is none. * @see #setShortDescription(String) */ public String getShortDescription() { return shortDesc; } /** * {@inheritDoc} */ public String getSummary() { return summary; } /** * Sets the short description of this completion. * * @param shortDesc The short description of this completion. * @see #getShortDescription() */ public void setShortDescription(String shortDesc) { this.shortDesc = shortDesc; } /** * Sets the summary for this completion. * * @param summary The summary for this completion. * @see #getSummary() */ public void setSummary(String summary) { this.summary = summary; } /** * Returns a string representation of this completion. If the short * description is not null, this method will return: * * getInputText() + " - " + shortDesc * * otherwise, it will return getInputText(). * * @return A string representation of this completion. */ @Override public String toString() { if (shortDesc==null) { return getInputText(); } return getInputText() + " - " + shortDesc; } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/Completion.java000066400000000000000000000116261220700102300245710ustar00rootroot00000000000000/* * 12/21/2008 * * Completion.java - Represents a single completion choice. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import javax.swing.Icon; import javax.swing.text.JTextComponent; /** * Represents a completion choice. A {@link CompletionProvider} returns lists * of objects implementing this interface. A Completion contains the * following information: * *

* * @author Robert Futrell * @version 1.0 * @see AbstractCompletion */ public interface Completion extends Comparable { /** * Compares this completion to another one lexicographically, ignoring * case. * * @param other Another completion instance. * @return How this completion compares to the other one. */ public int compareTo(Completion other); /** * Returns the portion of this completion that has already been entered * into the text component. The match is case-insensitive.

* * This is a convenience method for: * getProvider().getAlreadyEnteredText(comp). * * @param comp The text component. * @return The already-entered portion of this completion. */ public String getAlreadyEntered(JTextComponent comp); /** * Returns the icon to use for this completion. * * @return The icon, or null for none. */ public Icon getIcon(); /** * 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, "sysout" mapping * to "System.out.println("). * * @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 "relevance" of this completion. This is used when sorting * completions by their relevance. It is an abstract concept that may * mean different things to different languages, and may depend on the * context of the completion.

* * By default, all completions have a relevance of 0. The * higher the value returned by this method, the higher up in the list * this completion will be; the lower the value returned, the lower it will * be. Completions with equal relevance values will be * sorted alphabetically. * * @return The relevance of this completion. */ public int getRelevance(); /** * 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 * null if there is no description for this * completion. */ public String getSummary(); /** * Returns the tool tip text to display for mouse hovers over this * completion.

* * Note that for this functionality to be enabled, a * JTextComponent must be registered with the * ToolTipManager, and the text component must know to search * for this value. In the case of an * RSyntaxTextArea, this * can be done with a org.fife.ui.rtextarea.ToolTipSupplier that * calls into * {@link CompletionProvider#getCompletionsAt(JTextComponent, java.awt.Point)}. * * @return The tool tip text for this completion, or null if * none. */ public String getToolTipText(); }autocomplete-2.5.0/src/org/fife/ui/autocomplete/CompletionCellRenderer.java000066400000000000000000000415051220700102300270570ustar00rootroot00000000000000/* * 12/23/2008 * * CompletionCellRenderer.java - Cell renderer that can render the standard * completion types like Eclipse or NetBeans does. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.awt.Graphics; import java.awt.Rectangle; import javax.swing.DefaultListCellRenderer; import javax.swing.Icon; import javax.swing.JList; import javax.swing.SwingUtilities; import javax.swing.plaf.basic.BasicHTML; import javax.swing.text.View; /** * A cell renderer that adds some pizazz when rendering the standard * {@link Completion} types, like Eclipse and NetBeans do. Specifically, * this renderer handles: * *

    *
  • {@link FunctionCompletion}s
  • *
  • {@link VariableCompletion}s
  • *
  • {@link MarkupTagCompletion}s
  • *
  • {@link ShorthandCompletion}s
  • *
  • {@link TemplateCompletion}s
  • *
* * @author Robert Futrell * @version 1.0 */ public class CompletionCellRenderer extends DefaultListCellRenderer { /** * The alternating background color, or null if alternating * row colors should not be used. */ private static Color altBG; /** * The font to use when rendering items, or null if the * list's default font should be used. */ private Font font; /** * Whether to display the types of fields and return types of functions * in the completion text. */ private boolean showTypes; /** * The color to use when rendering types in completion text. */ private String typeColor; /** * During rendering, whether the item being rendered is selected. */ private boolean selected; /** * During rendering, this is the "real" background color of the item being * rendered (i.e., what its background color is if it isn't selected). */ private Color realBG; /** * The color to use for function arguments. */ private String paramColor; /** * Used in rendering calculations. */ private Rectangle paintTextR; /** * An optional delegate renderer (primarily for Substance). */ private DefaultListCellRenderer delegate; private static final String SUBSTANCE_RENDERER_CLASS_NAME = "org.pushingpixels.substance.api.renderers.SubstanceDefaultListCellRenderer"; /** * Keeps the HTML descriptions from "wrapping" in the list, which cuts off * words. */ private static final String PREFIX = ""; /** * Constructor. */ public CompletionCellRenderer() { init(); } /** * Constructor. This is primarily a hook for Substance, or any other * Look and Feel whose renderers look drastically different than standard * DefaultListCellRenderers. Everything except for the text * rendering will be done by the delegate. In almost all scenarios, you * will want to use the no-argument constructor instead of this one. * * @param delegate The delegate renderer. * @see #delegateToSubstanceRenderer() */ public CompletionCellRenderer(DefaultListCellRenderer delegate) { setDelegateRenderer(delegate); init(); } /** * Returns a decent "parameter" color based on the current default * foreground color. * * @return The parameter color to use. */ private String createParamColor() { return Util.isLightForeground(getForeground()) ? Util.getHexString(Util.getHyperlinkForeground()): "#aa0077"; } /** * Returns a decent "type" color based on the current default foreground * color. * * @return The type color to use. */ private String createTypeColor() { return "#808080"; } /** * Attempts to delegate rendering to a Substance cell renderer. This * should only be called if Substance is known to be on the classpath. * * @throws Exception If Substance is not on the classpath, or some other * error occurs creating the Substance cell renderer. * @see Util#getUseSubstanceRenderers() * @see #setDelegateRenderer(DefaultListCellRenderer) */ public void delegateToSubstanceRenderer() throws Exception { Class clazz = Class.forName(SUBSTANCE_RENDERER_CLASS_NAME); DefaultListCellRenderer delegate = (DefaultListCellRenderer)clazz.newInstance(); setDelegateRenderer(delegate); } /** * Returns the background color to use on alternating lines. * * @return The alternate background color. If this is null, * alternating colors are not used. * @see #setAlternateBackground(Color) */ public static Color getAlternateBackground() { return altBG; } /** * Returns the delegate renderer, or null if there is none. * * @return The delegate renderer. * @see #setDelegateRenderer(DefaultListCellRenderer) */ public DefaultListCellRenderer getDelegateRenderer() { return delegate; } /** * Returns the font used when rendering completions. * * @return The font. If this is null, then the default list * font is used. * @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 list being rendered. * @param selected Whether the item is selected. * @param hasFocus Whether the item has focus. */ @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean selected, boolean hasFocus) { super.getListCellRendererComponent(list,value,index,selected,hasFocus); if (font!=null) { setFont(font); // Overrides super's setFont(list.getFont()). } this.selected = selected; this.realBG = altBG!=null && (index&1)==1 ? altBG : list.getBackground(); Completion c = (Completion)value; setIcon(c.getIcon()); if (c instanceof FunctionCompletion) { FunctionCompletion fc = (FunctionCompletion)value; prepareForFunctionCompletion(list, fc, index, selected, hasFocus); } else if (c instanceof VariableCompletion) { VariableCompletion vc = (VariableCompletion)value; prepareForVariableCompletion(list, vc, index, selected, hasFocus); } else if (c instanceof TemplateCompletion) { TemplateCompletion tc = (TemplateCompletion)value; prepareForTemplateCompletion(list, tc, index, selected, hasFocus); } else if (c instanceof MarkupTagCompletion) { MarkupTagCompletion mtc = (MarkupTagCompletion)value; prepareForMarkupTagCompletion(list, mtc, index, selected, hasFocus); } else { prepareForOtherCompletion(list, c, index, selected, hasFocus); } // A delegate renderer might do its own alternate row striping // (Substance does). if (delegate!=null) { delegate.getListCellRendererComponent(list, getText(), index, selected, hasFocus); delegate.setFont(getFont()); delegate.setIcon(getIcon()); return delegate; } if (!selected && (index&1)==1 && altBG!=null) { setBackground(altBG); } return this; } /** * Returns whether the types of fields and return types of methods are * shown in the completion text. * * @return Whether to show the types. * @see #setShowTypes(boolean) */ public boolean getShowTypes() { return showTypes; } private void init() { //setDisplayFont(new Font("Monospaced", Font.PLAIN, 12)); setShowTypes(true); typeColor = createTypeColor(); paramColor = createParamColor(); paintTextR = new Rectangle(); } @Override protected void paintComponent(Graphics g) { //super.paintComponent(g); g.setColor(realBG); int iconW = 0; if (getIcon()!=null) { iconW = getIcon().getIconWidth(); } if (selected && iconW>0) { // The icon area is never in the "selection" g.fillRect(0, 0, iconW, getHeight()); g.setColor(getBackground()); g.fillRect(iconW,0, getWidth()-iconW,getHeight()); } else { g.setColor(getBackground()); g.fillRect(0, 0, getWidth(), getHeight()); } if (getIcon()!=null) { getIcon().paintIcon(this, g, 0, 0); } String text = getText(); if (text != null) { paintTextR.setBounds(iconW,0, getWidth()-iconW,getHeight()); paintTextR.x += 3; // Force a slight margin int space = paintTextR.height - g.getFontMetrics().getHeight(); View v = (View)getClientProperty(BasicHTML.propertyKey); if (v != null) { // HTML rendering doesn't auto-center vertically, for some // reason paintTextR.y += space/2; paintTextR.height -= space; v.paint(g, paintTextR); } else { int textX = paintTextR.x; int textY = paintTextR.y;// + g.getFontMetrics().getAscent(); //System.out.println(g.getFontMetrics().getAscent()); g.drawString(text, textX, textY); } } } /** * Prepares this renderer to display a function completion. * * @param list The list of choices being rendered. * @param fc The completion to render. * @param index The index into list being rendered. * @param selected Whether the item is selected. * @param hasFocus Whether the item has focus. */ protected void prepareForFunctionCompletion(JList list, FunctionCompletion fc, int index, boolean selected, boolean hasFocus) { StringBuilder sb = new StringBuilder(PREFIX); sb.append(fc.getName()); char paramListStart = fc.getProvider().getParameterListStart(); if (paramListStart!=0) { // 0 => no start char sb.append(paramListStart); } int paramCount = fc.getParamCount(); for (int i=0; i"); } sb.append(type); if (!selected) { sb.append(""); } if (name!=null) { sb.append(' '); } } if (name!=null) { sb.append(name); } if (i No parameter list end char sb.append(paramListEnd); } if (getShowTypes() && fc.getType()!=null) { sb.append(" : "); if (!selected) { sb.append(""); } sb.append(fc.getType()); if (!selected) { sb.append(""); } } setText(sb.toString()); } /** * Prepares this renderer to display a markup tag completion. * * @param list The list of choices being rendered. * @param mc The completion to render. * @param index The index into list being rendered. * @param selected Whether the item is selected. * @param hasFocus Whether the item has focus. */ protected void prepareForMarkupTagCompletion(JList list, MarkupTagCompletion mc, int index, boolean selected, boolean hasFocus) { StringBuilder sb = new StringBuilder(PREFIX); sb.append(mc.getName()); setText(sb.toString()); } /** * Prepares this renderer to display a completion not specifically handled * elsewhere. * * @param list The list of choices being rendered. * @param c The completion to render. * @param index The index into list being rendered. * @param selected Whether the item is selected. * @param hasFocus Whether the item has focus. */ protected void prepareForOtherCompletion(JList list, Completion c, int index, boolean selected, boolean hasFocus) { StringBuilder sb = new StringBuilder(PREFIX); sb.append(c.getInputText()); if (c instanceof BasicCompletion) { String definition = ((BasicCompletion)c).getShortDescription(); if (definition!=null) { sb.append(" - "); if (!selected) { sb.append(""); } sb.append(definition); if (!selected) { sb.append(""); } } } setText(sb.toString()); } /** * Prepares this renderer to display a template completion. * * @param list The list of choices being rendered. * @param tc The completion to render. * @param index The index into list being rendered. * @param selected Whether the item is selected. * @param hasFocus Whether the item has focus. */ protected void prepareForTemplateCompletion(JList list, TemplateCompletion tc, int index, boolean selected, boolean hasFocus) { StringBuilder sb = new StringBuilder(PREFIX); sb.append(tc.getInputText()); String definition = tc.getShortDescription(); if (definition!=null) { sb.append(" - "); if (!selected) { sb.append(""); } sb.append(definition); if (!selected) { sb.append(""); } } setText(sb.toString()); } /** * Prepares this renderer to display a variable completion. * * @param list The list of choices being rendered. * @param vc The completion to render. * @param index The index into list being rendered. * @param selected Whether the item is selected. * @param hasFocus Whether the item has focus. */ protected void prepareForVariableCompletion(JList list, VariableCompletion vc, int index, boolean selected, boolean hasFocus) { StringBuilder sb = new StringBuilder(PREFIX); sb.append(vc.getName()); if (getShowTypes() && vc.getType()!=null) { sb.append(" : "); if (!selected) { sb.append(""); } sb.append(vc.getType()); if (!selected) { sb.append(""); } } setText(sb.toString()); } /** * Sets the background color to use on alternating lines. * * @param altBG The new alternate background color. If this is * null, alternating lines will not use different * background colors. * @see #getAlternateBackground() */ public static void setAlternateBackground(Color altBG) { CompletionCellRenderer.altBG = altBG; } /** * Sets the delegate renderer. Most users will never use this method; it * is primarily a hook for Substance and other Look and Feels whose * renderers look drastically different from the standard * DefaultListCellRenderer. * * @param delegate The new delegate renderer. If this is null, * the default rendering of this component is used. * @see #getDelegateRenderer() * @see #delegateToSubstanceRenderer() */ public void setDelegateRenderer(DefaultListCellRenderer delegate) { this.delegate = delegate; } /** * Sets the font to use when rendering completion items. * * @param font The font to use. If this is null, then * the default list font is used. * @see #getDisplayFont() */ public void setDisplayFont(Font font) { this.font = font; } /** * Sets the icon to display based off of a completion, falling back to a * default icon if the completion has no icon. * * @param completion The completion to check. * @param defaultIcon The icon to use if completion does not * specify an icon. */ protected void setIconWithDefault(Completion completion, Icon defaultIcon) { Icon icon = completion.getIcon(); setIcon(icon!=null ? icon : defaultIcon); } /** * Sets the color to use for function arguments. * * @param color The color to use. This is ignored if null. * @see #setTypeColor(Color) */ public void setParamColor(Color color) { if (color!=null) { paramColor = Util.getHexString(color); } } /** * Sets whether the types of fields and return types of methods are * shown in the completion text. * * @param show Whether to show the types. * @see #getShowTypes() */ public void setShowTypes(boolean show) { this.showTypes = show; } /** * Sets the color to use for function/field types. Note that if * {@link #getShowTypes()} returns false, this property * effectively does nothing. * * @param color The color to use for types. This is ignored if * null. * @see #setShowTypes(boolean) * @see #setParamColor(Color) */ public void setTypeColor(Color color) { if (color!=null) { typeColor = Util.getHexString(color); } } /** * Overridden to update our delegate, if necessary. */ @Override public void updateUI() { super.updateUI(); if (delegate!=null) { SwingUtilities.updateComponentTreeUI(delegate); } paramColor = createParamColor(); } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/CompletionListModel.java000066400000000000000000000033521220700102300264030ustar00rootroot00000000000000/* * 12/22/2008 * * CompletionListModel.java - A model that allows bulk addition of elements. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.swing.AbstractListModel; /** * A list model implementation that allows the bulk addition of elements. * This is the only feature missing from DefaultListModel that * we need. * * @author Robert Futrell * @version 1.0 */ class CompletionListModel extends AbstractListModel { /** * Container for items in this model. */ private List 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()); } } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/CompletionProvider.java000066400000000000000000000157151220700102300263070ustar00rootroot00000000000000/* * 12/21/2008 * * CompletionProvider.java - Provides autocompletion values based on the * text currently in a text component. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.awt.Point; import java.util.List; import javax.swing.ListCellRenderer; import javax.swing.text.JTextComponent; /** * Provides autocompletion values to an {@link AutoCompletion}.

* * 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 { /** * Clears the values used to identify and insert "parameterized completions" * (e.g. functions or methods). After this method is called, functions and * methods will not have their parameters auto-completed. * * @see #setParameterizedCompletionParams(char, String, char) */ public void clearParameterizedCompletionParams(); /** * 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. A return value of null means nothing * should be auto-completed; a value of an empty string * ("") means auto-completion should still be * considered (i.e., all possible choices are valid). */ 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, this may be null. */ public List getCompletions(JTextComponent comp); /** * Returns the completions that have been entered at the specified visual * location. This can be used for tool tips when the user hovers the * mouse over completed text. * * @param comp The text component. * @param p The position, usually from a MouseEvent. * @return The completions, or an empty list if there are none. */ public List getCompletionsAt(JTextComponent comp, Point p); /** * Returns the cell renderer for completions returned from this provider. * * @return The cell renderer, or null if the default should * be used. * @see #setListCellRenderer(ListCellRenderer) */ public ListCellRenderer getListCellRenderer(); /** * Returns an object that can return a list of completion choices for * parameters. This is used when a user code-completes a parameterized * completion, such as a function or method. For any parameter to the * function/method, this object can return possible completions. * * @return The parameter choices provider, or null if * none is installed. */ public ParameterChoicesProvider getParameterChoicesProvider(); /** * Returns a list of parameterized completions that have been entered * at the current caret position of a text component (and thus can have * their completion choices displayed). * * @param tc The text component. * @return The list of {@link ParameterizedCompletion}s. If no completions * are available, this may be null. */ public List getParameterizedCompletions(JTextComponent tc); /** * Returns the text that marks the end of a list of parameters to a * function or method. * * @return The text for a parameter list end, for example, * ')'. * @see #getParameterListStart() * @see #getParameterListSeparator() * @see #setParameterizedCompletionParams(char, String, char) */ public char getParameterListEnd(); /** * Returns the text that separates parameters to a function or method. * * @return The text that separates parameters, for example, * ", ". * @see #getParameterListStart() * @see #getParameterListEnd() * @see #setParameterizedCompletionParams(char, String, char) */ public String getParameterListSeparator(); /** * Returns the text that marks the start of a list of parameters to a * function or method. * * @return The text for a parameter list start, for example, * "(". * @see #getParameterListEnd() * @see #getParameterListSeparator() * @see #setParameterizedCompletionParams(char, String, char) */ public char getParameterListStart(); /** * Returns the parent completion provider. * * @return The parent completion provider. * @see #setParent(CompletionProvider) */ public CompletionProvider getParent(); /** * This method is called if auto-activation is enabled in the parent * {@link AutoCompletion} after the user types a single character. This * provider should check the text at the current caret position of the * text component, and decide whether auto-activation would be appropriate * here. For example, a CompletionProvider for Java might * want to return true for this method only if the last * character typed was a '.'. * * @param tc The text component. * @return Whether auto-activation would be appropriate. */ public boolean isAutoActivateOkay(JTextComponent tc); /** * Sets the renderer to use when displaying completion choices. * * @param r The renderer to use. * @see #getListCellRenderer() */ public void setListCellRenderer(ListCellRenderer r); /** * Sets the values used to identify and insert "parameterized completions" * (e.g. functions or methods). If this method isn't called, functions * and methods will not have their parameters auto-completed. * * @param listStart The character that marks the beginning of a list of * parameters, such as '(' in C or Java. * @param separator Text that should separate parameters in a parameter * list when one is inserted. For example, ", ". * @param listEnd The character that marks the end of a list of parameters, * such as ')' in C or Java. * @throws IllegalArgumentException If either listStart or * listEnd is not printable ASCII, or if * separator is null or an empty string. * @see #clearParameterizedCompletionParams() */ public void setParameterizedCompletionParams(char listStart, String separator, char listEnd); /** * Sets the parent completion provider. * * @param parent The parent provider. null means there will * be no parent provider. * @see #getParent() */ public void setParent(CompletionProvider parent); }autocomplete-2.5.0/src/org/fife/ui/autocomplete/CompletionProviderBase.java000066400000000000000000000144011220700102300270710ustar00rootroot00000000000000/* * 02/06/2010 * * CompletionProviderBase.java - Base completion provider implementation. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.util.Collections; import java.util.Comparator; import java.util.List; import javax.swing.ListCellRenderer; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import javax.swing.text.Segment; /** * A base class for all standard completion providers. This class implements * functionality that should be sharable across all CompletionProvider * implementations. * * @author Robert Futrell * @version 1.0 * @see AbstractCompletionProvider */ public abstract class CompletionProviderBase implements CompletionProvider { /** * The parent completion provider. */ private CompletionProvider parent; /** * The renderer to use for completions from this provider. If this is * null, a default renderer is used. */ private ListCellRenderer listCellRenderer; /** * Text that marks the beginning of a parameter list, for example, '('. */ private char paramListStart; /** * Text that marks the end of a parameter list, for example, ')'. */ private char paramListEnd; /** * Text that separates items in a parameter list, for example, ", ". */ private String paramListSeparator; /** * Whether auto-activation should occur after letters. */ private boolean autoActivateAfterLetters; /** * Non-letter chars that should cause auto-activation to occur. */ private String autoActivateChars; /** * Provides completion choices for a parameterized completion's parameters. */ private ParameterChoicesProvider paramChoicesProvider; /** * A segment to use for fast char access. */ private Segment s = new Segment(); protected static final String EMPTY_STRING = ""; /** * Comparator used to sort completions by their relevance before sorting * them lexicographically. */ private static final Comparator sortByRelevanceComparator = new SortByRelevanceComparator(); /** * {@inheritDoc} */ public void clearParameterizedCompletionParams() { paramListEnd = paramListStart = 0; paramListSeparator = null; } /** * {@inheritDoc} */ public List getCompletions(JTextComponent comp) { List completions = getCompletionsImpl(comp); if (parent!=null) { completions.addAll(parent.getCompletions(comp)); Collections.sort(completions); } // NOTE: We can't sort by relevance prior to this; we need to have // things alphabetical so we can easily narrow down completions to // those starting with what was already typed. if (/*sortByRelevance*/true) { Collections.sort(completions, sortByRelevanceComparator); } 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 abstract List getCompletionsImpl(JTextComponent comp); /** * {@inheritDoc} */ public ListCellRenderer getListCellRenderer() { return listCellRenderer; } /** * {@inheritDoc} */ public ParameterChoicesProvider getParameterChoicesProvider() { return paramChoicesProvider; } /** * {@inheritDoc} */ public char getParameterListEnd() { return paramListEnd; } /** * {@inheritDoc} */ public String getParameterListSeparator() { return paramListSeparator; } /** * {@inheritDoc} */ public char getParameterListStart() { return paramListStart; } /** * {@inheritDoc} */ public CompletionProvider getParent() { return parent; } /** * {@inheritDoc} */ public boolean isAutoActivateOkay(JTextComponent tc) { Document doc = tc.getDocument(); char ch = 0; try { doc.getText(tc.getCaretPosition(), 1, s); ch = s.first(); } catch (BadLocationException ble) { // Never happens ble.printStackTrace(); } return (autoActivateAfterLetters && Character.isLetter(ch)) || (autoActivateChars!=null && autoActivateChars.indexOf(ch)>-1); } /** * Sets the characters that auto-activation should occur after. A Java * completion provider, for example, might want to set others * to ".", to allow auto-activation for members of an object. * * @param letters Whether auto-activation should occur after any letter. * @param others A string of (non-letter) chars that auto-activation should * occur after. This may be null. */ public void setAutoActivationRules(boolean letters, String others) { autoActivateAfterLetters = letters; autoActivateChars = others; } /** * Sets the param choices provider. This is used when a user * code-completes a parameterized completion, such as a function or method. * For any parameter to the function/method, this object can return * possible completions. * * @param pcp The parameter choices provider, or null for * none. * @see #getParameterChoicesProvider() */ public void setParameterChoicesProvider(ParameterChoicesProvider pcp) { paramChoicesProvider = pcp; } /** * {@inheritDoc} */ public void setListCellRenderer(ListCellRenderer r) { listCellRenderer = r; } /** * {@inheritDoc} */ public void setParameterizedCompletionParams(char listStart, String separator, char listEnd) { if (listStart<0x20 || listStart==0x7F) { throw new IllegalArgumentException("Invalid listStart"); } if (listEnd<0x20 || listEnd==0x7F) { throw new IllegalArgumentException("Invalid listEnd"); } if (separator==null || separator.length()==0) { throw new IllegalArgumentException("Invalid separator"); } paramListStart = listStart; paramListSeparator = separator; paramListEnd = listEnd; } /** * {@inheritDoc} */ public void setParent(CompletionProvider parent) { this.parent = parent; } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/CompletionXMLParser.java000066400000000000000000000263371220700102300263340ustar00rootroot00000000000000/* * 02/06/2010 * * CompletionXMLParser.java - Parses XML representing code completion for a * C-like language. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.List; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; /** * Parser for an XML file describing a procedural language such as C. XML * files will be validated against the CompletionXml.dtd DTD * found in this package. * * @author Robert Futrell * @version 1.0 */ public class CompletionXMLParser extends DefaultHandler { /** * The completions found after parsing the XML. */ private List completions; /** * The provider we're getting completions for. */ private CompletionProvider provider; /** * The completion provider to use when loading classes, such as custom * {@link FunctionCompletion}s. */ private ClassLoader completionCL; private String name; private String type; private String returnType; private StringBuilder returnValDesc; private StringBuilder desc; private String paramName; private String paramType; private StringBuilder paramDesc; private List params; private String definedIn; private boolean doingKeywords; private boolean inKeyword; private boolean gettingReturnValDesc; private boolean gettingDesc; private boolean gettingParams; private boolean inParam; private boolean gettingParamDesc; private boolean inCompletionTypes; private char paramStartChar; private char paramEndChar; private String paramSeparator; /** * If specified in the XML, this class will be used instead of * {@link FunctionCompletion} when appropriate. This class should extend * FunctionCompletion, or stuff will break. */ private String funcCompletionType; /** * The class loader to use to load custom completion classes, such as * the one defined by {@link #funcCompletionType}. If this is * null, then a default class loader is used. This field * will usually be null. */ private static ClassLoader DEFAULT_COMPLETION_CLASS_LOADER; /** * Constructor. * * @param provider The provider to get completions for. * @see #reset(CompletionProvider) */ public CompletionXMLParser(CompletionProvider provider) { this(provider, null); } /** * Constructor. * * @param provider The provider to get completions for. * @param cl The class loader to use, if necessary, when loading classes * from the XML (custom {@link FunctionCompletion}s, for example). * This may be null if the default is to be used, or * if the XML does not define specific classes for completion types. * @see #reset(CompletionProvider) */ public CompletionXMLParser(CompletionProvider provider, ClassLoader cl) { this.provider = provider; this.completionCL = cl; if (completionCL==null) { // May also be null, but that's okay. completionCL = DEFAULT_COMPLETION_CLASS_LOADER; } completions = new ArrayList(); params = new ArrayList(1); desc = new StringBuilder(); paramDesc = new StringBuilder(); returnValDesc = new StringBuilder(); paramStartChar = paramEndChar = 0; paramSeparator = null; } /** * Called when character data inside an element is found. */ @Override public void characters(char[] ch, int start, int length) { if (gettingDesc) { desc.append(ch, start, length); } else if (gettingParamDesc) { paramDesc.append(ch, start, length); } else if (gettingReturnValDesc) { returnValDesc.append(ch, start, length); } } private FunctionCompletion createFunctionCompletion() { FunctionCompletion fc = null; if (funcCompletionType!=null) { try { Class clazz = null; if (completionCL!=null) { clazz = Class.forName(funcCompletionType, true, completionCL); } else { clazz = Class.forName(funcCompletionType); } Constructor c = clazz.getDeclaredConstructor( CompletionProvider.class, String.class, String.class); fc = (FunctionCompletion)c.newInstance(provider, name, returnType); } catch (RuntimeException re) { // FindBugs throw re; } catch (Exception e) { e.printStackTrace(); } } if (fc==null) { // Fallback if completion failed for some reason fc = new FunctionCompletion(provider, name, returnType); } if (desc.length()>0) { fc.setShortDescription(desc.toString()); desc.setLength(0); } fc.setParams(params); fc.setDefinedIn(definedIn); if (returnValDesc.length()>0) { fc.setReturnValueDescription(returnValDesc.toString()); returnValDesc.setLength(0); } return fc; } private BasicCompletion createOtherCompletion() { BasicCompletion bc = new BasicCompletion(provider, name); if (desc.length()>0) { bc.setSummary(desc.toString()); desc.setLength(0); } return bc; } private MarkupTagCompletion createMarkupTagCompletion() { MarkupTagCompletion mc = new MarkupTagCompletion(provider, name); if (desc.length()>0) { mc.setDescription(desc.toString()); desc.setLength(0); } mc.setAttributes(params); mc.setDefinedIn(definedIn); return mc; } private VariableCompletion createVariableCompletion() { VariableCompletion vc = new VariableCompletion(provider, name, returnType); if (desc.length()>0) { vc.setShortDescription(desc.toString()); desc.setLength(0); } vc.setDefinedIn(definedIn); return vc; } /** * Called when an element is closed. */ @Override 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)) { c = createFunctionCompletion(); } else if ("constant".equals(type)) { c = createVariableCompletion(); } else if ("tag".equals(type)) { // Markup tag, such as HTML c = createMarkupTagCompletion(); } else if ("other".equals(type)) { c = createOtherCompletion(); } else { throw new InternalError("Unexpected type: " + type); } completions.add(c); inKeyword = false; } else if (inKeyword) { if ("returnValDesc".equals(qName)) { gettingReturnValDesc = false; } else if (gettingParams) { if ("params".equals(qName)) { gettingParams = false; } else if ("param".equals(qName)) { FunctionCompletion.Parameter param = new FunctionCompletion.Parameter(paramType, paramName); if (paramDesc.length()>0) { param.setDescription(paramDesc.toString()); paramDesc.setLength(0); } params.add(param); inParam = false; } else if (inParam) { if ("desc".equals(qName)) { gettingParamDesc = false; } } } else if ("desc".equals(qName)) { gettingDesc = false; } } } else if (inCompletionTypes) { if ("completionTypes".equals(qName)) { inCompletionTypes = false; } } } @Override public void error(SAXParseException e) throws SAXException { throw e; } /** * Returns the completions found after parsing the XML. * * @return The completions. */ public List getCompletions() { return completions; } /** * Returns the parameter end character specified. * * @return The character, or 0 if none was specified. */ public char getParamEndChar() { return paramEndChar; } /** * Returns the parameter end string specified. * * @return The string, or null if none was specified. */ public String getParamSeparator() { return paramSeparator; } /** * Returns the parameter start character specified. * * @return The character, or 0 if none was specified. */ public char getParamStartChar() { return paramStartChar; } private static final char getSingleChar(String str) { return str.length()==1 ? str.charAt(0) : 0; } /** * Resets this parser to grab more completions. * * @param provider The new provider to get completions for. */ public void reset(CompletionProvider provider) { this.provider = provider; completions.clear(); doingKeywords = inKeyword = gettingDesc = gettingParams = inParam = gettingParamDesc = false; paramStartChar = paramEndChar = 0; paramSeparator = null; } @Override public InputSource resolveEntity(String publicID, String systemID) throws SAXException { return new InputSource(getClass(). getResourceAsStream("CompletionXml.dtd")); } /** * Sets the class loader to use when loading custom classes to use for * various {@link Completion} types, such as {@link FunctionCompletion}s, * from XML.

* * Users should very rarely have a need to use this method. * * @param cl The class loader to use. If this is null, then * a default is used. */ public static void setDefaultCompletionClassLoader(ClassLoader cl) { DEFAULT_COMPLETION_CLASS_LOADER = cl; } /** * Called when an element starts. */ @Override 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 ("returnValDesc".equals(qName)) { gettingReturnValDesc = true; } else if ("params".equals(qName)) { gettingParams = true; } else if (gettingParams) { if ("param".equals(qName)) { paramName = attrs.getValue("name"); paramType = attrs.getValue("type"); inParam = true; } if (inParam) { if ("desc".equals(qName)) { gettingParamDesc = true; } } } else if ("desc".equals(qName)) { gettingDesc = true; } } } else if ("environment".equals(qName)) { paramStartChar = getSingleChar(attrs.getValue("paramStartChar")); paramEndChar = getSingleChar(attrs.getValue("paramEndChar")); paramSeparator = attrs.getValue("paramSeparator"); //paramTerminal = attrs.getValua("terminal"); } else if ("completionTypes".equals(qName)) { inCompletionTypes = true; } else if (inCompletionTypes) { if ("functionCompletionType".equals(qName)) { funcCompletionType = attrs.getValue("type"); } } } @Override public void warning(SAXParseException e) throws SAXException { throw e; } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/CompletionXml.dtd000066400000000000000000000022601220700102300250760ustar00rootroot00000000000000 autocomplete-2.5.0/src/org/fife/ui/autocomplete/DefaultCompletionProvider.java000066400000000000000000000250241220700102300276060ustar00rootroot00000000000000/* * 12/21/2008 * * DefaultCompletionProvider.java - A basic completion provider implementation. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.awt.Point; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; 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; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.SAXException; /** * A basic completion provider implementation. This provider has no * understanding of language semantics. It simply checks the text entered up * to the caret position for a match against known completions. This is all * that is needed in the majority of cases. * * @author Robert Futrell * @version 1.0 */ public class DefaultCompletionProvider extends AbstractCompletionProvider { protected Segment seg; /** * Used to speed up {@link #getCompletionsAt(JTextComponent, Point)}. */ private String lastCompletionsAtText; /** * Used to speed up {@link #getCompletionsAt(JTextComponent, Point)}, * since this may be called multiple times in succession (this is usually * called by JTextComponent.getToolTipText(), and if the user * wiggles the mouse while a tool tip is displayed, this method gets * repeatedly called. It can be costly so we try to speed it up a tad). */ private List lastParameterizedCompletionsAt; /** * Constructor. The returned provider will not be aware of any completions. * * @see #addCompletion(Completion) */ public DefaultCompletionProvider() { init(); } /** * Creates a completion provider that provides completion for a simple * list of words. * * @param words The words to offer as completion suggestions. If this is * null, no completions will be known. * @see BasicCompletion */ public DefaultCompletionProvider(String[] words) { init(); addWordCompletions(words); } /** * Returns the text just before the current caret position that could be * the start of something auto-completable.

* * This method returns all characters before the caret that are matched * by {@link #isValidChar(char)}. * * {@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); } /** * {@inheritDoc} */ public List getCompletionsAt(JTextComponent tc, Point p) { int offset = tc.viewToModel(p); if (offset<0 || offset>=tc.getDocument().getLength()) { lastCompletionsAtText = null; return lastParameterizedCompletionsAt = null; } Segment s = new Segment(); Document doc = tc.getDocument(); Element root = doc.getDefaultRootElement(); int line = root.getElementIndex(offset); Element elem = root.getElement(line); int start = elem.getStartOffset(); int end = elem.getEndOffset() - 1; try { doc.getText(start, end-start, s); // Get the valid chars before the specified offset. int startOffs = s.offset + (offset-start) - 1; while (startOffs>=s.offset && isValidChar(s.array[startOffs])) { startOffs--; } // Get the valid chars at and after the specified offset. int endOffs = s.offset + (offset-start); while (endOffs list = getCompletionByInputText(text); lastCompletionsAtText = text; return lastParameterizedCompletionsAt = list; } catch (BadLocationException ble) { ble.printStackTrace(); // Never happens } lastCompletionsAtText = null; return lastParameterizedCompletionsAt = null; } /** * {@inheritDoc} */ public List getParameterizedCompletions( JTextComponent tc) { List list = null; // If this provider doesn't support parameterized completions, // bail out now. char paramListStart = getParameterListStart(); if (paramListStart==0) { return list; // null } int dot = tc.getCaretPosition(); Segment s = new Segment(); Document doc = tc.getDocument(); Element root = doc.getDefaultRootElement(); int line = root.getElementIndex(dot); Element elem = root.getElement(line); int offs = elem.getStartOffset(); int len = dot - offs - 1/*paramListStart.length()*/; if (len<=0) { // Not enough chars on line for a method. return list; // null } try { doc.getText(offs, len, s); // Get the identifier preceding the '(', ignoring any whitespace // between them. offs = s.offset + len - 1; while (offs>=s.offset && Character.isWhitespace(s.array[offs])) { offs--; } int end = offs; while (offs>=s.offset && isValidChar(s.array[offs])) { offs--; } String text = new String(s.array, offs+1, end-offs); // Get a list of all Completions matching the text, but then // narrow it down to just the ParameterizedCompletions. List l = getCompletionByInputText(text); if (l!=null && !l.isEmpty()) { for (int i=0; i(1); } list.add((ParameterizedCompletion)o); } } } } catch (BadLocationException ble) { ble.printStackTrace(); // Never happens } return list; } /** * Initializes this completion provider. */ protected void init() { completions = new ArrayList(); seg = new Segment(); } /** * Returns whether the specified character is valid in an auto-completion. * The default implementation is equivalent to * "Character.isLetterOrDigit(ch) || ch=='_'". 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=='_'; } /** * Loads completions from an XML file. The XML should validate against * CompletionXml.dtd. * * @param file An XML file to load from. * @throws IOException If an IO error occurs. */ public void loadFromXML(File file) throws IOException { BufferedInputStream bin = new BufferedInputStream( new FileInputStream(file)); try { loadFromXML(bin); } finally { bin.close(); } } /** * Loads completions from an XML input stream. The XML should validate * against CompletionXml.dtd. * * @param in The input stream to read from. * @throws IOException If an IO error occurs. */ public void loadFromXML(InputStream in) throws IOException { loadFromXML(in, null); } /** * Loads completions from an XML input stream. The XML should validate * against CompletionXml.dtd. * * @param in The input stream to read from. * @param cl The class loader to use when loading any extra classes defined * in the XML, such as custom {@link FunctionCompletion}s. This * may be null if the default is to be used, or if no * custom completions are defined in the XML. * @throws IOException If an IO error occurs. */ public void loadFromXML(InputStream in, ClassLoader cl) throws IOException { //long start = System.currentTimeMillis(); SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setValidating(true); CompletionXMLParser handler = new CompletionXMLParser(this, cl); BufferedInputStream bin = new BufferedInputStream(in); try { SAXParser saxParser = factory.newSAXParser(); saxParser.parse(bin, handler); List completions = handler.getCompletions(); addCompletions(completions); char startChar = handler.getParamStartChar(); if (startChar!=0) { char endChar = handler.getParamEndChar(); String sep = handler.getParamSeparator(); if (endChar!=0 && sep!=null && sep.length()>0) { // Sanity setParameterizedCompletionParams(startChar, sep, endChar); } } } catch (SAXException se) { throw new IOException(se.toString()); } catch (ParserConfigurationException pce) { throw new IOException(pce.toString()); } finally { //long time = System.currentTimeMillis() - start; //System.out.println("XML loaded in: " + time + "ms"); bin.close(); } } /** * Loads completions from an XML file. The XML should validate against * CompletionXml.dtd. * * @param resource A resource the current ClassLoader can get to. * @throws IOException If an IO error occurs. */ public void loadFromXML(String resource) throws IOException { ClassLoader cl = getClass().getClassLoader(); InputStream in = cl.getResourceAsStream(resource); if (in==null) { File file = new File(resource); if (file.isFile()) { in = new FileInputStream(file); } else { throw new IOException("No such resource: " + resource); } } BufferedInputStream bin = new BufferedInputStream(in); try { loadFromXML(bin); } finally { bin.close(); } } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/DelegatingCellRenderer.java000066400000000000000000000046721220700102300270150ustar00rootroot00000000000000/* * 12/22/2008 * * DelegatingCellRenderer.java - A renderer for Completions that will delegate * to the Completion's provider's renderer, if there is one. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.awt.Component; import javax.swing.DefaultListCellRenderer; import javax.swing.JComponent; 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 calls into a fallback renderer. * If a fallback renderer isn't specified, it simply renders * (({@link Completion})value).toString(). * * @author Robert Futrell * @version 1.0 */ class DelegatingCellRenderer extends DefaultListCellRenderer { /** * The renderer to fall back on if one isn't specified by a provider. * This is usually this. */ private ListCellRenderer fallback; /** * Returns the fallback cell renderer. * * @return The fallback cell renderer. * @see #setFallbackCellRenderer(ListCellRenderer) */ public ListCellRenderer getFallbackCellRenderer() { return fallback; } /** * {@inheritDoc} */ @Override 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); } if (fallback==null) { return super.getListCellRendererComponent(list, value, index, selected, hasFocus); } return fallback.getListCellRendererComponent(list, value, index, selected, hasFocus); } /** * Sets the fallback cell renderer. * * @param fallback The fallback cell renderer. If this is * null, this will be used. * @see #getFallbackCellRenderer() */ public void setFallbackCellRenderer(ListCellRenderer fallback) { this.fallback = fallback; } /** * {@inheritDoc} */ @Override public void updateUI() { super.updateUI(); if ((fallback instanceof JComponent) && fallback!=this) { ((JComponent)fallback).updateUI(); } } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/DescWindowCallback.java000066400000000000000000000016111220700102300261340ustar00rootroot00000000000000/* * 05/11/2012 * * Copyright (C) 2012 Robert Futrell * robert_futrell at users.sourceforge.net * http://fifesoft.com/rsyntaxtextarea * * This library is distributed under a modified BSD license. See the included * RSTALanguageSupport.License.txt file for details. */ package org.fife.ui.autocomplete; /** * Passed to {@link ExternalURLHandler}s as a way for them to display a summary * for a new completion in response to a link event. * * @author Robert Futrell * @version 1.0 * @see ExternalURLHandler */ public interface DescWindowCallback { /** * Callback allowing a new code completion's description to be displayed * in the description window. * * @param completion The new completion. * @param anchor The anchor to scroll to, or null if none. */ public void showSummaryFor(Completion completion, String anchor); }autocomplete-2.5.0/src/org/fife/ui/autocomplete/EmptyIcon.java000066400000000000000000000016611220700102300243650ustar00rootroot00000000000000/* * 04/29/2010 * * EmptyIcon.java - The canonical icon that paints nothing. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.awt.Component; import java.awt.Graphics; import java.io.Serializable; import javax.swing.Icon; /** * A standard icon that doesn't paint anything. This can be used when some * Completions have icons and others don't, to visually align the * text of all completions. * * @author Robert Futrell * @version 1.0 */ public class EmptyIcon implements Icon, Serializable { private int size; public EmptyIcon(int size) { this.size = size; } public int getIconHeight() { return size; } public int getIconWidth() { return size; } public void paintIcon(Component c, Graphics g, int x, int y) { } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/ExternalURLHandler.java000066400000000000000000000030701220700102300261150ustar00rootroot00000000000000/* * 12/23/2008 * * ExternalURLHandler.java - Implementations can be registered as a callback * to handle the user clicking on external URL's. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import javax.swing.event.HyperlinkEvent; /** * 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}, and * open the URL in a web browser yourself.

* * Alternatively, folks implementing robust code completion support for a * language might install an ExternalURLHandler to handle * navigating through linked documentation of objects, functions, etc. * * @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 e The event containing the hyperlink clicked. * @param c The completion currently being displayed. * @param callback Allows you to display new content in the description * window. */ public void urlClicked(HyperlinkEvent e, Completion c, DescWindowCallback callback); }autocomplete-2.5.0/src/org/fife/ui/autocomplete/FastListUI.java000066400000000000000000000132671220700102300244520ustar00rootroot00000000000000/* * 04/26/2010 * * FastListUI.java - A JList UI implementation that computes the preferred size * of all cells really fast, to facilitate lists of possibly thousands of items * rendered with HTML, which is slow with BasicListUI extensions. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.awt.Color; import java.awt.Dimension; import java.awt.SystemColor; import javax.swing.JViewport; import javax.swing.ListCellRenderer; import javax.swing.ListModel; import javax.swing.UIManager; import javax.swing.plaf.basic.BasicListUI; /** * A custom list UI, used by the completion choices list. If the number of * completion choices is "large," it does a fast estimate of the preferred * width and height of list items. This allows HTML renderers to be used (such * as {@link CompletionCellRenderer}), with thousands of completion choices, * with no performance penalty. With standard BasicListUI subclasses, this can * cause very poor performance each time the list is displayed, which * is bad for lists that are repeatedly hidden and re-displayed, such as * completion choices. This is all because the calculation to get the * preferred size of each list item, when it is displayed with HTML, is slow. * * @author Robert Futrell * @version 1.0 */ class FastListUI extends BasicListUI { /** * Whether the selection background was overridden (usually because of * Nimbus) so we know to manually uninstall the color we installed. */ private boolean overriddenBackground; /** * Whether the selection foreground was overridden (usually because of * Nimbus) so we know to manually uninstall the color we installed. */ private boolean overriddenForeground; /** * If there are more than this many completions in a single list, this * UI will estimate the cell width and height needed for each item instead * of computing it, for performance reasons. */ private static final int ESTIMATION_THRESHOLD = 200; private Color determineSelectionBackground() { Color c = UIManager.getColor("List.selectionBackground"); if (c==null) { c = UIManager.getColor("nimbusSelectionBackground"); if (c==null) { // Not Nimbus, but still need a value - fallback c = UIManager.getColor("textHighlight"); if (c==null) { c = SystemColor.textHighlight; } } } // Nimbus unfortunately requires a Color, not a ColorUIResource, for // the background override to work. This causes this color to "stick" // even if the LAF is changed to something else later. "c" here may // actually be a ColorUIResource return new Color(c.getRGB());//new ColorUIResource(c); } private Color determineSelectionForeground() { Color c = UIManager.getColor("List.selectionForeground"); if (c==null) { c = UIManager.getColor("nimbusSelectedText"); if (c==null) { // Not Nimbus, but still need a value - fallback c = UIManager.getColor("textHighlightText"); if (c==null) { c = SystemColor.textHighlightText; } } } // Nimbus unfortunately requires Color, not ColorUIResource, and "c" // may actually be a ColorUIResource return new Color(c.getRGB()); } /** * Overridden to ensure we have selection background/foreground colors * defined, even if we're in some weirdo LAF such as Nimbus which doesn't * define them. Since FastListUI extends BasicListUI, we need these values * to be defined. */ @Override protected void installDefaults() { super.installDefaults(); if (list.getSelectionBackground()==null) { list.setSelectionBackground(determineSelectionBackground()); overriddenBackground = true; } if (list.getSelectionForeground()==null) { list.setSelectionForeground(determineSelectionForeground()); overriddenForeground = true; } } /** * Overridden to work around a Nimbus issue. */ @Override protected void uninstallDefaults() { super.uninstallDefaults(); if (overriddenBackground) { list.setSelectionBackground(null); } if (overriddenForeground) { list.setSelectionForeground(null); } } /** * Recalculates the cell width and height of each cell in the list. This * method is overridden to do a fast estimation if the completion list is * too long, to improve performance for lists with huge amounts of * completions. */ @Override protected void updateLayoutState() { ListModel model = list.getModel(); int itemCount = model.getSize(); // If the item count is small enough to run fast on practically all // machines, go ahead and use the super implementation to determine // the optimal cell sizes. if (itemCount0) { Object value = model.getElementAt(0); java.awt.Component c = renderer.getListCellRendererComponent(list, value, 0, false, false); rendererPane.add(c); Dimension cellSize = c.getPreferredSize(); cellHeight = cellSize.height; cellWidth = Math.max(cellWidth, cellSize.width); } else { cellHeight = 20; } } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/FunctionCompletion.java000066400000000000000000000171741220700102300263030ustar00rootroot00000000000000/* * 12/22/2008 * * FunctionCompletion.java - A completion representing a function. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.util.ArrayList; import java.util.List; import javax.swing.text.BadLocationException; import javax.swing.text.JTextComponent; import javax.swing.text.Position; /** * A completion choice representing a function. * * @author Robert Futrell * @version 1.0 */ public class FunctionCompletion extends VariableCompletion implements ParameterizedCompletion { /** * Parameters to the function. */ private List params; /** * A description of the return value of this function. */ private String returnValDesc; /** * 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); } @Override protected void addDefinitionString(StringBuilder sb) { sb.append(""); sb.append(getDefinitionString()); sb.append(""); } /** * Adds HTML describing the parameters to this function to a buffer. * * @param sb The buffer to append to. */ protected void addParameters(StringBuilder sb) { // TODO: Localize me int paramCount = getParamCount(); if (paramCount>0) { sb.append("Parameters:
"); sb.append("

"); for (int i=0; i"); sb.append(param.getName()!=null ? param.getName() : param.getType()); sb.append(" "); String desc = param.getDescription(); if (desc!=null) { sb.append(desc); } sb.append("
"); } sb.append("


"); } if (returnValDesc!=null) { sb.append("Returns:
"); sb.append(returnValDesc); sb.append("


"); } } /** * Returns the "definition string" for this function completion. For * example, for the C "printf" function, this would return * "int printf(const char *, ...)". * * @return The definition string. */ @Override public String getDefinitionString() { StringBuilder sb = new StringBuilder(); // Add the return type if applicable (C macros like NULL have no type). String type = getType(); if (type!=null) { sb.append(type).append(' '); } // Add the item being described's name. sb.append(getName()); // Add parameters for functions. CompletionProvider provider = getProvider(); char start = provider.getParameterListStart(); if (start!=0) { sb.append(start); } for (int i=0; i 2 - // thanks to Matthew Adereth! String sep = getProvider().getParameterListSeparator(); if (i0 ? (dot+firstParamLen) : dot; info.setInitialSelection(dot, selectionEnd); info.setTextToInsert(sb.toString()); return info; } /** * {@inheritDoc} */ public Parameter getParam(int index) { return 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 boolean getShowParameterToolTip() { return true; } /** * Returns the text to insert for a parameter. * * @param param The parameter. * @return The text. */ private String getParamText(ParameterizedCompletion.Parameter param) { String text = param.getName(); if (text==null) { text = param.getType(); if (text==null) { // Shouldn't ever happen text = "arg"; } } return text; } /** * Returns the description of the return value of this function. * * @return The description, or null if there is none. * @see #setReturnValueDescription(String) */ public String getReturnValueDescription() { return returnValDesc; } /** * {@inheritDoc} */ @Override public String getSummary() { StringBuilder sb = new StringBuilder(); addDefinitionString(sb); if (!possiblyAddDescription(sb)) { sb.append("


"); } addParameters(sb); possiblyAddDefinedIn(sb); return sb.toString(); } /** * {@inheritDoc} */ @Override public String getToolTipText() { String text = getSummary(); if (text==null) { text = getDefinitionString(); } return text; } /** * Sets the parameters to this function. * * @param params The parameters. This should be a list of * {@link ParameterizedCompletion.Parameter}s. * @see #getParam(int) * @see #getParamCount() */ public void setParams(List params) { if (params!=null) { // Deep copy so parsing can re-use its array. this.params = new ArrayList(params); } } /** * Sets the description of the return value of this function. * * @param desc The description. * @see #getReturnValueDescription() */ public void setReturnValueDescription(String desc) { this.returnValDesc = desc; } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/LanguageAwareCompletionProvider.java000066400000000000000000000274671220700102300307420ustar00rootroot00000000000000/* * 01/03/2009 * * LanguageAwareCompletionProvider.java - A completion provider that is aware * of the language it is working with. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.awt.Point; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.text.JTextComponent; import org.fife.ui.rsyntaxtextarea.RSyntaxDocument; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities; import org.fife.ui.rsyntaxtextarea.Token; import org.fife.ui.rtextarea.RTextArea; import org.fife.ui.rtextarea.ToolTipSupplier; /** * A completion provider for the C programming language (and other languages * with similar syntax). This provider simply delegates to another provider, * depending on whether the caret is in: * *
    *
  • Code (plain text)
  • *
  • A string
  • *
  • A comment
  • *
  • A documentation comment
  • *
* * This allows for different completion choices in comments than in code, * for example.

* * This provider also implements the * org.fife.ui.rtextarea.ToolTipSupplier interface, which allows it * to display tooltips for completion choices. Thus the standard * {@link VariableCompletion} and {@link FunctionCompletion} completions should * be able to display tooltips with the variable declaration or function * definition (provided the RSyntaxTextArea was registered with the * javax.swing.ToolTipManager). * * @author Robert Futrell * @version 1.0 */ public class LanguageAwareCompletionProvider extends CompletionProviderBase implements ToolTipSupplier { /** * The provider to use when no provider is assigned to a particular token * type. */ private CompletionProvider defaultProvider; /** * The provider to use when completing in a string. */ private CompletionProvider stringCompletionProvider; /** * The provider to use when completing in a comment. */ private CompletionProvider commentCompletionProvider; /** * The provider to use while in documentation comments. */ private CompletionProvider docCommentCompletionProvider; /** * Constructor subclasses can use when they don't have their default * provider created at construction time. They should call * {@link #setDefaultCompletionProvider(CompletionProvider)} in this * constructor. */ protected LanguageAwareCompletionProvider() { } /** * Constructor. * * @param defaultProvider The provider to use when no provider is assigned * to a particular token type. This cannot be null. */ public LanguageAwareCompletionProvider(CompletionProvider defaultProvider) { setDefaultCompletionProvider(defaultProvider); } /** * Calling this method will result in an * {@link UnsupportedOperationException} being thrown. To set the * parameter completion parameters, do so on the provider returned by * {@link #getDefaultCompletionProvider()}. * * @throws UnsupportedOperationException Always. * @see #setParameterizedCompletionParams(char, String, char) */ @Override public void clearParameterizedCompletionParams() { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ public String getAlreadyEnteredText(JTextComponent comp) { if (!(comp instanceof RSyntaxTextArea)) { return EMPTY_STRING; } CompletionProvider provider = getProviderFor(comp); return provider!=null ? provider.getAlreadyEnteredText(comp) : null; } /** * Returns the completion provider to use for comments. * * @return The completion provider to use. * @see #setCommentCompletionProvider(CompletionProvider) */ public CompletionProvider getCommentCompletionProvider() { return commentCompletionProvider; } /** * {@inheritDoc} */ public List getCompletionsAt(JTextComponent tc, Point p) { return defaultProvider==null ? null : defaultProvider.getCompletionsAt(tc, p); } /** * 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. */ @Override protected List getCompletionsImpl(JTextComponent comp) { if (!(comp instanceof RSyntaxTextArea)) { return new ArrayList(0); } CompletionProvider provider = getProviderFor(comp); if (provider!=null) { return provider.getCompletions(comp); } return Collections.emptyList(); } /** * Returns the completion provider used when one isn't defined for a * particular token type. * * @return The completion provider to use. * @see #setDefaultCompletionProvider(CompletionProvider) */ public CompletionProvider getDefaultCompletionProvider() { return defaultProvider; } /** * Returns the completion provider to use for documentation comments. * * @return The completion provider to use. * @see #setDocCommentCompletionProvider(CompletionProvider) */ public CompletionProvider getDocCommentCompletionProvider() { return docCommentCompletionProvider; } /** * {@inheritDoc} */ public List getParameterizedCompletions( JTextComponent tc) { // Parameterized completions can only come from the "code" completion // provider. We do not do function/method completions while editing // strings or comments. CompletionProvider provider = getProviderFor(tc); return provider==defaultProvider ? provider.getParameterizedCompletions(tc) : null; } /** * {@inheritDoc} */ @Override public char getParameterListEnd() { return defaultProvider.getParameterListEnd(); } /** * {@inheritDoc} */ @Override public String getParameterListSeparator() { return defaultProvider.getParameterListSeparator(); } /** * {@inheritDoc} */ @Override public char getParameterListStart() { return defaultProvider.getParameterListStart(); } /** * Returns the completion provider to use at the current caret position in * a text component. * * @param comp The text component to check. * @return The completion provider to use. */ private CompletionProvider getProviderFor(JTextComponent comp) { RSyntaxTextArea rsta = (RSyntaxTextArea)comp; RSyntaxDocument doc = (RSyntaxDocument)rsta.getDocument(); int line = rsta.getCaretLineNumber(); Token t = doc.getTokenListForLine(line); if (t==null) { return getDefaultCompletionProvider(); } int dot = rsta.getCaretPosition(); Token curToken = RSyntaxUtilities.getTokenAtOffset(t, dot); if (curToken==null) { // At end of the line int type = doc.getLastTokenTypeOnLine(line); if (type==Token.NULL) { Token temp = t.getLastPaintableToken(); if (temp==null) { return getDefaultCompletionProvider(); } type = temp.getType(); } // TokenMakers can use types < 0 for "internal types." This // gives them a chance to map their internal types back to "real" // types to get completion providers. else if (type<0) { type = doc.getClosestStandardTokenTypeForInternalType(type); } switch (type) { case Token.ERROR_STRING_DOUBLE: return getStringCompletionProvider(); case Token.COMMENT_EOL: case Token.COMMENT_MULTILINE: return getCommentCompletionProvider(); case Token.COMMENT_DOCUMENTATION: return getDocCommentCompletionProvider(); default: return getDefaultCompletionProvider(); } } // FIXME: This isn't always a safe assumption. if (dot==curToken.getOffset()) { // At the very beginning of a new token // Need to check previous token for its type before deciding. // Previous token may also be on previous line! return getDefaultCompletionProvider(); } switch (curToken.getType()) { case Token.LITERAL_STRING_DOUBLE_QUOTE: case Token.ERROR_STRING_DOUBLE: return getStringCompletionProvider(); case Token.COMMENT_EOL: case Token.COMMENT_MULTILINE: return getCommentCompletionProvider(); case Token.COMMENT_DOCUMENTATION: return getDocCommentCompletionProvider(); case Token.NULL: case Token.WHITESPACE: case Token.IDENTIFIER: case Token.VARIABLE: case Token.PREPROCESSOR: case Token.DATA_TYPE: case Token.FUNCTION: case Token.OPERATOR: return getDefaultCompletionProvider(); } return null; // In a token type we can't auto-complete from. } /** * Returns the completion provider to use for strings. * * @return The completion provider to use. * @see #setStringCompletionProvider(CompletionProvider) */ public CompletionProvider getStringCompletionProvider() { return stringCompletionProvider; } /** * {@inheritDoc} */ @Override public boolean isAutoActivateOkay(JTextComponent tc) { CompletionProvider provider = getProviderFor(tc); return provider!=null ? provider.isAutoActivateOkay(tc) : false; } /** * Sets the comment completion provider. * * @param provider The provider to use in comments. * @see #getCommentCompletionProvider() */ public void setCommentCompletionProvider(CompletionProvider provider) { this.commentCompletionProvider = provider; } /** * Sets the default completion provider. * * @param provider The provider to use when no provider is assigned to a * particular token type. This cannot be null. * @see #getDefaultCompletionProvider() */ public void setDefaultCompletionProvider(CompletionProvider provider) { if (provider==null) { throw new IllegalArgumentException("provider cannot be null"); } this.defaultProvider = provider; } /** * Sets the documentation comment completion provider. * * @param provider The provider to use in comments. * @see #getDocCommentCompletionProvider() */ public void setDocCommentCompletionProvider(CompletionProvider provider) { this.docCommentCompletionProvider = provider; } /** * Calling this method will result in an * {@link UnsupportedOperationException} being thrown. To set the * parameter completion parameters, do so on the provider returned by * {@link #getDefaultCompletionProvider()}. * * @throws UnsupportedOperationException Always. * @see #clearParameterizedCompletionParams() */ @Override public void setParameterizedCompletionParams(char listStart, String separator, char listEnd) { throw new UnsupportedOperationException(); } /** * Sets the completion provider to use while in a string. * * @param provider The provider to use. * @see #getStringCompletionProvider() */ public void setStringCompletionProvider(CompletionProvider provider) { stringCompletionProvider = provider; } /** * Returns the tool tip to display for a mouse event.

* * For this method to be called, the RSyntaxTextArea must be * registered with the javax.swing.ToolTipManager like so: * *

	 * ToolTipManager.sharedInstance().registerComponent(textArea);
	 * 
* * @param textArea The text area. * @param e The mouse event. * @return The tool tip text, or null if none. */ public String getToolTipText(RTextArea textArea, MouseEvent e) { String tip = null; List completions = getCompletionsAt(textArea, e.getPoint()); if (completions!=null && completions.size()>0) { // Only ever 1 match for us in C... Completion c = completions.get(0); tip = c.getToolTipText(); } return tip; } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/LinkRedirector.java000066400000000000000000000005721220700102300253760ustar00rootroot00000000000000package org.fife.ui.autocomplete; import java.net.URL; /** * Possibly redirects one URL to another. Useful if you want "external" URL's * in code completion documentation to point to a local copy instead, for * example. * * @author Robert Futrell * @version 1.0 */ public interface LinkRedirector { public URL possiblyRedirect(URL original); }autocomplete-2.5.0/src/org/fife/ui/autocomplete/MarkupTagCompletion.java000066400000000000000000000121061220700102300263770ustar00rootroot00000000000000/* * 01/06/2009 * * MarkupTagComletion.java - A completion representing a tag in markup, such * as HTML or XML. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.util.ArrayList; import java.util.List; import org.fife.ui.autocomplete.ParameterizedCompletion.Parameter; /** * A completion representing a tag in markup, such as HTML or XML. * * @author Robert Futrell * @version 1.0 */ public class MarkupTagCompletion extends AbstractCompletion { private String name; private String desc; private String definedIn; /** * Attributes of the tag. */ private List attrs; /** * Constructor. * * @param provider The parent provider instance. * @param name The name of the tag. */ public MarkupTagCompletion(CompletionProvider provider, String name) { super(provider); this.name = name; } /** * Adds HTML describing the attributes of this tag to a buffer. * * @param sb The buffer to append to. */ protected void addAttributes(StringBuilder sb) { // TODO: Localize me. int attrCount = getAttributeCount(); if (attrCount>0) { sb.append("Attributes:
"); sb.append("
"); for (int i=0; i"); sb.append(attr.getName()!=null ? attr.getName() : attr.getType()); sb.append(" "); String desc = attr.getDescription(); if (desc!=null) { sb.append(desc); } sb.append("
"); } sb.append("


"); } } protected void addDefinitionString(StringBuilder sb) { sb.append("").append(name).append(""); } /** * Returns all attributes of this tag. * * @return A list of {@link ParameterizedCompletion.Parameter}s. * @see #getAttribute(int) * @see #getAttributeCount() */ public List getAttributes() { return attrs; } /** * Returns the specified {@link ParameterizedCompletion.Parameter}. * * @param index The index of the attribute to retrieve. * @return The attribute. * @see #getAttributeCount() */ public Parameter getAttribute(int index) { return attrs.get(index); } /** * Returns the number of attributes of this tag. * * @return The number of attributes of this tag. * @see #getAttribute(int) */ public int getAttributeCount() { return attrs==null ? 0 : attrs.size(); } /** * 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 * null. * @see #setDescription(String) */ public String getDescription() { return desc; } /** * Returns the name of this tag. * * @return The name of this tag. */ public String getName() { return name; } /** * {@inheritDoc} */ public String getReplacementText() { return getName(); } /** * {@inheritDoc} */ public String getSummary() { StringBuilder sb = new StringBuilder(); addDefinitionString(sb); possiblyAddDescription(sb); addAttributes(sb); possiblyAddDefinedIn(sb); return sb.toString(); } /** * Adds some HTML describing where this variable is defined, if this * information is known. * * @param sb The buffer to append to. */ protected void possiblyAddDefinedIn(StringBuilder sb) { if (definedIn!=null) { sb.append("
Defined in:"); // TODO: Localize me sb.append(" ").append(definedIn).append(""); } } /** * Adds the description text as HTML to a buffer, if a description is * defined. * * @param sb The buffer to append to. */ protected void possiblyAddDescription(StringBuilder sb) { if (desc!=null) { sb.append("

"); sb.append(desc); sb.append("


"); } } /** * 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 tag. This should be an * HTML snippet. * * @param desc A short description of this tag. This may be * null. * @see #getDescription() */ public void setDescription(String desc) { this.desc = desc; } /** * Sets the attributes of this tag. * * @param attrs The attributes. * @see #getAttribute(int) * @see #getAttributeCount() */ public void setAttributes(List attrs) { // Deep copy so parsing can re-use its array. this.attrs = new ArrayList(attrs); } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/OutlineHighlightPainter.java000066400000000000000000000075561220700102300272610ustar00rootroot00000000000000/* * 04/26/2009 * * OutlineHighlightPainter.java - Highlight painter that draws an outline * around its text. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.awt.Color; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Shape; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultHighlighter; import javax.swing.text.JTextComponent; import javax.swing.text.Position; import javax.swing.text.View; /** * Highlight painter that draws an outline around the text. This is used to * draw bounds around function/method parameters. * * @author Robert Futrell * @version 1.0 */ /* * NOTE: Whenever you see text like "Workaround for Java Highlight issues", * this is because highlighted text in a JTextComponent gets "pushed" forward * when the caret is at the Highlight's start, when we need it to instead get * prepended to. For this reason, the auto-complete package adds its Highlights * 1 char too long (1 char earlier than where it should really start), but only * paint the Highlight from the 2nd char on. */ class OutlineHighlightPainter extends DefaultHighlighter.DefaultHighlightPainter { /** * DefaultHighlightPainter doesn't allow changing color, so we must cache * ours here. */ private Color color; /** * Constructor. * * @param color The color to draw the bounding boxes with. This cannot * be null. */ public OutlineHighlightPainter(Color color) { super(color); setColor(color); } /** * Returns the color to paint bounding boxes with. * * @return The color. * @see #setColor(Color) */ @Override public Color getColor() { return color; } /** * {@inheritDoc} */ @Override public Shape paintLayer(Graphics g, int p0, int p1, Shape viewBounds, JTextComponent c, View view) { g.setColor(getColor()); p0++; // Workaround for Java Highlight issues. // This special case isn't needed for most standard Swing Views (which // always return a width of 1 for modelToView() calls), but it is // needed for RSTA views, which actually return the width of chars for // modelToView calls. But this should be faster anyway, as we // short-circuit and do only one modelToView() for one offset. if (p0==p1) { try { Shape s = view.modelToView(p0, viewBounds, Position.Bias.Forward); Rectangle r = s.getBounds(); g.drawLine(r.x, r.y, r.x, r.y+r.height); return r; } catch (BadLocationException ble) { ble.printStackTrace(); // Never happens return null; } } if (p0 == view.getStartOffset() && p1 == view.getEndOffset()) { // Contained in view, can just use bounds. Rectangle alloc; if (viewBounds instanceof Rectangle) { alloc = (Rectangle) viewBounds; } else { alloc = viewBounds.getBounds(); } g.drawRect(alloc.x, alloc.y, alloc.width - 1, alloc.height - 1); return alloc; } // Should only render part of View. try { // --- determine locations --- Shape shape = view.modelToView(p0, Position.Bias.Forward, p1, Position.Bias.Backward, viewBounds); Rectangle r = (shape instanceof Rectangle) ? (Rectangle) shape : shape.getBounds(); g.drawRect(r.x, r.y, r.width - 1, r.height - 1); return r; } catch (BadLocationException e) { // Never happens e.printStackTrace(); return null; } } /** * Sets the color to paint the bounding boxes with. * * @param color The new color. This cannot be null. * @see #getColor() */ public void setColor(Color color) { if (color==null) { throw new IllegalArgumentException("color cannot be null"); } this.color = color; } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/ParameterChoicesProvider.java000066400000000000000000000022471220700102300274100ustar00rootroot00000000000000/* * 12/14/2010 * * ParameterChoicesProvider.java - Provides completions for a * ParameterizedCompletion's parameters. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.util.List; import javax.swing.text.JTextComponent; /** * Provides completions for a {@link ParameterizedCompletion}'s parameters. * So, for example, if the user code-completes a function or method, if * a ParameterChoicesProvider is installed, it can return possible * completions for the parameters to that function or method. * * @author Robert Futrell * @version 1.0 */ public interface ParameterChoicesProvider { /** * Returns a list of choices for a specific parameter. * * @param tc The text component. * @param param The currently focused parameter. * @return The list of parameters. This may be null for * "no parameters," but might also be an empty list. */ public List getParameterChoices(JTextComponent tc, ParameterizedCompletion.Parameter param); }autocomplete-2.5.0/src/org/fife/ui/autocomplete/ParameterizedCompletion.java000066400000000000000000000112301220700102300272750ustar00rootroot00000000000000/* * 12/11/2010 * * ParameterizedCompletion.java - A completion option. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import javax.swing.text.JTextComponent; /** * A completion option that takes parameters, such as a function or method. * * @author Robert Futrell * @version 1.0 */ public interface ParameterizedCompletion extends Completion { /** * Returns the "definition string" for this completion. For example, * for the C "printf" function, this would return * "int printf(const char *, ...)". * * @return The definition string. */ public String getDefinitionString(); /** * Returns the specified {@link Parameter}. * * @param index The index of the parameter to retrieve. * @return The parameter. * @see #getParamCount() */ public Parameter getParam(int index); /** * Returns the number of parameters this completion takes. * * @return The number of parameters this completion takes. * @see #getParam(int) */ public int getParamCount(); public ParameterizedCompletionInsertionInfo getInsertionInfo( JTextComponent tc, boolean replaceTabsWithSpaces); /** * Returns whether a tool tip displaying assistance for each parameter * while it is being edited is appropriate for this completion. * * @return Whether the tool tip is appropriate to display. */ public boolean getShowParameterToolTip(); /** * A parameter passed to a parameterized {@link Completion}. */ public static class Parameter { private String name; private Object type; private String desc; private boolean isEndParam; /** * Constructor. * * @param type The type of this parameter. This may be * null for languages without specific types, * dynamic typing, etc. Usually you'll pass a String for this * value, but you may pass any object representing a type in * your language, as long as its toString() method * returns a string representation of the type. * @param name The name of the parameter. */ public Parameter(Object type, String name) { this(type, name, false); } /** * Constructor. * * @param type The type of this parameter. This may be * null for languages without specific types, * dynamic typing, etc. Usually you'll pass a String for this * value, but you may pass any object representing a type in * your language, as long as its toString() method * returns a string representation of the type. * @param name The name of the parameter. * @param endParam Whether this parameter is an "ending parameter;" * that is, whether this parameter is at a logical "ending * point" in the completion text. If the user types in a * parameter that is an ending point, parameter completion mode * terminates. Set this to true for a trailing * parameter after a function call's closing ')', for example. */ public Parameter(Object type, String name, boolean endParam) { this.name = name; this.type = type; this.isEndParam = endParam; } public String getDescription() { return desc; } public String getName() { return name; } /** * Returns the type of this parameter, as a string. * * @return The type of the parameter, or null for none. */ public String getType() { return type==null ? null : type.toString(); } /** * Returns the object used to describe the type of this parameter. * * @return The type object, or null for none. */ public Object getTypeObject() { return type; } /** * @return Whether this parameter is an "ending parameter;" * that is, whether this parameter is at a logical "ending * point" in the completion text. If the user types in a * parameter that is an ending point, parameter completion mode * terminates. */ public boolean isEndParam() { return isEndParam; } public void setDescription(String desc) { this.desc = desc; } @Override public String toString() { StringBuilder sb = new StringBuilder(); if (getType()!=null) { sb.append(getType()); } if (getName()!=null) { if (getType()!=null) { sb.append(' '); } sb.append(getName()); } return sb.toString(); } } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/ParameterizedCompletionChoicesWindow.java000066400000000000000000000204701220700102300317710ustar00rootroot00000000000000/* * 12/11/2010 * * ParameterizedCompletionChoicesWindow.java - A list of likely choices for a * parameter. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.awt.ComponentOrientation; import java.awt.Dimension; import java.awt.Rectangle; import java.awt.Window; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import javax.swing.DefaultListModel; import javax.swing.JList; import javax.swing.JScrollPane; import javax.swing.JWindow; import javax.swing.SwingUtilities; import javax.swing.text.JTextComponent; import org.fife.ui.rsyntaxtextarea.PopupWindowDecorator; /** * A small popup window offering a list of likely choices for a parameter * when the user has code-completed a parameterized completion. For example, * if they have just code-completed the C function "fprintf", * when entering the file name, this popup might display all local variables * of type "char *". * * @author Robert Futrell * @version 1.0 */ public class ParameterizedCompletionChoicesWindow extends JWindow { /** * The parent AutoCompletion instance. */ private AutoCompletion ac; /** * The list of completion choices. */ private JList list; /** * The currently displayed completion choices. */ private DefaultListModel model; /** * A list of lists of choices for each parameter. */ private List> choicesListList; /** * The scroll pane containing the list. */ private JScrollPane sp; /** * Comparator used to sort completions by their relevance before sorting * them lexicographically. */ private static final Comparator sortByRelevanceComparator = new SortByRelevanceComparator(); /** * Constructor. * * @param parent The parent window (hosting the text component). * @param ac The auto-completion instance. * @param context The completion context. */ public ParameterizedCompletionChoicesWindow(Window parent, AutoCompletion ac, final ParameterizedCompletionContext context) { super(parent); this.ac = ac; ComponentOrientation o = ac.getTextComponentOrientation(); model = new DefaultListModel(); list = new JList(model); if (ac.getParamChoicesRenderer()!=null) { list.setCellRenderer(ac.getParamChoicesRenderer()); } list.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (e.getClickCount()==2) { context.insertSelectedChoice(); } } }); sp = new JScrollPane(list); setContentPane(sp); applyComponentOrientation(o); setFocusableWindowState(false); // Give apps a chance to decorate us with drop shadows, etc. PopupWindowDecorator decorator = PopupWindowDecorator.get(); if (decorator!=null) { decorator.decorate(this); } } /** * Returns the selected value. * * @return The selected value, or null if nothing is * selected. */ public String getSelectedChoice() { Completion c = (Completion)list.getSelectedValue(); return c==null ? null : c.toString(); } /** * Changes the selected index. * * @param amount The amount by which to change the selected index. */ public void incSelection(int amount) { int selection = list.getSelectedIndex(); selection += amount; if (selection<0) { // Account for nothing selected yet selection = model.getSize()-1;//+= model.getSize(); } else { selection %= model.getSize(); } list.setSelectedIndex(selection); list.ensureIndexIsVisible(selection); } /** * Initializes this window to offer suggestions for the parameters of * a specific completion. * * @param pc The completion whose parameters we should offer suggestions * for. */ public void initialize(ParameterizedCompletion pc) { CompletionProvider provider = pc.getProvider(); ParameterChoicesProvider pcp = provider.getParameterChoicesProvider(); if (pcp==null) { choicesListList = null; return; } int paramCount = pc.getParamCount(); choicesListList = new ArrayList>(paramCount); JTextComponent tc = ac.getTextComponent(); for (int i=0; i choices = pcp.getParameterChoices(tc, param); choicesListList.add(choices); } } /** * Sets the location of this window relative to the given rectangle. * * @param r The visual position of the caret (in screen coordinates). */ public void setLocationRelativeTo(Rectangle r) { // Multi-monitor support - make sure the completion window (and // description window, if applicable) both fit in the same window in // a multi-monitor environment. To do this, we decide which monitor // the rectangle "r" is in, and use that one (just pick top-left corner // as the defining point). Rectangle screenBounds = Util.getScreenBoundsForPoint(r.x, r.y); //Dimension screenSize = tooltip.getToolkit().getScreenSize(); // Try putting our stuff "below" the caret first. int y = r.y + r.height + 5; // Get x-coordinate of completions. Try to align left edge with the // caret first. int x = r.x; if (xscreenBounds.x+screenBounds.width) { // completions don't fit x = screenBounds.x + screenBounds.width - getWidth(); } setLocation(x, y); } /** * Displays the choices for the specified parameter matching the given * text. This will display or hide this popup window as necessary. * * @param param The index of the parameter the caret is currently in. * This may be -1 if not in a parameter (i.e., on * the comma between parameters). * @param prefix Text in the parameter before the dot. This may * be null to represent the empty string. */ public void setParameter(int param, String prefix) { model.clear(); List temp = new ArrayList(); if (choicesListList!=null && param>=0 && param choices = choicesListList.get(param); if (choices!=null) { for (Completion c : choices) { String choice = c.getReplacementText(); if (prefix==null || Util.startsWithIgnoreCase(choice, prefix)) { temp.add(c); } } } // Sort completions appropriately. Comparator c = null; if (/*sortByRelevance*/true) { c = sortByRelevanceComparator; } Collections.sort(temp, c); for (int i=0; i0) { Dimension size = getPreferredSize(); if (size.width<150) { setSize(150, size.height); } else { pack(); } // Make sure nothing is ever obscured by vertical scroll bar. if (sp.getVerticalScrollBar()!=null && sp.getVerticalScrollBar().isVisible()) { size = getSize(); int w = size.width + sp.getVerticalScrollBar().getWidth()+5; setSize(w, size.height); } list.setSelectedIndex(0); list.ensureIndexIsVisible(0); if (!isVisible()) { setVisible(true); } } } else { setVisible(false); } } /** * Toggles the visibility of this popup window. * * @param visible Whether this window should be visible. */ @Override public void setVisible(boolean visible) { if (visible!=isVisible()) { // i.e. if no possibilities matched what's been typed if (visible && model.size()==0) {//list.getVisibleRowCount()==0) { return; } super.setVisible(visible); } } /** * Updates the LookAndFeel of this window. */ public void updateUI() { SwingUtilities.updateComponentTreeUI(this); } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/ParameterizedCompletionContext.java000066400000000000000000001017671220700102300306610ustar00rootroot00000000000000/* * 06/17/2012 * * ParameritizedCompletionContext.java - Manages the state of parameterized * completion-related UI components during code completion. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.awt.Point; import java.awt.Rectangle; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.InputMap; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.AbstractDocument; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultEditorKit; import javax.swing.text.Document; import javax.swing.text.Highlighter; import javax.swing.text.JTextComponent; import javax.swing.text.Position; import javax.swing.text.Highlighter.Highlight; import javax.swing.text.Highlighter.HighlightPainter; import org.fife.ui.autocomplete.ParameterizedCompletion.Parameter; import org.fife.ui.autocomplete.ParameterizedCompletionInsertionInfo.ReplacementCopy; import org.fife.ui.rsyntaxtextarea.DocumentRange; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rtextarea.ChangeableHighlightPainter; /** * Manages UI and state specific to parameterized completions - the parameter * description tool tip, the parameter completion choices list, the actual * highlights in the editor, etc. This component installs new key bindings * when appropriate to allow the user to cycle through the parameters of the * completion, and optionally cycle through completion choices for those * parameters. * * @author Robert Futrell * @version 1.0 */ class ParameterizedCompletionContext { /** * The parent window. */ private Window parentWindow; /** * The parent AutoCompletion instance. */ private AutoCompletion ac; /** * The completion being described. */ private ParameterizedCompletion pc; /** * Whether parameterized completion assistance is active. */ private boolean active; /** * A tool tip displaying the currently edited parameter name and type. */ private ParameterizedCompletionDescriptionToolTip tip; /** * The painter to paint borders around the variables. */ private Highlighter.HighlightPainter p; private Highlighter.HighlightPainter endingP; private Highlighter.HighlightPainter paramCopyP; /** * The tags for the highlights around parameters. */ private List tags; private List paramCopyInfos; private transient boolean ignoringDocumentEvents; /** * Listens for events in the text component while this window is visible. */ private Listener listener; /** * The minimum offset into the document that the caret can move to * before this tool tip disappears. */ private int minPos; /** * The maximum offset into the document that the caret can move to * before this tool tip disappears. */ private Position maxPos; // Moves with text inserted. private Position defaultEndOffs; /** * The currently "selected" parameter in the displayed text. */ private int lastSelectedParam; /** * A small popup window giving likely choices for parameterized completions. */ private ParameterizedCompletionChoicesWindow paramChoicesWindow; /** * The text before the caret for the current parameter. If * {@link #paramChoicesWindow} is non-null, this is used to * determine what parameter choices to actually show. */ private String paramPrefix; private Object oldTabKey; private Action oldTabAction; private Object oldShiftTabKey; private Action oldShiftTabAction; private Object oldUpKey; private Action oldUpAction; private Object oldDownKey; private Action oldDownAction; private Object oldEnterKey; private Action oldEnterAction; private Object oldEscapeKey; private Action oldEscapeAction; private Object oldClosingKey; private Action oldClosingAction; private static final String IM_KEY_TAB = "ParamCompKey.Tab"; private static final String IM_KEY_SHIFT_TAB = "ParamCompKey.ShiftTab"; private static final String IM_KEY_UP = "ParamCompKey.Up"; private static final String IM_KEY_DOWN = "ParamCompKey.Down"; private static final String IM_KEY_ESCAPE = "ParamCompKey.Escape"; private static final String IM_KEY_ENTER = "ParamCompKey.Enter"; private static final String IM_KEY_CLOSING = "ParamCompKey.Closing"; /** * Constructor. */ public ParameterizedCompletionContext(Window owner, AutoCompletion ac, ParameterizedCompletion pc) { this.parentWindow = owner; this.ac = ac; this.pc = pc; listener = new Listener(); AutoCompletionStyleContext sc = AutoCompletion.getStyleContext(); p = new OutlineHighlightPainter(sc.getParameterOutlineColor()); endingP = new OutlineHighlightPainter( sc.getParameterizedCompletionCursorPositionColor()); paramCopyP = new ChangeableHighlightPainter(sc.getParameterCopyColor()); tags = new ArrayList(1); // Usually small paramCopyInfos = new ArrayList(1); } /** * Activates parameter completion support. * * @see #deactivate() */ public void activate() { if (active) { return; } active = true; JTextComponent tc = ac.getTextComponent(); lastSelectedParam = -1; if (pc.getShowParameterToolTip()) { tip = new ParameterizedCompletionDescriptionToolTip( parentWindow, this, ac, pc); try { int dot = tc.getCaretPosition(); Rectangle r = tc.modelToView(dot); Point p = new Point(r.x, r.y); SwingUtilities.convertPointToScreen(p, tc); r.x = p.x; r.y = p.y; tip.setLocationRelativeTo(r); tip.setVisible(true); } catch (BadLocationException ble) { // Should never happen UIManager.getLookAndFeel().provideErrorFeedback(tc); ble.printStackTrace(); tip = null; } } listener.install(tc); // First time through, we'll need to create this window. if (paramChoicesWindow==null) { paramChoicesWindow = createParamChoicesWindow(); } lastSelectedParam = getCurrentParameterIndex(); prepareParamChoicesWindow(); paramChoicesWindow.setVisible(true); } /** * Creates the completion window offering suggestions for parameters. * * @return The window. */ private ParameterizedCompletionChoicesWindow createParamChoicesWindow() { ParameterizedCompletionChoicesWindow pcw = new ParameterizedCompletionChoicesWindow(parentWindow, ac, this); pcw.initialize(pc); return pcw; } /** * Hides any popup windows and terminates parameterized completion * assistance. * * @see #activate() */ public void deactivate() { if (!active) { return; } active = false; listener.uninstall(); if (tip!=null) { tip.setVisible(false); } if (paramChoicesWindow!=null) { paramChoicesWindow.setVisible(false); } } /** * Returns the text inserted for the parameter containing the specified * offset. * * @param offs The offset into the document. * @return The text of the parameter containing the offset, or * null if the offset is not in a parameter. */ public String getArgumentText(int offs) { List paramHighlights = getParameterHighlights(); if (paramHighlights==null || paramHighlights.size()==0) { return null; } for (Highlight h : paramHighlights) { if (offs>=h.getStartOffset() && offs<=h.getEndOffset()) { int start = h.getStartOffset() + 1; int len = h.getEndOffset() - start; JTextComponent tc = ac.getTextComponent(); Document doc = tc.getDocument(); try { return doc.getText(start, len); } catch (BadLocationException ble) { UIManager.getLookAndFeel().provideErrorFeedback(tc); ble.printStackTrace(); return null; } } } return null; } /** * Returns the highlight of the current parameter. * * @return The current parameter's highlight, or null if * the caret is not in a parameter's bounds. * @see #getCurrentParameterStartOffset() */ private Highlight getCurrentParameterHighlight() { JTextComponent tc = ac.getTextComponent(); int dot = tc.getCaretPosition(); if (dot>0) { dot--; // Workaround for Java Highlight issues } List paramHighlights = getParameterHighlights(); for (Highlight h : paramHighlights) { if (dot>=h.getStartOffset() && dot0) { dot--; // Workaround for Java Highlight issues } List paramHighlights = getParameterHighlights(); for (int i=0; i=h.getStartOffset() && dot-1 if * the caret is not in a parameter's bounds. * @see #getCurrentParameterHighlight() */ private int getCurrentParameterStartOffset() { Highlight h = getCurrentParameterHighlight(); return h!=null ? h.getStartOffset()+1 : -1; } /** * Returns the highlight from a list that comes "first" in a list. Even * though most parameter highlights are ordered, sometimes they aren't * (e.g. the "cursor" parameter in a template completion is always last, * even though it can be anywhere in the template). * * @param highlights The list of highlights. Assumed to be non-empty. * @return The highlight that comes first in the document. * @see #getLastHighlight(List) */ private static final int getFirstHighlight(List highlights) { int first = -1; Highlight firstH = null; for (int i=0; i highlights) { int last = -1; Highlight lastH = null; for (int i=highlights.size()-1; i>=0; i--) { Highlight h = highlights.get(i); if (lastH==null || h.getStartOffset()>lastH.getStartOffset()) { lastH = h; last = i; } } return last; } public List getParameterHighlights() { List paramHighlights = new ArrayList(2); JTextComponent tc = ac.getTextComponent(); Highlight[] highlights = tc.getHighlighter().getHighlights(); for (int i=0; ifalse * if the window is not visible, or no choice is selected. */ boolean insertSelectedChoice() { if (paramChoicesWindow!=null && paramChoicesWindow.isVisible()) { String choice = paramChoicesWindow.getSelectedChoice(); if (choice!=null) { JTextComponent tc = ac.getTextComponent(); Highlight h = getCurrentParameterHighlight(); if (h!=null) { // "+1" is a workaround for Java Highlight issues. tc.setSelectionStart(h.getStartOffset()+1); tc.setSelectionEnd(h.getEndOffset()); tc.replaceSelection(choice); moveToNextParam(); } else { UIManager.getLookAndFeel().provideErrorFeedback(tc); } return true; } } return false; } /** * Installs key bindings on the text component that facilitate the user * editing this completion's parameters. * * @see #uninstallKeyBindings() */ private void installKeyBindings() { if (AutoCompletion.getDebug()) { System.out.println("CompletionContext: Installing keybindings"); } JTextComponent tc = ac.getTextComponent(); InputMap im = tc.getInputMap(); ActionMap am = tc.getActionMap(); KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0); oldTabKey = im.get(ks); im.put(ks, IM_KEY_TAB); oldTabAction = am.get(IM_KEY_TAB); am.put(IM_KEY_TAB, new NextParamAction()); ks = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK); oldShiftTabKey = im.get(ks); im.put(ks, IM_KEY_SHIFT_TAB); oldShiftTabAction = am.get(IM_KEY_SHIFT_TAB); am.put(IM_KEY_SHIFT_TAB, new PrevParamAction()); ks = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0); oldUpKey = im.get(ks); im.put(ks, IM_KEY_UP); oldUpAction = am.get(IM_KEY_UP); am.put(IM_KEY_UP, new NextChoiceAction(-1, oldUpAction)); ks = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0); oldDownKey = im.get(ks); im.put(ks, IM_KEY_DOWN); oldDownAction = am.get(IM_KEY_DOWN); am.put(IM_KEY_DOWN, new NextChoiceAction(1, oldDownAction)); ks = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); oldEnterKey = im.get(ks); im.put(ks, IM_KEY_ENTER); oldEnterAction = am.get(IM_KEY_ENTER); am.put(IM_KEY_ENTER, new GotoEndAction()); ks = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); oldEscapeKey = im.get(ks); im.put(ks, IM_KEY_ESCAPE); oldEscapeAction = am.get(IM_KEY_ESCAPE); am.put(IM_KEY_ESCAPE, new HideAction()); char end = pc.getProvider().getParameterListEnd(); ks = KeyStroke.getKeyStroke(end); oldClosingKey = im.get(ks); im.put(ks, IM_KEY_CLOSING); oldClosingAction = am.get(IM_KEY_CLOSING); am.put(IM_KEY_CLOSING, new ClosingAction()); } /** * Moves to and selects the next parameter. * * @see #moveToPreviousParam() */ private void moveToNextParam() { JTextComponent tc = ac.getTextComponent(); int dot = tc.getCaretPosition(); int tagCount = tags.size(); if (tagCount==0) { tc.setCaretPosition(maxPos.getOffset()); deactivate(); } Highlight currentNext = null; int pos = -1; List highlights = getParameterHighlights(); for (int i=0; idot && hl.getStartOffset()<=currentNext.getStartOffset())) { currentNext = hl; pos = i; } } // No params after caret - go to first one if (currentNext.getStartOffset()+1<=dot) { int nextIndex = getFirstHighlight(highlights); currentNext = highlights.get(nextIndex); pos = 0; } // "+1" is a workaround for Java Highlight issues. tc.setSelectionStart(currentNext.getStartOffset()+1); tc.setSelectionEnd(currentNext.getEndOffset()); updateToolTipText(pos); } /** * Moves to and selects the previous parameter. * * @see #moveToNextParam() */ private void moveToPreviousParam() { JTextComponent tc = ac.getTextComponent(); int tagCount = tags.size(); if (tagCount==0) { // Should never happen tc.setCaretPosition(maxPos.getOffset()); deactivate(); } int dot = tc.getCaretPosition(); int selStart = tc.getSelectionStart()-1; // Workaround for Java Highlight issues. Highlight currentPrev = null; int pos = 0; List highlights = getParameterHighlights(); for (int i=0; i=dot || (h.getStartOffset()currentPrev.getStartOffset() || pos==lastSelectedParam))) { currentPrev = h; pos = i; } } // Loop back from param 0 to last param. int firstIndex = getFirstHighlight(highlights); //if (pos==0 && lastSelectedParam==0 && highlights.size()>1) { if (pos==firstIndex && lastSelectedParam==firstIndex && highlights.size()>1) { pos = getLastHighlight(highlights); currentPrev = highlights.get(pos); // "+1" is a workaround for Java Highlight issues. tc.setSelectionStart(currentPrev.getStartOffset()+1); tc.setSelectionEnd(currentPrev.getEndOffset()); updateToolTipText(pos); } else if (currentPrev!=null && dot>currentPrev.getStartOffset()) { // "+1" is a workaround for Java Highlight issues. tc.setSelectionStart(currentPrev.getStartOffset()+1); tc.setSelectionEnd(currentPrev.getEndOffset()); updateToolTipText(pos); } else { tc.setCaretPosition(maxPos.getOffset()); deactivate(); } } private void possiblyUpdateParamCopies(Document doc) { int index = getCurrentParameterIndex(); // FunctionCompletions add an extra param at end of inserted text if (index>-1 && index stop parameter assistance. Parameter param = pc.getParam(index); if (param.isEndParam()) { deactivate(); return; } // Get the current value of the current parameter. List paramHighlights = getParameterHighlights(); Highlight h = paramHighlights.get(index); int start = h.getStartOffset() + 1; // param offsets are offset (!) by 1 int len = h.getEndOffset() - start; String replacement = null; try { replacement = doc.getText(start, len); } catch (BadLocationException ble) { ble.printStackTrace(); // Never happens } // Replace any param copies tracking this parameter with the // value of this parameter. for (ParamCopyInfo pci : paramCopyInfos) { if (pci.paramName.equals(param.getName())) { pci.h = replaceHighlightedText(doc, pci.h, replacement); } } } else { // Probably the "end parameter" for FunctionCompletions. deactivate(); } } /** * Updates the optional window listing likely completion choices, */ private void prepareParamChoicesWindow() { // If this window was set to null, the user pressed Escape to hide it if (paramChoicesWindow!=null) { int offs = getCurrentParameterStartOffset(); if (offs==-1) { paramChoicesWindow.setVisible(false); return; } JTextComponent tc = ac.getTextComponent(); try { Rectangle r = tc.modelToView(offs); Point p = new Point(r.x, r.y); SwingUtilities.convertPointToScreen(p, tc); r.x = p.x; r.y = p.y; paramChoicesWindow.setLocationRelativeTo(r); } catch (BadLocationException ble) { // Should never happen UIManager.getLookAndFeel().provideErrorFeedback(tc); ble.printStackTrace(); } // Toggles visibility, if necessary. paramChoicesWindow.setParameter(lastSelectedParam, paramPrefix); } } /** * Removes the bounding boxes around parameters. */ private void removeParameterHighlights() { JTextComponent tc = ac.getTextComponent(); Highlighter h = tc.getHighlighter(); for (int i=0; iHighlight classes are funny about insertions at * their start offsets. * * @param doc The document. * @param h The highlight whose text to change. * @param replacement The new text to be in the highlight. * @return The replacement highlight for h. */ private Highlight replaceHighlightedText(Document doc, Highlight h, String replacement) { try { int start = h.getStartOffset(); int len = h.getEndOffset() - start; Highlighter highlighter = ac.getTextComponent().getHighlighter(); highlighter.removeHighlight(h); if (doc instanceof AbstractDocument) { ((AbstractDocument)doc).replace(start, len, replacement, null); } else { doc.remove(start, len); doc.insertString(start, replacement, null); } int newEnd = start + replacement.length(); h = (Highlight)highlighter.addHighlight(start, newEnd, paramCopyP); return h; } catch (BadLocationException ble) { ble.printStackTrace(); // Never happens } return null; } /** * Removes the key bindings we installed. * * @see #installKeyBindings() */ private void uninstallKeyBindings() { if (AutoCompletion.getDebug()) { System.out.println("CompletionContext Uninstalling keybindings"); } JTextComponent tc = ac.getTextComponent(); InputMap im = tc.getInputMap(); ActionMap am = tc.getActionMap(); KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0); im.put(ks, oldTabKey); am.put(IM_KEY_TAB, oldTabAction); ks = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK); im.put(ks, oldShiftTabKey); am.put(IM_KEY_SHIFT_TAB, oldShiftTabAction); ks = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0); im.put(ks, oldUpKey); am.put(IM_KEY_UP, oldUpAction); ks = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0); im.put(ks, oldDownKey); am.put(IM_KEY_DOWN, oldDownAction); ks = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); im.put(ks, oldEnterKey); am.put(IM_KEY_ENTER, oldEnterAction); ks = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); im.put(ks, oldEscapeKey); am.put(IM_KEY_ESCAPE, oldEscapeAction); char end = pc.getProvider().getParameterListEnd(); ks = KeyStroke.getKeyStroke(end); im.put(ks, oldClosingKey); am.put(IM_KEY_CLOSING, oldClosingAction); } /** * Updates the text in the tool tip to have the current parameter * displayed in bold. The "current parameter" is determined from the * current caret position. * * @return The "prefix" of text in the caret's parameter before the caret. */ private String updateToolTipText() { JTextComponent tc = ac.getTextComponent(); int dot = tc.getSelectionStart(); int mark = tc.getSelectionEnd(); int index = -1; String paramPrefix = null; List paramHighlights = getParameterHighlights(); for (int i=0; i=start && dot<=h.getEndOffset()) { try { // All text selected => offer all suggestions, otherwise // use prefix before selection if (dot!=start || mark!=h.getEndOffset()) { paramPrefix = tc.getText(start, dot-start); } } catch (BadLocationException ble) { ble.printStackTrace(); } index = i; break; } } updateToolTipText(index); return paramPrefix; } private void updateToolTipText(int selectedParam) { if (selectedParam!=lastSelectedParam) { if (tip!=null) { tip.updateText(selectedParam); } this.lastSelectedParam = selectedParam; } } /** * Updates the LookAndFeel of all popup windows this context * manages. */ public void updateUI() { if (tip!=null) { tip.updateUI(); } if (paramChoicesWindow!=null) { paramChoicesWindow.updateUI(); } } /** * Called when the user presses Enter while entering parameters. */ private class GotoEndAction extends AbstractAction { public void actionPerformed(ActionEvent e) { // If the param choices window is visible and something is chosen, // replace the parameter with it and move to the next one. if (paramChoicesWindow!=null && paramChoicesWindow.isVisible()) { if (insertSelectedChoice()) { return; } } // Otherwise, just move to the end. deactivate(); JTextComponent tc = ac.getTextComponent(); int dot = tc.getCaretPosition(); if (dot!=defaultEndOffs.getOffset()) { tc.setCaretPosition(defaultEndOffs.getOffset()); } else { // oldEnterAction isn't what we're looking for (wrong key) Action a = getDefaultEnterAction(tc); if (a!=null) { a.actionPerformed(e); } else { tc.replaceSelection("\n"); } } } private Action getDefaultEnterAction(JTextComponent tc) { ActionMap am = tc.getActionMap(); return am.get(DefaultEditorKit.insertBreakAction); } } /** * Called when the user types the character marking the closing of the * parameter list, such as ')'. */ private class ClosingAction extends AbstractAction { public void actionPerformed(ActionEvent e) { JTextComponent tc = ac.getTextComponent(); int dot = tc.getCaretPosition(); char end = pc.getProvider().getParameterListEnd(); // Are they at or past the end of the parameters? if (dot>=maxPos.getOffset()-2) { // ">=" for overwrite mode // Try to decide if we're closing a paren that is a part // of the (last) arg being typed. String text = getArgumentText(dot); if (text!=null) { char start = pc.getProvider().getParameterListStart(); int startCount = getCount(text, start); int endCount = getCount(text, end); if (startCount>endCount) { // Just closing a paren tc.replaceSelection(Character.toString(end)); return; } } //tc.setCaretPosition(maxPos.getOffset()); tc.setCaretPosition(Math.min(tc.getCaretPosition()+1, tc.getDocument().getLength())); deactivate(); } // If not (in the middle of parameters), just insert the paren. else { tc.replaceSelection(Character.toString(end)); } } public int getCount(String text, char ch) { int count = 0; int old = 0; int pos = 0; while ((pos=text.indexOf(ch, old))>-1) { count++; old = pos + 1; } return count; } } /** * Action performed when the user hits the escape key. */ private class HideAction extends AbstractAction { public void actionPerformed(ActionEvent e) { // On first escape press, if the param choices window is visible, // just remove it, but keep ability to tab through params. If // param choices window isn't visible, or second escape press, // exit tabbing through params entirely. if (paramChoicesWindow!=null && paramChoicesWindow.isVisible()) { paramChoicesWindow.setVisible(false); paramChoicesWindow = null; } else { deactivate(); } } } /** * Listens for various events in the text component while this tool tip * is visible. */ private class Listener implements FocusListener, CaretListener, DocumentListener { private boolean markOccurrencesEnabled; /** * Called when the text component's caret moves. * * @param e The event. */ public void caretUpdate(CaretEvent e) { if (maxPos==null) { // Sanity check deactivate(); return; } int dot = e.getDot(); if (dotmaxPos.getOffset()) { deactivate(); return; } paramPrefix = updateToolTipText(); if (active) { prepareParamChoicesWindow(); } } public void changedUpdate(DocumentEvent e) { } /** * Called when the text component gains focus. * * @param e The event. */ public void focusGained(FocusEvent e) { // Do nothing } /** * Called when the text component loses focus. * * @param e The event. */ public void focusLost(FocusEvent e) { deactivate(); } private void handleDocumentEvent(final DocumentEvent e) { if (!ignoringDocumentEvents) { ignoringDocumentEvents = true; SwingUtilities.invokeLater(new Runnable() { public void run() { possiblyUpdateParamCopies(e.getDocument()); ignoringDocumentEvents = false; } }); } } public void insertUpdate(DocumentEvent e) { handleDocumentEvent(e); } /** * Installs this listener onto a text component. * * @param tc The text component to install onto. * @see #uninstall() */ public void install(JTextComponent tc) { boolean replaceTabs = false; if (tc instanceof RSyntaxTextArea) { RSyntaxTextArea textArea = (RSyntaxTextArea)tc; markOccurrencesEnabled = textArea.getMarkOccurrences(); textArea.setMarkOccurrences(false); replaceTabs = textArea.getTabsEmulated(); } Highlighter h = tc.getHighlighter(); try { // Insert the parameter text ParameterizedCompletionInsertionInfo info = pc.getInsertionInfo(tc, replaceTabs); tc.replaceSelection(info.getTextToInsert()); // Add highlights around the parameters. final int replacementCount = info.getReplacementCount(); for (int i=0; iscreenBounds.x+screenBounds.width) { // completions don't fit x = screenBounds.x + screenBounds.width - tooltip.getWidth(); } tooltip.setLocation(x, y); } /** * Toggles the visibility of this tool tip. * * @param visible Whether this tool tip should be visible. * @see #isVisible() */ public void setVisible(boolean visible) { tooltip.setVisible(visible); } /** * Updates the text in the tool tip to have the current parameter * displayed in bold. * * @param selectedParam The index of the selected parameter. * @return Whether the text needed to be updated. */ public boolean updateText(int selectedParam) { StringBuilder sb = new StringBuilder(""); int paramCount = pc.getParamCount(); for (int i=0; i"); } // Some parameter types may have chars in them unfriendly to HTML // (such as type parameters in Java). We need to take care to // escape these. String temp = pc.getParam(i).toString(); sb.append(RSyntaxUtilities.escapeForHtml(temp, "
", false)); if (i==selectedParam) { sb.append(""); } if (i=0 && selectedParam"); sb.append(desc); } } descLabel.setText(sb.toString()); tooltip.pack(); return true; } /** * Updates the LookAndFeel of this window and the description * window. */ public void updateUI() { SwingUtilities.updateComponentTreeUI(tooltip); } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/ParameterizedCompletionInsertionInfo.java000066400000000000000000000135351220700102300320160ustar00rootroot00000000000000/* * 05/26/2012 * * ParameterizedCompletionInsertionInfo.java - Used internally to track the * changes required for a specific parameterized completion. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.util.ArrayList; import java.util.List; import javax.swing.text.Position; import org.fife.ui.rsyntaxtextarea.DocumentRange; /** * Describes a parameterized completion - what's being inserted, where the * parameters are in the inserted text, etc. * * @author Robert Futrell * @version 1.0 */ class ParameterizedCompletionInsertionInfo { private int minOffs; private Position maxOffs; private int defaultEnd; private int selStart; private int selEnd; private String textToInsert; private List replacementLocations; private List replacementCopies; public ParameterizedCompletionInsertionInfo() { defaultEnd = -1; } public void addReplacementCopy(String id, int start, int end) { if (replacementCopies==null) { replacementCopies = new ArrayList(1); } replacementCopies.add(new ReplacementCopy(id, start, end)); } /** * Marks a region of the replacement text as representing a variable name * or some other construct that the user should replace. * * @param start The start offset. * @param end The end offset. * @see #getReplacementCount() * @see #getReplacementLocation(int) */ public void addReplacementLocation(int start, int end) { if (replacementLocations==null) { replacementLocations = new ArrayList(1); } replacementLocations.add(new DocumentRange(start, end)); } public int getDefaultEndOffs() { return defaultEnd>-1 ? defaultEnd : getMaxOffset().getOffset(); } /** * Returns the maximum offset the caret can move to before being outside * of the text inserted for this completion. * * @return The maximum offset. * @see #getMinOffset() */ public Position getMaxOffset() { return maxOffs; } /** * Returns the minimum offset the caret can move to before being outside * of the text inserted for this completion. * * @return The minimum offset. * @see #getMaxOffset() */ public int getMinOffset() { return minOffs; } public int getReplacementCopyCount() { return replacementCopies==null ? 0 : replacementCopies.size(); } /** * Returns the number of replacements in the completion. * * @return The number of replacements in the completion. */ public int getReplacementCount() { return replacementLocations==null ? 0 : replacementLocations.size(); } public ReplacementCopy getReplacementCopy(int index) { return replacementCopies.get(index); } /** * Returns the starting- and ending-offsets of the replacement regions * in the completion. * * @param index The replacement region. * @return The range in the document of that replacement region. * @see #getReplacementCount() */ public DocumentRange getReplacementLocation(int index) { return replacementLocations.get(index); } /** * Returns the offset that should be the end of the initially selected * text when the completion is inserted (i.e., the end offset of the first * replacement region). * * @return The end offset for the initial selection. * @see #getSelectionStart() */ public int getSelectionEnd() { return selEnd; } /** * Returns the offset that should be the start of the initially selected * text when the completion is inserted (i.e., the start offset of the * first replacement region). * * @return The start offset for the initial selection. * @see #getSelectionEnd() */ public int getSelectionStart() { return selStart; } /** * Returns the actual text to insert when the completion is selected. * * @return The text to insert. * @see #setTextToInsert(String) */ public String getTextToInsert() { return textToInsert; } /** * Returns whether or not there is an initial selected region for the * completion (i.e., whether the completion actually has any parameters). * * @return Whether there is a region to initially select for the completion. */ public boolean hasSelection() { return selEnd!=selStart; } /** * Sets the initially selected region for the completion. * * @param selStart The selection start. * @param selEnd The selection end. * @see #getSelectionEnd() * @see #getSelectionStart() */ public void setInitialSelection(int selStart, int selEnd) { this.selStart = selStart; this.selEnd = selEnd; } /** * Sets the document range the caret can move around in before being * outside of the text inserted for the completion. * * @param minOffs The minimum offset. * @param maxOffs The maximum offset, that will track its location as the * document is modified. * @see #getMinOffset() * @see #getMaxOffset() */ public void setCaretRange(int minOffs, Position maxOffs) { this.minOffs = minOffs; this.maxOffs = maxOffs; } public void setDefaultEndOffs(int end) { defaultEnd = end; } /** * Sets the text to insert for the completion. * * @param text The text to insert. * @see #getTextToInsert() */ public void setTextToInsert(String text) { this.textToInsert = text; } public static class ReplacementCopy { private String id; private int start; private int end; public ReplacementCopy(String id, int start, int end) { this.id = id; this.start = start; this.end = end; } public int getEnd() { return end; } public String getId() { return id; } public int getStart() { return start; } } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/ShorthandCompletion.java000066400000000000000000000070141220700102300264400ustar00rootroot00000000000000/* * 12/22/2008 * * ShorhandCompletion.java - A completion that is shorthand for some other * text. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ 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 * "sysout" could be associated with the completion * "System.out.println(" in Java. * * @author Robert Futrell * @version 1.0 */ public class ShorthandCompletion extends BasicCompletion { /** * 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; } /** * 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. * @param shortDesc A short description of the completion. This will be * displayed in the completion list. This may be null. */ public ShorthandCompletion(CompletionProvider provider, String inputText, String replacementText, String shortDesc) { super(provider, replacementText, shortDesc); this.inputText = 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. * @param shortDesc A short description of the completion. This will be * displayed in the completion list. This may be null. * @param summary The summary of this completion. This should be HTML. * This may be null. */ public ShorthandCompletion(CompletionProvider provider, String inputText, String replacementText, String shortDesc, String summary) { super(provider, replacementText, shortDesc, summary); this.inputText = inputText; } /** * Returns the text the user must start typing to get this completion. * * @return The text the user must start to input. */ @Override public String getInputText() { return inputText; } /** * If a summary has been set, that summary is returned. Otherwise, the * replacement text is returned. * * @return A description of this completion (the text that will be * inserted). * @see #getReplacementText() */ @Override public String getSummary() { String summary = super.getSummary(); return summary!=null ? summary : ("" + getSummaryBody()); } /** * Returns the "body" of the HTML returned by {@link #getSummary()} when * no summary text has been set. This is defined to return the replacement * text in a monospaced font. * * @return The summary text's body, if no other summary has been defined. * @see #getReplacementText() */ protected String getSummaryBody() { return "" + getReplacementText(); } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/SizeGrip.java000066400000000000000000000153231220700102300242120ustar00rootroot00000000000000/* * 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. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ 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.Image; import java.awt.Point; import java.awt.Window; import java.awt.event.MouseEvent; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import javax.imageio.ImageIO; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.MouseInputAdapter; /** * A component that allows its parent window to be resizable, similar to the * size grip seen on status bars. This is essentially a copy of the class with * the same name in RSyntaxTextArea, but is duplicated to prevent a dependency * on that library. * * @author Robert Futrell * @version 1.0 */ class SizeGrip extends JPanel { /** * The size grip to use if we're on OS X. */ private Image osxSizeGrip; public SizeGrip() { MouseHandler adapter = new MouseHandler(); addMouseListener(adapter); addMouseMotionListener(adapter); setPreferredSize(new Dimension(16, 16)); } /** * Overridden to ensure that the cursor for this component is appropriate * for the orientation. * * @param o The new orientation. */ @Override public void applyComponentOrientation(ComponentOrientation o) { possiblyFixCursor(o.isLeftToRight()); super.applyComponentOrientation(o); } /** * Creates and returns the OS X size grip image. * * @return The OS X size grip. */ private Image createOSXSizeGrip() { ClassLoader cl = getClass().getClassLoader(); URL url = cl.getResource("org/fife/ui/autocomplete/osx_sizegrip.png"); if (url==null) { // We're not running in a jar - we may be debugging in Eclipse, // for example File f = new File("../AutoComplete/src/org/fife/ui/autocomplete/osx_sizegrip.png"); if (f.isFile()) { try { url = f.toURI().toURL(); } catch (MalformedURLException mue) { // Never happens mue.printStackTrace(); return null; } } else { return null; // Can't find resource or image file } } Image image = null; try { image = ImageIO.read(url); } catch (IOException ioe) { // Never happens ioe.printStackTrace(); } return image; } /** * Paints this panel. * * @param g The graphics context. */ @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Dimension dim = getSize(); if (osxSizeGrip!=null) { g.drawImage(osxSizeGrip, dim.width-16, dim.height-16, null); return; } 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); } } /** * Ensures that the cursor for this component is appropriate for the * orientation. * * @param ltr Whether the current component orientation is LTR. */ protected void possiblyFixCursor(boolean ltr) { int cursor = Cursor.NE_RESIZE_CURSOR; if (ltr) { cursor = Cursor.NW_RESIZE_CURSOR; } if (cursor!=getCursor().getType()) { setCursor(Cursor.getPredefinedCursor(cursor)); } } @Override public void updateUI() { super.updateUI(); // TODO: Key off of Aqua LaF, not just OS X, as this size grip looks // bad on other LaFs on Mac such as Nimbus. if (System.getProperty("os.name").contains("OS X")) { if (osxSizeGrip==null) { osxSizeGrip = createOSXSizeGrip(); } } else { // Clear memory in case of runtime LaF change. osxSizeGrip = null; } } /** * Listens for mouse events on this panel and resizes the parent window * appropriately. */ /* * 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 MouseInputAdapter { private Point origPos; @Override 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 if (getComponentOrientation().isLeftToRight()) { 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); } else { // RTL int newW = Math.max(1, wind.getWidth()-xDelta); int newH = Math.max(1, wind.getHeight()+yDelta); wind.setBounds(newPos.x, wind.getY(), newW, newH); } // invalidate()/validate() needed pre-1.6. wind.invalidate(); wind.validate(); } origPos.setLocation(newPos); } @Override public void mousePressed(MouseEvent e) { origPos = e.getPoint(); SwingUtilities.convertPointToScreen(origPos, SizeGrip.this); } @Override public void mouseReleased(MouseEvent e) { origPos = null; } } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/SortByRelevanceComparator.java000066400000000000000000000014451220700102300275550ustar00rootroot00000000000000/* * 12/17/2010 * * SortByRelevanceComparator.java - Sorts two Completions by relevance before * sorting them lexicographically. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.util.Comparator; /** * Compares two Completions by their relevance before * sorting them lexicographically. * * @author Robert Futrell * @version 1.0 */ public class SortByRelevanceComparator implements Comparator { public int compare(Completion c1, Completion c2) { int rel1 = c1.getRelevance(); int rel2 = c2.getRelevance(); int diff = rel2 - rel1;//rel1 - rel2; return diff==0 ? c1.compareTo(c2) : diff; } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/TemplateCompletion.java000066400000000000000000000232561220700102300262670ustar00rootroot00000000000000/* * 05/26/2012 * * TemplateCompletion.java - A completion used to insert boilerplate code * snippets that have arbitrary sections the user will want to change, such as * for-loops. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.util.ArrayList; import java.util.List; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import javax.swing.text.PlainDocument; import javax.swing.text.Position; import org.fife.ui.autocomplete.TemplatePiece.Param; import org.fife.ui.autocomplete.TemplatePiece.ParamCopy; import org.fife.ui.autocomplete.TemplatePiece.Text; import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities; /** * A completion made up of a template with arbitrary parameters that the user * can tab through and fill in. This completion type is useful for inserting * common boilerplate code, such as for-loops.

* * The format of a template is similar to those in Eclipse. The following * example would be the format for a for-loop template: * *

 * for (int ${i} = 0; ${i} < ${array}.length; ${i}++) {
 *    ${cursor}
 * }
 * 
* * In the above example, the first ${i} is a parameter for the * user to type into; all the other ${i} instances are * automatically changed to what the user types in the first one. The parameter * named ${cursor} is the "ending position" of the template. It's * where the caret moves after it cycles through all other parameters. If the * user types into it, template mode terminates. If more than one * ${cursor} parameter is specified, behavior is undefined.

* * Two dollar signs in a row ("$$") will be evaluated as a single * dollar sign. Otherwise, the template parsing is pretty straightforward and * fault-tolerant.

* * Leading whitespace is automatically added to lines if the template spans * more than one line, and if used with a text component using a * PlainDocument, tabs will be converted to spaces if requested. * * @author Robert Futrell * @version 1.0 */ public class TemplateCompletion extends AbstractCompletion implements ParameterizedCompletion { private List pieces; private String inputText; private String definitionString; private String shortDescription; private String summary; /** * The template's parameters. */ private List params; public TemplateCompletion(CompletionProvider provider, String inputText, String definitionString, String template) { this(provider, inputText, definitionString, template, null, null); } public TemplateCompletion(CompletionProvider provider, String inputText, String definitionString, String template, String shortDescription, String summary) { super(provider); this.inputText = inputText; this.definitionString = definitionString; this.shortDescription = shortDescription; this.summary = summary; pieces = new ArrayList(3); params = new ArrayList(3); parse(template); } private void addTemplatePiece(TemplatePiece piece) { pieces.add(piece); if (piece instanceof Param && !"cursor".equals(piece.getText())) { final String type = null; // TODO Parameter param = new Parameter(type, piece.getText()); params.add(param); } } @Override public String getInputText() { return inputText; } private String getPieceText(int index, String leadingWS) { TemplatePiece piece = pieces.get(index); String text = piece.getText(); if (text.indexOf('\n')>-1) { text = text.replaceAll("\n", "\n" + leadingWS); } return text; } /** * Returns null; template completions insert all of their * text via getInsertionInfo(). * * @return null always. */ public String getReplacementText() { return null; } public String getSummary() { return summary; } public String getDefinitionString() { return definitionString; } public String getShortDescription() { return shortDescription; } /** * {@inheritDoc} */ public boolean getShowParameterToolTip() { return false; } public ParameterizedCompletionInsertionInfo getInsertionInfo( JTextComponent tc, boolean replaceTabsWithSpaces) { ParameterizedCompletionInsertionInfo info = new ParameterizedCompletionInsertionInfo(); StringBuilder sb = new StringBuilder(); int dot = tc.getCaretPosition(); // Get the range in which the caret can move before we hide // this tool tip. int minPos = dot; Position maxPos = null; int defaultEndOffs = -1; try { maxPos = tc.getDocument().createPosition(dot); } catch (BadLocationException ble) { ble.printStackTrace(); // Never happens } info.setCaretRange(minPos, maxPos); int selStart = dot; // Default value int selEnd = selStart; Document doc = tc.getDocument(); String leadingWS = null; try { leadingWS = RSyntaxUtilities.getLeadingWhitespace(doc, dot); } catch (BadLocationException ble) { // Never happens ble.printStackTrace(); leadingWS = ""; } // Create the text to insert (keep it one completion for // performance and simplicity of undo/redo). int start = dot; for (int i=0; i-1) { // ${cursor} specified selStart = selEnd = defaultEndOffs; } } info.setInitialSelection(selStart, selEnd); if (defaultEndOffs>-1) { // Keep this location "after" all others when tabbing info.addReplacementLocation(defaultEndOffs, defaultEndOffs); } info.setDefaultEndOffs(defaultEndOffs); info.setTextToInsert(sb.toString()); return info; } /** * {@inheritDoc} */ public Parameter getParam(int index) { return params.get(index); } /** * {@inheritDoc} */ public int getParamCount() { return params==null ? 0 : params.size(); } /** * Returns whether a parameter is already defined with a specific name. * * @param name The name. * @return Whether a parameter is defined with that name. */ private boolean isParamDefined(String name) { for (int i=0; i-1 && offs escaped single dollar sign addTemplatePiece(new TemplatePiece.Text( template.substring(lastOffs, offs+1))); lastOffs = offs += 2; break; case '{': // "${...}" => variable int closingCurly = template.indexOf('}', offs+2); if (closingCurly>-1) { addTemplatePiece(new TemplatePiece.Text( template.substring(lastOffs, offs))); String varName = template.substring(offs+2, closingCurly); if (!"cursor".equals(varName) && isParamDefined(varName)) { addTemplatePiece(new TemplatePiece.ParamCopy(varName)); } else { addTemplatePiece(new TemplatePiece.Param(varName)); } lastOffs = offs = closingCurly + 1; } break; } } if (lastOffs-1) { int startLen = sb.length(); int size = 4; Document doc = tc.getDocument(); if (doc != null) { Integer i = (Integer) doc.getProperty(PlainDocument.tabSizeAttribute); if (i != null) { size = i.intValue(); } } String tabStr = ""; for (int i=0; i-1); sb.append(text.substring(lastOffs)); start += sb.length() - startLen; } else { sb.append(text); start += text.length(); } return start; } @Override public String toString() { return getDefinitionString(); } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/TemplatePiece.java000066400000000000000000000026471220700102300252040ustar00rootroot00000000000000/* * 06/17/2012 * * TemplatePiece.java - A logical piece of a template completion. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; /** * A piece of a TemplateCompletion. You add instances of this * class to template completions to define them. * * @author Robert Futrell * @version 1.0 * @see TemplateCompletion */ interface TemplatePiece { String getText(); public class Text implements TemplatePiece { private String text; public Text(String text) { this.text = text; } public String getText() { return text; } @Override public String toString() { return "[TemplatePiece.Text: text=" + text + "]"; } } public class Param implements TemplatePiece { String text; public Param(String text) { this.text = text; } public String getText() { return text; } @Override public String toString() { return "[TemplatePiece.Param: param=" + text + "]"; } } public class ParamCopy implements TemplatePiece { private String text; public ParamCopy(String text) { this.text = text; } public String getText() { return text; } @Override public String toString() { return "[TemplatePiece.ParamCopy: param=" + text + "]"; } } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/TipUtil.java000066400000000000000000000124001220700102300240410ustar00rootroot00000000000000/* * 08/13/2009 * * TipUtil.java - Utility methods for homemade tool tips. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.awt.Color; import java.awt.Font; import java.awt.SystemColor; import java.net.URL; import javax.swing.BorderFactory; import javax.swing.JEditorPane; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.plaf.ColorUIResource; import javax.swing.text.html.HTMLDocument; /** * Static utility methods for homemade tool tips.

* * This is blatantly ripped off from RSyntaxTextArea's "FocusableTips" class * of the same name, but isn't re-used to prevent a hard dependency on the * RSTA library. * * @author Robert Futrell * @version 1.0 */ class TipUtil { private TipUtil() { } /** * Returns the default background color to use for tool tip windows. * * @return The default background color. */ public static Color getToolTipBackground() { Color c = UIManager.getColor("ToolTip.background"); // Tooltip.background is wrong color on Nimbus (!) boolean isNimbus = isNimbusLookAndFeel(); if (c==null || isNimbus) { c = UIManager.getColor("info"); // Used by Nimbus (and others) if (c==null || (isNimbus && isDerivedColor(c))) { c = SystemColor.info; // System default } } // Workaround for a bug (?) with Nimbus - calling JLabel.setBackground() // with a ColorUIResource does nothing, must be a normal Color if (c instanceof ColorUIResource) { c = new Color(c.getRGB()); } return c; } /** * Returns the border used by tool tips in this look and feel. * * @return The border. */ public static Border getToolTipBorder() { Border border = UIManager.getBorder("ToolTip.border"); if (border==null || isNimbusLookAndFeel()) { border = UIManager.getBorder("nimbusBorder"); if (border==null) { border = BorderFactory.createLineBorder(SystemColor.controlDkShadow); } } return border; } /** * Returns whether a color is a Nimbus DerivedColor, which is troublesome * in that it doesn't use its RGB values (uses HSB instead?) and so * querying them is useless. * * @param c The color to check. * @return Whether it is a DerivedColor */ private static final boolean isDerivedColor(Color c) { return c!=null && (c.getClass().getName().endsWith(".DerivedColor") || c.getClass().getName().endsWith(".DerivedColor$UIResource")); } /** * Returns whether the Nimbus Look and Feel is installed. * * @return Whether the current LAF is Nimbus. */ private static final boolean isNimbusLookAndFeel() { return UIManager.getLookAndFeel().getName().equals("Nimbus"); } /** * Tweaks a JEditorPane so it can be used to render the * content in a focusable pseudo-tool tip. It is assumed that the editor * pane is using an HTMLDocument. * * @param textArea The editor pane to tweak. */ public static void tweakTipEditorPane(JEditorPane textArea) { // Jump through a few hoops to get things looking nice in Nimbus boolean isNimbus = isNimbusLookAndFeel(); if (isNimbus) { Color selBG = textArea.getSelectionColor(); Color selFG = textArea.getSelectedTextColor(); textArea.setUI(new javax.swing.plaf.basic.BasicEditorPaneUI()); textArea.setSelectedTextColor(selFG); textArea.setSelectionColor(selBG); } textArea.setEditable(false); // Required for links to work! textArea.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); // Make selection visible even though we are not (initially) focusable. textArea.getCaret().setSelectionVisible(true); // Set the foreground color. Important because when rendering HTML, // default foreground becomes black, which may not match all LAF's // (e.g. Substance). Color fg = UIManager.getColor("Label.foreground"); if (fg==null || (isNimbus && isDerivedColor(fg))) { fg = SystemColor.textText; } textArea.setForeground(fg); // Make it use the "tool tip" background color. textArea.setBackground(TipUtil.getToolTipBackground()); // Force JEditorPane to use a certain font even in HTML. // All standard LookAndFeels, even Nimbus (!), define Label.font. Font font = UIManager.getFont("Label.font"); if (font == null) { // Try to make a sensible default font = new Font("SansSerif", Font.PLAIN, 12); } HTMLDocument doc = (HTMLDocument) textArea.getDocument(); doc.getStyleSheet().addRule( "body { font-family: " + font.getFamily() + "; font-size: " + font.getSize() + "pt" + "; color: " + Util.getHexString(fg) + "; }"); // Always add link foreground rule. Unfortunately these CSS rules // stack each time the LaF is changed (how can we overwrite them // without clearing out the important "standard" ones?). Color linkFG = Util.getHyperlinkForeground(); doc.getStyleSheet().addRule( "a { color: " + Util.getHexString(linkFG) + "; }"); URL url = TipUtil.class.getResource("bullet_black.png"); if (url!=null) { doc.getStyleSheet().addRule( "ul { list-style-image: '" + url.toString() + "'; }"); } } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/Util.java000066400000000000000000000232021220700102300233660ustar00rootroot00000000000000/* * 12/21/2008 * * Util.java - Utility methods for the autocompletion package. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import java.awt.Color; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Rectangle; import java.lang.reflect.Method; import java.net.URI; import java.security.AccessControlException; import java.util.regex.Pattern; import javax.swing.JLabel; import javax.swing.UIManager; import org.fife.ui.rsyntaxtextarea.PopupWindowDecorator; /** * Utility methods for the auto-complete framework. * * @author Robert Futrell * @version 1.0 */ public class Util { /** * If a system property is defined with this name and set, ignoring case, * to true, this library will not attempt to use Substance * renderers. Otherwise, if a Substance Look and Feel is installed, we * will attempt to use Substance cell renderers in all of our dropdowns.

* * Note that we do not have a build dependency on Substance, so all access * to Substance stuff is done via reflection. We will fall back onto * default renderers if something goes horribly wrong. */ public static final String PROPERTY_DONT_USE_SUBSTANCE_RENDERERS = "org.fife.ui.autocomplete.DontUseSubstanceRenderers"; /** * If this system property is true, then even the "main" two * auto-complete windows will allow window decorations via * {@link PopupWindowDecorator}. If this property is undefined or * false, they won't honor such decorations. This is due to * certain performance issues with translucent windows (used for drop * shadows), even as of Java 7u2. */ public static final String PROPERTY_ALLOW_DECORATED_AUTOCOMPLETE_WINDOWS = "org.fife.ui.autocomplete.allowDecoratedAutoCompleteWindows"; /** * Used for the color of hyperlinks when a LookAndFeel uses light text * against a dark background. */ private static final Color LIGHT_HYPERLINK_FG = new Color(0xd8ffff); private static final Pattern TAG_PATTERN = Pattern.compile("<[^>]*>"); private static final boolean useSubstanceRenderers; private static boolean desktopCreationAttempted; private static Object desktop; private static final Object LOCK_DESKTOP_CREATION = new Object(); /** * Attempts to open a web browser to the specified URI. * * @param uri The URI to open. If this is null, nothing happens and this method returns false. * @return Whether the operation was successful. This will be * false 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 java.awt.Desktop instance, or * null 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"); boolean supported= ((Boolean)m.invoke(null)).booleanValue(); if (supported) { m = desktopClazz.getDeclaredMethod("getDesktop"); desktop = m.invoke(null); } } catch (RuntimeException re) { throw re; // Keep FindBugs happy } catch (Exception e) { // Ignore; keeps desktop as null. } } } return desktop; } /** * Returns a hex string for the specified color, suitable for HTML. * * @param c The color. * @return The string representation, in the form "#rrggbb", * or null if c is null. */ public static String getHexString(Color c) { if (c==null) { return null; } // Don't assume 0xff alpha //return "#" + Integer.toHexString(c.getRGB()&0xffffff).substring(2); StringBuilder sb = new StringBuilder("#"); 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(); } /** * Returns the color to use for hyperlink-style components. This method * will return Color.blue unless it appears that the current * LookAndFeel uses light text on a dark background, in which case a * brighter alternative is returned. * * @return The color to use for hyperlinks. */ static final Color getHyperlinkForeground() { // This property is defined by all standard LaFs, even Nimbus (!), // but you never know what crazy LaFs there are... Color fg = UIManager.getColor("Label.foreground"); if (fg==null) { fg = new JLabel().getForeground(); } return isLightForeground(fg) ? LIGHT_HYPERLINK_FG : Color.blue; } /** * Returns the screen coordinates for the monitor that contains the * specified point. This is useful for setups with multiple monitors, * to ensure that popup windows are positioned properly. * * @param x The x-coordinate, in screen coordinates. * @param y The y-coordinate, in screen coordinates. * @return The bounds of the monitor that contains the specified point. */ public static Rectangle getScreenBoundsForPoint(int x, int y) { GraphicsEnvironment env = GraphicsEnvironment. getLocalGraphicsEnvironment(); GraphicsDevice[] devices = env.getScreenDevices(); for (int i=0; ifalse, we'll use our * standard rendering for completions, even when Substance is being used. * * @return Whether to use Substance renderers if Substance is installed. */ public static boolean getUseSubstanceRenderers() { return useSubstanceRenderers; } /** * Returns whether the specified color is "light" to use as a foreground. * Colors that return true indicate that the current Look and * Feel probably uses light text colors on a dark background. * * @param fg The foreground color. * @return Whether it is a "light" foreground color. */ public static final boolean isLightForeground(Color fg) { return fg.getRed()>0xa0 && fg.getGreen()>0xa0 && fg.getBlue()>0xa0; } /** * Returns whether str starts with start, * ignoring case. * * @param str The string to check. * @param start The prefix to check for. * @return Whether str starts with start, * ignoring case. */ public static boolean startsWithIgnoreCase(String str, String start) { int startLen = start.length(); if (str.length()>=startLen) { for (int i=0; i<html>" for markup tags to be stripped. * * @param text The string. * @return The string, with any HTML stripped. */ public static String stripHtml(String text) { if (text==null || !text.startsWith("")) { return text; } // TODO: Micro-optimize me, might be called in renderers and loops return TAG_PATTERN.matcher(text).replaceAll(""); } static { boolean use = true; try { use = !Boolean.getBoolean(PROPERTY_DONT_USE_SUBSTANCE_RENDERERS); } catch (AccessControlException ace) { // We're in an applet. use = true; } useSubstanceRenderers = use; } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/VariableCompletion.java000066400000000000000000000110161220700102300262300ustar00rootroot00000000000000/* * 12/22/2008 * * VariableCompletion.java - A completion for a variable. * * This library is distributed under a modified BSD license. See the included * RSyntaxTextArea.License.txt file for details. */ package org.fife.ui.autocomplete; import javax.swing.text.JTextComponent; /** * A completion for a variable (or constant) in a programming language.

* * This completion type uses its shortDescription property as part of * its summary returned by {@link #getSummary()}; for this reason, it may be * a little longer (even much longer), if desired, than what is recommended * for BasicCompletions (where the shortDescription is used * in {@link #toString()} for ListCellRenderers). * * @author Robert Futrell * @version 1.0 */ public class VariableCompletion extends BasicCompletion { /** * The variable's type. */ private String type; /** * What library (for example) this variable is defined in. */ 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. "int", * "String", etc.). */ public VariableCompletion(CompletionProvider provider, String name, String type) { super(provider, name); this.type = type; } protected void addDefinitionString(StringBuilder sb) { sb.append("").append(getDefinitionString()).append(""); } public String getDefinitionString() { StringBuilder sb = new StringBuilder(); // Add the return type if applicable (C macros like NULL have no type). if (type!=null) { sb.append(type).append(' '); } // Add the item being described's name. sb.append(getName()); return sb.toString(); } /** * Returns where this variable is defined. * * @return Where this variable is defined. * @see #setDefinedIn(String) */ public String getDefinedIn() { return definedIn; } /** * Returns the name of this variable. * * @return The name. */ public String getName() { return getReplacementText(); } /** * {@inheritDoc} */ @Override public String getSummary() { StringBuilder sb = new StringBuilder(); addDefinitionString(sb); possiblyAddDescription(sb); possiblyAddDefinedIn(sb); return sb.toString(); } /** * Returns the tool tip text to display for mouse hovers over this * completion.

* * Note that for this functionality to be enabled, a * JTextComponent must be registered with the * ToolTipManager, and the text component must know to search * for this value. In the case of an * RSyntaxTextArea, this * can be done with a org.fife.ui.rtextarea.ToolTipSupplier that * calls into * {@link CompletionProvider#getCompletionsAt(JTextComponent, java.awt.Point)}. * * @return The tool tip text for this completion, or null if * none. */ @Override public String getToolTipText() { return getDefinitionString(); } /** * Returns the type of this variable. * * @return The type. */ public String getType() { return type; } /** * Adds some HTML describing where this variable is defined, if this * information is known. * * @param sb The buffer to append to. */ protected void possiblyAddDefinedIn(StringBuilder sb) { if (definedIn!=null) { sb.append("


Defined in:"); // TODO: Localize me sb.append(" ").append(definedIn).append(""); } } /** * Adds the description text as HTML to a buffer, if a description is * defined. * * @param sb The buffer to append to. * @return Whether there was a description to add. */ protected boolean possiblyAddDescription(StringBuilder sb) { if (getShortDescription()!=null) { sb.append("

"); sb.append(getShortDescription()); sb.append("


"); return true; } return false; } /** * Sets where this variable is defined. * * @param definedIn Where this variable is defined. * @see #getDefinedIn() */ public void setDefinedIn(String definedIn) { this.definedIn = definedIn; } /** * Overridden to return the name of the variable being completed. * * @return A string representation of this completion. */ @Override public String toString() { return getName(); } }autocomplete-2.5.0/src/org/fife/ui/autocomplete/arrow_left.png000066400000000000000000000005311220700102300244600ustar00rootroot00000000000000PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8c?%B0 (=ĻI12$C_?3¿~1`._edj>)*n90_ ѿV\ٿ0aX`ſ4ܟ@_P303'×^ 4G)1vUMB9 i;N@ͺ@Ռ㡻zZIENDB`autocomplete-2.5.0/src/org/fife/ui/autocomplete/arrow_right.png000066400000000000000000000005351220700102300246470ustar00rootroot00000000000000PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8c?%B0 k_WAPz"e_~ ¿~1d7۷.j3Jؖ?7@&˗zZYj'Me7Xo!o+]r{:g0ARR oܽp{=x -YXPAku1ba7lIENDB`autocomplete-2.5.0/src/org/fife/ui/autocomplete/bullet_black.png000066400000000000000000000003351220700102300247410ustar00rootroot00000000000000PNG  IHDR Vu\gAMA7tEXtSoftwarePaint.NET v3.5.5IoIDAT(S͑A @E#&"X%[ޜuRo{Y5*Pqyﳸ'% Vt5BJ6, !kIιl[?:+FƒIENDB`autocomplete-2.5.0/src/org/fife/ui/autocomplete/osx_sizegrip.png000066400000000000000000000114141220700102300250430ustar00rootroot00000000000000PNG  IHDR(-SgAMA cHRM  @.LiCCPICC ProfileXíy<זּK YF]Jv,cɘc')IM*[!k,ei!")}~3ssϝ˔+dK#]f${IǶT[6̎8*FWޗ: DkT $BMewoWOA,CԃjkSmQ9݋:v4ÇW{d)]}NΞne/+;RdTۼb khnmtsL?48!z=ƃkZ>OHkHc@tWDzYpψSQS2-+:W|(pBVbń3N.{_H3JP*ɝZʞVz]KY[ƅEȢŭ%K#ܕ+)(Tw\yJV=Xs6}zL ɍM*t#.8jHOឪӶyF vju1t{B7ϩ?2ץo\8#*yg>n!|?rE=#m6=#jpEt6"{(*7.O#=&7n]\[XP*yWZu'Or򥊑{%Uq5߿QAgc{Sns`Cч'?!=.cWs LX^g Vh\F$bƮ}<3!=99{~,; UFVn'QZ<8* GPsF|A b'Ps @@&\ Om` SYˆdX9kq$ qG Hy+2مBQQ2ZB/Ҩ҄4ӢhMhi'^Ӌw020t`PL c.S339yŌuyy6g^998qpp+r7=ɻΗ/$`#0+NPXIQhK6)[gQ8RFKRHrX*u4k,YW9) PTRQ׬_KMD[N;tuc$^4J>m QD+jVݶǜ`v뜅\N|qv3lOIvAPpϑeQgLbΞ돯{11lJD*1;#03#{Z%MŴNw*D+/T6r6>yіپi]beA -&.WܺJ@R> !p xrAh' &ӇEra8I x3| A[HE$CѣP~t$ z!nѭћߦbp`ŰcHFy45&w.}y,0)V{n6m:vyB g W1k %>Q&~;y]{vu 1: ׊xf.%*6'^"!).9#U'X@#^J.VAAe/WJu /Yدy@K㠦~AaQN#&wL̅-,oX-hڞ;o/@plsvvqUu=iraޠၧX#ˣlWbrj͝/LpHdؗ┺pzմkewns+^viRTKMyrfz׹z9qެ5z?27fďg־kYYL5z|vѧ E^;z1"Ӆ2`O`pI3>A"n &HzC4"44h5hdaDQ+v&Qqɕiٛ;K(+5 Vn>qsC._nv"(~3z  `s}EfAA,]_HRVUמq^VZ[yJ*kU:Tϩ#@sҊ>xSWg^OLAaѦ*ta2daffej6j;d'm8SRnV/~>x8ߊh*1t,7b-2)J4AIh\y [Iw/9^Ff0^}e=?GUvKRQS;2 {߫Ց64~nyHvg]Pnz7U`pHt\ ?M|at͛\y酪W×~)/3/Z&6޹QYGNx"k3ta|?zI6P nfН ڔ|,ch 1 Z@sXMýQkA=O6́)8o{l/Z[6W[yb߄{֟&@ʌXCE>ꑁ+ @gTidA ࡾ?>PFAOvArK&oTYjC $z+*L+CZ;GzAciǻ۟u_kW{b{wsJOQwة('VH #xybuH$<G#2Xc VQAA/.5lAXyPLTEX*tEXtSoftwarePaint.NET v3.36%HIDAT(Sc`F ̜d6NT-l  ( >3ldςd3*`t;o 1,IENDB`