/******************************************************************************* * Copyright (c) 2000, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.ui.texteditor; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; import java.util.Iterator; import java.util.List; import com.ibm.icu.text.BreakIterator; import com.ibm.icu.text.MessageFormat; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.custom.StyledTextPrintOptions; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Shell; import org.eclipse.core.commands.operations.IOperationApprover; import org.eclipse.core.commands.operations.IUndoContext; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.filesystem.URIUtil; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceStatus; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.filebuffers.FileBuffers; import org.eclipse.core.filebuffers.IFileBufferStatusCodes; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.GroupMarker; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.MessageDialogWithToggle; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.window.Window; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewerExtension6; import org.eclipse.jface.text.ITextViewerExtension8; import org.eclipse.jface.text.JFaceTextUtil; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; import org.eclipse.jface.text.revisions.IRevisionRulerColumn; import org.eclipse.jface.text.revisions.IRevisionRulerColumnExtension; import org.eclipse.jface.text.revisions.IRevisionRulerColumnExtension.RenderingMode; import org.eclipse.jface.text.revisions.RevisionInformation; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.AnnotationRulerColumn; import org.eclipse.jface.text.source.ChangeRulerColumn; import org.eclipse.jface.text.source.CompositeRuler; import org.eclipse.jface.text.source.IAnnotationAccess; import org.eclipse.jface.text.source.IAnnotationAccessExtension2; import org.eclipse.jface.text.source.IAnnotationHover; import org.eclipse.jface.text.source.IAnnotationModel; import org.eclipse.jface.text.source.IChangeRulerColumn; import org.eclipse.jface.text.source.IOverviewRuler; import org.eclipse.jface.text.source.ISharedTextColors; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.ISourceViewerExtension; import org.eclipse.jface.text.source.ISourceViewerExtension3; 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.LineNumberChangeRulerColumn; import org.eclipse.jface.text.source.LineNumberRulerColumn; import org.eclipse.jface.text.source.OverviewRuler; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.ui.IEditorDescriptor; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.IURIEditorInput; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.IWorkbenchCommandConstants; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.ContributionItemFactory; import org.eclipse.ui.actions.OpenWithMenu; import org.eclipse.ui.actions.WorkspaceModifyOperation; import org.eclipse.ui.dialogs.PreferencesUtil; import org.eclipse.ui.dialogs.SaveAsDialog; import org.eclipse.ui.ide.FileStoreEditorInput; import org.eclipse.ui.ide.IDEActionFactory; import org.eclipse.ui.ide.IGotoMarker; import org.eclipse.ui.internal.editors.quickdiff.CompositeRevertAction; import org.eclipse.ui.internal.editors.quickdiff.RestoreAction; import org.eclipse.ui.internal.editors.quickdiff.RevertBlockAction; import org.eclipse.ui.internal.editors.quickdiff.RevertLineAction; import org.eclipse.ui.internal.editors.quickdiff.RevertSelectionAction; import org.eclipse.ui.internal.editors.text.EditorsPlugin; import org.eclipse.ui.internal.editors.text.NLSUtility; import org.eclipse.ui.internal.editors.text.RefreshEditorAction; import org.eclipse.ui.internal.texteditor.AnnotationColumn; import org.eclipse.ui.internal.texteditor.BooleanPreferenceToggleAction; import org.eclipse.ui.internal.texteditor.FocusedInformationPresenter; import org.eclipse.ui.internal.texteditor.LineNumberColumn; import org.eclipse.ui.internal.texteditor.TextChangeHover; import org.eclipse.ui.keys.IBindingService; import org.eclipse.ui.operations.NonLocalUndoUserApprover; import org.eclipse.ui.part.FileEditorInput; import org.eclipse.ui.part.IShowInSource; import org.eclipse.ui.part.ShowInContext; import org.eclipse.ui.views.markers.MarkerViewUtil; import org.eclipse.ui.texteditor.rulers.IColumnSupport; import org.eclipse.ui.texteditor.rulers.IContributedRulerColumn; import org.eclipse.ui.texteditor.rulers.RulerColumnDescriptor; import org.eclipse.ui.texteditor.rulers.RulerColumnPreferenceAdapter; import org.eclipse.ui.texteditor.rulers.RulerColumnRegistry; import org.eclipse.ui.editors.text.DefaultEncodingSupport; import org.eclipse.ui.editors.text.EditorsUI; import org.eclipse.ui.editors.text.ForwardingDocumentProvider; import org.eclipse.ui.editors.text.IEncodingSupport; import org.eclipse.ui.editors.text.IStorageDocumentProvider; import org.eclipse.ui.editors.text.ITextEditorHelpContextIds; /** * An intermediate editor comprising functionality not present in the leaner <code>AbstractTextEditor</code>, * but used in many heavy weight (and especially source editing) editors, such as line numbers, * change ruler, overview ruler, print margins, current line highlighting, etc. * * @author Stas Negara - Added getHackedViewer() in order to get public access to the source viewer. * Overrode method createUndoRedoActions() such that while replaying the approvers are not * registered in order to avoid confirmation dialog boxes. * * @since 3.0 */ public abstract class AbstractDecoratedTextEditor extends StatusTextEditor { /** * Preference key for showing the line number ruler. */ private final static String LINE_NUMBER_RULER= AbstractDecoratedTextEditorPreferenceConstants.EDITOR_LINE_NUMBER_RULER; /** * Preference key for showing the overview ruler. */ private final static String OVERVIEW_RULER= AbstractDecoratedTextEditorPreferenceConstants.EDITOR_OVERVIEW_RULER; /** * Preference key for highlighting current line. */ private final static String CURRENT_LINE= AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE; /** * Preference key for highlight color of current line. */ private final static String CURRENT_LINE_COLOR= AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE_COLOR; /** * Preference key for showing print margin ruler. */ private final static String PRINT_MARGIN= AbstractDecoratedTextEditorPreferenceConstants.EDITOR_PRINT_MARGIN; /** * Preference key for print margin ruler color. */ private final static String PRINT_MARGIN_COLOR= AbstractDecoratedTextEditorPreferenceConstants.EDITOR_PRINT_MARGIN_COLOR; /** * Preference key for print margin ruler column. */ private final static String PRINT_MARGIN_COLUMN= AbstractDecoratedTextEditorPreferenceConstants.EDITOR_PRINT_MARGIN_COLUMN; /** * Preference key to get whether the overwrite mode is disabled. * @since 3.1 */ private final static String DISABLE_OVERWRITE_MODE= AbstractDecoratedTextEditorPreferenceConstants.EDITOR_DISABLE_OVERWRITE_MODE; /** * Menu id for the overview ruler context menu. * * @since 3.4 */ public final static String DEFAULT_OVERVIEW_RULER_CONTEXT_MENU_ID= "#OverviewRulerContext"; //$NON-NLS-1$ /** * Adapter class for <code>IGotoMarker</code>. */ private class GotoMarkerAdapter implements IGotoMarker { public void gotoMarker(IMarker marker) { AbstractDecoratedTextEditor.this.gotoMarker(marker); } } /** * The annotation preferences. */ private MarkerAnnotationPreferences fAnnotationPreferences; /** * The overview ruler of this editor. * * <p>This field should not be referenced by subclasses. It is <code>protected</code> for API * compatibility reasons and will be made <code>private</code> soon. Use * {@link #getOverviewRuler()} instead.</p> */ protected IOverviewRuler fOverviewRuler; /** * The overview ruler's context menu id. * * @since 3.4 */ private String fOverviewRulerContextMenuId; /** * Helper for accessing annotation from the perspective of this editor. * * <p>This field should not be referenced by subclasses. It is <code>protected</code> for API * compatibility reasons and will be made <code>private</code> soon. Use * {@link #getAnnotationAccess()} instead.</p> */ protected IAnnotationAccess fAnnotationAccess; /** * Helper for managing the decoration support of this editor's viewer. * * <p>This field should not be referenced by subclasses. It is <code>protected</code> for API * compatibility reasons and will be made <code>private</code> soon. Use * {@link #getSourceViewerDecorationSupport(ISourceViewer)} instead.</p> */ protected SourceViewerDecorationSupport fSourceViewerDecorationSupport; /** * The line number column. * * <p>This field should not be referenced by subclasses. It is <code>protected</code> for API * compatibility reasons and will be made <code>private</code> soon. Use * {@link AbstractTextEditor#getVerticalRuler()} to access the vertical bar instead.</p> */ protected LineNumberRulerColumn fLineNumberRulerColumn; /** * The delegating line number ruler contribution. * @since 3.3 */ private LineNumberColumn fLineColumn; /** * The editor's implicit document provider. */ private IDocumentProvider fImplicitDocumentProvider; /** * The editor's goto marker adapter. */ private Object fGotoMarkerAdapter= new GotoMarkerAdapter(); /** * Indicates whether this editor is updating views that show markers. * @see #updateMarkerViews(Annotation) * @since 3.2 */ protected boolean fIsUpdatingMarkerViews= false; /** * Indicates whether it wants to update the marker views after a gotoMarker call. * @see #updateMarkerViews(Annotation) * @see #gotoMarker(IMarker) * @since 3.6 */ private boolean fIsComingFromGotoMarker= false; /** * Tells whether editing the current derived editor input is allowed. * @since 3.3 */ private boolean fIsEditingDerivedFileAllowed= true; /** * Tells whether the derived state has been validated. * @since 3.3 */ private boolean fIsDerivedStateValidated= false; /** * The focused information presenter, or <code>null</code> if not created yet. * @since 3.5 */ private FocusedInformationPresenter fInformationPresenter; //CODINGSPECTATOR: Added the method getHackedViewer. public final ISourceViewer getHackedViewer() { return getSourceViewer(); } //CODINGSPECTATOR: Overrode method createUndoRedoActions() such that while replaying the approvers are not registered in order to avoid confirmation dialog boxes. protected void createUndoRedoActions() { if (Platform.getBundle("edu.illinois.codingtracker.replaying") != null) { //$NON-NLS-1$ //do nothing } else { super.createUndoRedoActions(); } } /* * Workaround for IllegalAccessError thrown because we are accessing * a protected method in a different bundle from an inner class. * @since 3.3 */ private IVerticalRuler internalGetVerticalRuler() { return getVerticalRuler(); } /** * Creates a new text editor. * * @see #initializeEditor() * @see #initializeKeyBindingScopes() */ public AbstractDecoratedTextEditor() { super(); fAnnotationPreferences= EditorsPlugin.getDefault().getMarkerAnnotationPreferences(); setRangeIndicator(new DefaultRangeIndicator()); initializeKeyBindingScopes(); initializeEditor(); } /** * Initializes this editor. Subclasses may re-implement. If sub-classes do * not change the contract, this method should not be extended, i.e. do not * call <code>super.initializeEditor()</code> in order to avoid the * temporary creation of objects that are immediately overwritten by * subclasses. */ protected void initializeEditor() { setPreferenceStore(EditorsPlugin.getDefault().getPreferenceStore()); } /** * Initializes the key binding scopes of this editor. */ protected void initializeKeyBindingScopes() { setKeyBindingScopes(new String[] { "org.eclipse.ui.textEditorScope" }); //$NON-NLS-1$ } /* * @see IWorkbenchPart#dispose() */ public void dispose() { if (fSourceViewerDecorationSupport != null) { fSourceViewerDecorationSupport.dispose(); fSourceViewerDecorationSupport= null; } fAnnotationAccess= null; fAnnotationPreferences= null; fLineNumberRulerColumn= null; fLineColumn= null; if (fInformationPresenter != null) { fInformationPresenter.uninstall(); fInformationPresenter= null; } super.dispose(); } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int) */ protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) { fAnnotationAccess= getAnnotationAccess(); fOverviewRuler= createOverviewRuler(getSharedColors()); ISourceViewer viewer= new SourceViewer(parent, ruler, getOverviewRuler(), isOverviewRulerVisible(), styles); // ensure decoration support has been created and configured. getSourceViewerDecorationSupport(viewer); return viewer; } protected ISharedTextColors getSharedColors() { return EditorsPlugin.getDefault().getSharedTextColors(); } protected IOverviewRuler createOverviewRuler(ISharedTextColors sharedColors) { IOverviewRuler ruler= new OverviewRuler(getAnnotationAccess(), VERTICAL_RULER_WIDTH, sharedColors); Iterator e= fAnnotationPreferences.getAnnotationPreferences().iterator(); while (e.hasNext()) { AnnotationPreference preference= (AnnotationPreference) e.next(); if (preference.contributesToHeader()) ruler.addHeaderAnnotationType(preference.getAnnotationType()); } return ruler; } /** * Creates the annotation access for this editor. * * @return the created annotation access */ protected IAnnotationAccess createAnnotationAccess() { return new DefaultMarkerAnnotationAccess(); } /** * Configures the decoration support for this editor's source viewer. Subclasses may override this * method, but should call their superclass' implementation at some point. * * @param support the decoration support to configure */ protected void configureSourceViewerDecorationSupport(SourceViewerDecorationSupport support) { Iterator e= fAnnotationPreferences.getAnnotationPreferences().iterator(); while (e.hasNext()) support.setAnnotationPreference((AnnotationPreference) e.next()); support.setCursorLinePainterPreferenceKeys(CURRENT_LINE, CURRENT_LINE_COLOR); support.setMarginPainterPreferenceKeys(PRINT_MARGIN, PRINT_MARGIN_COLOR, PRINT_MARGIN_COLUMN); support.setSymbolicFontName(getFontPropertyPreferenceKey()); } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor.createPartControl(Composite) */ public void createPartControl(Composite parent) { super.createPartControl(parent); if (fSourceViewerDecorationSupport != null) fSourceViewerDecorationSupport.install(getPreferenceStore()); IColumnSupport columnSupport= (IColumnSupport)getAdapter(IColumnSupport.class); if (isLineNumberRulerVisible()) { RulerColumnDescriptor lineNumberColumnDescriptor= RulerColumnRegistry.getDefault().getColumnDescriptor(LineNumberColumn.ID); if (lineNumberColumnDescriptor != null) columnSupport.setColumnVisible(lineNumberColumnDescriptor, true); } if (isPrefQuickDiffAlwaysOn()) showChangeInformation(true); if (!isOverwriteModeEnabled()) enableOverwriteMode(false); if (!isRangeIndicatorEnabled()) { getSourceViewer().removeRangeIndication(); getSourceViewer().setRangeIndicator(null); } // Assign the quick assist assistant to the annotation access. ISourceViewer viewer= getSourceViewer(); if (fAnnotationAccess instanceof IAnnotationAccessExtension2 && viewer instanceof ISourceViewerExtension3) ((IAnnotationAccessExtension2)fAnnotationAccess).setQuickAssistAssistant(((ISourceViewerExtension3)viewer).getQuickAssistAssistant()); createOverviewRulerContextMenu(); } /** * Creates the context menu for the overview ruler. * <p> * Subclasses may extend or replace this method. * </p> * * @since 3.4 */ protected void createOverviewRulerContextMenu() { if (fOverviewRulerContextMenuId == null) fOverviewRulerContextMenuId= DEFAULT_OVERVIEW_RULER_CONTEXT_MENU_ID; if (fOverviewRuler == null || fOverviewRuler.getControl() == null) return; MenuManager menuManager= new MenuManager(fOverviewRulerContextMenuId, fOverviewRulerContextMenuId); menuManager.setRemoveAllWhenShown(true); menuManager.addMenuListener(getContextMenuListener()); Menu menu= menuManager.createContextMenu(getOverviewRuler().getControl()); getOverviewRuler().getControl().setMenu(menu); getEditorSite().registerContextMenu(fOverviewRulerContextMenuId, menuManager, getSelectionProvider(), false); } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#createContextMenuListener() * @since 3.4 */ protected IMenuListener createContextMenuListener() { final IMenuListener superListener= super.createContextMenuListener(); return new IMenuListener() { public void menuAboutToShow(IMenuManager menu) { if (!getOverviewRulerContextMenuId().equals(menu.getId())) { superListener.menuAboutToShow(menu); return; } setFocus(); overviewRulerContextMenuAboutToShow(menu); } }; } /* * @see org.eclipse.ui.texteditor.StatusTextEditor#createStatusControl(org.eclipse.swt.widgets.Composite, org.eclipse.core.runtime.IStatus) * @since 3.1 */ protected Control createStatusControl(Composite parent, final IStatus status) { Object adapter= getAdapter(IEncodingSupport.class); DefaultEncodingSupport encodingSupport= null; if (adapter instanceof DefaultEncodingSupport) encodingSupport= (DefaultEncodingSupport)adapter; if (encodingSupport == null || !encodingSupport.isEncodingError(status)) return super.createStatusControl(parent, status); Shell shell= getSite().getShell(); Display display= shell.getDisplay(); Color bgColor= display.getSystemColor(SWT.COLOR_LIST_BACKGROUND); Color fgColor= display.getSystemColor(SWT.COLOR_LIST_FOREGROUND); Composite composite= new Composite(parent, SWT.NONE); composite.setLayout(new GridLayout()); composite.setBackground(bgColor); composite.setForeground(fgColor); Control control= super.createStatusControl(composite, status); control.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); Composite buttonComposite= new Composite(composite, SWT.NONE); buttonComposite.setLayout(new GridLayout()); buttonComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); buttonComposite.setBackground(bgColor); buttonComposite.setForeground(fgColor); encodingSupport.createStatusEncodingChangeControl(buttonComposite, status); return composite; } /** * Tells whether the overview ruler is visible. * * @return whether the overview ruler is visible */ protected boolean isOverviewRulerVisible() { IPreferenceStore store= getPreferenceStore(); return store != null ? store.getBoolean(OVERVIEW_RULER) : false; } /* * @see org.eclipse.ui.texteditor.ITextEditorExtension3#showChangeInformation(boolean) */ public void showChangeInformation(boolean show) { if (show == isChangeInformationShowing()) return; IColumnSupport columnSupport= (IColumnSupport)getAdapter(IColumnSupport.class); // only handle visibility of the combined column, but not the number/change only state if (show && fLineColumn == null) { RulerColumnDescriptor lineNumberColumnDescriptor= RulerColumnRegistry.getDefault().getColumnDescriptor(LineNumberColumn.ID); if (lineNumberColumnDescriptor != null) columnSupport.setColumnVisible(lineNumberColumnDescriptor, true); } else if (!show && fLineColumn != null && !isLineNumberRulerVisible()) { columnSupport.setColumnVisible(fLineColumn.getDescriptor(), false); fLineColumn= null; } } /* * @see org.eclipse.ui.texteditor.ITextEditorExtension3#isChangeInformationShowing() */ public boolean isChangeInformationShowing() { return fLineColumn != null && fLineColumn.isShowingChangeInformation(); } /* * @see org.eclipse.ui.texteditor.ITextEditorExtension4#showRevisionInformation(org.eclipse.jface.text.revisions.RevisionInformation, java.lang.String) * @since 3.2 */ public void showRevisionInformation(RevisionInformation info, String quickDiffProviderId) { if (info.getHoverControlCreator() == null) info.setHoverControlCreator(new RevisionHoverInformationControlCreator(false)); if (info.getInformationPresenterControlCreator() == null) info.setInformationPresenterControlCreator(new RevisionHoverInformationControlCreator(true)); showChangeInformation(true); if (fLineColumn != null) fLineColumn.showRevisionInformation(info, quickDiffProviderId); } /** * Returns whether the line number ruler column should be * visible according to the preference store settings. Subclasses may override this * method to provide a custom preference setting. * * @return <code>true</code> if the line numbers should be visible */ protected boolean isLineNumberRulerVisible() { IPreferenceStore store= getPreferenceStore(); return store != null ? store.getBoolean(LINE_NUMBER_RULER) : false; } /** * Returns whether the overwrite mode is enabled according to the preference * store settings. Subclasses may override this method to provide a custom * preference setting. * * @return <code>true</code> if overwrite mode is enabled * @since 3.1 */ protected boolean isOverwriteModeEnabled() { IPreferenceStore store= getPreferenceStore(); return store != null ? !store.getBoolean(DISABLE_OVERWRITE_MODE) : true; } /** * Returns whether the range indicator is enabled according to the preference * store settings. Subclasses may override this method to provide a custom * preference setting. * * @return <code>true</code> if overwrite mode is enabled * @since 3.1 */ private boolean isRangeIndicatorEnabled() { IPreferenceStore store= getPreferenceStore(); return store != null ? store.getBoolean(AbstractDecoratedTextEditorPreferenceConstants.SHOW_RANGE_INDICATOR) : true; } /** * Returns whether quick diff info should be visible upon opening an editor * according to the preference store settings. * * @return <code>true</code> if the line numbers should be visible */ protected boolean isPrefQuickDiffAlwaysOn() { IPreferenceStore store= getPreferenceStore(); boolean setting= store != null ? store.getBoolean(AbstractDecoratedTextEditorPreferenceConstants.QUICK_DIFF_ALWAYS_ON) : false; return setting && isEditorInputModifiable(); } /** * Initializes the given line number ruler column from the preference store. * * @param rulerColumn the ruler column to be initialized */ protected void initializeLineNumberRulerColumn(LineNumberRulerColumn rulerColumn) { /* * Left for compatibility. See LineNumberColumn. */ if (fLineColumn != null) fLineColumn.initializeLineNumberRulerColumn(rulerColumn); } /** * Creates a new line number ruler column that is appropriately initialized. * * @return the created line number column */ protected IVerticalRulerColumn createLineNumberRulerColumn() { /* * Left for compatibility. See LineNumberColumn. */ fLineNumberRulerColumn= new LineNumberChangeRulerColumn(getSharedColors()); ((IChangeRulerColumn) fLineNumberRulerColumn).setHover(createChangeHover()); initializeLineNumberRulerColumn(fLineNumberRulerColumn); return fLineNumberRulerColumn; } /** * Creates and returns a <code>LineChangeHover</code> to be used on this editor's change * ruler column. This default implementation returns a plain <code>LineChangeHover</code>. * Subclasses may override. * * @return the change hover to be used by this editors quick diff display */ protected LineChangeHover createChangeHover() { return new TextChangeHover(); } /** * Creates a new change ruler column for quick diff display independent of the * line number ruler column * * @return a new change ruler column * @deprecated as of 3.3. Not called any longer, replaced by {@link #createLineNumberRulerColumn()} */ protected IChangeRulerColumn createChangeRulerColumn() { /* * Left for compatibility. See LineNumberColumn. */ return new ChangeRulerColumn(getSharedColors()); } /** * Returns {@link #createCompositeRuler()}. Subclasses should not override this method, but * rather <code>createCompositeRuler</code> if they want to contribute their own vertical ruler * implementation. If not an instance of {@link CompositeRuler} is returned, the built-in ruler * columns (line numbers, annotations) will not work. * * <p>May become <code>final</code> in the future.</p> * * @see AbstractTextEditor#createVerticalRuler() */ protected IVerticalRuler createVerticalRuler() { return createCompositeRuler(); } /** * Creates a composite ruler to be used as the vertical ruler by this editor. * Subclasses may re-implement this method. * * @return the vertical ruler */ protected CompositeRuler createCompositeRuler() { return new CompositeRuler(); } /** * Creates the annotation ruler column. Subclasses may re-implement or extend. * * @param ruler the composite ruler that the column will be added * @return an annotation ruler column * @since 3.2 */ protected IVerticalRulerColumn createAnnotationRulerColumn(CompositeRuler ruler) { return new AnnotationRulerColumn(VERTICAL_RULER_WIDTH, getAnnotationAccess()); } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#createColumnSupport() * @since 3.3 */ protected final IColumnSupport createColumnSupport() { return new ColumnSupport(this, RulerColumnRegistry.getDefault()) { /* * @see org.eclipse.ui.texteditor.rulers.ColumnSupport#initializeColumn(org.eclipse.ui.texteditor.rulers.AbstractContributedRulerColumn) */ protected void initializeColumn(IContributedRulerColumn column) { super.initializeColumn(column); RulerColumnDescriptor descriptor= column.getDescriptor(); IVerticalRuler ruler= internalGetVerticalRuler(); if (ruler instanceof CompositeRuler) { if (AnnotationColumn.ID.equals(descriptor.getId())) { ((AnnotationColumn)column).setDelegate(createAnnotationRulerColumn((CompositeRuler) ruler)); } else if (LineNumberColumn.ID.equals(descriptor.getId())) { fLineColumn= ((LineNumberColumn) column); fLineColumn.setForwarder(new LineNumberColumn.ICompatibilityForwarder() { public IVerticalRulerColumn createLineNumberRulerColumn() { return AbstractDecoratedTextEditor.this.createLineNumberRulerColumn(); } public boolean isQuickDiffEnabled() { return AbstractDecoratedTextEditor.this.isPrefQuickDiffAlwaysOn(); } public boolean isLineNumberRulerVisible() { return AbstractDecoratedTextEditor.this.isLineNumberRulerVisible(); } }); } } } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor.ColumnSupport#dispose() */ public void dispose() { fLineColumn= null; super.dispose(); } }; } /* * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent) */ protected void handlePreferenceStoreChanged(PropertyChangeEvent event) { try { ISourceViewer sourceViewer= getSourceViewer(); if (sourceViewer == null) return; String property= event.getProperty(); if (fSourceViewerDecorationSupport != null && fOverviewRuler != null && OVERVIEW_RULER.equals(property)) { if (isOverviewRulerVisible()) showOverviewRuler(); else hideOverviewRuler(); return; } if (DISABLE_OVERWRITE_MODE.equals(property)) { enableOverwriteMode(isOverwriteModeEnabled()); return; } if (LINE_NUMBER_RULER.equals(property)) { // only handle visibility of the combined column, but not the number/change only state IColumnSupport columnSupport= (IColumnSupport)getAdapter(IColumnSupport.class); if (isLineNumberRulerVisible() && fLineColumn == null) { RulerColumnDescriptor lineNumberColumnDescriptor= RulerColumnRegistry.getDefault().getColumnDescriptor(LineNumberColumn.ID); if (lineNumberColumnDescriptor != null) columnSupport.setColumnVisible(lineNumberColumnDescriptor, true); } else if (!isLineNumberRulerVisible() && fLineColumn != null && !fLineColumn.isShowingChangeInformation()) { columnSupport.setColumnVisible(fLineColumn.getDescriptor(), false); fLineColumn= null; } return; } if (AbstractDecoratedTextEditorPreferenceConstants.QUICK_DIFF_ALWAYS_ON.equals(property)) { showChangeInformation(isPrefQuickDiffAlwaysOn()); } if (AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH.equals(property)) { IPreferenceStore store= getPreferenceStore(); if (store != null) sourceViewer.getTextWidget().setTabs(store.getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH)); if (isTabsToSpacesConversionEnabled()) { uninstallTabsToSpacesConverter(); installTabsToSpacesConverter(); } return; } if (AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SPACES_FOR_TABS.equals(property)) { if (isTabsToSpacesConversionEnabled()) installTabsToSpacesConverter(); else uninstallTabsToSpacesConverter(); return; } if (AbstractDecoratedTextEditorPreferenceConstants.EDITOR_UNDO_HISTORY_SIZE.equals(property) && sourceViewer instanceof ITextViewerExtension6) { IPreferenceStore store= getPreferenceStore(); if (store != null) ((ITextViewerExtension6)sourceViewer).getUndoManager().setMaximalUndoLevel(store.getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_UNDO_HISTORY_SIZE)); return; } if (AbstractDecoratedTextEditorPreferenceConstants.SHOW_RANGE_INDICATOR.equals(property)) { if (isRangeIndicatorEnabled()) { getSourceViewer().setRangeIndicator(getRangeIndicator()); } else { getSourceViewer().removeRangeIndication(); getSourceViewer().setRangeIndicator(null); } } if (sourceViewer instanceof ITextViewerExtension6) { HyperlinkDetectorDescriptor[] descriptor= EditorsUI.getHyperlinkDetectorRegistry().getHyperlinkDetectorDescriptors(); for (int i= 0; i < descriptor.length; i++) { if (descriptor[i].getId().equals(property) || (descriptor[i].getId() + HyperlinkDetectorDescriptor.STATE_MASK_POSTFIX).equals(property)) { IHyperlinkDetector[] detectors= getSourceViewerConfiguration().getHyperlinkDetectors(sourceViewer); int stateMask= getSourceViewerConfiguration().getHyperlinkStateMask(sourceViewer); ITextViewerExtension6 textViewer6= (ITextViewerExtension6)sourceViewer; textViewer6.setHyperlinkDetectors(detectors, stateMask); return; } } } } finally { super.handlePreferenceStoreChanged(event); } } /** * Shows the overview ruler. */ protected void showOverviewRuler() { if (fOverviewRuler != null) { if (getSourceViewer() instanceof ISourceViewerExtension) { ((ISourceViewerExtension) getSourceViewer()).showAnnotationsOverview(true); fSourceViewerDecorationSupport.updateOverviewDecorations(); } } } /** * Hides the overview ruler. */ protected void hideOverviewRuler() { if (getSourceViewer() instanceof ISourceViewerExtension) { fSourceViewerDecorationSupport.hideAnnotationOverview(); ((ISourceViewerExtension) getSourceViewer()).showAnnotationsOverview(false); } } /** * Returns the annotation access. * * @return the annotation access */ protected IAnnotationAccess getAnnotationAccess() { if (fAnnotationAccess == null) fAnnotationAccess= createAnnotationAccess(); return fAnnotationAccess; } /** * Returns the annotation preference lookup. * * @return the annotation preference lookup */ protected AnnotationPreferenceLookup getAnnotationPreferenceLookup() { return EditorsPlugin.getDefault().getAnnotationPreferenceLookup(); } /** * Returns the overview ruler. * * @return the overview ruler */ protected IOverviewRuler getOverviewRuler() { if (fOverviewRuler == null) fOverviewRuler= createOverviewRuler(getSharedColors()); return fOverviewRuler; } /** * Returns the source viewer decoration support. * * @param viewer the viewer for which to return a decoration support * @return the source viewer decoration support */ protected SourceViewerDecorationSupport getSourceViewerDecorationSupport(ISourceViewer viewer) { if (fSourceViewerDecorationSupport == null) { fSourceViewerDecorationSupport= new SourceViewerDecorationSupport(viewer, getOverviewRuler(), getAnnotationAccess(), getSharedColors()); configureSourceViewerDecorationSupport(fSourceViewerDecorationSupport); } return fSourceViewerDecorationSupport; } /** * Returns the annotation preferences. * * @return the annotation preferences */ protected MarkerAnnotationPreferences getAnnotationPreferences() { return fAnnotationPreferences; } /** * If the editor can be saved all marker ranges have been changed according to * the text manipulations. However, those changes are not yet propagated to the * marker manager. Thus, when opening a marker, the marker's position in the editor * must be determined as it might differ from the position stated in the marker. * * @param marker the marker to go to * @deprecated visibility will be reduced, use <code>getAdapter(IGotoMarker.class) for accessing this method</code> */ public void gotoMarker(IMarker marker) { if (fIsUpdatingMarkerViews) return; if (getSourceViewer() == null) return; int start= MarkerUtilities.getCharStart(marker); int end= MarkerUtilities.getCharEnd(marker); boolean selectLine= start < 0 || end < 0; // look up the current range of the marker when the document has been edited IAnnotationModel model= getDocumentProvider().getAnnotationModel(getEditorInput()); if (model instanceof AbstractMarkerAnnotationModel) { AbstractMarkerAnnotationModel markerModel= (AbstractMarkerAnnotationModel) model; Position pos= markerModel.getMarkerPosition(marker); if (pos != null && !pos.isDeleted()) { // use position instead of marker values start= pos.getOffset(); end= pos.getOffset() + pos.getLength(); } if (pos != null && pos.isDeleted()) { // do nothing if position has been deleted return; } } IDocument document= getDocumentProvider().getDocument(getEditorInput()); if (selectLine) { int line; try { if (start >= 0) line= document.getLineOfOffset(start); else { line= MarkerUtilities.getLineNumber(marker); // Marker line numbers are 1-based -- line; start= document.getLineOffset(line); } end= start + document.getLineLength(line) - 1; } catch (BadLocationException e) { return; } } int length= document.getLength(); if (end <= length && start <= length) { fIsComingFromGotoMarker= true; selectAndReveal(start, end - start); } } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#isEditable() * @since 3.3 */ public boolean isEditable() { if (!super.isEditable()) return false; return fIsEditingDerivedFileAllowed; } /* * @see org.eclipse.ui.texteditor.StatusTextEditor#validateEditorInputState() * @since 3.3 */ public boolean validateEditorInputState() { if (!super.validateEditorInputState()) return false; return validateEditorInputDerived(); } /** * Validates the editor input for derived state. * If the given input is derived then this method * can show a dialog asking whether to edit the * derived file. * * @return <code>true</code> if the input is OK for editing, <code>false</code> otherwise * @since 3.3 */ private boolean validateEditorInputDerived() { if (fIsDerivedStateValidated) return fIsEditingDerivedFileAllowed; if (getDocumentProvider() instanceof IDocumentProviderExtension) { IDocumentProviderExtension extension= (IDocumentProviderExtension)getDocumentProvider(); IStatus status= extension.getStatus(getEditorInput()); String pluginId= status.getPlugin(); boolean isDerivedStatus= status.getCode() == IFileBufferStatusCodes.DERIVED_FILE && (FileBuffers.PLUGIN_ID.equals(pluginId) || EditorsUI.PLUGIN_ID.equals(pluginId)); if (!isDerivedStatus) return true; } final String warnKey= AbstractDecoratedTextEditorPreferenceConstants.EDITOR_WARN_IF_INPUT_DERIVED; IPreferenceStore store= getPreferenceStore(); if (!store.getBoolean(warnKey)) return true; MessageDialogWithToggle toggleDialog= MessageDialogWithToggle.openYesNoQuestion( getSite().getShell(), TextEditorMessages.AbstractDecoratedTextEditor_warning_derived_title, TextEditorMessages.AbstractDecoratedTextEditor_warning_derived_message, TextEditorMessages.AbstractDecoratedTextEditor_warning_derived_dontShowAgain, false, null, null); EditorsUI.getPreferenceStore().setValue(warnKey, !toggleDialog.getToggleState()); fIsDerivedStateValidated= true; return fIsEditingDerivedFileAllowed= toggleDialog.getReturnCode() == IDialogConstants.YES_ID; } /* * For an explanation why we override this method see http://bugs.eclipse.org/42230 * * @see org.eclipse.ui.texteditor.StatusTextEditor#isErrorStatus(org.eclipse.core.runtime.IStatus) */ protected boolean isErrorStatus(IStatus status) { if (!super.isErrorStatus(status)) return false; if (!status.isMultiStatus()) return !isReadOnlyLocalStatus(status); IStatus[] childrenStatus= status.getChildren(); for (int i= 0; i < childrenStatus.length; i++) { if (childrenStatus[i].getSeverity() == IStatus.ERROR && !isReadOnlyLocalStatus(childrenStatus[i])) return true; } return false; } /** * Check whether the given status is a <code>IResourceStatus.READ_ONLY_LOCAL</code> * error. * * @param status the status to be checked * @return <code>true</code> if the given status is a <code>IResourceStatus.READ_ONLY_LOCAL</code> error * @since 3.3 */ private boolean isReadOnlyLocalStatus(IStatus status) { return status.getCode() == IResourceStatus.READ_ONLY_LOCAL; } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#createActions() */ protected void createActions() { super.createActions(); ResourceAction action= new AddMarkerAction(TextEditorMessages.getBundleForConstructedKeys(), "Editor.AddBookmark.", this, IMarker.BOOKMARK, true); //$NON-NLS-1$ action.setHelpContextId(ITextEditorHelpContextIds.BOOKMARK_ACTION); action.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_ADD_BOOKMARK); setAction(IDEActionFactory.BOOKMARK.getId(), action); action= new AddTaskAction(TextEditorMessages.getBundleForConstructedKeys(), "Editor.AddTask.", this); //$NON-NLS-1$ action.setHelpContextId(ITextEditorHelpContextIds.ADD_TASK_ACTION); action.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_ADD_TASK); setAction(IDEActionFactory.ADD_TASK.getId(), action); action= new ChangeEncodingAction(TextEditorMessages.getBundleForConstructedKeys(), "Editor.ChangeEncodingAction.", this); //$NON-NLS-1$ action.setHelpContextId(ITextEditorHelpContextIds.CHANGE_ENCODING); action.setActionDefinitionId(ITextEditorActionDefinitionIds.CHANGE_ENCODING); setAction(ITextEditorActionConstants.CHANGE_ENCODING, action); markAsPropertyDependentAction(ITextEditorActionConstants.CHANGE_ENCODING, true); action= new ResourceAction(TextEditorMessages.getBundleForConstructedKeys(), "Editor.ToggleLineNumbersAction.", IAction.AS_CHECK_BOX) { //$NON-NLS-1$ public void run() { toggleLineNumberRuler(); } }; action.setActionDefinitionId(ITextEditorActionDefinitionIds.LINENUMBER_TOGGLE); setAction(ITextEditorActionConstants.LINENUMBERS_TOGGLE, action); action= new ResourceAction(TextEditorMessages.getBundleForConstructedKeys(), "Editor.ToggleQuickDiffAction.", IAction.AS_CHECK_BOX) { //$NON-NLS-1$ public void run() { toggleQuickDiffRuler(); } }; action.setActionDefinitionId(ITextEditorActionDefinitionIds.QUICKDIFF_TOGGLE); setAction(ITextEditorActionConstants.QUICKDIFF_TOGGLE, action); action= new RevertLineAction(this, false); action.setActionDefinitionId(ITextEditorActionDefinitionIds.QUICKDIFF_REVERTLINE); setAction(ITextEditorActionConstants.QUICKDIFF_REVERTLINE, action); action= new RevertSelectionAction(this, false); setAction(ITextEditorActionConstants.QUICKDIFF_REVERTSELECTION, action); action= new RevertBlockAction(this, false); setAction(ITextEditorActionConstants.QUICKDIFF_REVERTBLOCK, action); action= new RestoreAction(this, false); setAction(ITextEditorActionConstants.QUICKDIFF_REVERTDELETION, action); IAction action2= new CompositeRevertAction(this, new IAction[] { getAction(ITextEditorActionConstants.QUICKDIFF_REVERTSELECTION), getAction(ITextEditorActionConstants.QUICKDIFF_REVERTBLOCK), getAction(ITextEditorActionConstants.QUICKDIFF_REVERTDELETION), getAction(ITextEditorActionConstants.QUICKDIFF_REVERTLINE)}); action2.setActionDefinitionId(ITextEditorActionDefinitionIds.QUICKDIFF_REVERT); setAction(ITextEditorActionConstants.QUICKDIFF_REVERT, action2); action= new ResourceAction(TextEditorMessages.getBundleForConstructedKeys(), "Editor.HideRevisionInformationAction.") { //$NON-NLS-1$ public void run() { if (fLineColumn != null) fLineColumn.hideRevisionInformation(); } }; setAction(ITextEditorActionConstants.REVISION_HIDE_INFO, action); action= new ResourceAction(TextEditorMessages.getBundleForConstructedKeys(), "Editor.CycleRevisionRenderingAction.") { //$NON-NLS-1$ public void run() { final RenderingMode[] modes= { IRevisionRulerColumnExtension.AGE, IRevisionRulerColumnExtension.AUTHOR, IRevisionRulerColumnExtension.AUTHOR_SHADED_BY_AGE}; IPreferenceStore store= EditorsUI.getPreferenceStore(); String current= store.getString(AbstractDecoratedTextEditorPreferenceConstants.REVISION_RULER_RENDERING_MODE); for (int i= 0; i < modes.length; i++) { String mode= modes[i].name(); if (mode.equals(current)) { int nextIndex= (i + 1) % modes.length; RenderingMode nextMode= modes[nextIndex]; store.setValue(AbstractDecoratedTextEditorPreferenceConstants.REVISION_RULER_RENDERING_MODE, nextMode.name()); } } } }; action.setActionDefinitionId(ITextEditorActionDefinitionIds.REVISION_RENDERING_CYCLE); setAction(ITextEditorActionConstants.REVISION_RENDERING_CYCLE, action); action= new BooleanPreferenceToggleAction(TextEditorMessages.getBundleForConstructedKeys(), "Editor.ToggleRevisionAuthorAction.", IAction.AS_CHECK_BOX, EditorsUI.getPreferenceStore(), AbstractDecoratedTextEditorPreferenceConstants.REVISION_RULER_SHOW_AUTHOR); //$NON-NLS-1$ action.setActionDefinitionId(ITextEditorActionDefinitionIds.REVISION_AUTHOR_TOGGLE); setAction(ITextEditorActionConstants.REVISION_SHOW_AUTHOR_TOGGLE, action); action= new BooleanPreferenceToggleAction(TextEditorMessages.getBundleForConstructedKeys(), "Editor.ToggleRevisionIdAction.", IAction.AS_CHECK_BOX, EditorsUI.getPreferenceStore(), AbstractDecoratedTextEditorPreferenceConstants.REVISION_RULER_SHOW_REVISION); //$NON-NLS-1$ action.setActionDefinitionId(ITextEditorActionDefinitionIds.REVISION_ID_TOGGLE); setAction(ITextEditorActionConstants.REVISION_SHOW_ID_TOGGLE, action); final Shell shell; if (getSourceViewer() != null) shell= getSourceViewer().getTextWidget().getShell(); else shell= null; action= new ResourceAction(TextEditorMessages.getBundleForConstructedKeys(), "Editor.RulerPreferencesAction.") { //$NON-NLS-1$ public void run() { String[] preferencePages= collectRulerMenuPreferencePages(); if (preferencePages.length > 0 && (shell == null || !shell.isDisposed())) PreferencesUtil.createPreferenceDialogOn(shell, preferencePages[0], preferencePages, null).open(); } }; setAction(ITextEditorActionConstants.RULER_PREFERENCES, action); action= new ResourceAction(TextEditorMessages.getBundleForConstructedKeys(), "Editor.ContextPreferencesAction.") { //$NON-NLS-1$ public void run() { String[] preferencePages= collectContextMenuPreferencePages(); if (preferencePages.length > 0 && (shell == null || !shell.isDisposed())) PreferencesUtil.createPreferenceDialogOn(shell, preferencePages[0], preferencePages, null).open(); } }; setAction(ITextEditorActionConstants.CONTEXT_PREFERENCES, action); IAction showWhitespaceCharactersAction= getAction(ITextEditorActionConstants.SHOW_WHITESPACE_CHARACTERS); if (showWhitespaceCharactersAction instanceof ShowWhitespaceCharactersAction) ((ShowWhitespaceCharactersAction)showWhitespaceCharactersAction).setPreferenceStore(EditorsUI.getPreferenceStore()); setAction(ITextEditorActionConstants.REFRESH, new RefreshEditorAction(this)); markAsPropertyDependentAction(ITextEditorActionConstants.REFRESH, true); // Override print action to provide additional options if (getAction(ITextEditorActionConstants.PRINT).isEnabled() && getSourceViewer() instanceof ITextViewerExtension8) createPrintAction(); action= new ResourceAction(TextEditorMessages.getBundleForConstructedKeys(), "Editor.ShowChangeRulerInformation.", IAction.AS_PUSH_BUTTON) { //$NON-NLS-1$ public void run() { showChangeRulerInformation(); } }; action.setActionDefinitionId(ITextEditorActionDefinitionIds.SHOW_CHANGE_RULER_INFORMATION_ID); setAction(ITextEditorActionConstants.SHOW_CHANGE_RULER_INFORMATION, action); action= new ResourceAction(TextEditorMessages.getBundleForConstructedKeys(), "Editor.ShowRulerAnnotationInformation.", IAction.AS_PUSH_BUTTON) { //$NON-NLS-1$ public void run() { showRulerAnnotationInformation(); } }; action.setActionDefinitionId(ITextEditorActionDefinitionIds.SHOW_RULER_ANNOTATION_INFORMATION_ID); setAction(ITextEditorActionConstants.SHOW_RULER_ANNOTATION_INFORMATION, action); } /** * Opens a sticky change ruler hover for the caret line. Does nothing if no change hover is * available. * * @since 3.5 */ private void showChangeRulerInformation() { IVerticalRuler ruler= getVerticalRuler(); if (!(ruler instanceof CompositeRuler) || fLineColumn == null) return; CompositeRuler compositeRuler= (CompositeRuler)ruler; // fake a mouse move (some hovers rely on this to determine the hovered line): int x= fLineColumn.getControl().getLocation().x; ISourceViewer sourceViewer= getSourceViewer(); StyledText textWidget= sourceViewer.getTextWidget(); int caretOffset= textWidget.getCaretOffset(); int caretLine= textWidget.getLineAtOffset(caretOffset); int y= textWidget.getLinePixel(caretLine); compositeRuler.setLocationOfLastMouseButtonActivity(x, y); IAnnotationHover hover= fLineColumn.getHover(); showFocusedRulerHover(hover, sourceViewer, caretOffset); } /** * Opens a sticky annotation ruler hover for the caret line. Does nothing if no annotation hover * is available. * * @since 3.6 */ private void showRulerAnnotationInformation() { ISourceViewer sourceViewer= getSourceViewer(); IAnnotationHover hover= getSourceViewerConfiguration().getAnnotationHover(sourceViewer); int caretOffset= sourceViewer.getTextWidget().getCaretOffset(); showFocusedRulerHover(hover, sourceViewer, caretOffset); } /** * Shows a focused hover at the specified offset. * Does nothing if <code>hover</code> is <code>null</code> or cannot be shown. * * @param hover the hover to be shown, can be <code>null</code> * @param sourceViewer the source viewer * @param caretOffset the caret offset * * @since 3.6 */ private void showFocusedRulerHover(IAnnotationHover hover, ISourceViewer sourceViewer, int caretOffset) { if (hover == null) return; int modelCaretOffset= widgetOffset2ModelOffset(sourceViewer, caretOffset); if (modelCaretOffset == -1) return; IDocument document= sourceViewer.getDocument(); if (document == null) return; try { int line= document.getLineOfOffset(modelCaretOffset); if (fInformationPresenter == null) { fInformationPresenter= new FocusedInformationPresenter(sourceViewer, getSourceViewerConfiguration()); } fInformationPresenter.openFocusedAnnotationHover(hover, line); } catch (BadLocationException e) { return; } } /** * Creates and registers the print action. * * @since 3.4 */ private void createPrintAction() { final ISourceViewer viewer= getSourceViewer(); ResourceAction action= new ResourceAction(TextEditorMessages.getBundleForConstructedKeys(), "Editor.Print.") { //$NON-NLS-1$ public void run() { StyledTextPrintOptions options= new StyledTextPrintOptions(); options.printTextFontStyle= true; options.printTextForeground= true; options.printTextBackground= true; options.jobName= getTitle(); options.header= StyledTextPrintOptions.SEPARATOR + getTitle(); options.footer= StyledTextPrintOptions.SEPARATOR + NLSUtility.format(TextEditorMessages.AbstractDecoratedTextEditor_printPageNumber, StyledTextPrintOptions.PAGE_TAG); if (isLineNumberRulerVisible()) { options.printLineNumbers= true; // Compute line number labels options.lineLabels= new String[viewer.getTextWidget().getLineCount()]; for (int i= 0; i < options.lineLabels.length; i++) options.lineLabels[i]= String.valueOf(JFaceTextUtil.widgetLine2ModelLine(viewer, i) + 1); } ((ITextViewerExtension8)viewer).print(options); } }; action.setHelpContextId(IAbstractTextEditorHelpContextIds.PRINT_ACTION); action.setActionDefinitionId(IWorkbenchCommandConstants.FILE_PRINT); setAction(ITextEditorActionConstants.PRINT, action); } public Object getAdapter(Class adapter) { if (IGotoMarker.class.equals(adapter)) return fGotoMarkerAdapter; if (IAnnotationAccess.class.equals(adapter)) return getAnnotationAccess(); if (adapter == IShowInSource.class) { return new IShowInSource() { public ShowInContext getShowInContext() { ISelection selection= null; ISelectionProvider selectionProvider= getSelectionProvider(); if (selectionProvider != null) selection= selectionProvider.getSelection(); return new ShowInContext(getEditorInput(), selection); } }; } if (IRevisionRulerColumn.class.equals(adapter)) { if (fLineNumberRulerColumn instanceof IRevisionRulerColumn) return fLineNumberRulerColumn; } if (MarkerAnnotationPreferences.class.equals(adapter)) return EditorsPlugin.getDefault().getMarkerAnnotationPreferences(); return super.getAdapter(adapter); } /* * If there is no explicit document provider set, the implicit one is * re-initialized based on the given editor input. * * @see org.eclipse.ui.texteditor.AbstractTextEditor#setDocumentProvider(org.eclipse.ui.IEditorInput) */ protected void setDocumentProvider(IEditorInput input) { fImplicitDocumentProvider= DocumentProviderRegistry.getDefault().getDocumentProvider(input); IDocumentProvider provider= super.getDocumentProvider(); if (provider instanceof ForwardingDocumentProvider) { ForwardingDocumentProvider forwarder= (ForwardingDocumentProvider) provider; forwarder.setParentProvider(fImplicitDocumentProvider); } } /* * @see org.eclipse.ui.texteditor.ITextEditor#getDocumentProvider() */ public IDocumentProvider getDocumentProvider() { IDocumentProvider provider= super.getDocumentProvider(); if (provider == null) return fImplicitDocumentProvider; return provider; } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#disposeDocumentProvider() */ protected void disposeDocumentProvider() { super.disposeDocumentProvider(); fImplicitDocumentProvider= null; } /* * @see AbstractTextEditor#doSetInput(IEditorInput) * * This implementation also updates change information in the quick diff * ruler. */ protected void doSetInput(IEditorInput input) throws CoreException { fIsDerivedStateValidated= false; fIsEditingDerivedFileAllowed= true; if (fLineColumn != null) fLineColumn.hideRevisionInformation(); super.doSetInput(input); RulerColumnDescriptor lineNumberColumnDescriptor= RulerColumnRegistry.getDefault().getColumnDescriptor(LineNumberColumn.ID); if (lineNumberColumnDescriptor != null) { IColumnSupport columnSupport= (IColumnSupport)getAdapter(IColumnSupport.class); columnSupport.setColumnVisible(lineNumberColumnDescriptor, isLineNumberRulerVisible() || isPrefQuickDiffAlwaysOn()); } } /* * @see org.eclipse.ui.texteditor.StatusTextEditor#handleEditorInputChanged() * @since 3.7 */ protected void handleEditorInputChanged() { final IDocumentProvider provider= getDocumentProvider(); IEditorInput input= getEditorInput(); if (provider != null && input != null) { if (!provider.isDeleted(input) && !isDirty() && input.getAdapter(IFile.class) != null) { IEclipsePreferences pref= InstanceScope.INSTANCE.getNode(ResourcesPlugin.PI_RESOURCES); if (pref != null && pref.getBoolean(ResourcesPlugin.PREF_LIGHTWEIGHT_AUTO_REFRESH, false)) return; } } super.handleEditorInputChanged(); } /** * This implementation asks the user for the workspace path of a file resource and saves the document there. * * @param progressMonitor the progress monitor to be used * @since 3.2 */ protected void performSaveAs(IProgressMonitor progressMonitor) { Shell shell= PlatformUI.getWorkbench().getModalDialogShellProvider().getShell(); final IEditorInput input= getEditorInput(); IDocumentProvider provider= getDocumentProvider(); final IEditorInput newInput; if (input instanceof IURIEditorInput && !(input instanceof IFileEditorInput)) { FileDialog dialog= new FileDialog(shell, SWT.SAVE); IPath oldPath= URIUtil.toPath(((IURIEditorInput)input).getURI()); if (oldPath != null) { dialog.setFileName(oldPath.lastSegment()); dialog.setFilterPath(oldPath.toOSString()); } String path= dialog.open(); if (path == null) { if (progressMonitor != null) progressMonitor.setCanceled(true); return; } // Check whether file exists and if so, confirm overwrite final File localFile= new File(path); if (localFile.exists()) { MessageDialog overwriteDialog= new MessageDialog( shell, TextEditorMessages.AbstractDecoratedTextEditor_saveAs_overwrite_title, null, NLSUtility.format(TextEditorMessages.AbstractDecoratedTextEditor_saveAs_overwrite_message, path), MessageDialog.WARNING, new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL }, 1); // 'No' is the default if (overwriteDialog.open() != Window.OK) { if (progressMonitor != null) { progressMonitor.setCanceled(true); return; } } } IFileStore fileStore; try { fileStore= EFS.getStore(localFile.toURI()); } catch (CoreException ex) { EditorsPlugin.log(ex.getStatus()); String title= TextEditorMessages.AbstractDecoratedTextEditor_error_saveAs_title; String msg= NLSUtility.format(TextEditorMessages.AbstractDecoratedTextEditor_error_saveAs_message, ex.getMessage()); MessageDialog.openError(shell, title, msg); return; } IFile file= getWorkspaceFile(fileStore); if (file != null) newInput= new FileEditorInput(file); else newInput= new FileStoreEditorInput(fileStore); } else { SaveAsDialog dialog= new SaveAsDialog(shell); IFile original= (input instanceof IFileEditorInput) ? ((IFileEditorInput) input).getFile() : null; if (original != null) dialog.setOriginalFile(original); else dialog.setOriginalName(input.getName()); dialog.create(); if (provider.isDeleted(input) && original != null) { String message= NLSUtility.format(TextEditorMessages.AbstractDecoratedTextEditor_warning_saveAs_deleted, original.getName()); dialog.setErrorMessage(null); dialog.setMessage(message, IMessageProvider.WARNING); } if (dialog.open() == Window.CANCEL) { if (progressMonitor != null) progressMonitor.setCanceled(true); return; } IPath filePath= dialog.getResult(); if (filePath == null) { if (progressMonitor != null) progressMonitor.setCanceled(true); return; } IWorkspace workspace= ResourcesPlugin.getWorkspace(); IFile file= workspace.getRoot().getFile(filePath); newInput= new FileEditorInput(file); } if (provider == null) { // editor has programmatically been closed while the dialog was open return; } boolean success= false; try { provider.aboutToChange(newInput); provider.saveDocument(progressMonitor, newInput, provider.getDocument(input), true); success= true; } catch (CoreException x) { final IStatus status= x.getStatus(); if (status == null || status.getSeverity() != IStatus.CANCEL) { String title= TextEditorMessages.AbstractDecoratedTextEditor_error_saveAs_title; String msg= NLSUtility.format(TextEditorMessages.AbstractDecoratedTextEditor_error_saveAs_message, x.getMessage()); MessageDialog.openError(shell, title, msg); } } finally { provider.changed(newInput); if (success) setInput(newInput); } if (progressMonitor != null) progressMonitor.setCanceled(!success); } /** * Presents an error dialog to the user when a problem happens during save. * <p> * Overrides the default behavior by showing a more advanced error dialog in case of encoding * problems. * </p> * * @param title the dialog title * @param message the message to display * @param exception the exception to handle * @since 3.6 */ protected void openSaveErrorDialog(String title, String message, CoreException exception) { IStatus status= exception.getStatus(); final IDocumentProvider documentProvider= getDocumentProvider(); if (!(status.getCode() == IFileBufferStatusCodes.CHARSET_MAPPING_FAILED && documentProvider instanceof IStorageDocumentProvider)) { super.openSaveErrorDialog(title, message, exception); return; } final int saveAsUTF8ButtonId= IDialogConstants.OK_ID + IDialogConstants.CANCEL_ID + 1; final int selectUnmappableCharButtonId= saveAsUTF8ButtonId + 1; final Charset charset= getCharset(); ErrorDialog errorDialog= new ErrorDialog(getSite().getShell(), title, message, status, IStatus.ERROR) { protected void createButtonsForButtonBar(Composite parent) { super.createButtonsForButtonBar(parent); createButton(parent, saveAsUTF8ButtonId, TextEditorMessages.AbstractDecoratedTextEditor_save_error_Dialog_button_saveAsUTF8, false); if (charset != null) createButton(parent, selectUnmappableCharButtonId, TextEditorMessages.AbstractDecoratedTextEditor_save_error_Dialog_button_selectUnmappable, false); } protected void buttonPressed(int id) { if (id == saveAsUTF8ButtonId || id == selectUnmappableCharButtonId) { setReturnCode(id); close(); } else super.buttonPressed(id); } protected boolean shouldShowDetailsButton() { return false; } }; int returnCode= errorDialog.open(); if (returnCode == saveAsUTF8ButtonId) { ((IStorageDocumentProvider)documentProvider).setEncoding(getEditorInput(), "UTF-8"); //$NON-NLS-1$ doSave(getProgressMonitor()); } else if (returnCode == selectUnmappableCharButtonId) { CharsetEncoder encoder= charset.newEncoder(); IDocument document= getDocumentProvider().getDocument(getEditorInput()); int documentLength= document.getLength(); int offset= 0; BreakIterator charBreakIterator= BreakIterator.getCharacterInstance(); charBreakIterator.setText(document.get()); while (offset < documentLength) { try { int next= charBreakIterator.next(); String ch= document.get(offset, next - offset); if (!encoder.canEncode(ch)) { selectAndReveal(offset, next - offset); return; } offset= next; } catch (BadLocationException ex) { EditorsPlugin.log(ex); // Skip this character. Showing yet another dialog here is overkill } } } } /** * Returns the charset of the current editor input. * * @return the charset of the current editor input or <code>null</code> if it fails * @since 3.6 */ private Charset getCharset() { IEncodingSupport encodingSupport= (IEncodingSupport)getAdapter(IEncodingSupport.class); if (encodingSupport == null) return null; try { return Charset.forName(encodingSupport.getEncoding()); } catch (UnsupportedCharsetException ex) { return null; } catch (IllegalCharsetNameException ex) { return null; } } /** * Checks whether there given file store points * to a file in the workspace. Only returns a * workspace file if there's a single match. * * @param fileStore the file store * @return the <code>IFile</code> that matches the given file store * @since 3.2 */ private IFile getWorkspaceFile(IFileStore fileStore) { IWorkspaceRoot workspaceRoot= ResourcesPlugin.getWorkspace().getRoot(); IFile[] files= workspaceRoot.findFilesForLocationURI(fileStore.toURI()); if (files != null && files.length == 1) return files[0]; return null; } /** * Sets the ruler's overview context menu id. * * @param contextMenuId the overview ruler context menu id * @since 3.4 */ protected void setOverviewRulerContextMenuId(String contextMenuId) { Assert.isNotNull(contextMenuId); fOverviewRulerContextMenuId= contextMenuId; } /** * Returns the ruler's overview context menu id. May return * <code>null</code> before the editor's part has been created. * * @return the ruler's context menu id which may be <code>null</code> * @since 3.4 */ protected final String getOverviewRulerContextMenuId() { return fOverviewRulerContextMenuId; } /** * Sets up the overview ruler context menu before it is made visible. * <p> * Subclasses may extend to add other actions. * </p> * * @param menu the menu * @since 3.4 */ protected void overviewRulerContextMenuAboutToShow(IMenuManager menu) { final String preferenceLabel= findSelectedOverviewRulerAnnotationLabel(); final Shell shell= getSite().getShell(); IAction action= new ResourceAction(TextEditorMessages.getBundleForConstructedKeys(), "Editor.RulerPreferencesAction.") { //$NON-NLS-1$ public void run() { String[] preferencePages= collectOverviewRulerMenuPreferencePages(); if (preferencePages.length > 0 && (shell == null || !shell.isDisposed())) { PreferencesUtil.createPreferenceDialogOn(shell, preferencePages[0], preferencePages, preferenceLabel).open(); } } }; menu.add(new Separator(ITextEditorActionConstants.GROUP_REST)); menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); menu.add(action); } private String findSelectedOverviewRulerAnnotationLabel() { Point selection= getSourceViewer().getSelectedRange(); IAnnotationModel model= getSourceViewer().getAnnotationModel(); Annotation annotation= null; Iterator iter= model.getAnnotationIterator(); while (iter.hasNext()) { annotation= (Annotation)iter.next(); Position p= model.getPosition(annotation); if (p.getOffset() == selection.x && p.getLength() == selection.y) break; } if (annotation != null) { AnnotationPreference ap= getAnnotationPreferenceLookup().getAnnotationPreference(annotation); if (ap != null) return ap.getPreferenceLabel(); } return null; } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#rulerContextMenuAboutToShow(org.eclipse.jface.action.IMenuManager) * @since 3.1 */ protected void rulerContextMenuAboutToShow(IMenuManager menu) { /* * XXX: workaround for reliable menu item ordering. * This can be changed once the action contribution story converges, * see http://dev.eclipse.org/viewcvs/index.cgi/~checkout~/platform-ui-home/R3_1/dynamic_teams/dynamic_teams.html#actionContributions */ // pre-install menus for contributions and call super menu.add(new Separator("debug")); //$NON-NLS-1$ menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); menu.add(new GroupMarker(ITextEditorActionConstants.GROUP_RESTORE)); menu.add(new Separator("add")); //$NON-NLS-1$ menu.add(new Separator(ITextEditorActionConstants.GROUP_RULERS)); menu.add(new Separator(ITextEditorActionConstants.GROUP_REST)); super.rulerContextMenuAboutToShow(menu); addRulerContributionActions(menu); /* quick diff */ if (isEditorInputModifiable()) { IAction quickdiffAction= getAction(ITextEditorActionConstants.QUICKDIFF_TOGGLE); quickdiffAction.setChecked(isChangeInformationShowing()); menu.appendToGroup(ITextEditorActionConstants.GROUP_RULERS, quickdiffAction); if (isChangeInformationShowing()) { TextEditorAction revertLine= new RevertLineAction(this, true); TextEditorAction revertSelection= new RevertSelectionAction(this, true); TextEditorAction revertBlock= new RevertBlockAction(this, true); TextEditorAction revertDeletion= new RestoreAction(this, true); revertSelection.update(); revertBlock.update(); revertLine.update(); revertDeletion.update(); // only add block action if selection action is not enabled if (revertSelection.isEnabled()) menu.appendToGroup(ITextEditorActionConstants.GROUP_RESTORE, revertSelection); else if (revertBlock.isEnabled()) menu.appendToGroup(ITextEditorActionConstants.GROUP_RESTORE, revertBlock); if (revertLine.isEnabled()) menu.appendToGroup(ITextEditorActionConstants.GROUP_RESTORE, revertLine); if (revertDeletion.isEnabled()) menu.appendToGroup(ITextEditorActionConstants.GROUP_RESTORE, revertDeletion); } } // revision info if (fLineColumn != null && fLineColumn.isShowingRevisionInformation()) { IMenuManager revisionMenu= new MenuManager(TextEditorMessages.AbstractDecoratedTextEditor_revisions_menu); menu.appendToGroup(ITextEditorActionConstants.GROUP_RULERS, revisionMenu); IAction hideRevisionInfoAction= getAction(ITextEditorActionConstants.REVISION_HIDE_INFO); revisionMenu.add(hideRevisionInfoAction); revisionMenu.add(new Separator()); String[] labels= { TextEditorMessages.AbstractDecoratedTextEditor_revision_colors_option_by_date, TextEditorMessages.AbstractDecoratedTextEditor_revision_colors_option_by_author, TextEditorMessages.AbstractDecoratedTextEditor_revision_colors_option_by_author_and_date }; final RenderingMode[] modes= { IRevisionRulerColumnExtension.AGE, IRevisionRulerColumnExtension.AUTHOR, IRevisionRulerColumnExtension.AUTHOR_SHADED_BY_AGE}; final IPreferenceStore uiStore= EditorsUI.getPreferenceStore(); String current= uiStore.getString(AbstractDecoratedTextEditorPreferenceConstants.REVISION_RULER_RENDERING_MODE); for (int i= 0; i < modes.length; i++) { final String mode= modes[i].name(); IAction action= new Action(labels[i], IAction.AS_RADIO_BUTTON) { public void run() { // set preference globally, LineNumberColumn reacts on preference change uiStore.setValue(AbstractDecoratedTextEditorPreferenceConstants.REVISION_RULER_RENDERING_MODE, mode); } }; action.setChecked(mode.equals(current)); revisionMenu.add(action); } revisionMenu.add(new Separator()); IAction action= getAction(ITextEditorActionConstants.REVISION_SHOW_AUTHOR_TOGGLE); if (action instanceof IUpdate) ((IUpdate)action).update(); revisionMenu.add(action); action= getAction(ITextEditorActionConstants.REVISION_SHOW_ID_TOGGLE); if (action instanceof IUpdate) ((IUpdate)action).update(); revisionMenu.add(action); } IAction lineNumberAction= getAction(ITextEditorActionConstants.LINENUMBERS_TOGGLE); lineNumberAction.setChecked(fLineColumn != null && fLineColumn.isShowingLineNumbers()); menu.appendToGroup(ITextEditorActionConstants.GROUP_RULERS, lineNumberAction); IAction preferencesAction= getAction(ITextEditorActionConstants.RULER_PREFERENCES); menu.appendToGroup(ITextEditorActionConstants.GROUP_RULERS, new Separator(ITextEditorActionConstants.GROUP_SETTINGS)); menu.appendToGroup(ITextEditorActionConstants.GROUP_SETTINGS, preferencesAction); } /** * Adds "show" actions for all contributed rulers that support it. * * @param menu the ruler context menu * @since 3.3 */ private void addRulerContributionActions(IMenuManager menu) { // store directly in generic editor preferences final IColumnSupport support= (IColumnSupport) getAdapter(IColumnSupport.class); IPreferenceStore store= EditorsUI.getPreferenceStore(); final RulerColumnPreferenceAdapter adapter= new RulerColumnPreferenceAdapter(store, AbstractTextEditor.PREFERENCE_RULER_CONTRIBUTIONS); List descriptors= RulerColumnRegistry.getDefault().getColumnDescriptors(); for (Iterator t= descriptors.iterator(); t.hasNext();) { final RulerColumnDescriptor descriptor= (RulerColumnDescriptor) t.next(); if (!descriptor.isIncludedInMenu() || !support.isColumnSupported(descriptor)) continue; final boolean isVisible= support.isColumnVisible(descriptor); IAction action= new Action(MessageFormat.format(TextEditorMessages.AbstractDecoratedTextEditor_show_ruler_label, new Object[] {descriptor.getName()}), IAction.AS_CHECK_BOX) { public void run() { if (descriptor.isGlobal()) // column state is modified via preference listener of AbstractTextEditor adapter.setEnabled(descriptor, !isVisible); else // directly modify column for this editor instance support.setColumnVisible(descriptor, !isVisible); } }; action.setChecked(isVisible); action.setImageDescriptor(descriptor.getIcon()); menu.appendToGroup(ITextEditorActionConstants.GROUP_RULERS, action); } } /** * Toggles the line number global preference and shows the line number ruler * accordingly. * * @since 3.1 */ private void toggleLineNumberRuler() { // globally IPreferenceStore store= EditorsUI.getPreferenceStore(); store.setValue(LINE_NUMBER_RULER, !isLineNumberRulerVisible()); } /** * Toggles the quick diff global preference and shows the quick diff ruler * accordingly. * * @since 3.1 */ private void toggleQuickDiffRuler() { // change the visibility locally if this editor is not in sync with the global preference // toggle the preference if we are in sync. IPreferenceStore store= EditorsUI.getPreferenceStore(); boolean current= store.getBoolean(AbstractDecoratedTextEditorPreferenceConstants.QUICK_DIFF_ALWAYS_ON); if (current == isChangeInformationShowing()) store.setValue(AbstractDecoratedTextEditorPreferenceConstants.QUICK_DIFF_ALWAYS_ON, !current); else showChangeInformation(current); } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#editorContextMenuAboutToShow(org.eclipse.jface.action.IMenuManager) * @since 3.1 */ protected void editorContextMenuAboutToShow(IMenuManager menu) { super.editorContextMenuAboutToShow(menu); IAction preferencesAction= getAction(ITextEditorActionConstants.CONTEXT_PREFERENCES); menu.appendToGroup(IWorkbenchActionConstants.MB_ADDITIONS, new Separator(ITextEditorActionConstants.GROUP_SETTINGS)); menu.appendToGroup(ITextEditorActionConstants.GROUP_SETTINGS, preferencesAction); menu.appendToGroup(ITextEditorActionConstants.GROUP_SAVE, new Separator(ITextEditorActionConstants.GROUP_OPEN)); IEditorInput editorInput= getEditorInput(); if (((IResource)editorInput.getAdapter(IResource.class)) instanceof IFile) { MenuManager openWithSubMenu= new MenuManager(TextEditorMessages.AbstractDecoratedTextEditor_openWith_menu); final IWorkbenchPage page= getEditorSite().getPage(); // XXX: Internal reference will get fixed during 3.7, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=307026 openWithSubMenu.add(new OpenWithMenu(page, editorInput) { protected void openEditor(IEditorDescriptor editorDescriptor, boolean openUsingDescriptor) { super.openEditor(editorDescriptor, openUsingDescriptor); ISelection selection= getSelectionProvider().getSelection(); if (selection instanceof ITextSelection) { revealInEditor(page.getActiveEditor(), ((ITextSelection)selection).getOffset(), ((ITextSelection)selection).getLength()); } } }); menu.appendToGroup(ITextEditorActionConstants.GROUP_OPEN, openWithSubMenu); } MenuManager showInSubMenu= new MenuManager(getShowInMenuLabel()); showInSubMenu.add(ContributionItemFactory.VIEWS_SHOW_IN.create(getEditorSite().getWorkbenchWindow())); menu.appendToGroup(ITextEditorActionConstants.GROUP_OPEN, showInSubMenu); } /** * Selects and reveals the given offset and length in the given editor part. * * @param editor the editor part * @param offset the offset * @param length the length * @since 3.7 */ private static void revealInEditor(IEditorPart editor, final int offset, final int length) { if (editor instanceof ITextEditor) { ((ITextEditor)editor).selectAndReveal(offset, length); return; } // Support for non-text editor - try IGotoMarker interface final IGotoMarker gotoMarkerTarget; if (editor instanceof IGotoMarker) gotoMarkerTarget= (IGotoMarker)editor; else gotoMarkerTarget= editor != null ? (IGotoMarker)editor.getAdapter(IGotoMarker.class) : null; if (gotoMarkerTarget != null) { final IEditorInput input= editor.getEditorInput(); if (input instanceof IFileEditorInput) { WorkspaceModifyOperation op= new WorkspaceModifyOperation() { protected void execute(IProgressMonitor monitor) throws CoreException { IMarker marker= null; try { marker= ((IFileEditorInput)input).getFile().createMarker(IMarker.TEXT); marker.setAttribute(IMarker.CHAR_START, offset); marker.setAttribute(IMarker.CHAR_END, offset + length); gotoMarkerTarget.gotoMarker(marker); } finally { if (marker != null) marker.delete(); } } }; try { op.run(null); } catch (InvocationTargetException ex) { // reveal failed } catch (InterruptedException e) { Assert.isTrue(false, "this operation can not be canceled"); //$NON-NLS-1$ } } return; } } /** * Returns the menu label for 'Show In' together with its key binding string. * * @return the 'Show In' menu label * @since 3.2 */ private String getShowInMenuLabel() { String keyBinding= null; IBindingService bindingService= (IBindingService)PlatformUI.getWorkbench().getAdapter(IBindingService.class); if (bindingService != null) keyBinding= bindingService.getBestActiveBindingFormattedFor(IWorkbenchCommandConstants.NAVIGATE_SHOW_IN_QUICK_MENU); if (keyBinding == null) keyBinding= ""; //$NON-NLS-1$ return NLSUtility.format(TextEditorMessages.AbstractDecoratedTextEditor_showIn_menu, keyBinding); } /** * Returns the preference page ids of the preference pages to be shown when executing the * preferences action from the editor context menu. The first page will be selected. * <p> * Subclasses may extend or replace. * </p> * * @return the preference page ids to show, may be empty * @since 3.1 */ protected String[] collectContextMenuPreferencePages() { return new String[] { "org.eclipse.ui.preferencePages.GeneralTextEditor", //$NON-NLS-1$ "org.eclipse.ui.editors.preferencePages.Annotations", //$NON-NLS-1$ "org.eclipse.ui.editors.preferencePages.QuickDiff", //$NON-NLS-1$ "org.eclipse.ui.editors.preferencePages.Accessibility", //$NON-NLS-1$ "org.eclipse.ui.editors.preferencePages.Spelling", //$NON-NLS-1$ "org.eclipse.ui.editors.preferencePages.LinkedModePreferencePage", //$NON-NLS-1$ "org.eclipse.ui.preferencePages.ColorsAndFonts", //$NON-NLS-1$ }; } /** * Returns the preference page ids of the preference pages to be shown when executing the * preferences action from the editor ruler context menu. The first page will be selected. * <p> * The default is to return the same list as <code>collectContextMenuPreferencePages</code>. * </p> * <p> * Subclasses may extend or replace. * </p> * * @return the preference page ids to show, may be empty * @since 3.1 */ protected String[] collectRulerMenuPreferencePages() { return collectContextMenuPreferencePages(); } /** * Returns the preference page ids of the preference pages to be shown when executing the * preferences action from the editor overview ruler context menu. The first page will be * selected. * <p> * The default is to select the 'Annotations' preference page. * </p> * <p> * Subclasses may extend or replace. * </p> * * @return the preference page ids to show, may be empty * @since 3.4 */ protected String[] collectOverviewRulerMenuPreferencePages() { return new String[] { "org.eclipse.ui.editors.preferencePages.Annotations", //$NON-NLS-1$ "org.eclipse.ui.preferencePages.GeneralTextEditor", //$NON-NLS-1$ "org.eclipse.ui.editors.preferencePages.QuickDiff", //$NON-NLS-1$ "org.eclipse.ui.preferencePages.ColorsAndFonts" //$NON-NLS-1$ }; } /* * @see AbstractTextEditor#getUndoRedoOperationApprover(IUndoContext) * @since 3.1 */ protected IOperationApprover getUndoRedoOperationApprover(IUndoContext undoContext) { IEditorInput input= getEditorInput(); if (input != null && input.getAdapter(IResource.class) != null) return new NonLocalUndoUserApprover(undoContext, this, new Object [] { input }, IResource.class); return super.getUndoRedoOperationApprover(undoContext); } /** * Returns whether the given annotation is configured as a target for the * "Go to Next/Previous Annotation" actions. * <p> * The annotation is a target if their annotation type is configured to be * in the Next/Previous tool bar drop down menu and if it is checked. * </p> * * @param annotation the annotation * @return <code>true</code> if this is a target, <code>false</code> otherwise * @since 3.2 */ protected boolean isNavigationTarget(Annotation annotation) { AnnotationPreference preference= getAnnotationPreferenceLookup().getAnnotationPreference(annotation); // See bug 41689 // String key= forward ? preference.getIsGoToNextNavigationTargetKey() : preference.getIsGoToPreviousNavigationTargetKey(); String key= preference == null ? null : preference.getIsGoToNextNavigationTargetKey(); return (key != null && getPreferenceStore().getBoolean(key)); } /** * {@inheritDoc} * <p> * This extended implementation updates views that also show the * select marker annotation. * </p> * @since 3.2 */ public Annotation gotoAnnotation(boolean forward) { Annotation annotation= super.gotoAnnotation(forward); if (annotation != null) updateMarkerViews(annotation); return annotation; } /** * Updates visible views that show markers. * <p> * If the given annotation can be associated with a marker then this method tries select the * this marker in views that show markers. * </p> * * @param annotation the annotation * @since 3.2 */ protected void updateMarkerViews(Annotation annotation) { if (fIsComingFromGotoMarker) { fIsComingFromGotoMarker= false; return; } IMarker marker= null; if (annotation instanceof MarkerAnnotation) marker= ((MarkerAnnotation)annotation).getMarker(); if (marker != null) { try { fIsUpdatingMarkerViews= true; IWorkbenchPage page= getSite().getPage(); MarkerViewUtil.showMarker(page, marker, false); } finally { fIsUpdatingMarkerViews= false; } } } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#isTabConversionEnabled() * @since 3.3 */ protected boolean isTabsToSpacesConversionEnabled() { return getPreferenceStore() != null && getPreferenceStore().getBoolean(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SPACES_FOR_TABS); } }