/******************************************************************************* | |
* 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.help.WorkbenchHelp; | |
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.wst.jsdt.core.IClassFile; | |
import org.eclipse.wst.jsdt.core.ICodeAssist; | |
import org.eclipse.wst.jsdt.core.ICompilationUnit; | |
import org.eclipse.wst.jsdt.core.IImportContainer; | |
import org.eclipse.wst.jsdt.core.IImportDeclaration; | |
import org.eclipse.wst.jsdt.core.IJavaElement; | |
import org.eclipse.wst.jsdt.core.IMember; | |
import org.eclipse.wst.jsdt.core.IPackageDeclaration; | |
import org.eclipse.wst.jsdt.core.ISourceRange; | |
import org.eclipse.wst.jsdt.core.ISourceReference; | |
import org.eclipse.wst.jsdt.core.JavaCore; | |
import org.eclipse.wst.jsdt.core.JavaModelException; | |
import org.eclipse.wst.jsdt.core.dom.ASTNode; | |
import org.eclipse.wst.jsdt.ui.IContextMenuConstants; | |
import org.eclipse.wst.jsdt.ui.JavaUI; | |
import org.eclipse.wst.jsdt.ui.PreferenceConstants; | |
import org.eclipse.wst.jsdt.ui.actions.IJavaEditorActionDefinitionIds; | |
import org.eclipse.wst.jsdt.ui.actions.JavaSearchActionGroup; | |
import org.eclipse.wst.jsdt.ui.actions.OpenEditorActionGroup; | |
import org.eclipse.wst.jsdt.ui.actions.OpenViewActionGroup; | |
import org.eclipse.wst.jsdt.ui.actions.ShowActionGroup; | |
import org.eclipse.wst.jsdt.ui.text.JavaSourceViewerConfiguration; | |
import org.eclipse.wst.jsdt.ui.text.JavaTextTools; | |
import org.eclipse.wst.jsdt.internal.ui.IJavaHelpContextIds; | |
import org.eclipse.wst.jsdt.internal.ui.JavaPlugin; | |
import org.eclipse.wst.jsdt.internal.ui.actions.CompositeActionGroup; | |
import org.eclipse.wst.jsdt.internal.ui.actions.SelectionConverter; | |
import org.eclipse.wst.jsdt.internal.ui.javaeditor.selectionactions.GoToNextPreviousMemberAction; | |
import org.eclipse.wst.jsdt.internal.ui.javaeditor.selectionactions.SelectionHistory; | |
import org.eclipse.wst.jsdt.internal.ui.javaeditor.selectionactions.StructureSelectEnclosingAction; | |
import org.eclipse.wst.jsdt.internal.ui.javaeditor.selectionactions.StructureSelectHistoryAction; | |
import org.eclipse.wst.jsdt.internal.ui.javaeditor.selectionactions.StructureSelectNextAction; | |
import org.eclipse.wst.jsdt.internal.ui.javaeditor.selectionactions.StructureSelectPreviousAction; | |
import org.eclipse.wst.jsdt.internal.ui.javaeditor.selectionactions.StructureSelectionAction; | |
import org.eclipse.wst.jsdt.internal.ui.search.FindOccurrencesEngine; | |
import org.eclipse.wst.jsdt.internal.ui.text.HTMLTextPresenter; | |
import org.eclipse.wst.jsdt.internal.ui.text.IJavaPartitions; | |
import org.eclipse.wst.jsdt.internal.ui.text.JavaChangeHover; | |
import org.eclipse.wst.jsdt.internal.ui.text.JavaPairMatcher; | |
import org.eclipse.wst.jsdt.internal.ui.util.JavaUIHelp; | |
import org.eclipse.wst.jsdt.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.wst.jsdt.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.wst.jsdt.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.wst.jsdt.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.wst.jsdt.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.wst.jsdt.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.wst.jsdt.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.wst.jsdt.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$ | |
WorkbenchHelp.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); | |
WorkbenchHelp.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); | |
WorkbenchHelp.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); | |
WorkbenchHelp.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.wst.jsdt.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); | |
} | |
} |