Java tutorial
/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.ui.internal.text.editor; import com.google.dart.compiler.ast.DartNode; import com.google.dart.compiler.ast.DartUnit; import com.google.dart.compiler.ast.DartVariable; import com.google.dart.compiler.resolver.Element; import com.google.dart.tools.core.DartCore; import com.google.dart.tools.core.formatter.DefaultCodeFormatterConstants; import com.google.dart.tools.core.model.CompilationUnit; import com.google.dart.tools.core.model.DartElement; import com.google.dart.tools.core.model.DartModelException; import com.google.dart.tools.core.model.DartProject; import com.google.dart.tools.core.model.SourceRange; import com.google.dart.tools.core.model.SourceReference; import com.google.dart.tools.core.utilities.ast.DartElementLocator; import com.google.dart.tools.core.utilities.ast.NameOccurrencesFinder; import com.google.dart.tools.core.utilities.compiler.DartCompilerUtilities; import com.google.dart.tools.ui.DartToolsPlugin; import com.google.dart.tools.ui.DartX; import com.google.dart.tools.ui.IContextMenuConstants; import com.google.dart.tools.ui.PreferenceConstants; import com.google.dart.tools.ui.actions.DartEditorActionDefinitionIds; import com.google.dart.tools.ui.actions.DartSearchActionGroup; import com.google.dart.tools.ui.actions.OpenEditorActionGroup; import com.google.dart.tools.ui.actions.OpenViewActionGroup; import com.google.dart.tools.ui.callhierarchy.OpenCallHierarchyAction; import com.google.dart.tools.ui.internal.actions.FoldingActionGroup; import com.google.dart.tools.ui.internal.actions.SelectionConverter; import com.google.dart.tools.ui.internal.text.DartHelpContextIds; import com.google.dart.tools.ui.internal.text.IProductConstants; import com.google.dart.tools.ui.internal.text.ProductProperties; import com.google.dart.tools.ui.internal.text.dart.hover.SourceViewerInformationControl; import com.google.dart.tools.ui.internal.text.editor.saveactions.RemoveTrailingWhitespaceAction; import com.google.dart.tools.ui.internal.text.editor.selectionactions.GoToNextPreviousMemberAction; import com.google.dart.tools.ui.internal.text.editor.selectionactions.SelectionHistory; import com.google.dart.tools.ui.internal.text.editor.selectionactions.StructureSelectEnclosingAction; import com.google.dart.tools.ui.internal.text.editor.selectionactions.StructureSelectHistoryAction; import com.google.dart.tools.ui.internal.text.editor.selectionactions.StructureSelectNextAction; import com.google.dart.tools.ui.internal.text.editor.selectionactions.StructureSelectPreviousAction; import com.google.dart.tools.ui.internal.text.editor.selectionactions.StructureSelectionAction; import com.google.dart.tools.ui.internal.text.functions.DartChangeHover; import com.google.dart.tools.ui.internal.text.functions.DartPairMatcher; import com.google.dart.tools.ui.internal.text.functions.DartWordFinder; import com.google.dart.tools.ui.internal.text.functions.DartWordIterator; import com.google.dart.tools.ui.internal.text.functions.DocumentCharacterIterator; import com.google.dart.tools.ui.internal.text.functions.PreferencesAdapter; import com.google.dart.tools.ui.internal.util.DartUIHelp; import com.google.dart.tools.ui.internal.viewsupport.ISelectionListenerWithAST; import com.google.dart.tools.ui.internal.viewsupport.IViewPartInputProvider; import com.google.dart.tools.ui.internal.viewsupport.SelectionListenerWithASTManager; import com.google.dart.tools.ui.text.DartPartitions; import com.google.dart.tools.ui.text.DartSourceViewerConfiguration; import com.google.dart.tools.ui.text.DartTextTools; import com.google.dart.tools.ui.text.editor.tmp.JavaScriptCore; import com.google.dart.tools.ui.text.folding.IDartFoldingStructureProvider; import com.google.dart.tools.ui.text.folding.IDartFoldingStructureProviderExtension; import com.ibm.icu.text.BreakIterator; import org.eclipse.core.commands.operations.IOperationApprover; import org.eclipse.core.commands.operations.IUndoContext; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ProjectScope; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.IScopeContext; import org.eclipse.help.IContextProvider; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentExtension4; 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.ISelectionValidator; import org.eclipse.jface.text.ISynchronizable; import org.eclipse.jface.text.ITextHover; import org.eclipse.jface.text.ITextInputListener; import org.eclipse.jface.text.ITextOperationTarget; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.ITextViewerExtension2; import org.eclipse.jface.text.ITextViewerExtension5; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.TextUtilities; import org.eclipse.jface.text.link.LinkedModeModel; import org.eclipse.jface.text.link.LinkedPosition; import org.eclipse.jface.text.reconciler.IReconciler; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.CompositeRuler; import org.eclipse.jface.text.source.IAnnotationModel; import org.eclipse.jface.text.source.IAnnotationModelExtension; import org.eclipse.jface.text.source.ICharacterPairMatcher; import org.eclipse.jface.text.source.IOverviewRuler; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.ISourceViewerExtension2; import org.eclipse.jface.text.source.IVerticalRuler; import org.eclipse.jface.text.source.IVerticalRulerColumn; import org.eclipse.jface.text.source.LineChangeHover; import org.eclipse.jface.text.source.SourceViewerConfiguration; import org.eclipse.jface.text.source.projection.ProjectionSupport; import org.eclipse.jface.text.source.projection.ProjectionViewer; 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.swt.SWT; import org.eclipse.swt.custom.ST; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.IPageLayout; import org.eclipse.ui.IPartListener2; import org.eclipse.ui.IPartService; import org.eclipse.ui.IWindowListener; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartReference; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.ActionContext; import org.eclipse.ui.actions.ActionGroup; import org.eclipse.ui.editors.text.DefaultEncodingSupport; import org.eclipse.ui.editors.text.EditorsUI; import org.eclipse.ui.editors.text.IEncodingSupport; import org.eclipse.ui.operations.NonLocalUndoUserApprover; import org.eclipse.ui.part.IShowInSource; import org.eclipse.ui.part.IShowInTargetList; import org.eclipse.ui.part.ShowInContext; import org.eclipse.ui.texteditor.AbstractDecoratedTextEditor; import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants; import org.eclipse.ui.texteditor.AnnotationPreference; import org.eclipse.ui.texteditor.ChainedPreferenceStore; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.ITextEditorActionConstants; import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; import org.eclipse.ui.texteditor.IUpdate; import org.eclipse.ui.texteditor.MarkerAnnotation; import org.eclipse.ui.texteditor.SourceViewerDecorationSupport; 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.osgi.service.prefs.BackingStoreException; import java.lang.ref.SoftReference; import java.lang.reflect.InvocationTargetException; import java.text.CharacterIterator; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; /** * Dart specific text editor. */ @SuppressWarnings({ "unused", "deprecation" }) public abstract class DartEditor extends AbstractDecoratedTextEditor implements IViewPartInputProvider { /** * Internal implementation class for a change listener. */ 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 the selection provider */ public void uninstall(ISelectionProvider selectionProvider) { if (selectionProvider == null) { return; } if (selectionProvider instanceof IPostSelectionProvider) { IPostSelectionProvider provider = (IPostSelectionProvider) selectionProvider; provider.removePostSelectionChangedListener(this); } else { selectionProvider.removeSelectionChangedListener(this); } } } /** * Text operation action to delete the next sub-word. */ protected class DeleteNextSubWordAction extends NextSubWordAction implements IUpdate { /** * Creates a new delete next sub-word action. */ public DeleteNextSubWordAction() { super(ST.DELETE_WORD_NEXT); } /* * @see org.eclipse.ui.texteditor.IUpdate#update() */ @Override public void update() { setEnabled(isEditorInputModifiable()); } @Override protected void setCaretPosition(final int position) { if (!validateEditorInputState()) { return; } final ISourceViewer viewer = getSourceViewer(); StyledText text = viewer.getTextWidget(); Point widgetSelection = text.getSelection(); if (isBlockSelectionModeEnabled() && widgetSelection.y != widgetSelection.x) { final int caret = text.getCaretOffset(); final int offset = modelOffset2WidgetOffset(viewer, position); if (caret == widgetSelection.x) { text.setSelectionRange(widgetSelection.y, offset - widgetSelection.y); } else { text.setSelectionRange(widgetSelection.x, offset - widgetSelection.x); } text.invokeAction(ST.DELETE_NEXT); } else { Point selection = viewer.getSelectedRange(); final int caret, length; if (selection.y != 0) { caret = selection.x; length = selection.y; } else { caret = widgetOffset2ModelOffset(viewer, text.getCaretOffset()); length = position - caret; } try { viewer.getDocument().replace(caret, length, ""); //$NON-NLS-1$ } catch (BadLocationException exception) { // Should not happen } } } } /** * Text operation action to delete the previous sub-word. */ protected class DeletePreviousSubWordAction extends PreviousSubWordAction implements IUpdate { /** * Creates a new delete previous sub-word action. */ public DeletePreviousSubWordAction() { super(ST.DELETE_WORD_PREVIOUS); } /* * @see org.eclipse.ui.texteditor.IUpdate#update() */ @Override public void update() { setEnabled(isEditorInputModifiable()); } @Override protected void setCaretPosition(int position) { if (!validateEditorInputState()) { return; } final int length; final ISourceViewer viewer = getSourceViewer(); StyledText text = viewer.getTextWidget(); Point widgetSelection = text.getSelection(); if (isBlockSelectionModeEnabled() && widgetSelection.y != widgetSelection.x) { final int caret = text.getCaretOffset(); final int offset = modelOffset2WidgetOffset(viewer, position); if (caret == widgetSelection.x) { text.setSelectionRange(widgetSelection.y, offset - widgetSelection.y); } else { text.setSelectionRange(widgetSelection.x, offset - widgetSelection.x); } text.invokeAction(ST.DELETE_PREVIOUS); } else { Point selection = viewer.getSelectedRange(); if (selection.y != 0) { position = selection.x; length = selection.y; } else { length = widgetOffset2ModelOffset(viewer, text.getCaretOffset()) - position; } try { viewer.getDocument().replace(position, length, ""); //$NON-NLS-1$ } catch (BadLocationException exception) { // Should not happen } } } } /** * Format element action to format the enclosing Dart element. * <p> * The format element action works as follows: * <ul> * <li>If there is no selection and the caret is positioned on a Dart 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. */ protected class FormatElementAction extends Action implements IUpdate { /* * */ FormatElementAction() { setEnabled(isEditorInputModifiable()); } /* * @see org.eclipse.jface.action.IAction#run() */ @Override public void run() { final DartSourceViewer viewer = (DartSourceViewer) getSourceViewer(); if (viewer.isEditable()) { final Point selection = viewer.rememberSelection(); try { viewer.setRedraw(false); final String type = TextUtilities.getContentType(viewer.getDocument(), DartPartitions.DART_PARTITIONING, selection.x, true); if (type.equals(IDocument.DEFAULT_CONTENT_TYPE) && selection.y == 0) { try { final DartElement element = getElementAt(selection.x, true); if (element != null && element.exists()) { final int kind = element.getElementType(); if (kind == DartElement.TYPE || kind == DartElement.METHOD) { final SourceReference reference = (SourceReference) element; final SourceRange range = reference.getSourceRange(); if (range != null) { viewer.setSelectedRange(range.getOffset(), range.getLength()); viewer.doOperation(ISourceViewer.FORMAT); } } } } catch (DartModelException 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(); } } } /* * @see org.eclipse.ui.texteditor.IUpdate#update() */ @Override public void update() { setEnabled(isEditorInputModifiable()); } } /** * Text navigation action to navigate to the next sub-word. */ protected class NavigateNextSubWordAction extends NextSubWordAction { /** * Creates a new navigate next sub-word action. */ public NavigateNextSubWordAction() { super(ST.WORD_NEXT); } @Override protected void setCaretPosition(final int position) { getTextWidget().setCaretOffset(modelOffset2WidgetOffset(getSourceViewer(), position)); } } /** * Text navigation action to navigate to the previous sub-word. */ protected class NavigatePreviousSubWordAction extends PreviousSubWordAction { /** * Creates a new navigate previous sub-word action. */ public NavigatePreviousSubWordAction() { super(ST.WORD_PREVIOUS); } @Override protected void setCaretPosition(final int position) { getTextWidget().setCaretOffset(modelOffset2WidgetOffset(getSourceViewer(), position)); } } /** * Text navigation action to navigate to the next sub-word. */ protected abstract class NextSubWordAction extends TextNavigationAction { protected DartWordIterator fIterator = new DartWordIterator(); /** * 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); } /* * @see org.eclipse.jface.action.IAction#run() */ @Override public void run() { // Check whether we are in a Dart code partition and the preference is enabled final IPreferenceStore store = getPreferenceStore(); if (!store.getBoolean(PreferenceConstants.EDITOR_SUB_WORD_NAVIGATION)) { super.run(); return; } final ISourceViewer viewer = getSourceViewer(); final IDocument document = viewer.getDocument(); fIterator.setText((CharacterIterator) new DocumentCharacterIterator(document)); int position = widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset()); if (position == -1) { return; } int next = findNextPosition(position); try { if (isBlockSelectionModeEnabled() && document.getLineOfOffset(next) != document.getLineOfOffset(position)) { super.run(); // may navigate into virtual white space } else if (next != BreakIterator.DONE) { setCaretPosition(next); getTextWidget().showSelection(); fireSelectionChanged(); } } catch (BadLocationException x) { // ignore } } /** * Finds the next position after the given position. * * @param position the current position * @return the next position */ protected int findNextPosition(int position) { ISourceViewer viewer = getSourceViewer(); int widget = -1; int next = position; while (next != BreakIterator.DONE && widget == -1) { // TODO: optimize next = fIterator.following(next); if (next != BreakIterator.DONE) { widget = modelOffset2WidgetOffset(viewer, next); } } IDocument document = viewer.getDocument(); LinkedModeModel model = LinkedModeModel.getModel(document, position); if (model != null) { LinkedPosition linkedPosition = model.findPosition(new LinkedPosition(document, position, 0)); if (linkedPosition != null) { int linkedPositionEnd = linkedPosition.getOffset() + linkedPosition.getLength(); if (position != linkedPositionEnd && linkedPositionEnd < next) { next = linkedPositionEnd; } } else { LinkedPosition nextLinkedPosition = model.findPosition(new LinkedPosition(document, next, 0)); if (nextLinkedPosition != null) { int nextLinkedPositionOffset = nextLinkedPosition.getOffset(); if (position != nextLinkedPositionOffset && nextLinkedPositionOffset < next) { next = nextLinkedPositionOffset; } } } } return next; } /** * 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. */ protected abstract class PreviousSubWordAction extends TextNavigationAction { protected DartWordIterator fIterator = new DartWordIterator(); /** * 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); } /* * @see org.eclipse.jface.action.IAction#run() */ @Override public void run() { // Check whether we are in a Dart code partition and the preference is enabled final IPreferenceStore store = getPreferenceStore(); if (!store.getBoolean(PreferenceConstants.EDITOR_SUB_WORD_NAVIGATION)) { super.run(); return; } final ISourceViewer viewer = getSourceViewer(); final IDocument document = viewer.getDocument(); fIterator.setText((CharacterIterator) new DocumentCharacterIterator(document)); int position = widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset()); if (position == -1) { return; } int previous = findPreviousPosition(position); try { if (isBlockSelectionModeEnabled() && document.getLineOfOffset(previous) != document.getLineOfOffset(position)) { super.run(); // may navigate into virtual white space } else if (previous != BreakIterator.DONE) { setCaretPosition(previous); getTextWidget().showSelection(); fireSelectionChanged(); } } catch (BadLocationException x) { // ignore - getLineOfOffset failed } } /** * Finds the previous position before the given position. * * @param position the current position * @return the previous position */ protected int findPreviousPosition(int position) { ISourceViewer viewer = getSourceViewer(); int widget = -1; int previous = position; while (previous != BreakIterator.DONE && widget == -1) { // TODO: optimize previous = fIterator.preceding(previous); if (previous != BreakIterator.DONE) { widget = modelOffset2WidgetOffset(viewer, previous); } } IDocument document = viewer.getDocument(); LinkedModeModel model = LinkedModeModel.getModel(document, position); if (model != null) { LinkedPosition linkedPosition = model.findPosition(new LinkedPosition(document, position, 0)); if (linkedPosition != null) { int linkedPositionOffset = linkedPosition.getOffset(); if (position != linkedPositionOffset && previous < linkedPositionOffset) { previous = linkedPositionOffset; } } else { LinkedPosition previousLinkedPosition = model .findPosition(new LinkedPosition(document, previous, 0)); if (previousLinkedPosition != null) { int previousLinkedPositionEnd = previousLinkedPosition.getOffset() + previousLinkedPosition.getLength(); if (position != previousLinkedPositionEnd && previous < previousLinkedPositionEnd) { previous = previousLinkedPositionEnd; } } } } return previous; } /** * 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 operation action to select the next sub-word. */ protected class SelectNextSubWordAction extends NextSubWordAction { /** * Creates a new select next sub-word action. */ public SelectNextSubWordAction() { super(ST.SELECT_WORD_NEXT); } @Override 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 operation action to select the previous sub-word. */ protected class SelectPreviousSubWordAction extends PreviousSubWordAction { /** * Creates a new select previous sub-word action. */ public SelectPreviousSubWordAction() { super(ST.SELECT_WORD_PREVIOUS); } @Override 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); } } } } /** * 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. */ 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) */ @Override protected int getLineStartPosition(final IDocument document, final String line, final int length, final int offset) { String type = IDocument.DEFAULT_CONTENT_TYPE; try { type = TextUtilities.getContentType(document, DartPartitions.DART_PARTITIONING, offset, true); } catch (BadLocationException exception) { // Should not happen } int index = super.getLineStartPosition(document, line, length, offset); if (type.equals(DartPartitions.DART_DOC) || type.equals(DartPartitions.DART_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 + 1) == '/') { if (type.equals(DartPartitions.DART_SINGLE_LINE_DOC) && (index < length - 2 && line.charAt(index + 2) == '/')) { index++; } index++; do { ++index; } while (index < length && Character.isWhitespace(line.charAt(index))); } } return index; } } /** * Finds and marks occurrence annotations. */ class OccurrencesFinderJob extends Job { private final IDocument fDocument; private final ISelection fSelection; private ISelectionValidator fPostSelectionValidator; private boolean fCanceled = false; private IProgressMonitor fProgressMonitor; private final Position[] fPositions; public OccurrencesFinderJob(IDocument document, Position[] positions, ISelection selection) { super(DartEditorMessages.JavaEditor_markOccurrences_job_name); fDocument = document; fSelection = selection; fPositions = positions; if (getSelectionProvider() instanceof ISelectionValidator) { fPostSelectionValidator = (ISelectionValidator) getSelectionProvider(); } } /* * @see Job#run(org.eclipse.core.runtime.IProgressMonitor) */ @Override public IStatus run(IProgressMonitor progressMonitor) { fProgressMonitor = progressMonitor; if (isCanceled()) { return Status.CANCEL_STATUS; } ITextViewer textViewer = getViewer(); if (textViewer == null) { return Status.CANCEL_STATUS; } IDocument document = textViewer.getDocument(); if (document == null) { return Status.CANCEL_STATUS; } IDocumentProvider documentProvider = getDocumentProvider(); if (documentProvider == null) { return Status.CANCEL_STATUS; } IAnnotationModel annotationModel = documentProvider.getAnnotationModel(getEditorInput()); if (annotationModel == null) { return Status.CANCEL_STATUS; } // Add occurrence annotations int length = fPositions.length; Map<Annotation, Position> annotationMap = new HashMap<Annotation, Position>(length); for (int i = 0; i < length; i++) { if (isCanceled()) { return Status.CANCEL_STATUS; } String message; Position position = fPositions[i]; // Create & add annotation try { message = document.get(position.offset, position.length); } catch (BadLocationException ex) { // Skip this match continue; } annotationMap.put(new Annotation("com.google.dart.tools.ui.occurrences", false, message), //$NON-NLS-1$ position); } if (isCanceled()) { return Status.CANCEL_STATUS; } synchronized (getLockObject(annotationModel)) { if (annotationModel instanceof IAnnotationModelExtension) { ((IAnnotationModelExtension) annotationModel).replaceAnnotations(fOccurrenceAnnotations, annotationMap); } else { removeOccurrenceAnnotations(); Iterator<Map.Entry<Annotation, Position>> iter = annotationMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry<Annotation, Position> mapEntry = iter.next(); annotationModel.addAnnotation(mapEntry.getKey(), mapEntry.getValue()); } } fOccurrenceAnnotations = annotationMap.keySet() .toArray(new Annotation[annotationMap.keySet().size()]); } return Status.OK_STATUS; } // cannot use cancel() because it is declared final void doCancel() { fCanceled = true; cancel(); } private boolean isCanceled() { return fCanceled || fProgressMonitor.isCanceled() || fPostSelectionValidator != null && !(fPostSelectionValidator.isValid(fSelection) || fForcedMarkOccurrencesSelection == fSelection) || LinkedModeModel.hasInstalledModel(fDocument); } } /** * Cancels the occurrences finder job upon document changes. */ class OccurrencesFinderJobCanceler implements IDocumentListener, ITextInputListener { /* * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org * .eclipse.jface.text.DocumentEvent) */ @Override public void documentAboutToBeChanged(DocumentEvent event) { if (fOccurrencesFinderJob != null) { fOccurrencesFinderJob.doCancel(); } } /* * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse. * jface.text.DocumentEvent) */ @Override public void documentChanged(DocumentEvent event) { } /* * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged * (org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument) */ @Override public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { if (oldInput == null) { return; } oldInput.removeDocumentListener(this); } /* * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse * .jface.text.IDocument, org.eclipse.jface.text.IDocument) */ @Override public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { if (newInput == null) { return; } newInput.addDocumentListener(this); } public void install() { ISourceViewer sourceViewer = getSourceViewer(); if (sourceViewer == null) { return; } StyledText text = sourceViewer.getTextWidget(); if (text == null || text.isDisposed()) { return; } sourceViewer.addTextInputListener(this); IDocument document = sourceViewer.getDocument(); if (document != null) { document.addDocumentListener(this); } } public void uninstall() { ISourceViewer sourceViewer = getSourceViewer(); if (sourceViewer != null) { sourceViewer.removeTextInputListener(this); } IDocumentProvider documentProvider = getDocumentProvider(); if (documentProvider != null) { IDocument document = documentProvider.getDocument(getEditorInput()); if (document != null) { document.removeDocumentListener(this); } } } } /** * Internal activation listener. */ private class ActivationListener implements IWindowListener { /* * @see org.eclipse.ui.IWindowListener#windowActivated(org.eclipse.ui. IWorkbenchWindow) */ @Override public void windowActivated(IWorkbenchWindow window) { if (window == getEditorSite().getWorkbenchWindow() && fMarkOccurrenceAnnotations && isActivePart()) { fForcedMarkOccurrencesSelection = getSelectionProvider().getSelection(); try { DartElement input = getInputDartElement(); if (input != null) { updateOccurrenceAnnotations((ITextSelection) fForcedMarkOccurrencesSelection, DartToolsPlugin.getDefault().getASTProvider().getAST(input, ASTProvider.WAIT_NO, getProgressMonitor())); } } catch (Exception ex) { // ignore it } } } /* * @see org.eclipse.ui.IWindowListener#windowClosed(org.eclipse.ui.IWorkbenchWindow ) */ @Override public void windowClosed(IWorkbenchWindow window) { } /* * @see org.eclipse.ui.IWindowListener#windowDeactivated(org.eclipse.ui. IWorkbenchWindow) */ @Override public void windowDeactivated(IWorkbenchWindow window) { if (window == getEditorSite().getWorkbenchWindow() && fMarkOccurrenceAnnotations && isActivePart()) { removeOccurrenceAnnotations(); } } /* * @see org.eclipse.ui.IWindowListener#windowOpened(org.eclipse.ui.IWorkbenchWindow ) */ @Override public void windowOpened(IWorkbenchWindow window) { } } /** * Instances of the class <code>ASTCache</code> maintain an AST structure corresponding to the * contents of an editor's document. */ private static class ASTCache { /** * The time at which the cache was last cleared. */ private long clearTime; /** * The AST corresponding to the contents of the editor's document, or <code>null</code> if the * AST structure has not been accessed since the last time the cache was cleared. */ private SoftReference<DartUnit> cachedAST; /** * Initialize a newly created class to be empty. */ public ASTCache() { clearTime = 0L; cachedAST = null; } /** * Clear the contents of this cache. */ public void clear() { synchronized (this) { clearTime = System.nanoTime(); cachedAST = null; } } /** * Return the AST structure held in this cache, or <code>null</code> if the AST structure needs * to be created. * * @return the AST structure held in this cache */ public DartUnit getAST() { synchronized (this) { if (cachedAST != null) { return cachedAST.get(); } } return null; } /** * Set the AST structure held in this cache to the given AST structure provided that the cache * has not been cleared since the time at which the AST structure was created. * * @param creationTime the time at which the AST structure was created (in nanoseconds) * @param ast the AST structure that is to be cached */ public void setAST(long creationTime, DartUnit ast) { synchronized (this) { if (creationTime > clearTime) { cachedAST = new SoftReference<DartUnit>(ast); } } } } /** * Adapts an options {@link IEclipsePreferences} to * {@link org.eclipse.jface.preference.IPreferenceStore}. * <p> * This preference store is read-only i.e. write access throws an * {@link java.lang.UnsupportedOperationException}. * </p> */ private static class EclipsePreferencesAdapter implements IPreferenceStore { /** * Preference change listener. Listens for events preferences fires a * {@link org.eclipse.jface.util.PropertyChangeEvent} on this adapter with arguments from the * received event. */ private class PreferenceChangeListener implements IEclipsePreferences.IPreferenceChangeListener { /** * {@inheritDoc} */ @Override public void preferenceChange(final IEclipsePreferences.PreferenceChangeEvent event) { if (Display.getCurrent() == null) { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { firePropertyChangeEvent(event.getKey(), event.getOldValue(), event.getNewValue()); } }); } else { firePropertyChangeEvent(event.getKey(), event.getOldValue(), event.getNewValue()); } } } /** Listeners on on this adapter */ private final ListenerList fListeners = new ListenerList(ListenerList.IDENTITY); /** Listener on the node */ private final IEclipsePreferences.IPreferenceChangeListener fListener = new PreferenceChangeListener(); /** wrapped node */ private final IScopeContext fContext; private final String fQualifier; /** * Initialize with the node to wrap * * @param context the context to access * @param qualifier the qualifier */ public EclipsePreferencesAdapter(IScopeContext context, String qualifier) { fContext = context; fQualifier = qualifier; } /** * {@inheritDoc} */ @Override public void addPropertyChangeListener(IPropertyChangeListener listener) { if (fListeners.size() == 0) { getNode().addPreferenceChangeListener(fListener); } fListeners.add(listener); } /** * {@inheritDoc} */ @Override public boolean contains(String name) { return getNode().get(name, null) != null; } /** * {@inheritDoc} */ @Override public void firePropertyChangeEvent(String name, Object oldValue, Object newValue) { PropertyChangeEvent event = new PropertyChangeEvent(this, name, oldValue, newValue); Object[] listeners = fListeners.getListeners(); for (int i = 0; i < listeners.length; i++) { ((IPropertyChangeListener) listeners[i]).propertyChange(event); } } /** * {@inheritDoc} */ @Override public boolean getBoolean(String name) { return getNode().getBoolean(name, BOOLEAN_DEFAULT_DEFAULT); } /** * {@inheritDoc} */ @Override public boolean getDefaultBoolean(String name) { return BOOLEAN_DEFAULT_DEFAULT; } /** * {@inheritDoc} */ @Override public double getDefaultDouble(String name) { return DOUBLE_DEFAULT_DEFAULT; } /** * {@inheritDoc} */ @Override public float getDefaultFloat(String name) { return FLOAT_DEFAULT_DEFAULT; } /** * {@inheritDoc} */ @Override public int getDefaultInt(String name) { return INT_DEFAULT_DEFAULT; } /** * {@inheritDoc} */ @Override public long getDefaultLong(String name) { return LONG_DEFAULT_DEFAULT; } /** * {@inheritDoc} */ @Override public String getDefaultString(String name) { return STRING_DEFAULT_DEFAULT; } /** * {@inheritDoc} */ @Override public double getDouble(String name) { return getNode().getDouble(name, DOUBLE_DEFAULT_DEFAULT); } /** * {@inheritDoc} */ @Override public float getFloat(String name) { return getNode().getFloat(name, FLOAT_DEFAULT_DEFAULT); } /** * {@inheritDoc} */ @Override public int getInt(String name) { return getNode().getInt(name, INT_DEFAULT_DEFAULT); } /** * {@inheritDoc} */ @Override public long getLong(String name) { return getNode().getLong(name, LONG_DEFAULT_DEFAULT); } /** * {@inheritDoc} */ @Override public String getString(String name) { return getNode().get(name, STRING_DEFAULT_DEFAULT); } /** * {@inheritDoc} */ @Override public boolean isDefault(String name) { return false; } /** * {@inheritDoc} */ @Override public boolean needsSaving() { try { return getNode().keys().length > 0; } catch (BackingStoreException e) { // ignore } return true; } /** * {@inheritDoc} */ @Override public void putValue(String name, String value) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ @Override public void removePropertyChangeListener(IPropertyChangeListener listener) { fListeners.remove(listener); if (fListeners.size() == 0) { getNode().removePreferenceChangeListener(fListener); } } /** * {@inheritDoc} */ @Override public void setDefault(String name, boolean value) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ @Override public void setDefault(String name, double value) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ @Override public void setDefault(String name, float value) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ @Override public void setDefault(String name, int value) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ @Override public void setDefault(String name, long value) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ @Override public void setDefault(String name, String defaultObject) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ @Override public void setToDefault(String name) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ @Override public void setValue(String name, boolean value) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ @Override public void setValue(String name, double value) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ @Override public void setValue(String name, float value) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ @Override public void setValue(String name, int value) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ @Override public void setValue(String name, long value) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ @Override public void setValue(String name, String value) { throw new UnsupportedOperationException(); } private IEclipsePreferences getNode() { return fContext.getNode(fQualifier); } } /** * Updates the outline page selection and this editor's range indicator. */ private class EditorSelectionChangedListener extends AbstractSelectionChangedListener { /* * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged( * org.eclipse.jface.viewers.SelectionChangedEvent) */ @Override public void selectionChanged(SelectionChangedEvent event) { // XXX: see https://bugs.eclipse.org/bugs/show_bug.cgi?id=56161 DartEditor.this.selectionChanged(); } } /** * Runner that will toggle folding either instantly (if the editor is visible) or the next time it * becomes visible. If a runner is started when there is already one registered, the registered * one is canceled as toggling folding twice is a no-op. * <p> * The access to the fFoldingRunner field is not thread-safe, it is assumed that * <code>runWhenNextVisible</code> is only called from the UI thread. * </p> */ private final class ToggleFoldingRunner implements IPartListener2 { /** * The workbench page we registered the part listener with, or <code>null</code>. */ private IWorkbenchPage fPage; @Override public void partActivated(IWorkbenchPartReference partRef) { } @Override public void partBroughtToTop(IWorkbenchPartReference partRef) { } /* * @see org.eclipse.ui.IPartListener2#partClosed(org.eclipse.ui. IWorkbenchPartReference) */ @Override public void partClosed(IWorkbenchPartReference partRef) { if (DartEditor.this.equals(partRef.getPart(false))) { cancel(); } } @Override public void partDeactivated(IWorkbenchPartReference partRef) { } @Override public void partHidden(IWorkbenchPartReference partRef) { } @Override public void partInputChanged(IWorkbenchPartReference partRef) { } @Override public void partOpened(IWorkbenchPartReference partRef) { } /* * @see org.eclipse.ui.IPartListener2#partVisible(org.eclipse.ui. IWorkbenchPartReference) */ @Override public void partVisible(IWorkbenchPartReference partRef) { if (DartEditor.this.equals(partRef.getPart(false))) { cancel(); toggleFolding(); } } /** * Makes sure that the editor's folding state is correct the next time it becomes visible. If it * already is visible, it toggles the folding state. If not, it either registers a part listener * to toggle folding when the editor becomes visible, or cancels an already registered runner. */ public void runWhenNextVisible() { // if there is one already: toggling twice is the identity if (fFoldingRunner != null) { fFoldingRunner.cancel(); return; } IWorkbenchPartSite site = getSite(); if (site != null) { IWorkbenchPage page = site.getPage(); if (!page.isPartVisible(DartEditor.this)) { // if we're not visible - defer until visible fPage = page; fFoldingRunner = this; page.addPartListener(this); return; } } // we're visible - run now toggleFolding(); } /** * Remove the listener and clear the field. */ private void cancel() { if (fPage != null) { fPage.removePartListener(this); fPage = null; } if (fFoldingRunner == this) { fFoldingRunner = null; } } /** * Does the actual toggling of projection. */ private void toggleFolding() { ISourceViewer sourceViewer = getSourceViewer(); if (sourceViewer instanceof ProjectionViewer) { ProjectionViewer pv = (ProjectionViewer) sourceViewer; if (pv.isProjectionMode() != isFoldingEnabled()) { if (pv.canDoOperation(ProjectionViewer.TOGGLE)) { pv.doOperation(ProjectionViewer.TOGGLE); } } } } } /** 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; protected final static char[] BRACKETS = { '{', '}', '(', ')', '[', ']', '<', '>' }; 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; } } /** The outline page */ protected DartOutlinePage fOutlinePage; /** Outliner context menu Id */ protected String fOutlinerContextMenuId; /** * The editor selection changed listener. */ private EditorSelectionChangedListener fEditorSelectionChangedListener; /** The editor's bracket matcher */ protected DartPairMatcher fBracketMatcher = new DartPairMatcher(BRACKETS); /** This editor's encoding support */ private DefaultEncodingSupport fEncodingSupport; /** History for structure select action */ private SelectionHistory fSelectionHistory; protected CompositeActionGroup fActionGroups; /** * The action group for folding. */ private FoldingActionGroup fFoldingGroup; private CompositeActionGroup fOpenEditorActionGroup; /** * Removes trailing whitespace on editor saves. */ private RemoveTrailingWhitespaceAction removeTrailingWhitespaceAction; /** * Holds the current occurrence annotations. */ private Annotation[] fOccurrenceAnnotations = null; /** * Tells whether all occurrences of the element at the current caret location are automatically * marked in this editor. */ private boolean fMarkOccurrenceAnnotations; /** * Tells whether the occurrence annotations are sticky i.e. whether they stay even if there's no * valid Dart element at the current caret position. Only valid if * {@link #fMarkOccurrenceAnnotations} is <code>true</code>. */ private boolean fStickyOccurrenceAnnotations; /** * Tells whether to mark type occurrences in this editor. Only valid if * {@link #fMarkOccurrenceAnnotations} is <code>true</code>. */ private boolean fMarkTypeOccurrences; /** * Tells whether to mark method occurrences in this editor. Only valid if * {@link #fMarkOccurrenceAnnotations} is <code>true</code>. */ private boolean fMarkMethodOccurrences; /** * Tells whether to mark constant occurrences in this editor. Only valid if * {@link #fMarkOccurrenceAnnotations} is <code>true</code>. */ private boolean fMarkConstantOccurrences; /** * Tells whether to mark field occurrences in this editor. Only valid if * {@link #fMarkOccurrenceAnnotations} is <code>true</code>. */ private boolean fMarkFieldOccurrences; /** * Tells whether to mark local variable occurrences in this editor. Only valid if * {@link #fMarkOccurrenceAnnotations} is <code>true</code>. */ private boolean fMarkLocalVariableypeOccurrences; /** * Tells whether to mark exception occurrences in this editor. Only valid if * {@link #fMarkOccurrenceAnnotations} is <code>true</code>. */ private boolean fMarkExceptions; /** * Tells whether to mark method exits in this editor. Only valid if * {@link #fMarkOccurrenceAnnotations} is <code>true</code>. */ private boolean fMarkMethodExitPoints; /** * Tells whether to mark targets of <code>break</code> and <code>continue</code> statements in * this editor. Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>. */ private boolean fMarkBreakContinueTargets; /** * Tells whether to mark implementors in this editor. Only valid if * {@link #fMarkOccurrenceAnnotations} is <code>true</code>. */ private boolean fMarkImplementors; /** * The selection used when forcing occurrence marking through code. */ private ISelection fForcedMarkOccurrencesSelection; /** * The document modification stamp at the time when the last occurrence marking took place. */ private long fMarkOccurrenceModificationStamp = IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; /** * The region of the word under the caret used to when computing the current occurrence markings. */ private IRegion fMarkOccurrenceTargetRegion; /** * The internal shell activation listener for updating occurrences. */ private ActivationListener fActivationListener = new ActivationListener(); private ISelectionListenerWithAST fPostSelectionListenerWithAST; private OccurrencesFinderJob fOccurrencesFinderJob; /** The occurrences finder job canceler */ private OccurrencesFinderJobCanceler fOccurrencesFinderJobCanceler; /** * This editor's projection support */ private ProjectionSupport fProjectionSupport; /** * This editor's projection model updater */ private IDartFoldingStructureProvider fProjectionModelUpdater; /** * The override and implements indicator manager for this editor. */ protected OverrideIndicatorManager fOverrideIndicatorManager; /** * Semantic highlighting manager */ protected SemanticHighlightingManager fSemanticManager; /** * The folding runner. */ private ToggleFoldingRunner fFoldingRunner; /** * Tells whether the selection changed event is caused by a call to * {@link #gotoAnnotation(boolean)}. */ private boolean fSelectionChangedViaGotoAnnotation; /** * The cached selected range. * * @see ITextViewer#getSelectedRange() */ private Point fCachedSelectedRange; /** * A document listener that will clear the AST cache when the contents of the document change. */ private final IDocumentListener astCacheClearer = new IDocumentListener() { @Override public void documentAboutToBeChanged(DocumentEvent event) { } @Override public void documentChanged(DocumentEvent event) { astCache.clear(); } }; /** * The cache used to maintain the AST corresponding to the contents of this editor's document. */ private final ASTCache astCache = new ASTCache(); private boolean isEditableStateKnown; private boolean isEditable; private OpenCallHierarchyAction openCallHierarchy; /** * Default constructor. */ public DartEditor() { super(); } /** * Collapses all foldable comments if supported by the folding structure provider. */ public void collapseComments() { DartX.todo("folding"); if (fProjectionModelUpdater instanceof IDartFoldingStructureProviderExtension) { IDartFoldingStructureProviderExtension extension = (IDartFoldingStructureProviderExtension) fProjectionModelUpdater; extension.collapseComments(); } } /** * Collapses all foldable members if supported by the folding structure provider. */ public void collapseMembers() { DartX.todo("folding"); if (fProjectionModelUpdater instanceof IDartFoldingStructureProviderExtension) { IDartFoldingStructureProviderExtension extension = (IDartFoldingStructureProviderExtension) fProjectionModelUpdater; extension.collapseMembers(); } } /* * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt.widgets .Composite) */ @Override public void createPartControl(Composite parent) { super.createPartControl(parent); fEditorSelectionChangedListener = new EditorSelectionChangedListener(); fEditorSelectionChangedListener.install(getSelectionProvider()); if (isSemanticHighlightingEnabled()) { installSemanticHighlighting(); } PlatformUI.getWorkbench().addWindowListener(fActivationListener); } /* * @see IWorkbenchPart#dispose() */ @Override public void dispose() { DartX.todo("folding"); if (fProjectionModelUpdater != null) { fProjectionModelUpdater.uninstall(); fProjectionModelUpdater = null; } if (fProjectionSupport != null) { fProjectionSupport.dispose(); fProjectionSupport = null; } // cancel possible running computation fMarkOccurrenceAnnotations = false; uninstallOccurrencesFinder(); uninstallOverrideIndicator(); uninstallSemanticHighlighting(); if (fActivationListener != null) { PlatformUI.getWorkbench().removeWindowListener(fActivationListener); fActivationListener = null; } if (fEncodingSupport != null) { fEncodingSupport.dispose(); fEncodingSupport = null; } if (fBracketMatcher != null) { fBracketMatcher.dispose(); fBracketMatcher = null; } if (fSelectionHistory != null) { fSelectionHistory.dispose(); fSelectionHistory = null; } if (fEditorSelectionChangedListener != null) { fEditorSelectionChangedListener.uninstall(getSelectionProvider()); fEditorSelectionChangedListener = null; } if (fActionGroups != null) { fActionGroups.dispose(); fActionGroups = null; } super.dispose(); } /* * @see AbstractTextEditor#editorContextMenuAboutToShow */ @Override public void editorContextMenuAboutToShow(IMenuManager menu) { menu.add(new Separator(ITextEditorActionConstants.GROUP_OPEN)); menu.add(new Separator(ITextEditorActionConstants.GROUP_EDIT)); // TODO: Is this the right group to be using? menu.add(new Separator(ITextEditorActionConstants.GROUP_RESTORE)); menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); // Open Declaration action ActionContext context = new ActionContext(getSelectionProvider().getSelection()); fOpenEditorActionGroup.setContext(context); fOpenEditorActionGroup.fillContextMenu(menu); fOpenEditorActionGroup.setContext(null); // Quick Outline { IAction action = getAction(DartEditorActionDefinitionIds.SHOW_OUTLINE); menu.appendToGroup(IContextMenuConstants.GROUP_OPEN, action); } // Cut/Copy/Paste actions addAction(menu, ITextEditorActionConstants.GROUP_EDIT, ITextEditorActionConstants.UNDO); addAction(menu, ITextEditorActionConstants.GROUP_EDIT, ITextEditorActionConstants.CUT); addAction(menu, ITextEditorActionConstants.GROUP_EDIT, ITextEditorActionConstants.COPY); addAction(menu, ITextEditorActionConstants.GROUP_EDIT, ITextEditorActionConstants.PASTE); // Revert action addAction(menu, ITextEditorActionConstants.GROUP_RESTORE, ITextEditorActionConstants.REVERT_TO_SAVED); // Quick Assist { IAction action = getAction(ITextEditorActionConstants.QUICK_ASSIST); if (action != null && action.isEnabled()) { addAction(menu, ITextEditorActionConstants.GROUP_EDIT, ITextEditorActionConstants.QUICK_ASSIST); } } } /* * @see AbstractTextEditor#getAdapter(Class) */ @SuppressWarnings("rawtypes") @Override public Object getAdapter(Class required) { DartX.todo("outline"); 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() { @Override public String[] getShowInTargetIds() { String explorerViewID = ProductProperties .getProperty(IProductConstants.PERSPECTIVE_EXPLORER_VIEW); // make sure the specified view ID is known if (PlatformUI.getWorkbench().getViewRegistry().find(explorerViewID) == null) { explorerViewID = IPageLayout.ID_PROJECT_EXPLORER; } return new String[] { explorerViewID, IPageLayout.ID_OUTLINE, IPageLayout.ID_RES_NAV }; } }; } DartX.todo("hover"); if (required == IShowInSource.class) { return new IShowInSource() { @Override public ShowInContext getShowInContext() { return new ShowInContext(getEditorInput(), null) { /* * @see org.eclipse.ui.part.ShowInContext#getSelection() */ @Override public ISelection getSelection() { DartElement je = null; try { je = SelectionConverter.getElementAtOffset(DartEditor.this); if (je == null) { return null; } return new StructuredSelection(je); } catch (DartModelException ex) { return null; } } }; } }; } DartX.todo("folding"); if (required == IDartFoldingStructureProvider.class) { return fProjectionModelUpdater; } if (fProjectionSupport != null) { Object adapter = fProjectionSupport.getAdapter(getSourceViewer(), required); if (adapter != null) { return adapter; } } if (required == IContextProvider.class) { return DartUIHelp.getHelpContextProvider(this, DartHelpContextIds.JAVA_EDITOR); } return super.getAdapter(required); } /** * Return the AST structure corresponding to the current contents of this editor's document, or * <code>null</code> if the AST structure cannot be created. * * @return the AST structure corresponding to the current contents of this editor's document */ public DartUnit getAST() { DartUnit ast; synchronized (astCache) { ast = astCache.getAST(); } if (ast == null) { // There is a small chance that another thread could ask for the AST while we are computing // the AST, in which case we would compute the AST twice when we don't need to. try { long creationTime = System.nanoTime(); DartElement dartElement = getInputDartElement(); if (dartElement != null) { CompilationUnit input = dartElement.getAncestor(CompilationUnit.class); if (input != null) { ast = DartCompilerUtilities.resolveUnit(input); if (ast != null) { synchronized (astCache) { astCache.setAST(creationTime, ast); } } } } } catch (Throwable exception) { // Catch all exceptions so that a failure to create an AST cannot stop other actions. DartToolsPlugin.log(exception); } } return ast; } /** * Returns the cached selected range, which allows to query it from a non-UI thread. * <p> * The result might be outdated if queried from a non-UI thread.</em> * </p> * * @return the caret offset in the master document * @see ITextViewer#getSelectedRange() */ public Point getCachedSelectedRange() { return fCachedSelectedRange; } /* * @see org.eclipse.ui.part.WorkbenchPart#getOrientation() */ @Override public int getOrientation() { return SWT.LEFT_TO_RIGHT; // Dart editors are always left to right by default } @Override public String getTitleToolTip() { if (getEditorInput() instanceof IFileEditorInput) { IFileEditorInput input = (IFileEditorInput) getEditorInput(); if (input.getFile().getLocation() != null) { return input.getFile().getLocation().toFile().toString(); } } return super.getTitleToolTip(); } public final ISourceViewer getViewer() { return getSourceViewer(); } /* * @see com.google.dart.tools.ui.internal.viewsupport.IViewPartInputProvider# getViewPartInput () */ @Override public Object getViewPartInput() { return getEditorInput().getAdapter(DartElement.class); } /* * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#gotoAnnotation(boolean ) */ @Override public Annotation gotoAnnotation(boolean forward) { fSelectionChangedViaGotoAnnotation = true; return super.gotoAnnotation(forward); } /** * 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(DartEditorMessages.GotoMatchingBracket_error_invalidSelection); 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(DartEditorMessages.GotoMatchingBracket_error_noMatchingBracket); 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 = ICharacterPairMatcher.RIGHT == anchor ? offset + 1 : offset + length; boolean visible = false; if (sourceViewer instanceof ITextViewerExtension5) { ITextViewerExtension5 extension = (ITextViewerExtension5) 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(DartEditorMessages.GotoMatchingBracket_error_bracketOutsideSelectedElement); sourceViewer.getTextWidget().getDisplay().beep(); return; } if (selection.getLength() < 0) { targetOffset -= selection.getLength(); } sourceViewer.setSelectedRange(targetOffset, selection.getLength()); sourceViewer.revealRange(targetOffset, selection.getLength()); } @Override public boolean isDirty() { return isContentEditable() ? super.isDirty() : false; } @Override public boolean isEditable() { return isContentEditable() ? super.isEditable() : false; } @Override public boolean isEditorInputModifiable() { return isContentEditable() ? super.isEditorInputModifiable() : false; } @Override public boolean isEditorInputReadOnly() { return isContentEditable() ? super.isEditorInputReadOnly() : true; } /** * Informs the editor that its outliner has been closed. */ public void outlinePageClosed() { if (fOutlinePage != null) { fOutlinePage = null; resetHighlightRange(); } } /** * Resets the foldings structure according to the folding preferences. */ public void resetProjection() { DartX.todo("folding"); if (fProjectionModelUpdater != null) { fProjectionModelUpdater.initialize(); } } /** * Sets the AST resolved at the given moment of time. */ public void setAST(long creaitonTime, DartUnit ast) { synchronized (astCache) { astCache.setAST(creaitonTime, ast); } } public void setSelection(DartElement element) { if (element == null || element instanceof CompilationUnit) { /* * If the element is an CompilationUnit this unit is either the input of this editor or not * being displayed. In both cases, nothing should happened. */ return; } DartElement corresponding = getCorrespondingElement(element); if (corresponding instanceof SourceReference) { SourceReference reference = (SourceReference) corresponding; // set highlight range setSelection(reference, true); // set outliner selection if (fOutlinePage != null) { fOutlinePage.select(reference); } } } /** * Synchronizes the outliner selection with the actual cursor position in the editor. */ public void synchronizeOutlinePageSelection() { synchronizeOutlinePage(computeHighlightRangeSourceReference()); } public void updatedTitleImage(Image image) { setTitleImage(image); } /* * @see AbstractTextEditor#adjustHighlightRange(int, int) */ @Override protected void adjustHighlightRange(int offset, int length) { try { DartElement element = getElementAt(offset, false); while (element instanceof SourceReference) { SourceRange range = ((SourceReference) element).getSourceRange(); if (range != null && offset < range.getOffset() + range.getLength() && range.getOffset() < offset + length) { ISourceViewer viewer = getSourceViewer(); if (viewer instanceof ITextViewerExtension5) { ITextViewerExtension5 extension = (ITextViewerExtension5) viewer; extension.exposeModelRange(new Region(range.getOffset(), range.getLength())); } setHighlightRange(range.getOffset(), range.getLength(), true); if (fOutlinePage != null) { fOutlinePage.select((SourceReference) element); } return; } element = element.getParent(); } } catch (DartModelException x) { DartToolsPlugin.log(x.getStatus()); } ISourceViewer viewer = getSourceViewer(); if (viewer instanceof ITextViewerExtension5) { ITextViewerExtension5 extension = (ITextViewerExtension5) viewer; extension.exposeModelRange(new Region(offset, length)); } else { resetHighlightRange(); } } /** * Determines whether the preference change encoded by the given event changes the override * indication. * * @param event the event to be investigated * @return <code>true</code> if event causes a change */ protected boolean affectsOverrideIndicatorAnnotations(PropertyChangeEvent event) { String key = event.getProperty(); AnnotationPreference preference = getAnnotationPreferenceLookup() .getAnnotationPreference(OverrideIndicatorManager.ANNOTATION_TYPE); if (key == null || preference == null) { return false; } return key.equals(preference.getHighlightPreferenceKey()) || key.equals(preference.getVerticalRulerPreferenceKey()) || key.equals(preference.getOverviewRulerPreferenceKey()) || key.equals(preference.getTextPreferenceKey()); } /* * @see AbstractTextEditor#affectsTextPresentation(PropertyChangeEvent) */ @Override protected boolean affectsTextPresentation(PropertyChangeEvent event) { return ((DartSourceViewerConfiguration) getSourceViewerConfiguration()).affectsTextPresentation(event) || super.affectsTextPresentation(event); } protected void checkEditableState() { isEditableStateKnown = false; } /* * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor# collectContextMenuPreferencePages() */ @Override protected String[] collectContextMenuPreferencePages() { String[] inheritedPages = super.collectContextMenuPreferencePages(); int length = 10; String[] result = new String[inheritedPages.length + length]; result[0] = "com.google.dart.tools.ui.internal.preferences.JavaEditorPreferencePage"; //$NON-NLS-1$ result[1] = "com.google.dart.tools.ui.internal.preferences.JavaTemplatePreferencePage"; //$NON-NLS-1$ result[2] = "com.google.dart.tools.ui.internal.preferences.CodeAssistPreferencePage"; //$NON-NLS-1$ result[3] = "com.google.dart.tools.ui.internal.preferences.CodeAssistPreferenceAdvanced"; //$NON-NLS-1$ result[4] = "com.google.dart.tools.ui.internal.preferences.JavaEditorHoverPreferencePage"; //$NON-NLS-1$ result[5] = "com.google.dart.tools.ui.internal.preferences.JavaEditorColoringPreferencePage"; //$NON-NLS-1$ result[6] = "com.google.dart.tools.ui.internal.preferences.FoldingPreferencePage"; //$NON-NLS-1$ result[7] = "com.google.dart.tools.ui.internal.preferences.MarkOccurrencesPreferencePage"; //$NON-NLS-1$ result[8] = "com.google.dart.tools.ui.internal.preferences.SmartTypingPreferencePage"; //$NON-NLS-1$ result[9] = "com.google.dart.tools.ui.internal.preferences.SaveParticipantPreferencePage"; //$NON-NLS-1$ System.arraycopy(inheritedPages, 0, result, length, inheritedPages.length); return result; } /** * 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 */ protected SourceReference computeHighlightRangeSourceReference() { ISourceViewer sourceViewer = getSourceViewer(); if (sourceViewer == null) { return null; } StyledText styledText = sourceViewer.getTextWidget(); if (styledText == null) { return null; } int caret = 0; if (sourceViewer instanceof ITextViewerExtension5) { ITextViewerExtension5 extension = (ITextViewerExtension5) sourceViewer; caret = extension.widgetOffset2ModelOffset(styledText.getCaretOffset()); } else { int offset = sourceViewer.getVisibleRegion().getOffset(); caret = offset + styledText.getCaretOffset(); } DartElement element = getElementAt(caret, false); if (!(element instanceof SourceReference)) { return null; } return (SourceReference) element; } @Override protected void configureSourceViewerDecorationSupport(SourceViewerDecorationSupport support) { fBracketMatcher.setSourceVersion(getPreferenceStore().getString(JavaScriptCore.COMPILER_SOURCE)); support.setCharacterPairMatcher(fBracketMatcher); support.setMatchingCharacterPainterPreferenceKeys(MATCHING_BRACKETS, MATCHING_BRACKETS_COLOR); super.configureSourceViewerDecorationSupport(support); } @Override protected void createActions() { installEncodingSupport(); super.createActions(); DartX.todo("actions"); ActionGroup oeg, ovg; ActionGroup jsg; fActionGroups = new CompositeActionGroup(new ActionGroup[] { oeg = new OpenEditorActionGroup(this), ovg = new OpenViewActionGroup(this), jsg = new DartSearchActionGroup(this) }); fOpenEditorActionGroup = new CompositeActionGroup(new ActionGroup[] { ovg, oeg, jsg }); // Registers the folding actions with the editor fFoldingGroup = new FoldingActionGroup(this, getViewer()); Action action = new GotoMatchingBracketAction(this); action.setActionDefinitionId(DartEditorActionDefinitionIds.GOTO_MATCHING_BRACKET); setAction(GotoMatchingBracketAction.GOTO_MATCHING_BRACKET, action); openCallHierarchy = new OpenCallHierarchyAction(this); openCallHierarchy.setActionDefinitionId(DartEditorActionDefinitionIds.ANALYZE_CALL_HIERARCHY); setAction(DartEditorActionDefinitionIds.ANALYZE_CALL_HIERARCHY, openCallHierarchy); //$NON-NLS-1$ PlatformUI.getWorkbench().getHelpSystem().setHelp(action, DartHelpContextIds.CALL_HIERARCHY_VIEW); action = new TextOperationAction(DartEditorMessages.getBundleForConstructedKeys(), "ShowOutline.", this, //$NON-NLS-1$ DartSourceViewer.SHOW_OUTLINE, true); action.setActionDefinitionId(DartEditorActionDefinitionIds.SHOW_OUTLINE); setAction(DartEditorActionDefinitionIds.SHOW_OUTLINE, action); PlatformUI.getWorkbench().getHelpSystem().setHelp(action, DartHelpContextIds.SHOW_OUTLINE_ACTION); action = new TextOperationAction(DartEditorMessages.getBundleForConstructedKeys(), "OpenStructure.", this, //$NON-NLS-1$ DartSourceViewer.OPEN_STRUCTURE, true); action.setActionDefinitionId(DartEditorActionDefinitionIds.OPEN_STRUCTURE); setAction(DartEditorActionDefinitionIds.OPEN_STRUCTURE, action); PlatformUI.getWorkbench().getHelpSystem().setHelp(action, DartHelpContextIds.OPEN_STRUCTURE_ACTION); action = new TextOperationAction(DartEditorMessages.getBundleForConstructedKeys(), "OpenHierarchy.", this, //$NON-NLS-1$ DartSourceViewer.SHOW_HIERARCHY, true); action.setActionDefinitionId(DartEditorActionDefinitionIds.OPEN_HIERARCHY); setAction(DartEditorActionDefinitionIds.OPEN_HIERARCHY, action); PlatformUI.getWorkbench().getHelpSystem().setHelp(action, DartHelpContextIds.OPEN_HIERARCHY_ACTION); fSelectionHistory = new SelectionHistory(this); action = new StructureSelectEnclosingAction(this, fSelectionHistory); action.setActionDefinitionId(DartEditorActionDefinitionIds.SELECT_ENCLOSING); setAction(StructureSelectionAction.ENCLOSING, action); action = new StructureSelectNextAction(this, fSelectionHistory); action.setActionDefinitionId(DartEditorActionDefinitionIds.SELECT_NEXT); setAction(StructureSelectionAction.NEXT, action); action = new StructureSelectPreviousAction(this, fSelectionHistory); action.setActionDefinitionId(DartEditorActionDefinitionIds.SELECT_PREVIOUS); setAction(StructureSelectionAction.PREVIOUS, action); StructureSelectHistoryAction historyAction = new StructureSelectHistoryAction(this, fSelectionHistory); historyAction.setActionDefinitionId(DartEditorActionDefinitionIds.SELECT_LAST); setAction(StructureSelectionAction.HISTORY, historyAction); fSelectionHistory.setHistoryAction(historyAction); action = GoToNextPreviousMemberAction.newGoToNextMemberAction(this); action.setActionDefinitionId(DartEditorActionDefinitionIds.GOTO_NEXT_MEMBER); setAction(GoToNextPreviousMemberAction.NEXT_MEMBER, action); action = GoToNextPreviousMemberAction.newGoToPreviousMemberAction(this); action.setActionDefinitionId(DartEditorActionDefinitionIds.GOTO_PREVIOUS_MEMBER); setAction(GoToNextPreviousMemberAction.PREVIOUS_MEMBER, action); action = new FormatElementAction(); action.setActionDefinitionId(DartEditorActionDefinitionIds.QUICK_FORMAT); setAction("QuickFormat", action); //$NON-NLS-1$ markAsStateDependentAction("QuickFormat", true); //$NON-NLS-1$ action = new RemoveOccurrenceAnnotations(this); action.setActionDefinitionId(DartEditorActionDefinitionIds.REMOVE_OCCURRENCE_ANNOTATIONS); setAction("RemoveOccurrenceAnnotations", action); //$NON-NLS-1$ // add annotation actions for roll-over expand hover action = new DartSelectMarkerRulerAction2(DartEditorMessages.getBundleForConstructedKeys(), "Editor.RulerAnnotationSelection.", this); //$NON-NLS-1$ setAction("AnnotationAction", action); //$NON-NLS-1$ DartX.todo(); // action = new ShowInPackageViewAction(this); // action.setActionDefinitionId(IJavaEditorActionDefinitionIds.SHOW_IN_PACKAGE_VIEW); // setAction("ShowInPackageView", action); //$NON-NLS-1$ // replace cut/copy paste actions with a version that implement 'add imports // on paste' action = new ClipboardOperationAction(DartEditorMessages.getBundleForConstructedKeys(), "Editor.Cut.", this, //$NON-NLS-1$ ITextOperationTarget.CUT); setAction(ITextEditorActionConstants.CUT, action); action = new ClipboardOperationAction(DartEditorMessages.getBundleForConstructedKeys(), "Editor.Copy.", //$NON-NLS-1$ this, ITextOperationTarget.COPY); setAction(ITextEditorActionConstants.COPY, action); action = new ClipboardOperationAction(DartEditorMessages.getBundleForConstructedKeys(), "Editor.Paste.", //$NON-NLS-1$ this, ITextOperationTarget.PASTE); setAction(ITextEditorActionConstants.PASTE, action); DartX.todo(); // action = new CopyQualifiedNameAction(this); // setAction(IDartEditorActionConstants.COPY_QUALIFIED_NAME, action); removeTrailingWhitespaceAction = new RemoveTrailingWhitespaceAction(getSourceViewer()); } /* * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor# * createAnnotationRulerColumn(org.eclipse.jface.text.source.CompositeRuler) */ @Override protected IVerticalRulerColumn createAnnotationRulerColumn(CompositeRuler ruler) { DartX.todo(); return super.createAnnotationRulerColumn(ruler); // if (!getPreferenceStore().getBoolean( // PreferenceConstants.EDITOR_ANNOTATION_ROLL_OVER)) // return super.createAnnotationRulerColumn(ruler); // // AnnotationRulerColumn column = new AnnotationRulerColumn( // VERTICAL_RULER_WIDTH, getAnnotationAccess()); // column.setHover(new JavaExpandHover(ruler, getAnnotationAccess(), // new IDoubleClickListener() { // // public void doubleClick(DoubleClickEvent event) { // // for now: just invoke ruler double click action // triggerAction(ITextEditorActionConstants.RULER_DOUBLE_CLICK); // } // // private void triggerAction(String actionID) { // IAction action = getAction(actionID); // if (action != null) { // if (action instanceof IUpdate) // ((IUpdate) action).update(); // // hack to propagate line change // if (action instanceof ISelectionListener) { // ((ISelectionListener) action).selectionChanged(null, null); // } // if (action.isEnabled()) // action.run(); // } // } // // })); // // return column; } /* * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#createChangeHover() */ @Override protected LineChangeHover createChangeHover() { return new DartChangeHover(DartPartitions.DART_PARTITIONING, getOrientation()); } /* * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int) */ protected ISourceViewer createDartSourceViewer(Composite parent, IVerticalRuler verticalRuler, IOverviewRuler overviewRuler, boolean isOverviewRulerVisible, int styles, IPreferenceStore store) { return new DartSourceViewer(parent, verticalRuler, getOverviewRuler(), isOverviewRulerVisible(), styles, store); } /** * Returns a new Dart source viewer configuration. * * @return a new <code>DartSourceViewerConfiguration</code> */ protected DartSourceViewerConfiguration createDartSourceViewerConfiguration() { DartTextTools textTools = DartToolsPlugin.getDefault().getDartTextTools(); return new DartSourceViewerConfiguration(textTools.getColorManager(), getPreferenceStore(), this, DartPartitions.DART_PARTITIONING); } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#createNavigationActions() */ @Override 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 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); } /** * Creates the outline page used with this editor. * * @return the created Dart outline page */ protected DartOutlinePage createOutlinePage() { DartOutlinePage page = new DartOutlinePage(fOutlinerContextMenuId, this); setOutlinePageInput(page, getEditorInput()); return page; } /* * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int) */ @Override protected final ISourceViewer createSourceViewer(Composite parent, IVerticalRuler verticalRuler, int styles) { IPreferenceStore store = getPreferenceStore(); ISourceViewer viewer = createDartSourceViewer(parent, verticalRuler, getOverviewRuler(), isOverviewRulerVisible(), styles, store); DartUIHelp.setHelp(this, viewer.getTextWidget(), DartHelpContextIds.JAVA_EDITOR); DartSourceViewer dartSourceViewer = null; if (viewer instanceof DartSourceViewer) { dartSourceViewer = (DartSourceViewer) viewer; } /* * This is a performance optimization to reduce the computation of the text presentation * triggered by {@link #setVisibleDocument(IDocument)} */ if (dartSourceViewer != null && isFoldingEnabled() && (store == null || !store.getBoolean(PreferenceConstants.EDITOR_SHOW_SEGMENTS))) { dartSourceViewer.prepareDelayedProjection(); } ProjectionViewer projectionViewer = (ProjectionViewer) viewer; fProjectionSupport = new ProjectionSupport(projectionViewer, getAnnotationAccess(), getSharedColors()); fProjectionSupport.addSummarizableAnnotationType("org.eclipse.ui.workbench.texteditor.error"); //$NON-NLS-1$ fProjectionSupport.addSummarizableAnnotationType("org.eclipse.ui.workbench.texteditor.warning"); //$NON-NLS-1$ DartX.todo("hover"); fProjectionSupport.setHoverControlCreator(new IInformationControlCreator() { @Override public IInformationControl createInformationControl(Shell shell) { return new SourceViewerInformationControl(shell, SWT.TOOL | SWT.NO_TRIM | getOrientation(), SWT.NONE, EditorsUI.getTooltipAffordanceString()); } }); fProjectionSupport.setInformationPresenterControlCreator(new IInformationControlCreator() { @Override public IInformationControl createInformationControl(Shell shell) { int shellStyle = SWT.RESIZE | SWT.TOOL | getOrientation(); int style = SWT.V_SCROLL | SWT.H_SCROLL; return new SourceViewerInformationControl(shell, shellStyle, style); } }); fProjectionSupport.install(); fProjectionModelUpdater = DartToolsPlugin.getDefault().getFoldingStructureProviderRegistry() .getCurrentFoldingProvider(); if (fProjectionModelUpdater != null) { fProjectionModelUpdater.install(this, projectionViewer); } // ensure source viewer decoration support has been created and configured getSourceViewerDecorationSupport(viewer); // // Add the required listeners so that changes to the document will cause the AST structure to be // flushed. // viewer.addTextInputListener(new ITextInputListener() { @Override public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { } @Override public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { if (newInput != null) { newInput.addDocumentListener(astCacheClearer); } astCache.clear(); } }); IDocument document = getDocumentProvider().getDocument(null); if (document != null) { document.addDocumentListener(astCacheClearer); } return viewer; } protected void doSelectionChanged(ISelection selection) { SourceReference reference = null; Iterator<?> iter = ((IStructuredSelection) selection).iterator(); while (iter.hasNext()) { Object o = iter.next(); if (o instanceof SourceReference) { reference = (SourceReference) o; break; } } if (!isActivePart() && DartToolsPlugin.getActivePage() != null) { DartToolsPlugin.getActivePage().bringToTop(this); } setSelection(reference, !isActivePart()); ISelectionProvider selectionProvider = getSelectionProvider(); if (selectionProvider == null) { return; } ISelection textSelection = selectionProvider.getSelection(); if (!(textSelection instanceof ITextSelection)) { return; } DartElement inputElement = getInputDartElement(); if (inputElement == null) { return; } DartUnit ast = DartToolsPlugin.getDefault().getASTProvider().getAST(inputElement, ASTProvider.WAIT_NO, getProgressMonitor()); if (ast != null) { fForcedMarkOccurrencesSelection = textSelection; updateOccurrenceAnnotations((ITextSelection) textSelection, ast); } } /* * @see AbstractTextEditor#doSetInput */ @Override protected void doSetInput(IEditorInput input) throws CoreException { ISourceViewer sourceViewer = getSourceViewer(); if (!(sourceViewer instanceof ISourceViewerExtension2)) { setPreferenceStore(createCombinedPreferenceStore(input)); internalDoSetInput(input); return; } // uninstall & unregister preference store listener getSourceViewerDecorationSupport(sourceViewer).uninstall(); ((ISourceViewerExtension2) sourceViewer).unconfigure(); setPreferenceStore(createCombinedPreferenceStore(input)); // install & register preference store listener sourceViewer.configure(getSourceViewerConfiguration()); getSourceViewerDecorationSupport(sourceViewer).install(getPreferenceStore()); internalDoSetInput(input); } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#doSetSelection(ISelection) */ @Override protected void doSetSelection(ISelection selection) { super.doSetSelection(selection); synchronizeOutlinePageSelection(); } /** * {@inheritDoc} * <p> * Overrides the default implementation to handle {@link IJavaAnnotation}. * </p> * * @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 */ @Override protected Annotation findAnnotation(final int offset, final 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 = Integer.MAX_VALUE; IAnnotationModel model = getDocumentProvider().getAnnotationModel(getEditorInput()); @SuppressWarnings("rawtypes") Iterator e = new DartAnnotationIterator(model, true, true); while (e.hasNext()) { Annotation a = (Annotation) e.next(); if (a instanceof IJavaAnnotation && ((IJavaAnnotation) a).hasOverlay() || !isNavigationTarget(a)) { continue; } Position p = model.getPosition(a); if (p == null) { continue; } if (forward && p.offset == offset || !forward && p.offset + p.getLength() == offset + length) {// || // p.includes(offset)) // { if (containingAnnotation == null || forward && p.length >= containingAnnotationPosition.length || !forward && p.length >= containingAnnotationPosition.length) { containingAnnotation = a; containingAnnotationPosition = p; currentAnnotation = p.length == length; } } else { int currentDistance = 0; if (forward) { currentDistance = p.getOffset() - offset; if (currentDistance < 0) { currentDistance = endOfDocument + currentDistance; } if (currentDistance < distance || currentDistance == distance && p.length < nextAnnotationPosition.length) { distance = currentDistance; nextAnnotation = a; nextAnnotationPosition = p; } } else { currentDistance = offset + length - (p.getOffset() + p.length); if (currentDistance < 0) { currentDistance = endOfDocument + currentDistance; } if (currentDistance < distance || currentDistance == distance && p.length < nextAnnotationPosition.length) { distance = currentDistance; nextAnnotation = a; nextAnnotationPosition = p; } } } } 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 standard action group of this editor. * * @return returns this editor's standard action group */ protected ActionGroup getActionGroup() { return fActionGroups; } /** * Returns the Dart element of this editor's input corresponding to the given DartElement. * * @param element the Dart element * @return the corresponding Dart element */ abstract protected DartElement getCorrespondingElement(DartElement element); /** * Returns the most narrow Dart element including the given offset. * * @param offset the offset inside of the requested element * @return the most narrow Dart element */ abstract protected DartElement getElementAt(int offset); /** * Returns the most narrow Dart 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 element */ protected DartElement getElementAt(int offset, boolean reconcile) { return getElementAt(offset); } /** * Returns the folding action group, or <code>null</code> if there is none. * * @return the folding action group, or <code>null</code> if there is none */ protected FoldingActionGroup getFoldingActionGroup() { return fFoldingGroup; } /** * Returns the Dart element wrapped by this editors input. * * @return the Dart element wrapped by this editors input. */ protected DartElement getInputDartElement() { return EditorUtility.getEditorInputDartElement(this, false); } /** * Returns the signed current selection. The length will be negative if the resulting selection is * right-to-left (RtoL). * <p> * The selection offset is model based. * </p> * * @param sourceViewer the source viewer * @return a region denoting the current signed selection, for a resulting RtoL selections length * is < 0 */ protected IRegion getSignedSelection(ISourceViewer sourceViewer) { StyledText text = sourceViewer.getTextWidget(); Point selection = text.getSelectionRange(); if (text.getCaretOffset() == selection.x) { selection.x = selection.x + selection.y; selection.y = -selection.y; } selection.x = widgetOffset2ModelOffset(sourceViewer, selection.x); return new Region(selection.x, selection.y); } /* * @see StatusTextEditor#getStatusBanner(IStatus) */ @Override protected String getStatusBanner(IStatus status) { if (fEncodingSupport != null) { String message = fEncodingSupport.getStatusBanner(status); if (message != null) { return message; } } return super.getStatusBanner(status); } /* * @see StatusTextEditor#getStatusHeader(IStatus) */ @Override protected String getStatusHeader(IStatus status) { if (fEncodingSupport != null) { String message = fEncodingSupport.getStatusHeader(status); if (message != null) { return message; } } return super.getStatusHeader(status); } /* * @see StatusTextEditor#getStatusMessage(IStatus) */ @Override protected String getStatusMessage(IStatus status) { if (fEncodingSupport != null) { String message = fEncodingSupport.getStatusMessage(status); if (message != null) { return message; } } return super.getStatusMessage(status); } /* * @see AbstractTextEditor#getUndoRedoOperationApprover(IUndoContext) */ @Override protected IOperationApprover getUndoRedoOperationApprover(IUndoContext undoContext) { // since IResource is a more general way to compare dart elements, we // use this as the preferred class for comparing objects. return new NonLocalUndoUserApprover(undoContext, this, new Object[] { getInputDartElement() }, IResource.class); } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#handleCursorPositionChanged() */ @Override protected void handleCursorPositionChanged() { super.handleCursorPositionChanged(); fCachedSelectedRange = getViewer().getSelectedRange(); } /* * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent) */ @Override protected void handlePreferenceStoreChanged(PropertyChangeEvent event) { String property = event.getProperty(); if (AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH.equals(property)) { /* * Ignore tab setting since we rely on the formatter preferences. We do this outside the * try-finally block to avoid that EDITOR_TAB_WIDTH is handled by the sub-class * (AbstractDecoratedTextEditor). */ return; } try { ISourceViewer sourceViewer = getSourceViewer(); if (sourceViewer == null) { return; } if (isEditorHoverProperty(property)) { updateHoverBehavior(); } boolean newBooleanValue = false; Object newValue = event.getNewValue(); if (newValue != null) { newBooleanValue = Boolean.valueOf(newValue.toString()).booleanValue(); } if (PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE.equals(property)) { if (newBooleanValue) { selectionChanged(); } return; } if (PreferenceConstants.EDITOR_MARK_OCCURRENCES.equals(property)) { if (newBooleanValue != fMarkOccurrenceAnnotations) { fMarkOccurrenceAnnotations = newBooleanValue; if (!fMarkOccurrenceAnnotations) { uninstallOccurrencesFinder(); } else { installOccurrencesFinder(true); } } return; } if (PreferenceConstants.EDITOR_MARK_TYPE_OCCURRENCES.equals(property)) { fMarkTypeOccurrences = newBooleanValue; return; } if (PreferenceConstants.EDITOR_MARK_METHOD_OCCURRENCES.equals(property)) { fMarkMethodOccurrences = newBooleanValue; return; } if (PreferenceConstants.EDITOR_MARK_CONSTANT_OCCURRENCES.equals(property)) { fMarkConstantOccurrences = newBooleanValue; return; } if (PreferenceConstants.EDITOR_MARK_FIELD_OCCURRENCES.equals(property)) { fMarkFieldOccurrences = newBooleanValue; return; } if (PreferenceConstants.EDITOR_MARK_LOCAL_VARIABLE_OCCURRENCES.equals(property)) { fMarkLocalVariableypeOccurrences = newBooleanValue; return; } if (PreferenceConstants.EDITOR_MARK_EXCEPTION_OCCURRENCES.equals(property)) { fMarkExceptions = newBooleanValue; return; } if (PreferenceConstants.EDITOR_MARK_METHOD_EXIT_POINTS.equals(property)) { fMarkMethodExitPoints = newBooleanValue; return; } if (PreferenceConstants.EDITOR_MARK_BREAK_CONTINUE_TARGETS.equals(property)) { fMarkBreakContinueTargets = newBooleanValue; return; } if (PreferenceConstants.EDITOR_MARK_IMPLEMENTORS.equals(property)) { fMarkImplementors = newBooleanValue; return; } if (PreferenceConstants.EDITOR_STICKY_OCCURRENCES.equals(property)) { fStickyOccurrenceAnnotations = newBooleanValue; return; } if (SemanticHighlightings.affectsEnablement(getPreferenceStore(), event)) { if (isSemanticHighlightingEnabled()) { installSemanticHighlighting(); } else { uninstallSemanticHighlighting(); } return; } if (JavaScriptCore.COMPILER_SOURCE.equals(property)) { if (event.getNewValue() instanceof String) { fBracketMatcher.setSourceVersion((String) event.getNewValue()); // fall through as others are interested in source change as well. } } ((DartSourceViewerConfiguration) getSourceViewerConfiguration()).handlePropertyChangeEvent(event); if (affectsOverrideIndicatorAnnotations(event)) { if (isShowingOverrideIndicators()) { if (fOverrideIndicatorManager == null) { installOverrideIndicator(true); } } else { if (fOverrideIndicatorManager != null) { uninstallOverrideIndicator(); } } return; } if (PreferenceConstants.EDITOR_FOLDING_PROVIDER.equals(property)) { if (sourceViewer instanceof ProjectionViewer) { DartX.todo("folding"); ProjectionViewer projectionViewer = (ProjectionViewer) sourceViewer; if (fProjectionModelUpdater != null) { fProjectionModelUpdater.uninstall(); } // either freshly enabled or provider changed fProjectionModelUpdater = DartToolsPlugin.getDefault().getFoldingStructureProviderRegistry() .getCurrentFoldingProvider(); if (fProjectionModelUpdater != null) { fProjectionModelUpdater.install(this, projectionViewer); } } return; } if (DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE.equals(property) || DefaultCodeFormatterConstants.FORMATTER_INDENTATION_SIZE.equals(property) || DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR.equals(property)) { StyledText textWidget = sourceViewer.getTextWidget(); int tabWidth = getSourceViewerConfiguration().getTabWidth(sourceViewer); if (textWidget.getTabs() != tabWidth) { textWidget.setTabs(tabWidth); } return; } if (PreferenceConstants.EDITOR_FOLDING_ENABLED.equals(property)) { if (sourceViewer instanceof ProjectionViewer) { new ToggleFoldingRunner().runWhenNextVisible(); } return; } } finally { super.handlePreferenceStoreChanged(event); } if (AbstractDecoratedTextEditorPreferenceConstants.SHOW_RANGE_INDICATOR.equals(property)) { // superclass already installed the range indicator Object newValue = event.getNewValue(); ISourceViewer viewer = getSourceViewer(); if (newValue != null && viewer != null) { if (Boolean.valueOf(newValue.toString()).booleanValue()) { // adjust the highlightrange in order to get the magnet right after // changing the selection Point selection = viewer.getSelectedRange(); adjustHighlightRange(selection.x, selection.y); } } } } @Override protected void initializeEditor() { IPreferenceStore store = createCombinedPreferenceStore(null); setPreferenceStore(store); setSourceViewerConfiguration(createDartSourceViewerConfiguration()); fMarkOccurrenceAnnotations = store.getBoolean(PreferenceConstants.EDITOR_MARK_OCCURRENCES); fStickyOccurrenceAnnotations = store.getBoolean(PreferenceConstants.EDITOR_STICKY_OCCURRENCES); fMarkTypeOccurrences = store.getBoolean(PreferenceConstants.EDITOR_MARK_TYPE_OCCURRENCES); fMarkMethodOccurrences = store.getBoolean(PreferenceConstants.EDITOR_MARK_METHOD_OCCURRENCES); fMarkConstantOccurrences = store.getBoolean(PreferenceConstants.EDITOR_MARK_CONSTANT_OCCURRENCES); fMarkFieldOccurrences = store.getBoolean(PreferenceConstants.EDITOR_MARK_FIELD_OCCURRENCES); fMarkLocalVariableypeOccurrences = store .getBoolean(PreferenceConstants.EDITOR_MARK_LOCAL_VARIABLE_OCCURRENCES); fMarkExceptions = store.getBoolean(PreferenceConstants.EDITOR_MARK_EXCEPTION_OCCURRENCES); fMarkImplementors = store.getBoolean(PreferenceConstants.EDITOR_MARK_IMPLEMENTORS); fMarkMethodExitPoints = store.getBoolean(PreferenceConstants.EDITOR_MARK_METHOD_EXIT_POINTS); fMarkBreakContinueTargets = store.getBoolean(PreferenceConstants.EDITOR_MARK_BREAK_CONTINUE_TARGETS); } @Override protected void initializeKeyBindingScopes() { setKeyBindingScopes(new String[] { "com.google.dart.tools.ui.dartViewScope" }); //$NON-NLS-1$ } /** * Initializes the given viewer's colors. * * @param viewer the viewer to be initialized */ @Override protected void initializeViewerColors(ISourceViewer viewer) { // is handled by DartSourceViewer } /** * Installs the encoding support on the given text editor. * <p> * Subclasses may override to install their own encoding support or to disable the default * encoding support. * </p> */ protected void installEncodingSupport() { fEncodingSupport = new DefaultEncodingSupport(); fEncodingSupport.initialize(this); } protected void installOccurrencesFinder(boolean forceUpdate) { fMarkOccurrenceAnnotations = true; fPostSelectionListenerWithAST = new ISelectionListenerWithAST() { @Override public void selectionChanged(IEditorPart part, ITextSelection selection, DartUnit astRoot) { updateOccurrenceAnnotations(selection, astRoot); } }; SelectionListenerWithASTManager.getDefault().addListener(this, fPostSelectionListenerWithAST); if (forceUpdate && getSelectionProvider() != null) { fForcedMarkOccurrencesSelection = getSelectionProvider().getSelection(); DartElement input = getInputDartElement(); if (input != null) { updateOccurrenceAnnotations((ITextSelection) fForcedMarkOccurrencesSelection, DartToolsPlugin.getDefault().getASTProvider().getAST(getInputDartElement(), ASTProvider.WAIT_NO, getProgressMonitor())); } } if (fOccurrencesFinderJobCanceler == null) { fOccurrencesFinderJobCanceler = new OccurrencesFinderJobCanceler(); fOccurrencesFinderJobCanceler.install(); } } protected void installOverrideIndicator(boolean provideAST) { uninstallOverrideIndicator(); IAnnotationModel model = getDocumentProvider().getAnnotationModel(getEditorInput()); final DartElement inputElement = getInputDartElement(); if (model == null || inputElement == null) { return; } fOverrideIndicatorManager = new OverrideIndicatorManager(model, inputElement, null); if (provideAST) { DartUnit ast = DartToolsPlugin.getDefault().getASTProvider().getAST(inputElement, ASTProvider.WAIT_ACTIVE_ONLY, getProgressMonitor()); fOverrideIndicatorManager.reconciled(ast, true, getProgressMonitor()); } } protected boolean isActivePart() { IWorkbenchPart part = getActivePart(); return part != null && part.equals(this); } protected boolean isMarkingOccurrences() { IPreferenceStore store = getPreferenceStore(); return store != null && store.getBoolean(PreferenceConstants.EDITOR_MARK_OCCURRENCES); } /** * Tells whether override indicators are shown. * * @return <code>true</code> if the override indicators are shown */ protected boolean isShowingOverrideIndicators() { AnnotationPreference preference = getAnnotationPreferenceLookup() .getAnnotationPreference(OverrideIndicatorManager.ANNOTATION_TYPE); IPreferenceStore store = getPreferenceStore(); return getBoolean(store, preference.getHighlightPreferenceKey()) || getBoolean(store, preference.getVerticalRulerPreferenceKey()) || getBoolean(store, preference.getOverviewRulerPreferenceKey()) || getBoolean(store, preference.getTextPreferenceKey()); } @Override protected void performRevert() { ProjectionViewer projectionViewer = (ProjectionViewer) getSourceViewer(); projectionViewer.setRedraw(false); try { boolean projectionMode = projectionViewer.isProjectionMode(); if (projectionMode) { projectionViewer.disableProjection(); DartX.todo("folding"); if (fProjectionModelUpdater != null) { fProjectionModelUpdater.uninstall(); } } super.performRevert(); if (projectionMode) { DartX.todo("folding"); if (fProjectionModelUpdater != null) { fProjectionModelUpdater.install(this, projectionViewer); } projectionViewer.enableProjection(); } } finally { projectionViewer.setRedraw(true); checkEditableState(); } } @Override protected void performSave(boolean overwrite, IProgressMonitor progressMonitor) { performSaveActions(); super.performSave(overwrite, progressMonitor); } @Override protected void rulerContextMenuAboutToShow(IMenuManager menu) { super.rulerContextMenuAboutToShow(menu); // Need to remove preferences item from the list; can't supress it via activities // because there is no command defined for this item menu.remove(ITextEditorActionConstants.RULER_PREFERENCES); IAction action = getAction("FoldingToggle"); //$NON-NLS-1$ menu.add(action); action = getAction("FoldingExpandAll"); //$NON-NLS-1$ menu.add(action); action = getAction("FoldingCollapseAll"); //$NON-NLS-1$ menu.add(action); action = getAction("FoldingRestore"); //$NON-NLS-1$ menu.add(action); } /** * React to changed selection. */ protected void selectionChanged() { if (getSelectionProvider() == null) { return; } SourceReference element = computeHighlightRangeSourceReference(); if (getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE)) { synchronizeOutlinePage(element); } setSelection(element, false); if (!fSelectionChangedViaGotoAnnotation) { updateStatusLine(); } fSelectionChangedViaGotoAnnotation = false; } /** * Sets the input of the editor's outline page. * * @param page the Dart outline page * @param input the editor input */ protected void setOutlinePageInput(DartOutlinePage page, IEditorInput input) { if (page == null) { return; } DartElement je = getInputDartElement(); if (je != null && je.exists()) { page.setInput(je); } else { page.setInput(null); } } /** * Sets the outliner's context menu ID. * * @param menuId the menu ID */ protected void setOutlinerContextMenuId(String menuId) { fOutlinerContextMenuId = menuId; } @Override protected void setPreferenceStore(IPreferenceStore store) { super.setPreferenceStore(store); if (getSourceViewerConfiguration() instanceof DartSourceViewerConfiguration) { DartTextTools textTools = DartToolsPlugin.getDefault().getDartTextTools(); setSourceViewerConfiguration(new DartSourceViewerConfiguration(textTools.getColorManager(), store, this, DartPartitions.DART_PARTITIONING)); } if (getSourceViewer() instanceof DartSourceViewer) { ((DartSourceViewer) getSourceViewer()).setPreferenceStore(store); } } protected void setSelection(SourceReference reference, boolean moveCursor) { if (getSelectionProvider() == null) { return; } ISelection selection = getSelectionProvider().getSelection(); if (selection instanceof ITextSelection) { ITextSelection textSelection = (ITextSelection) 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 { SourceRange range = null; if (reference instanceof DartVariable) { DartX.notYet(); // DartElement je = ((Variable) reference).getParent(); // if (je instanceof SourceReference) // range = ((SourceReference) je).getSourceInfo().getSourceRange(); } else { 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; range = reference.getNameRange(); if (range != null) { offset = range.getOffset(); length = range.getLength(); } if (offset > -1 && length > 0) { try { textWidget.setRedraw(false); sourceViewer.revealRange(offset, length); sourceViewer.setSelectedRange(offset, length); } finally { textWidget.setRedraw(true); } markInNavigationHistory(); } } catch (DartModelException x) { } catch (IllegalArgumentException x) { } } else if (moveCursor) { resetHighlightRange(); markInNavigationHistory(); } } /** * Synchronizes the outliner selection with the given element position in the editor. * * @param element the dart element to select */ protected void synchronizeOutlinePage(SourceReference element) { synchronizeOutlinePage(element, true); } /** * Synchronizes the outliner selection with the given element position in the editor. * * @param element the Dart element to select * @param checkIfOutlinePageActive <code>true</code> if check for active outline page needs to be * done */ protected void synchronizeOutlinePage(SourceReference element, boolean checkIfOutlinePageActive) { if (fOutlinePage != null && element != null && !(checkIfOutlinePageActive && isOutlinePageActive())) { fOutlinePage.select(element); } } protected void uninstallOccurrencesFinder() { fMarkOccurrenceAnnotations = false; if (fOccurrencesFinderJob != null) { fOccurrencesFinderJob.cancel(); fOccurrencesFinderJob = null; } if (fOccurrencesFinderJobCanceler != null) { fOccurrencesFinderJobCanceler.uninstall(); fOccurrencesFinderJobCanceler = null; } if (fPostSelectionListenerWithAST != null) { SelectionListenerWithASTManager.getDefault().removeListener(this, fPostSelectionListenerWithAST); fPostSelectionListenerWithAST = null; } removeOccurrenceAnnotations(); } protected void uninstallOverrideIndicator() { if (fOverrideIndicatorManager != null) { fOverrideIndicatorManager.removeAnnotations(); fOverrideIndicatorManager = null; } } @Override protected void updateMarkerViews(Annotation annotation) { if (annotation instanceof IJavaAnnotation) { Iterator<IJavaAnnotation> e = ((IJavaAnnotation) annotation).getOverlaidIterator(); if (e != null) { while (e.hasNext()) { Object o = e.next(); if (o instanceof MarkerAnnotation) { super.updateMarkerViews((MarkerAnnotation) o); return; } } } return; } super.updateMarkerViews(annotation); } /** * Updates the occurrences annotations based on the current selection. * * @param selection the text selection * @param astRoot the compilation unit AST */ protected void updateOccurrenceAnnotations(ITextSelection selection, DartUnit astRoot) { if (fOccurrencesFinderJob != null) { fOccurrencesFinderJob.cancel(); } if (!fMarkOccurrenceAnnotations) { return; } if (astRoot == null || selection == null) { return; } IDocument document = getSourceViewer().getDocument(); if (document == null) { return; } if (document instanceof IDocumentExtension4) { int offset = selection.getOffset(); long currentModificationStamp = ((IDocumentExtension4) document).getModificationStamp(); IRegion markOccurrenceTargetRegion = fMarkOccurrenceTargetRegion; if (markOccurrenceTargetRegion != null && currentModificationStamp == fMarkOccurrenceModificationStamp) { if (markOccurrenceTargetRegion.getOffset() <= offset && offset <= markOccurrenceTargetRegion.getOffset() + markOccurrenceTargetRegion.getLength()) { return; } } fMarkOccurrenceTargetRegion = DartWordFinder.findWord(document, offset); fMarkOccurrenceModificationStamp = currentModificationStamp; } DartX.todo("marking"); List<DartNode> matches = null; CompilationUnit input = getInputDartElement().getAncestor(CompilationUnit.class); DartElementLocator locator = new DartElementLocator(input, selection.getOffset(), selection.getOffset() + selection.getLength(), true); try { if (astRoot.getLibrary() == null) { // if astRoot is from ExternalCompilationUnit then it needs to be resolved; it is apparently not cached astRoot = DartCompilerUtilities.resolveUnit(input); // TODO clean up astRoot } } catch (DartModelException e) { DartToolsPlugin.log(e); } /* DartElement selectedModelNode = */locator.searchWithin(astRoot); Element selectedNode = locator.getResolvedElement(); // if (fMarkExceptions || fMarkTypeOccurrences) { // ExceptionOccurrencesFinder exceptionFinder = new ExceptionOccurrencesFinder(); // String message = exceptionFinder.initialize(astRoot, selectedNode); // if (message == null) { // matches = exceptionFinder.perform(); // if (!fMarkExceptions && !matches.isEmpty()) // matches.clear(); // } // } // if ((matches == null || matches.isEmpty()) // && (fMarkMethodExitPoints || fMarkTypeOccurrences)) { // MethodExitsFinder finder = new MethodExitsFinder(); // String message = finder.initialize(astRoot, selectedNode); // if (message == null) { // matches = finder.perform(); // if (!fMarkMethodExitPoints && !matches.isEmpty()) // matches.clear(); // } // } // if ((matches == null || matches.isEmpty()) // && (fMarkBreakContinueTargets || fMarkTypeOccurrences)) { // BreakContinueTargetFinder finder = new BreakContinueTargetFinder(); // String message = finder.initialize(astRoot, selectedNode); // if (message == null) { // matches = finder.perform(); // if (!fMarkBreakContinueTargets && !matches.isEmpty()) // matches.clear(); // } // } // if ((matches == null || matches.isEmpty()) // && (fMarkImplementors || fMarkTypeOccurrences)) { // ImplementOccurrencesFinder finder = new ImplementOccurrencesFinder(); // String message = finder.initialize(astRoot, selectedNode); // if (message == null) { // matches = finder.perform(); // if (!fMarkImplementors && !matches.isEmpty()) // matches.clear(); // } // } // if (matches == null) { // IBinding binding = null; // if (selectedNode instanceof Name) { // binding = ((Name) selectedNode).resolveBinding(); // } // // if (binding != null && markOccurrencesOfType(binding)) { // // Find the matches && extract positions so we can forget the AST // NameOccurrencesFinder finder = new NameOccurrencesFinder(binding); // String message = finder.initialize(astRoot, selectedNode); // if (message == null) { // matches = finder.perform(); // } // } // } if (matches == null && selectedNode != null) { NameOccurrencesFinder finder = new NameOccurrencesFinder(selectedNode); finder.searchWithin(astRoot); matches = finder.getMatches(); } if (matches == null || matches.size() == 0) { if (!fStickyOccurrenceAnnotations) { removeOccurrenceAnnotations(); } return; } Position[] positions = new Position[matches.size()]; int i = 0; for (Iterator<DartNode> each = matches.iterator(); each.hasNext();) { DartNode currentNode = each.next(); positions[i++] = new Position(currentNode.getSourceInfo().getOffset(), currentNode.getSourceInfo().getLength()); } fOccurrencesFinderJob = new OccurrencesFinderJob(document, positions, selection); // fOccurrencesFinderJob.setPriority(Job.DECORATE); // fOccurrencesFinderJob.setSystem(true); // fOccurrencesFinderJob.schedule(); fOccurrencesFinderJob.run(new NullProgressMonitor()); } @Override protected void updatePropertyDependentActions() { super.updatePropertyDependentActions(); if (fEncodingSupport != null) { fEncodingSupport.reset(); } } protected void updateStatusLine() { ITextSelection selection = (ITextSelection) getSelectionProvider().getSelection(); Annotation annotation = getAnnotation(selection.getOffset(), selection.getLength()); setStatusLineErrorMessage(null); setStatusLineMessage(null); if (annotation != null) { updateMarkerViews(annotation); if (annotation instanceof IJavaAnnotation && ((IJavaAnnotation) annotation).isProblem()) { setStatusLineMessage(annotation.getText()); } } } boolean isFoldingEnabled() { return DartToolsPlugin.getDefault().getPreferenceStore() .getBoolean(PreferenceConstants.EDITOR_FOLDING_ENABLED); } boolean markOccurrencesOfType(/* IBinding */Object binding) { DartX.todo("modifiers,marking"); if (binding == null) { return false; } // int kind = binding.getKind(); // // if (fMarkTypeOccurrences && kind == IBinding.TYPE) // return true; // // if (fMarkMethodOccurrences && kind == IBinding.METHOD) // return true; // // if (kind == IBinding.VARIABLE) { // IVariableBinding variableBinding = (IVariableBinding) binding; // if (variableBinding.isField()) { // int constantModifier = IModifierConstants.ACC_STATIC // | IModifierConstants.ACC_FINAL; // boolean isConstant = (variableBinding.getModifiers() & constantModifier) == constantModifier; // if (isConstant) // return fMarkConstantOccurrences; // else // return fMarkFieldOccurrences; // } // // return fMarkLocalVariableypeOccurrences; // } return false; } void removeOccurrenceAnnotations() { fMarkOccurrenceModificationStamp = IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; fMarkOccurrenceTargetRegion = null; IDocumentProvider documentProvider = getDocumentProvider(); if (documentProvider == null) { return; } IAnnotationModel annotationModel = documentProvider.getAnnotationModel(getEditorInput()); if (annotationModel == null || fOccurrenceAnnotations == null) { return; } synchronized (getLockObject(annotationModel)) { if (annotationModel instanceof IAnnotationModelExtension) { ((IAnnotationModelExtension) annotationModel).replaceAnnotations(fOccurrenceAnnotations, null); } else { for (int i = 0, length = fOccurrenceAnnotations.length; i < length; i++) { annotationModel.removeAnnotation(fOccurrenceAnnotations[i]); } } fOccurrenceAnnotations = null; } } /** * Creates and returns the preference store for this Dart editor with the given input. * * @param input The editor input for which to create the preference store * @return the preference store for this editor */ private IPreferenceStore createCombinedPreferenceStore(IEditorInput input) { List<IPreferenceStore> stores = new ArrayList<IPreferenceStore>(3); DartProject project = EditorUtility.getDartProject(input); if (project != null) { stores.add(new EclipsePreferencesAdapter(new ProjectScope(project.getProject()), DartCore.PLUGIN_ID)); } stores.add(DartToolsPlugin.getDefault().getPreferenceStore()); stores.add(new PreferencesAdapter(DartCore.getPlugin().getPluginPreferences())); stores.add(EditorsUI.getPreferenceStore()); return new ChainedPreferenceStore(stores.toArray(new IPreferenceStore[stores.size()])); } private IWorkbenchPart getActivePart() { IWorkbenchWindow window = getSite().getWorkbenchWindow(); IPartService service = window.getPartService(); IWorkbenchPart part = service.getActivePart(); return part; } /** * 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> */ private Annotation getAnnotation(int offset, int length) { IAnnotationModel model = getDocumentProvider().getAnnotationModel(getEditorInput()); @SuppressWarnings("rawtypes") Iterator e = new DartAnnotationIterator(model, true, false); while (e.hasNext()) { Annotation a = (Annotation) e.next(); Position p = model.getPosition(a); if (p != null && p.overlapsWith(offset, length)) { return a; } } return null; } /** * Returns the boolean preference for the given key. * * @param store the preference store * @param key the preference key * @return <code>true</code> if the key exists in the store and its value is <code>true</code> */ private boolean getBoolean(IPreferenceStore store, String key) { return key != null && store.getBoolean(key); } /** * Returns the lock object for the given annotation model. * * @param annotationModel the annotation model * @return the annotation model's lock object */ private Object getLockObject(IAnnotationModel annotationModel) { if (annotationModel instanceof ISynchronizable) { Object lock = ((ISynchronizable) annotationModel).getLockObject(); if (lock != null) { return lock; } } return annotationModel; } /** * Install Semantic Highlighting. */ private void installSemanticHighlighting() { if (fSemanticManager == null) { fSemanticManager = new SemanticHighlightingManager(); fSemanticManager.install(this, (DartSourceViewer) getSourceViewer(), DartToolsPlugin.getDefault().getDartTextTools().getColorManager(), getPreferenceStore()); } } private void internalDoSetInput(IEditorInput input) throws CoreException { ISourceViewer sourceViewer = getSourceViewer(); DartSourceViewer dartSourceViewer = null; if (sourceViewer instanceof DartSourceViewer) { dartSourceViewer = (DartSourceViewer) sourceViewer; } IPreferenceStore store = getPreferenceStore(); if (dartSourceViewer != null && isFoldingEnabled() && (store == null || !store.getBoolean(PreferenceConstants.EDITOR_SHOW_SEGMENTS))) { dartSourceViewer.prepareDelayedProjection(); } super.doSetInput(input); if (dartSourceViewer != null && dartSourceViewer.getReconciler() == null) { IReconciler reconciler = getSourceViewerConfiguration().getReconciler(dartSourceViewer); if (reconciler != null) { reconciler.install(dartSourceViewer); dartSourceViewer.setReconciler(reconciler); } } if (fEncodingSupport != null) { fEncodingSupport.reset(); } setOutlinePageInput(fOutlinePage, input); if (isShowingOverrideIndicators()) { installOverrideIndicator(false); } } /* * Tells whether the content is editable. */ private boolean isContentEditable() { if (true) { return true; } if (!isEditableStateKnown) { IDocumentProvider p = getDocumentProvider(); if (p instanceof ICompilationUnitDocumentProvider) { ICompilationUnitDocumentProvider prov = (ICompilationUnitDocumentProvider) getDocumentProvider(); CompilationUnit unit = prov.getWorkingCopy(getEditorInput()); isEditable = !unit.isReadOnly(); } else { isEditable = true; } isEditableStateKnown = true; } return isEditable; } private boolean isEditorHoverProperty(String property) { return PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS.equals(property); } private boolean isOutlinePageActive() { IWorkbenchPart part = getActivePart(); return part instanceof ContentOutline && ((ContentOutline) part).getCurrentPage() == fOutlinePage; } private boolean isRemoveTrailingWhitespaceEnabled() { return PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_REMOVE_TRAILING_WS); } /** * @return <code>true</code> if Semantic Highlighting is enabled. */ private boolean isSemanticHighlightingEnabled() { return true; // return SemanticHighlightings.isEnabled(getPreferenceStore()); } private void performSaveActions() { if (isRemoveTrailingWhitespaceEnabled()) { try { removeTrailingWhitespaceAction.run(); } catch (InvocationTargetException e) { DartToolsPlugin.log(e); } } } /** * Uninstall Semantic Highlighting. */ private void uninstallSemanticHighlighting() { if (fSemanticManager != null) { fSemanticManager.uninstall(); fSemanticManager = null; } } /* * 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); } } } }