GithubHelp home page GithubHelp logo

Comments (3)

bobbylight avatar bobbylight commented on August 24, 2024

Just so I'm clear, what you'are asking for is this:

After the initial display of the popup window, have it refresh its completion choices only after a short delay after an appropriate event (typing, arrow key navigation, etc.) to alleviate lag seen when computing the completion list can be slow. Is that correct?

from autocomplete.

predi avatar predi commented on August 24, 2024

I think you understood what I was trying to say. The lag appears since currently every event causes the completion list to re-generate. It would be better if the list re-generates after the events have settled down. I'll just paste the whole class as it is currently in my repository, so you can diff it.

/*
 * 12/21/2008
 *
 * AutoCompletePopupWindow.java - A window containing a list of auto-complete
 * choices.
 * 
 * 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.ComponentOrientation;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JWindow;
import javax.swing.KeyStroke;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.ListUI;
import javax.swing.text.Caret;
import javax.swing.text.JTextComponent;

import org.fife.ui.rsyntaxtextarea.PopupWindowDecorator;


/**
 * The actual popup window of choices.  When visible, this window intercepts
 * certain keystrokes in the parent text component and uses them to navigate
 * the completion choices instead.  If Enter or Escape is pressed, the window
 * hides itself and notifies the {@link AutoCompletion} to insert the selected
 * text.
 *
 * @author Robert Futrell
 * @version 1.0
 */
