| /******************************************************************************* |
| * Copyright (c) 2000, 2018 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 |
| * Chris.Dennis@invidi.com - http://bugs.eclipse.org/bugs/show_bug.cgi?id=29027 |
| * Michel Ishizuka (cqw10305@nifty.com) - http://bugs.eclipse.org/bugs/show_bug.cgi?id=68963 |
| * Genady Beryozkin, me@genady.org - https://bugs.eclipse.org/bugs/show_bug.cgi?id=11668 |
| * Benjamin Muskalla <b.muskalla@gmx.net> - https://bugs.eclipse.org/bugs/show_bug.cgi?id=41573 |
| * Stephan Wahlbrink <stephan.wahlbrink@walware.de> - Wrong operations mode/feedback for text drag over/drop in text editors - https://bugs.eclipse.org/bugs/show_bug.cgi?id=206043 |
| * Tom Eicher (Avaloq Evolution AG) - block selection mode |
| * Nick Sandonato <nsandona@us.ibm.com> - [implementation] AbstractTextEditor does not prompt when out of sync in MultiPageEditorPart - http://bugs.eclipse.org/337719 |
| * Holger Voormann - Word Wrap - https://bugs.eclipse.org/bugs/show_bug.cgi?id=35779 |
| * Florian Weßling <flo@cdhq.de> - Word Wrap - https://bugs.eclipse.org/bugs/show_bug.cgi?id=35779 |
| * Andrey Loskutov <loskutov@gmx.de> - Word Wrap - https://bugs.eclipse.org/bugs/show_bug.cgi?id=35779 |
| * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide extension point for CodeMining - Bug 528419 |
| *******************************************************************************/ |
| package org.eclipse.ui.texteditor; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.ResourceBundle; |
| |
| import org.osgi.framework.Bundle; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.BusyIndicator; |
| import org.eclipse.swt.custom.ST; |
| import org.eclipse.swt.custom.StyledText; |
| import org.eclipse.swt.custom.VerifyKeyListener; |
| import org.eclipse.swt.dnd.DND; |
| import org.eclipse.swt.dnd.DragSource; |
| import org.eclipse.swt.dnd.DragSourceAdapter; |
| import org.eclipse.swt.dnd.DragSourceEvent; |
| import org.eclipse.swt.dnd.DropTargetAdapter; |
| import org.eclipse.swt.dnd.DropTargetEvent; |
| import org.eclipse.swt.dnd.DropTargetListener; |
| import org.eclipse.swt.dnd.TextTransfer; |
| import org.eclipse.swt.dnd.Transfer; |
| import org.eclipse.swt.events.GestureEvent; |
| import org.eclipse.swt.events.GestureListener; |
| import org.eclipse.swt.events.KeyEvent; |
| import org.eclipse.swt.events.KeyListener; |
| import org.eclipse.swt.events.MouseEvent; |
| import org.eclipse.swt.events.MouseListener; |
| import org.eclipse.swt.events.VerifyEvent; |
| import org.eclipse.swt.events.VerifyListener; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.graphics.FontData; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.ImageData; |
| import org.eclipse.swt.graphics.PaletteData; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.RGB; |
| import org.eclipse.swt.widgets.Caret; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Listener; |
| 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.IOperationHistory; |
| import org.eclipse.core.commands.operations.IUndoContext; |
| import org.eclipse.core.commands.operations.OperationHistoryFactory; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.ILog; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.SafeRunner; |
| import org.eclipse.core.runtime.Status; |
| |
| import org.eclipse.text.undo.DocumentUndoManagerRegistry; |
| import org.eclipse.text.undo.IDocumentUndoManager; |
| |
| 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.IStatusLineManager; |
| import org.eclipse.jface.action.MenuManager; |
| import org.eclipse.jface.action.Separator; |
| import org.eclipse.jface.dialogs.ErrorDialog; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.operation.IRunnableWithProgress; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.preference.PreferenceConverter; |
| import org.eclipse.jface.resource.ImageDescriptor; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.jface.util.SafeRunnable; |
| 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.SelectionChangedEvent; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jface.window.IShellProvider; |
| |
| import org.eclipse.jface.text.AbstractInformationControlManager; |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.DefaultLineTracker; |
| import org.eclipse.jface.text.DocumentEvent; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.IDocumentListener; |
| import org.eclipse.jface.text.IFindReplaceTarget; |
| import org.eclipse.jface.text.IFindReplaceTargetExtension; |
| import org.eclipse.jface.text.IInformationControlCreator; |
| import org.eclipse.jface.text.IMarkRegionTarget; |
| import org.eclipse.jface.text.IRegion; |
| import org.eclipse.jface.text.IRewriteTarget; |
| import org.eclipse.jface.text.ISelectionValidator; |
| import org.eclipse.jface.text.ITextHover; |
| import org.eclipse.jface.text.ITextInputListener; |
| import org.eclipse.jface.text.ITextListener; |
| import org.eclipse.jface.text.ITextOperationTarget; |
| import org.eclipse.jface.text.ITextSelection; |
| import org.eclipse.jface.text.ITextViewer; |
| import org.eclipse.jface.text.ITextViewerExtension; |
| import org.eclipse.jface.text.ITextViewerExtension2; |
| import org.eclipse.jface.text.ITextViewerExtension4; |
| import org.eclipse.jface.text.ITextViewerExtension5; |
| import org.eclipse.jface.text.ITextViewerExtension6; |
| import org.eclipse.jface.text.ITextViewerExtension7; |
| import org.eclipse.jface.text.ITextViewerExtension8; |
| import org.eclipse.jface.text.ITextViewerExtension8.EnrichMode; |
| import org.eclipse.jface.text.IUndoManager; |
| import org.eclipse.jface.text.IUndoManagerExtension; |
| import org.eclipse.jface.text.Position; |
| import org.eclipse.jface.text.Region; |
| import org.eclipse.jface.text.TabsToSpacesConverter; |
| import org.eclipse.jface.text.TextEvent; |
| import org.eclipse.jface.text.TextSelection; |
| import org.eclipse.jface.text.TextUtilities; |
| import org.eclipse.jface.text.codemining.ICodeMiningProvider; |
| import org.eclipse.jface.text.hyperlink.HyperlinkManager; |
| import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; |
| import org.eclipse.jface.text.information.IInformationProvider; |
| import org.eclipse.jface.text.information.IInformationProviderExtension2; |
| import org.eclipse.jface.text.link.LinkedModeModel; |
| import org.eclipse.jface.text.link.LinkedPosition; |
| import org.eclipse.jface.text.quickassist.IQuickAssistAssistant; |
| import org.eclipse.jface.text.revisions.RevisionInformation; |
| import org.eclipse.jface.text.source.Annotation; |
| import org.eclipse.jface.text.source.CompositeRuler; |
| import org.eclipse.jface.text.source.IAnnotationHover; |
| import org.eclipse.jface.text.source.IAnnotationModel; |
| import org.eclipse.jface.text.source.ISourceViewer; |
| import org.eclipse.jface.text.source.ISourceViewerExtension3; |
| import org.eclipse.jface.text.source.ISourceViewerExtension4; |
| import org.eclipse.jface.text.source.ISourceViewerExtension5; |
| import org.eclipse.jface.text.source.IVerticalRuler; |
| import org.eclipse.jface.text.source.IVerticalRulerColumn; |
| import org.eclipse.jface.text.source.IVerticalRulerExtension; |
| import org.eclipse.jface.text.source.IVerticalRulerInfo; |
| import org.eclipse.jface.text.source.SourceViewer; |
| import org.eclipse.jface.text.source.SourceViewerConfiguration; |
| import org.eclipse.jface.text.source.VerticalRuler; |
| |
| import org.eclipse.ui.IActionBars; |
| import org.eclipse.ui.IEditorDescriptor; |
| import org.eclipse.ui.IEditorInput; |
| import org.eclipse.ui.IEditorPart; |
| import org.eclipse.ui.IEditorRegistry; |
| import org.eclipse.ui.IEditorSite; |
| import org.eclipse.ui.IKeyBindingService; |
| import org.eclipse.ui.IMemento; |
| import org.eclipse.ui.INavigationLocation; |
| import org.eclipse.ui.INavigationLocationProvider; |
| import org.eclipse.ui.IPartListener; |
| import org.eclipse.ui.IPartService; |
| import org.eclipse.ui.IPersistableEditor; |
| import org.eclipse.ui.IReusableEditor; |
| import org.eclipse.ui.ISaveablesLifecycleListener; |
| import org.eclipse.ui.ISaveablesSource; |
| import org.eclipse.ui.IWindowListener; |
| import org.eclipse.ui.IWorkbenchActionConstants; |
| import org.eclipse.ui.IWorkbenchCommandConstants; |
| import org.eclipse.ui.IWorkbenchPart; |
| import org.eclipse.ui.IWorkbenchPartSite; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.Saveable; |
| import org.eclipse.ui.SaveablesLifecycleEvent; |
| import org.eclipse.ui.actions.ActionFactory; |
| import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; |
| import org.eclipse.ui.actions.CommandNotMappedException; |
| import org.eclipse.ui.actions.ContributedAction; |
| import org.eclipse.ui.dialogs.PropertyDialogAction; |
| import org.eclipse.ui.dnd.IDragAndDropService; |
| import org.eclipse.ui.internal.texteditor.EditPosition; |
| import org.eclipse.ui.internal.texteditor.FocusedInformationPresenter; |
| import org.eclipse.ui.internal.texteditor.NLSUtility; |
| import org.eclipse.ui.internal.texteditor.TextEditorPlugin; |
| import org.eclipse.ui.internal.texteditor.rulers.StringSetSerializer; |
| import org.eclipse.ui.operations.LinearUndoViolationUserApprover; |
| import org.eclipse.ui.operations.NonLocalUndoUserApprover; |
| import org.eclipse.ui.operations.OperationHistoryActionHandler; |
| import org.eclipse.ui.operations.RedoActionHandler; |
| import org.eclipse.ui.operations.UndoActionHandler; |
| import org.eclipse.ui.part.EditorPart; |
| import org.eclipse.ui.part.MultiPageEditorSite; |
| |
| 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; |
| |
| |
| /** |
| * Abstract base implementation of a text editor. |
| * <p> |
| * Subclasses are responsible for configuring the editor appropriately. The standard text editor, |
| * <code>TextEditor</code>, is one such example. |
| * </p> |
| * <p> |
| * If a subclass calls {@linkplain #setEditorContextMenuId(String) setEditorContextMenuId} the |
| * argument is used as the id under which the editor's context menu is registered for extensions. If |
| * no id is set, the context menu is registered under <b>[editor_id].EditorContext</b> whereby |
| * [editor_id] is replaced with the editor's part id. If the editor is instructed to run in version |
| * 1.0 context menu registration compatibility mode, the latter form of the registration even |
| * happens if a context menu id has been set via {@linkplain #setEditorContextMenuId(String) |
| * setEditorContextMenuId}. If no id is set while in compatibility mode, the menu is registered |
| * under {@link #DEFAULT_EDITOR_CONTEXT_MENU_ID}. |
| * </p> |
| * <p> |
| * If a subclass calls {@linkplain #setRulerContextMenuId(String) setRulerContextMenuId} the |
| * argument is used as the id under which the ruler's context menu is registered for extensions. If |
| * no id is set, the context menu is registered under <b>[editor_id].RulerContext</b> whereby |
| * [editor_id] is replaced with the editor's part id. If the editor is instructed to run in version |
| * 1.0 context menu registration compatibility mode, the latter form of the registration even |
| * happens if a context menu id has been set via {@linkplain #setRulerContextMenuId(String) |
| * setRulerContextMenuId}. If no id is set while in compatibility mode, the menu is registered under |
| * {@link #DEFAULT_RULER_CONTEXT_MENU_ID}. |
| * </p> |
| * <p> |
| * As of 3.5, contributers can contribute editor and ruler context menu actions to all subclasses of |
| * this class by using {@link #COMMON_EDITOR_CONTEXT_MENU_ID} and |
| * {@link #COMMON_RULER_CONTEXT_MENU_ID}. |
| * </p> |
| */ |
| public abstract class AbstractTextEditor extends EditorPart implements ITextEditor, IReusableEditor, ITextEditorExtension, ITextEditorExtension2, ITextEditorExtension3, ITextEditorExtension4, ITextEditorExtension5, ITextEditorExtension6, INavigationLocationProvider, ISaveablesSource, IPersistableEditor { |
| |
| /** |
| * Tag used in xml configuration files to specify editor action contributions. |
| * Current value: <code>editorContribution</code> |
| * @since 2.0 |
| */ |
| private static final String TAG_CONTRIBUTION_TYPE= "editorContribution"; //$NON-NLS-1$ |
| |
| /** |
| * Tag used in the {@link IMemento} when saving and restoring the editor's selection offset. |
| * |
| * @see #saveState(IMemento) |
| * @see #restoreState(IMemento) |
| * @see #doRestoreState(IMemento) |
| * @since 3.3 |
| */ |
| protected static final String TAG_SELECTION_OFFSET= "selectionOffset"; //$NON-NLS-1$ |
| |
| /** |
| * Tag used in the {@link IMemento} when saving and restoring the editor's selection length. |
| * |
| * @see #saveState(IMemento) |
| * @see #restoreState(IMemento) |
| * @see #doRestoreState(IMemento) |
| * @since 3.3 |
| */ |
| protected static final String TAG_SELECTION_LENGTH= "selectionLength"; //$NON-NLS-1$ |
| |
| /** |
| * Tag used in the {@link IMemento} when saving and restoring the editor's top pixel value. |
| * |
| * @see #saveState(IMemento) |
| * @see #restoreState(IMemento) |
| * @see #doRestoreState(IMemento) |
| * @since 3.6 |
| */ |
| protected static final String TAG_SELECTION_TOP_PIXEL= "selectionTopPixel"; //$NON-NLS-1$ |
| |
| /** |
| * Tag used in the {@link IMemento} when saving and restoring the editor's horizontal pixel |
| * value. |
| * |
| * @see #saveState(IMemento) |
| * @see #restoreState(IMemento) |
| * @see #doRestoreState(IMemento) |
| * @since 3.6 |
| */ |
| protected static final String TAG_SELECTION_HORIZONTAL_PIXEL= "selectionHorizontalPixel"; //$NON-NLS-1$ |
| |
| |
| /** |
| * The caret width for the wide (double) caret. |
| * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=21715. |
| * Value: {@value} |
| * @since 3.0 |
| */ |
| private static final int WIDE_CARET_WIDTH= 2; |
| |
| /** |
| * The caret width for the narrow (single) caret. |
| * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=21715. |
| * Value: {@value} |
| * @since 3.0 |
| */ |
| private static final int SINGLE_CARET_WIDTH= 1; |
| |
| /** |
| * The symbolic name of the block selection mode font. |
| * |
| * @since 3.5 |
| */ |
| private static final String BLOCK_SELECTION_MODE_FONT= "org.eclipse.ui.workbench.texteditor.blockSelectionModeFont"; //$NON-NLS-1$ |
| |
| /** |
| * The text input listener. |
| * |
| * @see ITextInputListener |
| * @since 2.1 |
| */ |
| private static class TextInputListener implements ITextInputListener { |
| /** Indicates whether the editor input changed during the process of state validation. */ |
| public boolean inputChanged; |
| |
| /* Detectors for editor input changes during the process of state validation. */ |
| @Override |
| public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {} |
| @Override |
| public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { inputChanged= true; } |
| } |
| |
| /** |
| * Internal element state listener. |
| */ |
| class ElementStateListener implements IElementStateListener, IElementStateListenerExtension { |
| |
| /** |
| * Internal <code>VerifyListener</code> for performing the state validation of the |
| * editor input in case of the first attempted manipulation via typing on the keyboard. |
| * @since 2.0 |
| */ |
| class Validator implements VerifyListener { |
| @Override |
| public void verifyText(VerifyEvent e) { |
| IDocument document= getDocumentProvider().getDocument(getEditorInput()); |
| final boolean[] documentChanged= new boolean[1]; |
| IDocumentListener listener= new IDocumentListener() { |
| @Override |
| public void documentAboutToBeChanged(DocumentEvent event) { |
| } |
| @Override |
| public void documentChanged(DocumentEvent event) { |
| documentChanged[0]= true; |
| } |
| }; |
| try { |
| if (document != null) |
| document.addDocumentListener(listener); |
| if (! validateEditorInputState() || documentChanged[0]) |
| e.doit= false; |
| } finally { |
| if (document != null) |
| document.removeDocumentListener(listener); |
| } |
| } |
| } |
| |
| /** |
| * The listener's validator. |
| * @since 2.0 |
| */ |
| private Validator fValidator; |
| /** |
| * The display used for posting runnable into the UI thread. |
| * @since 3.0 |
| */ |
| private Display fDisplay; |
| |
| @Override |
| public void elementStateValidationChanged(final Object element, final boolean isStateValidated) { |
| if (element != null && element.equals(getEditorInput())) { |
| Runnable r= new Runnable() { |
| @Override |
| public void run() { |
| enableSanityChecking(true); |
| if (isStateValidated) { |
| if (fValidator != null) { |
| ISourceViewer viewer= fSourceViewer; |
| if (viewer != null) { |
| StyledText textWidget= viewer.getTextWidget(); |
| if (textWidget != null && !textWidget.isDisposed()) |
| textWidget.removeVerifyListener(fValidator); |
| fValidator= null; |
| } |
| } |
| enableStateValidation(false); |
| } else if (!isStateValidated && fValidator == null) { |
| ISourceViewer viewer= fSourceViewer; |
| if (viewer != null) { |
| StyledText textWidget= viewer.getTextWidget(); |
| if (textWidget != null && !textWidget.isDisposed()) { |
| fValidator= new Validator(); |
| enableStateValidation(true); |
| textWidget.addVerifyListener(fValidator); |
| } |
| } |
| } |
| } |
| }; |
| execute(r, false); |
| } |
| } |
| |
| |
| @Override |
| public void elementDirtyStateChanged(Object element, boolean isDirty) { |
| if (element != null && element.equals(getEditorInput())) { |
| Runnable r= new Runnable() { |
| @Override |
| public void run() { |
| enableSanityChecking(true); |
| firePropertyChange(PROP_DIRTY); |
| } |
| }; |
| execute(r, false); |
| } |
| } |
| |
| @Override |
| public void elementContentAboutToBeReplaced(Object element) { |
| if (element != null && element.equals(getEditorInput())) { |
| Runnable r= new Runnable() { |
| @Override |
| public void run() { |
| enableSanityChecking(true); |
| rememberSelection(); |
| resetHighlightRange(); |
| } |
| }; |
| execute(r, false); |
| } |
| } |
| |
| @Override |
| public void elementContentReplaced(Object element) { |
| if (element != null && element.equals(getEditorInput())) { |
| Runnable r= new Runnable() { |
| @Override |
| public void run() { |
| enableSanityChecking(true); |
| firePropertyChange(PROP_DIRTY); |
| restoreSelection(); |
| handleElementContentReplaced(); |
| } |
| }; |
| execute(r, false); |
| } |
| } |
| |
| @Override |
| public void elementDeleted(Object deletedElement) { |
| if (deletedElement != null && deletedElement.equals(getEditorInput())) { |
| Runnable r= new Runnable() { |
| @Override |
| public void run() { |
| enableSanityChecking(true); |
| close(false); |
| } |
| }; |
| execute(r, false); |
| } |
| } |
| |
| @Override |
| public void elementMoved(final Object originalElement, final Object movedElement) { |
| if (originalElement != null && originalElement.equals(getEditorInput())) { |
| final boolean doValidationAsync= Display.getCurrent() != null; |
| Runnable r= new Runnable() { |
| @Override |
| public void run() { |
| enableSanityChecking(true); |
| |
| if (fSourceViewer == null) |
| return; |
| |
| if (!canHandleMove((IEditorInput) originalElement, (IEditorInput) movedElement)) { |
| close(true); |
| return; |
| } |
| |
| if (movedElement == null || movedElement instanceof IEditorInput) { |
| rememberSelection(); |
| |
| final IDocumentProvider d= getDocumentProvider(); |
| final String previousContent; |
| IDocumentUndoManager previousUndoManager=null; |
| IDocument changed= null; |
| boolean wasDirty= isDirty(); |
| changed= d.getDocument(getEditorInput()); |
| if (changed != null) { |
| if (wasDirty) |
| previousContent= changed.get(); |
| else |
| previousContent= null; |
| |
| previousUndoManager= DocumentUndoManagerRegistry.getDocumentUndoManager(changed); |
| if (previousUndoManager != null) |
| previousUndoManager.connect(this); |
| } |
| else |
| previousContent= null; |
| |
| setInput((IEditorInput) movedElement); |
| |
| // The undo manager needs to be replaced with one for the new document. |
| // Transfer the undo history and then disconnect from the old undo manager. |
| if (previousUndoManager != null) { |
| IDocument newDocument= getDocumentProvider().getDocument(movedElement); |
| if (newDocument != null) { |
| IDocumentUndoManager newUndoManager= DocumentUndoManagerRegistry.getDocumentUndoManager(newDocument); |
| if (newUndoManager != null) |
| newUndoManager.transferUndoHistory(previousUndoManager); |
| } |
| previousUndoManager.disconnect(this); |
| } |
| |
| if (wasDirty && changed != null) { |
| Runnable r2= new Runnable() { |
| @Override |
| public void run() { |
| validateState(getEditorInput()); |
| d.getDocument(getEditorInput()).set(previousContent); |
| updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE); |
| restoreSelection(); |
| } |
| }; |
| execute(r2, doValidationAsync); |
| } else |
| restoreSelection(); |
| |
| } |
| } |
| }; |
| execute(r, false); |
| } |
| } |
| |
| @Override |
| public void elementStateChanging(Object element) { |
| if (element != null && element.equals(getEditorInput())) |
| enableSanityChecking(false); |
| } |
| |
| @Override |
| public void elementStateChangeFailed(Object element) { |
| if (element != null && element.equals(getEditorInput())) |
| enableSanityChecking(true); |
| } |
| |
| /** |
| * Executes the given runnable in the UI thread. |
| * <p> |
| * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=76765 for details |
| * about why the parameter <code>postAsync</code> has been |
| * introduced in the course of 3.1. |
| * |
| * @param runnable runnable to be executed |
| * @param postAsync <code>true</code> if the runnable must be posted asynchronous, <code>false</code> otherwise |
| * @since 3.0 |
| */ |
| private void execute(Runnable runnable, boolean postAsync) { |
| if (postAsync || Display.getCurrent() == null) { |
| if (fDisplay == null) |
| fDisplay= getSite().getShell().getDisplay(); |
| fDisplay.asyncExec(runnable); |
| } else |
| runnable.run(); |
| } |
| } |
| |
| /** |
| * Internal text listener for updating all content dependent |
| * actions. The updating is done asynchronously. |
| */ |
| class TextListener implements ITextListener, ITextInputListener { |
| |
| /** The posted updater code. */ |
| private Runnable fRunnable= new Runnable() { |
| @Override |
| public void run() { |
| fIsRunnablePosted= false; |
| |
| if (fSourceViewer != null) { |
| updateContentDependentActions(); |
| |
| // remember the last edit position |
| if (isDirty() && fUpdateLastEditPosition) { |
| fUpdateLastEditPosition= false; |
| ISelection sel= getSelectionProvider().getSelection(); |
| IEditorInput input= getEditorInput(); |
| IDocument document= getDocumentProvider().getDocument(input); |
| |
| if (fLocalLastEditPosition != null) { |
| if (document != null) { |
| document.removePosition(fLocalLastEditPosition); |
| } |
| fLocalLastEditPosition= null; |
| } |
| |
| if (sel instanceof ITextSelection && !sel.isEmpty()) { |
| ITextSelection s= (ITextSelection) sel; |
| fLocalLastEditPosition= new Position(s.getOffset(), s.getLength()); |
| if (document != null) { |
| try { |
| document.addPosition(fLocalLastEditPosition); |
| } catch (BadLocationException ex) { |
| fLocalLastEditPosition = null; |
| } |
| } |
| } |
| |
| IEditorSite editorSite= getEditorSite(); |
| if (editorSite instanceof MultiPageEditorSite) |
| editorSite= ((MultiPageEditorSite)editorSite).getMultiPageEditor().getEditorSite(); |
| TextEditorPlugin.getDefault().setLastEditPosition(new EditPosition(input, editorSite.getId(), fLocalLastEditPosition)); |
| } |
| } |
| } |
| }; |
| |
| /** Display used for posting the updater code. */ |
| private Display fDisplay; |
| /** |
| * The editor's last edit position |
| * @since 3.0 |
| */ |
| private Position fLocalLastEditPosition; |
| /** |
| * Has the runnable been posted? |
| * @since 3.0 |
| */ |
| private boolean fIsRunnablePosted= false; |
| /** |
| * Should the last edit position be updated? |
| * @since 3.0 |
| */ |
| private boolean fUpdateLastEditPosition= false; |
| |
| @Override |
| public void textChanged(TextEvent event) { |
| |
| /* |
| * Also works for text events which do not base on a DocumentEvent. |
| * This way, if the visible document of the viewer changes, all content |
| * dependent actions are updated as well. |
| */ |
| |
| if (fDisplay == null) |
| fDisplay= getSite().getShell().getDisplay(); |
| |
| if (event.getDocumentEvent() != null) |
| fUpdateLastEditPosition= true; |
| |
| if (!fIsRunnablePosted) { |
| fIsRunnablePosted= true; |
| fDisplay.asyncExec(fRunnable); |
| } |
| } |
| |
| @Override |
| public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { |
| if (oldInput != null && fLocalLastEditPosition != null) { |
| oldInput.removePosition(fLocalLastEditPosition); |
| fLocalLastEditPosition= null; |
| } |
| } |
| |
| @Override |
| public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { |
| } |
| } |
| |
| /** |
| * Internal property change listener for handling changes in the editor's preferences. |
| */ |
| class PropertyChangeListener implements IPropertyChangeListener { |
| @Override |
| public void propertyChange(PropertyChangeEvent event) { |
| handlePreferenceStoreChanged(event); |
| } |
| } |
| |
| /** |
| * Internal property change listener for handling workbench font changes. |
| * @since 2.1 |
| */ |
| class FontPropertyChangeListener implements IPropertyChangeListener { |
| @Override |
| public void propertyChange(PropertyChangeEvent event) { |
| if (fSourceViewer == null) |
| return; |
| |
| String property= event.getProperty(); |
| |
| // IMPORTANT: Do not call isBlockSelectionModeEnabled() before checking the property! |
| |
| if (BLOCK_SELECTION_MODE_FONT.equals(property) && isBlockSelectionModeEnabled()) { |
| Font blockFont= JFaceResources.getFont(BLOCK_SELECTION_MODE_FONT); |
| setFont(fSourceViewer, blockFont); |
| disposeFont(); |
| updateCaret(); |
| return; |
| } |
| if (getFontPropertyPreferenceKey().equals(property) && !isBlockSelectionModeEnabled()) { |
| initializeViewerFont(fSourceViewer); |
| updateCaret(); |
| return; |
| } |
| } |
| } |
| |
| /** |
| * Internal key verify listener for triggering action activation codes. |
| */ |
| class ActivationCodeTrigger implements VerifyKeyListener { |
| |
| /** Indicates whether this trigger has been installed. */ |
| private boolean fIsInstalled= false; |
| /** |
| * The key binding service to use. |
| * @since 2.0 |
| */ |
| private IKeyBindingService fKeyBindingService; |
| |
| @Override |
| public void verifyKey(VerifyEvent event) { |
| |
| ActionActivationCode code= null; |
| int size= fActivationCodes.size(); |
| for (int i= 0; i < size; i++) { |
| code= fActivationCodes.get(i); |
| if (code.matches(event)) { |
| IAction action= getAction(code.fActionId); |
| if (action != null) { |
| |
| if (action instanceof IUpdate) |
| ((IUpdate) action).update(); |
| |
| if (!action.isEnabled() && action instanceof IReadOnlyDependent) { |
| IReadOnlyDependent dependent= (IReadOnlyDependent) action; |
| boolean writable= dependent.isEnabled(true); |
| if (writable) { |
| event.doit= false; |
| return; |
| } |
| } else if (action.isEnabled()) { |
| event.doit= false; |
| action.run(); |
| return; |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Installs this trigger on the editor's text widget. |
| * @since 2.0 |
| */ |
| public void install() { |
| if (!fIsInstalled) { |
| |
| if (fSourceViewer instanceof ITextViewerExtension) { |
| ITextViewerExtension e= (ITextViewerExtension) fSourceViewer; |
| e.prependVerifyKeyListener(this); |
| } else { |
| StyledText text= fSourceViewer.getTextWidget(); |
| text.addVerifyKeyListener(this); |
| } |
| |
| fKeyBindingService= getEditorSite().getKeyBindingService(); |
| fIsInstalled= true; |
| } |
| } |
| |
| /** |
| * Uninstalls this trigger from the editor's text widget. |
| * @since 2.0 |
| */ |
| public void uninstall() { |
| if (fIsInstalled) { |
| |
| if (fSourceViewer instanceof ITextViewerExtension) { |
| ITextViewerExtension e= (ITextViewerExtension) fSourceViewer; |
| e.removeVerifyKeyListener(this); |
| } else if (fSourceViewer != null) { |
| StyledText text= fSourceViewer.getTextWidget(); |
| if (text != null && !text.isDisposed()) |
| text.removeVerifyKeyListener(fActivationCodeTrigger); |
| } |
| |
| fIsInstalled= false; |
| fKeyBindingService= null; |
| } |
| } |
| |
| /** |
| * Registers the given action for key activation. |
| * @param action the action to be registered |
| * @since 2.0 |
| */ |
| public void registerActionForKeyActivation(IAction action) { |
| if (fIsInstalled && action.getActionDefinitionId() != null) |
| fKeyBindingService.registerAction(action); |
| } |
| |
| /** |
| * The given action is no longer available for key activation |
| * @param action the action to be unregistered |
| * @since 2.0 |
| */ |
| public void unregisterActionFromKeyActivation(IAction action) { |
| if (fIsInstalled && action.getActionDefinitionId() != null) |
| fKeyBindingService.unregisterAction(action); |
| } |
| |
| /** |
| * Sets the key binding scopes for this editor. |
| * @param keyBindingScopes the key binding scopes |
| * @since 2.1 |
| */ |
| public void setScopes(String[] keyBindingScopes) { |
| if (keyBindingScopes != null && keyBindingScopes.length > 0) |
| fKeyBindingService.setScopes(keyBindingScopes); |
| } |
| } |
| |
| /** |
| * Representation of action activation codes. |
| */ |
| static class ActionActivationCode { |
| |
| /** The action id. */ |
| public String fActionId; |
| /** The character. */ |
| public char fCharacter; |
| /** The key code. */ |
| public int fKeyCode= -1; |
| /** The state mask. */ |
| public int fStateMask= SWT.DEFAULT; |
| |
| /** |
| * Creates a new action activation code for the given action id. |
| * @param actionId the action id |
| */ |
| public ActionActivationCode(String actionId) { |
| fActionId= actionId; |
| } |
| |
| /** |
| * Returns <code>true</code> if this activation code matches the given verify event. |
| * @param event the event to test for matching |
| * @return whether this activation code matches <code>event</code> |
| */ |
| public boolean matches(VerifyEvent event) { |
| return (event.character == fCharacter && |
| (fKeyCode == -1 || event.keyCode == fKeyCode) && |
| (fStateMask == SWT.DEFAULT || event.stateMask == fStateMask)); |
| } |
| } |
| |
| /** |
| * Internal part and shell activation listener for triggering state validation. |
| * @since 2.0 |
| */ |
| class ActivationListener implements IPartListener, IWindowListener { |
| |
| /** Cache of the active workbench part. */ |
| private IWorkbenchPart fActivePart; |
| /** |
| * The part service. |
| * @since 3.1 |
| */ |
| private IPartService fPartService; |
| |
| /** |
| * Creates this activation listener. |
| * |
| * @param partService the part service on which to add the part listener |
| * @since 3.1 |
| */ |
| public ActivationListener(IPartService partService) { |
| fPartService= partService; |
| fPartService.addPartListener(this); |
| PlatformUI.getWorkbench().addWindowListener(this); |
| } |
| |
| /** |
| * Disposes this activation listener. |
| * |
| * @since 3.1 |
| */ |
| public void dispose() { |
| fPartService.removePartListener(this); |
| PlatformUI.getWorkbench().removeWindowListener(this); |
| fPartService= null; |
| } |
| |
| @Override |
| public void partActivated(IWorkbenchPart part) { |
| fActivePart= part; |
| handleActivation(); |
| } |
| |
| @Override |
| public void partBroughtToTop(IWorkbenchPart part) { |
| } |
| |
| @Override |
| public void partClosed(IWorkbenchPart part) { |
| } |
| |
| @Override |
| public void partDeactivated(IWorkbenchPart part) { |
| fActivePart= null; |
| } |
| |
| @Override |
| public void partOpened(IWorkbenchPart part) { |
| // Restore the saved state if any |
| if ((part == AbstractTextEditor.this || part.getAdapter(AbstractTextEditor.class) == AbstractTextEditor.this) && fMementoToRestore != null && containsSavedState(fMementoToRestore)) { |
| doRestoreState(fMementoToRestore); |
| fMementoToRestore= null; |
| } |
| } |
| |
| /** |
| * Handles the activation triggering a element state check in the editor. |
| */ |
| private void handleActivation() { |
| if (!fHandleActivation) |
| return; |
| |
| if (fActivePart == AbstractTextEditor.this || fActivePart != null && fActivePart.getAdapter(AbstractTextEditor.class) == AbstractTextEditor.this) { |
| fHandleActivation= false; |
| try { |
| safelySanityCheckState(getEditorInput()); |
| } finally { |
| fHandleActivation= true; |
| fHasBeenActivated= true; |
| } |
| } |
| } |
| |
| @Override |
| public void windowActivated(IWorkbenchWindow window) { |
| if (fHandleActivation && window == getEditorSite().getWorkbenchWindow()) { |
| /* |
| * Workaround for problem described in |
| * http://dev.eclipse.org/bugs/show_bug.cgi?id=11731 |
| * Will be removed when SWT has solved the problem. |
| */ |
| window.getShell().getDisplay().asyncExec(new Runnable() { |
| @Override |
| public void run() { |
| handleActivation(); |
| } |
| }); |
| } |
| } |
| |
| @Override |
| public void windowDeactivated(IWorkbenchWindow window) { |
| } |
| |
| @Override |
| public void windowClosed(IWorkbenchWindow window) { |
| } |
| |
| @Override |
| public void windowOpened(IWorkbenchWindow window) { |
| } |
| } |
| |
| /** |
| * Internal interface for a cursor listener. I.e. aggregation |
| * of mouse and key listener. |
| * @since 2.0 |
| */ |
| interface ICursorListener extends MouseListener, KeyListener { |
| } |
| |
| /** |
| * Maps an action definition id to an StyledText action. |
| * @since 2.0 |
| */ |
| protected static final class IdMapEntry { |
| |
| /** The action id. */ |
| private String fActionId; |
| /** The StyledText action. */ |
| private int fAction; |
| |
| /** |
| * Creates a new mapping. |
| * @param actionId the action id |
| * @param action the StyledText action |
| */ |
| public IdMapEntry(String actionId, int action) { |
| fActionId= actionId; |
| fAction= action; |
| } |
| |
| /** |
| * Returns the action id. |
| * @return the action id |
| */ |
| public String getActionId() { |
| return fActionId; |
| } |
| |
| /** |
| * Returns the action. |
| * @return the action |
| */ |
| public int getAction() { |
| return fAction; |
| } |
| } |
| |
| /** |
| * Internal action to scroll the editor's viewer by a specified number of lines. |
| * @since 2.0 |
| */ |
| class ScrollLinesAction extends Action { |
| |
| /** Number of lines to scroll. */ |
| private int fScrollIncrement; |
| |
| /** |
| * Creates a new scroll action that scroll the given number of lines. If the |
| * increment is < 0, it's scrolling up, if > 0 it's scrolling down. |
| * @param scrollIncrement the number of lines to scroll |
| */ |
| public ScrollLinesAction(int scrollIncrement) { |
| fScrollIncrement= scrollIncrement; |
| } |
| |
| @Override |
| public void run() { |
| if (fSourceViewer instanceof ITextViewerExtension5) { |
| ITextViewerExtension5 extension= (ITextViewerExtension5) fSourceViewer; |
| StyledText textWidget= fSourceViewer.getTextWidget(); |
| int topIndex= textWidget.getTopIndex(); |
| int newTopIndex= Math.max(0, topIndex + fScrollIncrement); |
| fSourceViewer.setTopIndex(extension.widgetLine2ModelLine(newTopIndex)); |
| } else { |
| int topIndex= fSourceViewer.getTopIndex(); |
| int newTopIndex= Math.max(0, topIndex + fScrollIncrement); |
| fSourceViewer.setTopIndex(newTopIndex); |
| } |
| } |
| } |
| |
| /** |
| * Action to toggle the insert mode. The action is checked if smart mode is |
| * turned on. |
| * |
| * @since 2.1 |
| */ |
| class ToggleInsertModeAction extends ResourceAction { |
| |
| public ToggleInsertModeAction(ResourceBundle bundle, String prefix) { |
| super(bundle, prefix, IAction.AS_CHECK_BOX); |
| } |
| |
| @Override |
| public void run() { |
| switchToNextInsertMode(); |
| } |
| |
| @Override |
| public boolean isChecked() { |
| return fInsertMode == SMART_INSERT; |
| } |
| } |
| |
| /** |
| * Action to toggle the overwrite mode. |
| * |
| * @since 3.0 |
| */ |
| class ToggleOverwriteModeAction extends ResourceAction { |
| |
| public ToggleOverwriteModeAction(ResourceBundle bundle, String prefix) { |
| super(bundle, prefix); |
| } |
| |
| @Override |
| public void run() { |
| toggleOverwriteMode(); |
| } |
| } |
| |
| /** |
| * This action implements smart end. |
| * Instead of going to the end of a line it does the following: |
| * - if smart home/end is enabled and the caret is before the line's last non-whitespace and then the caret is moved directly after it |
| * - if the caret is after last non-whitespace the caret is moved at the end of the line |
| * - if the caret is at the end of the line the caret is moved directly after the line's last non-whitespace character |
| * @since 2.1 (in 3.3 the access modifier changed from package visibility to protected) |
| */ |
| protected class LineEndAction extends TextNavigationAction { |
| |
| /** boolean flag which tells if the text up to the line end should be selected. */ |
| private boolean fDoSelect; |
| |
| /** |
| * Create a new line end action. |
| * |
| * @param textWidget the styled text widget |
| * @param doSelect a boolean flag which tells if the text up to the line end should be selected |
| */ |
| public LineEndAction(StyledText textWidget, boolean doSelect) { |
| super(textWidget, ST.LINE_END); |
| fDoSelect= doSelect; |
| } |
| |
| /** |
| * Computes the offset of the line end position. |
| * |
| * @param document the document where to compute the line end position |
| * @param line the line to determine the end position of |
| * @param length the length of the line |
| * @param offset the caret position in the document |
| * @return the offset of the line end |
| * @since 3.4 protected, was added in 3.3 as private method |
| */ |
| protected int getLineEndPosition(final IDocument document, final String line, final int length, final int offset) { |
| int index= length - 1; |
| while (index > -1 && Character.isWhitespace(line.charAt(index))) |
| index--; |
| index++; |
| |
| LinkedModeModel model= LinkedModeModel.getModel(document, offset); |
| if (model != null) { |
| LinkedPosition linkedPosition= model.findPosition(new LinkedPosition(document, offset, 0)); |
| if (linkedPosition != null) { |
| int linkedPositionEnd= linkedPosition.getOffset() + linkedPosition.getLength(); |
| int lineOffset; |
| try { |
| lineOffset= document.getLineInformationOfOffset(offset).getOffset(); |
| if (offset != linkedPositionEnd && linkedPositionEnd - lineOffset < index) |
| index= linkedPositionEnd - lineOffset; |
| } catch (BadLocationException e) { |
| //should not happen |
| } |
| } |
| } |
| return index; |
| } |
| |
| @Override |
| public void run() { |
| boolean isSmartHomeEndEnabled= false; |
| IPreferenceStore store= getPreferenceStore(); |
| if (store != null) |
| isSmartHomeEndEnabled= store.getBoolean(AbstractTextEditor.PREFERENCE_NAVIGATION_SMART_HOME_END); |
| |
| StyledText st= fSourceViewer.getTextWidget(); |
| if (st == null || st.isDisposed()) |
| return; |
| int caretOffset= st.getCaretOffset(); |
| int lineNumber= st.getLineAtOffset(caretOffset); |
| int lineOffset= st.getOffsetAtLine(lineNumber); |
| |
| int lineLength; |
| int caretOffsetInDocument; |
| final IDocument document= fSourceViewer.getDocument(); |
| |
| try { |
| caretOffsetInDocument= widgetOffset2ModelOffset(fSourceViewer, caretOffset); |
| lineLength= document.getLineInformationOfOffset(caretOffsetInDocument).getLength(); |
| } catch (BadLocationException ex) { |
| return; |
| } |
| int lineEndOffset= lineOffset + lineLength; |
| |
| int delta= lineEndOffset - st.getCharCount(); |
| if (delta > 0) { |
| lineEndOffset -= delta; |
| lineLength -= delta; |
| } |
| |
| String line= ""; //$NON-NLS-1$ |
| if (lineLength > 0) |
| line= st.getText(lineOffset, lineEndOffset - 1); |
| |
| // Remember current selection |
| Point oldSelection= st.getSelection(); |
| |
| // The new caret position |
| int newCaretOffset= -1; |
| |
| if (isSmartHomeEndEnabled) { |
| // Compute the line end offset |
| int i= getLineEndPosition(document, line, lineLength, caretOffsetInDocument); |
| |
| if (caretOffset - lineOffset == i) |
| // to end of line |
| newCaretOffset= lineEndOffset; |
| else |
| // to end of text |
| newCaretOffset= lineOffset + i; |
| |
| } else { |
| |
| if (caretOffset < lineEndOffset) |
| // to end of line |
| newCaretOffset= lineEndOffset; |
| |
| } |
| |
| if (newCaretOffset == -1) |
| newCaretOffset= caretOffset; |
| else |
| st.setCaretOffset(newCaretOffset); |
| |
| st.setCaretOffset(newCaretOffset); |
| if (fDoSelect) { |
| if (caretOffset < oldSelection.y) |
| st.setSelection(oldSelection.y, newCaretOffset); |
| else |
| st.setSelection(oldSelection.x, newCaretOffset); |
| } else |
| st.setSelection(newCaretOffset); |
| |
| fireSelectionChanged(oldSelection); |
| } |
| } |
| |
| /** |
| * 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 |
| * - 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 the caret is moved directly before the line's first non-whitespace character |
| * @since 2.1 |
| */ |
| protected class LineStartAction extends TextNavigationAction { |
| |
| /** boolean flag which tells if the text up to the beginning of the line should be selected. */ |
| private final boolean fDoSelect; |
| |
| /** |
| * Creates a new 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 LineStartAction(final StyledText textWidget, final boolean doSelect) { |
| super(textWidget, ST.LINE_START); |
| fDoSelect= doSelect; |
| } |
| |
| /** |
| * Computes the offset of the line start position. |
| * |
| * @param document the document where to compute the line start position |
| * @param line the line to determine the start position of |
| * @param length the length of the line |
| * @param offset the caret position in the document |
| * @return the offset of the line start |
| * @since 3.0 |
| */ |
| protected int getLineStartPosition(final IDocument document, final String line, final int length, final int offset) { |
| int index= 0; |
| while (index < length && Character.isWhitespace(line.charAt(index))) |
| index++; |
| |
| LinkedModeModel model= LinkedModeModel.getModel(document, offset); |
| if (model != null) { |
| LinkedPosition linkedPosition= model.findPosition(new LinkedPosition(document, offset, 0)); |
| if (linkedPosition != null) { |
| int linkedPositionOffset= linkedPosition.getOffset(); |
| int lineOffset; |
| try { |
| lineOffset= document.getLineInformationOfOffset(offset).getOffset(); |
| if (offset != linkedPositionOffset && index < linkedPositionOffset - lineOffset) |
| index= linkedPositionOffset - lineOffset; |
| } catch (BadLocationException e) { |
| //should not happen |
| } |
| } |
| } |
| return index; |
| } |
| |
| @Override |
| public void run() { |
| boolean isSmartHomeEndEnabled= false; |
| IPreferenceStore store= getPreferenceStore(); |
| if (store != null) |
| isSmartHomeEndEnabled= store.getBoolean(AbstractTextEditor.PREFERENCE_NAVIGATION_SMART_HOME_END); |
| |
| StyledText st= fSourceViewer.getTextWidget(); |
| if (st == null || st.isDisposed()) |
| return; |
| |
| int caretOffset= st.getCaretOffset(); |
| int lineNumber= st.getLineAtOffset(caretOffset); |
| int lineOffset= st.getOffsetAtLine(lineNumber); |
| |
| int lineLength; |
| int caretOffsetInDocument; |
| final IDocument document= fSourceViewer.getDocument(); |
| |
| try { |
| caretOffsetInDocument= widgetOffset2ModelOffset(fSourceViewer, caretOffset); |
| lineLength= document.getLineInformationOfOffset(caretOffsetInDocument).getLength(); |
| } catch (BadLocationException ex) { |
| return; |
| } |
| |
| String line= ""; //$NON-NLS-1$ |
| if (lineLength > 0) { |
| int end= lineOffset + lineLength - 1; |
| end= Math.min(end, st.getCharCount() -1); |
| line= st.getText(lineOffset, end); |
| } |
| |
| // Remember current selection |
| Point oldSelection= st.getSelection(); |
| |
| // The new caret position |
| int newCaretOffset= -1; |
| |
| if (isSmartHomeEndEnabled) { |
| |
| // Compute the line start offset |
| int index= getLineStartPosition(document, line, lineLength, caretOffsetInDocument); |
| |
| if (caretOffset - lineOffset == index) |
| // to beginning of line |
| newCaretOffset= lineOffset; |
| else |
| // to beginning of text |
| newCaretOffset= lineOffset + index; |
| |
| } else { |
| |
| if (caretOffset > lineOffset) |
| // to beginning of line |
| newCaretOffset= lineOffset; |
| } |
| |
| if (newCaretOffset == -1) |
| newCaretOffset= caretOffset; |
| else |
| st.setCaretOffset(newCaretOffset); |
| |
| if (fDoSelect) { |
| if (caretOffset < oldSelection.y) |
| st.setSelection(oldSelection.y, newCaretOffset); |
| else |
| st.setSelection(oldSelection.x, newCaretOffset); |
| } else |
| st.setSelection(newCaretOffset); |
| |
| fireSelectionChanged(oldSelection); |
| } |
| |
| } |
| |
| /** |
| * Internal action to show the editor's ruler context menu (accessibility). |
| * @since 2.0 |
| */ |
| class ShowRulerContextMenuAction extends Action { |
| @Override |
| public void run() { |
| if (fSourceViewer == null) |
| return; |
| |
| StyledText text= fSourceViewer.getTextWidget(); |
| if (text == null || text.isDisposed()) |
| return; |
| |
| Point location= text.getLocationAtOffset(text.getCaretOffset()); |
| location.x= 0; |
| |
| if (fVerticalRuler instanceof IVerticalRulerExtension) |
| ((IVerticalRulerExtension) fVerticalRuler).setLocationOfLastMouseButtonActivity(location.x, location.y); |
| |
| location= text.toDisplay(location); |
| fRulerContextMenu.setLocation(location.x, location.y); |
| fRulerContextMenu.setVisible(true); |
| } |
| } |
| |
| /** |
| * Editor specific selection provider which wraps the source viewer's selection provider. |
| * |
| * @since 3.4 protected, was added in 2.1 as private class |
| */ |
| protected class SelectionProvider implements IPostSelectionProvider, ISelectionValidator { |
| |
| @Override |
| public void addSelectionChangedListener(ISelectionChangedListener listener) { |
| if (fSourceViewer != null) |
| fSourceViewer.getSelectionProvider().addSelectionChangedListener(listener); |
| } |
| |
| @Override |
| public ISelection getSelection() { |
| return doGetSelection(); |
| } |
| |
| @Override |
| public void removeSelectionChangedListener(ISelectionChangedListener listener) { |
| if (fSourceViewer != null) |
| fSourceViewer.getSelectionProvider().removeSelectionChangedListener(listener); |
| } |
| |
| @Override |
| public void setSelection(ISelection selection) { |
| doSetSelection(selection); |
| } |
| |
| @Override |
| public void addPostSelectionChangedListener(ISelectionChangedListener listener) { |
| if (fSourceViewer != null) { |
| if (fSourceViewer.getSelectionProvider() instanceof IPostSelectionProvider) { |
| IPostSelectionProvider provider= (IPostSelectionProvider) fSourceViewer.getSelectionProvider(); |
| provider.addPostSelectionChangedListener(listener); |
| } |
| } |
| } |
| |
| @Override |
| public void removePostSelectionChangedListener(ISelectionChangedListener listener) { |
| if (fSourceViewer != null) { |
| if (fSourceViewer.getSelectionProvider() instanceof IPostSelectionProvider) { |
| IPostSelectionProvider provider= (IPostSelectionProvider) fSourceViewer.getSelectionProvider(); |
| provider.removePostSelectionChangedListener(listener); |
| } |
| } |
| } |
| |
| @Override |
| public boolean isValid(ISelection postSelection) { |
| return fSelectionListener != null && fSelectionListener.isValid(postSelection); |
| } |
| } |
| |
| /** |
| * Internal implementation class for a change listener. |
| * @since 3.0 |
| */ |
| protected abstract class AbstractSelectionChangedListener implements ISelectionChangedListener { |
| |
| /** |
| * Installs this selection changed listener with the given selection provider. If the |
| * selection provider is a post selection provider, post selection changed events are the |
| * preferred choice, otherwise normal selection changed events are requested. |
| * |
| * @param selectionProvider the selection provider |
| */ |
| 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); |
| } |
| } |
| } |
| |
| /** |
| * This selection listener allows the SelectionProvider to implement {@link ISelectionValidator}. |
| * |
| * @since 3.0 |
| */ |
| private class SelectionListener extends AbstractSelectionChangedListener implements IDocumentListener { |
| |
| private IDocument fDocument; |
| private final Object INVALID_SELECTION= new Object(); |
| private Object fPostSelection= INVALID_SELECTION; |
| |
| @Override |
| public synchronized void selectionChanged(SelectionChangedEvent event) { |
| fPostSelection= event.getSelection(); |
| } |
| |
| @Override |
| public synchronized void documentAboutToBeChanged(DocumentEvent event) { |
| fPostSelection= INVALID_SELECTION; |
| } |
| |
| @Override |
| public void documentChanged(DocumentEvent event) { |
| } |
| |
| public synchronized boolean isValid(ISelection selection) { |
| return fPostSelection != INVALID_SELECTION && fPostSelection == selection; |
| } |
| |
| public void setDocument(IDocument document) { |
| if (fDocument != null) |
| fDocument.removeDocumentListener(this); |
| |
| fDocument= document; |
| if (fDocument != null) |
| fDocument.addDocumentListener(this); |
| } |
| |
| @Override |
| public void install(ISelectionProvider selectionProvider) { |
| super.install(selectionProvider); |
| |
| if (selectionProvider != null) |
| selectionProvider.addSelectionChangedListener(this); |
| } |
| |
| @Override |
| public void uninstall(ISelectionProvider selectionProvider) { |
| if (selectionProvider != null) |
| selectionProvider.removeSelectionChangedListener(this); |
| |
| if (fDocument != null) { |
| fDocument.removeDocumentListener(this); |
| fDocument= null; |
| } |
| super.uninstall(selectionProvider); |
| } |
| } |
| |
| |
| /** |
| * Implements the ruler column support of for the given editor. |
| * <p> |
| * This is currently only used to support vertical ruler columns. |
| * </p> |
| * |
| * @since 3.3 |
| */ |
| protected static class ColumnSupport implements IColumnSupport { |
| private final AbstractTextEditor fEditor; |
| private final RulerColumnRegistry fRegistry; |
| private final List<IContributedRulerColumn> fColumns; |
| |
| /** |
| * Creates a new column support for the given editor. Only the editor itself should normally |
| * create such an instance. |
| * |
| * @param editor the editor |
| * @param registry the contribution registry to refer to |
| */ |
| public ColumnSupport(AbstractTextEditor editor, RulerColumnRegistry registry) { |
| Assert.isLegal(editor != null); |
| Assert.isLegal(registry != null); |
| fEditor= editor; |
| fRegistry= registry; |
| fColumns= new ArrayList<>(); |
| } |
| |
| @Override |
| public final void setColumnVisible(RulerColumnDescriptor descriptor, boolean visible) { |
| Assert.isLegal(descriptor != null); |
| |
| final CompositeRuler ruler= getRuler(); |
| if (ruler == null) |
| return; |
| |
| if (!isColumnSupported(descriptor)) |
| visible= false; |
| |
| if (isColumnVisible(descriptor)) { |
| if (!visible) |
| removeColumn(ruler, descriptor); |
| } else { |
| if (visible) |
| addColumn(ruler, descriptor); |
| } |
| } |
| |
| private void addColumn(final CompositeRuler ruler, final RulerColumnDescriptor descriptor) { |
| |
| final int idx= computeIndex(ruler, descriptor); |
| |
| SafeRunnable runnable= new SafeRunnable() { |
| @Override |
| public void run() throws Exception { |
| IContributedRulerColumn column= descriptor.createColumn(fEditor); |
| fColumns.add(column); |
| initializeColumn(column); |
| ruler.addDecorator(idx, column); |
| } |
| }; |
| SafeRunner.run(runnable); |
| } |
| |
| /** |
| * Hook to let subclasses initialize a newly created column. |
| * <p> |
| * Subclasses may extend this method.</p> |
| * |
| * @param column the created column |
| */ |
| protected void initializeColumn(IContributedRulerColumn column) { |
| } |
| |
| private void removeColumn(final CompositeRuler ruler, final RulerColumnDescriptor descriptor) { |
| removeColumn(ruler, getVisibleColumn(ruler, descriptor)); |
| } |
| |
| private void removeColumn(final CompositeRuler ruler, final IContributedRulerColumn rulerColumn) { |
| if (rulerColumn != null) { |
| SafeRunnable runnable= new SafeRunnable() { |
| @Override |
| public void run() throws Exception { |
| if (ruler != null) |
| ruler.removeDecorator(rulerColumn); |
| rulerColumn.columnRemoved(); |
| } |
| }; |
| SafeRunner.run(runnable); |
| } |
| } |
| |
| /** |
| * Returns the currently visible column matching <code>id</code>, <code>null</code> if |
| * none. |
| * |
| * @param ruler the composite ruler to scan |
| * @param descriptor the descriptor of the column of interest |
| * @return the matching column or <code>null</code> |
| */ |
| private IContributedRulerColumn getVisibleColumn(CompositeRuler ruler, RulerColumnDescriptor descriptor) { |
| for (Iterator<IVerticalRulerColumn> it= ruler.getDecoratorIterator(); it.hasNext();) { |
| IVerticalRulerColumn column= it.next(); |
| if (column instanceof IContributedRulerColumn) { |
| IContributedRulerColumn rulerColumn= (IContributedRulerColumn)column; |
| RulerColumnDescriptor rcd= rulerColumn.getDescriptor(); |
| if (descriptor.equals(rcd)) |
| return rulerColumn; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Computes the insertion index for a column contribution into the currently visible columns. |
| * |
| * @param ruler the composite ruler into which to insert the column |
| * @param descriptor the descriptor to compute the index for |
| * @return the insertion index for a new column |
| */ |
| private int computeIndex(CompositeRuler ruler, RulerColumnDescriptor descriptor) { |
| int index= 0; |
| List<RulerColumnDescriptor> all= fRegistry.getColumnDescriptors(); |
| int newPos= all.indexOf(descriptor); |
| for (Iterator<IVerticalRulerColumn> it= ruler.getDecoratorIterator(); it.hasNext();) { |
| IVerticalRulerColumn column= it.next(); |
| if (column instanceof IContributedRulerColumn) { |
| RulerColumnDescriptor rcd= ((IContributedRulerColumn)column).getDescriptor(); |
| if (rcd != null && all.indexOf(rcd) > newPos) |
| break; |
| } else if ("org.eclipse.jface.text.source.projection.ProjectionRulerColumn".equals(column.getClass().getName())) { //$NON-NLS-1$ |
| // projection column is always the rightmost column |
| break; |
| } |
| index++; |
| } |
| return index; |
| } |
| |
| @Override |
| public final boolean isColumnVisible(RulerColumnDescriptor descriptor) { |
| Assert.isLegal(descriptor != null); |
| CompositeRuler ruler= getRuler(); |
| return ruler != null && getVisibleColumn(ruler, descriptor) != null; |
| } |
| |
| @Override |
| public final boolean isColumnSupported(RulerColumnDescriptor descriptor) { |
| Assert.isLegal(descriptor != null); |
| if (getRuler() == null) |
| return false; |
| |
| return descriptor.matchesEditor(fEditor); |
| } |
| |
| /** |
| * Returns the editor's vertical ruler, if it is a {@link CompositeRuler}, <code>null</code> |
| * otherwise. |
| * |
| * @return the editor's {@link CompositeRuler} or <code>null</code> |
| */ |
| private CompositeRuler getRuler() { |
| Object ruler= fEditor.getAdapter(IVerticalRulerInfo.class); |
| if (ruler instanceof CompositeRuler) |
| return (CompositeRuler) ruler; |
| return null; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * <p> |
| * Subclasses may extend this method.</p> |
| * |
| */ |
| @Override |
| public void dispose() { |
| for (Iterator<IContributedRulerColumn> iter= new ArrayList<>(fColumns).iterator(); iter.hasNext();) |
| removeColumn(getRuler(), iter.next()); |
| fColumns.clear(); |
| } |
| } |
| |
| |
| |
| /** |
| * This action behaves in two different ways: If there is no current text |
| * hover, the javadoc is displayed using information presenter. If there is |
| * a current text hover, it is converted into a information presenter in |
| * order to make it sticky. |
| * |
| * @since 3.3 |
| */ |
| private final class InformationDispatchAction extends TextEditorAction { |
| |
| /** The wrapped text operation action. */ |
| private final TextOperationAction fTextOperationAction; |
| |
| /** |
| * Creates a dispatch action. |
| * |
| * @param resourceBundle the resource bundle |
| * @param prefix the prefix |
| * @param textOperationAction the text operation action |
| */ |
| public InformationDispatchAction(ResourceBundle resourceBundle, String prefix, final TextOperationAction textOperationAction) { |
| super(resourceBundle, prefix, AbstractTextEditor.this); |
| if (textOperationAction == null) |
| throw new IllegalArgumentException(); |
| fTextOperationAction= textOperationAction; |
| } |
| |
| @Override |
| public void run() { |
| |
| ISourceViewer sourceViewer= getSourceViewer(); |
| if (sourceViewer == null) { |
| if (fTextOperationAction.isEnabled()) |
| fTextOperationAction.run(); |
| return; |
| } |
| |
| if (sourceViewer instanceof ITextViewerExtension4) { |
| ITextViewerExtension4 extension4= (ITextViewerExtension4) sourceViewer; |
| if (extension4.moveFocusToWidgetToken()) |
| return; |
| } |
| |
| if (sourceViewer instanceof ITextViewerExtension2) { |
| // does a text hover exist? |
| ITextHover textHover= ((ITextViewerExtension2) sourceViewer).getCurrentTextHover(); |
| if (textHover != null && makeTextHoverFocusable(sourceViewer, textHover)) |
| return; |
| } |
| |
| if (sourceViewer instanceof ISourceViewerExtension3) { |
| // does an annotation hover exist? |
| IAnnotationHover annotationHover= ((ISourceViewerExtension3) sourceViewer).getCurrentAnnotationHover(); |
| if (annotationHover != null && makeAnnotationHoverFocusable(annotationHover)) |
| return; |
| } |
| |
| // otherwise, just run the action |
| if (fTextOperationAction.isEnabled()) |
| fTextOperationAction.run(); |
| } |
| |
| /** |
| * Tries to make a text hover focusable (or "sticky"). |
| * |
| * @param sourceViewer the source viewer to display the hover over |
| * @param textHover the hover to make focusable |
| * @return <code>true</code> if successful, <code>false</code> otherwise |
| */ |
| private boolean makeTextHoverFocusable(ISourceViewer sourceViewer, ITextHover textHover) { |
| Point hoverEventLocation= ((ITextViewerExtension2) sourceViewer).getHoverEventLocation(); |
| int offset= computeOffsetAtLocation(sourceViewer, hoverEventLocation.x, hoverEventLocation.y); |
| if (offset == -1) |
| return false; |
| |
| try { |
| IRegion hoverRegion= textHover.getHoverRegion(sourceViewer, offset); |
| if (hoverRegion == null) |
| return false; |
| |
| String hoverInfo= textHover.getHoverInfo(sourceViewer, hoverRegion); |
| |
| IInformationControlCreator controlCreator= null; |
| if (textHover instanceof IInformationProviderExtension2) // this is conceptually wrong, but left here for backwards compatibility |
| controlCreator= ((IInformationProviderExtension2)textHover).getInformationPresenterControlCreator(); |
| |
| IInformationProvider informationProvider= new FocusedInformationPresenter.InformationProvider(hoverRegion, hoverInfo, controlCreator); |
| |
| FocusedInformationPresenter informationPresenter= getInformationPresenter(); |
| informationPresenter.setOffset(offset); |
| informationPresenter.setAnchor(AbstractInformationControlManager.ANCHOR_BOTTOM); |
| informationPresenter.setMargins(6, 6); // default values from AbstractInformationControlManager |
| String contentType= TextUtilities.getContentType(sourceViewer.getDocument(), getSourceViewerConfiguration().getConfiguredDocumentPartitioning(getSourceViewer()), offset, true); |
| informationPresenter.setInformationProvider(informationProvider, contentType); |
| informationPresenter.showInformation(); |
| |
| return true; |
| |
| } catch (BadLocationException e) { |
| return false; |
| } |
| } |
| |
| /** |
| * Tries to make an annotation hover focusable (or "sticky"). |
| * |
| * @param annotationHover the hover to make focusable |
| * @return <code>true</code> if successful, <code>false</code> otherwise |
| */ |
| private boolean makeAnnotationHoverFocusable(IAnnotationHover annotationHover) { |
| IVerticalRulerInfo info= getVerticalRuler(); |
| int line= info.getLineOfLastMouseButtonActivity(); |
| if (line == -1) |
| return false; |
| |
| return getInformationPresenter().openFocusedAnnotationHover(annotationHover, line); |
| } |
| |
| /** |
| * Returns the information presenter (creates it if necessary). |
| * |
| * @return the information presenter |
| * @since 3.6 |
| */ |
| private FocusedInformationPresenter getInformationPresenter() { |
| if (fInformationPresenter == null) { |
| fInformationPresenter= new FocusedInformationPresenter(getSourceViewer(), getSourceViewerConfiguration()); |
| } |
| return fInformationPresenter; |
| } |
| |
| // modified version from TextViewer |
| private int computeOffsetAtLocation(ITextViewer textViewer, int x, int y) { |
| |
| StyledText styledText= textViewer.getTextWidget(); |
| IDocument document= textViewer.getDocument(); |
| |
| int widgetOffset = styledText.getOffsetAtPoint(new Point(x, y)); |
| if (document == null || widgetOffset == -1) { |
| return -1; |
| } |
| |
| try { |
| Point p= styledText.getLocationAtOffset(widgetOffset); |
| if (p.x > x) { |
| widgetOffset--; |
| } |
| |
| if (textViewer instanceof ITextViewerExtension5) { |
| ITextViewerExtension5 extension= (ITextViewerExtension5) textViewer; |
| return extension.widgetOffset2ModelOffset(widgetOffset); |
| } |
| IRegion visibleRegion= textViewer.getVisibleRegion(); |
| return widgetOffset + visibleRegion.getOffset(); |
| } catch (IllegalArgumentException e) { |
| return -1; |
| } |
| } |
| } |
| |
| /** |
| * Key used to look up font preference. |
| * Value: <code>"org.eclipse.jface.textfont"</code> |
| * |
| * @deprecated As of 2.1, replaced by {@link JFaceResources#TEXT_FONT} |
| */ |
| @Deprecated |
| public static final String PREFERENCE_FONT= JFaceResources.TEXT_FONT; |
| /** |
| * Key used to look up foreground color preference. |
| * Value: <code>AbstractTextEditor.Color.Foreground</code> |
| * @since 2.0 |
| */ |
| public static final String PREFERENCE_COLOR_FOREGROUND= "AbstractTextEditor.Color.Foreground"; //$NON-NLS-1$ |
| /** |
| * Key used to look up background color preference. |
| * Value: <code>AbstractTextEditor.Color.Background</code> |
| * @since 2.0 |
| */ |
| public static final String PREFERENCE_COLOR_BACKGROUND= "AbstractTextEditor.Color.Background"; //$NON-NLS-1$ |
| /** |
| * Key used to look up foreground color system default preference. |
| * Value: <code>AbstractTextEditor.Color.Foreground.SystemDefault</code> |
| * @since 2.0 |
| */ |
| public static final String PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT= "AbstractTextEditor.Color.Foreground.SystemDefault"; //$NON-NLS-1$ |
| /** |
| * Key used to look up background color system default preference. |
| * Value: <code>AbstractTextEditor.Color.Background.SystemDefault</code> |
| * @since 2.0 |
| */ |
| public static final String PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT= "AbstractTextEditor.Color.Background.SystemDefault"; //$NON-NLS-1$ |
| /** |
| * Key used to look up selection foreground color preference. |
| * Value: <code>AbstractTextEditor.Color.SelectionForeground</code> |
| * @since 3.0 |
| */ |
| public static final String PREFERENCE_COLOR_SELECTION_FOREGROUND= "AbstractTextEditor.Color.SelectionForeground"; //$NON-NLS-1$ |
| /** |
| * Key used to look up selection background color preference. |
| * Value: <code>AbstractTextEditor.Color.SelectionBackground</code> |
| * @since 3.0 |
| */ |
| public static final String PREFERENCE_COLOR_SELECTION_BACKGROUND= "AbstractTextEditor.Color.SelectionBackground"; //$NON-NLS-1$ |
| /** |
| * Key used to look up selection foreground color system default preference. |
| * Value: <code>AbstractTextEditor.Color.SelectionForeground.SystemDefault</code> |
| * @since 3.0 |
| */ |
| public static final String PREFERENCE_COLOR_SELECTION_FOREGROUND_SYSTEM_DEFAULT= "AbstractTextEditor.Color.SelectionForeground.SystemDefault"; //$NON-NLS-1$ |
| /** |
| * Key used to look up selection background color system default preference. |
| * Value: <code>AbstractTextEditor.Color.SelectionBackground.SystemDefault</code> |
| * @since 3.0 |
| */ |
| public static final String PREFERENCE_COLOR_SELECTION_BACKGROUND_SYSTEM_DEFAULT= "AbstractTextEditor.Color.SelectionBackground.SystemDefault"; //$NON-NLS-1$ |
| /** |
| * Key used to look up find scope background color preference. |
| * Value: <code>AbstractTextEditor.Color.FindScope</code> |
| * @since 2.0 |
| */ |
| public static final String PREFERENCE_COLOR_FIND_SCOPE= "AbstractTextEditor.Color.FindScope"; //$NON-NLS-1$ |
| /** |
| * Key used to look up smart home/end preference. |
| * Value: <code>AbstractTextEditor.Navigation.SmartHomeEnd</code> |
| * @since 2.1 |
| */ |
| public static final String PREFERENCE_NAVIGATION_SMART_HOME_END= "AbstractTextEditor.Navigation.SmartHomeEnd"; //$NON-NLS-1$ |
| /** |
| * Key used to look up the custom caret preference. |
| * Value: {@value} |
| * @since 3.0 |
| */ |
| public static final String PREFERENCE_USE_CUSTOM_CARETS= "AbstractTextEditor.Accessibility.UseCustomCarets"; //$NON-NLS-1$ |
| /** |
| * Key used to look up the caret width preference. |
| * Value: {@value} |
| * @since 3.0 |
| */ |
| public static final String PREFERENCE_WIDE_CARET= "AbstractTextEditor.Accessibility.WideCaret"; //$NON-NLS-1$ |
| /** |
| * A named preference that controls if hyperlinks are turned on or off. |
| * <p> |
| * Value is of type <code>Boolean</code>. |
| * </p> |
| * |
| * @since 3.1 |
| */ |
| public static final String PREFERENCE_HYPERLINKS_ENABLED= "hyperlinksEnabled"; //$NON-NLS-1$ |
| |
| /** |
| * A named preference that controls the key modifier for hyperlinks. |
| * <p> |
| * Value is of type <code>String</code>. |
| * </p> |
| * |
| * @since 3.1 |
| */ |
| public static final String PREFERENCE_HYPERLINK_KEY_MODIFIER= "hyperlinkKeyModifier"; //$NON-NLS-1$ |
| /** |
| * A named preference that controls the key modifier mask for hyperlinks. |
| * The value is only used if the value of <code>PREFERENCE_HYPERLINK_KEY_MODIFIER</code> |
| * cannot be resolved to valid SWT modifier bits. |
| * <p> |
| * Value is of type <code>String</code>. |
| * </p> |
| * |
| * @see #PREFERENCE_HYPERLINK_KEY_MODIFIER |
| * @since 3.1 |
| */ |
| public static final String PREFERENCE_HYPERLINK_KEY_MODIFIER_MASK= "hyperlinkKeyModifierMask"; //$NON-NLS-1$ |
| /** |
| * A named preference that controls the visible ruler column contributions. |
| * <p> |
| * Value is of type <code>String</code> and should be read using a {@link RulerColumnPreferenceAdapter}. |
| * </p> |
| * |
| * @since 3.3 |
| */ |
| public static final String PREFERENCE_RULER_CONTRIBUTIONS= "rulerContributions"; //$NON-NLS-1$ |
| |
| /** |
| * A named preference that controls the display of whitespace characters. |
| * <p> |
| * Value is of type <code>Boolean</code>. |
| * </p> |
| * |
| * <p> |
| * The following preferences can be used for fine-grained configuration when enabled. |
| * <ul> |
| * <li>{@link #PREFERENCE_SHOW_LEADING_SPACES}</li> |
| * <li>{@link #PREFERENCE_SHOW_ENCLOSED_SPACES}</li> |
| * <li>{@link #PREFERENCE_SHOW_TRAILING_SPACES}</li> |
| * <li>{@link #PREFERENCE_SHOW_LEADING_IDEOGRAPHIC_SPACES}</li> |
| * <li>{@link #PREFERENCE_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES}</li> |
| * <li>{@link #PREFERENCE_SHOW_TRAILING_IDEOGRAPHIC_SPACES}</li> |
| * <li>{@link #PREFERENCE_SHOW_LEADING_TABS}</li> |
| * <li>{@link #PREFERENCE_SHOW_ENCLOSED_TABS}</li> |
| * <li>{@link #PREFERENCE_SHOW_TRAILING_TABS}</li> |
| * <li>{@link #PREFERENCE_SHOW_CARRIAGE_RETURN}</li> |
| * <li>{@link #PREFERENCE_SHOW_LINE_FEED}</li> |
| * <li>{@link #PREFERENCE_WHITESPACE_CHARACTER_ALPHA_VALUE}</li> |
| * </ul> |
| * </p> |
| * |
| * @since 3.3 |
| */ |
| public static final String PREFERENCE_SHOW_WHITESPACE_CHARACTERS= "showWhitespaceCharacters"; //$NON-NLS-1$ |
| |
| /** |
| * A named preference that controls the display of leading Space characters. The value is used |
| * only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>. |
| * <p> |
| * Value is of type <code>Boolean</code>. |
| * </p> |
| * |
| * @since 3.7 |
| */ |
| public static final String PREFERENCE_SHOW_LEADING_SPACES= "showLeadingSpaces"; //$NON-NLS-1$ |
| |
| /** |
| * A named preference that controls the display of enclosed Space characters. The value is used |
| * only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>. |
| * <p> |
| * Value is of type <code>Boolean</code>. |
| * </p> |
| * |
| * @since 3.7 |
| */ |
| public static final String PREFERENCE_SHOW_ENCLOSED_SPACES= "showEnclosedSpaces"; //$NON-NLS-1$ |
| |
| /** |
| * A named preference that controls the display of trailing Space characters. The value is used |
| * only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>. |
| * <p> |
| * Value is of type <code>Boolean</code>. |
| * </p> |
| * |
| * @since 3.7 |
| */ |
| public static final String PREFERENCE_SHOW_TRAILING_SPACES= "showTrailingSpaces"; //$NON-NLS-1$ |
| |
| /** |
| * A named preference that controls the display of leading Ideographic Space characters. The |
| * value is used only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is |
| * <code>true</code>. |
| * <p> |
| * Value is of type <code>Boolean</code>. |
| * </p> |
| * |
| * @since 3.7 |
| */ |
| public static final String PREFERENCE_SHOW_LEADING_IDEOGRAPHIC_SPACES= "showLeadingIdeographicSpaces"; //$NON-NLS-1$ |
| |
| /** |
| * A named preference that controls the display of enclosed Ideographic Space characters. The |
| * value is used only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is |
| * <code>true</code>. |
| * <p> |
| * Value is of type <code>Boolean</code>. |
| * </p> |
| * |
| * @since 3.7 |
| */ |
| public static final String PREFERENCE_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES= "showEnclosedIdeographicSpaces"; //$NON-NLS-1$ |
| |
| /** |
| * A named preference that controls the display of trailing Ideographic Space characters. The |
| * value is used only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is |
| * <code>true</code>. |
| * <p> |
| * Value is of type <code>Boolean</code>. |
| * </p> |
| * |
| * @since 3.7 |
| */ |
| public static final String PREFERENCE_SHOW_TRAILING_IDEOGRAPHIC_SPACES= "showTrailingIdeographicSpaces"; //$NON-NLS-1$ |
| |
| /** |
| * A named preference that controls the display of leading Tab characters. The value is used |
| * only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>. |
| * <p> |
| * Value is of type <code>Boolean</code>. |
| * </p> |
| * |
| * @since 3.7 |
| */ |
| public static final String PREFERENCE_SHOW_LEADING_TABS= "showLeadingTabs"; //$NON-NLS-1$ |
| |
| /** |
| * A named preference that controls the display of enclosed Tab characters. The value is used |
| * only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>. |
| * <p> |
| * Value is of type <code>Boolean</code>. |
| * </p> |
| * |
| * @since 3.7 |
| */ |
| public static final String PREFERENCE_SHOW_ENCLOSED_TABS= "showEnclosedTabs"; //$NON-NLS-1$ |
| |
| /** |
| * A named preference that controls the display of trailing Tab characters. The value is used |
| * only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>. |
| * <p> |
| * Value is of type <code>Boolean</code>. |
| * </p> |
| * |
| * @since 3.7 |
| */ |
| public static final String PREFERENCE_SHOW_TRAILING_TABS= "showTrailingTabs"; //$NON-NLS-1$ |
| |
| /** |
| * A named preference that controls the display of Carriage Return characters. The value is used |
| * only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>. |
| * <p> |
| * Value is of type <code>Boolean</code>. |
| * </p> |
| * |
| * @since 3.7 |
| */ |
| public static final String PREFERENCE_SHOW_CARRIAGE_RETURN= "showCarriageReturn"; //$NON-NLS-1$ |
| |
| /** |
| * A named preference that controls the display of Line Feed characters. The value is used only |
| * if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>. |
| * <p> |
| * Value is of type <code>Boolean</code>. |
| * </p> |
| * |
| * @since 3.7 |
| */ |
| public static final String PREFERENCE_SHOW_LINE_FEED= "showLineFeed"; //$NON-NLS-1$ |
| |
| /** |
| * A named preference that controls the alpha value of whitespace characters. The value is used |
| * only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>. |
| * <p> |
| * Value is of type <code>Integer</code>. |
| * </p> |
| * |
| * @since 3.7 |
| */ |
| public static final String PREFERENCE_WHITESPACE_CHARACTER_ALPHA_VALUE= "whitespaceCharacterAlphaValue"; //$NON-NLS-1$ |
| |
| /** |
| * A named preference that controls whether text drag and drop is enabled. |
| * <p> |
| * Value is of type <code>Boolean</code>. |
| * </p> |
| * |
| * @since 3.3 |
| */ |
| public static final String PREFERENCE_TEXT_DRAG_AND_DROP_ENABLED= "textDragAndDropEnabled"; //$NON-NLS-1$ |
| |
| /** |
| * A named preference that controls if hovers should automatically be closed |
| * when the mouse is moved into them, or when they should be enriched. |
| * <p> |
| * Value is of type <code>Integer</code> and maps to the following |
| * {@link org.eclipse.jface.text.ITextViewerExtension8.EnrichMode}: |
| * </p> |
| * <ul> |
| * <li>-1: <code>null</code> (don't allow moving the mouse into a hover),</li> |
| * <li>0: {@link org.eclipse.jface.text.ITextViewerExtension8.EnrichMode#AFTER_DELAY},</li> |
| * <li>1: {@link org.eclipse.jface.text.ITextViewerExtension8.EnrichMode#IMMEDIATELY},</li> |
| * <li>2: {@link org.eclipse.jface.text.ITextViewerExtension8.EnrichMode#ON_CLICK}.</li> |
| * </ul> |
| * |
| * @since 3.4 |
| */ |
| public static final String PREFERENCE_HOVER_ENRICH_MODE= "hoverReplaceMode"; //$NON-NLS-1$ |
| |
| /** |
| * A named preference to control the initial word wrap status. |
| * <p> |
| * Value is of type <code>Boolean</code>. |
| * </p> |
| * |
| * @since 3.10 |
| */ |
| public static final String PREFERENCE_WORD_WRAP_ENABLED= "wordwrap.enabled"; //$NON-NLS-1$ |
| |
| /** Menu id for the editor context menu. */ |
| public static final String DEFAULT_EDITOR_CONTEXT_MENU_ID= "#EditorContext"; //$NON-NLS-1$ |
| /** Menu id for the ruler context menu. */ |
| public static final String DEFAULT_RULER_CONTEXT_MENU_ID= "#RulerContext"; //$NON-NLS-1$ |
| |
| /** |
| * Menu id used to contribute to the editor context menu of all textual editors. |
| * |
| * @since 3.5 |
| */ |
| public static final String COMMON_EDITOR_CONTEXT_MENU_ID= "#AbstractTextEditorContext"; //$NON-NLS-1$ |
| |
| /** |
| * Menu id used to contribute to the ruler context menu of all textual editors. |
| * |
| * @since 3.5 |
| */ |
| public static final String COMMON_RULER_CONTEXT_MENU_ID= "#AbstractTextEditorRulerContext"; //$NON-NLS-1$ |
| |
| /** The width of the vertical ruler. */ |
| protected static final int VERTICAL_RULER_WIDTH= 12; |
| |
| /** |
| * The complete mapping between action definition IDs used by eclipse and StyledText actions. |
| * |
| * @since 2.0 |
| */ |
| protected static final IdMapEntry[] ACTION_MAP= new IdMapEntry[] { |
| // navigation |
| new IdMapEntry(ITextEditorActionDefinitionIds.LINE_UP, ST.LINE_UP), |
| new IdMapEntry(ITextEditorActionDefinitionIds.LINE_DOWN, ST.LINE_DOWN), |
| new IdMapEntry(ITextEditorActionDefinitionIds.LINE_START, ST.LINE_START), |
| new IdMapEntry(ITextEditorActionDefinitionIds.LINE_END, ST.LINE_END), |
| new IdMapEntry(ITextEditorActionDefinitionIds.COLUMN_PREVIOUS, ST.COLUMN_PREVIOUS), |
| new IdMapEntry(ITextEditorActionDefinitionIds.COLUMN_NEXT, ST.COLUMN_NEXT), |
| new IdMapEntry(ITextEditorActionDefinitionIds.PAGE_UP, ST.PAGE_UP), |
| new IdMapEntry(ITextEditorActionDefinitionIds.PAGE_DOWN, ST.PAGE_DOWN), |
| new IdMapEntry(ITextEditorActionDefinitionIds.WORD_PREVIOUS, ST.WORD_PREVIOUS), |
| new IdMapEntry(ITextEditorActionDefinitionIds.WORD_NEXT, ST.WORD_NEXT), |
| new IdMapEntry(ITextEditorActionDefinitionIds.TEXT_START, ST.TEXT_START), |
| new IdMapEntry(ITextEditorActionDefinitionIds.TEXT_END, ST.TEXT_END), |
| new IdMapEntry(ITextEditorActionDefinitionIds.WINDOW_START, ST.WINDOW_START), |
| new IdMapEntry(ITextEditorActionDefinitionIds.WINDOW_END, ST.WINDOW_END), |
| // selection |
| new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_LINE_UP, ST.SELECT_LINE_UP), |
| new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_LINE_DOWN, ST.SELECT_LINE_DOWN), |
| new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_LINE_START, ST.SELECT_LINE_START), |
| new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_LINE_END, ST.SELECT_LINE_END), |
| new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_COLUMN_PREVIOUS, ST.SELECT_COLUMN_PREVIOUS), |
| new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_COLUMN_NEXT, ST.SELECT_COLUMN_NEXT), |
| new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_PAGE_UP, ST.SELECT_PAGE_UP), |
| new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_PAGE_DOWN, ST.SELECT_PAGE_DOWN), |
| new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS, ST.SELECT_WORD_PREVIOUS), |
| new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT, ST.SELECT_WORD_NEXT), |
| new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_TEXT_START, ST.SELECT_TEXT_START), |
| new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_TEXT_END, ST.SELECT_TEXT_END), |
| new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_WINDOW_START, ST.SELECT_WINDOW_START), |
| new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_WINDOW_END, ST.SELECT_WINDOW_END), |
| // modification |
| new IdMapEntry(IWorkbenchCommandConstants.EDIT_CUT, ST.CUT), |
| new IdMapEntry(IWorkbenchCommandConstants.EDIT_COPY, ST.COPY), |
| new IdMapEntry(IWorkbenchCommandConstants.EDIT_PASTE, ST.PASTE), |
| new IdMapEntry(ITextEditorActionDefinitionIds.DELETE_PREVIOUS, ST.DELETE_PREVIOUS), |
| new IdMapEntry(ITextEditorActionDefinitionIds.DELETE_NEXT, ST.DELETE_NEXT), |
| new IdMapEntry(ITextEditorActionDefinitionIds.DELETE_PREVIOUS_WORD, ST.DELETE_WORD_PREVIOUS), |
| new IdMapEntry(ITextEditorActionDefinitionIds.DELETE_NEXT_WORD, ST.DELETE_WORD_NEXT), |
| // miscellaneous |
| new IdMapEntry(ITextEditorActionDefinitionIds.TOGGLE_OVERWRITE, ST.TOGGLE_OVERWRITE) |
| }; |
| |
| private final String fReadOnlyLabel= EditorMessages.Editor_statusline_state_readonly_label; |
| private final String fWritableLabel= EditorMessages.Editor_statusline_state_writable_label; |
| private final String fInsertModeLabel= EditorMessages.Editor_statusline_mode_insert_label; |
| private final String fOverwriteModeLabel= EditorMessages.Editor_statusline_mode_overwrite_label; |
| private final String fSmartInsertModeLabel= EditorMessages.Editor_statusline_mode_smartinsert_label; |
| |
| /** The error message shown in the status line in case of failed information look up. */ |
| protected final String fErrorLabel= EditorMessages.Editor_statusline_error_label; |
| |
| /** |
| * Data structure for the position label value. |
| */ |
| private static class PositionLabelValue { |
| |
| public int fValue; |
| |
| @Override |
| public String toString() { |
| return String.valueOf(fValue); |
| } |
| } |
| /** The pattern used to show the position label in the status line. */ |
| private final String fPositionLabelPattern= EditorMessages.Editor_statusline_position_pattern; |
| /** The position label value of the current line. */ |
| private final PositionLabelValue fLineLabel= new PositionLabelValue(); |
| /** The position label value of the current column. */ |
| private final PositionLabelValue fColumnLabel= new PositionLabelValue(); |
| /** The arguments for the position label pattern. */ |
| private final Object[] fPositionLabelPatternArguments= new Object[] { fLineLabel, fColumnLabel }; |
| /** |
| * The column support of this editor. |
| * @since 3.3 |
| */ |
| private IColumnSupport fColumnSupport; |
| |
| /** The editor's explicit document provider. */ |
| private IDocumentProvider fExplicitDocumentProvider; |
| /** The editor's preference store. */ |
| private IPreferenceStore fPreferenceStore; |
| /** The editor's range indicator. */ |
| private Annotation fRangeIndicator; |
| /** The editor's source viewer configuration. */ |
| private SourceViewerConfiguration fConfiguration; |
| /** The editor's source viewer. */ |
| private ISourceViewer fSourceViewer; |
| /** |
| * The editor's selection provider. |
| * @since 2.1 |
| */ |
| private SelectionProvider fSelectionProvider= new SelectionProvider(); |
| /** |
| * The editor's selection listener. |
| * @since 3.0 |
| */ |
| private SelectionListener fSelectionListener; |
| /** The editor's font. */ |
| private Font fFont; /** |
| * The editor's foreground color. |
| * @since 2.0 |
| */ |
| private Color fForegroundColor; |
| /** |
| * The editor's background color. |
| * @since 2.0 |
| */ |
| private Color fBackgroundColor; |
| /** |
| * The editor's selection foreground color. |
| * @since 3.0 |
| */ |
| private Color fSelectionForegroundColor; |
| /** |
| * The editor's selection background color. |
| * @since 3.0 |
| */ |
| private Color fSelectionBackgroundColor; |
| /** |
| * The find scope's highlight color. |
| * @since 2.0 |
| */ |
| private Color fFindScopeHighlightColor; |
| |
| /** |
| * The editor's status line. |
| * @since 2.1 |
| */ |
| private IEditorStatusLine fEditorStatusLine; |
| /** The editor's vertical ruler. */ |
| private IVerticalRuler fVerticalRuler; |
| /** The editor's context menu id. */ |
| private String fEditorContextMenuId; |
| /** The ruler's context menu id. */ |
| private String fRulerContextMenuId; |
| /** The editor's help context id. */ |
| private String fHelpContextId; |
| /** The editor's presentation mode. */ |
| private boolean fShowHighlightRangeOnly; |
| /** The actions registered with the editor. */ |
| private Map<String, IAction> fActions= new HashMap<>(10); |
| /** The actions marked as selection dependent. */ |
| private List<String> fSelectionActions= new ArrayList<>(5); |
| /** The actions marked as content dependent. */ |
| private List<String> fContentActions= new ArrayList<>(5); |
| /** |
| * The actions marked as property dependent. |
| * @since 2.0 |
| */ |
| private List<String> fPropertyActions= new ArrayList<>(5); |
| /** |
| * The actions marked as state dependent. |
| * @since 2.0 |
| */ |
| private List<String> fStateActions= new ArrayList<>(5); |
| /** The editor's action activation codes. */ |
| private List<ActionActivationCode> fActivationCodes= new ArrayList<>(2); |
| /** The verify key listener for activation code triggering. */ |
| private ActivationCodeTrigger fActivationCodeTrigger= new ActivationCodeTrigger(); |
| /** Context menu listener. */ |
| private IMenuListener fMenuListener; |
| /** Vertical ruler mouse listener. */ |
| private MouseListener fMouseListener; |
| /** Selection changed listener. */ |
| private ISelectionChangedListener fSelectionChangedListener; |
| /** Title image to be disposed. */ |
| private Image fTitleImage; |
| /** The text context menu to be disposed. */ |
| private Menu fTextContextMenu; |
| /** The ruler context menu to be disposed. */ |
| private Menu fRulerContextMenu; |
| /** The editor's element state listener. */ |
| private IElementStateListener fElementStateListener= new ElementStateListener(); |
| /** |
| * The editor's text input listener. |
| * @since 2.1 |
| */ |
| private TextInputListener fTextInputListener= new TextInputListener(); |
| /** The editor's text listener. */ |
| private TextListener fTextListener= new TextListener(); |
| /** The editor's property change listener. */ |
| private IPropertyChangeListener fPropertyChangeListener= new PropertyChangeListener(); |
| /** |
| * The editor's font properties change listener. |
| * @since 2.1 |
| */ |
| private IPropertyChangeListener fFontPropertyChangeListener= new FontPropertyChangeListener(); |
| |
| /** |
| * The editor's activation listener. |
| * @since 2.0 |
| */ |
| private ActivationListener fActivationListener; |
| /** |
| * Indicates activation should be handled. |
| * @since 3.9 |
| */ |
| private boolean fHandleActivation= true; |
| /** |
| * The map of the editor's status fields. |
| * @since 2.0 |
| */ |
| private Map<String, IStatusField> fStatusFields; |
| /** |
| * The editor's cursor listener. |
| * @since 2.0 |
| */ |
| private ICursorListener fCursorListener; |
| /** |
| * The editor's remembered text selection. |
| * @since 2.0 |
| */ |
| private ISelection fRememberedSelection; |
| /** |
| * Indicates whether the editor runs in 1.0 context menu registration compatibility mode. |
| * @since 2.0 |
| */ |
| private boolean fCompatibilityMode= true; |
| /** |
| * The number of re-entrances into error correction code while saving. |
| * @since 2.0 |
| */ |
| private int fErrorCorrectionOnSave; |
| /** |
| * The delete line target. |
| * @since 2.1 |
| */ |
| private IDeleteLineTarget fDeleteLineTarget; |
| /** |
| * The incremental find target. |
| * @since 2.0 |
| */ |
| private IncrementalFindTarget fIncrementalFindTarget; |
| /** |
| * The mark region target. |
| * @since 2.0 |
| */ |
| private IMarkRegionTarget fMarkRegionTarget; |
| /** |
| * Cached modification stamp of the editor's input. |
| * @since 2.0 |
| */ |
| private long fModificationStamp= -1; |
| /** |
| * Ruler context menu listeners. |
| * @since 2.0 |
| */ |
| private List<IMenuListener> fRulerContextMenuListeners= new ArrayList<>(); |
| /** |
| * Indicates whether sanity checking in enabled. |
| * @since 2.0 |
| */ |
| private boolean fIsSanityCheckEnabled= true; |
| /** |
| * The find replace target. |
| * @since 2.1 |
| */ |
| private FindReplaceTarget fFindReplaceTarget; |
| /** |
| * Indicates whether state validation is enabled. |
| * @since 2.1 |
| */ |
| private boolean fIsStateValidationEnabled= true; |
| /** |
| * The key binding scopes of this editor. |
| * @since 2.1 |
| */ |
| private String[] fKeyBindingScopes; |
| /** |
| * Whether the overwrite mode can be turned on. |
| * @since 3.0 |
| */ |
| private boolean fIsOverwriteModeEnabled= true; |
| /** |
| * Whether the overwrite mode is currently on. |
| * @since 3.0 |
| */ |
| private boolean fIsOverwriting= false; |
| /** |
| * The editor's insert mode. |
| * @since 3.0 |
| */ |
| private InsertMode fInsertMode= SMART_INSERT; |
| /** |
| * The sequence of legal editor insert modes. |
| * @since 3.0 |
| */ |
| private List<InsertMode> fLegalInsertModes= null; |
| /** |
| * The non-default caret. |
| * @since 3.0 |
| */ |
| private Caret fNonDefaultCaret; |
| /** |
| * The image used in non-default caret. |
| * @since 3.0 |
| */ |
| private Image fNonDefaultCaretImage; |
| /** |
| * The styled text's initial caret. |
| * @since 3.0 |
| */ |
| private Caret fInitialCaret; |
| /** |
| * The operation approver used to warn on undoing of non-local operations. |
| * @since 3.1 |
| */ |
| private IOperationApprover fNonLocalOperationApprover; |
| /** |
| * The operation approver used to warn of linear undo violations. |
| * @since 3.1 |
| */ |
| private IOperationApprover fLinearUndoViolationApprover; |
| /** |
| * This editor's memento holding data for restoring it after restart. |
| * @since 3.3 |
| */ |
| private IMemento fMementoToRestore; |
| /** |
| * This editor's savable. |
| * @since 3.3 |
| */ |
| private TextEditorSavable fSavable; |
| /** |
| * Tells whether text drag and drop has been installed on the control. |
| * @since 3.3 |
| */ |
| private boolean fIsTextDragAndDropInstalled= false; |
| /** |
| * Helper token to decide whether drag and |
| * drop happens inside the same editor. |
| * @since 3.3 |
| */ |
| private Object fTextDragAndDropToken; |
| /** |
| * The information presenter, may be <code>null</code>. |
| * @since 3.3 |
| */ |
| private FocusedInformationPresenter fInformationPresenter; |
| |
| /** |
| * Tells whether this editor has been activated at least once. |
| * @since 3.3.2 |
| */ |
| private boolean fHasBeenActivated= false; |
| /** |
| * Key binding support for the quick assist assistant. |
| * @since 3.4 |
| */ |
| private KeyBindingSupportForAssistant fKeyBindingSupportForQuickAssistant; |
| |
| /** |
| * Key binding support for the quick assist assistant. |
| * @since 3.5 |
| */ |
| private KeyBindingSupportForAssistant fKeyBindingSupportForContentAssistant; |
| |
| /** |
| * The save action. |
| * @since 3.6.1 |
| */ |
| private IWorkbenchAction fSaveAction; |
| |
| |
| /** |
| * Creates a new text editor. If not explicitly set, this editor uses |
| * a <code>SourceViewerConfiguration</code> to configure its |
| * source viewer. This viewer does not have a range indicator installed, |
| * nor any menu id set. By default, the created editor runs in 1.0 context |
| * menu registration compatibility mode. |
| */ |
| protected AbstractTextEditor() { |
| super(); |
| fEditorContextMenuId= null; |
| fRulerContextMenuId= null; |
| fHelpContextId= null; |
| } |
| |
| @Override |
| public IDocumentProvider getDocumentProvider() { |
| return fExplicitDocumentProvider; |
| } |
| |
| /** |
| * Returns the editor's range indicator. May return <code>null</code> if no |
| * range indicator is installed. |
| * |
| * @return the editor's range indicator which may be <code>null</code> |
| */ |
| protected final Annotation getRangeIndicator() { |
| return fRangeIndicator; |
| } |
| |
| /** |
| * Returns the editor's source viewer configuration. May return <code>null</code> |
| * before the editor's part has been created and after disposal. |
| * |
| * @return the editor's source viewer configuration which may be <code>null</code> |
| */ |
| protected final SourceViewerConfiguration getSourceViewerConfiguration() { |
| return fConfiguration; |
| } |
| |
| /** |
| * Returns the editor's source viewer. May return <code>null</code> before |
| * the editor's part has been created and after disposal. |
| * |
| * @return the editor's source viewer which may be <code>null</code> |
| */ |
| protected final ISourceViewer getSourceViewer() { |
| return fSourceViewer; |
| } |
| |
| /** |
| * Returns the editor's vertical ruler. May return <code>null</code> before |
| * the editor's part has been created and after disposal. |
| * |
| * @return the editor's vertical ruler which may be <code>null</code> |
| */ |
| protected final IVerticalRuler getVerticalRuler() { |
| return fVerticalRuler; |
| } |
| |
| /** |
| * Returns the editor's context menu id. May return <code>null</code> before |
| * the editor's part has been created. |
| * |
| * @return the editor's context menu id which may be <code>null</code> |
| */ |
| protected final String getEditorContextMenuId() { |
| return fEditorContextMenuId; |
| } |
| |
| /** |
| * Returns the ruler's 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> |
| */ |
| protected final String getRulerContextMenuId() { |
| return fRulerContextMenuId; |
| } |
| |
| /** |
| * Returns the editor's help context id or <code>null</code> if none has |
| * been set. |
| * |
| * @return the editor's help context id which may be <code>null</code> |
| */ |
| protected final String getHelpContextId() { |
| return fHelpContextId; |
| } |
| |
| /** |
| * Returns this editor's preference store or <code>null</code> if none has |
| * been set. |
| * |
| * @return this editor's preference store which may be <code>null</code> |
| */ |
| protected final IPreferenceStore getPreferenceStore() { |
| return fPreferenceStore; |
| } |
| |
| /** |
| * Sets this editor's document provider. This method must be |
| * called before the editor's control is created. |
| * |
| * @param provider the document provider |
| */ |
| protected void setDocumentProvider(IDocumentProvider provider) { |
| fExplicitDocumentProvider= provider; |
| } |
| |
| /** |
| * Sets this editor's source viewer configuration used to configure its |
| * internal source viewer. This method must be called before the editor's |
| * control is created. If not, this editor uses a <code>SourceViewerConfiguration</code>. |
| * |
| * @param configuration the source viewer configuration object |
| */ |
| protected void setSourceViewerConfiguration(SourceViewerConfiguration configuration) { |
| Assert.isNotNull(configuration); |
| fConfiguration= configuration; |
| } |
| |
| /** |
| * Sets the annotation which this editor uses to represent the highlight |
| * range if the editor is configured to show the entire document. If the |
| * range indicator is not set, this editor will not show a range indication. |
| * |
| * @param rangeIndicator the annotation |
| */ |
| protected void setRangeIndicator(Annotation rangeIndicator) { |
| Assert.isNotNull(rangeIndicator); |
| fRangeIndicator= rangeIndicator; |
| } |
| |
| /** |
| * Sets this editor's context menu id. |
| * |
| * @param contextMenuId the context menu id |
| */ |
| protected void setEditorContextMenuId(String contextMenuId) { |
| Assert.isNotNull(contextMenuId); |
| fEditorContextMenuId= contextMenuId; |
| } |
| |
| /** |
| * Sets the ruler's context menu id. |
| * |
| * @param contextMenuId the context menu id |
| */ |
| protected void setRulerContextMenuId(String contextMenuId) { |
| Assert.isNotNull(contextMenuId); |
| fRulerContextMenuId= contextMenuId; |
| } |
| |
| /** |
| * Sets the context menu registration 1.0 compatibility mode. (See class |
| * description for more details.) |
| * |
| * @param compatible <code>true</code> if compatibility mode is enabled |
| * @since 2.0 |
| */ |
| protected final void setCompatibilityMode(boolean compatible) { |
| fCompatibilityMode= compatible; |
| } |
| |
| /** |
| * Sets the editor's help context id. |
| * |
| * @param helpContextId the help context id |
| */ |
| protected void setHelpContextId(String helpContextId) { |
| Assert.isNotNull(helpContextId); |
| fHelpContextId= helpContextId; |
| } |
| |
| /** |
| * Sets the key binding scopes for this editor. |
| * |
| * @param scopes a non-empty array of key binding scope identifiers |
| * @since 2.1 |
| */ |
| protected void setKeyBindingScopes(String[] scopes) { |
| Assert.isTrue(scopes != null && scopes.length > 0); |
| fKeyBindingScopes= scopes; |
| } |
| |
| /** |
| * Sets this editor's preference store. This method must be |
| * called before the editor's control is created. |
| * |
| * @param store the preference store or <code>null</code> to remove the |
| * preference store |
| */ |
| protected void setPreferenceStore(IPreferenceStore store) { |
| if (fPreferenceStore != null) { |
| fPreferenceStore.removePropertyChangeListener(fPropertyChangeListener); |
| fPreferenceStore.removePropertyChangeListener(fFontPropertyChangeListener); |
| } |
| |
| fPreferenceStore= store; |
| |
| if (fPreferenceStore != null) { |
| fPreferenceStore.addPropertyChangeListener(fPropertyChangeListener); |
| fPreferenceStore.addPropertyChangeListener(fFontPropertyChangeListener); |
| } |
| } |
| |
| @Override |
| public boolean isEditable() { |
| IDocumentProvider provider= getDocumentProvider(); |
| if (provider instanceof IDocumentProviderExtension) { |
| IDocumentProviderExtension extension= (IDocumentProviderExtension) provider; |
| return extension.isModifiable(getEditorInput()); |
| } |
| return false; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * <p> |
| * Returns <code>null</code> after disposal. |
| * </p> |
| * |
| * @return the selection provider or <code>null</code> if the editor has |
| * been disposed |
| */ |
| @Override |
| public ISelectionProvider getSelectionProvider() { |
| return fSelectionProvider; |
| } |
| |
| /** |
| * Remembers the current selection of this editor. This method is called when, e.g., |
| * the content of the editor is about to be reverted to the saved state. This method |
| * remembers the selection in a semantic format, i.e., in a format which allows to |
| * restore the selection even if the originally selected text is no longer part of the |
| * editor's content. |
| * <p> |
| * Subclasses should implement this method including all necessary state. This |
| * default implementation remembers the textual range only and is thus purely |
| * syntactic.</p> |
| * |
| * @see #restoreSelection() |
| * @since 2.0 |
| */ |
| protected void rememberSelection() { |
| fRememberedSelection= doGetSelection(); |
| } |
| |
| /** |
| * Returns the current selection. |
| * @return ISelection |
| * @since 2.1 |
| */ |
| protected ISelection doGetSelection() { |
| ISelectionProvider sp= null; |
| if (fSourceViewer != null) |
| sp= fSourceViewer.getSelectionProvider(); |
| return (sp == null ? null : sp.getSelection()); |
| } |
| |
| /** |
| * Restores a selection previously remembered by <code>rememberSelection</code>. |
| * Subclasses may reimplement this method and thereby semantically adapt the |
| * remembered selection. This default implementation just selects the |
| * remembered textual range. |
| * |
| * @see #rememberSelection() |
| * @since 2.0 |
| */ |
| protected void restoreSelection() { |
| if (fRememberedSelection instanceof ITextSelection) { |
| ITextSelection textSelection= (ITextSelection)fRememberedSelection; |
| if (isValidSelection(textSelection.getOffset(), textSelection.getLength())) |
| doSetSelection(fRememberedSelection); |
| } |
| fRememberedSelection= null; |
| } |
| |
| /** |
| * Tells whether the given selection is valid. |
| * |
| * @param offset the offset of the selection |
| * @param length the length of the selection |
| * @return <code>true</code> if the selection is valid |
| * @since 2.1 |
| */ |
| private boolean isValidSelection(int offset, int length) { |
| IDocumentProvider provider= getDocumentProvider(); |
| if (provider != null) { |
| IDocument document= provider.getDocument(getEditorInput()); |
| if (document != null) { |
| int end= offset + length; |
| int documentLength= document.getLength(); |
| return 0 <= offset && offset <= documentLength && 0 <= end && end <= documentLength && length >= 0; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Sets the given selection. |
| * |
| * @param selection the selection |
| * @since 2.1 |
| */ |
| protected void doSetSelection(ISelection selection) { |
| if (selection instanceof ITextSelection) { |
| ITextSelection textSelection= (ITextSelection) selection; |
| selectAndReveal(textSelection.getOffset(), textSelection.getLength()); |
| } |
| } |
| |
| /** |
| * Creates the listener on this editor's context menus. |
| * |
| * @return the created menu listener |
| * @since 3.4 |
| */ |
| protected IMenuListener createContextMenuListener() { |
| return new IMenuListener() { |
| @Override |
| public void menuAboutToShow(IMenuManager menu) { |
| String id= menu.getId(); |
| if (getRulerContextMenuId().equals(id)) { |
| setFocus(); |
| rulerContextMenuAboutToShow(menu); |
| } else if (getEditorContextMenuId().equals(id)) { |
| setFocus(); |
| editorContextMenuAboutToShow(menu); |
| } |
| } |
| }; |
| } |
| |
| /** |
| * Creates and returns the listener on this editor's context menus. |
| * |
| * @return the menu listener |
| */ |
| protected final IMenuListener getContextMenuListener() { |
| if (fMenuListener == null) |
| fMenuListener= createContextMenuListener(); |
| return fMenuListener; |
| } |
| |
| /** |
| * Creates and returns the listener on this editor's vertical ruler. |
| * |
| * @return the mouse listener |
| */ |
| protected final MouseListener getRulerMouseListener() { |
| if (fMouseListener == null) { |
| fMouseListener= new MouseListener() { |
| |
| private boolean fDoubleClicked= false; |
| private final int fDoubleClickTime= getSite().getShell().getDisplay().getDoubleClickTime(); |
| private long fMouseUpDelta= 0; |
| |
| private void triggerAction(String actionID, MouseEvent e) { |
| IAction action= getAction(actionID); |
| if (action != null) { |
| if (action instanceof IUpdate) |
| ((IUpdate) action).update(); |
| if (action.isEnabled()) { |
| Event event= new Event(); |
| event.type= fDoubleClicked ? SWT.MouseDoubleClick : SWT.MouseUp; |
| event.display= e.display; |
| event.widget= e.widget; |
| event.time= e.time; |
| event.data= e.data; |
| event.x= e.x; |
| event.y= e.y; |
| event.button= e.button; |
| event.stateMask= e.stateMask; |
| event.count= e.count; |
| action.runWithEvent(event); |
| } |
| } |
| } |
| |
| @Override |
| public void mouseUp(final MouseEvent e) { |
| setFocus(); |
| final int delay= fMouseUpDelta == 0 ? 0 : fDoubleClickTime - (int)(System.currentTimeMillis() - fMouseUpDelta); |
| if (1 != e.button) |
| return; |
| |
| Runnable runnable= new Runnable() { |
| @Override |
| public void run() { |
| if (!fDoubleClicked) |
| triggerAction(ITextEditorActionConstants.RULER_CLICK, e); |
| } |
| }; |
| if (delay <= 0) |
| runnable.run(); |
| else |
| e.widget.getDisplay().timerExec(delay, runnable); |
| } |
| |
| @Override |
| public void mouseDoubleClick(MouseEvent e) { |
| if (1 == e.button) { |
| fDoubleClicked= true; |
| triggerAction(ITextEditorActionConstants.RULER_DOUBLE_CLICK, e); |
| } |
| } |
| |
| @Override |
| public void mouseDown(MouseEvent e) { |
| fMouseUpDelta= System.currentTimeMillis(); |
| fDoubleClicked= false; |
| if (fRulerContextMenu != null && !fRulerContextMenu.isDisposed()) { |
| Display display= fRulerContextMenu.getDisplay(); |
| Point location= display.getCursorLocation(); |
| fRulerContextMenu.setLocation(location.x, location.y); |
| } |
| } |
| }; |
| } |
| return fMouseListener; |
| } |
| |
| /** |
| * Returns this editor's selection changed listener to be installed |
| * on the editor's source viewer. |
| * |
| * @return the listener |
| */ |
| protected final ISelectionChangedListener getSelectionChangedListener() { |
| if (fSelectionChangedListener == null) { |
| fSelectionChangedListener= new ISelectionChangedListener() { |
| |
| private Runnable fRunnable= new Runnable() { |
| @Override |
| public void run() { |
| // check whether editor has not been disposed yet |
| if (fSourceViewer != null && fSourceViewer.getDocument() != null) { |
| handleCursorPositionChanged(); |
| updateSelectionDependentActions(); |
| } |
| } |
| }; |
| |
| private Display fDisplay; |
| |
| @Override |
| public void selectionChanged(SelectionChangedEvent event) { |
| if (fDisplay == null) |
| fDisplay= getSite().getShell().getDisplay(); |
| if (Display.getCurrent() == fDisplay) |
| fRunnable.run(); |
| else |
| fDisplay.asyncExec(fRunnable); |
| } |
| }; |
| } |
| |
| return fSelectionChangedListener; |
| } |
| |
| /** |
| * Returns this editor's "cursor" listener to be installed on the editor's |
| * source viewer. This listener is listening to key and mouse button events. |
| * It triggers the updating of the status line by calling |
| * <code>handleCursorPositionChanged()</code>. |
| * |
| * @return the listener |
| * @since 2.0 |
| */ |
| protected final ICursorListener getCursorListener() { |
| if (fCursorListener == null) { |
| fCursorListener= new ICursorListener() { |
| |
| @Override |
| public void keyPressed(KeyEvent e) { |
| handleCursorPositionChanged(); |
| } |
| |
| @Override |
| public void keyReleased(KeyEvent e) { |
| } |
| |
| @Override |
| public void mouseDoubleClick(MouseEvent e) { |
| } |
| |
| @Override |
| public void mouseDown(MouseEvent e) { |
| } |
| |
| @Override |
| public void mouseUp(MouseEvent e) { |
| handleCursorPositionChanged(); |
| } |
| }; |
| } |
| return fCursorListener; |
| } |
| |
| /** |
| * Implements the <code>init</code> method of <code>IEditorPart</code>. |
| * Subclasses replacing <code>init</code> may choose to call this method in |
| * their implementation. |
| * |
| * @param window the workbench window |
| * @param site the editor's site |
| * @param input the editor input for the editor being created |
| * @throws PartInitException if {@link #doSetInput(IEditorInput)} fails or gets canceled |
| * |
| * @see org.eclipse.ui.IEditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput) |
| * @since 2.1 |
| */ |
| protected final void internalInit(IWorkbenchWindow window, final IEditorSite site, final IEditorInput input) throws PartInitException { |
| |
| IRunnableWithProgress runnable= new IRunnableWithProgress() { |
| @Override |
| public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { |
| try { |
| |
| if (getDocumentProvider() instanceof IDocumentProviderExtension2) { |
| IDocumentProviderExtension2 extension= (IDocumentProviderExtension2) getDocumentProvider(); |
| extension.setProgressMonitor(monitor); |
| } |
| |
| doSetInput(input); |
| |
| } catch (CoreException x) { |
| throw new InvocationTargetException(x); |
| } finally { |
| if (getDocumentProvider() instanceof IDocumentProviderExtension2) { |
| IDocumentProviderExtension2 extension= (IDocumentProviderExtension2) getDocumentProvider(); |
| extension.setProgressMonitor(null); |
| } |
| } |
| } |
| }; |
| |
| try { |
| // When using the progress service always a modal dialog pops up. The site should be asked for a runnable context |
| // which could be the workbench window or the progress service, depending on what the site represents. |
| // getSite().getWorkbenchWindow().getWorkbench().getProgressService().run(false, true, runnable); |
| |
| getSite().getWorkbenchWindow().run(false, true, runnable); |
| |
| } catch (InterruptedException x) { |
| } catch (InvocationTargetException x) { |
| Throwable t= x.getTargetException(); |
| if (t instanceof CoreException) { |
| /* |
| /* XXX: Remove unpacking of CoreException once the following bug is |
| * fixed: https://bugs.eclipse.org/bugs/show_bug.cgi?id=81640 |
| */ |
| CoreException e= (CoreException)t; |
| IStatus status= e.getStatus(); |
| if (status.getException() != null) |
| throw new PartInitException(status); |
| throw new PartInitException(new Status(status.getSeverity(), status.getPlugin(), status.getCode(), status.getMessage(), t)); |
| } |
| throw new PartInitException(new Status(IStatus.ERROR, TextEditorPlugin.PLUGIN_ID, IStatus.OK, EditorMessages.Editor_error_init, t)); |
| } |
| } |
| |
| @Override |
| public void init(final IEditorSite site, final IEditorInput input) throws PartInitException { |
| |
| setSite(site); |
| |
| internalInit(site.getWorkbenchWindow(), site, input); |
| fActivationListener= new ActivationListener(site.getWorkbenchWindow().getPartService()); |
| } |
| |
| /** |
| * Creates the vertical ruler to be used by this editor. |
| * Subclasses may re-implement this method. |
| * |
| * @return the vertical ruler |
| */ |
| protected IVerticalRuler createVerticalRuler() { |
| return new VerticalRuler(VERTICAL_RULER_WIDTH); |
| } |
| |
| /** |
| * Adds enabled ruler contributions to the vertical ruler. |
| * <p> |
| * Clients may extend or replace.</p> |
| * |
| * @param ruler the composite ruler to add contributions to |
| * @since 3.3 |
| */ |
| protected void updateContributedRulerColumns(CompositeRuler ruler) { |
| IColumnSupport support= getAdapter(IColumnSupport.class); |
| if (support == null) |
| return; |
| |
| RulerColumnPreferenceAdapter adapter= null; |
| if (fPreferenceStore != null) |
| adapter= new RulerColumnPreferenceAdapter(getPreferenceStore(), PREFERENCE_RULER_CONTRIBUTIONS); |
| |
| RulerColumnRegistry registry= RulerColumnRegistry.getDefault(); |
| List<RulerColumnDescriptor> descriptors= registry.getColumnDescriptors(); |
| for (Iterator<RulerColumnDescriptor> it= descriptors.iterator(); it.hasNext();) { |
| final RulerColumnDescriptor descriptor= it.next(); |
| support.setColumnVisible(descriptor, adapter == null || adapter.isEnabled(descriptor)); |
| } |
| } |
| |
| /** |
| * Creates the column support to be used by this editor to manage the |
| * contributed ruler columns. |
| * Subclasses may re-implement this method using the {@link ColumnSupport}, |
| * e.g. by returning <code>new ColumnSupport(this, RulerColumnRegistry.getDefault());</code>. |
| * <p> |
| * <strong>Note:</strong> If you override this method to provide column support you will |
| * also need to override {@link #createVerticalRuler()} to return a {@link CompositeRuler}.</p> |
| * <p> |
| * Out of the box this class does not install this support and hence this |
| * implementation always returns <code>null</code>.</p> |
| * |
| * @return the column support or <code>null</code> if none |
| * @since 3.3 |
| */ |
| protected IColumnSupport createColumnSupport() { |
| return null; |
| } |
| |
| /** |
| * Creates the source viewer to be used by this editor. |
| * Subclasses may re-implement this method. |
| * |
| * @param parent the parent control |
| * @param ruler the vertical ruler |
| * @param styles style bits, <code>SWT.WRAP</code> is currently not supported |
| * @return the source viewer |
| */ |
| protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) { |
| return new SourceViewer(parent, ruler, styles); |
| } |
| |
| /** |
| * Initializes the drag and drop support for the given viewer based on |
| * provided editor adapter for drop target listeners. |
| * |
| * @param viewer the viewer |
| * @since 3.0 |
| */ |
| protected void initializeDragAndDrop(ISourceViewer viewer) { |
| IDragAndDropService dndService= getSite().getService(IDragAndDropService.class); |
| if (dndService == null) |
| return; |
| |
| ITextEditorDropTargetListener listener= getAdapter(ITextEditorDropTargetListener.class); |
| |
| if (listener == null) { |
| Object object= Platform.getAdapterManager().loadAdapter(this, "org.eclipse.ui.texteditor.ITextEditorDropTargetListener"); //$NON-NLS-1$ |
| if (object instanceof ITextEditorDropTargetListener) |
| listener= (ITextEditorDropTargetListener)object; |
| } |
| |
| if (listener != null) |
| dndService.addMergedDropTarget(viewer.getTextWidget(), DND.DROP_MOVE | DND.DROP_COPY, listener.getTransfers(), listener); |
| |
| IPreferenceStore store= getPreferenceStore(); |
| if (store != null && store.getBoolean(PREFERENCE_TEXT_DRAG_AND_DROP_ENABLED)) |
| installTextDragAndDrop(viewer); |
| |
| } |
| |
| /** |
| * The <code>AbstractTextEditor</code> implementation of this |
| * <code>IWorkbenchPart</code> method creates the vertical ruler and |
| * source viewer. |
| * <p> |
| * Subclasses may extend this method. Besides extending this method, the |
| * behavior of <code>createPartControl</code> may be customized by |
| * calling, extending or replacing the following methods: <br> |
| * Subclasses may supply customized implementations for some members using |
| * the following methods before <code>createPartControl</code> is invoked: |
| * <ul> |
| * <li> |
| * {@linkplain #setSourceViewerConfiguration(SourceViewerConfiguration) setSourceViewerConfiguration} |
| * to supply a custom source viewer configuration,</li> |
| * <li>{@linkplain #setRangeIndicator(Annotation) setRangeIndicator} to |
| * provide a range indicator,</li> |
| * <li>{@linkplain #setHelpContextId(String) setHelpContextId} to provide a |
| * help context id,</li> |
| * <li>{@linkplain #setEditorContextMenuId(String) setEditorContextMenuId} |
| * to set a custom context menu id,</li> |
| * <li>{@linkplain #setRulerContextMenuId(String) setRulerContextMenuId} to |
| * set a custom ruler context menu id.</li> |
| * </ul> |
| * <br> |
| * Subclasses may replace the following methods called from within |
| * <code>createPartControl</code>: |
| * <ul> |
| * <li>{@linkplain #createVerticalRuler() createVerticalRuler} to supply a |
| * custom vertical ruler,</li> |
| * <li>{@linkplain #createSourceViewer(Composite, IVerticalRuler, int) createSourceViewer} |
| * to supply a custom source viewer,</li> |
| * <li>{@linkplain #getSelectionProvider() getSelectionProvider} to supply |
| * a custom selection provider.</li> |
| * </ul> |
| * <br> |
| * Subclasses may extend the following methods called from within |
| * <code>createPartControl</code>: |
| * <ul> |
| * <li> |
| * {@linkplain #initializeViewerColors(ISourceViewer) initializeViewerColors} |
| * to customize the viewer color scheme (may also be replaced),</li> |
| * <li> |
| * {@linkplain #initializeDragAndDrop(ISourceViewer) initializeDragAndDrop} |
| * to customize drag and drop (may also be replaced),</li> |
| * <li>{@linkplain #createNavigationActions() createNavigationActions} to |
| * add navigation actions,</li> |
| * <li>{@linkplain #createActions() createActions} to add text editor |
| * actions.</li> |
| * </ul> |
| * </p> |
| * |
| * @param parent the parent composite |
| */ |
| @Override |
| public void createPartControl(Composite parent) { |
| |
| fVerticalRuler= createVerticalRuler(); |
| |
| int styles= SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION; |
| fSourceViewer= createSourceViewer(parent, fVerticalRuler, styles); |
| |
| if (fConfiguration == null) |
| fConfiguration= new SourceViewerConfiguration(); |
| fSourceViewer.configure(fConfiguration); |
| |
| if (fSourceViewer instanceof ISourceViewerExtension4) |
| fKeyBindingSupportForContentAssistant= new KeyBindingSupportForAssistant(((ISourceViewerExtension4)fSourceViewer)); |
| |
| if (fSourceViewer instanceof ISourceViewerExtension3) { |
| IQuickAssistAssistant assistant= ((ISourceViewerExtension3)fSourceViewer).getQuickAssistAssistant(); |
| if (assistant != null) |
| fKeyBindingSupportForQuickAssistant= new KeyBindingSupportForAssistant(assistant); |
| } |
| |
| if (fRangeIndicator != null) |
| fSourceViewer.setRangeIndicator(fRangeIndicator); |
| |
| fSourceViewer.addTextListener(fTextListener); |
| fSourceViewer.addTextInputListener(fTextListener); |
| getSelectionProvider().addSelectionChangedListener(getSelectionChangedListener()); |
| |
| initializeViewerFont(fSourceViewer); |
| initializeViewerColors(fSourceViewer); |
| initializeFindScopeColor(fSourceViewer); |
| initializeDragAndDrop(fSourceViewer); |
| |
| StyledText styledText= fSourceViewer.getTextWidget(); |
| styledText.addMouseListener(getCursorListener()); |
| styledText.addKeyListener(getCursorListener()); |
| |
| // Disable orientation switching until we fully support it. |
| styledText.addListener(SWT.OrientationChange, new Listener() { |
| @Override |
| public void handleEvent(Event event) { |
| event.doit= false; |
| } |
| }); |
| |
| if (getHelpContextId() != null) |
| PlatformUI.getWorkbench().getHelpSystem().setHelp(styledText, getHelpContextId()); |
| |
| |
| String id= fEditorContextMenuId != null ? fEditorContextMenuId : DEFAULT_EDITOR_CONTEXT_MENU_ID; |
| |
| MenuManager manager= new MenuManager(id, id); |
| manager.setRemoveAllWhenShown(true); |
| manager.addMenuListener(getContextMenuListener()); |
| fTextContextMenu= manager.createContextMenu(styledText); |
| |
| styledText.setMenu(fTextContextMenu); |
| |
| if (fEditorContextMenuId != null) |
| getEditorSite().registerContextMenu(fEditorContextMenuId, manager, getSelectionProvider(), isEditorInputIncludedInContextMenu()); |
| else if (fCompatibilityMode) |
| getEditorSite().registerContextMenu(DEFAULT_EDITOR_CONTEXT_MENU_ID, manager, getSelectionProvider(), isEditorInputIncludedInContextMenu()); |
| |
| if ((fEditorContextMenuId != null && fCompatibilityMode) || fEditorContextMenuId == null) { |
| String partId= getEditorSite().getId(); |
| if (partId != null) |
| getEditorSite().registerContextMenu(partId + ".EditorContext", manager, getSelectionProvider(), isEditorInputIncludedInContextMenu()); //$NON-NLS-1$ |
| } |
| |
| getEditorSite().registerContextMenu(COMMON_EDITOR_CONTEXT_MENU_ID, manager, getSelectionProvider(), false); |
| |
| if (fEditorContextMenuId == null) |
| fEditorContextMenuId= DEFAULT_EDITOR_CONTEXT_MENU_ID; |
| |
| |
| id= fRulerContextMenuId != null ? fRulerContextMenuId : DEFAULT_RULER_CONTEXT_MENU_ID; |
| manager= new MenuManager(id, id); |
| manager.setRemoveAllWhenShown(true); |
| manager.addMenuListener(getContextMenuListener()); |
| |
| Control rulerControl= fVerticalRuler.getControl(); |
| fRulerContextMenu= manager.createContextMenu(rulerControl); |
| rulerControl.setMenu(fRulerContextMenu); |
| rulerControl.addMouseListener(getRulerMouseListener()); |
| |
| if (fRulerContextMenuId != null) |
| getEditorSite().registerContextMenu(fRulerContextMenuId, manager, getSelectionProvider(), false); |
| else if (fCompatibilityMode) |
| getEditorSite().registerContextMenu(DEFAULT_RULER_CONTEXT_MENU_ID, manager, getSelectionProvider(), false); |
| |
| if ((fRulerContextMenuId != null && fCompatibilityMode) || fRulerContextMenuId == null) { |
| String partId= getSite().getId(); |
| if (partId != null) |
| getEditorSite().registerContextMenu(partId + ".RulerContext", manager, getSelectionProvider(), false); //$NON-NLS-1$ |
| } |
| |
| getEditorSite().registerContextMenu(COMMON_RULER_CONTEXT_MENU_ID, manager, getSelectionProvider(), false); |
| |
| if (fRulerContextMenuId == null) |
| fRulerContextMenuId= DEFAULT_RULER_CONTEXT_MENU_ID; |
| |
| initializeZoomGestures(rulerControl, fSourceViewer); |
| |
| getSite().setSelectionProvider(getSelectionProvider()); |
| |
| fSelectionListener= new SelectionListener(); |
| fSelectionListener.install(getSelectionProvider()); |
| fSelectionListener.setDocument(getDocumentProvider().getDocument(getEditorInput())); |
| |
| initializeActivationCodeTrigger(); |
| |
| createNavigationActions(); |
| createAccessibilityActions(); |
| createActions(); |
| |
| initializeSourceViewer(getEditorInput()); |
| |
| /* since 3.2 - undo redo actions should be created after |
| * the source viewer is initialized, so that the undo manager |
| * can obtain its undo context from its document. |
| */ |
| createUndoRedoActions(); |
| |
| JFaceResources.getFontRegistry().addListener(fFontPropertyChangeListener); |
| |
| IVerticalRuler ruler= getVerticalRuler(); |
| if (ruler instanceof CompositeRuler) |
| updateContributedRulerColumns((CompositeRuler) ruler); |
| |
| if (isWordWrapSupported()) { |
| setWordWrap(getInitialWordWrapStatus()); |
| } |
| } |
| |
| /** |
| * Installs text drag and drop on the given source viewer. |
| * |
| * @param viewer the viewer |
| * @since 3.3 |
| */ |
| protected void installTextDragAndDrop(final ISourceViewer viewer) { |
| if (viewer == null || fIsTextDragAndDropInstalled) |
| return; |
| |
| final IDragAndDropService dndService= getSite().getService(IDragAndDropService.class); |
| if (dndService == null) |
| return; |
| |
| final StyledText st= viewer.getTextWidget(); |
| |
| // Install drag source |
| final ISelectionProvider selectionProvider= viewer.getSelectionProvider(); |
| final DragSource source= new DragSource(st, DND.DROP_COPY | DND.DROP_MOVE); |
| source.setTransfer(new Transfer[] {TextTransfer.getInstance()}); |
| source.addDragListener(new DragSourceAdapter() { |
| String fSelectedText; |
| Point fSelection; |
| @Override |
| public void dragStart(DragSourceEvent event) { |
| fTextDragAndDropToken= null; |
| try { |
| fSelection= st.getSelection(); |
| event.doit= isLocationSelected(new Point(event.x, event.y)); |
| |
| ISelection selection= selectionProvider.getSelection(); |
| if (selection instanceof ITextSelection) |
| fSelectedText= ((ITextSelection)selection).getText(); |
| else // fallback to widget |
| fSelectedText= st.getSelectionText(); |
| } catch (IllegalArgumentException ex) { |
| event.doit= false; |
| } |
| } |
| |
| private boolean isLocationSelected(Point point) { |
| // FIXME: https://bugs.eclipse.org/bugs/show_bug.cgi?id=260922 |
| if (isBlockSelectionModeEnabled()) |
| return false; |
| |
| int offset = st.getOffsetAtPoint(point); |
| Point p= st.getLocationAtOffset(offset); |
| if (p.x > point.x) |
| offset--; |
| return offset >= fSelection.x && offset < fSelection.y; |
| } |
| |
| @Override |
| public void dragSetData(DragSourceEvent event) { |
| event.data= fSelectedText; |
| fTextDragAndDropToken= this; // Can be any non-null object |
| } |
| |
| @Override |
| public void dragFinished(DragSourceEvent event) { |
| try { |
| if (event.detail == DND.DROP_MOVE && validateEditorInputState()) { |
| Point newSelection= st.getSelection(); |
| int length= fSelection.y - fSelection.x; |
| int delta= 0; |
| if (newSelection.x < fSelection.x) |
| delta= length; |
| st.replaceTextRange(fSelection.x + delta, length, ""); //$NON-NLS-1$ |
| |
| if (fTextDragAndDropToken == null) { |
| // Move in same editor - end compound change |
| IRewriteTarget target= getAdapter(IRewriteTarget.class); |
| if (target != null) |
| target.endCompoundChange(); |
| } |
| |
| } |
| } finally { |
| fTextDragAndDropToken= null; |
| } |
| } |
| }); |
| |
| // Install drag target |
| DropTargetListener dropTargetListener= new DropTargetAdapter() { |
| |
| private Point fSelection; |
| |
| @Override |
| public void dragEnter(DropTargetEvent event) { |
| fTextDragAndDropToken= null; |
| fSelection= st.getSelection(); |
| if (event.detail == DND.DROP_DEFAULT) { |
| if ((event.operations & DND.DROP_MOVE) != 0) { |
| event.detail= DND.DROP_MOVE; |
| } else if ((event.operations & DND.DROP_COPY) != 0) { |
| event.detail= DND.DROP_COPY; |
| } else { |
| event.detail= DND.DROP_NONE; |
| } |
| } |
| } |
| |
| @Override |
| public void dragOperationChanged(DropTargetEvent event) { |
| if (event.detail == DND.DROP_DEFAULT) { |
| if ((event.operations & DND.DROP_MOVE) != 0) { |
| event.detail= DND.DROP_MOVE; |
| } else if ((event.operations & DND.DROP_COPY) != 0) { |
| event.detail= DND.DROP_COPY; |
| } else { |
| event.detail= DND.DROP_NONE; |
| } |
| } |
| } |
| |
| @Override |
| public void dragOver(DropTargetEvent event) { |
| event.feedback |= DND.FEEDBACK_SCROLL; |
| } |
| |
| @Override |
| public void drop(DropTargetEvent event) { |
| try { |
| if (fTextDragAndDropToken != null && event.detail == DND.DROP_MOVE) { |
| // Move in same editor |
| int caretOffset= st.getCaretOffset(); |
| if (fSelection.x <= caretOffset && caretOffset <= fSelection.y) { |
| event.detail= DND.DROP_NONE; |
| return; |
| } |
| |
| // Start compound change |
| IRewriteTarget target= getAdapter(IRewriteTarget.class); |
| if (target != null) |
| target.beginCompoundChange(); |
| } |
| |
| if (!validateEditorInputState()) { |
| event.detail= DND.DROP_NONE; |
| return; |
| } |
| |
| String text= (String)event.data; |
| if (isBlockSelectionModeEnabled()) { |
| // FIXME fix block selection and DND |
| // if (fTextDNDColumnSelection != null && fTextDragAndDropToken != null && event.detail == DND.DROP_MOVE) { |
| // // DND_MOVE within same editor - remove origin before inserting |
| // Rectangle newSelection= st.getColumnSelection(); |
| // st.replaceColumnSelection(fTextDNDColumnSelection, ""); //$NON-NLS-1$ |
| // st.replaceColumnSelection(newSelection, text); |
| // st.setColumnSelection(newSelection.x, newSelection.y, newSelection.x + fTextDNDColumnSelection.width - fTextDNDColumnSelection.x, newSelection.y + fTextDNDColumnSelection.height - fTextDNDColumnSelection.y); |
| // } else { |
| // Point newSelection= st.getSelection(); |
| // st.insert(text); |
| // IDocument document= getDocumentProvider().getDocument(getEditorInput()); |
| // int startLine= st.getLineAtOffset(newSelection.x); |
| // int startColumn= newSelection.x - st.getOffsetAtLine(startLine); |
| // int endLine= startLine + document.computeNumberOfLines(text); |
| // int endColumn= startColumn + TextUtilities.indexOf(document.getLegalLineDelimiters(), text, 0)[0]; |
| // st.setColumnSelection(startColumn, startLine, endColumn, endLine); |
| // } |
| } else { |
| Point newSelection= st.getSelection(); |
| try { |
| int modelOffset= widgetOffset2ModelOffset(viewer, newSelection.x); |
| viewer.getDocument().replace(modelOffset, 0, text); |
| } catch (BadLocationException e) { |
| return; |
| } |
| st.setSelectionRange(newSelection.x, text.length()); |
| } |
| } finally { |
| fTextDragAndDropToken= null; |
| } |
| } |
| }; |
| dndService.addMergedDropTarget(st, DND.DROP_MOVE | DND.DROP_COPY, new Transfer[] {TextTransfer.getInstance()}, dropTargetListener); |
| |
| fIsTextDragAndDropInstalled= true; |
| } |
| |
| /** |
| * Uninstalls text drag and drop from the given source viewer. |
| * |
| * @param viewer the viewer |
| * @since 3.3 |
| */ |
| protected void uninstallTextDragAndDrop(ISourceViewer viewer) { |
| if (viewer == null || !fIsTextDragAndDropInstalled) |
| return; |
| |
| final IDragAndDropService dndService= getSite().getService(IDragAndDropService.class); |
| if (dndService == null) |
| return; |
| |
| StyledText st= viewer.getTextWidget(); |
| dndService.removeMergedDropTarget(st); |
| |
| DragSource dragSource= (DragSource)st.getData(DND.DRAG_SOURCE_KEY); |
| if (dragSource != null) { |
| dragSource.dispose(); |
| st.setData(DND.DRAG_SOURCE_KEY, null); |
| } |
| |
| fIsTextDragAndDropInstalled= false; |
| } |
| |
| /** |
| * Tells whether the editor input should be included when adding object |
| * contributions to this editor's context menu. |
| * <p> |
| * This implementation always returns <code>true</code>. |
| * </p> |
| * |
| * @return <code>true</code> if the editor input should be considered |
| * @since 3.2 |
| */ |
| protected boolean isEditorInputIncludedInContextMenu() { |
| return true; |
| } |
| |
| /** |
| * Initializes the activation code trigger. |
| * |
| * @since 2.1 |
| */ |
| private void initializeActivationCodeTrigger() { |
| fActivationCodeTrigger.install(); |
| fActivationCodeTrigger.setScopes(fKeyBindingScopes); |
| } |
| |
| /** |
| * Initializes the given viewer's font. |
| * |
| * @param viewer the viewer |
| * @since 2.0 |
| */ |
| private void initializeViewerFont(ISourceViewer viewer) { |
| |
| boolean isSharedFont= true; |
| Font font= null; |
| String symbolicFontName= getSymbolicFontName(); |
| |
| if (symbolicFontName != null) |
| font= JFaceResources.getFont(symbolicFontName); |
| else if (fPreferenceStore != null) { |
| // Backward compatibility |
| if (fPreferenceStore.contains(JFaceResources.TEXT_FONT) && !fPreferenceStore.isDefault(JFaceResources.TEXT_FONT)) { |
| FontData data= PreferenceConverter.getFontData(fPreferenceStore, JFaceResources.TEXT_FONT); |
| |
| if (data != null) { |
| isSharedFont= false; |
| font= new Font(viewer.getTextWidget().getDisplay(), data); |
| } |
| } |
| } |
| if (font == null) |
| font= JFaceResources.getTextFont(); |
| |
| if (!font.equals(fSourceViewer.getTextWidget().getFont())) { |
| setFont(viewer, font); |
| |
| disposeFont(); |
| if (!isSharedFont) |
| fFont= font; |
| } else if (!isSharedFont) { |
| font.dispose(); |
| } |
| } |
| |
| /** |
| * Disposes of the non-shared font. |
| * |
| * @since 3.5 |
| */ |
| private void disposeFont() { |
| if (fFont != null) { |
| fFont.dispose(); |
| fFont= null; |
| } |
| } |
| |
| /** |
| * Sets the font for the given viewer sustaining selection and scroll position. |
| * |
| * @param sourceViewer the source viewer |
| * @param font the font |
| * @since 2.0 |
| */ |
| private void setFont(ISourceViewer sourceViewer, Font font) { |
| if (sourceViewer.getDocument() != null) { |
| |
| ISelectionProvider provider= sourceViewer.getSelectionProvider(); |
| ISelection selection= provider.getSelection(); |
| int topIndex= sourceViewer.getTopIndex(); |
| |
| StyledText styledText= sourceViewer.getTextWidget(); |
| Control parent= styledText; |
| if (sourceViewer instanceof ITextViewerExtension) { |
| ITextViewerExtension extension= (ITextViewerExtension) sourceViewer; |
| parent= extension.getControl(); |
| } |
| |
| parent.setRedraw(false); |
| |
| styledText.setFont(font); |
| |
| if (fVerticalRuler instanceof IVerticalRulerExtension) { |
| IVerticalRulerExtension e= (IVerticalRulerExtension) fVerticalRuler; |
| e.setFont(font); |
| } |
| |
| provider.setSelection(selection); |
| sourceViewer.setTopIndex(topIndex); |
| |
| if (parent instanceof Composite) { |
| Composite composite= (Composite) parent; |
| composite.layout(true); |
| } |
| |
| parent.setRedraw(true); |
| |
| |
| } else { |
| |
| StyledText styledText= sourceViewer.getTextWidget(); |
| styledText.setFont(font); |
| |
| if (fVerticalRuler instanceof IVerticalRulerExtension) { |
| IVerticalRulerExtension e= (IVerticalRulerExtension) fVerticalRuler; |
| e.setFont(font); |
| } |
| } |
| } |
| |
| private void initializeZoomGestures(Control rulerControl, final ISourceViewer sourceViewer) { |
| final StyledText styledText= sourceViewer.getTextWidget(); |
| GestureListener gestureListener= new GestureListener() { |
| private Font fMagnificationStartFont; |
| private int fLastHeight= -1; |
| |
| @Override |
| public void gesture(GestureEvent e) { |
| if (e.detail == SWT.GESTURE_BEGIN) { |
| fMagnificationStartFont= styledText.getFont(); |
| } else if (e.detail == SWT.GESTURE_END) { |
| fMagnificationStartFont= null; |
| updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_POSITION); |
| } else if (e.detail == SWT.GESTURE_ROTATE) { |
| if (Math.abs(e.rotation) > 45) { |
| fMagnificationStartFont= null; // don't observe magnify events after reset |
| initializeViewerFont(fSourceViewer); |
| updateCaret(); |
| IStatusField statusField= getStatusField(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_POSITION); |
| if (statusField != null) { |
| int newHeight= styledText.getFont().getFontData()[0].getHeight(); |
| statusField.setText(NLSUtility.format(EditorMessages.Editor_font_reset_message, Integer.valueOf(newHeight))); |
| } |
| } |
| } else if (e.detail == SWT.GESTURE_MAGNIFY && fMagnificationStartFont != null) { |
| FontData fontData= fMagnificationStartFont.getFontData()[0]; |
| int startHeight= fontData.getHeight(); |
| int newHeight= Math.max(1, (int) (startHeight * e.magnification)); |
| if (newHeight != fLastHeight) { |
| fLastHeight= newHeight; |
| fontData.setHeight(newHeight); |
| Font newFont= new Font(fMagnificationStartFont.getDevice(), fontData); |
| setFont(sourceViewer, newFont); |
| disposeFont(); |
| updateCaret(); |
| IStatusField statusField= getStatusField(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_POSITION); |
| if (statusField != null) { |
| statusField.setText(NLSUtility.format(EditorMessages.Editor_font_zoom_message, new Object[] { Integer.valueOf(startHeight), Integer.valueOf(newHeight) })); |
| } |
| } |
| } |
| } |
| }; |
| styledText.addGestureListener(gestureListener); |
| rulerControl.addGestureListener(gestureListener); |
| } |
| |
| /** |
| * Creates a color from the information stored in the given preference store. |
| * Returns <code>null</code> if there is no such information available. |
| * |
| * @param store the store to read from |
| * @param key the key used for the lookup in the preference store |
| * @param display the display used create the color |
| * @return the created color according to the specification in the preference store |
| * @since 2.0 |
| */ |
| private Color createColor(IPreferenceStore store, String key, Display display) { |
| |
| RGB rgb= null; |
| |
| if (store.contains(key)) { |
| |
| if (store.isDefault(key)) |
| rgb= PreferenceConverter.getDefaultColor(store, key); |
| else |
| rgb= PreferenceConverter.getColor(store, key); |
| |
| if (rgb != null) |
| return new Color(display, rgb); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Initializes the fore- and background colors of the given viewer for both |
| * normal and selected text. |
| * |
| * @param viewer the viewer to be initialized |
| * @since 2.0 |
| */ |
| protected void initializeViewerColors(ISourceViewer viewer) { |
| |
| IPreferenceStore store= getPreferenceStore(); |
| if (store != null) { |
| |
| StyledText styledText= viewer.getTextWidget(); |
| |
| // ----------- foreground color -------------------- |
| Color color= store.getBoolean(PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT) |
| ? null |
| : createColor(store, PREFERENCE_COLOR_FOREGROUND, styledText.getDisplay()); |
| styledText.setForeground(color); |
| |
| if (fForegroundColor != null) |
| fForegroundColor.dispose(); |
| |
| fForegroundColor= color; |
| |
| // ---------- background color ---------------------- |
| color= store.getBoolean(PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT) |
| ? null |
| : createColor(store, PREFERENCE_COLOR_BACKGROUND, styledText.getDisplay()); |
| styledText.setBackground(color); |
| |
| if (fBackgroundColor != null) |
| fBackgroundColor.dispose(); |
| |
| fBackgroundColor= color; |
| |
| // ----------- selection foreground color -------------------- |
| color= store.getBoolean(PREFERENCE_COLOR_SELECTION_FOREGROUND_SYSTEM_DEFAULT) |
| ? null |
| : createColor(store, PREFERENCE_COLOR_SELECTION_FOREGROUND, styledText.getDisplay()); |
| styledText.setSelectionForeground(color); |
| |
| if (fSelectionForegroundColor != null) |
| fSelectionForegroundColor.dispose(); |
| |
| fSelectionForegroundColor= color; |
| |
| // ---------- selection background color ---------------------- |
| color= store.getBoolean(PREFERENCE_COLOR_SELECTION_BACKGROUND_SYSTEM_DEFAULT) |
| ? null |
| : createColor(store, PREFERENCE_COLOR_SELECTION_BACKGROUND, styledText.getDisplay()); |
| styledText.setSelectionBackground(color); |
| |
| if (fSelectionBackgroundColor != null) |
| fSelectionBackgroundColor.dispose(); |
| |
| fSelectionBackgroundColor= color; |
| } |
| } |
| |
| /** |
| * Initializes the background color used for highlighting the document ranges |
| * defining search scopes. |
| * |
| * @param viewer the viewer to initialize |
| * @since 2.0 |
| */ |
| private void initializeFindScopeColor(ISourceViewer viewer) { |
| |
| IPreferenceStore store= getPreferenceStore(); |
| if (store != null) { |
| |
| StyledText styledText= viewer.getTextWidget(); |
| |
| Color color= createColor(store, PREFERENCE_COLOR_FIND_SCOPE, styledText.getDisplay()); |
| |
| IFindReplaceTarget target= viewer.getFindReplaceTarget(); |
| if (target != null && target instanceof IFindReplaceTargetExtension) |
| ((IFindReplaceTargetExtension) target).setScopeHighlightColor(color); |
| |
| if (fFindScopeHighlightColor != null) |
| fFindScopeHighlightColor.dispose(); |
| |
| fFindScopeHighlightColor= color; |
| } |
| } |
| |
| |
| /** |
| * Initializes the editor's source viewer based on the given editor input. |
| * |
| * @param input the editor input to be used to initialize the source viewer |
| */ |
| private void initializeSourceViewer(IEditorInput input) { |
| |
| IDocumentProvider documentProvider= getDocumentProvider(); |
| IAnnotationModel model= documentProvider.getAnnotationModel(input); |
| IDocument document= documentProvider.getDocument(input); |
| |
| if (document != null) { |
| fSourceViewer.setDocument(document, model); |
| fSourceViewer.setEditable(isEditable()); |
| fSourceViewer.showAnnotations(model != null); |
| } |
| |
| if (fElementStateListener instanceof IElementStateListenerExtension) { |
| boolean isStateValidated= false; |
| if (documentProvider instanceof IDocumentProviderExtension) |
| isStateValidated= ((IDocumentProviderExtension)documentProvider).isStateValidated(input); |
| |
| IElementStateListenerExtension extension= (IElementStateListenerExtension) fElementStateListener; |
| extension.elementStateValidationChanged(input, isStateValidated); |
| } |
| |
| if (fInitialCaret == null) |
| fInitialCaret= fSourceViewer.getTextWidget().getCaret(); |
| |
| if (fIsOverwriting) |
| fSourceViewer.getTextWidget().invokeAction(ST.TOGGLE_OVERWRITE); |
| handleInsertModeChanged(); |
| |
| if (isTabsToSpacesConversionEnabled()) |
| installTabsToSpacesConverter(); |
| |
| if (fSourceViewer instanceof ITextViewerExtension8) { |
| IPreferenceStore store= getPreferenceStore(); |
| EnrichMode mode= store != null ? convertEnrichModePreference(store.getInt(PREFERENCE_HOVER_ENRICH_MODE)) : EnrichMode.AFTER_DELAY; |
| ((ITextViewerExtension8)fSourceViewer).setHoverEnrichMode(mode); |
| } |
| |
| if (fSourceViewer instanceof ISourceViewerExtension5) |
| installCodeMinigProviders(); |
| } |
| |
| /** |
| * Install codemining providers. |
| * @since 3.10 |
| */ |
| private void installCodeMinigProviders() { |
| ICodeMiningProvider[] providers = TextEditorPlugin.getDefault().getCodeMiningProviderRegistry() |
| .getProviders(this.getSourceViewer(), this); |
| ((ISourceViewerExtension5) fSourceViewer).setCodeMiningProviders(providers); |
| } |
| |
| /** |
| * Converts the {link #PREFERENCE_HOVER_ENRICH_MODE} preference value to |
| * {@link org.eclipse.jface.text.ITextViewerExtension8.EnrichMode}. |
| * |
| * @param mode the preference value |
| * @return the enrich mode, can be <code>null</code> |
| * @since 3.4 |
| */ |
| private EnrichMode convertEnrichModePreference(int mode) { |
| switch (mode) { |
| case -1: |
| return null; |
| case 0: |
| return EnrichMode.AFTER_DELAY; |
| case 1: |
| return EnrichMode.IMMEDIATELY; |
| case 2: |
| return EnrichMode.ON_CLICK; |
| default: |
| Assert.isLegal(false); |
| return null; |
| } |
| } |
| |
| /** |
| * Initializes the editor's title based on the given editor input. |
| * <p> |
| * <strong>Note:</strong> We use the editor's image instead of the image from the |
| * editor input to distinguish situations where the same editor input is |
| * opened in different kinds of editors. |
| * </p> |
| * |
| * @param input the editor input to be used |
| */ |
| private void initializeTitle(IEditorInput input) { |
| |
| Image oldImage= fTitleImage; |
| fTitleImage= null; |
| String title= ""; //$NON-NLS-1$ |
| |
| if (input != null) { |
| IEditorRegistry editorRegistry= PlatformUI.getWorkbench().getEditorRegistry(); |
| IEditorDescriptor editorDesc= editorRegistry.findEditor(getSite().getId()); |
| ImageDescriptor imageDesc= editorDesc != null ? editorDesc.getImageDescriptor() : null; |
| |
| fTitleImage= imageDesc != null ? imageDesc.createImage() : null; |
| title= input.getName(); |
| } |
| |
| setTitleImage(fTitleImage); |
| setPartName(title); |
| |
| firePropertyChange(PROP_DIRTY); |
| |
| if (oldImage != null && !oldImage.isDisposed()) |
| oldImage.dispose(); |
| } |
| |
| /** |
| * Hook method for setting the document provider for the given input. |
| * This default implementation does nothing. Clients may |
| * reimplement. |
| * |
| * @param input the input of this editor. |
| * @since 3.0 |
| */ |
| protected void setDocumentProvider(IEditorInput input) { |
| } |
| |
| /** |
| * If there is no explicit document provider set, the implicit one is |
| * re-initialized based on the given editor input. |
| * |
| * @param input the editor input. |
| */ |
| private void updateDocumentProvider(IEditorInput input) { |
| |
| IProgressMonitor rememberedProgressMonitor= null; |
| |
| IDocumentProvider provider= getDocumentProvider(); |
| if (provider != null) { |
| provider.removeElementStateListener(fElementStateListener); |
| if (provider instanceof IDocumentProviderExtension2) { |
| IDocumentProviderExtension2 extension= (IDocumentProviderExtension2) provider; |
| rememberedProgressMonitor= extension.getProgressMonitor(); |
| extension.setProgressMonitor(null); |
| } |
| } |
| |
| setDocumentProvider(input); |
| |
| provider= getDocumentProvider(); |
| if (provider != null) { |
| provider.addElementStateListener(fElementStateListener); |
| if (provider instanceof IDocumentProviderExtension2) { |
| IDocumentProviderExtension2 extension= (IDocumentProviderExtension2) provider; |
| extension.setProgressMonitor(rememberedProgressMonitor); |
| } |
| } |
| } |
| |
| /** |
| * Called directly from <code>setInput</code> and from within a workspace |
| * runnable from <code>init</code>, this method does the actual setting |
| * of the editor input. Closes the editor if <code>input</code> is |
| * <code>null</code>. Disconnects from any previous editor input and its |
| * document provider and connects to the new one. |
| * <p> |
| * Subclasses may extend. |
| * </p> |
| * |
| * @param input the input to be set |
| * @exception CoreException if input cannot be connected to the document |
| * provider |
| */ |
| protected void doSetInput(IEditorInput input) throws CoreException { |
| ISaveablesLifecycleListener listener= getSite().getService(ISaveablesLifecycleListener.class); |
| if (listener == null) |
| fSavable= null; |
| |
| if (input == null) { |
| close(isSaveOnCloseNeeded()); |
| |
| if (fSavable != null) { |
| listener.handleLifecycleEvent(new SaveablesLifecycleEvent(this, SaveablesLifecycleEvent.POST_CLOSE, getSaveables(), false)); |
| fSavable.disconnectEditor(); |
| fSavable= null; |
| } |
| |
| } else { |
| boolean mustSendLifeCycleEvent= false; |
| if (fSavable != null) { |
| listener.handleLifecycleEvent(new SaveablesLifecycleEvent(this, SaveablesLifecycleEvent.POST_CLOSE, getSaveables(), false)); |
| fSavable.disconnectEditor(); |
| fSavable= null; |
| mustSendLifeCycleEvent= true; |
| } |
| |
| IEditorInput oldInput= getEditorInput(); |
| if (oldInput != null) |
| getDocumentProvider().disconnect(oldInput); |
| |
| super.setInput(input); |
| |
| updateDocumentProvider(input); |
| |
| IDocumentProvider provider= getDocumentProvider(); |
| if (provider == null) { |
| IStatus s= new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.OK, EditorMessages.Editor_error_no_provider, null); |
| throw new CoreException(s); |
| } |
| |
| provider.connect(input); |
| |
| initializeTitle(input); |
| |
| if (fSourceViewer != null) { |
| initializeSourceViewer(input); |
| |
| // Reset the undo context for the undo and redo action handlers |
| IAction undoAction= getAction(ITextEditorActionConstants.UNDO); |
| IAction redoAction= getAction(ITextEditorActionConstants.REDO); |
| boolean areOperationActionHandlersInstalled= undoAction instanceof OperationHistoryActionHandler && redoAction instanceof OperationHistoryActionHandler; |
| IUndoContext undoContext= getUndoContext(); |
| if (undoContext != null && areOperationActionHandlersInstalled) { |
| ((OperationHistoryActionHandler)undoAction).setContext(undoContext); |
| ((OperationHistoryActionHandler)redoAction).setContext(undoContext); |
| } else { |
| createUndoRedoActions(); |
| } |
| } |
| |
| if (fIsOverwriting) |
| toggleOverwriteMode(); |
| setInsertMode(getLegalInsertModes().get(0)); |
| updateCaret(); |
| |
| updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE); |
| |
| if (fSelectionListener != null) |
| fSelectionListener.setDocument(getDocumentProvider().getDocument(input)); |
| |
| IVerticalRuler ruler= getVerticalRuler(); |
| if (ruler instanceof CompositeRuler) |
| updateContributedRulerColumns((CompositeRuler) ruler); |
| |
| // Send savable life-cycle if needed. |
| if (mustSendLifeCycleEvent && listener != null) |
| listener.handleLifecycleEvent(new SaveablesLifecycleEvent(this, SaveablesLifecycleEvent.POST_OPEN, getSaveables(), false)); |
| |
| } |
| |
| } |
| |
| /** |
| * Returns this editor's viewer's undo manager undo context. |
| * |
| * @return the undo context or <code>null</code> if not available |
| * @since 3.1 |
| */ |
| private IUndoContext getUndoContext() { |
| if (fSourceViewer instanceof ITextViewerExtension6) { |
| IUndoManager undoManager= ((ITextViewerExtension6)fSourceViewer).getUndoManager(); |
| if (undoManager instanceof IUndoManagerExtension) |
| return ((IUndoManagerExtension)undoManager).getUndoContext(); |
| } |
| return null; |
| } |
| |
| @Override |
| protected final void setInputWithNotify(IEditorInput input) { |
| try { |
| |
| doSetInput(input); |
| |
| /* |
| * The following bugs explain why we fire this property change: |
| * https://bugs.eclipse.org/bugs/show_bug.cgi?id=90283 |
| * https://bugs.eclipse.org/bugs/show_bug.cgi?id=92049 |
| * https://bugs.eclipse.org/bugs/show_bug.cgi?id=92286 |
| */ |
| firePropertyChange(IEditorPart.PROP_INPUT); |
| |
| } catch (CoreException x) { |
| String title= EditorMessages.Editor_error_setinput_title; |
| String msg= EditorMessages.Editor_error_setinput_message; |
| Shell shell= getSite().getShell(); |
| ErrorDialog.openError(shell, title, msg, x.getStatus()); |
| } |
| } |
| |
| @Override |
| public final void setInput(IEditorInput input) { |
| setInputWithNotify(input); |
| } |
| |
| /* |
| * @see ITextEditor#close |
| */ |
| @Override |
| public void close(final boolean save) { |
| |
| enableSanityChecking(false); |
| |
| Display display= getSite().getShell().getDisplay(); |
| display.asyncExec(new Runnable() { |
| @Override |
| public void run() { |
| if (fSourceViewer != null) |
| getSite().getPage().closeEditor(AbstractTextEditor.this, save); |
| } |
| }); |
| } |
| |
| /** |
| * The <code>AbstractTextEditor</code> implementation of this |
| * <code>IWorkbenchPart</code> method may be extended by subclasses. |
| * Subclasses must call <code>super.dispose()</code>. |
| * <p> |
| * Note that many methods may return <code>null</code> after the editor is |
| * disposed. |
| * </p> |
| */ |
| @Override |
| public void dispose() { |
| |
| if (fActivationListener != null) { |
| fActivationListener.dispose(); |
| fActivationListener= null; |
| } |
| |
| if (fTitleImage != null) { |
| fTitleImage.dispose(); |
| fTitleImage= null; |
| } |
| |
| disposeFont(); |
| |
| disposeNonDefaultCaret(); |
| fInitialCaret= null; |
| |
| if (fForegroundColor != null) { |
| fForegroundColor.dispose(); |
| fForegroundColor= null; |
| } |
| |
| if (fBackgroundColor != null) { |
| fBackgroundColor.dispose(); |
| fBackgroundColor= null; |
| } |
| |
| if (fSelectionForegroundColor != null) { |
| fSelectionForegroundColor.dispose(); |
| fSelectionForegroundColor= null; |
| } |
| |
| if (fSelectionBackgroundColor != null) { |
| fSelectionBackgroundColor.dispose(); |
| fSelectionBackgroundColor= null; |
| } |
| |
| if (fFindScopeHighlightColor != null) { |
| fFindScopeHighlightColor.dispose(); |
| fFindScopeHighlightColor= null; |
| } |
| |
| if (fFontPropertyChangeListener != null) { |
| JFaceResources.getFontRegistry().removeListener(fFontPropertyChangeListener); |
| if (fPreferenceStore != null) |
| fPreferenceStore.removePropertyChangeListener(fFontPropertyChangeListener); |
| fFontPropertyChangeListener= null; |
| } |
| |
| if (fPropertyChangeListener != null) { |
| if (fPreferenceStore != null) { |
| fPreferenceStore.removePropertyChangeListener(fPropertyChangeListener); |
| fPreferenceStore= null; |
| } |
| fPropertyChangeListener= null; |
| } |
| |
| if (fActivationCodeTrigger != null) { |
| fActivationCodeTrigger.uninstall(); |
| fActivationCodeTrigger= null; |
| } |
| |
| if (fSelectionListener != null) { |
| fSelectionListener.uninstall(getSelectionProvider()); |
| fSelectionListener= null; |
| } |
| |
| if (fSavable != null) { |
| fSavable.disconnectEditor(); |
| fSavable= null; |
| } |
| |
| disposeDocumentProvider(); |
| |
| if (fSourceViewer != null) { |
| |
| if (fTextListener != null) { |
| fSourceViewer.removeTextListener(fTextListener); |
| fSourceViewer.removeTextInputListener(fTextListener); |
| fTextListener= null; |
| } |
| |
| uninstallTabsToSpacesConverter(); |
| |
| fTextInputListener= null; |
| fSelectionProvider= null; |
| fSourceViewer= null; |
| } |
| |
| if (fTextContextMenu != null) { |
| fTextContextMenu.dispose(); |
| fTextContextMenu= null; |
| } |
| |
| if (fRulerContextMenu != null) { |
| fRulerContextMenu.dispose(); |
| fRulerContextMenu= null; |
| } |
| |
| if (fActions != null) { |
| registerUndoRedoAction(ITextEditorActionConstants.UNDO, null); |
| registerUndoRedoAction(ITextEditorActionConstants.REDO, null); |
| fActions.clear(); |
| fActions= null; |
| } |
| |
| if (fSelectionActions != null) { |
| fSelectionActions.clear(); |
| fSelectionActions= null; |
| } |
| |
| if (fContentActions != null) { |
| fContentActions.clear(); |
| fContentActions= null; |
| } |
| |
| if (fPropertyActions != null) { |
| fPropertyActions.clear(); |
| fPropertyActions= null; |
| } |
| |
| if (fStateActions != null) { |
| fStateActions.clear(); |
| fStateActions= null; |
| } |
| |
| if (fActivationCodes != null) { |
| fActivationCodes.clear(); |
| fActivationCodes= null; |
| } |
| |
| if (fEditorStatusLine != null) |
| fEditorStatusLine= null; |
| |
| if (fConfiguration != null) |
| fConfiguration= null; |
| |
| if (fColumnSupport != null) { |
| fColumnSupport.dispose(); |
| fColumnSupport= null; |
| } |
| |
| if (fVerticalRuler != null) |
| fVerticalRuler= null; |
| |
| IOperationHistory history= OperationHistoryFactory.getOperationHistory(); |
| if (history != null) { |
| if (fNonLocalOperationApprover != null) |
| history.removeOperationApprover(fNonLocalOperationApprover); |
| if (fLinearUndoViolationApprover != null) |
| history.removeOperationApprover(fLinearUndoViolationApprover); |
| } |
| fNonLocalOperationApprover= null; |
| fLinearUndoViolationApprover= null; |
| |
| if (fKeyBindingSupportForContentAssistant != null) { |
| fKeyBindingSupportForContentAssistant.dispose(); |
| fKeyBindingSupportForContentAssistant= null; |
| } |
| |
| if (fKeyBindingSupportForQuickAssistant != null) { |
| fKeyBindingSupportForQuickAssistant.dispose(); |
| fKeyBindingSupportForQuickAssistant= null; |
| } |
| |
| if (fInformationPresenter != null) { |
| fInformationPresenter.uninstall(); |
| fInformationPresenter= null; |
| } |
| |
| if (fSaveAction != null) { |
| fSaveAction.dispose(); |
| fSaveAction= null; |
| } |
| |
| super.dispose(); |
| } |
| |
| /** |
| * Disposes of the connection with the document provider. Subclasses |
| * may extend. |
| * |
| * @since 3.0 |
| */ |
| protected void disposeDocumentProvider() { |
| IDocumentProvider provider= getDocumentProvider(); |
| if (provider != null) { |
| |
| IEditorInput input= getEditorInput(); |
| if (input != null) |
| provider.disconnect(input); |
| |
| if (fElementStateListener != null) { |
| provider.removeElementStateListener(fElementStateListener); |
| fElementStateListener= null; |
| } |
| |
| } |
| fExplicitDocumentProvider= null; |
| } |
| |
| /** |
| * Determines whether the given preference change affects the editor's |
| * presentation. This implementation always returns <code>false</code>. |
| * May be reimplemented by subclasses. |
| * |
| * @param event the event which should be investigated |
| * @return <code>true</code> if the event describes a preference change affecting the editor's presentation |
| * @since 2.0 |
| */ |
| protected boolean affectsTextPresentation(PropertyChangeEvent event) { |
| return false; |
| } |
| |
| /** |
| * Returns the symbolic font name for this editor as defined in XML. |
| * |
| * @return a String with the symbolic font name or <code>null</code> if |
| * none is defined |
| * @since 2.1 |
| */ |
| /*package*/ String getSymbolicFontName() { |
| if (getConfigurationElement() != null) |
| return getConfigurationElement().getAttribute("symbolicFontName"); //$NON-NLS-1$ |
| return null; |
| } |
| |
| /** |
| * Returns the property preference key for the editor font. |
| * <p> |
| * If the editor is defined with a <code>symbolicFontName </code> then this name is returned and |
| * the font is looked up in the JFace resource registry. Otherwise, |
| * {@link JFaceResources#TEXT_FONT} is returned and the font is looked up in this editor's |
| * preference store. |
| * </p> |
| * |
| * @return a String with the key |
| * @since 2.1 |
| */ |
| protected final String getFontPropertyPreferenceKey() { |
| String symbolicFontName= getSymbolicFontName(); |
| if (symbolicFontName != null) |
| return symbolicFontName; |
| return JFaceResources.TEXT_FONT; |
| } |
| |
| /** |
| * Handles a property change event describing a change of the editor's |
| * preference store and updates the preference related editor properties. |
| * <p> |
| * Subclasses may extend. |
| * </p> |
| * |
| * @param event the property change event |
| */ |
| protected void handlePreferenceStoreChanged(PropertyChangeEvent event) { |
| |
| if (fSourceViewer == null) |
| return; |
| |
| String property= event.getProperty(); |
| |
| if (getFontPropertyPreferenceKey().equals(property)) |
| // There is a separate handler for font preference changes |
| return; |
| |
| if (PREFERENCE_COLOR_FOREGROUND.equals(property) || PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT.equals(property) || |
| PREFERENCE_COLOR_BACKGROUND.equals(property) || PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property) || |
| PREFERENCE_COLOR_SELECTION_FOREGROUND.equals(property) || PREFERENCE_COLOR_SELECTION_FOREGROUND_SYSTEM_DEFAULT.equals(property) || |
| PREFERENCE_COLOR_SELECTION_BACKGROUND.equals(property) || PREFERENCE_COLOR_SELECTION_BACKGROUND_SYSTEM_DEFAULT.equals(property)) |
| { |
| initializeViewerColors(fSourceViewer); |
| } else if (PREFERENCE_COLOR_FIND_SCOPE.equals(property)) { |
| initializeFindScopeColor(fSourceViewer); |
| } else if (PREFERENCE_USE_CUSTOM_CARETS.equals(property)) { |
| updateCaret(); |
| } else if (PREFERENCE_WIDE_CARET.equals(property)) { |
| updateCaret(); |
| } |
| |
| if (affectsTextPresentation(event)) |
| fSourceViewer.invalidateTextPresentation(); |
| |
| if (PREFERENCE_HYPERLINKS_ENABLED.equals(property)) { |
| if (fSourceViewer instanceof ITextViewerExtension6) { |
| IHyperlinkDetector[] detectors= getSourceViewerConfiguration().getHyperlinkDetectors(fSourceViewer); |
| int stateMask= getSourceViewerConfiguration().getHyperlinkStateMask(fSourceViewer); |
| ITextViewerExtension6 textViewer6= (ITextViewerExtension6)fSourceViewer; |
| textViewer6.setHyperlinkDetectors(detectors, stateMask); |
| } |
| return; |
| } |
| |
| if (PREFERENCE_HYPERLINK_KEY_MODIFIER.equals(property)) { |
| if (fSourceViewer instanceof ITextViewerExtension6) { |
| ITextViewerExtension6 textViewer6= (ITextViewerExtension6)fSourceViewer; |
| IHyperlinkDetector[] detectors= getSourceViewerConfiguration().getHyperlinkDetectors(fSourceViewer); |
| int stateMask= getSourceViewerConfiguration().getHyperlinkStateMask(fSourceViewer); |
| textViewer6.setHyperlinkDetectors(detectors, stateMask); |
| } |
| return; |
| } |
| |
| if (PREFERENCE_RULER_CONTRIBUTIONS.equals(property)) { |
| String[] difference= StringSetSerializer.getDifference((String) event.getOldValue(), (String) event.getNewValue()); |
| IColumnSupport support= getAdapter(IColumnSupport.class); |
| for (int i= 0; i < difference.length; i++) { |
| RulerColumnDescriptor desc= RulerColumnRegistry.getDefault().getColumnDescriptor(difference[i]); |
| if (desc != null && support.isColumnSupported(desc)) { |
| boolean newState= !support.isColumnVisible(desc); |
| support.setColumnVisible(desc, newState); |
| } |
| } |
| return; |
| } |
| |
| if (PREFERENCE_SHOW_WHITESPACE_CHARACTERS.equals(property) || |
| PREFERENCE_SHOW_LEADING_SPACES.equals(property) || |
| PREFERENCE_SHOW_ENCLOSED_SPACES.equals(property) || |
| PREFERENCE_SHOW_TRAILING_SPACES.equals(property) || |
| PREFERENCE_SHOW_LEADING_IDEOGRAPHIC_SPACES.equals(property) || |
| PREFERENCE_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES.equals(property) || |
| PREFERENCE_SHOW_TRAILING_IDEOGRAPHIC_SPACES.equals(property) || |
| PREFERENCE_SHOW_LEADING_TABS.equals(property) || |
| PREFERENCE_SHOW_ENCLOSED_TABS.equals(property) || |
| PREFERENCE_SHOW_TRAILING_TABS.equals(property) || |
| PREFERENCE_SHOW_CARRIAGE_RETURN.equals(property) || |
| PREFERENCE_SHOW_LINE_FEED.equals(property) || |
| PREFERENCE_WHITESPACE_CHARACTER_ALPHA_VALUE.equals(property)) { |
| IAction action= getAction(ITextEditorActionConstants.SHOW_WHITESPACE_CHARACTERS); |
| if (action instanceof IUpdate) |
| ((IUpdate)action).update(); |
| return; |
| } |
| |
| if (PREFERENCE_TEXT_DRAG_AND_DROP_ENABLED.equals(property)) { |
| IPreferenceStore store= getPreferenceStore(); |
| if (store != null && store.getBoolean(PREFERENCE_TEXT_DRAG_AND_DROP_ENABLED)) |
| installTextDragAndDrop(getSourceViewer()); |
| else |
| uninstallTextDragAndDrop(getSourceViewer()); |
| return; |
| } |
| |
| if (PREFERENCE_HOVER_ENRICH_MODE.equals(property)) { |
| if (fSourceViewer instanceof ITextViewerExtension8) { |
| IPreferenceStore store= getPreferenceStore(); |
| if (store != null) { |
| ((ITextViewerExtension8)fSourceViewer).setHoverEnrichMode(convertEnrichModePreference(store.getInt(PREFERENCE_HOVER_ENRICH_MODE))); |
| } |
| } |
| return; |
| } |
| |
| } |
| |
| /** |
| * Returns the progress monitor related to this editor. It should not be |
| * necessary to extend this method. |
| * |
| * @return the progress monitor related to this editor |
| * @since 2.1 |
| */ |
| protected IProgressMonitor getProgressMonitor() { |
| |
| IProgressMonitor pm= null; |
| |
| IStatusLineManager manager= getStatusLineManager(); |
| if (manager != null) |
| pm= manager.getProgressMonitor(); |
| |
| return pm != null ? pm : new NullProgressMonitor(); |
| } |
| |
| /** |
| * Handles an external change of the editor's input element. Subclasses may |
| * extend. |
| */ |
| protected void handleEditorInputChanged() { |
| |
| String title; |
| String msg; |
| Shell shell= getSite().getShell(); |
| |
| final IDocumentProvider provider= getDocumentProvider(); |
| if (provider == null) { |
| // fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=15066 |
| close(false); |
| return; |
| } |
| |
| final IEditorInput input= getEditorInput(); |
| final String inputName= input.getToolTipText(); |
| |
| if (provider.isDeleted(input)) { |
| |
| if (isSaveAsAllowed()) { |
| |
| title= EditorMessages.Editor_error_activated_deleted_save_title; |
| msg= NLSUtility.format(EditorMessages.Editor_error_activated_deleted_save_message, inputName); |
| |
| String[] buttons= { |
| EditorMessages.Editor_error_activated_deleted_save_button_save, |
| EditorMessages.Editor_error_activated_deleted_save_button_close, |
| }; |
| |
| MessageDialog dialog= new MessageDialog(shell, title, null, msg, MessageDialog.QUESTION, buttons, 0); |
| |
| if (dialog.open() == 0) { |
| IProgressMonitor pm= getProgressMonitor(); |
| try { |
| performSaveAs(pm); |
| if (pm.isCanceled()) |
| handleEditorInputChanged(); |
| } finally { |
| pm.done(); |
| } |
| } else { |
| close(false); |
| } |
| |
| } else { |
| |
| title= EditorMessages.Editor_error_activated_deleted_close_title; |
| msg= NLSUtility.format(EditorMessages.Editor_error_activated_deleted_close_message, inputName); |
| if (MessageDialog.openConfirm(shell, title, msg)) |
| close(false); |
| } |
| |
| } else if (fHasBeenActivated) { |
| |
| title= EditorMessages.Editor_error_activated_outofsync_title; |
| msg= NLSUtility.format(EditorMessages.Editor_error_activated_outofsync_message, inputName); |
| |
| if (MessageDialog.openQuestion(shell, title, msg)) { |
| |
| |
| try { |
| if (provider instanceof IDocumentProviderExtension) { |
| IDocumentProviderExtension extension= (IDocumentProviderExtension) provider; |
| extension.synchronize(input); |
| } else { |
| doSetInput(input); |
| } |
| } catch (CoreException x) { |
| IStatus status= x.getStatus(); |
| if (status == null || status.getSeverity() != IStatus.CANCEL) { |
| title= EditorMessages.Editor_error_refresh_outofsync_title; |
| msg= NLSUtility.format(EditorMessages.Editor_error_refresh_outofsync_message, inputName); |
| ErrorDialog.openError(shell, title, msg, x.getStatus()); |
| } |
| } |
| } else if (!isDirty()) { |
| // Trigger dummy change to dirty the editor, for details see https://bugs.eclipse.org/344101 . |
| try { |
| IDocument document= provider.getDocument(input); |
| if (document != null) |
| document.replace(0, 0, ""); //$NON-NLS-1$ |
| } catch (BadLocationException e) { |
| // Ignore as this can't happen |
| } |
| } |
| } |
| } |
| |
| /** |
| * The <code>AbstractTextEditor</code> implementation of this |
| * <code>IEditorPart</code> method calls <code>performSaveAs</code>. |
| * Subclasses may reimplement. |
| */ |
| @Override |
| public void doSaveAs() { |
| IProgressMonitor monitor= getProgressMonitor(); |
| try { |
| /* |
| * 1GEUSSR: ITPUI:ALL - User should never loose changes made in the editors. |
| * Changed Behavior to make sure that if called inside a regular save (because |
| * of deletion of input element) there is a way to report back to the caller. |
| */ |
| performSaveAs(monitor); |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| /** |
| * Performs a save as and reports the result state back to the |
| * given progress monitor. This default implementation does nothing. |
| * Subclasses may reimplement. |
| * |
| * @param progressMonitor the progress monitor for communicating result state or <code>null</code> |
| */ |
| protected void performSaveAs(IProgressMonitor progressMonitor) { |
| } |
| |
| /** |
| * The <code>AbstractTextEditor</code> implementation of this |
| * <code>IEditorPart</code> method may be extended by subclasses. |
| * |
| * @param progressMonitor the progress monitor for communicating result state or <code>null</code> |
| */ |
| @Override |
| public void doSave(IProgressMonitor progressMonitor) { |
| |
| IDocumentProvider p= getDocumentProvider(); |
| if (p == null) |
| return; |
| |
| if (p.isDeleted(getEditorInput())) { |
| |
| if (isSaveAsAllowed()) { |
| |
| /* |
| * 1GEUSSR: ITPUI:ALL - User should never loose changes made in the editors. |
| * Changed Behavior to make sure that if called inside a regular save (because |
| * of deletion of input element) there is a way to report back to the caller. |
| */ |
| performSaveAs(progressMonitor); |
| |
| } else { |
| |
| Shell shell= getSite().getShell(); |
| String title= EditorMessages.Editor_error_save_deleted_title; |
| String msg= EditorMessages.Editor_error_save_deleted_message; |
| MessageDialog.openError(shell, title, msg); |
| } |
| |
| } else { |
| updateState(getEditorInput()); |
| validateState(getEditorInput()); |
| performSave(false, progressMonitor); |
| } |
| } |
| |
| /** |
| * Enables/disables sanity checking. |
| * @param enable <code>true</code> if sanity checking should be enabled, <code>false</code> otherwise |
| * @since 2.0 |
| */ |
| protected void enableSanityChecking(boolean enable) { |
| synchronized (this) { |
| fIsSanityCheckEnabled= enable; |
| } |
| } |
| |
| /** |
| * Checks the state of the given editor input if sanity checking is enabled. |
| * @param input the editor input whose state is to be checked |
| * @since 2.0 |
| */ |
| protected void safelySanityCheckState(IEditorInput input) { |
| boolean enabled= false; |
| |
| synchronized (this) { |
| enabled= fIsSanityCheckEnabled; |
| } |
| |
| if (enabled) |
| sanityCheckState(input); |
| } |
| |
| /** |
| * Checks the state of the given editor input. |
| * @param input the editor input whose state is to be checked |
| * @since 2.0 |
| */ |
| protected void sanityCheckState(IEditorInput input) { |
| |
| IDocumentProvider p= getDocumentProvider(); |
| if (p == null) |
| return; |
| |
| if (p instanceof IDocumentProviderExtension3) { |
| |
| IDocumentProviderExtension3 p3= (IDocumentProviderExtension3) p; |
| |
| long stamp= p.getModificationStamp(input); |
| if (stamp != fModificationStamp) { |
| fModificationStamp= stamp; |
| if (!p3.isSynchronized(input)) |
| handleEditorInputChanged(); |
| } |
| |
| } else { |
| |
| if (fModificationStamp == -1) |
| fModificationStamp= p.getSynchronizationStamp(input); |
| |
| long stamp= p.getModificationStamp(input); |
| if (stamp != fModificationStamp) { |
| fModificationStamp= stamp; |
| if (stamp != p.getSynchronizationStamp(input)) |
| handleEditorInputChanged(); |
| } |
| } |
| |
| updateState(getEditorInput()); |
| updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE); |
| } |
| |
| /** |
| * Enables/disables state validation. |
| * @param enable <code>true</code> if state validation should be enabled, <code>false</code> otherwise |
| * @since 2.1 |
| */ |
| protected void enableStateValidation(boolean enable) { |
| synchronized (this) { |
| fIsStateValidationEnabled= enable; |
| } |
| } |
| |
| /** |
| * Validates the state of the given editor input. The predominate intent |
| * of this method is to take any action probably necessary to ensure that |
| * the input can persistently be changed. |
| * |
| * @param input the input to be validated |
| * @since 2.0 |
| */ |
| protected void validateState(IEditorInput input) { |
| |
| IDocumentProvider provider= getDocumentProvider(); |
| if (! (provider instanceof IDocumentProviderExtension)) |
| return; |
| |
| IDocumentProviderExtension extension= (IDocumentProviderExtension) provider; |
| |
| try { |
| |
| extension.validateState(input, getSite().getShell()); |
| |
| } catch (CoreException x) { |
| IStatus status= x.getStatus(); |
| if (status == null || status.getSeverity() != IStatus.CANCEL) { |
| Bundle bundle= Platform.getBundle(PlatformUI.PLUGIN_ID); |
| ILog log= Platform.getLog(bundle); |
| log.log(x.getStatus()); |
| |
| Shell shell= getSite().getShell(); |
| String title= EditorMessages.Editor_error_validateEdit_title; |
| String msg= EditorMessages.Editor_error_validateEdit_message; |
| ErrorDialog.openError(shell, title, msg, x.getStatus()); |
| } |
| return; |
| } |
| |
| if (fSourceViewer != null) |
| fSourceViewer.setEditable(isEditable()); |
| |
| updateStateDependentActions(); |
| } |
| |
| @Override |
| public boolean validateEditorInputState() { |
| |
| boolean enabled= false; |
| |
| synchronized (this) { |
| enabled= fIsStateValidationEnabled; |
| } |
| |
| if (enabled) { |
| |
| ISourceViewer viewer= fSourceViewer; |
| if (viewer == null) |
| return false; |
| |
| fTextInputListener.inputChanged= false; |
| viewer.addTextInputListener(fTextInputListener); |
| |
| try { |
| final IEditorInput input= getEditorInput(); |
| BusyIndicator.showWhile(getSite().getShell().getDisplay(), new Runnable() { |
| @Override |
| public void run() { |
| validateState(input); |
| } |
| }); |
| sanityCheckState(input); |
| return !isEditorInputReadOnly() && !fTextInputListener.inputChanged; |
| |
| } finally { |
| viewer.removeTextInputListener(fTextInputListener); |
| } |
| |
| } |
| |
| return !isEditorInputReadOnly(); |
| } |
| |
| /** |
| * Updates the state of the given editor input such as read-only flag. |
| * |
| * @param input the input to be validated |
| * @since 2.0 |
| */ |
| protected void updateState(IEditorInput input) { |
| IDocumentProvider provider= getDocumentProvider(); |
| if (provider instanceof IDocumentProviderExtension) { |
| IDocumentProviderExtension extension= (IDocumentProviderExtension) provider; |
| try { |
| |
| boolean wasReadOnly= isEditorInputReadOnly(); |
| extension.updateStateCache(input); |
| |
| if (fSourceViewer != null) |
| fSourceViewer.setEditable(isEditable()); |
| |
| if (wasReadOnly != isEditorInputReadOnly()) |
| updateStateDependentActions(); |
| |
| } catch (CoreException x) { |
| Bundle bundle= Platform.getBundle(PlatformUI.PLUGIN_ID); |
| ILog log= Platform.getLog(bundle); |
| log.log(x.getStatus()); |
| } |
| } |
| } |
| |
| /** |
| * Performs the save and handles errors appropriately. |
| * |
| * @param overwrite indicates whether or not overwriting is allowed |
| * @param progressMonitor the monitor in which to run the operation |
| * @since 3.0 |
| */ |
| protected void performSave(boolean overwrite, IProgressMonitor progressMonitor) { |
| IDocumentProvider provider= getDocumentProvider(); |
| if (provider == null) |
| return; |
| |
| fHandleActivation= false; |
| try { |
| provider.aboutToChange(getEditorInput()); |
| IEditorInput input= getEditorInput(); |
| provider.saveDocument(progressMonitor, input, getDocumentProvider().getDocument(input), overwrite); |
| editorSaved(); |
| |
| } catch (CoreException x) { |
| IStatus status= x.getStatus(); |
| if (status == null || status.getSeverity() != IStatus.CANCEL) |
| handleExceptionOnSave(x, progressMonitor); |
| } finally { |
| provider.changed(getEditorInput()); |
| fHandleActivation= true; |
| } |
| } |
| |
| /** |
| * Handles the given exception. If the exception reports an out-of-sync |
| * situation, this is reported to the user. Otherwise, the exception |
| * is generically reported. |
| * |
| * @param exception the exception to handle |
| * @param progressMonitor the progress monitor |
| */ |
| protected void handleExceptionOnSave(CoreException exception, IProgressMonitor progressMonitor) { |
| |
| try { |
| ++fErrorCorrectionOnSave; |
| |
| boolean isSynchronized= false; |
| IDocumentProvider p= getDocumentProvider(); |
| |
| if (p instanceof IDocumentProviderExtension3) { |
| IDocumentProviderExtension3 p3= (IDocumentProviderExtension3) p; |
| isSynchronized= p3.isSynchronized(getEditorInput()); |
| } else if (p != null) { |
| long modifiedStamp= p.getModificationStamp(getEditorInput()); |
| long synchStamp= p.getSynchronizationStamp(getEditorInput()); |
| isSynchronized= (modifiedStamp == synchStamp); |
| } |
| |
| if (isNotSynchronizedException(exception) && fErrorCorrectionOnSave == 1 && !isSynchronized) { |
| String title= EditorMessages.Editor_error_save_outofsync_title; |
| String msg= NLSUtility.format(EditorMessages.Editor_error_save_outofsync_message, getEditorInput().getToolTipText()); |
| |
| if (MessageDialog.openQuestion(getSite().getShell(), title, msg)) |
| performSave(true, progressMonitor); |
| else { |
| /* |
| * 1GEUPKR: ITPJUI:ALL - Loosing work with simultaneous edits |
| * Set progress monitor to canceled in order to report back |
| * to enclosing operations. |
| */ |
| if (progressMonitor != null) |
| progressMonitor.setCanceled(true); |
| } |
| } else { |
| String title= EditorMessages.Editor_error_save_title; |
| String msg= EditorMessages.Editor_error_save_message; |
| openSaveErrorDialog(title, msg, exception); |
| |
| /* |
| * 1GEUPKR: ITPJUI:ALL - Loosing work with simultaneous edits |
| * Set progress monitor to canceled in order to report back |
| * to enclosing operations. |
| */ |
| if (progressMonitor != null) |
| progressMonitor.setCanceled(true); |
| } |
| } finally { |
| --fErrorCorrectionOnSave; |
| } |
| } |
| |
| /** |
| * Presents an error dialog to the user when a problem |
| * happens during save. |
| * <p> |
| * Subclasses can decide to override the given title and message. |
| * </p> |
| * |
| * @param title the dialog title |
| * @param message the message to display |
| * @param exception the exception to handle |
| * @since 3.3 |
| */ |
| protected void openSaveErrorDialog(String title, String message, CoreException exception) { |
| ErrorDialog.openError(getSite().getShell(), title, message, exception.getStatus()); |
| } |
| |
| /** |
| * Tells whether the given core exception is exactly the |
| * exception which is thrown for a non-synchronized element. |
| * |
| * @param ex the core exception |
| * @return <code>true</code> iff the given core exception is exactly the |
| * exception which is thrown for a non-synchronized element |
| * @since 3.1 |
| */ |
| private boolean isNotSynchronizedException(CoreException ex) { |
| IDocumentProvider provider= getDocumentProvider(); |
| if (provider instanceof IDocumentProviderExtension5) |
| return ((IDocumentProviderExtension5)provider).isNotSynchronizedException(getEditorInput(), ex); |
| return false; |
| } |
| |
| /** |
| * The <code>AbstractTextEditor</code> implementation of this |
| * <code>IEditorPart</code> method returns <code>false</code>. |
| * Subclasses may override. |
| * |
| * @return <code>false</code> |
| */ |
| @Override |
| public boolean isSaveAsAllowed() { |
| return false; |
| } |
| |
| @Override |
| public boolean isDirty() { |
| IDocumentProvider p= getDocumentProvider(); |
| return p == null ? false : p.canSaveDocument(getEditorInput()); |
| } |
| |
| /** |
| * The <code>AbstractTextEditor</code> implementation of this |
| * <code>ITextEditor</code> method may be extended by subclasses. |
| */ |
| @Override |
| public void doRevertToSaved() { |
| IDocumentProvider p= getDocumentProvider(); |
| if (p == null) |
| return; |
| |
| performRevert(); |
| } |
| |
| /** |
| * Performs revert and handles errors appropriately. |
| * <p> |
| * Subclasses may extend. |
| * </p> |
| * |
| * @since 3.0 |
| */ |
| protected void performRevert() { |
| |
| IDocumentProvider provider= getDocumentProvider(); |
| if (provider == null) |
| return; |
| |
| try { |
| |
| provider.aboutToChange(getEditorInput()); |
| provider.resetDocument(getEditorInput()); |
| editorSaved(); |
| |
| } catch (CoreException x) { |
| IStatus status= x.getStatus(); |
| if (status == null || status.getSeverity() != IStatus.CANCEL ) { |
| Shell shell= getSite().getShell(); |
| String title= EditorMessages.Editor_error_revert_title; |
| String msg= EditorMessages.Editor_error_revert_message; |
| ErrorDialog.openError(shell, title, msg, x.getStatus()); |
| } |
| } finally { |
| provider.changed(getEditorInput()); |
| } |
| } |
| |
| /** |
| * Performs any additional action necessary to perform after the input |
| * document's content has been replaced. |
| * <p> |
| * Clients may extended this method. |
| * |
| * @since 3.0 |
| */ |
| protected void handleElementContentReplaced() { |
| } |
| |
| @Override |
| public void setAction(String actionID, IAction action) { |
| Assert.isNotNull(actionID); |
| if (action == null) { |
| action= fActions.remove(actionID); |
| if (action != null) |
| fActivationCodeTrigger.unregisterActionFromKeyActivation(action); |
| } else { |
| if (action.getId() == null) |
| action.setId(actionID); // make sure the action ID has been set |
| fActions.put(actionID, action); |
| fActivationCodeTrigger.registerActionForKeyActivation(action); |
| } |
| } |
| |
| /** |
| * Sets this editor's actions into activated (default) or deactived state. |
| * <p> |
| * XXX: This is called by the Java editor for its breadcrumb feature. We |
| * don't want to make this risky method API because the Java editor |
| * breadcrumb might become a Platform UI feature during 3.5 and hence we can |
| * then delete this workaround. |
| * </p> |
| * |
| * @param state <code>true</code> if activated |
| * @since 3.4 |
| */ |
| private void setActionActivation(boolean state) { |
| if (state) { |
| fActivationCodeTrigger.install(); |
| Iterator<IAction> iter= fActions.values().iterator(); |
| while (iter.hasNext()) { |
| IAction action= iter.next(); |
| if (action != null) |
| fActivationCodeTrigger.registerActionForKeyActivation(action); |
| } |
| getEditorSite().getActionBarContributor().setActiveEditor(this); |
| } else { |
| getEditorSite().getActionBarContributor().setActiveEditor(null); |
| Iterator<IAction> iter= fActions.values().iterator(); |
| while (iter.hasNext()) { |
| IAction action= iter.next(); |
| if (action != null) |
| fActivationCodeTrigger.unregisterActionFromKeyActivation(action); |
| } |
| fActivationCodeTrigger.uninstall(); |
| } |
| } |
| |
| private static final boolean HACK_TO_SUPPRESS_UNUSUED_WARNING= false; |
| { |
| if (HACK_TO_SUPPRESS_UNUSUED_WARNING) |
| setActionActivation(true); |
| } |
| |
| @Override |
| public void setActionActivationCode(String actionID, char activationCharacter, int activationKeyCode, int activationStateMask) { |
| |
| Assert.isNotNull(actionID); |
| |
| ActionActivationCode found= findActionActivationCode(actionID); |
| if (found == null) { |
| found= new ActionActivationCode(actionID); |
| fActivationCodes.add(found); |
| } |
| |
| found.fCharacter= activationCharacter; |
| found.fKeyCode= activationKeyCode; |
| found.fStateMask= activationStateMask; |
| } |
| |
| /** |
| * Returns the activation code registered for the specified action. |
| * |
| * @param actionID the action id |
| * @return the registered activation code or <code>null</code> if no code has been installed |
| */ |
| private ActionActivationCode findActionActivationCode(String actionID) { |
| int size= fActivationCodes.size(); |
| for (int i= 0; i < size; i++) { |
| ActionActivationCode code= fActivationCodes.get(i); |
| if (actionID.equals(code.fActionId)) |
| return code; |
| } |
| return null; |
| } |
| |
| @Override |
| public void removeActionActivationCode(String actionID) { |
| Assert.isNotNull(actionID); |
| ActionActivationCode code= findActionActivationCode(actionID); |
| if (code != null) |
| fActivationCodes.remove(code); |
| } |
| |
| @Override |
| public IAction getAction(String actionID) { |
| Assert.isNotNull(actionID); |
| IAction action= fActions.get(actionID); |
| |
| if (action == null) { |
| action= findContributedAction(actionID); |
| if (action != null) |
| setAction(actionID, action); |
| } |
| |
| return action; |
| } |
| |
| /** |
| * Returns the action with the given action id that has been contributed via XML to this editor. |
| * The lookup honors the dependencies of plug-ins. |
| * |
| * @param actionID the action id to look up |
| * @return the action that has been contributed |
| * @since 2.0 |
| */ |
| private IAction findContributedAction(String actionID) { |
| List<IConfigurationElement> actions= new ArrayList<>(); |
| IConfigurationElement[] elements= Platform.getExtensionRegistry().getConfigurationElementsFor(PlatformUI.PLUGIN_ID, "editorActions"); //$NON-NLS-1$ |
| for (int i= 0; i < elements.length; i++) { |
| IConfigurationElement element= elements[i]; |
| if (TAG_CONTRIBUTION_TYPE.equals(element.getName())) { |
| IWorkbenchPartSite site = getSite(); |
| if (site == null) { |
| return null; |
| } |
| if (!site.getId().equals(element.getAttribute("targetID"))) //$NON-NLS-1$ |
| continue; |
| |
| IConfigurationElement[] children= element.getChildren("action"); //$NON-NLS-1$ |
| for (int j= 0; j < children.length; j++) { |
| IConfigurationElement child= children[j]; |
| if (actionID.equals(child.getAttribute("actionID"))) //$NON-NLS-1$ |
| actions.add(child); |
| } |
| } |
| } |
| int actionSize= actions.size(); |
| if (actionSize > 0) { |
| IConfigurationElement element; |
| if (actionSize > 1) { |
| IConfigurationElement[] actionArray= actions.toArray(new IConfigurationElement[actionSize]); |
| ConfigurationElementSorter sorter= new ConfigurationElementSorter() { |
| @Override |
| public IConfigurationElement getConfigurationElement(Object object) { |
| return (IConfigurationElement)object; |
| } |
| }; |
| sorter.sort(actionArray); |
| element= actionArray[0]; |
| } else |
| element= actions.get(0); |
| |
| try { |
| return new ContributedAction(getSite(), element); |
| } catch (CommandNotMappedException e) { |
| // out of luck, no command action mapping |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Updates the specified action by calling <code>IUpdate.update</code> |
| * if applicable. |
| * |
| * @param actionId the action id |
| */ |
| private void updateAction(String actionId) { |
| Assert.isNotNull(actionId); |
| if (fActions != null) { |
| IAction action= fActions.get(actionId); |
| if (action instanceof IUpdate) |
| ((IUpdate) action).update(); |
| } |
| } |
| |
| /** |
| * Marks or unmarks the given action to be updated on text selection changes. |
| * |
| * @param actionId the action id |
| * @param mark <code>true</code> if the action is selection dependent |
| */ |
| public void markAsSelectionDependentAction(String actionId, boolean mark) { |
| Assert.isNotNull(actionId); |
| if (mark) { |
| if (!fSelectionActions.contains(actionId)) |
| fSelectionActions.add(actionId); |
| } else |
| fSelectionActions.remove(actionId); |
| } |
| |
| /** |
| * Marks or unmarks the given action to be updated on content changes. |
| * |
| * @param actionId the action id |
| * @param mark <code>true</code> if the action is content dependent |
| */ |
| public void markAsContentDependentAction(String actionId, boolean mark) { |
| Assert.isNotNull(actionId); |
| if (mark) { |
| if (!fContentActions.contains(actionId)) |
| fContentActions.add(actionId); |
| } else |
| fContentActions.remove(actionId); |
| } |
| |
| /** |
| * Marks or unmarks the given action to be updated on property changes. |
| * |
| * @param actionId the action id |
| * @param mark <code>true</code> if the action is property dependent |
| * @since 2.0 |
| */ |
| public void markAsPropertyDependentAction(String actionId, boolean mark) { |
| Assert.isNotNull(actionId); |
| if (mark) { |
| if (!fPropertyActions.contains(actionId)) |
| fPropertyActions.add(actionId); |
| } else |
| fPropertyActions.remove(actionId); |
| } |
| |
| /** |
| * Marks or unmarks the given action to be updated on state changes. |
| * |
| * @param actionId the action id |
| * @param mark <code>true</code> if the action is state dependent |
| * @since 2.0 |
| */ |
| public void markAsStateDependentAction(String actionId, boolean mark) { |
| Assert.isNotNull(actionId); |
| if (mark) { |
| if (!fStateActions.contains(actionId)) |
| fStateActions.add(actionId); |
| } else |
| fStateActions.remove(actionId); |
| } |
| |
| /** |
| * Updates all selection dependent actions. |
| */ |
| protected void updateSelectionDependentActions() { |
| if (fSelectionActions != null) { |
| Iterator<String> e= fSelectionActions.iterator(); |
| while (e.hasNext()) |
| updateAction(e.next()); |
| } |
| } |
| |
| /** |
| * Updates all content dependent actions. |
| */ |
| protected void updateContentDependentActions() { |
| if (fContentActions != null) { |
| Iterator<String> e= fContentActions.iterator(); |
| while (e.hasNext()) |
| updateAction(e.next()); |
| } |
| } |
| |
| /** |
| * Updates all property dependent actions. |
| * @since 2.0 |
| */ |
| protected void updatePropertyDependentActions() { |
| if (fPropertyActions != null) { |
| Iterator<String> e= fPropertyActions.iterator(); |
| while (e.hasNext()) |
| updateAction(e.next()); |
| } |
| } |
| |
| /** |
| * Updates all state dependent actions. |
| * @since 2.0 |
| */ |
| protected void updateStateDependentActions() { |
| if (fStateActions != null) { |
| Iterator<String> e= fStateActions.iterator(); |
| while (e.hasNext()) |
| updateAction(e.next()); |
| } |
| } |
| |
| /** |
| * Creates action entries for all SWT StyledText actions as defined in |
| * <code>org.eclipse.swt.custom.ST</code>. Overwrites and |
| * extends the list of these actions afterwards. |
| * <p> |
| * Subclasses may extend. |
| * </p> |
| * @since 2.0 |
| */ |
| protected void createNavigationActions() { |
| |
| IAction action; |
| |
| StyledText textWidget= fSourceViewer.getTextWidget(); |
| for (int i= 0; i < ACTION_MAP.length; i++) { |
| IdMapEntry entry= ACTION_MAP[i]; |
| action= new TextNavigationAction(textWidget, entry.getAction()); |
| action.setActionDefinitionId(entry.getActionId()); |
| setAction(entry.getActionId(), action); |
| } |
| |
| action= new ToggleOverwriteModeAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ToggleOverwriteMode."); //$NON-NLS-1$ |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.TOGGLE_OVERWRITE); |
| setAction(ITextEditorActionDefinitionIds.TOGGLE_OVERWRITE, action); |
| textWidget.setKeyBinding(SWT.INSERT, SWT.NULL); |
| |
| action= new ScrollLinesAction(-1); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.SCROLL_LINE_UP); |
| setAction(ITextEditorActionDefinitionIds.SCROLL_LINE_UP, action); |
| |
| action= new ScrollLinesAction(1); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.SCROLL_LINE_DOWN); |
| setAction(ITextEditorActionDefinitionIds.SCROLL_LINE_DOWN, action); |
| |
| action= new LineEndAction(textWidget, false); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.LINE_END); |
| setAction(ITextEditorActionDefinitionIds.LINE_END, action); |
| |
| action= new LineStartAction(textWidget, false); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.LINE_START); |
| setAction(ITextEditorActionDefinitionIds.LINE_START, action); |
| |
| action= new LineEndAction(textWidget, true); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_LINE_END); |
| setAction(ITextEditorActionDefinitionIds.SELECT_LINE_END, action); |
| |
| action= new LineStartAction(textWidget, true); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_LINE_START); |
| setAction(ITextEditorActionDefinitionIds.SELECT_LINE_START, action); |
| |
| // to accommodate https://bugs.eclipse.org/bugs/show_bug.cgi?id=51516 |
| // nullify handling of DELETE key by StyledText |
| textWidget.setKeyBinding(SWT.DEL, SWT.NULL); |
| } |
| |
| /** |
| * Creates this editor's accessibility actions. |
| * @since 2.0 |
| */ |
| private void createAccessibilityActions() { |
| IAction action= new ShowRulerContextMenuAction(); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.SHOW_RULER_CONTEXT_MENU); |
| setAction(ITextEditorActionDefinitionIds.SHOW_RULER_CONTEXT_MENU, action); |
| } |
| |
| /** |
| * Creates this editor's undo/redo actions. |
| * <p> |
| * Subclasses may override or extend.</p> |
| * |
| * @since 3.1 |
| */ |
| protected void createUndoRedoActions() { |
| IUndoContext undoContext= getUndoContext(); |
| if (undoContext != null) { |
| // Use actions provided by global undo/redo |
| |
| // Create the undo action |
| OperationHistoryActionHandler undoAction= new UndoActionHandler(getEditorSite(), undoContext); |
| PlatformUI.getWorkbench().getHelpSystem().setHelp(undoAction, IAbstractTextEditorHelpContextIds.UNDO_ACTION); |
| undoAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_UNDO); |
| registerUndoRedoAction(ITextEditorActionConstants.UNDO, undoAction); |
| |
| // Create the redo action. |
| OperationHistoryActionHandler redoAction= new RedoActionHandler(getEditorSite(), undoContext); |
| PlatformUI.getWorkbench().getHelpSystem().setHelp(redoAction, IAbstractTextEditorHelpContextIds.REDO_ACTION); |
| redoAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_REDO); |
| registerUndoRedoAction(ITextEditorActionConstants.REDO, redoAction); |
| |
| // Install operation approvers |
| IOperationHistory history= OperationHistoryFactory.getOperationHistory(); |
| |
| // The first approver will prompt when operations affecting outside elements are to be undone or redone. |
| if (fNonLocalOperationApprover != null) |
| history.removeOperationApprover(fNonLocalOperationApprover); |
| fNonLocalOperationApprover= getUndoRedoOperationApprover(undoContext); |
| history.addOperationApprover(fNonLocalOperationApprover); |
| |
| // The second approver will prompt from this editor when an undo is attempted on an operation |
| // and it is not the most recent operation in the editor. |
| if (fLinearUndoViolationApprover != null) |
| history.removeOperationApprover(fLinearUndoViolationApprover); |
| fLinearUndoViolationApprover= new LinearUndoViolationUserApprover(undoContext, this); |
| history.addOperationApprover(fLinearUndoViolationApprover); |
| |
| } else { |
| // Use text operation actions (pre 3.1 style) |
| |
| ResourceAction action; |
| |
| if (getAction(ITextEditorActionConstants.UNDO) == null) { |
| action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Undo.", this, ITextOperationTarget.UNDO); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.UNDO_ACTION); |
| action.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_UNDO); |
| setAction(ITextEditorActionConstants.UNDO, action); |
| } |
| |
| if (getAction(ITextEditorActionConstants.REDO) == null) { |
| action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Redo.", this, ITextOperationTarget.REDO); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.REDO_ACTION); |
| action.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_REDO); |
| setAction(ITextEditorActionConstants.REDO, action); |
| } |
| } |
| } |
| |
| /** |
| * Registers the given undo/redo action under the given ID and ensures that previously installed |
| * actions get disposed. It also takes care of re-registering the new action with the global |
| * action handler. |
| * |
| * @param actionId the action id under which to register the action |
| * @param action the action to register or <code>null</code> to dispose them |
| * @since 3.1 |
| */ |
| private void registerUndoRedoAction(String actionId, OperationHistoryActionHandler action) { |
| IAction oldAction= getAction(actionId); |
| if (oldAction instanceof OperationHistoryActionHandler) |
| ((OperationHistoryActionHandler)oldAction).dispose(); |
| |
| if (action == null) |
| return; |
| |
| setAction(actionId, action); |
| |
| IActionBars actionBars= getEditorSite().getActionBars(); |
| if (actionBars != null) |
| actionBars.setGlobalActionHandler(actionId, action); |
| } |
| |
| /** |
| * Return an {@link IOperationApprover} appropriate for approving the undo and |
| * redo of operations that have the specified undo context. |
| * <p> |
| * Subclasses may override. |
| * </p> |
| * @param undoContext the IUndoContext of operations that should be examined |
| * by the operation approver |
| * @return the <code>IOperationApprover</code> appropriate for approving undo |
| * and redo operations inside this editor, or <code>null</code> if no |
| * approval is needed |
| * @since 3.1 |
| */ |
| protected IOperationApprover getUndoRedoOperationApprover(IUndoContext undoContext) { |
| return new NonLocalUndoUserApprover(undoContext, this, new Object [] { getEditorInput() }, Object.class); |
| } |
| |
| /** |
| * Creates this editor's standard actions and connects them with the global |
| * workbench actions. |
| * <p> |
| * Subclasses may extend.</p> |
| */ |
| protected void createActions() { |
| |
| ResourceAction action; |
| |
| setAction(IWorkbenchCommandConstants.EDIT_CUT, null); |
| action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Cut.", this, ITextOperationTarget.CUT); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.CUT_ACTION); |
| action.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_CUT); |
| setAction(ITextEditorActionConstants.CUT, action); |
| |
| setAction(IWorkbenchCommandConstants.EDIT_COPY, null); |
| action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Copy.", this, ITextOperationTarget.COPY, true); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.COPY_ACTION); |
| action.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_COPY); |
| setAction(ITextEditorActionConstants.COPY, action); |
| |
| setAction(IWorkbenchCommandConstants.EDIT_PASTE, null); |
| action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Paste.", this, ITextOperationTarget.PASTE); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.PASTE_ACTION); |
| action.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_PASTE); |
| setAction(ITextEditorActionConstants.PASTE, action); |
| |
| action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Delete.", this, ITextOperationTarget.DELETE); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.DELETE_ACTION); |
| action.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_DELETE); |
| setAction(ITextEditorActionConstants.DELETE, action); |
| |
| action= new DeleteLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.DeleteLine.", this, DeleteLineAction.WHOLE, false); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.DELETE_LINE_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.DELETE_LINE); |
| setAction(ITextEditorActionConstants.DELETE_LINE, action); |
| |
| action= new DeleteLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.CutLine.", this, DeleteLineAction.WHOLE, true); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.CUT_LINE_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.CUT_LINE); |
| setAction(ITextEditorActionConstants.CUT_LINE, action); |
| |
| action= new DeleteLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.DeleteLineToBeginning.", this, DeleteLineAction.TO_BEGINNING, false); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.DELETE_LINE_TO_BEGINNING_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.DELETE_LINE_TO_BEGINNING); |
| setAction(ITextEditorActionConstants.DELETE_LINE_TO_BEGINNING, action); |
| |
| action= new DeleteLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.CutLineToBeginning.", this, DeleteLineAction.TO_BEGINNING, true); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.CUT_LINE_TO_BEGINNING_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.CUT_LINE_TO_BEGINNING); |
| setAction(ITextEditorActionConstants.CUT_LINE_TO_BEGINNING, action); |
| |
| action= new DeleteLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.DeleteLineToEnd.", this, DeleteLineAction.TO_END, false); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.DELETE_LINE_TO_END_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.DELETE_LINE_TO_END); |
| setAction(ITextEditorActionConstants.DELETE_LINE_TO_END, action); |
| |
| action= new DeleteLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.CutLineToEnd.", this, DeleteLineAction.TO_END, true); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.CUT_LINE_TO_END_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.CUT_LINE_TO_END); |
| setAction(ITextEditorActionConstants.CUT_LINE_TO_END, action); |
| |
| action= new JoinLinesAction(EditorMessages.getBundleForConstructedKeys(), "Editor.JoinLines.", this, " "); //$NON-NLS-1$ //$NON-NLS-2$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.JOIN_LINES_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.JOIN_LINES); |
| setAction(ITextEditorActionConstants.JOIN_LINES, action); |
| |
| action= new MarkAction(EditorMessages.getBundleForConstructedKeys(), "Editor.SetMark.", this, MarkAction.SET_MARK); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.SET_MARK_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.SET_MARK); |
| setAction(ITextEditorActionConstants.SET_MARK, action); |
| |
| action= new MarkAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ClearMark.", this, MarkAction.CLEAR_MARK); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.CLEAR_MARK_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.CLEAR_MARK); |
| setAction(ITextEditorActionConstants.CLEAR_MARK, action); |
| |
| action= new MarkAction(EditorMessages.getBundleForConstructedKeys(), "Editor.SwapMark.", this, MarkAction.SWAP_MARK); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.SWAP_MARK_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.SWAP_MARK); |
| setAction(ITextEditorActionConstants.SWAP_MARK, action); |
| |
| action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.SelectAll.", this, ITextOperationTarget.SELECT_ALL, true); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.SELECT_ALL_ACTION); |
| action.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_SELECT_ALL); |
| setAction(ITextEditorActionConstants.SELECT_ALL, action); |
| |
| action= new ShiftAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ShiftRight.", this, ITextOperationTarget.SHIFT_RIGHT); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.SHIFT_RIGHT_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.SHIFT_RIGHT); |
| setAction(ITextEditorActionConstants.SHIFT_RIGHT, action); |
| |
| action= new ShiftAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ShiftRight.", this, ITextOperationTarget.SHIFT_RIGHT) { //$NON-NLS-1$ |
| @Override |
| public void update() { |
| updateForTab(); |
| } |
| }; |
| setAction(ITextEditorActionConstants.SHIFT_RIGHT_TAB, action); |
| |
| action= new ShiftAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ShiftLeft.", this, ITextOperationTarget.SHIFT_LEFT); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.SHIFT_LEFT_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.SHIFT_LEFT); |
| setAction(ITextEditorActionConstants.SHIFT_LEFT, action); |
| |
| action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Print.", this, ITextOperationTarget.PRINT, true); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.PRINT_ACTION); |
| action.setActionDefinitionId(IWorkbenchCommandConstants.FILE_PRINT); |
| setAction(ITextEditorActionConstants.PRINT, action); |
| |
| action= new FindReplaceAction(EditorMessages.getBundleForConstructedKeys(), "Editor.FindReplace.", this); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_ACTION); |
| action.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_FIND_AND_REPLACE); |
| setAction(ITextEditorActionConstants.FIND, action); |
| |
| action= new FindNextAction(EditorMessages.getBundleForConstructedKeys(), "Editor.FindNext.", this, true); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_NEXT_ACTION); |
| action.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_NEXT); |
| setAction(ITextEditorActionConstants.FIND_NEXT, action); |
| |
| action= new FindNextAction(EditorMessages.getBundleForConstructedKeys(), "Editor.FindPrevious.", this, false); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_PREVIOUS_ACTION); |
| action.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_PREVIOUS); |
| setAction(ITextEditorActionConstants.FIND_PREVIOUS, action); |
| |
| action= new IncrementalFindAction(EditorMessages.getBundleForConstructedKeys(), "Editor.FindIncremental.", this, true); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_INCREMENTAL_ACTION); |
| action.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_INCREMENTAL); |
| setAction(ITextEditorActionConstants.FIND_INCREMENTAL, action); |
| |
| action= new IncrementalFindAction(EditorMessages.getBundleForConstructedKeys(), "Editor.FindIncrementalReverse.", this, false); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_INCREMENTAL_REVERSE_ACTION); |
| action.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_INCREMENTAL_REVERSE); |
| setAction(ITextEditorActionConstants.FIND_INCREMENTAL_REVERSE, action); |
| |
| fSaveAction= ActionFactory.SAVE.create(getSite().getWorkbenchWindow()); |
| setAction(ITextEditorActionConstants.SAVE, fSaveAction); |
| |
| action= new RevertToSavedAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Revert.", this); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.REVERT_TO_SAVED_ACTION); |
| action.setActionDefinitionId(IWorkbenchCommandConstants.FILE_REVERT); |
| setAction(ITextEditorActionConstants.REVERT_TO_SAVED, action); |
| |
| action= new GotoLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.GotoLine.", this); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.GOTO_LINE_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.LINE_GOTO); |
| setAction(ITextEditorActionConstants.GOTO_LINE, action); |
| |
| action= new MoveLinesAction(EditorMessages.getBundleForConstructedKeys(), "Editor.MoveLinesUp.", this, getSourceViewer(), true, false); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.MOVE_LINES_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.MOVE_LINES_UP); |
| setAction(ITextEditorActionConstants.MOVE_LINE_UP, action); |
| |
| action= new MoveLinesAction(EditorMessages.getBundleForConstructedKeys(), "Editor.MoveLinesDown.", this, getSourceViewer(), false, false); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.MOVE_LINES_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.MOVE_LINES_DOWN); |
| setAction(ITextEditorActionConstants.MOVE_LINE_DOWN, action); |
| |
| action= new MoveLinesAction(EditorMessages.getBundleForConstructedKeys(), "Editor.CopyLineUp.", this, getSourceViewer(), true, true); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.COPY_LINES_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.COPY_LINES_UP); |
| setAction(ITextEditorActionConstants.COPY_LINE_UP, action); |
| |
| action= new MoveLinesAction(EditorMessages.getBundleForConstructedKeys(), "Editor.CopyLineDown.", this, getSourceViewer(), false, true); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.COPY_LINES_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.COPY_LINES_DOWN); |
| setAction(ITextEditorActionConstants.COPY_LINE_DOWN, action); |
| |
| action= new CaseAction(EditorMessages.getBundleForConstructedKeys(), "Editor.UpperCase.", this, true); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.UPPER_CASE_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.UPPER_CASE); |
| setAction(ITextEditorActionConstants.UPPER_CASE, action); |
| |
| action= new CaseAction(EditorMessages.getBundleForConstructedKeys(), "Editor.LowerCase.", this, false); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.LOWER_CASE_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.LOWER_CASE); |
| setAction(ITextEditorActionConstants.LOWER_CASE, action); |
| |
| action= new InsertLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.SmartEnter.", this, false); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.SMART_ENTER_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.SMART_ENTER); |
| setAction(ITextEditorActionConstants.SMART_ENTER, action); |
| |
| action= new InsertLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.SmartEnterInverse.", this, true); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.SMART_ENTER_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.SMART_ENTER_INVERSE); |
| setAction(ITextEditorActionConstants.SMART_ENTER_INVERSE, action); |
| |
| action= new ToggleInsertModeAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ToggleInsertMode."); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.TOGGLE_INSERT_MODE_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.TOGGLE_INSERT_MODE); |
| setAction(ITextEditorActionConstants.TOGGLE_INSERT_MODE, action); |
| |
| action= new HippieCompleteAction(EditorMessages.getBundleForConstructedKeys(), "Editor.HippieCompletion.", this); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.HIPPIE_COMPLETION_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.HIPPIE_COMPLETION); |
| setAction(ITextEditorActionConstants.HIPPIE_COMPLETION, action); |
| |
| action= new ContentAssistAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ContentAssistProposal.", this); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.CONTENT_ASSIST_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); |
| setAction(ITextEditorActionConstants.CONTENT_ASSIST, action); |
| markAsStateDependentAction(ITextEditorActionConstants.CONTENT_ASSIST, true); |
| |
| action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ContentAssistContextInformation.", this, ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.CONTENT_ASSIST_CONTEXT_INFORMATION_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_CONTEXT_INFORMATION); |
| setAction(ITextEditorActionConstants.CONTENT_ASSIST_CONTEXT_INFORMATION, action); |
| markAsStateDependentAction(ITextEditorActionConstants.CONTENT_ASSIST_CONTEXT_INFORMATION, true); |
| |
| action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.QuickAssist.", this, ISourceViewer.QUICK_ASSIST); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.QUICK_ASSIST_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.QUICK_ASSIST); |
| setAction(ITextEditorActionConstants.QUICK_ASSIST, action); |
| markAsStateDependentAction(ITextEditorActionConstants.QUICK_ASSIST, true); |
| |
| action= new GotoAnnotationAction(this, true); |
| setAction(ITextEditorActionConstants.NEXT, action); |
| action= new GotoAnnotationAction(this, false); |
| setAction(ITextEditorActionConstants.PREVIOUS, action); |
| |
| action= new RecenterAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Recenter.", this); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.RECENTER_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.RECENTER); |
| setAction(ITextEditorActionConstants.RECENTER, action); |
| |
| action= new ShowWhitespaceCharactersAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ShowWhitespaceCharacters.", this, getPreferenceStore()); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.SHOW_WHITESPACE_CHARACTERS_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.SHOW_WHITESPACE_CHARACTERS); |
| setAction(ITextEditorActionConstants.SHOW_WHITESPACE_CHARACTERS, action); |
| |
| action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ShowInformation.", this, ISourceViewer.INFORMATION, true); //$NON-NLS-1$ |
| action= new InformationDispatchAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ShowInformation.", (TextOperationAction) action); //$NON-NLS-1$ |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.SHOW_INFORMATION_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.SHOW_INFORMATION); |
| setAction(ITextEditorActionConstants.SHOW_INFORMATION, action); |
| |
| final BlockSelectionModeToggleAction blockAction= new BlockSelectionModeToggleAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ToggleBlockSelectionMode.", this); //$NON-NLS-1$ |
| action= blockAction; |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.BLOCK_SELECTION_MODE_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.BLOCK_SELECTION_MODE); |
| setAction(ITextEditorActionConstants.BLOCK_SELECTION_MODE, action); |
| |
| if (isWordWrapSupported()) { |
| final WordWrapToggleAction wrapAction= new WordWrapToggleAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ToggleWordWrap.", this, getInitialWordWrapStatus()); //$NON-NLS-1$ |
| action= wrapAction; |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.WORD_WRAP_TOGGLE_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.WORD_WRAP); |
| setAction(ITextEditorActionConstants.WORD_WRAP, action); |
| |
| blockAction.addPropertyChangeListener(new IPropertyChangeListener() { |
| @Override |
| public void propertyChange(PropertyChangeEvent event) { |
| if (IAction.CHECKED == event.getProperty() && |
| Boolean.TRUE.equals(event.getNewValue())) { |
| wrapAction.setChecked(false); |
| } |
| } |
| }); |
| wrapAction.addPropertyChangeListener(new IPropertyChangeListener() { |
| @Override |
| public void propertyChange(PropertyChangeEvent event) { |
| if (IAction.CHECKED == event.getProperty() && |
| Boolean.TRUE.equals(event.getNewValue())) { |
| blockAction.setChecked(false); |
| } |
| } |
| }); |
| } |
| |
| action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.OpenHyperlink.", this, HyperlinkManager.OPEN_HYPERLINK, true); //$NON-NLS-1$; |
| action.setHelpContextId(IAbstractTextEditorHelpContextIds.OPEN_HYPERLINK_ACTION); |
| action.setActionDefinitionId(ITextEditorActionDefinitionIds.OPEN_HYPERLINK); |
| setAction(ITextEditorActionConstants.OPEN_HYPERLINK, action); |
| |
| PropertyDialogAction openProperties= new PropertyDialogAction( |
| new IShellProvider() { |
| @Override |
| public Shell getShell() { |
| return getSite().getShell(); |
| } |
| }, |
| new ISelectionProvider() { |
| @Override |
| public void addSelectionChangedListener(ISelectionChangedListener listener) { |
| } |
| @Override |
| public ISelection getSelection() { |
| return new StructuredSelection(getEditorInput()); |
| } |
| @Override |
| public void removeSelectionChangedListener(ISelectionChangedListener listener) { |
| } |
| @Override |
| public void setSelection(ISelection selection) { |
| } |
| }); |
| openProperties.setActionDefinitionId(IWorkbenchCommandConstants.FILE_PROPERTIES); |
| setAction(ITextEditorActionConstants.PROPERTIES, openProperties); |
| |
| markAsContentDependentAction(ITextEditorActionConstants.UNDO, true); |
| markAsContentDependentAction(ITextEditorActionConstants.REDO, true); |
| markAsContentDependentAction(ITextEditorActionConstants.FIND, true); |
| markAsContentDependentAction(ITextEditorActionConstants.FIND_NEXT, true); |
| markAsContentDependentAction(ITextEditorActionConstants.FIND_PREVIOUS, true); |
| markAsContentDependentAction(ITextEditorActionConstants.FIND_INCREMENTAL, true); |
| markAsContentDependentAction(ITextEditorActionConstants.FIND_INCREMENTAL_REVERSE, true); |
| |
| markAsSelectionDependentAction(ITextEditorActionConstants.CUT, true); |
| markAsSelectionDependentAction(ITextEditorActionConstants.COPY, true); |
| markAsSelectionDependentAction(ITextEditorActionConstants.PASTE, true); |
| markAsSelectionDependentAction(ITextEditorActionConstants.DELETE, true); |
| markAsSelectionDependentAction(ITextEditorActionConstants.SHIFT_RIGHT, true); |
| markAsSelectionDependentAction(ITextEditorActionConstants.SHIFT_RIGHT_TAB, true); |
| markAsSelectionDependentAction(ITextEditorActionConstants.UPPER_CASE, true); |
| markAsSelectionDependentAction(ITextEditorActionConstants.LOWER_CASE, true); |
| |
| markAsPropertyDependentAction(ITextEditorActionConstants.UNDO, true); |
| markAsPropertyDependentAction(ITextEditorActionConstants.REDO, true); |
| markAsPropertyDependentAction(ITextEditorActionConstants.REVERT_TO_SAVED, true); |
| markAsPropertyDependentAction(ITextEditorActionConstants.SAVE, true); |
| |
| markAsStateDependentAction(ITextEditorActionConstants.UNDO, true); |
| markAsStateDependentAction(ITextEditorActionConstants.REDO, true); |
| markAsStateDependentAction(ITextEditorActionConstants.CUT, true); |
| markAsStateDependentAction(ITextEditorActionConstants.PASTE, true); |
| markAsStateDependentAction(ITextEditorActionConstants.DELETE, true); |
| markAsStateDependentAction(ITextEditorActionConstants.SHIFT_RIGHT, true); |
| markAsStateDependentAction(ITextEditorActionConstants.SHIFT_RIGHT_TAB, true); |
| markAsStateDependentAction(ITextEditorActionConstants.SHIFT_LEFT, true); |
| markAsStateDependentAction(ITextEditorActionConstants.FIND, true); |
| markAsStateDependentAction(ITextEditorActionConstants.DELETE_LINE, true); |
| markAsStateDependentAction(ITextEditorActionConstants.DELETE_LINE_TO_BEGINNING, true); |
| markAsStateDependentAction(ITextEditorActionConstants.DELETE_LINE_TO_END, true); |
| markAsStateDependentAction(ITextEditorActionConstants.MOVE_LINE_UP, true); |
| markAsStateDependentAction(ITextEditorActionConstants.MOVE_LINE_DOWN, true); |
| markAsStateDependentAction(ITextEditorActionConstants.CUT_LINE, true); |
| markAsStateDependentAction(ITextEditorActionConstants.CUT_LINE_TO_BEGINNING, true); |
| markAsStateDependentAction(ITextEditorActionConstants.CUT_LINE_TO_END, true); |
| |
| setActionActivationCode(ITextEditorActionConstants.SHIFT_RIGHT_TAB,'\t', -1, SWT.NONE); |
| setActionActivationCode(ITextEditorActionConstants.SHIFT_LEFT, '\t', -1, SWT.SHIFT); |
| } |
| |
| /** |
| * Convenience method to add the action installed under the given action id to the given menu. |
| * @param menu the menu to add the action to |
| * @param actionId the id of the action to be added |
| */ |
| protected final void addAction(IMenuManager menu, String actionId) { |
| IAction action= getAction(actionId); |
| if (action != null) { |
| if (action instanceof IUpdate) |
| ((IUpdate) action).update(); |
| menu.add(action); |
| } |
| } |
| |
| /** |
| * Convenience method to add the action installed under the given action id to the specified group of the menu. |
| * @param menu the menu to add the action to |
| * @param group the group in the menu |
| * @param actionId the id of the action to add |
| */ |
| protected final void addAction(IMenuManager menu, String group, String actionId) { |
| IAction action= getAction(actionId); |
| if (action != null) { |
| if (action instanceof IUpdate) |
| ((IUpdate) action).update(); |
| |
| IMenuManager subMenu= menu.findMenuUsingPath(group); |
| if (subMenu != null) |
| subMenu.add(action); |
| else |
| menu.appendToGroup(group, action); |
| } |
| } |
| |
| /** |
| * Convenience method to add a new group after the specified group. |
| * @param menu the menu to add the new group to |
| * @param existingGroup the group after which to insert the new group |
| * @param newGroup the new group |
| */ |
| protected final void addGroup(IMenuManager menu, String existingGroup, String newGroup) { |
| IMenuManager subMenu= menu.findMenuUsingPath(existingGroup); |
| if (subMenu != null) |
| subMenu.add(new Separator(newGroup)); |
| else |
| menu.appendToGroup(existingGroup, new Separator(newGroup)); |
| } |
| |
| /** |
| * Sets up the ruler context menu before it is made visible. |
| * <p> |
| * Subclasses may extend to add other actions.</p> |
| * |
| * @param menu the menu |
| */ |
| protected void rulerContextMenuAboutToShow(IMenuManager menu) { |
| |
| menu.add(new Separator(ITextEditorActionConstants.GROUP_REST)); |
| menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); |
| |
| for (Iterator<IMenuListener> i= fRulerContextMenuListeners.iterator(); i.hasNext();) |
| i.next().menuAboutToShow(menu); |
| |
| addAction(menu, ITextEditorActionConstants.RULER_MANAGE_BOOKMARKS); |
| addAction(menu, ITextEditorActionConstants.RULER_MANAGE_TASKS); |
| } |
| |
| /** |
| * Sets up this editor's context menu before it is made visible. |
| * <p> |
| * Subclasses may extend to add other actions.</p> |
| * |
| * @param menu the menu |
| */ |
| protected void editorContextMenuAboutToShow(IMenuManager menu) { |
| |
| menu.add(new Separator(ITextEditorActionConstants.GROUP_UNDO)); |
| menu.add(new GroupMarker(ITextEditorActionConstants.GROUP_SAVE)); |
| menu.add(new Separator(ITextEditorActionConstants.GROUP_COPY)); |
| menu.add(new Separator(ITextEditorActionConstants.GROUP_PRINT)); |
| menu.add(new Separator(ITextEditorActionConstants.GROUP_EDIT)); |
| menu.add(new Separator(ITextEditorActionConstants.GROUP_FIND)); |
| menu.add(new Separator(IWorkbenchActionConstants.GROUP_ADD)); |
| menu.add(new Separator(ITextEditorActionConstants.GROUP_REST)); |
| menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); |
| |
| if (isEditable()) { |
| addAction(menu, ITextEditorActionConstants.GROUP_UNDO, ITextEditorActionConstants.UNDO); |
| addAction(menu, ITextEditorActionConstants.GROUP_UNDO, ITextEditorActionConstants.REVERT_TO_SAVED); |
| addAction(menu, ITextEditorActionConstants.GROUP_SAVE, ITextEditorActionConstants.SAVE); |
| addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.CUT); |
| addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.COPY); |
| addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.PASTE); |
| IAction action= getAction(ITextEditorActionConstants.QUICK_ASSIST); |
| if (action != null && action.isEnabled()) |
| addAction(menu, ITextEditorActionConstants.GROUP_EDIT, ITextEditorActionConstants.QUICK_ASSIST); |
| } else { |
| addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.COPY); |
| } |
| } |
| |
| /** |
| * Returns the status line manager of this editor. |
| * |
| * @return the status line manager of this editor |
| * @since 2.0, protected since 3.3 |
| */ |
| protected IStatusLineManager getStatusLineManager() { |
| return getEditorSite().getActionBars().getStatusLineManager(); |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Override |
| public <T> T getAdapter(Class<T> required) { |
| |
| if (IEditorStatusLine.class.equals(required)) { |
| if (fEditorStatusLine == null) { |
| IStatusLineManager statusLineManager= getStatusLineManager(); |
| ISelectionProvider selectionProvider= getSelectionProvider(); |
| if (statusLineManager != null && selectionProvider != null) |
| fEditorStatusLine= new EditorStatusLine(statusLineManager, selectionProvider); |
| } |
| return (T) fEditorStatusLine; |
| } |
| |
| if (IVerticalRulerInfo.class.equals(required)) { |
| if (fVerticalRuler != null) |
| return (T) fVerticalRuler; |
| } |
| |
| if (IMarkRegionTarget.class.equals(required)) { |
| if (fMarkRegionTarget == null) { |
| IStatusLineManager manager= getStatusLineManager(); |
| if (manager != null) |
| fMarkRegionTarget= (fSourceViewer == null ? null : new MarkRegionTarget(fSourceViewer, manager)); |
| } |
| return (T) fMarkRegionTarget; |
| } |
| |
| if (IDeleteLineTarget.class.equals(required)) { |
| if (fDeleteLineTarget == null) { |
| fDeleteLineTarget= new TextViewerDeleteLineTarget(fSourceViewer); |
| } |
| return (T) fDeleteLineTarget; |
| } |
| |
| if (IncrementalFindTarget.class.equals(required)) { |
| if (fIncrementalFindTarget == null) { |
| IStatusLineManager manager= getStatusLineManager(); |
| if (manager != null) |
| fIncrementalFindTarget= (fSourceViewer == null ? null : new IncrementalFindTarget(fSourceViewer, manager)); |
| } |
| return (T) fIncrementalFindTarget; |
| } |
| |
| if (IFindReplaceTarget.class.equals(required)) { |
| if (fFindReplaceTarget == null) { |
| IFindReplaceTarget target= (fSourceViewer == null ? null : fSourceViewer.getFindReplaceTarget()); |
| if (target != null) { |
| fFindReplaceTarget= new FindReplaceTarget(this, target); |
| if (fFindScopeHighlightColor != null) |
| fFindReplaceTarget.setScopeHighlightColor(fFindScopeHighlightColor); |
| } |
| } |
| return (T) fFindReplaceTarget; |
| } |
| |
| if (ITextOperationTarget.class.equals(required)) |
| return (fSourceViewer == null ? null : (T) fSourceViewer.getTextOperationTarget()); |
| |
| if (IRewriteTarget.class.equals(required)) { |
| if (fSourceViewer instanceof ITextViewerExtension) { |
| ITextViewerExtension extension= (ITextViewerExtension) fSourceViewer; |
| return (T) extension.getRewriteTarget(); |
| } |
| return null; |
| } |
| |
| if (Control.class.equals(required)) |
| return fSourceViewer != null ? (T) fSourceViewer.getTextWidget() : null; |
| |
| if (IColumnSupport.class.equals(required)) { |
| if (fColumnSupport == null) |
| fColumnSupport= createColumnSupport(); |
| return (T) fColumnSupport; |
| } |
| |
| return super.getAdapter(required); |
| } |
| |
| @Override |
| public void setFocus() { |
| if (fSourceViewer != null && fSourceViewer.getTextWidget() != null) |
| fSourceViewer.getTextWidget().setFocus(); |
| } |
| |
| @Override |
| public boolean showsHighlightRangeOnly() { |
| return fShowHighlightRangeOnly; |
| } |
| |
| @Override |
| public void showHighlightRangeOnly(boolean showHighlightRangeOnly) { |
| fShowHighlightRangeOnly= showHighlightRangeOnly; |
| } |
| |
| @Override |
| public void setHighlightRange(int offset, int length, boolean moveCursor) { |
| if (fSourceViewer == null) |
| return; |
| |
| if (fShowHighlightRangeOnly) { |
| if (moveCursor) |
| fSourceViewer.setVisibleRegion(offset, length); |
| } else { |
| IRegion rangeIndication= fSourceViewer.getRangeIndication(); |
| if (rangeIndication == null || offset != rangeIndication.getOffset() || length != rangeIndication.getLength()) |
| fSourceViewer.setRangeIndication(offset, length, moveCursor); |
| } |
| } |
| |
| @Override |
| public IRegion getHighlightRange() { |
| if (fSourceViewer == null) |
| return null; |
| |
| if (fShowHighlightRangeOnly) |
| return getCoverage(fSourceViewer); |
| |
| return fSourceViewer.getRangeIndication(); |
| } |
| |
| /* |
| * @see ITextEditor#resetHighlightRange |
| */ |
| @Override |
| public void resetHighlightRange() { |
| if (fSourceViewer == null) |
| return; |
| |
| if (fShowHighlightRangeOnly) |
| fSourceViewer.resetVisibleRegion(); |
| else |
| fSourceViewer.removeRangeIndication(); |
| } |
| |
| /** |
| * Adjusts the highlight range so that at least the specified range |
| * is highlighted. |
| * <p> |
| * Subclasses may re-implement this method.</p> |
| * |
| * @param offset the offset of the range which at least should be highlighted |
| * @param length the length of the range which at least should be highlighted |
| */ |
| protected void adjustHighlightRange(int offset, int length) { |
| if (fSourceViewer == null) |
| return; |
| |
| if (fSourceViewer instanceof ITextViewerExtension5) { |
| ITextViewerExtension5 extension= (ITextViewerExtension5) fSourceViewer; |
| extension.exposeModelRange(new Region(offset, length)); |
| } else if (!isVisible(fSourceViewer, offset, length)) { |
| fSourceViewer.resetVisibleRegion(); |
| } |
| } |
| |
| @Override |
| public void selectAndReveal(int start, int length) { |
| selectAndReveal(start, length, start, length); |
| } |
| |
| /** |
| * Selects and reveals the specified ranges in this text editor. |
| * |
| * @param selectionStart the offset of the selection |
| * @param selectionLength the length of the selection |
| * @param revealStart the offset of the revealed range |
| * @param revealLength the length of the revealed range |
| * @since 3.0 |
| */ |
| protected void selectAndReveal(int selectionStart, int selectionLength, int revealStart, int revealLength) { |
| if (fSourceViewer == null) |
| return; |
| |
| ISelection selection= getSelectionProvider().getSelection(); |
| if (selection instanceof ITextSelection) { |
| ITextSelection textSelection= (ITextSelection) selection; |
| if (textSelection.getOffset() != 0 || textSelection.getLength() != 0) |
| markInNavigationHistory(); |
| } |
| |
| StyledText widget= fSourceViewer.getTextWidget(); |
| widget.setRedraw(false); |
| { |
| adjustHighlightRange(revealStart, revealLength); |
| fSourceViewer.revealRange(revealStart, revealLength); |
| |
| fSourceViewer.setSelectedRange(selectionStart, selectionLength); |
| |
| markInNavigationHistory(); |
| } |
| widget.setRedraw(true); |
| } |
| |
| /* |
| * @see org.eclipse.ui.INavigationLocationProvider#createNavigationLocation() |
| * @since 2.1 |
| */ |
| @Override |
| public INavigationLocation createEmptyNavigationLocation() { |
| return new TextSelectionNavigationLocation(this, false); |
| } |
| |
| @Override |
| public INavigationLocation createNavigationLocation() { |
| return new TextSelectionNavigationLocation(this, true); |
| } |
| |
| /** |
| * Writes a check mark of the given situation into the navigation history. |
| * @since 2.1 |
| */ |
| protected void markInNavigationHistory() { |
| getSite().getPage().getNavigationHistory().markLocation(this); |
| } |
| |
| /** |
| * Hook which gets called when the editor has been saved. |
| * Subclasses may extend. |
| * @since 2.1 |
| */ |
| protected void editorSaved() { |
| INavigationLocation[] locations= getSite().getPage().getNavigationHistory().getLocations(); |
| IEditorInput input= getEditorInput(); |
| for (int i= 0; i < locations.length; i++) { |
| if (locations[i] instanceof TextSelectionNavigationLocation) { |
| if(input.equals(locations[i].getInput())) { |
| TextSelectionNavigationLocation location= (TextSelectionNavigationLocation) locations[i]; |
| location.partSaved(this); |
| } |
| } |
| } |
| } |
| |
| @Override |
| protected void firePropertyChange(int property) { |
| super.firePropertyChange(property); |
| updatePropertyDependentActions(); |
| } |
| |
| @Override |
| public void setStatusField(IStatusField field, String category) { |
| Assert.isNotNull(category); |
| if (field != null) { |
| |
| if (fStatusFields == null) |
| fStatusFields= new HashMap<>(3); |
| |
| fStatusFields.put(category, field); |
| updateStatusField(category); |
| |
| } else if (fStatusFields != null) |
| fStatusFields.remove(category); |
| |
| if (fIncrementalFindTarget != null && ITextEditorActionConstants.STATUS_CATEGORY_FIND_FIELD.equals(category)) |
| fIncrementalFindTarget.setStatusField(field); |
| } |
| |
| /** |
| * Returns the current status field for the given status category. |
| * |
| * @param category the status category |
| * @return the current status field for the given status category |
| * @since 2.0 |
| */ |
| protected IStatusField getStatusField(String category) { |
| if (category != null && fStatusFields != null) |
| return fStatusFields.get(category); |
| return null; |
| } |
| |
| /** |
| * Returns whether this editor is in overwrite or insert mode. |
| * |
| * @return <code>true</code> if in insert mode, <code>false</code> for overwrite mode |
| * @since 2.0 |
| */ |
| protected boolean isInInsertMode() { |
| return !fIsOverwriting; |
| } |
| |
| @Override |
| public InsertMode getInsertMode() { |
| return fInsertMode; |
| } |
| |
| @Override |
| public void setInsertMode(InsertMode newMode) { |
| List<InsertMode> legalModes= getLegalInsertModes(); |
| if (!legalModes.contains(newMode)) |
| throw new IllegalArgumentException(); |
| |
| fInsertMode= newMode; |
| |
| handleInsertModeChanged(); |
| } |
| |
| /** |
| * Returns the set of legal insert modes. If insert modes are configured all defined insert modes |
| * are legal. |
| * |
| * @return the set of legal insert modes |
| * @since 3.0 |
| */ |
| protected List<InsertMode> getLegalInsertModes() { |
| if (fLegalInsertModes == null) { |
| fLegalInsertModes= new ArrayList<>(); |
| fLegalInsertModes.add(SMART_INSERT); |
| fLegalInsertModes.add(INSERT); |
| } |
| return fLegalInsertModes; |
| } |
| |
| private void switchToNextInsertMode() { |
| |
| InsertMode mode= getInsertMode(); |
| List<InsertMode> legalModes= getLegalInsertModes(); |
| |
| int i= 0; |
| while (i < legalModes.size()) { |
| if (legalModes.get(i) == mode) break; |
| ++ i; |
| } |
| |
| i= (i + 1) % legalModes.size(); |
| InsertMode newMode= legalModes.get(i); |
| setInsertMode(newMode); |
| } |
| |
| private void toggleOverwriteMode() { |
| if (fIsOverwriteModeEnabled) { |
| fIsOverwriting= !fIsOverwriting; |
| fSourceViewer.getTextWidget().invokeAction(ST.TOGGLE_OVERWRITE); |
| handleInsertModeChanged(); |
| } |
| } |
| |
| /** |
| * Configures the given insert mode as legal or illegal. This call is ignored if the set of legal |
| * input modes would be empty after the call. |
| * |
| * @param mode the insert mode to be configured |
| * @param legal <code>true</code> if the given mode is legal, <code>false</code> otherwise |
| * @since 3.0 |
| */ |
| protected void configureInsertMode(InsertMode mode, boolean legal) { |
| List<InsertMode> legalModes= getLegalInsertModes(); |
| if (legal) { |
| if (!legalModes.contains(mode)) |
| legalModes.add(mode); |
| } else if (legalModes.size() > 1) { |
| if (getInsertMode() == mode) |
| switchToNextInsertMode(); |
| legalModes.remove(mode); |
| } |
| } |
| |
| /** |
| * Sets the overwrite mode enablement. |
| * |
| * @param enable <code>true</code> to enable new overwrite mode, |
| * <code>false</code> to disable |
| * @since 3.0 |
| */ |
| protected void enableOverwriteMode(boolean enable) { |
| if (fIsOverwriting && !enable) |
| toggleOverwriteMode(); |
| fIsOverwriteModeEnabled= enable; |
| } |
| |
| private Caret createOverwriteCaret(StyledText styledText) { |
| Caret caret= new Caret(styledText, SWT.NULL); |
| GC gc= new GC(styledText); |
| // XXX: this overwrite box is not proportional-font aware |
| // take 'a' as a medium sized character |
| Point charSize= gc.stringExtent("a"); //$NON-NLS-1$ |
| |
| // XXX: Filed request to get a caret with auto-height: https://bugs.eclipse.org/bugs/show_bug.cgi?id=118612 |
| caret.setSize(charSize.x, styledText.getLineHeight()); |
| caret.setFont(styledText.getFont()); |
| |
| gc.dispose(); |
| |
| return caret; |
| } |
| |
| private Caret createInsertCaret(StyledText styledText) { |
| Caret caret= new Caret(styledText, SWT.NULL); |
| |
| // XXX: Filed request to get a caret with auto-height: https://bugs.eclipse.org/bugs/show_bug.cgi?id=118612 |
| caret.setSize(getCaretWidthPreference(), styledText.getLineHeight()); |
| caret.setFont(styledText.getFont()); |
| |
| return caret; |
| } |
| |
| private Image createRawInsertModeCaretImage(StyledText styledText) { |
| |
| PaletteData caretPalette= new PaletteData(new RGB[] {new RGB (0,0,0), new RGB (255,255,255)}); |
| int width= getCaretWidthPreference(); |
| int widthOffset= width - 1; |
| |
| // XXX: Filed request to get a caret with auto-height: https://bugs.eclipse.org/bugs/show_bug.cgi?id=118612 |
| ImageData imageData= new ImageData(4 + widthOffset, styledText.getLineHeight(), 1, caretPalette); |
| |
| Display display= styledText.getDisplay(); |
| Image bracketImage= new Image(display, imageData); |
| GC gc= new GC (bracketImage); |
| gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE)); |
| gc.setLineWidth(0); // NOTE: 0 means width is 1 but with optimized performance |
| int height= imageData.height / 3; |
| // gap between two bars of one third of the height |
| // draw boxes using lines as drawing a line of a certain width produces |
| // rounded corners. |
| for (int i= 0; i < width ; i++) { |
| gc.drawLine(i, 0, i, height - 1); |
| gc.drawLine(i, imageData.height - height, i, imageData.height - 1); |
| } |
| |
| gc.dispose(); |
| |
| return bracketImage; |
| } |
| |
| private Caret createRawInsertModeCaret(StyledText styledText) { |
| // don't draw special raw caret if no smart mode is enabled |
| if (!getLegalInsertModes().contains(SMART_INSERT)) |
| return createInsertCaret(styledText); |
| |
| Caret caret= new Caret(styledText, SWT.NULL); |
| Image image= createRawInsertModeCaretImage(styledText); |
| caret.setImage(image); |
| caret.setFont(styledText.getFont()); |
| |
| return caret; |
| } |
| |
| private int getCaretWidthPreference() { |
| if (getPreferenceStore() != null && getPreferenceStore().getBoolean(PREFERENCE_WIDE_CARET)) |
| return WIDE_CARET_WIDTH; |
| |
| return SINGLE_CARET_WIDTH; |
| } |
| |
| private void updateCaret() { |
| if (fSourceViewer == null || fSourceViewer.getTextWidget() == null) { |
| return; |
| } |
| |
| StyledText styledText= fSourceViewer.getTextWidget(); |
| |
| InsertMode mode= getInsertMode(); |
| |
| styledText.setCaret(null); |
| disposeNonDefaultCaret(); |
| |
| if (getPreferenceStore() == null || !getPreferenceStore().getBoolean(PREFERENCE_USE_CUSTOM_CARETS)) |
| Assert.isTrue(fNonDefaultCaret == null); |
| else if (fIsOverwriting) |
| fNonDefaultCaret= createOverwriteCaret(styledText); |
| else if (SMART_INSERT == mode) |
| fNonDefaultCaret= createInsertCaret(styledText); |
| else if (INSERT == mode) |
| fNonDefaultCaret= createRawInsertModeCaret(styledText); |
| |
| if (fNonDefaultCaret != null) { |
| styledText.setCaret(fNonDefaultCaret); |
| fNonDefaultCaretImage= fNonDefaultCaret.getImage(); |
| } else if (fInitialCaret != styledText.getCaret()) |
| styledText.setCaret(fInitialCaret); |
| } |
| |
| private void disposeNonDefaultCaret() { |
| if (fNonDefaultCaretImage != null) { |
| fNonDefaultCaretImage.dispose(); |
| fNonDefaultCaretImage= null; |
| } |
| |
| if (fNonDefaultCaret != null) { |
| fNonDefaultCaret.dispose(); |
| fNonDefaultCaret= null; |
| } |
| } |
| |
| /** |
| * Handles a change of the editor's insert mode. |
| * Subclasses may extend. |
| * |
| * @since 2.0 |
| */ |
| protected void handleInsertModeChanged() { |
| updateInsertModeAction(); |
| updateCaret(); |
| updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_MODE); |
| } |
| |
| private void updateInsertModeAction() { |
| |
| // this may be called before the part is fully initialized (see configureInsertMode) |
| // drop out in this case. |
| if (getSite() == null) |
| return; |
| |
| IAction action= getAction(ITextEditorActionConstants.TOGGLE_INSERT_MODE); |
| if (action != null) { |
| action.setEnabled(!fIsOverwriting); |
| action.setChecked(fInsertMode == SMART_INSERT); |
| } |
| } |
| |
| /** |
| * Handles a potential change of the cursor position. |
| * Subclasses may extend. |
| * |
| * @since 2.0 |
| */ |
| protected void handleCursorPositionChanged() { |
| updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_POSITION); |
| } |
| |
| /** |
| * Updates the status fields for the given category. |
| * |
| * @param category the category |
| * @since 2.0 |
| */ |
| protected void updateStatusField(String category) { |
| |
| if (category == null) |
| return; |
| |
| IStatusField field= getStatusField(category); |
| if (field != null) { |
| |
| String text= null; |
| |
| if (ITextEditorActionConstants.STATUS_CATEGORY_INPUT_POSITION.equals(category)) |
| text= getCursorPosition(); |
| else if (ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE.equals(category)) |
| text= isEditorInputReadOnly() ? fReadOnlyLabel : fWritableLabel; |
| else if (ITextEditorActionConstants.STATUS_CATEGORY_INPUT_MODE.equals(category)) { |
| InsertMode mode= getInsertMode(); |
| if (fIsOverwriting) |
| text= fOverwriteModeLabel; |
| else if (INSERT == mode) |
| text= fInsertModeLabel; |
| else if (SMART_INSERT == mode) |
| text= fSmartInsertModeLabel; |
| } |
| |
| field.setText(text == null ? fErrorLabel : text); |
| } |
| } |
| |
| /** |
| * Updates all status fields. |
| * |
| * @since 2.0 |
| */ |
| protected void updateStatusFields() { |
| if (fStatusFields != null) { |
| Iterator<String> e= fStatusFields.keySet().iterator(); |
| while (e.hasNext()) |
| updateStatusField(e.next()); |
| } |
| } |
| |
| /** |
| * Returns a description of the cursor position. |
| * |
| * @return a description of the cursor position |
| * @since 2.0 |
| */ |
| protected String getCursorPosition() { |
| |
| if (fSourceViewer == null) |
| return fErrorLabel; |
| |
| StyledText styledText= fSourceViewer.getTextWidget(); |
| int caret= widgetOffset2ModelOffset(fSourceViewer, styledText.getCaretOffset()); |
| IDocument document= fSourceViewer.getDocument(); |
| |
| if (document == null) |
| return fErrorLabel; |
| |
| try { |
| |
| int line= document.getLineOfOffset(caret); |
| |
| int lineOffset= document.getLineOffset(line); |
| int tabWidth= styledText.getTabs(); |
| int column= 0; |
| for (int i= lineOffset; i < caret; i++) |
| if ('\t' == document.getChar(i)) |
| column += tabWidth - (tabWidth == 0 ? 0 : column % tabWidth); |
| else |
| column++; |
| |
| fLineLabel.fValue= line + 1; |
| fColumnLabel.fValue= column + 1; |
| return NLSUtility.format(fPositionLabelPattern, fPositionLabelPatternArguments); |
| |
| } catch (BadLocationException x) { |
| return fErrorLabel; |
| } |
| } |
| |
| @Override |
| public boolean isEditorInputReadOnly() { |
| IDocumentProvider provider= getDocumentProvider(); |
| if (provider instanceof IDocumentProviderExtension) { |
| IDocumentProviderExtension extension= (IDocumentProviderExtension) provider; |
| return extension.isReadOnly(getEditorInput()); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean isEditorInputModifiable() { |
| IDocumentProvider provider= getDocumentProvider(); |
| if (provider instanceof IDocumentProviderExtension) { |
| IDocumentProviderExtension extension= (IDocumentProviderExtension) provider; |
| return extension.isModifiable(getEditorInput()); |
| } |
| return true; |
| } |
| |
| @Override |
| public void addRulerContextMenuListener(IMenuListener listener) { |
| fRulerContextMenuListeners.add(listener); |
| } |
| |
| @Override |
| public void removeRulerContextMenuListener(IMenuListener listener) { |
| fRulerContextMenuListeners.remove(listener); |
| } |
| |
| /** |
| * Returns whether this editor can handle the move of the original element |
| * so that it ends up being the moved element. By default this method |
| * returns <code>true</code>. Subclasses may reimplement. |
| * |
| * @param originalElement the original element |
| * @param movedElement the moved element |
| * @return whether this editor can handle the move of the original element |
| * so that it ends up being the moved element |
| * @since 2.0 |
| */ |
| protected boolean canHandleMove(IEditorInput originalElement, IEditorInput movedElement) { |
| return true; |
| } |
| |
| /** |
| * Returns the offset of the given source viewer's document that corresponds |
| * to the given widget offset or <code>-1</code> if there is no such offset. |
| * |
| * @param viewer the source viewer |
| * @param widgetOffset the widget offset |
| * @return the corresponding offset in the source viewer's document or <code>-1</code> |
| * @since 2.1 |
| */ |
| protected static final int widgetOffset2ModelOffset(ISourceViewer viewer, int widgetOffset) { |
| if (viewer instanceof ITextViewerExtension5) { |
| ITextViewerExtension5 extension= (ITextViewerExtension5) viewer; |
| return extension.widgetOffset2ModelOffset(widgetOffset); |
| } |
| return widgetOffset + viewer.getVisibleRegion().getOffset(); |
| } |
| |
| /** |
| * Returns the offset of the given source viewer's text widget that corresponds |
| * to the given model offset or <code>-1</code> if there is no such offset. |
| * |
| * @param viewer the source viewer |
| * @param modelOffset the model offset |
| * @return the corresponding offset in the source viewer's text widget or <code>-1</code> |
| * @since 3.0 |
| */ |
| protected static final int modelOffset2WidgetOffset(ISourceViewer viewer, int modelOffset) { |
| if (viewer instanceof ITextViewerExtension5) { |
| ITextViewerExtension5 extension= (ITextViewerExtension5) viewer; |
| return extension.modelOffset2WidgetOffset(modelOffset); |
| } |
| return modelOffset - viewer.getVisibleRegion().getOffset(); |
| } |
| |
| /** |
| * Returns the minimal region of the given source viewer's document that completely |
| * comprises everything that is visible in the viewer's widget. |
| * |
| * @param viewer the viewer go return the coverage for |
| * @return the minimal region of the source viewer's document comprising the contents of the viewer's widget |
| * @since 2.1 |
| */ |
| protected static final IRegion getCoverage(ISourceViewer viewer) { |
| if (viewer instanceof ITextViewerExtension5) { |
| ITextViewerExtension5 extension= (ITextViewerExtension5) viewer; |
| return extension.getModelCoverage(); |
| } |
| return viewer.getVisibleRegion(); |
| } |
| |
| /** |
| * Tells whether the given region is visible in the given source viewer. |
| * |
| * @param viewer the source viewer |
| * @param offset the offset of the region |
| * @param length the length of the region |
| * @return <code>true</code> if visible |
| * @since 2.1 |
| */ |
| protected static final boolean isVisible(ISourceViewer viewer, int offset, int length) { |
| if (viewer instanceof ITextViewerExtension5) { |
| ITextViewerExtension5 extension= (ITextViewerExtension5) viewer; |
| IRegion overlap= extension.modelRange2WidgetRange(new Region(offset, length)); |
| return overlap != null; |
| } |
| return viewer.overlapsWithVisibleRegion(offset, length); |
| } |
| |
| @Override |
| public void showChangeInformation(boolean show) { |
| // do nothing |
| } |
| |
| @Override |
| public boolean isChangeInformationShowing() { |
| return false; |
| } |
| |
| /** |
| * Sets the given message as error message to this editor's status line. |
| * |
| * @param message message to be set |
| * @since 3.2 |
| */ |
| protected void setStatusLineErrorMessage(String message) { |
| IEditorStatusLine statusLine= getAdapter(IEditorStatusLine.class); |
| if (statusLine != null) |
| statusLine.setMessage(true, message, null); |
| } |
| |
| /** |
| * Sets the given message as message to this editor's status line. |
| * |
| * @param message message to be set |
| * @since 3.2 |
| */ |
| protected void setStatusLineMessage(String message) { |
| IEditorStatusLine statusLine= getAdapter(IEditorStatusLine.class); |
| if (statusLine != null) |
| statusLine.setMessage(false, message, null); |
| } |
| |
| /** |
| * Jumps to the next annotation according to the given direction. |
| * |
| * @param forward <code>true</code> if search direction is forward, <code>false</code> if backward |
| * @return the selected annotation or <code>null</code> if none |
| * @see #isNavigationTarget(Annotation) |
| * @see #findAnnotation(int, int, boolean, Position) |
| * @since 3.2 |
| */ |
| @Override |
| public Annotation gotoAnnotation(boolean forward) { |
| ITextSelection selection= (ITextSelection) getSelectionProvider().getSelection(); |
| Position position= new Position(0, 0); |
| Annotation annotation= findAnnotation(selection.getOffset(), selection.getLength(), forward, position); |
| setStatusLineErrorMessage(null); |
| setStatusLineMessage(null); |
| |
| if (annotation != null) { |
| selectAndReveal(position.getOffset(), position.getLength()); |
| setStatusLineMessage(annotation.getText()); |
| } |
| return annotation; |
| } |
| |
| /** |
| * Returns the annotation closest to the given range respecting the given |
| * direction. If an annotation is found, the annotations current position |
| * is copied into the provided annotation position. |
| * |
| * @param offset the region offset |
| * @param length the region length |
| * @param forward <code>true</code> for forwards, <code>false</code> for backward |
| * @param annotationPosition the position of the found annotation |
| * @return the found annotation |
| * @since 3.2 |
| */ |
| 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 = 0; |
| if (document != null) { |
| endOfDocument = document.getLength(); |
| } |
| int distance= Integer.MAX_VALUE; |
| |
| IAnnotationModel model= getDocumentProvider().getAnnotationModel(getEditorInput()); |
| Iterator<Annotation> e= model.getAnnotationIterator(); |
| while (e.hasNext()) { |
| Annotation a= e.next(); |
| if (!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 whether the given annotation is configured as a target for the |
| * "Go to Next/Previous Annotation" actions. |
| * <p> |
| * Per default every annotation is a target. |
| * </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) { |
| return true; |
| } |
| |
| @Override |
| public void showRevisionInformation(RevisionInformation info, String quickDiffProviderId) { |
| // no implementation |
| } |
| |
| @Override |
| public void restoreState(IMemento memento) { |
| fMementoToRestore= memento; |
| } |
| |
| @Override |
| public void saveState(IMemento memento) { |
| ISelection selection= doGetSelection(); |
| if (selection instanceof ITextSelection) { |
| memento.putInteger(TAG_SELECTION_OFFSET, ((ITextSelection)selection).getOffset()); |
| memento.putInteger(TAG_SELECTION_LENGTH, ((ITextSelection)selection).getLength()); |
| } |
| final StyledText textWidget= fSourceViewer.getTextWidget(); |
| memento.putInteger(TAG_SELECTION_TOP_PIXEL, textWidget.getTopPixel()); |
| memento.putInteger(TAG_SELECTION_HORIZONTAL_PIXEL, textWidget.getHorizontalPixel()); |
| } |
| |
| /** |
| * Returns whether the given memento contains saved state |
| * <p> |
| * Subclasses may extend or override this method.</p> |
| * |
| * @param memento the saved state of this editor |
| * @return <code>true</code> if the given memento contains saved state |
| * @since 3.3 |
| */ |
| protected boolean containsSavedState(IMemento memento) { |
| return memento.getInteger(TAG_SELECTION_OFFSET) != null && memento.getInteger(TAG_SELECTION_LENGTH) != null; |
| } |
| |
| /** |
| * Restores this editor's state using the given memento. |
| * <p> |
| * Subclasses may extend or override this method.</p> |
| * |
| * @param memento the saved state of this editor |
| * @since 3.3 |
| */ |
| protected void doRestoreState(IMemento memento) { |
| Integer offset= memento.getInteger(TAG_SELECTION_OFFSET); |
| if (offset == null) |
| return; |
| |
| Integer length= memento.getInteger(TAG_SELECTION_LENGTH); |
| if (length == null) |
| return; |
| |
| doSetSelection(new TextSelection(offset.intValue(), length.intValue())); |
| |
| final StyledText textWidget= fSourceViewer.getTextWidget(); |
| |
| Integer topPixel= memento.getInteger(TAG_SELECTION_TOP_PIXEL); |
| if (topPixel != null) |
| textWidget.setTopPixel(topPixel.intValue()); |
| |
| Integer horizontalPixel= memento.getInteger(TAG_SELECTION_HORIZONTAL_PIXEL); |
| if (horizontalPixel != null) |
| textWidget.setHorizontalPixel(horizontalPixel.intValue()); |
| } |
| |
| @Override |
| public Saveable[] getSaveables() { |
| if (fSavable == null) |
| fSavable= new TextEditorSavable(this); |
| |
| return new Saveable[] { fSavable }; |
| } |
| |
| @Override |
| public Saveable[] getActiveSaveables() { |
| return getSaveables(); |
| } |
| |
| /** |
| * This text editor's savable. |
| * |
| * @since 3.3 |
| */ |
| protected static class TextEditorSavable extends Saveable { |
| |
| /** The cached editor. */ |
| private ITextEditor fTextEditor; |
| /** The cached editor input. */ |
| private IEditorInput fEditorInput; |
| /** The cached document. */ |
| private IDocument fDocument; |
| |
| /** |
| * Creates a new savable for this text editor. |
| * |
| * @param textEditor the text editor |
| */ |
| public TextEditorSavable(ITextEditor textEditor) { |
| Assert.isLegal(textEditor != null); |
| fTextEditor= textEditor; |
| fEditorInput= fTextEditor.getEditorInput(); |
| Assert.isLegal(fEditorInput != null); |
| } |
| |
| /** |
| * Disconnects the editor from this savable. |
| */ |
| public void disconnectEditor() { |
| getAdapter(IDocument.class); // make sure the document is cached |
| fTextEditor= null; |
| } |
| |
| @Override |
| public String getName() { |
| return fEditorInput.getName(); |
| } |
| |
| @Override |
| public String getToolTipText() { |
| return fEditorInput.getToolTipText(); |
| } |
| |
| @Override |
| public ImageDescriptor getImageDescriptor() { |
| return fEditorInput.getImageDescriptor(); |
| } |
| |
| @Override |
| public void doSave(IProgressMonitor monitor) throws CoreException { |
| fTextEditor.doSave(monitor); |
| } |
| |
| @Override |
| public boolean isDirty() { |
| return fTextEditor.isDirty(); |
| } |
| |
| /* |
| * @see org.eclipse.ui.Saveable#supportsBackgroundSave() |
| */ |
| public boolean supportsBackgroundSave() { |
| return false; |
| } |
| |
| @Override |
| public int hashCode() { |
| Object document= getAdapter(IDocument.class); |
| if (document == null) |
| return 0; |
| return document.hashCode(); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) |
| return true; |
| |
| if (!(obj instanceof Saveable)) |
| return false; |
| |
| Object thisDocument= getAdapter(IDocument.class); |
| Object otherDocument= ((Saveable)obj).getAdapter(IDocument.class); |
| |
| if (thisDocument == null && otherDocument == null) |
| return true; |
| |
| return thisDocument != null && thisDocument.equals(otherDocument); |
| } |
| |
| /** |
| * Explicit comment needed to suppress wrong warning caused by |
| * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4848177 |
| * |
| * @see org.eclipse.ui.Saveable#getAdapter(java.lang.Class) |
| */ |
| @SuppressWarnings("unchecked") |
| @Override |
| public <T> T getAdapter(Class<T> adapter) { |
| if (adapter == IDocument.class) { |
| if (fDocument == null) { |
| IDocumentProvider documentProvider= fTextEditor.getDocumentProvider(); |
| if (documentProvider != null) |
| fDocument= documentProvider.getDocument(fEditorInput); |
| } |
| return (T) fDocument; |
| } |
| return super.getAdapter(adapter); |
| } |
| } |
| |
| //---- Tabs to spaces conversion support ------------------ |
| |
| /** |
| * Installs a tabs to spaces converter. |
| * |
| * <p>Subclasses may extend or override this method.</p> |
| * |
| * @since 3.3 |
| */ |
| protected void installTabsToSpacesConverter() { |
| SourceViewerConfiguration config= getSourceViewerConfiguration(); |
| if (config != null && fSourceViewer instanceof ITextViewerExtension7) { |
| int tabWidth= config.getTabWidth(fSourceViewer); |
| TabsToSpacesConverter tabToSpacesConverter= new TabsToSpacesConverter(); |
| tabToSpacesConverter.setLineTracker(new DefaultLineTracker()); |
| tabToSpacesConverter.setNumberOfSpacesPerTab(tabWidth); |
| ((ITextViewerExtension7)fSourceViewer).setTabsToSpacesConverter(tabToSpacesConverter); |
| updateIndentPrefixes(); |
| } |
| } |
| |
| /** |
| * Installs a tabs to spaces converter. |
| * |
| * <p>Subclasses may extend or override this method.</p> |
| * |
| * @since 3.3 |
| */ |
| protected void uninstallTabsToSpacesConverter() { |
| if (fSourceViewer instanceof ITextViewerExtension7) { |
| ((ITextViewerExtension7)fSourceViewer).setTabsToSpacesConverter(null); |
| if (fSourceViewer.getTextWidget() != null) |
| updateIndentPrefixes(); |
| } |
| } |
| |
| /** |
| * Tells whether tabs should be converted to |
| * spaces while editing inside this editor. |
| * |
| * <p>Subclasses may override this method.</p> |
| * |
| * @return <code>true</code> if tabs should be converted to spaces |
| * @since 3.3 |
| */ |
| protected boolean isTabsToSpacesConversionEnabled() { |
| return false; |
| } |
| |
| /** |
| * Updates the source viewer's indent prefixes with |
| * the values provided by the source viewer configuration. |
| * |
| * @since 3.3 |
| */ |
| protected final void updateIndentPrefixes() { |
| SourceViewerConfiguration configuration= getSourceViewerConfiguration(); |
| String[] types= configuration.getConfiguredContentTypes(fSourceViewer); |
| for (int i= 0; i < types.length; i++) { |
| String[] prefixes= configuration.getIndentPrefixes(fSourceViewer, types[i]); |
| if (prefixes != null && prefixes.length > 0) |
| fSourceViewer.setIndentPrefixes(prefixes, types[i]); |
| } |
| } |
| |
| /** |
| * Tells whether selection mode is supported. |
| * <p> |
| * By default block selection mode is supported. Subclasses may override this method to disable |
| * it. |
| * </p> |
| * |
| * @return <code>true</code> if block selection mode is supported, <code>false</code> otherwise |
| * @since 3.5 |
| */ |
| protected boolean isBlockSelectionModeSupported() { |
| return true; |
| } |
| |
| /** |
| * @see org.eclipse.ui.texteditor.ITextEditorExtension5#isBlockSelectionModeEnabled() |
| * @since 3.5 |
| */ |
| @Override |
| public final boolean isBlockSelectionModeEnabled() { |
| ISourceViewer viewer= getSourceViewer(); |
| if (viewer != null) { |
| StyledText styledText= viewer.getTextWidget(); |
| if (styledText != null) |
| return styledText.getBlockSelection(); |
| } |
| return false; |
| } |
| |
| /** |
| * @see org.eclipse.ui.texteditor.ITextEditorExtension5#setBlockSelectionMode(boolean) |
| * @since 3.5 |
| */ |
| @Override |
| public void setBlockSelectionMode(boolean enable) { |
| if (!isBlockSelectionModeSupported()) |
| return; |
| |
| ISourceViewer viewer= getSourceViewer(); |
| if (viewer != null) { |
| StyledText styledText= viewer.getTextWidget(); |
| if (styledText != null) { |
| /* |
| * Font switching. block selection mode needs a monospace font. |
| * - set the font _before enabling_ block selection mode in order to maintain the |
| * selection |
| * - revert the font _after disabling_ block selection mode in order to maintain the |
| * selection |
| */ |
| if (enable) { |
| Font blockFont= JFaceResources.getFont(BLOCK_SELECTION_MODE_FONT); |
| Font normalFont= styledText.getFont(); |
| if (!blockFont.equals(normalFont) && !normalFont.getFontData()[0].equals(blockFont.getFontData()[0])) { |
| setFont(viewer, blockFont); |
| disposeFont(); |
| updateCaret(); |
| } |
| |
| // we must unset word wrap before we can set block selection |
| if (isWordWrapEnabled()) { |
| setWordWrap(false); |
| } |
| } |
| |
| styledText.setBlockSelection(enable); |
| |
| if (!enable) { |
| initializeViewerFont(viewer); |
| updateCaret(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Tells whether word wrap is supported. |
| * <p> |
| * By default word wrap is supported. Subclasses may override this method to disable |
| * it. |
| * </p> |
| * |
| * @return <code>true</code> if word wrap is supported, <code>false</code> otherwise |
| * @since 3.10 |
| */ |
| protected boolean isWordWrapSupported() { |
| return true; |
| } |
| |
| /** |
| * <code>true</code> if word wrap is supported and enabled, <code>false</code> otherwise |
| * @return the receiver's word wrap state if word wrap is supported |
| * @since 3.10 |
| * @see AbstractTextEditor#isWordWrapSupported() |
| */ |
| @Override |
| public final boolean isWordWrapEnabled() { |
| if (!isWordWrapSupported()) { |
| return false; |
| } |
| ISourceViewer viewer= getSourceViewer(); |
| if (viewer != null) { |
| StyledText styledText= viewer.getTextWidget(); |
| if (styledText != null) { |
| return styledText.getWordWrap(); |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * @see org.eclipse.ui.texteditor.ITextEditorExtension6#setWordWrap(boolean) |
| * @since 3.10 |
| */ |
| @Override |
| public void setWordWrap(boolean enable) { |
| if (!isWordWrapSupported() || isWordWrapEnabled() == enable) { |
| return; |
| } |
| |
| ISourceViewer viewer= getSourceViewer(); |
| if (viewer != null) { |
| StyledText styledText= viewer.getTextWidget(); |
| if (styledText != null) { |
| if (isBlockSelectionModeEnabled()) { |
| setBlockSelectionMode(false); |
| } |
| styledText.setWordWrap(enable); |
| if (fVerticalRuler != null) { |
| // update ruler layout so that it can consider |
| // changed horizontal scrollbar visibility |
| boolean updated= false; |
| if (viewer instanceof ITextViewerExtension) { |
| Control control= ((ITextViewerExtension)viewer).getControl(); |
| if (control instanceof Composite) { |
| ((Composite)control).layout(); |
| updated= true; |
| } |
| } |
| if (!updated) { |
| fVerticalRuler.update(); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Returns the initial word wrap status. |
| * |
| * @return initial word wrap status |
| * @since 3.10 |
| */ |
| protected boolean getInitialWordWrapStatus() { |
| IPreferenceStore store= getPreferenceStore(); |
| if (store == null) { |
| return false; |
| } |
| return store.getBoolean(PREFERENCE_WORD_WRAP_ENABLED); |
| } |
| } |