• [原][Java]eclipse 修改自动提示


    前者按 http://blog.csdn.net/tomsheng321/article/details/39548627 修改
    后者按 http://blog.csdn.net/lethwei/article/details/5837282 修改,同时注释了 accept 方法实现 和 去掉 Home End 键在提示窗口的上下定位
    /*******************************************************************************
     * Copyright (c) 2000, 2010 IBM Corporation and others.
     * All rights reserved. This program and the accompanying materials
     * are made available under the terms of the Eclipse Public License v1.0
     * which accompanies this distribution, and is available at
     * http://www.eclipse.org/legal/epl-v10.html
     *
     * Contributors:
     *     IBM Corporation - initial API and implementation
     *     Sean Montgomery, sean_montgomery@comcast.net - https://bugs.eclipse.org/bugs/show_bug.cgi?id=116454
     *******************************************************************************/
    package org.eclipse.jface.text.contentassist;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.eclipse.osgi.util.TextProcessor;
    
    import org.eclipse.swt.SWT;
    import org.eclipse.swt.custom.BusyIndicator;
    import org.eclipse.swt.custom.StyleRange;
    import org.eclipse.swt.events.ControlEvent;
    import org.eclipse.swt.events.ControlListener;
    import org.eclipse.swt.events.DisposeEvent;
    import org.eclipse.swt.events.DisposeListener;
    import org.eclipse.swt.events.FocusEvent;
    import org.eclipse.swt.events.FocusListener;
    import org.eclipse.swt.events.KeyAdapter;
    import org.eclipse.swt.events.KeyEvent;
    import org.eclipse.swt.events.KeyListener;
    import org.eclipse.swt.events.MouseAdapter;
    import org.eclipse.swt.events.MouseEvent;
    import org.eclipse.swt.events.SelectionEvent;
    import org.eclipse.swt.events.SelectionListener;
    import org.eclipse.swt.events.TraverseEvent;
    import org.eclipse.swt.events.TraverseListener;
    import org.eclipse.swt.events.VerifyEvent;
    import org.eclipse.swt.graphics.Color;
    import org.eclipse.swt.graphics.Font;
    import org.eclipse.swt.graphics.FontData;
    import org.eclipse.swt.graphics.Image;
    import org.eclipse.swt.graphics.Point;
    import org.eclipse.swt.graphics.Rectangle;
    import org.eclipse.swt.layout.GridData;
    import org.eclipse.swt.layout.GridLayout;
    import org.eclipse.swt.widgets.Control;
    import org.eclipse.swt.widgets.Display;
    import org.eclipse.swt.widgets.Event;
    import org.eclipse.swt.widgets.Label;
    import org.eclipse.swt.widgets.Listener;
    import org.eclipse.swt.widgets.Shell;
    import org.eclipse.swt.widgets.Table;
    import org.eclipse.swt.widgets.TableItem;
    
    import org.eclipse.core.commands.AbstractHandler;
    import org.eclipse.core.commands.ExecutionEvent;
    import org.eclipse.core.commands.ExecutionException;
    import org.eclipse.core.commands.IHandler;
    
    import org.eclipse.core.runtime.Assert;
    
    import org.eclipse.jface.bindings.keys.KeySequence;
    import org.eclipse.jface.bindings.keys.SWTKeySupport;
    import org.eclipse.jface.contentassist.IContentAssistSubjectControl;
    import org.eclipse.jface.internal.text.InformationControlReplacer;
    import org.eclipse.jface.internal.text.TableOwnerDrawSupport;
    import org.eclipse.jface.preference.JFacePreferences;
    import org.eclipse.jface.resource.JFaceResources;
    import org.eclipse.jface.util.Geometry;
    import org.eclipse.jface.viewers.StyledString;
    
    import org.eclipse.jface.text.AbstractInformationControlManager;
    import org.eclipse.jface.text.AbstractInformationControlManager.Anchor;
    import org.eclipse.jface.text.BadLocationException;
    import org.eclipse.jface.text.DocumentEvent;
    import org.eclipse.jface.text.IDocument;
    import org.eclipse.jface.text.IDocumentListener;
    import org.eclipse.jface.text.IEditingSupport;
    import org.eclipse.jface.text.IEditingSupportRegistry;
    import org.eclipse.jface.text.IInformationControl;
    import org.eclipse.jface.text.IRegion;
    import org.eclipse.jface.text.IRewriteTarget;
    import org.eclipse.jface.text.ITextViewer;
    import org.eclipse.jface.text.ITextViewerExtension;
    import org.eclipse.jface.text.TextUtilities;
    
    /**
     * This class is used to present proposals to the user. If additional
     * information exists for a proposal, then selecting that proposal will result
     * in the information being displayed in a secondary window.
     * 
     * @see org.eclipse.jface.text.contentassist.ICompletionProposal
     * @see org.eclipse.jface.text.contentassist.AdditionalInfoController
     */
    class CompletionProposalPopup implements IContentAssistListener {
        /**
         * Set to <code>true</code> to use a Table with SWT.VIRTUAL. XXX: This is a
         * workaround for: https://bugs.eclipse.org/bugs/show_bug.cgi?id=90321 More
         * details see also: https://bugs.eclipse.org/bugs/show_bug.cgi?id=98585#c36
         * 
         * @since 3.1
         */
        private static final boolean USE_VIRTUAL = !"motif".equals(SWT.getPlatform()); //$NON-NLS-1$
    
        /**
         * Completion proposal selection handler.
         * 
         * @since 3.4
         */
        final class ProposalSelectionHandler extends AbstractHandler {
    
            /**
             * Selection operation codes.
             */
            static final int SELECT_NEXT = 1;
            static final int SELECT_PREVIOUS = 2;
    
            private final int fOperationCode;
    
            /**
             * Creates a new selection handler.
             * 
             * @param operationCode
             *            the operation code
             * @since 3.4
             */
            public ProposalSelectionHandler(int operationCode) {
                Assert.isLegal(operationCode == SELECT_NEXT || operationCode == SELECT_PREVIOUS);
                fOperationCode = operationCode;
            }
    
            /*
             * @see
             * org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core
             * .commands.ExecutionEvent)
             * 
             * @since 3.4
             */
            public Object execute(ExecutionEvent event) throws ExecutionException {
                int itemCount = fProposalTable.getItemCount();
                int selectionIndex = fProposalTable.getSelectionIndex();
                switch (fOperationCode) {
                case SELECT_NEXT:
                    selectionIndex += 1;
                    if (selectionIndex > itemCount - 1)
                        selectionIndex = 0;
                    break;
                case SELECT_PREVIOUS:
                    selectionIndex -= 1;
                    if (selectionIndex < 0)
                        selectionIndex = itemCount - 1;
                    break;
                }
                selectProposal(selectionIndex, false);
                return null;
            }
    
        }
    
        /**
         * The empty proposal displayed if there is nothing else to show.
         * 
         * @since 3.2
         */
        private static final class EmptyProposal implements ICompletionProposal, ICompletionProposalExtension {
    
            String fDisplayString;
            int fOffset;
    
            /*
             * @see ICompletionProposal#apply(IDocument)
             */
            public void apply(IDocument document) {
            }
    
            /*
             * @see ICompletionProposal#getSelection(IDocument)
             */
            public Point getSelection(IDocument document) {
                return new Point(fOffset, 0);
            }
    
            /*
             * @see ICompletionProposal#getContextInformation()
             */
            public IContextInformation getContextInformation() {
                return null;
            }
    
            /*
             * @see ICompletionProposal#getImage()
             */
            public Image getImage() {
                return null;
            }
    
            /*
             * @see ICompletionProposal#getDisplayString()
             */
            public String getDisplayString() {
                return fDisplayString;
            }
    
            /*
             * @see ICompletionProposal#getAdditionalProposalInfo()
             */
            public String getAdditionalProposalInfo() {
                return null;
            }
    
            /*
             * @see
             * org.eclipse.jface.text.contentassist.ICompletionProposalExtension
             * #apply(org.eclipse.jface.text.IDocument, char, int)
             */
            public void apply(IDocument document, char trigger, int offset) {
            }
    
            /*
             * @see
             * org.eclipse.jface.text.contentassist.ICompletionProposalExtension
             * #isValidFor(org.eclipse.jface.text.IDocument, int)
             */
            public boolean isValidFor(IDocument document, int offset) {
                return false;
            }
    
            /*
             * @see
             * org.eclipse.jface.text.contentassist.ICompletionProposalExtension
             * #getTriggerCharacters()
             */
            public char[] getTriggerCharacters() {
                return null;
            }
    
            /*
             * @see
             * org.eclipse.jface.text.contentassist.ICompletionProposalExtension
             * #getContextInformationPosition()
             */
            public int getContextInformationPosition() {
                return -1;
            }
        }
    
        private final class ProposalSelectionListener implements KeyListener {
            public void keyPressed(KeyEvent e) {
                if (!Helper.okToUse(fProposalShell))
                    return;
    
                if (e.character == 0 && e.keyCode == SWT.CTRL) {
                    // http://dev.eclipse.org/bugs/show_bug.cgi?id=34754
                    int index = fProposalTable.getSelectionIndex();
                    if (index >= 0)
                        selectProposal(index, true);
                }
            }
    
            public void keyReleased(KeyEvent e) {
                if (!Helper.okToUse(fProposalShell))
                    return;
    
                if (e.character == 0 && e.keyCode == SWT.CTRL) {
                    // http://dev.eclipse.org/bugs/show_bug.cgi?id=34754
                    int index = fProposalTable.getSelectionIndex();
                    if (index >= 0)
                        selectProposal(index, false);
                }
            }
        }
    
        private final class CommandKeyListener extends KeyAdapter {
            private final KeySequence fCommandSequence;
    
            private CommandKeyListener(KeySequence keySequence) {
                fCommandSequence = keySequence;
            }
    
            public void keyPressed(KeyEvent e) {
                if (!Helper.okToUse(fProposalShell))
                    return;
    
                int accelerator = SWTKeySupport.convertEventToUnmodifiedAccelerator(e);
                KeySequence sequence = KeySequence.getInstance(SWTKeySupport.convertAcceleratorToKeyStroke(accelerator));
                if (sequence.equals(fCommandSequence))
                    if (fContentAssistant.isPrefixCompletionEnabled())
                        incrementalComplete();
                    else
                        showProposals(false);
    
            }
        }
    
        /** The associated text viewer. */
        private ITextViewer fViewer;
        /** The associated content assistant. */
        private final ContentAssistant fContentAssistant;
        /** The used additional info controller, or <code>null</code> if none. */
        private final AdditionalInfoController fAdditionalInfoController;
        /** The closing strategy for this completion proposal popup. */
        private final PopupCloser fPopupCloser = new PopupCloser();
        /** The popup shell. */
        private Shell fProposalShell;
        /** The proposal table. */
        private Table fProposalTable;
        /** Indicates whether a completion proposal is being inserted. */
        private boolean fInserting = false;
        /** The key listener to control navigation. */
        private ProposalSelectionListener fKeyListener;
        /** List of document events used for filtering proposals. */
        private final List fDocumentEvents = new ArrayList();
        /** Listener filling the document event queue. */
        private IDocumentListener fDocumentListener;
        /** The filter list of proposals. */
        private ICompletionProposal[] fFilteredProposals;
        /** The computed list of proposals. */
        private ICompletionProposal[] fComputedProposals;
        /** The offset for which the proposals have been computed. */
        private int fInvocationOffset;
        /** The offset for which the computed proposals have been filtered. */
        private int fFilterOffset;
        /**
         * The most recently selected proposal.
         * 
         * @since 3.0
         */
        private ICompletionProposal fLastProposal;
        /**
         * The content assist subject control. This replaces <code>fViewer</code>
         * 
         * @since 3.0
         */
        private IContentAssistSubjectControl fContentAssistSubjectControl;
        /**
         * The content assist subject control adapter. This replaces
         * <code>fViewer</code>
         * 
         * @since 3.0
         */
        private final ContentAssistSubjectControlAdapter fContentAssistSubjectControlAdapter;
        /**
         * Remembers the size for this completion proposal popup.
         * 
         * @since 3.0
         */
        private Point fSize;
        /**
         * Editor helper that communicates that the completion proposal popup may
         * have focus while the 'logical focus' is still with the editor.
         * 
         * @since 3.1
         */
        private IEditingSupport fFocusHelper;
        /**
         * Set to true by {@link #computeFilteredProposals(int, DocumentEvent)} if
         * the returned proposals are a subset of {@link #fFilteredProposals},
         * <code>false</code> if not.
         * 
         * @since 3.1
         */
        private boolean fIsFilteredSubset;
        /**
         * The filter runnable.
         * 
         * @since 3.1.1
         */
        private final Runnable fFilterRunnable = new Runnable() {
            public void run() {
                if (!fIsFilterPending)
                    return;
    
                fIsFilterPending = false;
    
                if (!Helper.okToUse(fContentAssistSubjectControlAdapter.getControl()))
                    return;
    
                int offset = fContentAssistSubjectControlAdapter.getSelectedRange().x;
                ICompletionProposal[] proposals = null;
                try {
                    if (offset > -1) {
                        DocumentEvent event = TextUtilities.mergeProcessedDocumentEvents(fDocumentEvents);
                        proposals = computeFilteredProposals(offset, event);
                    }
                } catch (BadLocationException x) {
                } finally {
                    fDocumentEvents.clear();
                }
                fFilterOffset = offset;
    
                if (proposals != null && proposals.length > 0)
                    setProposals(proposals, fIsFilteredSubset);
                else
                    hide();
            }
        };
        /**
         * <code>true</code> if <code>fFilterRunnable</code> has been posted,
         * <code>false</code> if not.
         * 
         * @since 3.1.1
         */
        private boolean fIsFilterPending = false;
        /**
         * The info message at the bottom of the popup, or <code>null</code> for no
         * popup (if ContentAssistant does not provide one).
         * 
         * @since 3.2
         */
        private Label fMessageText;
        /**
         * The font used for <code>fMessageText</code> or null; dispose when done.
         * 
         * @since 3.2
         */
        private Font fMessageTextFont;
        /**
         * The most recent completion offset (used to determine repeated invocation)
         * 
         * @since 3.2
         */
        private int fLastCompletionOffset;
        /**
         * The (reusable) empty proposal.
         * 
         * @since 3.2
         */
        private final EmptyProposal fEmptyProposal = new EmptyProposal();
        /**
         * The text for the empty proposal, or <code>null</code> to use the default
         * text.
         * 
         * @since 3.2
         */
        private String fEmptyMessage = null;
        /**
         * Tells whether colored labels support is enabled. Only valid while the
         * popup is active.
         * 
         * @since 3.4
         */
        private boolean fIsColoredLabelsSupportEnabled = false;
    
        /**
         * Creates a new completion proposal popup for the given elements.
         * 
         * @param contentAssistant
         *            the content assistant feeding this popup
         * @param viewer
         *            the viewer on top of which this popup appears
         * @param infoController
         *            the information control collaborating with this popup, or
         *            <code>null</code>
         * @since 2.0
         */
        public CompletionProposalPopup(ContentAssistant contentAssistant, ITextViewer viewer, AdditionalInfoController infoController) {
            fContentAssistant = contentAssistant;
            fViewer = viewer;
            fAdditionalInfoController = infoController;
            fContentAssistSubjectControlAdapter = new ContentAssistSubjectControlAdapter(fViewer);
        }
    
        /**
         * Creates a new completion proposal popup for the given elements.
         * 
         * @param contentAssistant
         *            the content assistant feeding this popup
         * @param contentAssistSubjectControl
         *            the content assist subject control on top of which this popup
         *            appears
         * @param infoController
         *            the information control collaborating with this popup, or
         *            <code>null</code>
         * @since 3.0
         */
        public CompletionProposalPopup(ContentAssistant contentAssistant, IContentAssistSubjectControl contentAssistSubjectControl, AdditionalInfoController infoController) {
            fContentAssistant = contentAssistant;
            fContentAssistSubjectControl = contentAssistSubjectControl;
            fAdditionalInfoController = infoController;
            fContentAssistSubjectControlAdapter = new ContentAssistSubjectControlAdapter(fContentAssistSubjectControl);
        }
    
        /**
         * Computes and presents completion proposals. The flag indicates whether
         * this call has be made out of an auto activation context.
         * 
         * @param autoActivated
         *            <code>true</code> if auto activation context
         * @return an error message or <code>null</code> in case of no error
         */
        public String showProposals(final boolean autoActivated) {
    
            if (fKeyListener == null)
                fKeyListener = new ProposalSelectionListener();
    
            final Control control = fContentAssistSubjectControlAdapter.getControl();
    
            if (!Helper.okToUse(fProposalShell) && control != null && !control.isDisposed()) {
                // add the listener before computing the proposals so we don't move
                // the caret
                // when the user types fast.
                fContentAssistSubjectControlAdapter.addKeyListener(fKeyListener);
    
                BusyIndicator.showWhile(control.getDisplay(), new Runnable() {
                    public void run() {
    
                        fInvocationOffset = fContentAssistSubjectControlAdapter.getSelectedRange().x;
                        fFilterOffset = fInvocationOffset;
                        fLastCompletionOffset = fFilterOffset;
                        fComputedProposals = computeProposals(fInvocationOffset);
    
                        int count = (fComputedProposals == null ? 0 : fComputedProposals.length);
                        if (count == 0 && hideWhenNoProposals(autoActivated))
                            return;
    
                        if (count == 1 && !autoActivated && canAutoInsert(fComputedProposals[0])) {
                            insertProposal(fComputedProposals[0], (char) 0, 0, fInvocationOffset);
                            hide();
                        } else {
                            createProposalSelector();
                            setProposals(fComputedProposals, false);
                            displayProposals();
                        }
                    }
                });
            } else {
                fLastCompletionOffset = fFilterOffset;
                handleRepeatedInvocation();
            }
    
            return getErrorMessage();
        }
    
        /**
         * Hides the popup and returns <code>true</code> if the popup is configured
         * to never display an empty list. Returns <code>false</code> otherwise.
         * 
         * @param autoActivated
         *            whether the invocation was auto-activated
         * @return <code>false</code> if an empty list should be displayed,
         *         <code>true</code> otherwise
         * @since 3.2
         */
        private boolean hideWhenNoProposals(boolean autoActivated) {
            if (autoActivated || !fContentAssistant.isShowEmptyList()) {
                if (!autoActivated) {
                    Control control = fContentAssistSubjectControlAdapter.getControl();
                    if (control != null && !control.isDisposed())
                        control.getDisplay().beep();
                }
                hide();
                return true;
            }
            return false;
        }
    
        /**
         * If content assist is set up to handle cycling, then the proposals are
         * recomputed. Otherwise, nothing happens.
         * 
         * @since 3.2
         */
        private void handleRepeatedInvocation() {
            if (fContentAssistant.isRepeatedInvocationMode()) {
                fComputedProposals = computeProposals(fFilterOffset);
                setProposals(fComputedProposals, false);
            }
        }
    
        /**
         * Returns the completion proposal available at the given offset of the
         * viewer's document. Delegates the work to the content assistant.
         * 
         * @param offset
         *            the offset
         * @return the completion proposals available at this offset
         */
        private ICompletionProposal[] computeProposals(int offset) {
            if (fContentAssistSubjectControl != null)
                return fContentAssistant.computeCompletionProposals(fContentAssistSubjectControl, offset);
            return fContentAssistant.computeCompletionProposals(fViewer, offset);
        }
    
        /**
         * Returns the error message.
         * 
         * @return the error message
         */
        private String getErrorMessage() {
            return fContentAssistant.getErrorMessage();
        }
    
        /**
         * Creates the proposal selector.
         */
        private void createProposalSelector() {
            if (Helper.okToUse(fProposalShell))
                return;
    
            Control control = fContentAssistSubjectControlAdapter.getControl();
            fProposalShell = new Shell(control.getShell(), SWT.ON_TOP | SWT.RESIZE);
            fProposalShell.setFont(JFaceResources.getDefaultFont());
            if (USE_VIRTUAL) {
                fProposalTable = new Table(fProposalShell, SWT.H_SCROLL | SWT.V_SCROLL | SWT.VIRTUAL);
    
                Listener listener = new Listener() {
                    public void handleEvent(Event event) {
                        handleSetData(event);
                    }
                };
                fProposalTable.addListener(SWT.SetData, listener);
            } else {
                fProposalTable = new Table(fProposalShell, SWT.H_SCROLL | SWT.V_SCROLL);
            }
    
            fIsColoredLabelsSupportEnabled = fContentAssistant.isColoredLabelsSupportEnabled();
            if (fIsColoredLabelsSupportEnabled)
                TableOwnerDrawSupport.install(fProposalTable);
    
            fProposalTable.setLocation(0, 0);
            if (fAdditionalInfoController != null)
                fAdditionalInfoController.setSizeConstraints(50, 10, true, true);
    
            GridLayout layout = new GridLayout();
            layout.marginWidth = 0;
            layout.marginHeight = 0;
            layout.verticalSpacing = 1;
            fProposalShell.setLayout(layout);
    
            if (fContentAssistant.isStatusLineVisible()) {
                createMessageText();
            }
    
            GridData data = new GridData(GridData.FILL_BOTH);
    
            Point size = fContentAssistant.restoreCompletionProposalPopupSize();
            if (size != null) {
                fProposalTable.setLayoutData(data);
                fProposalShell.setSize(size);
            } else {
                int height = fProposalTable.getItemHeight() * 10;
                // use golden ratio as default aspect ratio
                final double aspectRatio = (1 + Math.sqrt(5)) / 2;
                int width = (int) (height * aspectRatio);
                Rectangle trim = fProposalTable.computeTrim(0, 0, width, height);
                data.heightHint = trim.height;
                data.widthHint = trim.width;
                fProposalTable.setLayoutData(data);
                fProposalShell.pack();
            }
            fContentAssistant.addToLayout(this, fProposalShell, ContentAssistant.LayoutManager.LAYOUT_PROPOSAL_SELECTOR, fContentAssistant.getSelectionOffset());
    
            fProposalShell.addControlListener(new ControlListener() {
    
                public void controlMoved(ControlEvent e) {
                }
    
                public void controlResized(ControlEvent e) {
                    if (fAdditionalInfoController != null) {
                        // reset the cached resize constraints
                        fAdditionalInfoController.setSizeConstraints(50, 10, true, false);
                        fAdditionalInfoController.hideInformationControl();
                        fAdditionalInfoController.handleTableSelectionChanged();
                    }
    
                    fSize = fProposalShell.getSize();
                }
            });
    
            fProposalShell.setBackground(control.getDisplay().getSystemColor(SWT.COLOR_GRAY));
    
            Color c = getBackgroundColor(control);
            fProposalTable.setBackground(c);
    
            c = getForegroundColor(control);
            fProposalTable.setForeground(c);
    
            fProposalTable.addSelectionListener(new SelectionListener() {
    
                public void widgetSelected(SelectionEvent e) {
                }
    
                public void widgetDefaultSelected(SelectionEvent e) {
                    insertSelectedProposalWithMask(e.stateMask);
                }
            });
    
            fPopupCloser.install(fContentAssistant, fProposalTable, fAdditionalInfoController);
    
            fProposalShell.addDisposeListener(new DisposeListener() {
                public void widgetDisposed(DisposeEvent e) {
                    unregister(); // but don't dispose the shell, since we're being
                                    // called from its disposal event!
                }
            });
    
            fProposalTable.setHeaderVisible(false);
    
            addCommandSupport(fProposalTable);
        }
    
        /**
         * Returns the minimal required height for the proposal, may return 0 if the
         * popup has not been created yet.
         * 
         * @return the minimal height
         * @since 3.3
         */
        int getMinimalHeight() {
            int height = 0;
            if (Helper.okToUse(fProposalTable)) {
                int items = fProposalTable.getItemHeight() * 10;
                Rectangle trim = fProposalTable.computeTrim(0, 0, SWT.DEFAULT, items);
                height = trim.height;
            }
            if (Helper.okToUse(fMessageText))
                height += fMessageText.getSize().y + 1;
            return height;
        }
    
        /**
         * Adds command support to the given control.
         * 
         * @param control
         *            the control to watch for focus
         * @since 3.2
         */
        private void addCommandSupport(final Control control) {
            final KeySequence commandSequence = fContentAssistant.getRepeatedInvocationKeySequence();
            if (commandSequence != null && !commandSequence.isEmpty() && fContentAssistant.isRepeatedInvocationMode()) {
                control.addFocusListener(new FocusListener() {
                    private CommandKeyListener fCommandKeyListener;
    
                    public void focusGained(FocusEvent e) {
                        if (Helper.okToUse(control)) {
                            if (fCommandKeyListener == null) {
                                fCommandKeyListener = new CommandKeyListener(commandSequence);
                                fProposalTable.addKeyListener(fCommandKeyListener);
                            }
                        }
                    }
    
                    public void focusLost(FocusEvent e) {
                        if (fCommandKeyListener != null) {
                            control.removeKeyListener(fCommandKeyListener);
                            fCommandKeyListener = null;
                        }
                    }
                });
            }
            if (fAdditionalInfoController != null) {
                control.addFocusListener(new FocusListener() {
                    private TraverseListener fTraverseListener;
    
                    public void focusGained(FocusEvent e) {
                        if (Helper.okToUse(control)) {
                            if (fTraverseListener == null) {
                                fTraverseListener = new TraverseListener() {
                                    public void keyTraversed(TraverseEvent event) {
                                        if (event.detail == SWT.TRAVERSE_TAB_NEXT) {
                                            IInformationControl iControl = fAdditionalInfoController.getCurrentInformationControl2();
                                            if (fAdditionalInfoController.getInternalAccessor().canReplace(iControl)) {
                                                fAdditionalInfoController.getInternalAccessor().replaceInformationControl(true);
                                                event.doit = false;
                                            }
                                        }
                                    }
                                };
                                fProposalTable.addTraverseListener(fTraverseListener);
                            }
                        }
                    }
    
                    public void focusLost(FocusEvent e) {
                        if (fTraverseListener != null) {
                            control.removeTraverseListener(fTraverseListener);
                            fTraverseListener = null;
                        }
                    }
                });
            }
        }
    
        /**
         * Returns the background color to use.
         * 
         * @param control
         *            the control to get the display from
         * @return the background color
         * @since 3.2
         */
        private Color getBackgroundColor(Control control) {
            Color c = fContentAssistant.getProposalSelectorBackground();
            if (c == null)
                c = JFaceResources.getColorRegistry().get(JFacePreferences.CONTENT_ASSIST_BACKGROUND_COLOR);
            return c;
        }
    
        /**
         * Returns the foreground color to use.
         * 
         * @param control
         *            the control to get the display from
         * @return the foreground color
         * @since 3.2
         */
        private Color getForegroundColor(Control control) {
            Color c = fContentAssistant.getProposalSelectorForeground();
            if (c == null)
                c = JFaceResources.getColorRegistry().get(JFacePreferences.CONTENT_ASSIST_FOREGROUND_COLOR);
            return c;
        }
    
        /**
         * Creates the caption line under the proposal table.
         * 
         * @since 3.2
         */
        private void createMessageText() {
            if (fMessageText == null) {
                fMessageText = new Label(fProposalShell, SWT.RIGHT);
                GridData textData = new GridData(SWT.FILL, SWT.BOTTOM, true, false);
                fMessageText.setLayoutData(textData);
                fMessageText.setText(fContentAssistant.getStatusMessage() + " "); //$NON-NLS-1$
                if (fMessageTextFont == null) {
                    Font font = fMessageText.getFont();
                    Display display = fProposalShell.getDisplay();
                    FontData[] fontDatas = font.getFontData();
                    for (int i = 0; i < fontDatas.length; i++)
                        fontDatas[i].setHeight(fontDatas[i].getHeight() * 9 / 10);
                    fMessageTextFont = new Font(display, fontDatas);
                }
                fMessageText.setFont(fMessageTextFont);
                fMessageText.setBackground(getBackgroundColor(fProposalShell));
                fMessageText.setForeground(getForegroundColor(fProposalShell));
    
                if (fContentAssistant.isRepeatedInvocationMode()) {
                    fMessageText.setCursor(fProposalShell.getDisplay().getSystemCursor(SWT.CURSOR_HAND));
                    fMessageText.addMouseListener(new MouseAdapter() {
                        public void mouseUp(MouseEvent e) {
                            fLastCompletionOffset = fFilterOffset;
                            fProposalTable.setFocus();
                            handleRepeatedInvocation();
                        }
    
                        public void mouseDown(MouseEvent e) {
                        }
                    });
                }
            }
        }
    
        /*
         * @since 3.1
         */
        private void handleSetData(Event event) {
            TableItem item = (TableItem) event.item;
            int index = fProposalTable.indexOf(item);
    
            if (0 <= index && index < fFilteredProposals.length) {
                ICompletionProposal current = fFilteredProposals[index];
    
                String displayString;
                StyleRange[] styleRanges = null;
                if (fIsColoredLabelsSupportEnabled && current instanceof ICompletionProposalExtension6) {
                    StyledString styledString = ((ICompletionProposalExtension6) current).getStyledDisplayString();
                    displayString = styledString.getString();
                    styleRanges = styledString.getStyleRanges();
                } else
                    displayString = current.getDisplayString();
    
                item.setText(displayString);
                if (fIsColoredLabelsSupportEnabled)
                    TableOwnerDrawSupport.storeStyleRanges(item, 0, styleRanges);
    
                item.setImage(current.getImage());
                item.setData(current);
            } else {
                // this should not happen, but does on win32
            }
        }
    
        /**
         * Returns the proposal selected in the proposal selector.
         * 
         * @return the selected proposal
         * @since 2.0
         */
        private ICompletionProposal getSelectedProposal() {
            /*
             * Make sure that there is no filter runnable pending. See
             * https://bugs.eclipse.org/bugs/show_bug.cgi?id=31427
             */
            if (fIsFilterPending)
                fFilterRunnable.run();
    
            // filter runnable may have hidden the proposals
            if (!Helper.okToUse(fProposalTable))
                return null;
    
            int i = fProposalTable.getSelectionIndex();
            if (fFilteredProposals == null || i < 0 || i >= fFilteredProposals.length)
                return null;
            return fFilteredProposals[i];
        }
    
        /**
         * Takes the selected proposal and applies it.
         * 
         * @param stateMask
         *            the state mask
         * @since 3.2
         */
        private void insertSelectedProposalWithMask(int stateMask) {
            ICompletionProposal p = getSelectedProposal();
            hide();
            if (p != null)
                insertProposal(p, (char) 0, stateMask, fContentAssistSubjectControlAdapter.getSelectedRange().x);
        }
    
        /**
         * Applies the given proposal at the given offset. The given character is
         * the one that triggered the insertion of this proposal.
         * 
         * @param p
         *            the completion proposal
         * @param trigger
         *            the trigger character
         * @param stateMask
         *            the state mask
         * @param offset
         *            the offset
         * @since 2.1
         */
        private void insertProposal(ICompletionProposal p, char trigger, int stateMask, final int offset) {
    
            fInserting = true;
            IRewriteTarget target = null;
            IEditingSupport helper = new IEditingSupport() {
    
                public boolean isOriginator(DocumentEvent event, IRegion focus) {
                    return focus.getOffset() <= offset && focus.getOffset() + focus.getLength() >= offset;
                }
    
                public boolean ownsFocusShell() {
                    return false;
                }
    
            };
    
            try {
    
                IDocument document = fContentAssistSubjectControlAdapter.getDocument();
    
                if (fViewer instanceof ITextViewerExtension) {
                    ITextViewerExtension extension = (ITextViewerExtension) fViewer;
                    target = extension.getRewriteTarget();
                }
    
                if (target != null)
                    target.beginCompoundChange();
    
                if (fViewer instanceof IEditingSupportRegistry) {
                    IEditingSupportRegistry registry = (IEditingSupportRegistry) fViewer;
                    registry.register(helper);
                }
    
                if (p instanceof ICompletionProposalExtension2 && fViewer != null) {
                    ICompletionProposalExtension2 e = (ICompletionProposalExtension2) p;
                    e.apply(fViewer, trigger, stateMask, offset);
                } else if (p instanceof ICompletionProposalExtension) {
                    ICompletionProposalExtension e = (ICompletionProposalExtension) p;
                    e.apply(document, trigger, offset);
                } else {
                    p.apply(document);
                }
    
                Point selection = p.getSelection(document);
                if (selection != null) {
                    fContentAssistSubjectControlAdapter.setSelectedRange(selection.x, selection.y);
                    fContentAssistSubjectControlAdapter.revealRange(selection.x, selection.y);
                }
    
                IContextInformation info = p.getContextInformation();
                if (info != null) {
    
                    int contextInformationOffset;
                    if (p instanceof ICompletionProposalExtension) {
                        ICompletionProposalExtension e = (ICompletionProposalExtension) p;
                        contextInformationOffset = e.getContextInformationPosition();
                    } else {
                        if (selection == null)
                            selection = fContentAssistSubjectControlAdapter.getSelectedRange();
                        contextInformationOffset = selection.x + selection.y;
                    }
    
                    fContentAssistant.showContextInformation(info, contextInformationOffset);
                } else
                    fContentAssistant.showContextInformation(null, -1);
    
            } finally {
                if (target != null)
                    target.endCompoundChange();
    
                if (fViewer instanceof IEditingSupportRegistry) {
                    IEditingSupportRegistry registry = (IEditingSupportRegistry) fViewer;
                    registry.unregister(helper);
                }
                fInserting = false;
            }
        }
    
        /**
         * Returns whether this popup has the focus.
         * 
         * @return <code>true</code> if the popup has the focus
         */
        public boolean hasFocus() {
            if (Helper.okToUse(fProposalShell)) {
                if ((fProposalShell.getDisplay().getActiveShell() == fProposalShell))
                    return true;
                /*
                 * We have to delegate this query to the additional info controller
                 * as well, since the content assistant is the widget token owner
                 * and its closer does not know that the additional info control can
                 * now also take focus.
                 */
                if (fAdditionalInfoController != null) {
                    IInformationControl informationControl = fAdditionalInfoController.getCurrentInformationControl2();
                    if (informationControl != null && informationControl.isFocusControl())
                        return true;
                    InformationControlReplacer replacer = fAdditionalInfoController.getInternalAccessor().getInformationControlReplacer();
                    if (replacer != null) {
                        informationControl = replacer.getCurrentInformationControl2();
                        if (informationControl != null && informationControl.isFocusControl())
                            return true;
                    }
                }
            }
    
            return false;
        }
    
        /**
         * Hides this popup.
         */
        public void hide() {
    
            unregister();
    
            if (fViewer instanceof IEditingSupportRegistry) {
                IEditingSupportRegistry registry = (IEditingSupportRegistry) fViewer;
                registry.unregister(fFocusHelper);
            }
    
            if (Helper.okToUse(fProposalShell)) {
    
                fContentAssistant.removeContentAssistListener(this, ContentAssistant.PROPOSAL_SELECTOR);
    
                fPopupCloser.uninstall();
                fProposalShell.setVisible(false);
                fProposalShell.dispose();
                fProposalShell = null;
            }
    
            if (fMessageTextFont != null) {
                fMessageTextFont.dispose();
                fMessageTextFont = null;
            }
    
            if (fMessageText != null) {
                fMessageText = null;
            }
    
            fEmptyMessage = null;
    
            fLastCompletionOffset = -1;
    
            fContentAssistant.fireSessionEndEvent();
        }
    
        /**
         * Unregister this completion proposal popup.
         * 
         * @since 3.0
         */
        private void unregister() {
            if (fDocumentListener != null) {
                IDocument document = fContentAssistSubjectControlAdapter.getDocument();
                if (document != null)
                    document.removeDocumentListener(fDocumentListener);
                fDocumentListener = null;
            }
            fDocumentEvents.clear();
    
            if (fKeyListener != null && fContentAssistSubjectControlAdapter.getControl() != null && !fContentAssistSubjectControlAdapter.getControl().isDisposed()) {
                fContentAssistSubjectControlAdapter.removeKeyListener(fKeyListener);
                fKeyListener = null;
            }
    
            if (fLastProposal != null) {
                if (fLastProposal instanceof ICompletionProposalExtension2 && fViewer != null) {
                    ICompletionProposalExtension2 extension = (ICompletionProposalExtension2) fLastProposal;
                    extension.unselected(fViewer);
                }
                fLastProposal = null;
            }
    
            fFilteredProposals = null;
            fComputedProposals = null;
    
            fContentAssistant.possibleCompletionsClosed();
        }
    
        /**
         * Returns whether this popup is active. It is active if the proposal
         * selector is visible.
         * 
         * @return <code>true</code> if this popup is active
         */
        public boolean isActive() {
            return fProposalShell != null && !fProposalShell.isDisposed();
        }
    
        /**
         * Initializes the proposal selector with these given proposals.
         * 
         * @param proposals
         *            the proposals
         * @param isFilteredSubset
         *            if <code>true</code>, the proposal table is not cleared, but
         *            the proposals that are not in the passed array are removed
         *            from the displayed set
         */
        private void setProposals(ICompletionProposal[] proposals, boolean isFilteredSubset) {
            ICompletionProposal[] oldProposals = fFilteredProposals;
            ICompletionProposal oldProposal = getSelectedProposal(); // may trigger
                                                                        // filtering
                                                                        // and a
                                                                        // reentrant
                                                                        // call to
                                                                        // setProposals()
            if (oldProposals != fFilteredProposals) // reentrant call was first -
                                                    // abort
                return;
    
            if (Helper.okToUse(fProposalTable)) {
                if (oldProposal instanceof ICompletionProposalExtension2 && fViewer != null)
                    ((ICompletionProposalExtension2) oldProposal).unselected(fViewer);
    
                if (proposals == null || proposals.length == 0) {
                    fEmptyProposal.fOffset = fFilterOffset;
                    fEmptyProposal.fDisplayString = fEmptyMessage != null ? fEmptyMessage : JFaceTextMessages.getString("CompletionProposalPopup.no_proposals"); //$NON-NLS-1$
                    proposals = new ICompletionProposal[] { fEmptyProposal };
                }
    
                fFilteredProposals = proposals;
                final int newLen = proposals.length;
                if (USE_VIRTUAL) {
                    fProposalTable.setItemCount(newLen);
                    fProposalTable.clearAll();
                } else {
                    fProposalTable.setRedraw(false);
                    fProposalTable.setItemCount(newLen);
                    TableItem[] items = fProposalTable.getItems();
                    for (int i = 0; i < items.length; i++) {
                        TableItem item = items[i];
                        ICompletionProposal proposal = proposals[i];
                        item.setText(proposal.getDisplayString());
                        item.setImage(proposal.getImage());
                        item.setData(proposal);
                    }
                    fProposalTable.setRedraw(true);
                }
    
                Point currentLocation = fProposalShell.getLocation();
                Point newLocation = getLocation();
                if ((newLocation.x < currentLocation.x && newLocation.y == currentLocation.y) || newLocation.y < currentLocation.y)
                    fProposalShell.setLocation(newLocation);
    
                selectProposal(0, false);
            }
        }
    
        /**
         * Returns the graphical location at which this popup should be made
         * visible.
         * 
         * @return the location of this popup
         */
        private Point getLocation() {
            int caret = fContentAssistSubjectControlAdapter.getCaretOffset();
            Rectangle location = fContentAssistant.getLayoutManager().computeBoundsBelowAbove(fProposalShell, fSize == null ? fProposalShell.getSize() : fSize, caret, this);
            return Geometry.getLocation(location);
        }
    
        /**
         * Returns the size of this completion proposal popup.
         * 
         * @return a Point containing the size
         * @since 3.0
         */
        Point getSize() {
            return fSize;
        }
    
        /**
         * Displays this popup and install the additional info controller, so that
         * additional info is displayed when a proposal is selected and additional
         * info is available.
         */
        private void displayProposals() {
    
            if (!Helper.okToUse(fProposalShell) || !Helper.okToUse(fProposalTable))
                return;
    
            if (fContentAssistant.addContentAssistListener(this, ContentAssistant.PROPOSAL_SELECTOR)) {
    
                ensureDocumentListenerInstalled();
    
                if (fFocusHelper == null) {
                    fFocusHelper = new IEditingSupport() {
    
                        public boolean isOriginator(DocumentEvent event, IRegion focus) {
                            return false; // this helper just covers the focus
                                            // change to the proposal shell, no
                                            // remote editions
                        }
    
                        public boolean ownsFocusShell() {
                            return true;
                        }
    
                    };
                }
                if (fViewer instanceof IEditingSupportRegistry) {
                    IEditingSupportRegistry registry = (IEditingSupportRegistry) fViewer;
                    registry.register(fFocusHelper);
                }
    
                /*
                 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=52646 on GTK,
                 * setVisible and such may run the event loop (see also
                 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=47511) Since the
                 * user may have already canceled the popup or selected an entry
                 * (ESC or RETURN), we have to double check whether the table is
                 * still okToUse. See comments below
                 */
                fProposalShell.setVisible(true); // may run event loop on GTK
                // transfer focus since no verify key listener can be attached
                if (!fContentAssistSubjectControlAdapter.supportsVerifyKeyListener() && Helper.okToUse(fProposalShell))
                    fProposalShell.setFocus(); // may run event loop on GTK ??
    
                if (fAdditionalInfoController != null && Helper.okToUse(fProposalTable)) {
                    fAdditionalInfoController.install(fProposalTable);
                    fAdditionalInfoController.handleTableSelectionChanged();
                }
            } else
                hide();
        }
    
        /**
         * Installs the document listener if not already done.
         * 
         * @since 3.2
         */
        private void ensureDocumentListenerInstalled() {
            if (fDocumentListener == null) {
                fDocumentListener = new IDocumentListener() {
                    public void documentAboutToBeChanged(DocumentEvent event) {
                        if (!fInserting)
                            fDocumentEvents.add(event);
                    }
    
                    public void documentChanged(DocumentEvent event) {
                        if (!fInserting)
                            filterProposals();
                    }
                };
                IDocument document = fContentAssistSubjectControlAdapter.getDocument();
                if (document != null)
                    document.addDocumentListener(fDocumentListener);
            }
        }
    
        /*
         * @see IContentAssistListener#verifyKey(VerifyEvent)
         */
        public boolean verifyKey(VerifyEvent e) {
            if (!Helper.okToUse(fProposalShell))
                return true;
    
            char key = e.character;
            if (key == 0) {
                int newSelection = fProposalTable.getSelectionIndex();
                int visibleRows = (fProposalTable.getSize().y / fProposalTable.getItemHeight()) - 1;
                int itemCount = fProposalTable.getItemCount();
                switch (e.keyCode) {
    
                case SWT.ARROW_LEFT:
                case SWT.ARROW_RIGHT:
                    filterProposals();
                    return true;
    
                case SWT.ARROW_UP:
                    newSelection -= 1;
                    if (newSelection < 0)
                        newSelection = itemCount - 1;
                    break;
    
                case SWT.ARROW_DOWN:
                    newSelection += 1;
                    if (newSelection > itemCount - 1)
                        newSelection = 0;
                    break;
    
                case SWT.PAGE_DOWN:
                    newSelection += visibleRows;
                    if (newSelection >= itemCount)
                        newSelection = itemCount - 1;
                    break;
    
                case SWT.PAGE_UP:
                    newSelection -= visibleRows;
                    if (newSelection < 0)
                        newSelection = 0;
                    break;
                /*
                 * case SWT.HOME : newSelection= 0; break;
                 * 
                 * case SWT.END : newSelection= itemCount - 1; break;
                 */
                default:
                    if (e.keyCode != SWT.CAPS_LOCK && e.keyCode != SWT.MOD1 && e.keyCode != SWT.MOD2 && e.keyCode != SWT.MOD3 && e.keyCode != SWT.MOD4)
                        hide();
                    return true;
                }
    
                selectProposal(newSelection, (e.stateMask & SWT.CTRL) != 0);
    
                e.doit = false;
                return false;
    
            }
    
            // key != 0
            switch (key) {
            case 0x1B: // Esc
                e.doit = false;
                hide();
                break;
    
            case '
    ': // Ctrl-Enter on w2k
            case '
    ': // Enter
            case '	': // 2017年6月7日09时52分00秒 6 Add
                e.doit = false;
                insertSelectedProposalWithMask(e.stateMask);
                break;
            /*
             * case '	': e.doit= false; fProposalShell.setFocus(); return false;
             */
            default:
                ICompletionProposal p = getSelectedProposal();
                if (p instanceof ICompletionProposalExtension) {
                    ICompletionProposalExtension t = (ICompletionProposalExtension) p;
                    char[] triggers = t.getTriggerCharacters();
                    if (key != 0x20 && key != '=' && key != ';' && contains(triggers, key)) {
                        // if (contains(triggers, key)) {
                        e.doit = false;
                        hide();
                        insertProposal(p, key, e.stateMask, fContentAssistSubjectControlAdapter.getSelectedRange().x);
                    }
                }
            }
    
            return true;
        }
    
        /**
         * Selects the entry with the given index in the proposal selector and feeds
         * the selection to the additional info controller.
         * 
         * @param index
         *            the index in the list
         * @param smartToggle
         *            <code>true</code> if the smart toggle key has been pressed
         * @since 2.1
         */
        private void selectProposal(int index, boolean smartToggle) {
    
            ICompletionProposal oldProposal = getSelectedProposal();
            if (oldProposal instanceof ICompletionProposalExtension2 && fViewer != null)
                ((ICompletionProposalExtension2) oldProposal).unselected(fViewer);
    
            if (fFilteredProposals == null) {
                fireSelectionEvent(null, smartToggle);
                return;
            }
    
            ICompletionProposal proposal = fFilteredProposals[index];
            if (proposal instanceof ICompletionProposalExtension2 && fViewer != null)
                ((ICompletionProposalExtension2) proposal).selected(fViewer, smartToggle);
    
            fireSelectionEvent(proposal, smartToggle);
    
            fLastProposal = proposal;
    
            fProposalTable.setSelection(index);
            fProposalTable.showSelection();
            if (fAdditionalInfoController != null)
                fAdditionalInfoController.handleTableSelectionChanged();
        }
    
        /**
         * Fires a selection event, see {@link ICompletionListener}.
         * 
         * @param proposal
         *            the selected proposal, possibly <code>null</code>
         * @param smartToggle
         *            true if the smart toggle is on
         * @since 3.2
         */
        private void fireSelectionEvent(ICompletionProposal proposal, boolean smartToggle) {
            fContentAssistant.fireSelectionEvent(proposal, smartToggle);
        }
    
        /**
         * Returns whether the given character is contained in the given array of
         * characters.
         * 
         * @param characters
         *            the list of characters
         * @param c
         *            the character to look for in the list
         * @return <code>true</code> if character belongs to the list
         * @since 2.0
         */
        private boolean contains(char[] characters, char c) {
    
            if (characters == null)
                return false;
    
            for (int i = 0; i < characters.length; i++) {
                if (c == characters[i])
                    return true;
            }
    
            return false;
        }
    
        /*
         * @see IEventConsumer#processEvent(VerifyEvent)
         */
        public void processEvent(VerifyEvent e) {
        }
    
        /**
         * Filters the displayed proposal based on the given cursor position and the
         * offset of the original invocation of the content assistant.
         */
        private void filterProposals() {
            if (!fIsFilterPending) {
                fIsFilterPending = true;
                Control control = fContentAssistSubjectControlAdapter.getControl();
                control.getDisplay().asyncExec(fFilterRunnable);
            }
        }
    
        /**
         * Computes the subset of already computed proposals that are still valid
         * for the given offset.
         * 
         * @param offset
         *            the offset
         * @param event
         *            the merged document event
         * @return the set of filtered proposals
         * @since 3.0
         */
        private ICompletionProposal[] computeFilteredProposals(int offset, DocumentEvent event) {
    
            if (offset == fInvocationOffset && event == null) {
                fIsFilteredSubset = false;
                return fComputedProposals;
            }
    
            if (offset < fInvocationOffset) {
                fIsFilteredSubset = false;
                fInvocationOffset = offset;
                fContentAssistant.fireSessionRestartEvent();
                fComputedProposals = computeProposals(fInvocationOffset);
                return fComputedProposals;
            }
    
            ICompletionProposal[] proposals;
            if (offset < fFilterOffset) {
                proposals = fComputedProposals;
                fIsFilteredSubset = false;
            } else {
                proposals = fFilteredProposals;
                fIsFilteredSubset = true;
            }
    
            if (proposals == null) {
                fIsFilteredSubset = false;
                return null;
            }
    
            IDocument document = fContentAssistSubjectControlAdapter.getDocument();
            int length = proposals.length;
            List filtered = new ArrayList(length);
            for (int i = 0; i < length; i++) {
    
                if (proposals[i] instanceof ICompletionProposalExtension2) {
    
                    ICompletionProposalExtension2 p = (ICompletionProposalExtension2) proposals[i];
                    if (p.validate(document, offset, event))
                        filtered.add(p);
    
                } else if (proposals[i] instanceof ICompletionProposalExtension) {
    
                    ICompletionProposalExtension p = (ICompletionProposalExtension) proposals[i];
                    if (p.isValidFor(document, offset))
                        filtered.add(p);
    
                } else {
                    // restore original behavior
                    fIsFilteredSubset = false;
                    fInvocationOffset = offset;
                    fContentAssistant.fireSessionRestartEvent();
                    fComputedProposals = computeProposals(fInvocationOffset);
                    return fComputedProposals;
                }
            }
    
            return (ICompletionProposal[]) filtered.toArray(new ICompletionProposal[filtered.size()]);
        }
    
        /**
         * Requests the proposal shell to take focus.
         * 
         * @since 3.0
         */
        public void setFocus() {
            if (Helper.okToUse(fProposalShell)) {
                fProposalShell.setFocus();
            }
        }
    
        /**
         * Returns <code>true</code> if <code>proposal</code> should be
         * auto-inserted, <code>false</code> otherwise.
         * 
         * @param proposal
         *            the single proposal that might be automatically inserted
         * @return <code>true</code> if <code>proposal</code> can be inserted
         *         automatically, <code>false</code> otherwise
         * @since 3.1
         */
        private boolean canAutoInsert(ICompletionProposal proposal) {
            if (fContentAssistant.isAutoInserting()) {
                if (proposal instanceof ICompletionProposalExtension4) {
                    ICompletionProposalExtension4 ext = (ICompletionProposalExtension4) proposal;
                    return ext.isAutoInsertable();
                }
                return true; // default behavior before
                                // ICompletionProposalExtension4 was introduced
            }
            return false;
        }
    
        /**
         * Completes the common prefix of all proposals directly in the code. If no
         * common prefix can be found, the proposal popup is shown.
         * 
         * @return an error message if completion failed.
         * @since 3.0
         */
        public String incrementalComplete() {
            if (Helper.okToUse(fProposalShell) && fFilteredProposals != null) {
                if (fLastCompletionOffset == fFilterOffset) {
                    handleRepeatedInvocation();
                } else {
                    fLastCompletionOffset = fFilterOffset;
                    completeCommonPrefix();
                }
            } else {
                final Control control = fContentAssistSubjectControlAdapter.getControl();
    
                if (fKeyListener == null)
                    fKeyListener = new ProposalSelectionListener();
    
                if (!Helper.okToUse(fProposalShell) && !control.isDisposed())
                    fContentAssistSubjectControlAdapter.addKeyListener(fKeyListener);
    
                BusyIndicator.showWhile(control.getDisplay(), new Runnable() {
                    public void run() {
    
                        fInvocationOffset = fContentAssistSubjectControlAdapter.getSelectedRange().x;
                        fFilterOffset = fInvocationOffset;
                        fLastCompletionOffset = fFilterOffset;
                        fFilteredProposals = computeProposals(fInvocationOffset);
    
                        int count = (fFilteredProposals == null ? 0 : fFilteredProposals.length);
                        if (count == 0 && hideWhenNoProposals(false))
                            return;
    
                        if (count == 1 && canAutoInsert(fFilteredProposals[0])) {
                            insertProposal(fFilteredProposals[0], (char) 0, 0, fInvocationOffset);
                            hide();
                        } else {
                            ensureDocumentListenerInstalled();
                            if (count > 0 && completeCommonPrefix())
                                hide();
                            else {
                                fComputedProposals = fFilteredProposals;
                                createProposalSelector();
                                setProposals(fComputedProposals, false);
                                displayProposals();
                            }
                        }
                    }
                });
            }
            return getErrorMessage();
        }
    
        /**
         * Acts upon <code>fFilteredProposals</code>: if there is just one valid
         * proposal, it is inserted, otherwise, the common prefix of all proposals
         * is inserted into the document. If there is no common prefix, nothing
         * happens and <code>false</code> is returned.
         * 
         * @return <code>true</code> if a single proposal was inserted and the
         *         selector can be closed, <code>false</code> otherwise
         * @since 3.0
         */
        private boolean completeCommonPrefix() {
    
            // 0: insert single proposals
            if (fFilteredProposals.length == 1) {
                if (canAutoInsert(fFilteredProposals[0])) {
                    insertProposal(fFilteredProposals[0], (char) 0, 0, fFilterOffset);
                    hide();
                    return true;
                }
                return false;
            }
    
            // 1: extract pre- and postfix from all remaining proposals
            IDocument document = fContentAssistSubjectControlAdapter.getDocument();
    
            // contains the common postfix in the case that there are any proposals
            // matching our LHS
            StringBuffer rightCasePostfix = null;
            List rightCase = new ArrayList();
    
            boolean isWrongCaseMatch = false;
    
            // the prefix of all case insensitive matches. This differs from the
            // document
            // contents and will be replaced.
            CharSequence wrongCasePrefix = null;
            int wrongCasePrefixStart = 0;
            // contains the common postfix of all case-insensitive matches
            StringBuffer wrongCasePostfix = null;
            List wrongCase = new ArrayList();
    
            for (int i = 0; i < fFilteredProposals.length; i++) {
                ICompletionProposal proposal = fFilteredProposals[i];
    
                if (!(proposal instanceof ICompletionProposalExtension3))
                    return false;
    
                int start = ((ICompletionProposalExtension3) proposal).getPrefixCompletionStart(fContentAssistSubjectControlAdapter.getDocument(), fFilterOffset);
                CharSequence insertion = ((ICompletionProposalExtension3) proposal).getPrefixCompletionText(fContentAssistSubjectControlAdapter.getDocument(), fFilterOffset);
                if (insertion == null)
                    insertion = TextProcessor.deprocess(proposal.getDisplayString());
                try {
                    int prefixLength = fFilterOffset - start;
                    int relativeCompletionOffset = Math.min(insertion.length(), prefixLength);
                    String prefix = document.get(start, prefixLength);
                    if (!isWrongCaseMatch && insertion.toString().startsWith(prefix)) {
                        isWrongCaseMatch = false;
                        rightCase.add(proposal);
                        CharSequence newPostfix = insertion.subSequence(relativeCompletionOffset, insertion.length());
                        if (rightCasePostfix == null)
                            rightCasePostfix = new StringBuffer(newPostfix.toString());
                        else
                            truncatePostfix(rightCasePostfix, newPostfix);
                    } else if (i == 0 || isWrongCaseMatch) {
                        CharSequence newPrefix = insertion.subSequence(0, relativeCompletionOffset);
                        if (isPrefixCompatible(wrongCasePrefix, wrongCasePrefixStart, newPrefix, start, document)) {
                            isWrongCaseMatch = true;
                            wrongCasePrefix = newPrefix;
                            wrongCasePrefixStart = start;
                            CharSequence newPostfix = insertion.subSequence(relativeCompletionOffset, insertion.length());
                            if (wrongCasePostfix == null)
                                wrongCasePostfix = new StringBuffer(newPostfix.toString());
                            else
                                truncatePostfix(wrongCasePostfix, newPostfix);
                            wrongCase.add(proposal);
                        } else {
                            return false;
                        }
                    } else
                        return false;
                } catch (BadLocationException e2) {
                    // bail out silently
                    return false;
                }
    
                if (rightCasePostfix != null && rightCasePostfix.length() == 0 && rightCase.size() > 1)
                    return false;
            }
    
            // 2: replace single proposals
    
            if (rightCase.size() == 1) {
                ICompletionProposal proposal = (ICompletionProposal) rightCase.get(0);
                if (canAutoInsert(proposal) && rightCasePostfix.length() > 0) {
                    insertProposal(proposal, (char) 0, 0, fInvocationOffset);
                    hide();
                    return true;
                }
                return false;
            } else if (isWrongCaseMatch && wrongCase.size() == 1) {
                ICompletionProposal proposal = (ICompletionProposal) wrongCase.get(0);
                if (canAutoInsert(proposal)) {
                    insertProposal(proposal, (char) 0, 0, fInvocationOffset);
                    hide();
                    return true;
                }
                return false;
            }
    
            // 3: replace post- / prefixes
    
            CharSequence prefix;
            if (isWrongCaseMatch)
                prefix = wrongCasePrefix;
            else
                prefix = ""; //$NON-NLS-1$
    
            CharSequence postfix;
            if (isWrongCaseMatch)
                postfix = wrongCasePostfix;
            else
                postfix = rightCasePostfix;
    
            if (prefix == null || postfix == null)
                return false;
    
            try {
                // 4: check if parts of the postfix are already in the document
                int to = Math.min(document.getLength(), fFilterOffset + postfix.length());
                StringBuffer inDocument = new StringBuffer(document.get(fFilterOffset, to - fFilterOffset));
                truncatePostfix(inDocument, postfix);
    
                // 5: replace and reveal
                document.replace(fFilterOffset - prefix.length(), prefix.length() + inDocument.length(), prefix.toString() + postfix.toString());
    
                fContentAssistSubjectControlAdapter.setSelectedRange(fFilterOffset + postfix.length(), 0);
                fContentAssistSubjectControlAdapter.revealRange(fFilterOffset + postfix.length(), 0);
                fFilterOffset += postfix.length();
                fLastCompletionOffset = fFilterOffset;
    
                return false;
            } catch (BadLocationException e) {
                // ignore and return false
                return false;
            }
        }
    
        /*
         * @since 3.1
         */
        private boolean isPrefixCompatible(CharSequence oneSequence, int oneOffset, CharSequence twoSequence, int twoOffset, IDocument document) throws BadLocationException {
            if (oneSequence == null || twoSequence == null)
                return true;
    
            int min = Math.min(oneOffset, twoOffset);
            int oneEnd = oneOffset + oneSequence.length();
            int twoEnd = twoOffset + twoSequence.length();
    
            String one = document.get(oneOffset, min - oneOffset) + oneSequence + document.get(oneEnd, Math.min(fFilterOffset, fFilterOffset - oneEnd));
            String two = document.get(twoOffset, min - twoOffset) + twoSequence + document.get(twoEnd, Math.min(fFilterOffset, fFilterOffset - twoEnd));
    
            return one.equals(two);
        }
    
        /**
         * Truncates <code>buffer</code> to the common prefix of <code>buffer</code>
         * and <code>sequence</code>.
         * 
         * @param buffer
         *            the common postfix to truncate
         * @param sequence
         *            the characters to truncate with
         */
        private void truncatePostfix(StringBuffer buffer, CharSequence sequence) {
            // find common prefix
            int min = Math.min(buffer.length(), sequence.length());
            for (int c = 0; c < min; c++) {
                if (sequence.charAt(c) != buffer.charAt(c)) {
                    buffer.delete(c, buffer.length());
                    return;
                }
            }
    
            // all equal up to minimum
            buffer.delete(min, buffer.length());
        }
    
        /**
         * Sets the message for the repetition affordance text at the bottom of the
         * proposal. Only has an effect if
         * {@link ContentAssistant#isRepeatedInvocationMode()} returns
         * <code>true</code>.
         * 
         * @param message
         *            the new caption
         * @since 3.2
         */
        void setMessage(String message) {
            Assert.isNotNull(message);
            if (isActive() && fMessageText != null)
                fMessageText.setText(message + " "); //$NON-NLS-1$
        }
    
        /**
         * Sets the text to be displayed if no proposals are available. Only has an
         * effect if {@link ContentAssistant#isShowEmptyList()} returns
         * <code>true</code>.
         * 
         * @param message
         *            the empty message
         * @since 3.2
         */
        void setEmptyMessage(String message) {
            Assert.isNotNull(message);
            fEmptyMessage = message;
        }
    
        /**
         * Enables or disables showing of the caption line. See also
         * {@link #setMessage(String)}.
         * 
         * @param show
         *            <code>true</code> if the status line is visible
         * @since 3.2
         */
        public void setStatusLineVisible(boolean show) {
            if (!isActive() || show == (fMessageText != null))
                return; // nothing to do
    
            if (show) {
                createMessageText();
            } else {
                fMessageText.dispose();
                fMessageText = null;
            }
            fProposalShell.layout();
        }
    
        /**
         * Informs the popup that it is being placed above the caret line instead of
         * below.
         * 
         * @param above
         *            <code>true</code> if the location of the popup is above the
         *            caret line, <code>false</code> if it is below
         * @since 3.3
         */
        void switchedPositionToAbove(boolean above) {
            if (fAdditionalInfoController != null) {
                fAdditionalInfoController.setFallbackAnchors(new Anchor[] { AbstractInformationControlManager.ANCHOR_RIGHT, AbstractInformationControlManager.ANCHOR_LEFT, above ? AbstractInformationControlManager.ANCHOR_TOP : AbstractInformationControlManager.ANCHOR_BOTTOM });
            }
        }
    
        /**
         * Returns a new proposal selection handler.
         * 
         * @param operationCode
         *            the operation code
         * @return the handler
         * @since 3.4
         */
        IHandler createProposalSelectionHandler(int operationCode) {
            return new ProposalSelectionHandler(operationCode);
        }
    
    }

    下载 jre 1.4 后,复制到 C:Program FilesJavajre1.4.2 目录下,然后在 eclipse 项目属性中 Configure Build Path -> Libraries 选项卡下

    Add Library -> JRE System Library -> Alternate JRE 选择 1.4.2 版本 然后 Installed JREs... -> Add -> Standard VM -> Directory...

    找到 C:Program FilesJavajre1.4.2 目录,其余选项会被自动完成,这时候就添加 jre 成功了。

  • 相关阅读:
    概率论基础
    感知机
    CSS3实现jquery的特效
    有品质的生活
    table点击一行显示下一行的特效
    colspan在浏览器中失效的问题
    css的框架——common.css
    使用 document.onreadystatechange()来判断页面加载完
    iframe中子页面通过js计算高度(使得页面不会显示不全)
    js返回上一页并刷新的多种方法
  • 原文地址:https://www.cnblogs.com/z5337/p/6954387.html
Copyright © 2020-2023  润新知