class AutoCompletePopupWindow extends JWindow implements CaretListener,
                                    ListSelectionListener, MouseListener {

    /**
     * The parent AutoCompletion instance.
     */
    private AutoCompletion ac;

    /**
     * The list of completion choices.
     */
    private JList list;

    /**
     * The contents of {@link #list()}.
     */
    private CompletionListModel model;

    /**
     * A hack to work around the fact that we clear our completion model (and
     * our selection) when hiding the completion window.  This allows us to
     * still know what the user selected after the popup is hidden.
     */
    private Completion lastSelection;

    /**
     * Optional popup window containing a description of the currently
     * selected completion.
     */
    private AutoCompleteDescWindow descWindow;

    /**
     * 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;

    /**
     * Whether the completion window and the optional description window
     * should be displayed above the current caret position (as opposed to
     * underneath it, which is preferred unless there is not enough space).
     */
    private boolean aboveCaret;

    private int lastLine;

    private KeyActionPair escapeKap;
    private KeyActionPair upKap;
    private KeyActionPair downKap;
    private KeyActionPair leftKap;
    private KeyActionPair rightKap;
    private KeyActionPair enterKap;
    private KeyActionPair tabKap;
    private KeyActionPair homeKap;
    private KeyActionPair endKap;
    private KeyActionPair pageUpKap;
    private KeyActionPair pageDownKap;
    private KeyActionPair ctrlCKap;

    private KeyActionPair oldEscape, oldUp, oldDown, oldLeft, oldRight,
            oldEnter, oldTab, oldHome, oldEnd, oldPageUp, oldPageDown,
            oldCtrlC;

    /**
     * The space between the caret and the completion popup.
     */
    private static final int VERTICAL_SPACE         = 1;

    /**
     * The class name of the Substance List UI.
     */
    private static final String SUBSTANCE_LIST_UI =
            "org.pushingpixels.substance.internal.ui.SubstanceListUI";


        private Timer doAutocompleteTimer;

    /**
     * Constructor.
     *
     * @param parent The parent window (hosting the text component).
     * @param ac The auto-completion instance.
     */
    public AutoCompletePopupWindow(Window parent, final AutoCompletion ac) {

        super(parent);
        ComponentOrientation o = ac.getTextComponentOrientation();

        this.ac = ac;
        model = new CompletionListModel();
        list = new PopupList(model);

        list.setCellRenderer(new DelegatingCellRenderer());
        list.addListSelectionListener(this);
        list.addMouseListener(this);

        JPanel contentPane = new JPanel(new BorderLayout());
        JScrollPane sp = new JScrollPane(list,
                            JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                            JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);

        // In 1.4, JScrollPane.setCorner() has a bug where it won't accept
        // JScrollPane.LOWER_TRAILING_CORNER, even though that constant is
        // defined.  So we have to put the logic added in 1.5 to handle it
        // here.
        JPanel corner = new SizeGrip();
        //sp.setCorner(JScrollPane.LOWER_TRAILING_CORNER, corner);
        boolean isLeftToRight = o.isLeftToRight();
        String str = isLeftToRight ? JScrollPane.LOWER_RIGHT_CORNER :
                                        JScrollPane.LOWER_LEFT_CORNER;
        sp.setCorner(str, corner);

        contentPane.add(sp);
        setContentPane(contentPane);
        applyComponentOrientation(o);

        // Give apps a chance to decorate us with drop shadows, etc.
        if (Util.getShouldAllowDecoratingMainAutoCompleteWindows()) {
            PopupWindowDecorator decorator = PopupWindowDecorator.get();
            if (decorator!=null) {
                decorator.decorate(this);
            }
        }

        pack();

        setFocusableWindowState(false);

        lastLine = -1;

                doAutocompleteTimer = new Timer(100, new ActionListener() {

                    public void actionPerformed(ActionEvent e) {
                        lastLine = ac.refreshPopupWindow();
                    }
                });
                doAutocompleteTimer.setRepeats(false);
    }


    public void caretUpdate(CaretEvent e) {
        if (isVisible()) { // Should always be true
            int line = ac.getLineOfCaret();
            if (line!=lastLine) {
                lastLine = -1;
                setVisible(false);
            }
            else {
                doAutocomplete();
            }
        }
        else if (AutoCompletion.getDebug()) {
            Thread.dumpStack();
        }
    }


    /**
     * Creates the description window.
     *
     * @return The description window.
     */
    private AutoCompleteDescWindow createDescriptionWindow() {
        AutoCompleteDescWindow dw = new AutoCompleteDescWindow(this, ac);
        dw.applyComponentOrientation(ac.getTextComponentOrientation());
        Dimension size = preferredDescWindowSize;
        if (size==null) {
            size = getSize();
        }
        dw.setSize(size);
        return dw;
    }


    /**
     * Creates the mappings from keys to Actions we'll be putting into the
     * text component's ActionMap and InputMap.
     */
    private void createKeyActionPairs() {

        // Actions we'll install.
        EnterAction enterAction = new EnterAction();
        escapeKap = new KeyActionPair("Escape", new EscapeAction());
        upKap = new KeyActionPair("Up", new UpAction());
        downKap = new KeyActionPair("Down", new DownAction());
        leftKap = new KeyActionPair("Left", new LeftAction());
        rightKap = new KeyActionPair("Right", new RightAction());
        enterKap = new KeyActionPair("Enter", enterAction);
        tabKap = new KeyActionPair("Tab", enterAction);
        homeKap = new KeyActionPair("Home", new HomeAction());
        endKap = new KeyActionPair("End", new EndAction());
        pageUpKap = new KeyActionPair("PageUp", new PageUpAction());
        pageDownKap = new KeyActionPair("PageDown", new PageDownAction());
        ctrlCKap = new KeyActionPair("CtrlC", new CopyAction());

        // Buffers for the actions we replace.
        oldEscape = new KeyActionPair();
        oldUp = new KeyActionPair();
        oldDown = new KeyActionPair();
        oldLeft = new KeyActionPair();
        oldRight = new KeyActionPair();
        oldEnter = new KeyActionPair();
        oldTab = new KeyActionPair();
        oldHome = new KeyActionPair();
        oldEnd = new KeyActionPair();
        oldPageUp = new KeyActionPair();
        oldPageDown = new KeyActionPair();
        oldCtrlC = new KeyActionPair();

    }


    protected void doAutocomplete() {
        //lastLine = ac.refreshPopupWindow();
            doAutocompleteTimer.restart();
    }


    /**
     * Returns the copy keystroke to use for this platform.
     *
     * @return The copy keystroke.
     */
    private static final KeyStroke getCopyKeyStroke() {
        int key = KeyEvent.VK_C;
        int mask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
        return KeyStroke.getKeyStroke(key, mask);
    }


    /**
     * 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() {
        DelegatingCellRenderer dcr = (DelegatingCellRenderer)list.
                                                            getCellRenderer();
        return dcr.getFallbackCellRenderer();
    }


    /**
     * Returns the selected value, or <code>null</code> 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 (x<screenBounds.x) { // Doesn't fit
                x = getX() + getWidth() + 5;
            }
        }

        int y = getY();
        if (aboveCaret) {
            y = y + getHeight() - descWindow.getHeight();
        }

        if (x!=descWindow.getX() || y!=descWindow.getY()) { 
            descWindow.setLocation(x, y);
        }

    }


    /**
     * "Puts back" the original key/Action pair for a keystroke.  This is used
     * when this popup is hidden.
     *
     * @param im The input map.
     * @param am The action map.
     * @param key The keystroke whose key/Action pair to change.
     * @param kap The (original) key/Action pair.
     * @see #replaceAction(InputMap, ActionMap, int, KeyActionPair, KeyActionPair)
     */
    private void putBackAction(InputMap im, ActionMap am, int key,
                                KeyActionPair kap) {
        KeyStroke ks = KeyStroke.getKeyStroke(key, 0);
        am.put(im.get(ks), kap.action); // Original action for the "new" key
        im.put(ks, kap.key); // Original key for the keystroke.
    }


    /**
     * Replaces a key/Action pair in an InputMap and ActionMap with a new
     * pair.
     *
     * @param im The input map.
     * @param am The action map.
     * @param key The keystroke whose information to replace.
     * @param kap The new key/Action pair for <code>key</code>.
     * @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<Completion> completions) {
        model.setContents(completions);
        selectFirstItem();
    }


    /**
     * Sets the size of the description window.
     *
     * @param size The new size.  This cannot be <code>null</code>.
     */
    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 <code>null</code>,
     *        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 (x<screenBounds.x) {
            x = screenBounds.x;
        }
        else if (x+getWidth()>screenBounds.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 <tt>LookAndFeel</tt> 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();
            }
        }

    }


}

from autocomplete.

predi avatar predi commented on August 24, 2024

Yeah.. That was a bad idea. Sorry for tl;dr.

from autocomplete.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.