/******************************************************************************* * Copyright (c) 2000, 2003 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package test0501; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.CollationElementIterator; import java.text.Collator; import java.text.RuleBasedCollator; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ResourceBundle; import java.util.StringTokenizer; import org.eclipse.core.resources.IMarker; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Preferences; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BidiSegmentEvent; import org.eclipse.swt.custom.BidiSegmentListener; import org.eclipse.swt.custom.ST; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.GroupMarker; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferenceConverter; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.IPostSelectionProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.DefaultInformationControl; import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentListener; import org.eclipse.jface.text.IInformationControl; import org.eclipse.jface.text.IInformationControlCreator; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextHover; import org.eclipse.jface.text.ITextInputListener; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.ITextViewerExtension2; import org.eclipse.jface.text.ITextViewerExtension3; import org.eclipse.jface.text.ITextViewerExtension4; import org.eclipse.jface.text.ITypedRegion; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.text.TextUtilities; import org.eclipse.jface.text.information.IInformationProvider; import org.eclipse.jface.text.information.IInformationProviderExtension2; import org.eclipse.jface.text.information.InformationPresenter; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.IAnnotationAccess; import org.eclipse.jface.text.source.IAnnotationModel; import org.eclipse.jface.text.source.IOverviewRuler; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.IVerticalRuler; import org.eclipse.jface.text.source.LineChangeHover; import org.eclipse.jface.text.source.SourceViewerConfiguration; import org.eclipse.ui.editors.text.DefaultEncodingSupport; import org.eclipse.ui.editors.text.IEncodingSupport; import org.eclipse.ui.IEditorActionBarContributor; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IPageLayout; import org.eclipse.ui.IPartService; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.actions.ActionContext; import org.eclipse.ui.actions.ActionGroup; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.EditorActionBarContributor; import org.eclipse.ui.part.IShowInTargetList; import org.eclipse.ui.texteditor.AddTaskAction; import org.eclipse.ui.texteditor.AnnotationPreference; import org.eclipse.ui.texteditor.DefaultAnnotation; import org.eclipse.ui.texteditor.DefaultMarkerAnnotationAccess; import org.eclipse.ui.texteditor.DefaultRangeIndicator; import org.eclipse.ui.texteditor.ExtendedTextEditor; import org.eclipse.ui.texteditor.IAbstractTextEditorHelpContextIds; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.IEditorStatusLine; import org.eclipse.ui.texteditor.ITextEditorActionConstants; import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; import org.eclipse.ui.texteditor.MarkerAnnotation; import org.eclipse.ui.texteditor.MarkerAnnotationPreferences; import org.eclipse.ui.texteditor.ResourceAction; import org.eclipse.ui.texteditor.SourceViewerDecorationSupport; import org.eclipse.ui.texteditor.TextEditorAction; import org.eclipse.ui.texteditor.TextNavigationAction; import org.eclipse.ui.texteditor.TextOperationAction; import org.eclipse.ui.views.contentoutline.ContentOutline; import org.eclipse.ui.views.contentoutline.IContentOutlinePage; import org.eclipse.search.ui.SearchUI; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.ICodeAssist; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IImportContainer; import org.eclipse.jdt.core.IImportDeclaration; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IPackageDeclaration; import org.eclipse.jdt.core.ISourceRange; import org.eclipse.jdt.core.ISourceReference; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.ui.IContextMenuConstants; import org.eclipse.jdt.ui.JavaUI; import org.eclipse.jdt.ui.PreferenceConstants; import org.eclipse.jdt.ui.actions.IJavaEditorActionDefinitionIds; import org.eclipse.jdt.ui.actions.JavaSearchActionGroup; import org.eclipse.jdt.ui.actions.OpenEditorActionGroup; import org.eclipse.jdt.ui.actions.OpenViewActionGroup; import org.eclipse.jdt.ui.actions.ShowActionGroup; import org.eclipse.jdt.ui.text.JavaSourceViewerConfiguration; import org.eclipse.jdt.ui.text.JavaTextTools; import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; import org.eclipse.jdt.internal.ui.JavaPlugin; import org.eclipse.jdt.internal.ui.actions.CompositeActionGroup; import org.eclipse.jdt.internal.ui.actions.SelectionConverter; import org.eclipse.jdt.internal.ui.javaeditor.selectionactions.GoToNextPreviousMemberAction; import org.eclipse.jdt.internal.ui.javaeditor.selectionactions.SelectionHistory; import org.eclipse.jdt.internal.ui.javaeditor.selectionactions.StructureSelectEnclosingAction; import org.eclipse.jdt.internal.ui.javaeditor.selectionactions.StructureSelectHistoryAction; import org.eclipse.jdt.internal.ui.javaeditor.selectionactions.StructureSelectNextAction; import org.eclipse.jdt.internal.ui.javaeditor.selectionactions.StructureSelectPreviousAction; import org.eclipse.jdt.internal.ui.javaeditor.selectionactions.StructureSelectionAction; import org.eclipse.jdt.internal.ui.search.FindOccurrencesEngine; import org.eclipse.jdt.internal.ui.text.HTMLTextPresenter; import org.eclipse.jdt.internal.ui.text.IJavaPartitions; import org.eclipse.jdt.internal.ui.text.JavaChangeHover; import org.eclipse.jdt.internal.ui.text.JavaPairMatcher; import org.eclipse.jdt.internal.ui.util.JavaUIHelp; import org.eclipse.jdt.internal.ui.viewsupport.IViewPartInputProvider; /** * Java specific text editor. */ public abstract class JavaEditor extends ExtendedTextEditor implements IViewPartInputProvider { /** * Internal implementation class for a change listener. * @since 3.0 */ protected abstract class AbstractSelectionChangedListener implements ISelectionChangedListener { /** * Installs this selection changed listener with the given selection provider. If * the selection provider is a post selection provider, post selection changed * events are the preferred choice, otherwise normal selection changed events * are requested. * * @param selectionProvider */ public void install(ISelectionProvider selectionProvider) { if (selectionProvider == null) return; if (selectionProvider instanceof IPostSelectionProvider) { IPostSelectionProvider provider= (IPostSelectionProvider) selectionProvider; provider.addPostSelectionChangedListener(this); } else { selectionProvider.addSelectionChangedListener(this); } } /** * Removes this selection changed listener from the given selection provider. * * @param selectionProvider */ public void uninstall(ISelectionProvider selectionProvider) { if (selectionProvider == null) return; if (selectionProvider instanceof IPostSelectionProvider) { IPostSelectionProvider provider= (IPostSelectionProvider) selectionProvider; provider.removePostSelectionChangedListener(this); } else { selectionProvider.removeSelectionChangedListener(this); } } } /** * Updates the Java outline page selection and this editor's range indicator. * * @since 3.0 */ private class EditorSelectionChangedListener extends AbstractSelectionChangedListener { /* * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent) */ public void selectionChanged(SelectionChangedEvent event) { selectionChanged(); } public void selectionChanged() { ISourceReference element= computeHighlightRangeSourceReference(); synchronizeOutlinePage(element); setSelection(element, false); updateStatusLine(); updateOccurrences(); } } /** * Updates the selection in the editor's widget with the selection of the outline page. */ class OutlineSelectionChangedListener extends AbstractSelectionChangedListener { public void selectionChanged(SelectionChangedEvent event) { doSelectionChanged(event); } } /* * Link mode. */ class MouseClickListener implements KeyListener, MouseListener, MouseMoveListener, FocusListener, PaintListener, IPropertyChangeListener, IDocumentListener, ITextInputListener { /** The session is active. */ private boolean fActive; /** The currently active style range. */ private IRegion fActiveRegion; /** The currently active style range as position. */ private Position fRememberedPosition; /** The hand cursor. */ private Cursor fCursor; /** The link color. */ private Color fColor; /** The key modifier mask. */ private int fKeyModifierMask; /** * Style ranges before link mode. * @since 3.0 */ private StyleRange[] fOldStyleRanges; /** * Link mode style ranges region. * @since 3.0 */ IRegion fOldStyleRangeRegion; public void deactivate() { deactivate(false); } public void deactivate(boolean redrawAll) { if (!fActive) return; repairRepresentation(redrawAll); fActive= false; } public void install() { ISourceViewer sourceViewer= getSourceViewer(); if (sourceViewer == null) return; StyledText text= sourceViewer.getTextWidget(); if (text == null || text.isDisposed()) return; updateColor(sourceViewer); sourceViewer.addTextInputListener(this); IDocument document= sourceViewer.getDocument(); if (document != null) document.addDocumentListener(this); text.addKeyListener(this); text.addMouseListener(this); text.addMouseMoveListener(this); text.addFocusListener(this); text.addPaintListener(this); updateKeyModifierMask(); IPreferenceStore preferenceStore= getPreferenceStore(); preferenceStore.addPropertyChangeListener(this); } private void updateKeyModifierMask() { String modifiers= getPreferenceStore().getString(BROWSER_LIKE_LINKS_KEY_MODIFIER); fKeyModifierMask= computeStateMask(modifiers); if (fKeyModifierMask == -1) { // Fallback to stored state mask fKeyModifierMask= getPreferenceStore().getInt(BROWSER_LIKE_LINKS_KEY_MODIFIER_MASK); } } private int computeStateMask(String modifiers) { if (modifiers == null) return -1; if (modifiers.length() == 0) return SWT.NONE; int stateMask= 0; StringTokenizer modifierTokenizer= new StringTokenizer(modifiers, ",;.:+-* "); //$NON-NLS-1$ while (modifierTokenizer.hasMoreTokens()) { int modifier= EditorUtility.findLocalizedModifier(modifierTokenizer.nextToken()); if (modifier == 0 || (stateMask & modifier) == modifier) return -1; stateMask= stateMask | modifier; } return stateMask; } public void uninstall() { if (fColor != null) { fColor.dispose(); fColor= null; } if (fCursor != null) { fCursor.dispose(); fCursor= null; } ISourceViewer sourceViewer= getSourceViewer(); if (sourceViewer == null) return; sourceViewer.removeTextInputListener(this); IDocument document= sourceViewer.getDocument(); if (document != null) document.removeDocumentListener(this); IPreferenceStore preferenceStore= getPreferenceStore(); if (preferenceStore != null) preferenceStore.removePropertyChangeListener(this); StyledText text= sourceViewer.getTextWidget(); if (text == null || text.isDisposed()) return; text.removeKeyListener(this); text.removeMouseListener(this); text.removeMouseMoveListener(this); text.removeFocusListener(this); text.removePaintListener(this); } /* * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent) */ public void propertyChange(PropertyChangeEvent event) { if (event.getProperty().equals(JavaEditor.LINK_COLOR)) { ISourceViewer viewer= getSourceViewer(); if (viewer != null) updateColor(viewer); } else if (event.getProperty().equals(BROWSER_LIKE_LINKS_KEY_MODIFIER)) { updateKeyModifierMask(); } } private void updateColor(ISourceViewer viewer) { if (fColor != null) fColor.dispose(); StyledText text= viewer.getTextWidget(); if (text == null || text.isDisposed()) return; Display display= text.getDisplay(); fColor= createColor(getPreferenceStore(), JavaEditor.LINK_COLOR, display); } /** * Creates a color from the information stored in the given preference store. * Returns <code>null</code> if there is no such information available. */ private Color createColor(IPreferenceStore store, String key, Display display) { RGB rgb= null; if (store.contains(key)) { if (store.isDefault(key)) rgb= PreferenceConverter.getDefaultColor(store, key); else rgb= PreferenceConverter.getColor(store, key); if (rgb != null) return new Color(display, rgb); } return null; } private void repairRepresentation() { repairRepresentation(false); } private void repairRepresentation(boolean redrawAll) { if (fActiveRegion == null) return; int offset= fActiveRegion.getOffset(); int length= fActiveRegion.getLength(); fActiveRegion= null; ISourceViewer viewer= getSourceViewer(); if (viewer != null) { resetCursor(viewer); // remove style if (!redrawAll && viewer instanceof ITextViewerExtension2) ((ITextViewerExtension2) viewer).invalidateTextPresentation(offset, length); else viewer.invalidateTextPresentation(); if (viewer instanceof ITextViewerExtension3) { ITextViewerExtension3 extension= (ITextViewerExtension3) viewer; offset= extension.modelOffset2WidgetOffset(offset); } else { offset -= viewer.getVisibleRegion().getOffset(); } try { StyledText text= viewer.getTextWidget(); // Removes style text.replaceStyleRanges(fOldStyleRangeRegion.getOffset(), fOldStyleRangeRegion.getLength(), fOldStyleRanges); // text.replaceStyleRanges(offset, length, fOldStyleRanges); // Causes underline to disappear text.redrawRange(offset, length, false); } catch (IllegalArgumentException x) { JavaPlugin.log(x); } } } // will eventually be replaced by a method provided by jdt.core private IRegion selectWord(IDocument document, int anchor) { try { int offset= anchor; char c; while (offset >= 0) { c= document.getChar(offset); if (!Character.isJavaIdentifierPart(c)) break; --offset; } int start= offset; offset= anchor; int length= document.getLength(); while (offset < length) { c= document.getChar(offset); if (!Character.isJavaIdentifierPart(c)) break; ++offset; } int end= offset; if (start == end) return new Region(start, 0); else return new Region(start + 1, end - start - 1); } catch (BadLocationException x) { return null; } } IRegion getCurrentTextRegion(ISourceViewer viewer) { int offset= getCurrentTextOffset(viewer); if (offset == -1) return null; IJavaElement input= SelectionConverter.getInput(JavaEditor.this); if (input == null) return null; try { IJavaElement[] elements= null; synchronized (input) { elements= ((ICodeAssist) input).codeSelect(offset, 0); } if (elements == null || elements.length == 0) return null; return selectWord(viewer.getDocument(), offset); } catch (JavaModelException e) { return null; } } private int getCurrentTextOffset(ISourceViewer viewer) { try { StyledText text= viewer.getTextWidget(); if (text == null || text.isDisposed()) return -1; Display display= text.getDisplay(); Point absolutePosition= display.getCursorLocation(); Point relativePosition= text.toControl(absolutePosition); int widgetOffset= text.getOffsetAtLocation(relativePosition); if (viewer instanceof ITextViewerExtension3) { ITextViewerExtension3 extension= (ITextViewerExtension3) viewer; return extension.widgetOffset2ModelOffset(widgetOffset); } else { return widgetOffset + viewer.getVisibleRegion().getOffset(); } } catch (IllegalArgumentException e) { return -1; } } private void highlightRegion(ISourceViewer viewer, IRegion region) { if (region.equals(fActiveRegion)) return; repairRepresentation(); StyledText text= viewer.getTextWidget(); if (text == null || text.isDisposed()) return; // highlight region int offset= 0; int length= 0; if (viewer instanceof ITextViewerExtension3) { ITextViewerExtension3 extension= (ITextViewerExtension3) viewer; IRegion widgetRange= extension.modelRange2WidgetRange(region); if (widgetRange == null) return; offset= widgetRange.getOffset(); length= widgetRange.getLength(); } else { offset= region.getOffset() - viewer.getVisibleRegion().getOffset(); length= region.getLength(); } fOldStyleRanges = text.getStyleRanges(offset, length); fOldStyleRangeRegion= new Region(offset, length); applyForgroundStyle(text, offset, length); text.redrawRange(offset, length, false); fActiveRegion= region; } private void applyForgroundStyle(StyledText fTextWidget, int offset, int length) { StyleRange[] styleRanges= fTextWidget.getStyleRanges(offset, length); ArrayList newStyleRanges= new ArrayList(styleRanges.length + 10); int rangeOffset= offset; for (int i= 0, max= styleRanges.length; i < max; i++) { StyleRange sr= styleRanges[i]; if (rangeOffset < sr.start) { // Unstyled range StyleRange usr= new StyleRange(rangeOffset, sr.start - rangeOffset, fColor, null); newStyleRanges.add(usr); } rangeOffset= sr.start + sr.length; // Important: Must create a new one sr= new StyleRange(sr.start, sr.length, fColor, sr.background, sr.fontStyle); newStyleRanges.add(sr); } int endOffset= offset + length; if (rangeOffset < endOffset) { // Last unstyled range StyleRange usr= new StyleRange(rangeOffset, endOffset - rangeOffset, fColor, null); newStyleRanges.add(usr); } styleRanges= (StyleRange[])newStyleRanges.toArray(new StyleRange[newStyleRanges.size()]); fTextWidget.replaceStyleRanges(offset, length, styleRanges); } private void activateCursor(ISourceViewer viewer) { StyledText text= viewer.getTextWidget(); if (text == null || text.isDisposed()) return; Display display= text.getDisplay(); if (fCursor == null) fCursor= new Cursor(display, SWT.CURSOR_HAND); text.setCursor(fCursor); } private void resetCursor(ISourceViewer viewer) { StyledText text= viewer.getTextWidget(); if (text != null && !text.isDisposed()) text.setCursor(null); if (fCursor != null) { fCursor.dispose(); fCursor= null; } } /* * @see org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.KeyEvent) */ public void keyPressed(KeyEvent event) { if (fActive) { deactivate(); return; } if (event.keyCode != fKeyModifierMask) { deactivate(); return; } fActive= true; // removed for #25871 // // ISourceViewer viewer= getSourceViewer(); // if (viewer == null) // return; // // IRegion region= getCurrentTextRegion(viewer); // if (region == null) // return; // // highlightRegion(viewer, region); // activateCursor(viewer); } /* * @see org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent) */ public void keyReleased(KeyEvent event) { if (!fActive) return; deactivate(); } /* * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent) */ public void mouseDoubleClick(MouseEvent e) {} /* * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent) */ public void mouseDown(MouseEvent event) { if (!fActive) return; if (event.stateMask != fKeyModifierMask) { deactivate(); return; } if (event.button != 1) { deactivate(); return; } } /* * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent) */ public void mouseUp(MouseEvent e) { if (!fActive) return; if (e.button != 1) { deactivate(); return; } boolean wasActive= fCursor != null; deactivate(); if (wasActive) { IAction action= getAction("OpenEditor"); //$NON-NLS-1$ if (action != null) action.run(); } } /* * @see org.eclipse.swt.events.MouseMoveListener#mouseMove(org.eclipse.swt.events.MouseEvent) */ public void mouseMove(MouseEvent event) { if (event.widget instanceof Control && !((Control) event.widget).isFocusControl()) { deactivate(); return; } if (!fActive) { if (event.stateMask != fKeyModifierMask) return; // modifier was already pressed fActive= true; } ISourceViewer viewer= getSourceViewer(); if (viewer == null) { deactivate(); return; } StyledText text= viewer.getTextWidget(); if (text == null || text.isDisposed()) { deactivate(); return; } if ((event.stateMask & SWT.BUTTON1) != 0 && text.getSelectionCount() != 0) { deactivate(); return; } IRegion region= getCurrentTextRegion(viewer); if (region == null || region.getLength() == 0) { repairRepresentation(); return; } highlightRegion(viewer, region); activateCursor(viewer); } /* * @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent) */ public void focusGained(FocusEvent e) {} /* * @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent) */ public void focusLost(FocusEvent event) { deactivate(); } /* * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent) */ public void documentAboutToBeChanged(DocumentEvent event) { if (fActive && fActiveRegion != null) { fRememberedPosition= new Position(fActiveRegion.getOffset(), fActiveRegion.getLength()); try { event.getDocument().addPosition(fRememberedPosition); } catch (BadLocationException x) { fRememberedPosition= null; } } } /* * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent) */ public void documentChanged(DocumentEvent event) { if (fRememberedPosition != null) { if (!fRememberedPosition.isDeleted()) { event.getDocument().removePosition(fRememberedPosition); fActiveRegion= new Region(fRememberedPosition.getOffset(), fRememberedPosition.getLength()); fRememberedPosition= null; ISourceViewer viewer= getSourceViewer(); if (viewer != null) { StyledText widget= viewer.getTextWidget(); if (widget != null && !widget.isDisposed()) { widget.getDisplay().asyncExec(new Runnable() { public void run() { deactivate(); } }); } } } else { fActiveRegion= null; fRememberedPosition= null; deactivate(); } } } /* * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument) */ public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { if (oldInput == null) return; deactivate(); oldInput.removeDocumentListener(this); } /* * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument) */ public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { if (newInput == null) return; newInput.addDocumentListener(this); } /* * @see PaintListener#paintControl(PaintEvent) */ public void paintControl(PaintEvent event) { if (fActiveRegion == null) return; ISourceViewer viewer= getSourceViewer(); if (viewer == null) return; StyledText text= viewer.getTextWidget(); if (text == null || text.isDisposed()) return; int offset= 0; int length= 0; if (viewer instanceof ITextViewerExtension3) { ITextViewerExtension3 extension= (ITextViewerExtension3) viewer; IRegion widgetRange= extension.modelRange2WidgetRange(new Region(offset, length)); if (widgetRange == null) return; offset= widgetRange.getOffset(); length= widgetRange.getLength(); } else { IRegion region= viewer.getVisibleRegion(); if (!includes(region, fActiveRegion)) return; offset= fActiveRegion.getOffset() - region.getOffset(); length= fActiveRegion.getLength(); } // support for bidi Point minLocation= getMinimumLocation(text, offset, length); Point maxLocation= getMaximumLocation(text, offset, length); int x1= minLocation.x; int x2= minLocation.x + maxLocation.x - minLocation.x - 1; int y= minLocation.y + text.getLineHeight() - 1; GC gc= event.gc; if (fColor != null && !fColor.isDisposed()) gc.setForeground(fColor); gc.drawLine(x1, y, x2, y); } private boolean includes(IRegion region, IRegion position) { return position.getOffset() >= region.getOffset() && position.getOffset() + position.getLength() <= region.getOffset() + region.getLength(); } private Point getMinimumLocation(StyledText text, int offset, int length) { Point minLocation= new Point(Integer.MAX_VALUE, Integer.MAX_VALUE); for (int i= 0; i <= length; i++) { Point location= text.getLocationAtOffset(offset + i); if (location.x < minLocation.x) minLocation.x= location.x; if (location.y < minLocation.y) minLocation.y= location.y; } return minLocation; } private Point getMaximumLocation(StyledText text, int offset, int length) { Point maxLocation= new Point(Integer.MIN_VALUE, Integer.MIN_VALUE); for (int i= 0; i <= length; i++) { Point location= text.getLocationAtOffset(offset + i); if (location.x > maxLocation.x) maxLocation.x= location.x; if (location.y > maxLocation.y) maxLocation.y= location.y; } return maxLocation; } } /** * This action dispatches into two behaviours: If there is no current text * hover, the javadoc is displayed using information presenter. If there is * a current text hover, it is converted into a information presenter in * order to make it sticky. */ class InformationDispatchAction extends TextEditorAction { /** The wrapped text operation action. */ private final TextOperationAction fTextOperationAction; /** * Creates a dispatch action. */ public InformationDispatchAction(ResourceBundle resourceBundle, String prefix, final TextOperationAction textOperationAction) { super(resourceBundle, prefix, JavaEditor.this); if (textOperationAction == null) throw new IllegalArgumentException(); fTextOperationAction= textOperationAction; } /* * @see org.eclipse.jface.action.IAction#run() */ public void run() { /** * Information provider used to present the information. * * @since 3.0 */ class InformationProvider implements IInformationProvider, IInformationProviderExtension2 { private IRegion fHoverRegion; private String fHoverInfo; private IInformationControlCreator fControlCreator; InformationProvider(IRegion hoverRegion, String hoverInfo, IInformationControlCreator controlCreator) { fHoverRegion= hoverRegion; fHoverInfo= hoverInfo; fControlCreator= controlCreator; } /* * @see org.eclipse.jface.text.information.IInformationProvider#getSubject(org.eclipse.jface.text.ITextViewer, int) */ public IRegion getSubject(ITextViewer textViewer, int invocationOffset) { return fHoverRegion; } /* * @see org.eclipse.jface.text.information.IInformationProvider#getInformation(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion) */ public String getInformation(ITextViewer textViewer, IRegion subject) { return fHoverInfo; } /* * @see org.eclipse.jface.text.information.IInformationProviderExtension2#getInformationPresenterControlCreator() * @since 3.0 */ public IInformationControlCreator getInformationPresenterControlCreator() { return fControlCreator; } } ISourceViewer sourceViewer= getSourceViewer(); if (sourceViewer == null) { fTextOperationAction.run(); return; } if (sourceViewer instanceof ITextViewerExtension4) { ITextViewerExtension4 extension4= (ITextViewerExtension4) sourceViewer; if (extension4.moveFocusToWidgetToken()) return; } if (! (sourceViewer instanceof ITextViewerExtension2)) { fTextOperationAction.run(); return; } ITextViewerExtension2 textViewerExtension2= (ITextViewerExtension2) sourceViewer; // does a text hover exist? ITextHover textHover= textViewerExtension2.getCurrentTextHover(); if (textHover == null) { fTextOperationAction.run(); return; } Point hoverEventLocation= textViewerExtension2.getHoverEventLocation(); int offset= computeOffsetAtLocation(sourceViewer, hoverEventLocation.x, hoverEventLocation.y); if (offset == -1) { fTextOperationAction.run(); return; } try { // get the text hover content String contentType= TextUtilities.getContentType(sourceViewer.getDocument(), IJavaPartitions.JAVA_PARTITIONING, offset); IRegion hoverRegion= textHover.getHoverRegion(sourceViewer, offset); if (hoverRegion == null) return; String hoverInfo= textHover.getHoverInfo(sourceViewer, hoverRegion); IInformationControlCreator controlCreator= null; if (textHover instanceof IInformationProviderExtension2) controlCreator= ((IInformationProviderExtension2)textHover).getInformationPresenterControlCreator(); IInformationProvider informationProvider= new InformationProvider(hoverRegion, hoverInfo, controlCreator); fInformationPresenter.setOffset(offset); fInformationPresenter.setInformationProvider(informationProvider, contentType); fInformationPresenter.showInformation(); } catch (BadLocationException e) { } } // modified version from TextViewer private int computeOffsetAtLocation(ITextViewer textViewer, int x, int y) { StyledText styledText= textViewer.getTextWidget(); IDocument document= textViewer.getDocument(); if (document == null) return -1; try { int widgetLocation= styledText.getOffsetAtLocation(new Point(x, y)); if (textViewer instanceof ITextViewerExtension3) { ITextViewerExtension3 extension= (ITextViewerExtension3) textViewer; return extension.widgetOffset2ModelOffset(widgetLocation); } else { IRegion visibleRegion= textViewer.getVisibleRegion(); return widgetLocation + visibleRegion.getOffset(); } } catch (IllegalArgumentException e) { return -1; } } } static protected class AnnotationAccess extends DefaultMarkerAnnotationAccess { public AnnotationAccess(MarkerAnnotationPreferences markerAnnotationPreferences) { super(markerAnnotationPreferences); } /* * @see org.eclipse.jface.text.source.IAnnotationAccess#getType(org.eclipse.jface.text.source.Annotation) */ public Object getType(Annotation annotation) { if (annotation instanceof IJavaAnnotation) { IJavaAnnotation javaAnnotation= (IJavaAnnotation) annotation; if (javaAnnotation.isRelevant()) return javaAnnotation.getAnnotationType(); return null; } return super.getType(annotation); } /* * @see org.eclipse.jface.text.source.IAnnotationAccess#isMultiLine(org.eclipse.jface.text.source.Annotation) */ public boolean isMultiLine(Annotation annotation) { return true; } /* * @see org.eclipse.jface.text.source.IAnnotationAccess#isTemporary(org.eclipse.jface.text.source.Annotation) */ public boolean isTemporary(Annotation annotation) { if (annotation instanceof IJavaAnnotation) { IJavaAnnotation javaAnnotation= (IJavaAnnotation) annotation; if (javaAnnotation.isRelevant()) return javaAnnotation.isTemporary(); } return false; } } private class PropertyChangeListener implements org.eclipse.core.runtime.Preferences.IPropertyChangeListener { /* * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent) */ public void propertyChange(org.eclipse.core.runtime.Preferences.PropertyChangeEvent event) { handlePreferencePropertyChanged(event); } } /** * This action implements smart home. * * Instead of going to the start of a line it does the following: * * - if smart home/end is enabled and the caret is after the line's first non-whitespace then the caret is moved directly before it, taking JavaDoc and multi-line comments into account. * - if the caret is before the line's first non-whitespace the caret is moved to the beginning of the line * - if the caret is at the beginning of the line see first case. * * @since 3.0 */ protected class SmartLineStartAction extends LineStartAction { /** * Creates a new smart line start action * * @param textWidget the styled text widget * @param doSelect a boolean flag which tells if the text up to the beginning of the line should be selected */ public SmartLineStartAction(final StyledText textWidget, final boolean doSelect) { super(textWidget, doSelect); } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor.LineStartAction#getLineStartPosition(java.lang.String, int, java.lang.String) */ protected int getLineStartPosition(final IDocument document, final String line, final int length, final int offset) { String type= IDocument.DEFAULT_CONTENT_TYPE; try { type= TextUtilities.getPartition(document, IJavaPartitions.JAVA_PARTITIONING, offset).getType(); } catch (BadLocationException exception) { // Should not happen } int index= super.getLineStartPosition(document, line, length, offset); if (type.equals(IJavaPartitions.JAVA_DOC) || type.equals(IJavaPartitions.JAVA_MULTI_LINE_COMMENT)) { if (index < length - 1 && line.charAt(index) == '*' && line.charAt(index + 1) != '/') { do { ++index; } while (index < length && Character.isWhitespace(line.charAt(index))); } } else { if (index < length - 1 && line.charAt(index) == '/' && line.charAt(++index) == '/') { do { ++index; } while (index < length && Character.isWhitespace(line.charAt(index))); } } return index; } } /** * Text navigation action to navigate to the next sub-word. * * @since 3.0 */ protected abstract class NextSubWordAction extends TextNavigationAction { /** Collator to determine the sub-word boundaries */ private final RuleBasedCollator fCollator= (RuleBasedCollator)Collator.getInstance(); /** * Creates a new next sub-word action. * * @param code Action code for the default operation. Must be an action code from @see org.eclipse.swt.custom.ST. */ protected NextSubWordAction(int code) { super(getSourceViewer().getTextWidget(), code); // Only compare upper-/lower case fCollator.setStrength(Collator.TERTIARY); } /* * @see org.eclipse.jface.action.IAction#run() */ public void run() { try { final ISourceViewer viewer= getSourceViewer(); final IDocument document= viewer.getDocument(); int position= widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset()); // Check whether we are in a java code partititon and the preference is enabled final IPreferenceStore store= getPreferenceStore(); final ITypedRegion region= TextUtilities.getPartition(document, IJavaPartitions.JAVA_PARTITIONING, position); if (!store.getBoolean(PreferenceConstants.EDITOR_SUB_WORD_NAVIGATION)) { super.run(); return; } // Check whether right hand character of caret is valid identifier start if (Character.isJavaIdentifierStart(document.getChar(position))) { int offset= 0; int order= CollationElementIterator.NULLORDER; short previous= Short.MAX_VALUE; short next= Short.MAX_VALUE; // Acquire collator for partition around caret final String buffer= document.get(position, region.getOffset() + region.getLength() - position); final CollationElementIterator iterator= fCollator.getCollationElementIterator(buffer); // Iterate to first upper-case character do { // Check whether we reached end of word offset= iterator.getOffset(); if (!Character.isJavaIdentifierPart(document.getChar(position + offset))) throw new BadLocationException(); // Test next characters order= iterator.next(); next= CollationElementIterator.tertiaryOrder(order); if (next <= previous) previous= next; else break; } while (order != CollationElementIterator.NULLORDER); // Check for leading underscores position += offset; if (Character.getType(document.getChar(position - 1)) != Character.CONNECTOR_PUNCTUATION) { setCaretPosition(position); getTextWidget().showSelection(); fireSelectionChanged(); return; } } } catch (BadLocationException exception) { // Use default behavior } super.run(); } /** * Sets the caret position to the sub-word boundary given with <code>position</code>. * * @param position Position where the action should move the caret */ protected abstract void setCaretPosition(int position); } /** * Text navigation action to navigate to the next sub-word. * * @since 3.0 */ protected class NavigateNextSubWordAction extends NextSubWordAction { /** * Creates a new navigate next sub-word action. */ public NavigateNextSubWordAction() { super(ST.WORD_NEXT); } /* * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int) */ protected void setCaretPosition(final int position) { getTextWidget().setCaretOffset(modelOffset2WidgetOffset(getSourceViewer(), position)); } } /** * Text operation action to delete the next sub-word. * * @since 3.0 */ protected class DeleteNextSubWordAction extends NextSubWordAction { /** * Creates a new delete next sub-word action. */ public DeleteNextSubWordAction() { super(ST.DELETE_WORD_NEXT); } /* * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int) */ protected void setCaretPosition(final int position) { final ISourceViewer viewer= getSourceViewer(); final int caret= widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset()); try { viewer.getDocument().replace(caret, position - caret, ""); //$NON-NLS-1$ } catch (BadLocationException exception) { // Should not happen } } } /** * Text operation action to select the next sub-word. * * @since 3.0 */ protected class SelectNextSubWordAction extends NextSubWordAction { /** * Creates a new select next sub-word action. */ public SelectNextSubWordAction() { super(ST.SELECT_WORD_NEXT); } /* * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int) */ protected void setCaretPosition(final int position) { final ISourceViewer viewer= getSourceViewer(); final StyledText text= viewer.getTextWidget(); if (text != null && !text.isDisposed()) { final Point selection= text.getSelection(); final int caret= text.getCaretOffset(); final int offset= modelOffset2WidgetOffset(viewer, position); if (caret == selection.x) text.setSelectionRange(selection.y, offset - selection.y); else text.setSelectionRange(selection.x, offset - selection.x); } } } /** * Text navigation action to navigate to the previous sub-word. * * @since 3.0 */ protected abstract class PreviousSubWordAction extends TextNavigationAction { /** Collator to determine the sub-word boundaries */ private final RuleBasedCollator fCollator= (RuleBasedCollator)Collator.getInstance(); /** * Creates a new previous sub-word action. * * @param code Action code for the default operation. Must be an action code from @see org.eclipse.swt.custom.ST. */ protected PreviousSubWordAction(final int code) { super(getSourceViewer().getTextWidget(), code); // Only compare upper-/lower case fCollator.setStrength(Collator.TERTIARY); } /* * @see org.eclipse.jface.action.IAction#run() */ public void run() { try { final ISourceViewer viewer= getSourceViewer(); final IDocument document= viewer.getDocument(); int position= widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset()) - 1; // Check whether we are in a java code partititon and the preference is enabled final IPreferenceStore store= getPreferenceStore(); if (!store.getBoolean(PreferenceConstants.EDITOR_SUB_WORD_NAVIGATION)) { super.run(); return; } // Ignore trailing white spaces char character= document.getChar(position); while (position > 0 && Character.isWhitespace(character)) { --position; character= document.getChar(position); } // Check whether left hand character of caret is valid identifier part if (Character.isJavaIdentifierPart(character)) { int offset= 0; int order= CollationElementIterator.NULLORDER; short previous= Short.MAX_VALUE; short next= Short.MAX_VALUE; // Acquire collator for partition around caret final ITypedRegion region= TextUtilities.getPartition(document, IJavaPartitions.JAVA_PARTITIONING, position); final String buffer= document.get(region.getOffset(), position - region.getOffset() + 1); final CollationElementIterator iterator= fCollator.getCollationElementIterator(buffer); // Iterate to first upper-case character iterator.setOffset(buffer.length() - 1); do { // Check whether we reached begin of word or single upper-case start offset= iterator.getOffset(); character= document.getChar(region.getOffset() + offset); if (!Character.isJavaIdentifierPart(character)) throw new BadLocationException(); else if (Character.isUpperCase(character)) { ++offset; break; } // Test next characters order= iterator.previous(); next= CollationElementIterator.tertiaryOrder(order); if (next <= previous) previous= next; else break; } while (order != CollationElementIterator.NULLORDER); // Check left character for multiple upper-case characters position= position - buffer.length() + offset - 1; character= document.getChar(position); while (position >= 0 && Character.isUpperCase(character)) character= document.getChar(--position); setCaretPosition(position + 1); getTextWidget().showSelection(); fireSelectionChanged(); return; } } catch (BadLocationException exception) { // Use default behavior } super.run(); } /** * Sets the caret position to the sub-word boundary given with <code>position</code>. * * @param position Position where the action should move the caret */ protected abstract void setCaretPosition(int position); } /** * Text navigation action to navigate to the previous sub-word. * * @since 3.0 */ protected class NavigatePreviousSubWordAction extends PreviousSubWordAction { /** * Creates a new navigate previous sub-word action. */ public NavigatePreviousSubWordAction() { super(ST.WORD_PREVIOUS); } /* * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int) */ protected void setCaretPosition(final int position) { getTextWidget().setCaretOffset(modelOffset2WidgetOffset(getSourceViewer(), position)); } } /** * Text operation action to delete the previous sub-word. * * @since 3.0 */ protected class DeletePreviousSubWordAction extends PreviousSubWordAction { /** * Creates a new delete previous sub-word action. */ public DeletePreviousSubWordAction() { super(ST.DELETE_WORD_PREVIOUS); } /* * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int) */ protected void setCaretPosition(final int position) { final ISourceViewer viewer= getSourceViewer(); final int caret= widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset()); try { viewer.getDocument().replace(position, caret - position, ""); //$NON-NLS-1$ } catch (BadLocationException exception) { // Should not happen } } } /** * Text operation action to select the previous sub-word. * * @since 3.0 */ protected class SelectPreviousSubWordAction extends PreviousSubWordAction { /** * Creates a new select previous sub-word action. */ public SelectPreviousSubWordAction() { super(ST.SELECT_WORD_PREVIOUS); } /* * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int) */ protected void setCaretPosition(final int position) { final ISourceViewer viewer= getSourceViewer(); final StyledText text= viewer.getTextWidget(); if (text != null && !text.isDisposed()) { final Point selection= text.getSelection(); final int caret= text.getCaretOffset(); final int offset= modelOffset2WidgetOffset(viewer, position); if (caret == selection.x) text.setSelectionRange(selection.y, offset - selection.y); else text.setSelectionRange(selection.x, offset - selection.x); } } } /** * Quick format action to format the enclosing java element. * <p> * The quick format action works as follows: * <ul> * <li>If there is no selection and the caret is positioned on a Java element, * only this element is formatted. If the element has some accompanying comment, * then the comment is formatted as well.</li> * <li>If the selection spans one or more partitions of the document, then all * partitions covered by the selection are entirely formatted.</li> * <p> * Partitions at the end of the selection are not completed, except for comments. * * @since 3.0 */ protected class QuickFormatAction extends Action { /* * @see org.eclipse.jface.action.IAction#run() */ public void run() { final JavaSourceViewer viewer= (JavaSourceViewer) getSourceViewer(); if (viewer.isEditable()) { final Point selection= viewer.rememberSelection(); try { viewer.setRedraw(false); final String type= TextUtilities.getContentType(viewer.getDocument(), IJavaPartitions.JAVA_PARTITIONING, selection.x); if (type.equals(IDocument.DEFAULT_CONTENT_TYPE) && selection.y == 0) { try { final IJavaElement element= getElementAt(selection.x, true); if (element != null && element.exists()) { final int kind= element.getElementType(); if (kind == IJavaElement.TYPE || kind == IJavaElement.METHOD || kind == IJavaElement.INITIALIZER) { final ISourceReference reference= (ISourceReference)element; final ISourceRange range= reference.getSourceRange(); if (range != null) { viewer.setSelectedRange(range.getOffset(), range.getLength()); viewer.doOperation(ISourceViewer.FORMAT); } } } } catch (JavaModelException exception) { // Should not happen } } else { viewer.setSelectedRange(selection.x, 1); viewer.doOperation(ISourceViewer.FORMAT); } } catch (BadLocationException exception) { // Can not happen } finally { viewer.setRedraw(true); viewer.restoreSelection(); } } } } /** Preference key for the link color */ protected final static String LINK_COLOR= PreferenceConstants.EDITOR_LINK_COLOR; /** Preference key for matching brackets */ protected final static String MATCHING_BRACKETS= PreferenceConstants.EDITOR_MATCHING_BRACKETS; /** Preference key for matching brackets color */ protected final static String MATCHING_BRACKETS_COLOR= PreferenceConstants.EDITOR_MATCHING_BRACKETS_COLOR; /** Preference key for compiler task tags */ private final static String COMPILER_TASK_TAGS= JavaCore.COMPILER_TASK_TAGS; /** Preference key for browser like links */ private final static String BROWSER_LIKE_LINKS= PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS; /** Preference key for key modifier of browser like links */ private final static String BROWSER_LIKE_LINKS_KEY_MODIFIER= PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS_KEY_MODIFIER; /** * Preference key for key modifier mask of browser like links. * The value is only used if the value of <code>EDITOR_BROWSER_LIKE_LINKS</code> * cannot be resolved to valid SWT modifier bits. * * @since 2.1.1 */ private final static String BROWSER_LIKE_LINKS_KEY_MODIFIER_MASK= PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS_KEY_MODIFIER_MASK; protected final static char[] BRACKETS= { '{', '}', '(', ')', '[', ']' }; /** The outline page */ protected JavaOutlinePage fOutlinePage; /** Outliner context menu Id */ protected String fOutlinerContextMenuId; /** * The editor selection changed listener. * * @since 3.0 */ private EditorSelectionChangedListener fEditorSelectionChangedListener; /** The selection changed listener */ protected AbstractSelectionChangedListener fOutlineSelectionChangedListener= new OutlineSelectionChangedListener(); /** The editor's bracket matcher */ protected JavaPairMatcher fBracketMatcher= new JavaPairMatcher(BRACKETS); /** This editor's encoding support */ private DefaultEncodingSupport fEncodingSupport; /** The mouse listener */ private MouseClickListener fMouseListener; /** The information presenter. */ private InformationPresenter fInformationPresenter; /** History for structure select action */ private SelectionHistory fSelectionHistory; /** The preference property change listener for java core. */ private org.eclipse.core.runtime.Preferences.IPropertyChangeListener fPropertyChangeListener= new PropertyChangeListener(); /** * Indicates whether this editor is about to update any annotation views. * @since 3.0 */ private boolean fIsUpdatingAnnotationViews= false; /** * The marker that served as last target for a goto marker request. * @since 3.0 */ private IMarker fLastMarkerTarget= null; protected CompositeActionGroup fActionGroups; private CompositeActionGroup fContextMenuGroup; /** * Holds the current occurrence annotations. * @since 3.0 */ private ArrayList fOccurrenceAnnotations= new ArrayList(); /** * Counts the number of background computation requests. * @since 3.0 */ private volatile int fComputeCount; private boolean fMarkOccurrenceAnnotations; /** * Returns the most narrow java element including the given offset. * * @param offset the offset inside of the requested element * @return the most narrow java element */ abstract protected IJavaElement getElementAt(int offset); /** * Returns the java element of this editor's input corresponding to the given IJavaElement */ abstract protected IJavaElement getCorrespondingElement(IJavaElement element); /** * Sets the input of the editor's outline page. */ abstract protected void setOutlinePageInput(JavaOutlinePage page, IEditorInput input); /** * Default constructor. */ public JavaEditor() { super(); JavaTextTools textTools= JavaPlugin.getDefault().getJavaTextTools(); setSourceViewerConfiguration(new JavaSourceViewerConfiguration(textTools, this, IJavaPartitions.JAVA_PARTITIONING)); setRangeIndicator(new DefaultRangeIndicator()); IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore(); setPreferenceStore(store); setKeyBindingScopes(new String[] { "org.eclipse.jdt.ui.javaEditorScope" }); //$NON-NLS-1$ fMarkOccurrenceAnnotations= store.getBoolean(PreferenceConstants.EDITOR_MARK_OCCURRENCES); } /* * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int) */ protected final ISourceViewer createSourceViewer(Composite parent, IVerticalRuler verticalRuler, int styles) { ISourceViewer viewer= createJavaSourceViewer(parent, verticalRuler, getOverviewRuler(), isOverviewRulerVisible(), styles); StyledText text= viewer.getTextWidget(); text.addBidiSegmentListener(new BidiSegmentListener() { public void lineGetSegments(BidiSegmentEvent event) { event.segments= getBidiLineSegments(event.lineOffset, event.lineText); } }); JavaUIHelp.setHelp(this, text, IJavaHelpContextIds.JAVA_EDITOR); // ensure source viewer decoration support has been created and configured getSourceViewerDecorationSupport(viewer); return viewer; } /* * @see org.eclipse.ui.texteditor.ExtendedTextEditor#createAnnotationAccess() */ protected IAnnotationAccess createAnnotationAccess() { return new AnnotationAccess(new MarkerAnnotationPreferences()); } public final ISourceViewer getViewer() { return getSourceViewer(); } /* * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int) */ protected ISourceViewer createJavaSourceViewer(Composite parent, IVerticalRuler verticalRuler, IOverviewRuler overviewRuler, boolean isOverviewRulerVisible, int styles) { return new JavaSourceViewer(parent, verticalRuler, getOverviewRuler(), isOverviewRulerVisible(), styles); } /* * @see AbstractTextEditor#affectsTextPresentation(PropertyChangeEvent) */ protected boolean affectsTextPresentation(PropertyChangeEvent event) { JavaTextTools textTools= JavaPlugin.getDefault().getJavaTextTools(); return textTools.affectsBehavior(event); } /** * Sets the outliner's context menu ID. */ protected void setOutlinerContextMenuId(String menuId) { fOutlinerContextMenuId= menuId; } /** * Returns the standard action group of this editor. */ protected ActionGroup getActionGroup() { return fActionGroups; } /* * @see AbstractTextEditor#editorContextMenuAboutToShow */ public void editorContextMenuAboutToShow(IMenuManager menu) { super.editorContextMenuAboutToShow(menu); menu.appendToGroup(ITextEditorActionConstants.GROUP_UNDO, new Separator(IContextMenuConstants.GROUP_OPEN)); menu.insertAfter(IContextMenuConstants.GROUP_OPEN, new GroupMarker(IContextMenuConstants.GROUP_SHOW)); ActionContext context= new ActionContext(getSelectionProvider().getSelection()); fContextMenuGroup.setContext(context); fContextMenuGroup.fillContextMenu(menu); fContextMenuGroup.setContext(null); } /** * Creates the outline page used with this editor. */ protected JavaOutlinePage createOutlinePage() { JavaOutlinePage page= new JavaOutlinePage(fOutlinerContextMenuId, this); fOutlineSelectionChangedListener.install(page); setOutlinePageInput(page, getEditorInput()); return page; } /** * Informs the editor that its outliner has been closed. */ public void outlinePageClosed() { if (fOutlinePage != null) { fOutlineSelectionChangedListener.uninstall(fOutlinePage); fOutlinePage= null; resetHighlightRange(); } } /** * Synchronizes the outliner selection with the given element * position in the editor. * * @param element the java element to select */ protected void synchronizeOutlinePage(ISourceReference element) { synchronizeOutlinePage(element, true); } /** * Synchronizes the outliner selection with the given element * position in the editor. * * @param element the java element to select * @param checkIfOutlinePageActive <code>true</code> if check for active outline page needs to be done */ protected void synchronizeOutlinePage(ISourceReference element, boolean checkIfOutlinePageActive) { if (fOutlinePage != null && element != null && !(checkIfOutlinePageActive && isJavaOutlinePageActive())) { fOutlineSelectionChangedListener.uninstall(fOutlinePage); fOutlinePage.select(element); fOutlineSelectionChangedListener.install(fOutlinePage); } } /** * Synchronizes the outliner selection with the actual cursor * position in the editor. */ public void synchronizeOutlinePageSelection() { synchronizeOutlinePage(computeHighlightRangeSourceReference()); } /* * Get the desktop's StatusLineManager */ protected IStatusLineManager getStatusLineManager() { IEditorActionBarContributor contributor= getEditorSite().getActionBarContributor(); if (contributor instanceof EditorActionBarContributor) { return ((EditorActionBarContributor) contributor).getActionBars().getStatusLineManager(); } return null; } /* * @see AbstractTextEditor#getAdapter(Class) */ public Object getAdapter(Class required) { if (IContentOutlinePage.class.equals(required)) { if (fOutlinePage == null) fOutlinePage= createOutlinePage(); return fOutlinePage; } if (IEncodingSupport.class.equals(required)) return fEncodingSupport; if (required == IShowInTargetList.class) { return new IShowInTargetList() { public String[] getShowInTargetIds() { return new String[] { JavaUI.ID_PACKAGES, IPageLayout.ID_OUTLINE, IPageLayout.ID_RES_NAV }; } }; } return super.getAdapter(required); } protected void setSelection(ISourceReference reference, boolean moveCursor) { ISelection selection= getSelectionProvider().getSelection(); if (selection instanceof TextSelection) { TextSelection textSelection= (TextSelection) selection; // PR 39995: [navigation] Forward history cleared after going back in navigation history: // mark only in navigation history if the cursor is being moved (which it isn't if // this is called from a PostSelectionEvent that should only update the magnet) if (moveCursor && (textSelection.getOffset() != 0 || textSelection.getLength() != 0)) markInNavigationHistory(); } if (reference != null) { StyledText textWidget= null; ISourceViewer sourceViewer= getSourceViewer(); if (sourceViewer != null) textWidget= sourceViewer.getTextWidget(); if (textWidget == null) return; try { ISourceRange range= reference.getSourceRange(); if (range == null) return; int offset= range.getOffset(); int length= range.getLength(); if (offset < 0 || length < 0) return; setHighlightRange(offset, length, moveCursor); if (!moveCursor) return; offset= -1; length= -1; if (reference instanceof IMember) { range= ((IMember) reference).getNameRange(); if (range != null) { offset= range.getOffset(); length= range.getLength(); } } else if (reference instanceof IImportDeclaration) { String name= ((IImportDeclaration) reference).getElementName(); if (name != null && name.length() > 0) { String content= reference.getSource(); if (content != null) { offset= range.getOffset() + content.indexOf(name); length= name.length(); } } } else if (reference instanceof IPackageDeclaration) { String name= ((IPackageDeclaration) reference).getElementName(); if (name != null && name.length() > 0) { String content= reference.getSource(); if (content != null) { offset= range.getOffset() + content.indexOf(name); length= name.length(); } } } if (offset > -1 && length > 0) { try { textWidget.setRedraw(false); sourceViewer.revealRange(offset, length); sourceViewer.setSelectedRange(offset, length); } finally { textWidget.setRedraw(true); } markInNavigationHistory(); } } catch (JavaModelException x) { } catch (IllegalArgumentException x) { } } else if (moveCursor) { resetHighlightRange(); markInNavigationHistory(); } } public void setSelection(IJavaElement element) { if (element == null || element instanceof ICompilationUnit || element instanceof IClassFile) { /* * If the element is an ICompilationUnit this unit is either the input * of this editor or not being displayed. In both cases, nothing should * happened. (http://dev.eclipse.org/bugs/show_bug.cgi?id=5128) */ return; } IJavaElement corresponding= getCorrespondingElement(element); if (corresponding instanceof ISourceReference) { ISourceReference reference= (ISourceReference) corresponding; // set hightlight range setSelection(reference, true); // set outliner selection if (fOutlinePage != null) { fOutlineSelectionChangedListener.uninstall(fOutlinePage); fOutlinePage.select(reference); fOutlineSelectionChangedListener.install(fOutlinePage); } } } protected void doSelectionChanged(SelectionChangedEvent event) { ISourceReference reference= null; ISelection selection= event.getSelection(); Iterator iter= ((IStructuredSelection) selection).iterator(); while (iter.hasNext()) { Object o= iter.next(); if (o instanceof ISourceReference) { reference= (ISourceReference) o; break; } } if (!isActivePart() && JavaPlugin.getActivePage() != null) JavaPlugin.getActivePage().bringToTop(this); setSelection(reference, !isActivePart()); } /* * @see AbstractTextEditor#adjustHighlightRange(int, int) */ protected void adjustHighlightRange(int offset, int length) { try { IJavaElement element= getElementAt(offset); while (element instanceof ISourceReference) { ISourceRange range= ((ISourceReference) element).getSourceRange(); if (offset < range.getOffset() + range.getLength() && range.getOffset() < offset + length) { setHighlightRange(range.getOffset(), range.getLength(), true); if (fOutlinePage != null) { fOutlineSelectionChangedListener.uninstall(fOutlinePage); fOutlinePage.select((ISourceReference) element); fOutlineSelectionChangedListener.install(fOutlinePage); } return; } element= element.getParent(); } } catch (JavaModelException x) { JavaPlugin.log(x.getStatus()); } resetHighlightRange(); } protected boolean isActivePart() { IWorkbenchPart part= getActivePart(); return part != null && part.equals(this); } private boolean isJavaOutlinePageActive() { IWorkbenchPart part= getActivePart(); return part instanceof ContentOutline && ((ContentOutline)part).getCurrentPage() == fOutlinePage; } private IWorkbenchPart getActivePart() { IWorkbenchWindow window= getSite().getWorkbenchWindow(); IPartService service= window.getPartService(); IWorkbenchPart part= service.getActivePart(); return part; } /* * @see StatusTextEditor#getStatusHeader(IStatus) */ protected String getStatusHeader(IStatus status) { if (fEncodingSupport != null) { String message= fEncodingSupport.getStatusHeader(status); if (message != null) return message; } return super.getStatusHeader(status); } /* * @see StatusTextEditor#getStatusBanner(IStatus) */ protected String getStatusBanner(IStatus status) { if (fEncodingSupport != null) { String message= fEncodingSupport.getStatusBanner(status); if (message != null) return message; } return super.getStatusBanner(status); } /* * @see StatusTextEditor#getStatusMessage(IStatus) */ protected String getStatusMessage(IStatus status) { if (fEncodingSupport != null) { String message= fEncodingSupport.getStatusMessage(status); if (message != null) return message; } return super.getStatusMessage(status); } /* * @see AbstractTextEditor#doSetInput */ protected void doSetInput(IEditorInput input) throws CoreException { super.doSetInput(input); if (fEncodingSupport != null) fEncodingSupport.reset(); setOutlinePageInput(fOutlinePage, input); } /* * @see IWorkbenchPart#dispose() */ public void dispose() { // cancel possible running computation fMarkOccurrenceAnnotations= false; fComputeCount++; if (isBrowserLikeLinks()) disableBrowserLikeLinks(); if (fEncodingSupport != null) { fEncodingSupport.dispose(); fEncodingSupport= null; } if (fPropertyChangeListener != null) { Preferences preferences= JavaCore.getPlugin().getPluginPreferences(); preferences.removePropertyChangeListener(fPropertyChangeListener); fPropertyChangeListener= null; } if (fBracketMatcher != null) { fBracketMatcher.dispose(); fBracketMatcher= null; } if (fSelectionHistory != null) { fSelectionHistory.dispose(); fSelectionHistory= null; } if (fEditorSelectionChangedListener != null) { fEditorSelectionChangedListener.uninstall(getSelectionProvider()); fEditorSelectionChangedListener= null; } super.dispose(); } protected void createActions() { super.createActions(); ResourceAction resAction= new AddTaskAction(JavaEditorMessages.getResourceBundle(), "AddTask.", this); //$NON-NLS-1$ resAction.setHelpContextId(IAbstractTextEditorHelpContextIds.ADD_TASK_ACTION); resAction.setActionDefinitionId(ITextEditorActionDefinitionIds.ADD_TASK); setAction(ITextEditorActionConstants.ADD_TASK, resAction); ActionGroup oeg, ovg, jsg, sg; fActionGroups= new CompositeActionGroup(new ActionGroup[] { oeg= new OpenEditorActionGroup(this), sg= new ShowActionGroup(this), ovg= new OpenViewActionGroup(this), jsg= new JavaSearchActionGroup(this) }); fContextMenuGroup= new CompositeActionGroup(new ActionGroup[] {oeg, ovg, sg, jsg}); resAction= new TextOperationAction(JavaEditorMessages.getResourceBundle(), "ShowJavaDoc.", this, ISourceViewer.INFORMATION, true); //$NON-NLS-1$ resAction= new InformationDispatchAction(JavaEditorMessages.getResourceBundle(), "ShowJavaDoc.", (TextOperationAction) resAction); //$NON-NLS-1$ resAction.setActionDefinitionId(IJavaEditorActionDefinitionIds.SHOW_JAVADOC); setAction("ShowJavaDoc", resAction); //$NON-NLS-1$ PlatformUI.getWorkbench().getHelpSystem().setHelp(resAction, IJavaHelpContextIds.SHOW_JAVADOC_ACTION); Action action= new GotoMatchingBracketAction(this); action.setActionDefinitionId(IJavaEditorActionDefinitionIds.GOTO_MATCHING_BRACKET); setAction(GotoMatchingBracketAction.GOTO_MATCHING_BRACKET, action); action= new TextOperationAction(JavaEditorMessages.getResourceBundle(),"ShowOutline.", this, JavaSourceViewer.SHOW_OUTLINE, true); //$NON-NLS-1$ action.setActionDefinitionId(IJavaEditorActionDefinitionIds.SHOW_OUTLINE); setAction(IJavaEditorActionDefinitionIds.SHOW_OUTLINE, action); PlatformUI.getWorkbench().getHelpSystem().setHelp(action, IJavaHelpContextIds.SHOW_OUTLINE_ACTION); action= new TextOperationAction(JavaEditorMessages.getResourceBundle(),"OpenStructure.", this, JavaSourceViewer.OPEN_STRUCTURE, true); //$NON-NLS-1$ action.setActionDefinitionId(IJavaEditorActionDefinitionIds.OPEN_STRUCTURE); setAction(IJavaEditorActionDefinitionIds.OPEN_STRUCTURE, action); PlatformUI.getWorkbench().getHelpSystem().setHelp(action, IJavaHelpContextIds.OPEN_STRUCTURE_ACTION); action= new TextOperationAction(JavaEditorMessages.getResourceBundle(),"OpenHierarchy.", this, JavaSourceViewer.SHOW_HIERARCHY, true); //$NON-NLS-1$ action.setActionDefinitionId(IJavaEditorActionDefinitionIds.OPEN_HIERARCHY); setAction(IJavaEditorActionDefinitionIds.OPEN_HIERARCHY, action); PlatformUI.getWorkbench().getHelpSystem().setHelp(action, IJavaHelpContextIds.OPEN_HIERARCHY_ACTION); fEncodingSupport= new DefaultEncodingSupport(); fEncodingSupport.initialize(this); fSelectionHistory= new SelectionHistory(this); action= new StructureSelectEnclosingAction(this, fSelectionHistory); action.setActionDefinitionId(IJavaEditorActionDefinitionIds.SELECT_ENCLOSING); setAction(StructureSelectionAction.ENCLOSING, action); action= new StructureSelectNextAction(this, fSelectionHistory); action.setActionDefinitionId(IJavaEditorActionDefinitionIds.SELECT_NEXT); setAction(StructureSelectionAction.NEXT, action); action= new StructureSelectPreviousAction(this, fSelectionHistory); action.setActionDefinitionId(IJavaEditorActionDefinitionIds.SELECT_PREVIOUS); setAction(StructureSelectionAction.PREVIOUS, action); StructureSelectHistoryAction historyAction= new StructureSelectHistoryAction(this, fSelectionHistory); historyAction.setActionDefinitionId(IJavaEditorActionDefinitionIds.SELECT_LAST); setAction(StructureSelectionAction.HISTORY, historyAction); fSelectionHistory.setHistoryAction(historyAction); action= GoToNextPreviousMemberAction.newGoToNextMemberAction(this); action.setActionDefinitionId(IJavaEditorActionDefinitionIds.GOTO_NEXT_MEMBER); setAction(GoToNextPreviousMemberAction.NEXT_MEMBER, action); action= GoToNextPreviousMemberAction.newGoToPreviousMemberAction(this); action.setActionDefinitionId(IJavaEditorActionDefinitionIds.GOTO_PREVIOUS_MEMBER); setAction(GoToNextPreviousMemberAction.PREVIOUS_MEMBER, action); action= new QuickFormatAction(); action.setActionDefinitionId(IJavaEditorActionDefinitionIds.QUICK_FORMAT); setAction(IJavaEditorActionDefinitionIds.QUICK_FORMAT, action); action= new RemoveOccurrenceAnnotations(this); action.setActionDefinitionId(IJavaEditorActionDefinitionIds.REMOVE_OCCURRENCE_ANNOTATIONS); setAction("RemoveOccurrenceAnnotations", action); //$NON-NLS-1$ } public void updatedTitleImage(Image image) { setTitleImage(image); } /* * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent) */ protected void handlePreferenceStoreChanged(PropertyChangeEvent event) { try { ISourceViewer sourceViewer= getSourceViewer(); if (sourceViewer == null) return; String property= event.getProperty(); if (PreferenceConstants.EDITOR_TAB_WIDTH.equals(property)) { Object value= event.getNewValue(); if (value instanceof Integer) { sourceViewer.getTextWidget().setTabs(((Integer) value).intValue()); } else if (value instanceof String) { sourceViewer.getTextWidget().setTabs(Integer.parseInt((String) value)); } return; } if (isJavaEditorHoverProperty(property)) updateHoverBehavior(); if (BROWSER_LIKE_LINKS.equals(property)) { if (isBrowserLikeLinks()) enableBrowserLikeLinks(); else disableBrowserLikeLinks(); return; } if (PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE.equals(property)) { if ((event.getNewValue() instanceof Boolean) && ((Boolean)event.getNewValue()).booleanValue()) { fEditorSelectionChangedListener= new EditorSelectionChangedListener(); fEditorSelectionChangedListener.install(getSelectionProvider()); fEditorSelectionChangedListener.selectionChanged(); } else { fEditorSelectionChangedListener.uninstall(getSelectionProvider()); fEditorSelectionChangedListener= null; } return; } if (PreferenceConstants.EDITOR_DISABLE_OVERWRITE_MODE.equals(property)) { if (event.getNewValue() instanceof Boolean) { Boolean disable= (Boolean) event.getNewValue(); configureInsertMode(OVERWRITE, !disable.booleanValue()); } } if (PreferenceConstants.EDITOR_MARK_OCCURRENCES.equals(property)) { if (event.getNewValue() instanceof Boolean) { fMarkOccurrenceAnnotations= ((Boolean)event.getNewValue()).booleanValue(); if (!fMarkOccurrenceAnnotations) { fComputeCount++; removeOccurrenceAnnotations(); } } } } finally { super.handlePreferenceStoreChanged(event); } } /** * Initializes the given viewer's colors. * * @param viewer the viewer to be initialized * @since 3.0 */ protected void initializeViewerColors(ISourceViewer viewer) { // is handled by JavaSourceViewer } private boolean isJavaEditorHoverProperty(String property) { return PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS.equals(property); } /** * Return whether the browser like links should be enabled * according to the preference store settings. * @return <code>true</code> if the browser like links should be enabled */ private boolean isBrowserLikeLinks() { IPreferenceStore store= getPreferenceStore(); return store.getBoolean(BROWSER_LIKE_LINKS); } /** * Enables browser like links. */ private void enableBrowserLikeLinks() { if (fMouseListener == null) { fMouseListener= new MouseClickListener(); fMouseListener.install(); } } /** * Disables browser like links. */ private void disableBrowserLikeLinks() { if (fMouseListener != null) { fMouseListener.uninstall(); fMouseListener= null; } } /** * Handles a property change event describing a change * of the java core's preferences and updates the preference * related editor properties. * * @param event the property change event */ protected void handlePreferencePropertyChanged(org.eclipse.core.runtime.Preferences.PropertyChangeEvent event) { if (COMPILER_TASK_TAGS.equals(event.getProperty())) { ISourceViewer sourceViewer= getSourceViewer(); if (sourceViewer != null && affectsTextPresentation(new PropertyChangeEvent(event.getSource(), event.getProperty(), event.getOldValue(), event.getNewValue()))) sourceViewer.invalidateTextPresentation(); } } /** * Returns a segmentation of the line of the given viewer's input document appropriate for * bidi rendering. The default implementation returns only the string literals of a java code * line as segments. * * @param viewer the text viewer * @param lineOffset the offset of the line * @return the line's bidi segmentation * @throws BadLocationException in case lineOffset is not valid in document */ public static int[] getBidiLineSegments(ITextViewer viewer, int lineOffset) throws BadLocationException { IDocument document= viewer.getDocument(); if (document == null) return null; IRegion line= document.getLineInformationOfOffset(lineOffset); ITypedRegion[] linePartitioning= TextUtilities.computePartitioning(document, IJavaPartitions.JAVA_PARTITIONING, lineOffset, line.getLength()); List segmentation= new ArrayList(); for (int i= 0; i < linePartitioning.length; i++) { if (IJavaPartitions.JAVA_STRING.equals(linePartitioning[i].getType())) segmentation.add(linePartitioning[i]); } if (segmentation.size() == 0) return null; int size= segmentation.size(); int[] segments= new int[size * 2 + 1]; int j= 0; for (int i= 0; i < size; i++) { ITypedRegion segment= (ITypedRegion) segmentation.get(i); if (i == 0) segments[j++]= 0; int offset= segment.getOffset() - lineOffset; if (offset > segments[j - 1]) segments[j++]= offset; if (offset + segment.getLength() >= line.getLength()) break; segments[j++]= offset + segment.getLength(); } if (j < segments.length) { int[] result= new int[j]; System.arraycopy(segments, 0, result, 0, j); segments= result; } return segments; } /** * Returns a segmentation of the given line appropriate for bidi rendering. The default * implementation returns only the string literals of a java code line as segments. * * @param lineOffset the offset of the line * @param line the content of the line * @return the line's bidi segmentation */ protected int[] getBidiLineSegments(int widgetLineOffset, String line) { if (line != null && line.length() > 0) { ISourceViewer sourceViewer= getSourceViewer(); if (sourceViewer != null) { int lineOffset; if (sourceViewer instanceof ITextViewerExtension3) { ITextViewerExtension3 extension= (ITextViewerExtension3) sourceViewer; lineOffset= extension.widgetOffset2ModelOffset(widgetLineOffset); } else { IRegion visible= sourceViewer.getVisibleRegion(); lineOffset= visible.getOffset() + widgetLineOffset; } try { return getBidiLineSegments(sourceViewer, lineOffset); } catch (BadLocationException x) { // don't segment line in this case } } } return null; } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#updatePropertyDependentActions() */ protected void updatePropertyDependentActions() { super.updatePropertyDependentActions(); if (fEncodingSupport != null) fEncodingSupport.reset(); } /* * Update the hovering behavior depending on the preferences. */ private void updateHoverBehavior() { SourceViewerConfiguration configuration= getSourceViewerConfiguration(); String[] types= configuration.getConfiguredContentTypes(getSourceViewer()); for (int i= 0; i < types.length; i++) { String t= types[i]; ISourceViewer sourceViewer= getSourceViewer(); if (sourceViewer instanceof ITextViewerExtension2) { // Remove existing hovers ((ITextViewerExtension2)sourceViewer).removeTextHovers(t); int[] stateMasks= configuration.getConfiguredTextHoverStateMasks(getSourceViewer(), t); if (stateMasks != null) { for (int j= 0; j < stateMasks.length; j++) { int stateMask= stateMasks[j]; ITextHover textHover= configuration.getTextHover(sourceViewer, t, stateMask); ((ITextViewerExtension2)sourceViewer).setTextHover(textHover, t, stateMask); } } else { ITextHover textHover= configuration.getTextHover(sourceViewer, t); ((ITextViewerExtension2)sourceViewer).setTextHover(textHover, t, ITextViewerExtension2.DEFAULT_HOVER_STATE_MASK); } } else sourceViewer.setTextHover(configuration.getTextHover(sourceViewer, t), t); } } /* * @see org.eclipse.jdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput() */ public Object getViewPartInput() { return getEditorInput().getAdapter(IJavaElement.class); } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#doSetSelection(ISelection) */ protected void doSetSelection(ISelection selection) { super.doSetSelection(selection); synchronizeOutlinePageSelection(); } /* * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite) */ public void createPartControl(Composite parent) { super.createPartControl(parent); Preferences preferences= JavaCore.getPlugin().getPluginPreferences(); preferences.addPropertyChangeListener(fPropertyChangeListener); IInformationControlCreator informationControlCreator= new IInformationControlCreator() { public IInformationControl createInformationControl(Shell shell) { boolean cutDown= false; int style= cutDown ? SWT.NONE : (SWT.V_SCROLL | SWT.H_SCROLL); return new DefaultInformationControl(shell, SWT.RESIZE, style, new HTMLTextPresenter(cutDown)); } }; fInformationPresenter= new InformationPresenter(informationControlCreator); fInformationPresenter.setSizeConstraints(60, 10, true, true); fInformationPresenter.install(getSourceViewer()); if (PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE)) { fEditorSelectionChangedListener= new EditorSelectionChangedListener(); fEditorSelectionChangedListener.install(getSelectionProvider()); } if (isBrowserLikeLinks()) enableBrowserLikeLinks(); if (PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_DISABLE_OVERWRITE_MODE)) configureInsertMode(OVERWRITE, false); } protected void configureSourceViewerDecorationSupport(SourceViewerDecorationSupport support) { support.setCharacterPairMatcher(fBracketMatcher); support.setMatchingCharacterPainterPreferenceKeys(MATCHING_BRACKETS, MATCHING_BRACKETS_COLOR); super.configureSourceViewerDecorationSupport(support); } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#gotoMarker(org.eclipse.core.resources.IMarker) */ public void gotoMarker(IMarker marker) { fLastMarkerTarget= marker; if (!fIsUpdatingAnnotationViews) super.gotoMarker(marker); } /** * Jumps to the next enabled annotation according to the given direction. * An annotation type is enabled if it is configured to be in the * Next/Previous tool bar drop down menu and if it is checked. * * @param forward <code>true</code> if search direction is forward, <code>false</code> if backward */ public void gotoAnnotation(boolean forward) { ITextSelection selection= (ITextSelection) getSelectionProvider().getSelection(); Position position= new Position(0, 0); if (false /* delayed - see bug 18316 */) { getNextAnnotation(selection.getOffset(), selection.getLength(), forward, position); selectAndReveal(position.getOffset(), position.getLength()); } else /* no delay - see bug 18316 */ { Annotation annotation= getNextAnnotation(selection.getOffset(), selection.getLength(), forward, position); setStatusLineErrorMessage(null); setStatusLineMessage(null); if (annotation != null) { updateAnnotationViews(annotation); selectAndReveal(position.getOffset(), position.getLength()); if (annotation instanceof IJavaAnnotation && ((IJavaAnnotation)annotation).isProblem()) setStatusLineMessage(((IJavaAnnotation)annotation).getMessage()); } } } /** * Updates the annotation views that show the given annotation. * * @param annotation the annotation */ private void updateAnnotationViews(Annotation annotation) { IMarker marker= null; if (annotation instanceof MarkerAnnotation) marker= ((MarkerAnnotation) annotation).getMarker(); else if (annotation instanceof IJavaAnnotation) { Iterator e= ((IJavaAnnotation) annotation).getOverlaidIterator(); if (e != null) { while (e.hasNext()) { Object o= e.next(); if (o instanceof MarkerAnnotation) { marker= ((MarkerAnnotation) o).getMarker(); break; } } } } if (marker != null && !marker.equals(fLastMarkerTarget)) { try { boolean isProblem= marker.isSubtypeOf(IMarker.PROBLEM); IWorkbenchPage page= getSite().getPage(); IViewPart view= page.findView(isProblem ? IPageLayout.ID_PROBLEM_VIEW: IPageLayout.ID_TASK_LIST); //$NON-NLS-1$ //$NON-NLS-2$ if (view != null) { Method method= view.getClass().getMethod("setSelection", new Class[] { IStructuredSelection.class, boolean.class}); //$NON-NLS-1$ method.invoke(view, new Object[] {new StructuredSelection(marker), Boolean.TRUE }); } } catch (CoreException x) { } catch (NoSuchMethodException x) { } catch (IllegalAccessException x) { } catch (InvocationTargetException x) { } // ignore exceptions, don't update any of the lists, just set statusline } } /** * Finds and marks occurrence annotations. * * @since 3.0 */ class OccurrencesFinder implements Runnable, IDocumentListener { private int fCount; private IDocument fDocument; private ITextSelection fSelection; private boolean fCancelled= false; public OccurrencesFinder(int count, IDocument document, ITextSelection selection) { fCount= count; fDocument= document; fSelection= selection; fDocument.addDocumentListener(this); } private boolean isCancelled() { return fCount != fComputeCount || fCancelled; } /* * @see java.lang.Runnable#run() */ public void run() { try { if (isCancelled()) return; // Find occurrences FindOccurrencesEngine engine= FindOccurrencesEngine.create(getInputJavaElement()); List matches= new ArrayList(); try { matches= engine.findOccurrences(fSelection.getOffset(), fSelection.getLength()); } catch (JavaModelException e) { JavaPlugin.log(e); return; } if (matches == null || matches.isEmpty()) return; if (isCancelled()) return; removeOccurrenceAnnotations(); if (isCancelled()) return; ITextViewer textViewer= getViewer(); if (textViewer == null) return; IDocument document= textViewer.getDocument(); if (document == null) return; IDocumentProvider documentProvider= getDocumentProvider(); if (documentProvider == null) return; IAnnotationModel annotationModel= documentProvider.getAnnotationModel(getEditorInput()); if (annotationModel == null) return; // Add occurrence annotations ArrayList annotations= new ArrayList(); ArrayList positions= new ArrayList(); for (Iterator each= matches.iterator(); each.hasNext();) { if (isCancelled()) return; ASTNode node= (ASTNode) each.next(); if (node == null) continue; String message; // Create & add annotation try { message= document.get(node.getStartPosition(), node.getLength()); } catch (BadLocationException ex) { // Skip this match continue; } annotations.add(new DefaultAnnotation(SearchUI.SEARCH_MARKER, IMarker.SEVERITY_INFO, true, message)); positions.add(new Position(node.getStartPosition(), node.getLength())); } if (isCancelled()) return; synchronized (annotationModel) { fOccurrenceAnnotations= annotations; for (int i= 0, size= annotations.size(); i < size; i++) annotationModel.addAnnotation((Annotation) annotations.get(i), (Position) positions.get(i)); } } finally { fDocument.removeDocumentListener(this); } } /* * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent) */ public void documentAboutToBeChanged(DocumentEvent event) { fCancelled= true; } /* * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent) */ public void documentChanged(DocumentEvent event) { } } /** * Updates the occurrences annotations based * on the current selection. * * @since 3.0 */ protected void updateOccurrences() { if (!fMarkOccurrenceAnnotations) return; IDocument document= getSourceViewer().getDocument(); if (document == null) return; OccurrencesFinder finder= new OccurrencesFinder(++fComputeCount, document, (ITextSelection) getSelectionProvider().getSelection()); Thread thread= new Thread(finder, "Occurrences Marker"); //$NON-NLS-1$ thread.setDaemon(true); thread.start(); } void removeOccurrenceAnnotations() { IDocumentProvider documentProvider= getDocumentProvider(); if (documentProvider == null) return; IAnnotationModel annotationModel= documentProvider.getAnnotationModel(getEditorInput()); if (annotationModel == null) return; synchronized (annotationModel) { for (int i= 0, size= fOccurrenceAnnotations.size(); i < size; i++) annotationModel.removeAnnotation((Annotation)fOccurrenceAnnotations.get(i)); fOccurrenceAnnotations.clear(); } } /** * Returns the Java element wrapped by this editors input. * * @return the Java element wrapped by this editors input. * @since 3.0 */ abstract protected IJavaElement getInputJavaElement(); protected void updateStatusLine() { ITextSelection selection= (ITextSelection) getSelectionProvider().getSelection(); Annotation annotation= getAnnotation(selection.getOffset(), selection.getLength()); setStatusLineErrorMessage(null); setStatusLineMessage(null); if (annotation != null) { try { fIsUpdatingAnnotationViews= true; updateAnnotationViews(annotation); } finally { fIsUpdatingAnnotationViews= false; } if (annotation instanceof IJavaAnnotation && ((IJavaAnnotation)annotation).isProblem()) setStatusLineMessage(((IJavaAnnotation)annotation).getMessage()); } } /** * Jumps to the matching bracket. */ public void gotoMatchingBracket() { ISourceViewer sourceViewer= getSourceViewer(); IDocument document= sourceViewer.getDocument(); if (document == null) return; IRegion selection= getSignedSelection(sourceViewer); int selectionLength= Math.abs(selection.getLength()); if (selectionLength > 1) { setStatusLineErrorMessage(JavaEditorMessages.getString("GotoMatchingBracket.error.invalidSelection")); //$NON-NLS-1$ sourceViewer.getTextWidget().getDisplay().beep(); return; } // #26314 int sourceCaretOffset= selection.getOffset() + selection.getLength(); if (isSurroundedByBrackets(document, sourceCaretOffset)) sourceCaretOffset -= selection.getLength(); IRegion region= fBracketMatcher.match(document, sourceCaretOffset); if (region == null) { setStatusLineErrorMessage(JavaEditorMessages.getString("GotoMatchingBracket.error.noMatchingBracket")); //$NON-NLS-1$ sourceViewer.getTextWidget().getDisplay().beep(); return; } int offset= region.getOffset(); int length= region.getLength(); if (length < 1) return; int anchor= fBracketMatcher.getAnchor(); // http://dev.eclipse.org/bugs/show_bug.cgi?id=34195 int targetOffset= (JavaPairMatcher.RIGHT == anchor) ? offset + 1: offset + length; boolean visible= false; if (sourceViewer instanceof ITextViewerExtension3) { ITextViewerExtension3 extension= (ITextViewerExtension3) sourceViewer; visible= (extension.modelOffset2WidgetOffset(targetOffset) > -1); } else { IRegion visibleRegion= sourceViewer.getVisibleRegion(); // http://dev.eclipse.org/bugs/show_bug.cgi?id=34195 visible= (targetOffset >= visibleRegion.getOffset() && targetOffset <= visibleRegion.getOffset() + visibleRegion.getLength()); } if (!visible) { setStatusLineErrorMessage(JavaEditorMessages.getString("GotoMatchingBracket.error.bracketOutsideSelectedElement")); //$NON-NLS-1$ sourceViewer.getTextWidget().getDisplay().beep(); return; } if (selection.getLength() < 0) targetOffset -= selection.getLength(); sourceViewer.setSelectedRange(targetOffset, selection.getLength()); sourceViewer.revealRange(targetOffset, selection.getLength()); } /** * Sets the given message as error message to this editor's status line. * * @param msg message to be set */ protected void setStatusLineErrorMessage(String msg) { IEditorStatusLine statusLine= (IEditorStatusLine) getAdapter(IEditorStatusLine.class); if (statusLine != null) statusLine.setMessage(true, msg, null); } /** * Sets the given message as message to this editor's status line. * * @param msg message to be set * @since 3.0 */ protected void setStatusLineMessage(String msg) { IEditorStatusLine statusLine= (IEditorStatusLine) getAdapter(IEditorStatusLine.class); if (statusLine != null) statusLine.setMessage(false, msg, null); } private static IRegion getSignedSelection(ITextViewer viewer) { StyledText text= viewer.getTextWidget(); int caretOffset= text.getCaretOffset(); Point selection= text.getSelection(); // caret left int offset, length; if (caretOffset == selection.x) { offset= selection.y; length= selection.x - selection.y; // caret right } else { offset= selection.x; length= selection.y - selection.x; } return new Region(offset, length); } private static boolean isBracket(char character) { for (int i= 0; i != BRACKETS.length; ++i) if (character == BRACKETS[i]) return true; return false; } private static boolean isSurroundedByBrackets(IDocument document, int offset) { if (offset == 0 || offset == document.getLength()) return false; try { return isBracket(document.getChar(offset - 1)) && isBracket(document.getChar(offset)); } catch (BadLocationException e) { return false; } } /** * Returns the annotation closest to the given range respecting the given * direction. If an annotation is found, the annotations current position * is copied into the provided annotation position. * * @param offset the region offset * @param length the region length * @param forward <code>true</code> for forwards, <code>false</code> for backward * @param annotationPosition the position of the found annotation * @return the found annotation */ private Annotation getNextAnnotation(int offset, int length, boolean forward, Position annotationPosition) { Annotation nextAnnotation= null; Position nextAnnotationPosition= null; Annotation containingAnnotation= null; Position containingAnnotationPosition= null; boolean currentAnnotation= false; IDocument document= getDocumentProvider().getDocument(getEditorInput()); int endOfDocument= document.getLength(); int distance= 0; IAnnotationAccess access= getAnnotationAccess(); IAnnotationModel model= getDocumentProvider().getAnnotationModel(getEditorInput()); Iterator e= new JavaAnnotationIterator(model, true, true); while (e.hasNext()) { Annotation a= (Annotation) e.next(); Object type; if (a instanceof IJavaAnnotation) type= ((IJavaAnnotation) a).getAnnotationType(); else type= access.getType(a); boolean isNavigationTarget= isNavigationTargetType(type); if ((a instanceof IJavaAnnotation) && ((IJavaAnnotation)a).hasOverlay() || !isNavigationTarget) continue; Position p= model.getPosition(a); if (p == null) continue; if (!(p.includes(offset) || (p.getLength() == 0 && offset == p.offset))) { int currentDistance= 0; if (forward) { currentDistance= p.getOffset() - offset; if (currentDistance < 0) currentDistance= endOfDocument - offset + p.getOffset(); } else { currentDistance= offset - p.getOffset(); if (currentDistance < 0) currentDistance= offset + endOfDocument - p.getOffset(); } if (nextAnnotation == null || currentDistance < distance) { distance= currentDistance; nextAnnotation= a; nextAnnotationPosition= p; } } else { if (containingAnnotationPosition == null || containingAnnotationPosition.length > p.length) { containingAnnotation= a; containingAnnotationPosition= p; if (length == p.length) currentAnnotation= true; } } } if (containingAnnotationPosition != null && (!currentAnnotation || nextAnnotation == null)) { annotationPosition.setOffset(containingAnnotationPosition.getOffset()); annotationPosition.setLength(containingAnnotationPosition.getLength()); return containingAnnotation; } if (nextAnnotationPosition != null) { annotationPosition.setOffset(nextAnnotationPosition.getOffset()); annotationPosition.setLength(nextAnnotationPosition.getLength()); } return nextAnnotation; } /** * Returns the annotation overlapping with the given range or <code>null</code>. * * @param offset the region offset * @param length the region length * @return the found annotation or <code>null</code> * @since 3.0 */ private Annotation getAnnotation(int offset, int length) { IAnnotationAccess access= getAnnotationAccess(); IAnnotationModel model= getDocumentProvider().getAnnotationModel(getEditorInput()); Iterator e= new JavaAnnotationIterator(model, true, true); while (e.hasNext()) { Annotation a= (Annotation) e.next(); if (a instanceof IJavaAnnotation) { IJavaAnnotation annotation= (IJavaAnnotation) a; if (annotation.hasOverlay() || !isNavigationTargetType(annotation.getAnnotationType())) continue; } else if (!isNavigationTargetType(access.getType(a))) continue; Position p= model.getPosition(a); if (p != null && p.overlapsWith(offset, length)) return a; } return null; } /** * Returns whether the given annotation type is configured as a target type * for the "Go to Next/Previous Annotation" actions * * @param type the annotation type * @return <code>true</code> if this is a target type, <code>false</code> * otherwise * @since 3.0 */ private boolean isNavigationTargetType(Object type) { Preferences preferences= Platform.getPlugin("org.eclipse.ui.workbench.texteditor").getPluginPreferences(); //$NON-NLS-1$ Iterator i= getAnnotationPreferences().getAnnotationPreferences().iterator(); while (i.hasNext()) { AnnotationPreference annotationPref= (AnnotationPreference) i.next(); if (annotationPref.getAnnotationType().equals(type)) { // See bug 41689 // String key= forward ? annotationPref.getIsGoToNextNavigationTargetKey() : annotationPref.getIsGoToPreviousNavigationTargetKey(); String key= annotationPref.getIsGoToNextNavigationTargetKey(); if (key != null && preferences.getBoolean(key)) return true; } } return false; } /** * Computes and returns the source reference that includes the caret and * serves as provider for the outline page selection and the editor range * indication. * * @return the computed source reference * @since 3.0 */ protected ISourceReference computeHighlightRangeSourceReference() { ISourceViewer sourceViewer= getSourceViewer(); if (sourceViewer == null) return null; StyledText styledText= sourceViewer.getTextWidget(); if (styledText == null) return null; int caret= 0; if (sourceViewer instanceof ITextViewerExtension3) { ITextViewerExtension3 extension= (ITextViewerExtension3)sourceViewer; caret= extension.widgetOffset2ModelOffset(styledText.getCaretOffset()); } else { int offset= sourceViewer.getVisibleRegion().getOffset(); caret= offset + styledText.getCaretOffset(); } IJavaElement element= getElementAt(caret, false); if ( !(element instanceof ISourceReference)) return null; if (element.getElementType() == IJavaElement.IMPORT_DECLARATION) { IImportDeclaration declaration= (IImportDeclaration) element; IImportContainer container= (IImportContainer) declaration.getParent(); ISourceRange srcRange= null; try { srcRange= container.getSourceRange(); } catch (JavaModelException e) { } if (srcRange != null && srcRange.getOffset() == caret) return container; } return (ISourceReference) element; } /** * Returns the most narrow java element including the given offset. * * @param offset the offset inside of the requested element * @param reconcile <code>true</code> if editor input should be reconciled in advance * @return the most narrow java element * @since 3.0 */ protected IJavaElement getElementAt(int offset, boolean reconcile) { return getElementAt(offset); } /* * @see org.eclipse.ui.texteditor.ExtendedTextEditor#createChangeHover() */ protected LineChangeHover createChangeHover() { return new JavaChangeHover(IJavaPartitions.JAVA_PARTITIONING); } protected boolean isPrefQuickDiffAlwaysOn() { return false; // never show change ruler for the non-editable java editor. Overridden in subclasses like CompilationUnitEditor } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#createNavigationActions() */ protected void createNavigationActions() { super.createNavigationActions(); final StyledText textWidget= getSourceViewer().getTextWidget(); IAction action= new SmartLineStartAction(textWidget, false); action.setActionDefinitionId(ITextEditorActionDefinitionIds.LINE_START); setAction(ITextEditorActionDefinitionIds.LINE_START, action); action= new SmartLineStartAction(textWidget, true); action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_LINE_START); setAction(ITextEditorActionDefinitionIds.SELECT_LINE_START, action); action= new NavigatePreviousSubWordAction(); action.setActionDefinitionId(ITextEditorActionDefinitionIds.WORD_PREVIOUS); setAction(ITextEditorActionDefinitionIds.WORD_PREVIOUS, action); textWidget.setKeyBinding(SWT.CTRL | SWT.ARROW_LEFT, SWT.NULL); action= new NavigateNextSubWordAction(); action.setActionDefinitionId(ITextEditorActionDefinitionIds.WORD_NEXT); setAction(ITextEditorActionDefinitionIds.WORD_NEXT, action); textWidget.setKeyBinding(SWT.CTRL | SWT.ARROW_RIGHT, SWT.NULL); action= new DeletePreviousSubWordAction(); action.setActionDefinitionId(ITextEditorActionDefinitionIds.DELETE_PREVIOUS_WORD); setAction(ITextEditorActionDefinitionIds.DELETE_PREVIOUS_WORD, action); textWidget.setKeyBinding(SWT.CTRL | SWT.BS, SWT.NULL); action= new DeleteNextSubWordAction(); action.setActionDefinitionId(ITextEditorActionDefinitionIds.DELETE_NEXT_WORD); setAction(ITextEditorActionDefinitionIds.DELETE_NEXT_WORD, action); textWidget.setKeyBinding(SWT.CTRL | SWT.DEL, SWT.NULL); action= new SelectPreviousSubWordAction(); action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS); setAction(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS, action); textWidget.setKeyBinding(SWT.CTRL | SWT.SHIFT | SWT.ARROW_LEFT, SWT.NULL); action= new SelectNextSubWordAction(); action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT); setAction(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT, action); textWidget.setKeyBinding(SWT.CTRL | SWT.SHIFT | SWT.ARROW_RIGHT, SWT.NULL); } }