| /******************************************************************************* |
| * Copyright (c) 2000, 2008 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 |
| *******************************************************************************/ |
| package org.eclipse.jface.text.contentassist; |
| |
| import java.util.Iterator; |
| import java.util.Stack; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.BusyIndicator; |
| import org.eclipse.swt.custom.StyledText; |
| import org.eclipse.swt.events.KeyEvent; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.SelectionListener; |
| import org.eclipse.swt.events.VerifyEvent; |
| import org.eclipse.swt.graphics.Color; |
| 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.Shell; |
| import org.eclipse.swt.widgets.Table; |
| import org.eclipse.swt.widgets.TableItem; |
| |
| import org.eclipse.jface.contentassist.IContentAssistSubjectControl; |
| |
| import org.eclipse.jface.text.ITextViewer; |
| import org.eclipse.jface.text.TextPresentation; |
| |
| |
| /** |
| * This class is used to present context information to the user. |
| * If multiple contexts are valid at the current cursor location, |
| * a list is presented from which the user may choose one context. |
| * Once the user makes their choice, or if there was only a single |
| * possible context, the context information is shown in a tool tip like popup. <p> |
| * If the tool tip is visible and the user wants to see context information of |
| * a context embedded into the one for which context information is displayed, |
| * context information for the embedded context is shown. As soon as the |
| * cursor leaves the embedded context area, the context information for |
| * the embedding context is shown again. |
| * |
| * @see IContextInformation |
| * @see IContextInformationValidator |
| */ |
| class ContextInformationPopup implements IContentAssistListener { |
| |
| |
| /** |
| * Represents the state necessary for embedding contexts. |
| * |
| * @since 2.0 |
| */ |
| static class ContextFrame { |
| |
| final int fBeginOffset; |
| final int fOffset; |
| final int fVisibleOffset; |
| final IContextInformation fInformation; |
| final IContextInformationValidator fValidator; |
| final IContextInformationPresenter fPresenter; |
| |
| /* |
| * @since 3.1 |
| */ |
| public ContextFrame(IContextInformation information, int beginOffset, int offset, int visibleOffset, IContextInformationValidator validator, IContextInformationPresenter presenter) { |
| fInformation = information; |
| fBeginOffset = beginOffset; |
| fOffset = offset; |
| fVisibleOffset = visibleOffset; |
| fValidator = validator; |
| fPresenter = presenter; |
| } |
| |
| /* |
| * @see java.lang.Object#equals(java.lang.Object) |
| * @since 3.0 |
| */ |
| public boolean equals(Object obj) { |
| if (obj instanceof ContextFrame) { |
| ContextFrame frame= (ContextFrame) obj; |
| return fInformation.equals(frame.fInformation) && fBeginOffset == frame.fBeginOffset; |
| } |
| return super.equals(obj); |
| } |
| |
| /* |
| * @see java.lang.Object#hashCode() |
| * @since 3.1 |
| */ |
| public int hashCode() { |
| return (fInformation.hashCode() << 16) | fBeginOffset; |
| } |
| } |
| |
| private ITextViewer fViewer; |
| private ContentAssistant fContentAssistant; |
| |
| private PopupCloser fPopupCloser= new PopupCloser(); |
| private Shell fContextSelectorShell; |
| private Table fContextSelectorTable; |
| private IContextInformation[] fContextSelectorInput; |
| private String fLineDelimiter= null; |
| |
| private Shell fContextInfoPopup; |
| private StyledText fContextInfoText; |
| private TextPresentation fTextPresentation; |
| |
| private Stack fContextFrameStack= new Stack(); |
| /** |
| * The content assist subject control. |
| * |
| * @since 3.0 |
| */ |
| private IContentAssistSubjectControl fContentAssistSubjectControl; |
| /** |
| * The content assist subject control adapter. |
| * |
| * @since 3.0 |
| */ |
| private ContentAssistSubjectControlAdapter fContentAssistSubjectControlAdapter; |
| |
| /** |
| * Selection listener on the text widget which is active |
| * while a context information pop up is shown. |
| * |
| * @since 3.0 |
| */ |
| private SelectionListener fTextWidgetSelectionListener; |
| |
| /** |
| * The last removed context frame is remembered in order to not re-query the |
| * user about which context should be used. |
| * |
| * @since 3.0 |
| */ |
| private ContextFrame fLastContext= null; |
| |
| /** |
| * Creates a new context information popup. |
| * |
| * @param contentAssistant the content assist for computing the context information |
| * @param viewer the viewer on top of which the context information is shown |
| */ |
| public ContextInformationPopup(ContentAssistant contentAssistant, ITextViewer viewer) { |
| fContentAssistant= contentAssistant; |
| fViewer= viewer; |
| fContentAssistSubjectControlAdapter= new ContentAssistSubjectControlAdapter(fViewer); |
| } |
| |
| /** |
| * Creates a new context information popup. |
| * |
| * @param contentAssistant the content assist for computing the context information |
| * @param contentAssistSubjectControl the content assist subject control on top of which the context information is shown |
| * @since 3.0 |
| */ |
| public ContextInformationPopup(ContentAssistant contentAssistant, IContentAssistSubjectControl contentAssistSubjectControl) { |
| fContentAssistant= contentAssistant; |
| fContentAssistSubjectControl= contentAssistSubjectControl; |
| fContentAssistSubjectControlAdapter= new ContentAssistSubjectControlAdapter(fContentAssistSubjectControl); |
| } |
| |
| /** |
| * Shows all possible contexts for the given cursor position of the viewer. |
| * |
| * @param autoActivated <code>true</code> if auto activated |
| * @return a potential error message or <code>null</code> in case of no error |
| */ |
| public String showContextProposals(final boolean autoActivated) { |
| final Control control= fContentAssistSubjectControlAdapter.getControl(); |
| BusyIndicator.showWhile(control.getDisplay(), new Runnable() { |
| public void run() { |
| |
| int offset= fContentAssistSubjectControlAdapter.getSelectedRange().x; |
| |
| IContextInformation[] contexts= computeContextInformation(offset); |
| int count = (contexts == null ? 0 : contexts.length); |
| if (count == 1) { |
| |
| ContextFrame frame= createContextFrame(contexts[0], offset); |
| if (isDuplicate(frame)) |
| validateContextInformation(); |
| else |
| // Show context information directly |
| internalShowContextInfo(frame); |
| |
| } else if (count > 0) { |
| |
| // if any of the proposed context matches any of the contexts on the stack, |
| // assume that one (so, if context info is invoked repeatedly, the current |
| // info is kept) |
| for (int i= 0; i < contexts.length; i++) { |
| IContextInformation info= contexts[i]; |
| ContextFrame frame= createContextFrame(info, offset); |
| |
| // check top of stack and stored context |
| if (isDuplicate(frame)) { |
| validateContextInformation(); |
| return; |
| } |
| |
| if (isLastFrame(frame)) { |
| internalShowContextInfo(frame); |
| return; |
| } |
| |
| // also check all other contexts |
| for (Iterator it= fContextFrameStack.iterator(); it.hasNext(); ) { |
| ContextFrame stackFrame= (ContextFrame) it.next(); |
| if (stackFrame.equals(frame)) { |
| validateContextInformation(); |
| return; |
| } |
| } |
| } |
| |
| // otherwise: |
| // Precise context must be selected |
| |
| if (fLineDelimiter == null) |
| fLineDelimiter= fContentAssistSubjectControlAdapter.getLineDelimiter(); |
| |
| createContextSelector(); |
| setContexts(contexts); |
| displayContextSelector(); |
| } |
| } |
| }); |
| |
| return getErrorMessage(); |
| } |
| |
| /** |
| * Displays the given context information for the given offset. |
| * |
| * @param info the context information |
| * @param offset the offset |
| * @since 2.0 |
| */ |
| public void showContextInformation(final IContextInformation info, final int offset) { |
| Control control= fContentAssistSubjectControlAdapter.getControl(); |
| BusyIndicator.showWhile(control.getDisplay(), new Runnable() { |
| public void run() { |
| if (info == null) |
| validateContextInformation(); |
| else { |
| ContextFrame frame= createContextFrame(info, offset); |
| if (isDuplicate(frame)) |
| validateContextInformation(); |
| else |
| internalShowContextInfo(frame); |
| hideContextSelector(); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Displays the given context information for the given offset. |
| * |
| * @param frame the context frame to display, or <code>null</code> |
| * @since 3.0 |
| */ |
| private void internalShowContextInfo(ContextFrame frame) { |
| if (frame != null) { |
| fContextFrameStack.push(frame); |
| if (fContextFrameStack.size() == 1) |
| fLastContext= null; |
| internalShowContextFrame(frame, fContextFrameStack.size() == 1); |
| validateContextInformation(); |
| } |
| } |
| |
| /** |
| * Creates a context frame for the given offset. |
| * |
| * @param information the context information |
| * @param offset the offset |
| * @return the created context frame |
| * @since 3.0 |
| */ |
| private ContextFrame createContextFrame(IContextInformation information, int offset) { |
| IContextInformationValidator validator= fContentAssistSubjectControlAdapter.getContextInformationValidator(fContentAssistant, offset); |
| |
| if (validator != null) { |
| int beginOffset= (information instanceof IContextInformationExtension) ? ((IContextInformationExtension) information).getContextInformationPosition() : offset; |
| if (beginOffset == -1) beginOffset= offset; |
| int visibleOffset= fContentAssistSubjectControlAdapter.getWidgetSelectionRange().x - (offset - beginOffset); |
| IContextInformationPresenter presenter = fContentAssistSubjectControlAdapter.getContextInformationPresenter(fContentAssistant, offset); |
| return new ContextFrame(information, beginOffset, offset, visibleOffset, validator, presenter); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Compares <code>frame</code> with the top of the stack, returns <code>true</code> |
| * if the frames are the same. |
| * |
| * @param frame the frame to check |
| * @return <code>true</code> if <code>frame</code> matches the top of the stack |
| * @since 3.0 |
| */ |
| private boolean isDuplicate(ContextFrame frame) { |
| if (frame == null) |
| return false; |
| if (fContextFrameStack.isEmpty()) |
| return false; |
| // stack not empty |
| ContextFrame top= (ContextFrame) fContextFrameStack.peek(); |
| return frame.equals(top); |
| } |
| |
| /** |
| * Compares <code>frame</code> with most recently removed context frame, returns <code>true</code> |
| * if the frames are the same. |
| * |
| * @param frame the frame to check |
| * @return <code>true</code> if <code>frame</code> matches the most recently removed |
| * @since 3.0 |
| */ |
| private boolean isLastFrame(ContextFrame frame) { |
| return frame != null && frame.equals(fLastContext); |
| } |
| |
| /** |
| * Shows the given context frame. |
| * |
| * @param frame the frame to display |
| * @param initial <code>true</code> if this is the first frame to be displayed |
| * @since 2.0 |
| */ |
| private void internalShowContextFrame(ContextFrame frame, boolean initial) { |
| |
| fContentAssistSubjectControlAdapter.installValidator(frame); |
| |
| if (frame.fPresenter != null) { |
| if (fTextPresentation == null) |
| fTextPresentation= new TextPresentation(); |
| fContentAssistSubjectControlAdapter.installContextInformationPresenter(frame); |
| frame.fPresenter.updatePresentation(frame.fOffset, fTextPresentation); |
| } |
| |
| createContextInfoPopup(); |
| |
| fContextInfoText.setText(frame.fInformation.getInformationDisplayString()); |
| if (fTextPresentation != null) |
| TextPresentation.applyTextPresentation(fTextPresentation, fContextInfoText); |
| resize(frame.fVisibleOffset); |
| |
| if (initial) { |
| if (fContentAssistant.addContentAssistListener(this, ContentAssistant.CONTEXT_INFO_POPUP)) { |
| if (fContentAssistSubjectControlAdapter.getControl() != null) { |
| fTextWidgetSelectionListener= new SelectionAdapter() { |
| /* |
| * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) |
| */ |
| public void widgetSelected(SelectionEvent e) { |
| validateContextInformation(); |
| }}; |
| fContentAssistSubjectControlAdapter.addSelectionListener(fTextWidgetSelectionListener); |
| } |
| fContentAssistant.addToLayout(this, fContextInfoPopup, ContentAssistant.LayoutManager.LAYOUT_CONTEXT_INFO_POPUP, frame.fVisibleOffset); |
| fContextInfoPopup.setVisible(true); |
| } |
| } else { |
| fContentAssistant.layout(ContentAssistant.LayoutManager.LAYOUT_CONTEXT_INFO_POPUP, frame.fVisibleOffset); |
| } |
| } |
| |
| /** |
| * Computes all possible context information for the given offset. |
| * |
| * @param offset the offset |
| * @return all possible context information for the given offset |
| * @since 2.0 |
| */ |
| private IContextInformation[] computeContextInformation(int offset) { |
| return fContentAssistSubjectControlAdapter.computeContextInformation(fContentAssistant, offset); |
| } |
| |
| /** |
| *Returns the error message generated while computing context information. |
| * |
| * @return the error message |
| */ |
| private String getErrorMessage() { |
| return fContentAssistant.getErrorMessage(); |
| } |
| |
| /** |
| * Creates the context information popup. This is the tool tip like overlay window. |
| */ |
| private void createContextInfoPopup() { |
| if (Helper.okToUse(fContextInfoPopup)) |
| return; |
| |
| Control control= fContentAssistSubjectControlAdapter.getControl(); |
| Display display= control.getDisplay(); |
| |
| fContextInfoPopup= new Shell(control.getShell(), SWT.NO_TRIM | SWT.ON_TOP); |
| fContextInfoPopup.setBackground(display.getSystemColor(SWT.COLOR_BLACK)); |
| |
| fContextInfoText= new StyledText(fContextInfoPopup, SWT.MULTI | SWT.READ_ONLY | SWT.WRAP); |
| |
| Color c= fContentAssistant.getContextInformationPopupBackground(); |
| if (c == null) |
| c= display.getSystemColor(SWT.COLOR_INFO_BACKGROUND); |
| fContextInfoText.setBackground(c); |
| |
| c= fContentAssistant.getContextInformationPopupForeground(); |
| if (c == null) |
| c= display.getSystemColor(SWT.COLOR_INFO_FOREGROUND); |
| fContextInfoText.setForeground(c); |
| } |
| |
| /** |
| * Resizes the context information popup. |
| * |
| * @param offset the caret offset in widget coordinates |
| * @since 2.0 |
| */ |
| private void resize(int offset) { |
| Point size= fContextInfoText.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); |
| final int TEXT_PAD= 0; |
| final int BORDER_PAD= 2; |
| final int PAD= TEXT_PAD + BORDER_PAD; |
| size.x += PAD; |
| Rectangle bounds= fContentAssistant.getLayoutManager().computeBoundsAboveBelow(fContextInfoPopup, size, offset); |
| if (bounds.width < size.x) |
| // we don't fit on the screen - try again and wrap |
| size= fContextInfoText.computeSize(bounds.width - PAD, SWT.DEFAULT, true); |
| |
| size.x += TEXT_PAD; |
| fContextInfoText.setSize(size); |
| fContextInfoText.setLocation(1,1); |
| size.x += BORDER_PAD; |
| size.y += BORDER_PAD; |
| fContextInfoPopup.setSize(size); |
| } |
| |
| /** |
| * Hides the context information popup. |
| */ |
| private void hideContextInfoPopup() { |
| |
| if (Helper.okToUse(fContextInfoPopup)) { |
| |
| int size= fContextFrameStack.size(); |
| if (size > 0) { |
| fLastContext= (ContextFrame) fContextFrameStack.pop(); |
| -- size; |
| } |
| |
| if (size > 0) { |
| ContextFrame current= (ContextFrame) fContextFrameStack.peek(); |
| internalShowContextFrame(current, false); |
| } else { |
| |
| fContentAssistant.removeContentAssistListener(this, ContentAssistant.CONTEXT_INFO_POPUP); |
| |
| if (fContentAssistSubjectControlAdapter.getControl() != null) |
| fContentAssistSubjectControlAdapter.removeSelectionListener(fTextWidgetSelectionListener); |
| fTextWidgetSelectionListener= null; |
| |
| fContextInfoPopup.setVisible(false); |
| fContextInfoPopup.dispose(); |
| fContextInfoPopup= null; |
| |
| if (fTextPresentation != null) { |
| fTextPresentation.clear(); |
| fTextPresentation= null; |
| } |
| } |
| } |
| |
| if (fContextInfoPopup == null) |
| fContentAssistant.contextInformationClosed(); |
| } |
| |
| /** |
| * Creates the context selector in case the user has the choice between multiple valid contexts |
| * at a given offset. |
| */ |
| private void createContextSelector() { |
| if (Helper.okToUse(fContextSelectorShell)) |
| return; |
| |
| Control control= fContentAssistSubjectControlAdapter.getControl(); |
| fContextSelectorShell= new Shell(control.getShell(), SWT.ON_TOP | SWT.RESIZE); |
| GridLayout layout= new GridLayout(); |
| layout.marginWidth= 0; |
| layout.marginHeight= 0; |
| fContextSelectorShell.setLayout(layout); |
| fContextSelectorShell.setBackground(control.getDisplay().getSystemColor(SWT.COLOR_BLACK)); |
| |
| |
| fContextSelectorTable= new Table(fContextSelectorShell, SWT.H_SCROLL | SWT.V_SCROLL); |
| fContextSelectorTable.setLocation(1, 1); |
| GridData gd= new GridData(GridData.FILL_BOTH); |
| gd.heightHint= fContextSelectorTable.getItemHeight() * 10; |
| gd.widthHint= 300; |
| fContextSelectorTable.setLayoutData(gd); |
| |
| fContextSelectorShell.pack(true); |
| |
| Color c= fContentAssistant.getContextSelectorBackground(); |
| if (c == null) |
| c= control.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND); |
| fContextSelectorTable.setBackground(c); |
| |
| c= fContentAssistant.getContextSelectorForeground(); |
| if (c == null) |
| c= control.getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND); |
| fContextSelectorTable.setForeground(c); |
| |
| fContextSelectorTable.addSelectionListener(new SelectionListener() { |
| public void widgetSelected(SelectionEvent e) { |
| } |
| |
| public void widgetDefaultSelected(SelectionEvent e) { |
| insertSelectedContext(); |
| hideContextSelector(); |
| } |
| }); |
| |
| fPopupCloser.install(fContentAssistant, fContextSelectorTable); |
| |
| fContextSelectorTable.setHeaderVisible(false); |
| fContentAssistant.addToLayout(this, fContextSelectorShell, ContentAssistant.LayoutManager.LAYOUT_CONTEXT_SELECTOR, fContentAssistant.getSelectionOffset()); |
| } |
| |
| /** |
| * Returns the minimal required height for the popup, 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(fContextSelectorTable)) { |
| int items= fContextSelectorTable.getItemHeight() * 10; |
| Rectangle trim= fContextSelectorTable.computeTrim(0, 0, SWT.DEFAULT, items); |
| height= trim.height; |
| } |
| return height; |
| } |
| |
| /** |
| * Causes the context information of the context selected in the context selector |
| * to be displayed in the context information popup. |
| */ |
| private void insertSelectedContext() { |
| int i= fContextSelectorTable.getSelectionIndex(); |
| |
| if (i < 0 || i >= fContextSelectorInput.length) |
| return; |
| |
| int offset= fContentAssistSubjectControlAdapter.getSelectedRange().x; |
| internalShowContextInfo(createContextFrame(fContextSelectorInput[i], offset)); |
| } |
| |
| /** |
| * Sets the contexts in the context selector to the given set. |
| * |
| * @param contexts the possible contexts |
| */ |
| private void setContexts(IContextInformation[] contexts) { |
| if (Helper.okToUse(fContextSelectorTable)) { |
| |
| fContextSelectorInput= contexts; |
| |
| fContextSelectorTable.setRedraw(false); |
| fContextSelectorTable.removeAll(); |
| |
| TableItem item; |
| IContextInformation t; |
| for (int i= 0; i < contexts.length; i++) { |
| t= contexts[i]; |
| item= new TableItem(fContextSelectorTable, SWT.NULL); |
| if (t.getImage() != null) |
| item.setImage(t.getImage()); |
| item.setText(t.getContextDisplayString()); |
| } |
| |
| fContextSelectorTable.select(0); |
| fContextSelectorTable.setRedraw(true); |
| } |
| } |
| |
| /** |
| * Displays the context selector. |
| */ |
| private void displayContextSelector() { |
| if (fContentAssistant.addContentAssistListener(this, ContentAssistant.CONTEXT_SELECTOR)) |
| fContextSelectorShell.setVisible(true); |
| } |
| |
| /** |
| * Hides the context selector. |
| */ |
| private void hideContextSelector() { |
| if (Helper.okToUse(fContextSelectorShell)) { |
| fContentAssistant.removeContentAssistListener(this, ContentAssistant.CONTEXT_SELECTOR); |
| |
| fPopupCloser.uninstall(); |
| fContextSelectorShell.setVisible(false); |
| fContextSelectorShell.dispose(); |
| fContextSelectorShell= null; |
| } |
| |
| if (!Helper.okToUse(fContextInfoPopup)) |
| fContentAssistant.contextInformationClosed(); |
| } |
| |
| /** |
| *Returns whether the context selector has the focus. |
| * |
| * @return <code>true</code> if the context selector has the focus |
| */ |
| public boolean hasFocus() { |
| if (Helper.okToUse(fContextSelectorShell)) |
| return (fContextSelectorShell.isFocusControl() || fContextSelectorTable.isFocusControl()); |
| |
| return false; |
| } |
| |
| /** |
| * Hides context selector and context information popup. |
| */ |
| public void hide() { |
| hideContextSelector(); |
| hideContextInfoPopup(); |
| } |
| |
| /** |
| * Returns whether this context information popup is active. I.e., either |
| * a context selector or context information is displayed. |
| * |
| * @return <code>true</code> if the context selector is active |
| */ |
| public boolean isActive() { |
| return (Helper.okToUse(fContextInfoPopup) || Helper.okToUse(fContextSelectorShell)); |
| } |
| |
| /* |
| * @see IContentAssistListener#verifyKey(VerifyEvent) |
| */ |
| public boolean verifyKey(VerifyEvent e) { |
| if (Helper.okToUse(fContextSelectorShell)) |
| return contextSelectorKeyPressed(e); |
| if (Helper.okToUse(fContextInfoPopup)) |
| return contextInfoPopupKeyPressed(e); |
| return true; |
| } |
| |
| /** |
| * Processes a key stroke in the context selector. |
| * |
| * @param e the verify event describing the key stroke |
| * @return <code>true</code> if processing can be stopped |
| */ |
| private boolean contextSelectorKeyPressed(VerifyEvent e) { |
| |
| char key= e.character; |
| if (key == 0) { |
| |
| int newSelection= fContextSelectorTable.getSelectionIndex(); |
| int visibleRows= (fContextSelectorTable.getSize().y / fContextSelectorTable.getItemHeight()) - 1; |
| int itemCount= fContextSelectorTable.getItemCount(); |
| switch (e.keyCode) { |
| 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) |
| hideContextSelector(); |
| return true; |
| } |
| |
| fContextSelectorTable.setSelection(newSelection); |
| fContextSelectorTable.showSelection(); |
| e.doit= false; |
| return false; |
| |
| } else if ('\t' == key) { |
| // switch focus to selector shell |
| e.doit= false; |
| fContextSelectorShell.setFocus(); |
| return false; |
| } else if (key == SWT.ESC) { |
| e.doit= false; |
| hideContextSelector(); |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Processes a key stroke while the info popup is up. |
| * |
| * @param e the verify event describing the key stroke |
| * @return <code>true</code> if processing can be stopped |
| */ |
| private boolean contextInfoPopupKeyPressed(KeyEvent e) { |
| |
| char key= e.character; |
| if (key == 0) { |
| |
| switch (e.keyCode) { |
| case SWT.ARROW_LEFT: |
| case SWT.ARROW_RIGHT: |
| case SWT.ARROW_UP: |
| case SWT.ARROW_DOWN: |
| validateContextInformation(); |
| break; |
| default: |
| if (e.keyCode != SWT.CAPS_LOCK && e.keyCode != SWT.MOD1 && e.keyCode != SWT.MOD2 && e.keyCode != SWT.MOD3 && e.keyCode != SWT.MOD4) |
| hideContextInfoPopup(); |
| break; |
| } |
| |
| } else if (key == SWT.ESC) { |
| e.doit= false; |
| hideContextInfoPopup(); |
| } else { |
| validateContextInformation(); |
| } |
| return true; |
| } |
| |
| /* |
| * @see IEventConsumer#processEvent(VerifyEvent) |
| */ |
| public void processEvent(VerifyEvent event) { |
| if (Helper.okToUse(fContextSelectorShell)) |
| contextSelectorProcessEvent(event); |
| if (Helper.okToUse(fContextInfoPopup)) |
| contextInfoPopupProcessEvent(event); |
| } |
| |
| /** |
| * Processes a key stroke in the context selector. |
| * |
| * @param e the verify event describing the key stroke |
| */ |
| private void contextSelectorProcessEvent(VerifyEvent e) { |
| |
| if (e.start == e.end && e.text != null && e.text.equals(fLineDelimiter)) { |
| e.doit= false; |
| insertSelectedContext(); |
| } |
| |
| hideContextSelector(); |
| } |
| |
| /** |
| * Processes a key stroke while the info popup is up. |
| * |
| * @param e the verify event describing the key stroke |
| */ |
| private void contextInfoPopupProcessEvent(VerifyEvent e) { |
| if (e.start != e.end && (e.text == null || e.text.length() == 0)) |
| validateContextInformation(); |
| } |
| |
| /** |
| * Validates the context information for the viewer's actual cursor position. |
| */ |
| private void validateContextInformation() { |
| /* |
| * Post the code in the event queue in order to ensure that the |
| * action described by this verify key event has already been executed. |
| * Otherwise, we'd validate the context information based on the |
| * pre-key-stroke state. |
| */ |
| if (!Helper.okToUse(fContextInfoPopup)) |
| return; |
| |
| fContextInfoPopup.getDisplay().asyncExec(new Runnable() { |
| |
| private ContextFrame fFrame= (ContextFrame) fContextFrameStack.peek(); |
| |
| public void run() { |
| // only do this if no other frames have been added in between |
| if (!fContextFrameStack.isEmpty() && fFrame == fContextFrameStack.peek()) { |
| int offset= fContentAssistSubjectControlAdapter.getSelectedRange().x; |
| |
| // iterate all contexts on the stack |
| while (Helper.okToUse(fContextInfoPopup) && !fContextFrameStack.isEmpty()) { |
| ContextFrame top= (ContextFrame) fContextFrameStack.peek(); |
| if (top.fValidator == null || !top.fValidator.isContextInformationValid(offset)) { |
| hideContextInfoPopup(); // loop variant: reduces the number of contexts on the stack |
| } else if (top.fPresenter != null && top.fPresenter.updatePresentation(offset, fTextPresentation)) { |
| int widgetOffset= fContentAssistSubjectControlAdapter.getWidgetSelectionRange().x; |
| TextPresentation.applyTextPresentation(fTextPresentation, fContextInfoText); |
| resize(widgetOffset); |
| break; |
| } else |
| break; |
| } |
| } |
| } |
| }); |
| } |
| } |