blob: 0cdefde1a6be0b8b2113c3fecc4e24408293e109 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Chris.Dennis@invidi.com - http://bugs.eclipse.org/bugs/show_bug.cgi?id=29027
*******************************************************************************/
package org.eclipse.ui.texteditor;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ST;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.VerifyKeyListener;
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.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
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.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IPluginDescriptor;
import org.eclipse.core.runtime.IPluginPrerequisite;
import org.eclipse.core.runtime.IPluginRegistry;
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.Status;
import org.eclipse.jface.text.Assert;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IFindReplaceTarget;
import org.eclipse.jface.text.IFindReplaceTargetExtension;
import org.eclipse.jface.text.IMarkRegionTarget;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.IRewriteTarget;
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.ITextViewerExtension;
import org.eclipse.jface.text.ITextViewerExtension3;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.TextEvent;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
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.jface.action.Action;
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.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableContext;
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.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorActionBarContributor;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorRegistry;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IKeyBindingService;
import org.eclipse.ui.INavigationLocation;
import org.eclipse.ui.INavigationLocationProvider;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.IReusableEditor;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.help.WorkbenchHelp;
import org.eclipse.ui.internal.ActionDescriptor;
import org.eclipse.ui.internal.EditorPluginAction;
import org.eclipse.ui.internal.texteditor.EditPosition;
import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
import org.eclipse.ui.part.EditorActionBarContributor;
import org.eclipse.ui.part.EditorPart;
/**
* 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 <code>setEditorContextMenuId</code> the arguments 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 <code>setEditorContextMenuId</code>.
* If no id is set while in compatibility mode, the menu is registered under
* <code>DEFAULT_EDITOR_CONTEXT_MENU_ID</code>.</p>
* <p>
* If a subclass calls <code>setRulerContextMenuId</code> 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 <code>setRulerContextMenuId</code>.
* If no id is set while in compatibility mode, the menu is registered under
* <code>DEFAULT_RULER_CONTEXT_MENU_ID</code>.</p>
*
* @see org.eclipse.ui.editors.text.TextEditor
*/
public abstract class AbstractTextEditor extends EditorPart implements ITextEditor, IReusableEditor, ITextEditorExtension, ITextEditorExtension2, INavigationLocationProvider {
/**
* 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$
/**
* 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. */
public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {}
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 {
/*
* @see VerifyListener#verifyText(org.eclipse.swt.events.VerifyEvent)
*/
public void verifyText(VerifyEvent e) {
if (! validateEditorInputState())
e.doit= false;
}
};
/**
* The listener's validator.
* @since 2.0
*/
private Validator fValidator;
/*
* @see IElementStateListenerExtension#elementStateValidationChanged(Object, boolean)
* @since 2.0
*/
public void elementStateValidationChanged(Object element, boolean isStateValidated) {
if (element != null && element.equals(getEditorInput())) {
enableSanityChecking(true);
if (isStateValidated && fValidator != null) {
ISourceViewer viewer= getSourceViewer();
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= getSourceViewer();
if (viewer != null) {
StyledText textWidget= viewer.getTextWidget();
if (textWidget != null && !textWidget.isDisposed()) {
fValidator= new Validator();
enableStateValidation(true);
textWidget.addVerifyListener(fValidator);
}
}
}
}
}
/*
* @see IElementStateListener#elementDirtyStateChanged(Object, boolean)
*/
public void elementDirtyStateChanged(Object element, boolean isDirty) {
if (element != null && element.equals(getEditorInput())) {
enableSanityChecking(true);
firePropertyChange(PROP_DIRTY);
}
}
/*
* @see IElementStateListener#elementContentAboutToBeReplaced(Object)
*/
public void elementContentAboutToBeReplaced(Object element) {
if (element != null && element.equals(getEditorInput())) {
enableSanityChecking(true);
rememberSelection();
resetHighlightRange();
}
}
/*
* @see IElementStateListener#elementContentReplaced(Object)
*/
public void elementContentReplaced(Object element) {
if (element != null && element.equals(getEditorInput())) {
enableSanityChecking(true);
firePropertyChange(PROP_DIRTY);
restoreSelection();
}
}
/*
* @see IElementStateListener#elementDeleted(Object)
*/
public void elementDeleted(Object deletedElement) {
if (deletedElement != null && deletedElement.equals(getEditorInput())) {
enableSanityChecking(true);
close(false);
}
}
/*
* @see IElementStateListener#elementMoved(Object, Object)
*/
public void elementMoved(Object originalElement, Object movedElement) {
if (originalElement != null && originalElement.equals(getEditorInput())) {
enableSanityChecking(true);
if (!canHandleMove((IEditorInput) originalElement, (IEditorInput) movedElement)) {
close(true);
return;
}
if (movedElement == null || movedElement instanceof IEditorInput) {
rememberSelection();
IDocumentProvider d= getDocumentProvider();
IDocument changed= null;
if (isDirty())
changed= d.getDocument(getEditorInput());
setInput((IEditorInput) movedElement);
if (changed != null) {
d.getDocument(getEditorInput()).set(changed.get());
validateState(getEditorInput());
updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE);
}
restoreSelection();
}
}
}
/*
* @see IElementStateListenerExtension#elementStateChanging(Object)
* @since 2.0
*/
public void elementStateChanging(Object element) {
if (element != null && element.equals(getEditorInput()))
enableSanityChecking(false);
}
/*
* @see IElementStateListenerExtension#elementStateChangeFailed(Object)
* @since 2.0
*/
public void elementStateChangeFailed(Object element) {
if (element != null && element.equals(getEditorInput()))
enableSanityChecking(true);
}
};
/**
* Internal text listener for updating all content dependent
* actions. The updating is done asynchronously.
*/
class TextListener implements ITextListener {
/** The posted updater code. */
private Runnable fRunnable= new Runnable() {
public void run() {
TextEvent textEvent= (TextEvent) fTextEventQueue.remove(0);
if (fSourceViewer != null) {
// check whether editor has not been disposed yet
if (fTextEventQueue.isEmpty())
updateContentDependentActions();
// remember the last edit position
if (isDirty() && (textEvent.getDocumentEvent() != null)) {
ISelection sel= getSelectionProvider().getSelection();
IEditorInput input= getEditorInput();
Position pos= null;
if (sel instanceof ITextSelection) {
int offset= ((ITextSelection)sel).getOffset();
int length= ((ITextSelection)sel).getLength();
pos= new Position(offset, length);
try {
getDocumentProvider().getDocument(input).addPosition(pos);
} catch (BadLocationException ex) {
// pos is null
}
}
TextEditorPlugin.getDefault().setLastEditPosition(new EditPosition(input, getEditorSite().getId(), getSelectionProvider().getSelection(), pos));
}
}
}
};
/** Display used for posting the updater code. */
private Display fDisplay;
/**
* Display used for posting the updater code.
* @since 2.1
*/
private ArrayList fTextEventQueue= new ArrayList(5);
/*
* @see ITextListener#textChanged(TextEvent)
*/
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();
fTextEventQueue.add(event);
fDisplay.asyncExec(fRunnable);
}
};
/**
* Compare configuration elements according to the prerequisite relation
* of their defining plug-ins.
*
* @since 2.0
*/
static class ConfigurationElementComparator implements Comparator {
/*
* @see Comparator#compare(java.lang.Object, java.lang.Object)
* @since 2.0
*/
public int compare(Object object0, Object object1) {
IConfigurationElement element0= (IConfigurationElement)object0;
IConfigurationElement element1= (IConfigurationElement)object1;
if (dependsOn(element0, element1))
return -1;
if (dependsOn(element1, element0))
return +1;
return 0;
}
/**
* Returns whether one configuration element depends on the other element.
* This is done by checking the dependency chain of the defining plug-ins.
*
* @param element0 the first element
* @param element1 the second element
* @return <code>true</code> if <code>element0</code> depends on <code>element1</code>.
* @since 2.0
*/
private static boolean dependsOn(IConfigurationElement element0, IConfigurationElement element1) {
IPluginDescriptor descriptor0= element0.getDeclaringExtension().getDeclaringPluginDescriptor();
IPluginDescriptor descriptor1= element1.getDeclaringExtension().getDeclaringPluginDescriptor();
return dependsOn(descriptor0, descriptor1);
}
/**
* Returns whether one plug-in depends on the other plugin.
*
* @param descriptor0 descriptor of the first plug-in
* @param descriptor1 descriptor of the second plug-in
* @return <code>true</code> if <code>descriptor0</code> depends on <code>descriptor1</code>.
* @since 2.0
*/
private static boolean dependsOn(IPluginDescriptor descriptor0, IPluginDescriptor descriptor1) {
IPluginRegistry registry= Platform.getPluginRegistry();
IPluginPrerequisite[] prerequisites= descriptor0.getPluginPrerequisites();
for (int i= 0; i < prerequisites.length; i++) {
IPluginPrerequisite prerequisite= prerequisites[i];
String id= prerequisite.getUniqueIdentifier();
IPluginDescriptor descriptor= registry.getPluginDescriptor(id);
if (descriptor != null && (descriptor.equals(descriptor1) || dependsOn(descriptor, descriptor1)))
return true;
}
return false;
}
}
/**
* Internal property change listener for handling changes in the editor's preferences.
*/
class PropertyChangeListener implements IPropertyChangeListener {
/*
* @see IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent event) {
handlePreferenceStoreChanged(event);
}
};
/**
* Internal property change listener for handling workbench font changes.
* @since 2.1
*/
class FontPropertyChangeListener implements IPropertyChangeListener {
/*
* @see IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent event) {
if (fSourceViewer == null)
return;
String property= event.getProperty();
if (getFontPropertyPreferenceKey().equals(property))
initializeViewerFont(fSourceViewer);
}
};
/**
* 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;
/*
* @see VerifyKeyListener#verifyKey(org.eclipse.swt.events.VerifyEvent)
*/
public void verifyKey(VerifyEvent event) {
ActionActivationCode code= null;
int size= fActivationCodes.size();
for (int i= 0; i < size; i++) {
code= (ActionActivationCode) 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 (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 (action.getActionDefinitionId() != null)
fKeyBindingService.unregisterAction(action);
}
/**
* Sets the keybindings scopes for this editor.
* @param keyBindingScopes the keybinding 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
*/
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 extends ShellAdapter implements IPartListener {
/** Cache of the active workbench part. */
private IWorkbenchPart fActivePart;
/** Indicates whether activation handling is currently be done. */
private boolean fIsHandlingActivation= false;
/*
* @see IPartListener#partActivated(org.eclipse.ui.IWorkbenchPart)
*/
public void partActivated(IWorkbenchPart part) {
fActivePart= part;
handleActivation();
}
/*
* @see IPartListener#partBroughtToTop(org.eclipse.ui.IWorkbenchPart)
*/
public void partBroughtToTop(IWorkbenchPart part) {
}
/*
* @see IPartListener#partClosed(org.eclipse.ui.IWorkbenchPart)
*/
public void partClosed(IWorkbenchPart part) {
}
/*
* @see IPartListener#partDeactivated(org.eclipse.ui.IWorkbenchPart)
*/
public void partDeactivated(IWorkbenchPart part) {
fActivePart= null;
}
/*
* @see IPartListener#partOpened(org.eclipse.ui.IWorkbenchPart)
*/
public void partOpened(IWorkbenchPart part) {
}
/*
* @see ShellListener#shellActivated(org.eclipse.swt.events.ShellEvent)
*/
public void shellActivated(ShellEvent e) {
/*
* Workaround for problem described in
* http://dev.eclipse.org/bugs/show_bug.cgi?id=11731
* Will be removed when SWT has solved the problem.
*/
e.widget.getDisplay().asyncExec(new Runnable() {
public void run() {
handleActivation();
}
});
}
/**
* Handles the activation triggering a element state check in the editor.
*/
private void handleActivation() {
if (fIsHandlingActivation)
return;
if (fActivePart == AbstractTextEditor.this) {
fIsHandlingActivation= true;
try {
safelySanityCheckState(getEditorInput());
} finally {
fIsHandlingActivation= false;
}
}
}
};
/**
* 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
*/
static 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 &lt 0, it's scrolling up, if &gt 0 it's scrolling down.
* @param scrollIncrement the number of lines to scroll
*/
public ScrollLinesAction(int scrollIncrement) {
fScrollIncrement= scrollIncrement;
}
/*
* @see IAction#run()
*/
public void run() {
ISourceViewer viewer= getSourceViewer();
int topIndex= viewer.getTopIndex();
int newTopIndex= Math.max(0, topIndex + fScrollIncrement);
viewer.setTopIndex(newTopIndex);
}
};
/**
* Action to toggle the insert mode.
* @since 2.1
*/
class ToggleInsertModeAction extends TextNavigationAction {
public ToggleInsertModeAction(StyledText textWidget) {
super(textWidget, ST.TOGGLE_OVERWRITE);
}
/*
* @see org.eclipse.jface.action.IAction#run()
*/
public void run() {
super.run();
fOverwriting= !fOverwriting;
handleInsertModeChanged();
}
};
/**
* 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
*/
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;
}
/*
* @see org.eclipse.jface.action.IAction#run()
*/
public void run() {
boolean isSmartHomeEndEnabled= false;
IPreferenceStore store= getPreferenceStore();
if (store != null)
isSmartHomeEndEnabled= store.getBoolean(AbstractTextEditor.PREFERENCE_NAVIGATION_SMART_HOME_END);
StyledText st= getSourceViewer().getTextWidget();
if (st == null || st.isDisposed())
return;
int caretOffset= st.getCaretOffset();
int lineNumber= st.getLineAtOffset(caretOffset);
int lineOffset= st.getOffsetAtLine(lineNumber);
int lineLength;
try {
int caretOffsetInDocument= widgetOffset2ModelOffset(getSourceViewer(), caretOffset);
lineLength= getSourceViewer().getDocument().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);
int i= lineLength - 1;
while (i > -1 && Character.isWhitespace(line.charAt(i))) {
i--;
}
i++;
// Remember current selection
Point oldSelection= st.getSelection();
// Compute new caret position
int newCaretOffset= -1;
if (isSmartHomeEndEnabled) {
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);
// send selection changed event
Event event= new Event();
event.x= st.getSelection().x;
event.y= st.getSelection().y;
st.notifyListeners(SWT.Selection, event);
}
};
/**
* This action implements smart home.
* Instead of going to the start of a line it does the following:
* - if smart home/end is enabled and the caret is after the line's first non-whitespace then the caret is moved directly before it
* - 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
*/
class LineStartAction extends TextNavigationAction {
/** boolean flag which tells if the text up to the beginning of the line should be selected. */
private 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(StyledText textWidget, boolean doSelect) {
super(textWidget, ST.LINE_START);
fDoSelect= doSelect;
}
/*
* @see org.eclipse.jface.action.IAction#run()
*/
public void run() {
boolean isSmartHomeEndEnabled= false;
IPreferenceStore store= getPreferenceStore();
if (store != null)
isSmartHomeEndEnabled= store.getBoolean(AbstractTextEditor.PREFERENCE_NAVIGATION_SMART_HOME_END);
StyledText st= getSourceViewer().getTextWidget();
if (st == null || st.isDisposed())
return;
int caretOffset= st.getCaretOffset();
int lineNumber= st.getLineAtOffset(caretOffset);
int lineOffset= st.getOffsetAtLine(lineNumber);
int lineLength;
try {
int caretOffsetInDocument= widgetOffset2ModelOffset(getSourceViewer(), caretOffset);
lineLength= getSourceViewer().getDocument().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);
}
int i= 0;
while (i < lineLength && Character.isWhitespace(line.charAt(i)))
i++;
// Remember current selection
Point oldSelection= st.getSelection();
// Compute new caret position
int newCaretOffset= -1;
if (isSmartHomeEndEnabled) {
if (caretOffset - lineOffset == i)
// to beginning of line
newCaretOffset= lineOffset;
else
// to beginning of text
newCaretOffset= lineOffset + i;
} 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);
// send selection changed event
Event event= new Event();
event.x= st.getSelection().x;
event.y= st.getSelection().y;
st.notifyListeners(SWT.Selection, event);
}
};
/**
* Internal action to show the editor's ruler context menu (accessibility).
* @since 2.0
*/
class ShowRulerContextMenuAction extends Action {
/*
* @see IAction#run()
*/
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 2.1
*/
class SelectionProvider implements ISelectionProvider {
/*
* @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(ISelectionChangedListener)
*/
public void addSelectionChangedListener(ISelectionChangedListener listener) {
if (fSourceViewer != null)
fSourceViewer.getSelectionProvider().addSelectionChangedListener(listener);
}
/*
* @see org.eclipse.jface.viewers.ISelectionProvider#getSelection()
*/
public ISelection getSelection() {
return doGetSelection();
}
/*
* @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(ISelectionChangedListener)
*/
public void removeSelectionChangedListener(ISelectionChangedListener listener) {
if (fSourceViewer != null)
fSourceViewer.getSelectionProvider().removeSelectionChangedListener(listener);
}
/*
* @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(ISelection)
*/
public void setSelection(ISelection selection) {
doSetSelection(selection);
}
};
/**
* 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}
*/
public final static String PREFERENCE_FONT= JFaceResources.TEXT_FONT;
/**
* Key used to look up foreground color preference.
* Value: <code>AbstractTextEditor.Color.Foreground</code>
* @since 2.0
*/
public final static 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 final static 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 final static 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 final static String PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT= "AbstractTextEditor.Color.Background.SystemDefault"; //$NON-NLS-1$
/**
* Key used to look up find scope background color preference.
* Value: <code>AbstractTextEditor.Color.FindScope</code>
* @since 2.0
*/
public final static 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 final static String PREFERENCE_NAVIGATION_SMART_HOME_END= "AbstractTextEditor.Navigation.SmartHomeEnd"; //$NON-NLS-1$
/** Menu id for the editor context menu. */
public final static String DEFAULT_EDITOR_CONTEXT_MENU_ID= "#EditorContext"; //$NON-NLS-1$
/** Menu id for the ruler context menu. */
public final static String DEFAULT_RULER_CONTEXT_MENU_ID= "#RulerContext"; //$NON-NLS-1$
/** The width of the vertical ruler. */
protected final static int VERTICAL_RULER_WIDTH= 12;
/**
* The complete mapping between action definition ids used by eclipse and StyledText actions.
* @since 2.0
*/
protected final static 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(ITextEditorActionDefinitionIds.CUT, ST.CUT),
new IdMapEntry(ITextEditorActionDefinitionIds.COPY, ST.COPY),
new IdMapEntry(ITextEditorActionDefinitionIds.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.getString("Editor.statusline.state.readonly.label"); //$NON-NLS-1$
private final String fWritableLabel = EditorMessages.getString("Editor.statusline.state.writable.label"); //$NON-NLS-1$
private final String fInsertModeLabel = EditorMessages.getString("Editor.statusline.mode.insert.label"); //$NON-NLS-1$
private final String fOverwriteModeLabel = EditorMessages.getString("Editor.statusline.mode.overwrite.label"); //$NON-NLS-1$
/** The error message shown in the status line in case of failed information look up. */
protected final String fErrorLabel= EditorMessages.getString("Editor.statusline.error.label"); //$NON-NLS-1$
/**
* Data structure for the position label value.
*/
private static class PositionLabelValue {
public int fValue;
public String toString() {
return String.valueOf(fValue);
}
};
/** The pattern used to show the position label in the status line. */
private final String fPositionLabelPattern= EditorMessages.getString("Editor.statusline.position.pattern"); //$NON-NLS-1$
/** 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 editor's internal document provider. */
private IDocumentProvider fInternalDocumentProvider;
/** The editor's external document provider. */
private IDocumentProvider fExternalDocumentProvider;
/** 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 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 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 fActions= new HashMap(10);
/** The actions marked as selection dependent. */
private List fSelectionActions= new ArrayList(5);
/** The actions marked as content dependent. */
private List fContentActions= new ArrayList(5);
/**
* The actions marked as property dependent.
* @since 2.0
*/
private List fPropertyActions= new ArrayList(5);
/**
* The actions marked as state dependent.
* @since 2.0
*/
private List fStateActions= new ArrayList(5);
/** The editor's action activation codes. */
private List 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 ITextListener 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= new ActivationListener();
/**
* The map of the editor's status fields.
* @since 2.0
*/
private Map fStatusFields;
/**
* The editor's cursor listener.
* @since 2.0
*/
private ICursorListener fCursorListener;
/**
* The editor's insert mode.
* @since 2.0
*/
private boolean fOverwriting= false;
/**
* 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 reentrances into error correction code while saving.
* @since 2.0
*/
private int fErrorCorrectionOnSave;
/**
* The delete line target.
* @since 2.1
*/
private DeleteLineTarget 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 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;
/**
* 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;
}
/*
* @see ITextEditor#getDocumentProvider()
*/
public IDocumentProvider getDocumentProvider() {
if (fInternalDocumentProvider != null)
return fInternalDocumentProvider;
return fExternalDocumentProvider;
}
/**
* Returns the editor's range indicator.
*
* @return the editor's range indicator
*/
protected final Annotation getRangeIndicator() {
return fRangeIndicator;
}
/**
* Returns the editor's source viewer configuration.
*
* @return the editor's source viewer configuration
*/
protected final SourceViewerConfiguration getSourceViewerConfiguration() {
return fConfiguration;
}
/**
* Returns the editor's source viewer.
*
* @return the editor's source viewer
*/
protected final ISourceViewer getSourceViewer() {
return fSourceViewer;
}
/**
* Returns the editor's vertical ruler.
*
* @return the editor's vertical ruler
*/
protected final IVerticalRuler getVerticalRuler() {
return fVerticalRuler;
}
/**
* Returns the editor's context menu id.
*
* @return the editor's context menu id
*/
protected final String getEditorContextMenuId() {
return fEditorContextMenuId;
}
/**
* Returns the ruler's context menu id.
*
* @return the ruler's context menu id
*/
protected final String getRulerContextMenuId() {
return fRulerContextMenuId;
}
/**
* Returns the editor's help context id.
*
* @return the editor's help context id
*/
protected final String getHelpContextId() {
return fHelpContextId;
}
/**
* Returns this editor's preference store.
*
* @return this editor's preference store
*/
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) {
Assert.isNotNull(provider);
fInternalDocumentProvider= 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 uses a <code>DefaultRangeIndicator</code>.
*
* @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 keybinding scopes for this editor.
*
* @param scopes the scopes
* @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 new preference store
*/
protected void setPreferenceStore(IPreferenceStore store) {
if (fPreferenceStore != null)
fPreferenceStore.removePropertyChangeListener(fPropertyChangeListener);
fPreferenceStore= store;
if (fPreferenceStore != null)
fPreferenceStore.addPropertyChangeListener(fPropertyChangeListener);
}
/*
* @see ITextEditor#isEditable()
*/
public boolean isEditable() {
IDocumentProvider provider= getDocumentProvider();
if (provider instanceof IDocumentProviderExtension) {
IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
return extension.isModifiable(getEditorInput());
}
return false;
}
/*
* @see ITextEditor#getSelectionProvider()
*/
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;
}
}
return false;
}
/**
* Sets the given selection.
* @param selection
* @since 2.1
*/
protected void doSetSelection(ISelection selection) {
if (selection instanceof ITextSelection) {
ITextSelection textSelection= (ITextSelection) selection;
selectAndReveal(textSelection.getOffset(), textSelection.getLength());
}
}
/**
* Creates and returns the listener on this editor's context menus.
*
* @return the menu listener
*/
protected final IMenuListener getContextMenuListener() {
if (fMenuListener == null) {
fMenuListener= new IMenuListener() {
public void menuAboutToShow(IMenuManager menu) {
String id= menu.getId();
if (getRulerContextMenuId().equals(id)) {
setFocus();
rulerContextMenuAboutToShow(menu);
} else if (getEditorContextMenuId().equals(id)) {
setFocus();
editorContextMenuAboutToShow(menu);
}
}
};
}
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 void triggerAction(String actionID) {
IAction action= getAction(actionID);
if (action != null) {
if (action instanceof IUpdate)
((IUpdate) action).update();
if (action.isEnabled())
action.run();
}
}
public void mouseUp(MouseEvent e) {
setFocus();
if (1 == e.button && !fDoubleClicked)
triggerAction(ITextEditorActionConstants.RULER_CLICK);
fDoubleClicked= false;
}
public void mouseDoubleClick(MouseEvent e) {
if (1 == e.button) {
fDoubleClicked= true;
triggerAction(ITextEditorActionConstants.RULER_DOUBLE_CLICK);
}
}
public void mouseDown(MouseEvent e) {
StyledText text= fSourceViewer.getTextWidget();
if (text != null && !text.isDisposed()) {
Display display= text.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() {
public void run() {
// check whether editor has not been disposed yet
if (fSourceViewer != null) {
updateSelectionDependentActions();
}
}
};
private Display fDisplay;
public void selectionChanged(SelectionChangedEvent event) {
if (fDisplay == null)
fDisplay= getSite().getShell().getDisplay();
fDisplay.asyncExec(fRunnable);
handleCursorPositionChanged();
}
};
}
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() {
public void keyPressed(KeyEvent e) {
handleCursorPositionChanged();
}
public void keyReleased(KeyEvent e) {
}
public void mouseDoubleClick(MouseEvent e) {
}
public void mouseDown(MouseEvent e) {
}
public void mouseUp(MouseEvent e) {
handleCursorPositionChanged();
}
};
}
return fCursorListener;
}
/*
* @see 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 {
final PartInitException[] exceptions= new PartInitException[1];
IRunnableWithProgress runnable= new IRunnableWithProgress() {
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) {
exceptions[0]= new PartInitException(x.getStatus());
} finally {
if (getDocumentProvider() instanceof IDocumentProviderExtension2) {
IDocumentProviderExtension2 extension= (IDocumentProviderExtension2) getDocumentProvider();
extension.setProgressMonitor(null);
}
}
}
};
try {
IRunnableContext context= (window instanceof IRunnableContext) ? (IRunnableContext) window : new ProgressMonitorDialog(window.getShell());
context.run(false, true, runnable);
} catch (InvocationTargetException x) {
} catch (InterruptedException x) {
}
if (exceptions[0] != null)
throw exceptions[0];
}
/*
* @see IEditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
*/
public void init(final IEditorSite site, final IEditorInput input) throws PartInitException {
setSite(site);
IWorkbenchWindow window= getSite().getWorkbenchWindow();
internalInit(window, site, input);
window.getPartService().addPartListener(fActivationListener);
window.getShell().addShellListener(fActivationListener);
}
/**
* 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);
}
/**
* 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
* @return the source viewer
*/
protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
return new SourceViewer(parent, ruler, styles);
}
/**
* The <code>AbstractTextEditor</code> implementation of this
* <code>IWorkbenchPart</code> method creates the vertical ruler and
* source viewer.
* Subclasses may extend.
*
* @param parent the parent composite
*/
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 (fRangeIndicator != null)
fSourceViewer.setRangeIndicator(fRangeIndicator);
fSourceViewer.addTextListener(fTextListener);
getSelectionProvider().addSelectionChangedListener(getSelectionChangedListener());
initializeViewerFont(fSourceViewer);
initializeViewerColors(fSourceViewer);
initializeFindScopeColor(fSourceViewer);
StyledText styledText= fSourceViewer.getTextWidget();
/* gestures commented out until proper solution (i.e. preference page) can be found
* for bug # 28417:
*
final Map gestureMap = new HashMap();
gestureMap.put("E", "org.eclipse.ui.navigate.forwardHistory");
gestureMap.put("N", "org.eclipse.ui.file.save");
gestureMap.put("NW", "org.eclipse.ui.file.saveAll");
gestureMap.put("S", "org.eclipse.ui.file.close");
gestureMap.put("SW", "org.eclipse.ui.file.closeAll");
gestureMap.put("W", "org.eclipse.ui.navigate.backwardHistory");
gestureMap.put("EN", "org.eclipse.ui.edit.copy");
gestureMap.put("ES", "org.eclipse.ui.edit.paste");
gestureMap.put("EW", "org.eclipse.ui.edit.cut");
Capture capture = Capture.create();
capture.setControl(styledText);
capture.addCaptureListener(new CaptureListener() {
public void gesture(Gesture gesture) {
if (gesture.getPen() == 3) {
String actionId = (String) gestureMap.get(Util.recognize(gesture.getPoints(), 20));
if (actionId != null) {
IKeyBindingService keyBindingService = getEditorSite().getKeyBindingService();
if (keyBindingService instanceof KeyBindingService) {
IAction action = ((KeyBindingService) keyBindingService).getAction(actionId);
if (action != null) {
if (action instanceof IUpdate)
((IUpdate) action).update();
if (action.isEnabled())
action.run();
}
}
return;
}
fTextContextMenu.setVisible(true);
}
};
});
*/
styledText.addMouseListener(getCursorListener());
styledText.addKeyListener(getCursorListener());
if (getHelpContextId() != null)
WorkbenchHelp.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);
// comment this line if using gestures, above.
styledText.setMenu(fTextContextMenu);
if (fEditorContextMenuId != null)
getSite().registerContextMenu(fEditorContextMenuId, manager, getSelectionProvider());
else if (fCompatibilityMode)
getSite().registerContextMenu(DEFAULT_EDITOR_CONTEXT_MENU_ID, manager, getSelectionProvider());
if ((fEditorContextMenuId != null && fCompatibilityMode) || fEditorContextMenuId == null) {
String partId= getSite().getId();
if (partId != null)
getSite().registerContextMenu(partId + ".EditorContext", manager, getSelectionProvider()); //$NON-NLS-1$
}
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)
getSite().registerContextMenu(fRulerContextMenuId, manager, getSelectionProvider());
else if (fCompatibilityMode)
getSite().registerContextMenu(DEFAULT_RULER_CONTEXT_MENU_ID, manager, getSelectionProvider());
if ((fRulerContextMenuId != null && fCompatibilityMode) || fRulerContextMenuId == null) {
String partId= getSite().getId();
if (partId != null)
getSite().registerContextMenu(partId + ".RulerContext", manager, getSelectionProvider()); //$NON-NLS-1$
}
if (fRulerContextMenuId == null)
fRulerContextMenuId= DEFAULT_RULER_CONTEXT_MENU_ID;
getSite().setSelectionProvider(getSelectionProvider());
initializeActivationCodeTrigger();
createNavigationActions();
createAccessibilityActions();
createActions();
initializeSourceViewer(getEditorInput());
JFaceResources.getFontRegistry().addListener(fFontPropertyChangeListener);
}
/**
* @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();
setFont(viewer, font);
if (fFont != null) {
fFont.dispose();
fFont= null;
}
if (!isSharedFont)
fFont= font;
}
/**
* 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) {
Point selection= sourceViewer.getSelectedRange();
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);
}
sourceViewer.setSelectedRange(selection.x , selection.y);
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);
}
}
}
/**
* 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 given viewer's colors.
*
* @param viewer the viewer to be initialized
* @since 2.0
*/
private 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;
}
}
/**
* 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) {
IAnnotationModel model= getDocumentProvider().getAnnotationModel(input);
IDocument document= getDocumentProvider().getDocument(input);
if (document != null) {
fSourceViewer.setDocument(document, model);
fSourceViewer.setEditable(isEditable());
fSourceViewer.showAnnotations(model != null);
}
if (fElementStateListener instanceof IElementStateListenerExtension) {
IElementStateListenerExtension extension= (IElementStateListenerExtension) fElementStateListener;
extension.elementStateValidationChanged(input, false);
}
}
/**
* Initializes the editor's title based on the given editor input.
*
* @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 = getEditorSite().getPage().getWorkbenchWindow().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);
setTitle(title);
firePropertyChange(PROP_DIRTY);
if (oldImage != null && !oldImage.isDisposed())
oldImage.dispose();
}
/**
* If there is no implicit document provider set, the external 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);
}
}
if (fInternalDocumentProvider == null)
fExternalDocumentProvider= DocumentProviderRegistry.getDefault().getDocumentProvider(input);
provider= getDocumentProvider();
if (provider != null) {
provider.addElementStateListener(fElementStateListener);
if (provider instanceof IDocumentProviderExtension2) {
IDocumentProviderExtension2 extension= (IDocumentProviderExtension2) provider;
extension.setProgressMonitor(rememberedProgressMonitor);
}
}
}
/**
* Internal <code>setInput</code> method.
*
* @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 {
if (input == null)
close(isSaveOnCloseNeeded());
else {
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.getString("Editor.error.no_provider"), null); //$NON-NLS-1$
throw new CoreException(s);
}
provider.connect(input);
initializeTitle(input);
if (fSourceViewer != null)
initializeSourceViewer(input);
updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE);
}
}
/*
* @see EditorPart#setInput(org.eclipse.ui.IEditorInput)
*/
public final void setInput(IEditorInput input) {
try {
doSetInput(input);
} catch (CoreException x) {
String title= EditorMessages.getString("Editor.error.setinput.title"); //$NON-NLS-1$
String msg= EditorMessages.getString("Editor.error.setinput.message"); //$NON-NLS-1$
Shell shell= getSite().getShell();
ErrorDialog.openError(shell, title, msg, x.getStatus());
}
}
/*
* @see ITextEditor#close
*/
public void close(final boolean save) {
enableSanityChecking(false);
Display display= getSite().getShell().getDisplay();
display.asyncExec(new Runnable() {
public void run() {
if (fSourceViewer != null) {
// check whether editor has not been disposed yet
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>.
*/
public void dispose() {
if (fActivationListener != null) {
IWorkbenchWindow window= getSite().getWorkbenchWindow();
window.getPartService().removePartListener(fActivationListener);
Shell shell= window.getShell();
if (shell != null && !shell.isDisposed())
shell.removeShellListener(fActivationListener);
fActivationListener= null;
}
if (fTitleImage != null) {
fTitleImage.dispose();
fTitleImage= null;
}
if (fFont != null) {
fFont.dispose();
fFont= null;
}
if (fForegroundColor != null) {
fForegroundColor.dispose();
fForegroundColor= null;
}
if (fBackgroundColor != null) {
fBackgroundColor.dispose();
fBackgroundColor= null;
}
if (fFindScopeHighlightColor != null) {
fFindScopeHighlightColor.dispose();
fFindScopeHighlightColor= null;
}
if (fFontPropertyChangeListener != null) {
JFaceResources.getFontRegistry().removeListener(fFontPropertyChangeListener);
fFontPropertyChangeListener= null;
}
if (fPropertyChangeListener != null) {
if (fPreferenceStore != null) {
fPreferenceStore.removePropertyChangeListener(fPropertyChangeListener);
fPreferenceStore= null;
}
fPropertyChangeListener= null;
}
if (fActivationCodeTrigger != null) {
fActivationCodeTrigger.uninstall();
fActivationCodeTrigger= null;
}
IDocumentProvider provider= getDocumentProvider();
if (provider != null) {
IEditorInput input= getEditorInput();
if (input != null)
provider.disconnect(input);
if (fElementStateListener != null) {
provider.removeElementStateListener(fElementStateListener);
fElementStateListener= null;
}
fInternalDocumentProvider= null;
fExternalDocumentProvider= null;
}
if (fSourceViewer != null) {
if (fTextListener != null) {
fSourceViewer.removeTextListener(fTextListener);
fTextListener= null;
}
fTextInputListener= null;
fSelectionProvider= null;
fSourceViewer= null;
}
if (fTextContextMenu != null) {
fTextContextMenu.dispose();
fTextContextMenu= null;
}
if (fRulerContextMenu != null) {
fRulerContextMenu.dispose();
fRulerContextMenu= null;
}
if (fActions != 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;
super.setInput(null);
super.dispose();
}
/**
* 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
*/
private String getSymbolicFontName() {
if (getConfigurationElement() != null)
return getConfigurationElement().getAttribute("symbolicFontName"); //$NON-NLS-1$
else
return null;
}
/**
* Returns the property preference key for the editor font.
*
* @return a String with the key
* @since 2.1
*/
protected final String getFontPropertyPreferenceKey() {
String symbolicFontName= getSymbolicFontName();
if (symbolicFontName != null)
return symbolicFontName;
else
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.
*
* @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;
} else 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))
{
initializeViewerColors(fSourceViewer);
} else if (PREFERENCE_COLOR_FIND_SCOPE.equals(property)) {
initializeFindScopeColor(fSourceViewer);
}
if (affectsTextPresentation(event))
fSourceViewer.invalidateTextPresentation();
}
/**
* Returns the progress monitor related to this editor.
*
* @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.
*/
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();
if (provider.isDeleted(input)) {
if (isSaveAsAllowed()) {
title= EditorMessages.getString("Editor.error.activated.deleted.save.title"); //$NON-NLS-1$
msg= EditorMessages.getString("Editor.error.activated.deleted.save.message"); //$NON-NLS-1$
String[] buttons= {
EditorMessages.getString("Editor.error.activated.deleted.save.button.save"), //$NON-NLS-1$
EditorMessages.getString("Editor.error.activated.deleted.save.button.close"), //$NON-NLS-1$
};
MessageDialog dialog= new MessageDialog(shell, title, null, msg, MessageDialog.QUESTION, buttons, 0);
if (dialog.open() == 0) {
IProgressMonitor pm= getProgressMonitor();
performSaveAs(pm);
if (pm.isCanceled())
handleEditorInputChanged();
} else {
close(false);
}
} else {
title= EditorMessages.getString("Editor.error.activated.deleted.close.title"); //$NON-NLS-1$
msg= EditorMessages.getString("Editor.error.activated.deleted.close.message"); //$NON-NLS-1$
if (MessageDialog.openConfirm(shell, title, msg))
close(false);
}
} else {
title= EditorMessages.getString("Editor.error.activated.outofsync.title"); //$NON-NLS-1$
msg= EditorMessages.getString("Editor.error.activated.outofsync.message"); //$NON-NLS-1$
if (MessageDialog.openQuestion(shell, title, msg)) {
title= EditorMessages.getString("Editor.error.refresh.outofsync.title"); //$NON-NLS-1$
msg= EditorMessages.getString("Editor.error.refresh.outofsync.message"); //$NON-NLS-1$
if (provider instanceof IDocumentProviderExtension) {
WorkspaceModifyOperation operation= new WorkspaceModifyOperation() {
protected void execute(final IProgressMonitor monitor) throws CoreException {
IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
extension.synchronize(input);
}
};
try {
operation.run(getProgressMonitor());
} catch (InterruptedException x) {
} catch (InvocationTargetException x) {
Throwable t= x.getTargetException();
MessageDialog.openError(shell, title, msg + t.getMessage());
}
} else {
try {
doSetInput(input);
} catch (CoreException x) {
ErrorDialog.openError(shell, title, msg, x.getStatus());
}
}
}
// // disabled because of http://bugs.eclipse.org/bugs/show_bug.cgi?id=15166
// else {
// markEditorAsDirty();
// }
}
}
// /**
// * Marks this editor and its editor input as dirty.
// * @since 2.0
// */
// private void markEditorAsDirty() {
//
// if (isDirty())
// return;
//
// IDocumentProvider provider= getDocumentProvider();
// if (provider instanceof IDocumentProviderExtension) {
//
// provider.removeElementStateListener(fElementStateListener);
// try {
//
// IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
// extension.setCanSaveDocument(getEditorInput());
// firePropertyChange(PROP_DIRTY);
//
// } finally {
// provider.addElementStateListener(fElementStateListener);
// }
//
// }
// }
/**
* The <code>AbstractTextEditor</code> implementation of this
* <code>IEditorPart</code> method calls <code>performSaveAs</code>.
* Subclasses may reimplement.
*/
public void doSaveAs() {
/*
* 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(getProgressMonitor());
}
/**
* 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>
*/
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.getString("Editor.error.save.deleted.title"); //$NON-NLS-1$
String msg= EditorMessages.getString("Editor.error.save.deleted.message"); //$NON-NLS-1$
MessageDialog.openError(shell, title, msg);
}
} else {
performSaveOperation(createSaveOperation(false), progressMonitor);
}
}
/**
* Enables/disables sanity checking.
* @param enable <code>true</code> if santity 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 (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 propably 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 exception) {
ILog log= Platform.getPlugin(PlatformUI.PLUGIN_ID).getLog();
log.log(exception.getStatus());
Shell shell= getSite().getShell();
String title= EditorMessages.getString("Editor.error.validateEdit.title"); //$NON-NLS-1$
String msg= EditorMessages.getString("Editor.error.validateEdit.message"); //$NON-NLS-1$
ErrorDialog.openError(shell, title, msg, exception.getStatus());
return;
}
if (fSourceViewer != null)
fSourceViewer.setEditable(isEditable());
updateStateDependentActions();
}
/*
* @see org.eclipse.ui.texteditor.ITextEditorExtension2#validateEditorInputState()
* @since 2.1
*/
public boolean validateEditorInputState() {
boolean enabled= false;
synchronized (this) {
enabled= fIsStateValidationEnabled;
}
if (enabled) {
ISourceViewer viewer= getSourceViewer();
fTextInputListener.inputChanged= false;
viewer.addTextInputListener(fTextInputListener);
try {
IEditorInput input= getEditorInput();
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) {
ILog log= Platform.getPlugin(PlatformUI.PLUGIN_ID).getLog();
log.log(x.getStatus());
}
}
}
/**
* Creates a workspace modify operation which saves the content of the editor
* to the editor's input element. <code>overwrite</code> indicates whether
* the editor input element may be overwritten if necessary.
* Clients may reimplement this method.
*
* @param overwrite indicates whether or not overwrititng is allowed
* @return the save operation
*/
protected WorkspaceModifyOperation createSaveOperation(final boolean overwrite) {
return new WorkspaceModifyOperation() {
public void execute(final IProgressMonitor monitor) throws CoreException {
IEditorInput input= getEditorInput();
getDocumentProvider().saveDocument(monitor, input, getDocumentProvider().getDocument(input), overwrite);
}
};
}
/**
* Performs the given save operation and handles errors appropriatly.
*
* @param operation the operation to be performed
* @param progressMonitor the monitor in which to run the operation
*/
protected void performSaveOperation(WorkspaceModifyOperation operation, IProgressMonitor progressMonitor) {
IDocumentProvider provider= getDocumentProvider();
if (provider == null)
return;
try {
provider.aboutToChange(getEditorInput());
operation.run(progressMonitor);
editorSaved();
} catch (InterruptedException x) {
} catch (InvocationTargetException x) {
Throwable t= x.getTargetException();
if (t instanceof CoreException)
handleExceptionOnSave((CoreException) t, progressMonitor);
else {
Shell shell= getSite().getShell();
String title= EditorMessages.getString("Editor.error.save.title"); //$NON-NLS-1$
String msg= EditorMessages.getString("Editor.error.save.message"); //$NON-NLS-1$
MessageDialog.openError(shell, title, msg + t.getMessage());
}
} finally {
provider.changed(getEditorInput());
}
}
/**
* 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;
Shell shell= getSite().getShell();
IDocumentProvider p= getDocumentProvider();
long modifiedStamp= p.getModificationStamp(getEditorInput());
long synchStamp= p.getSynchronizationStamp(getEditorInput());
if (fErrorCorrectionOnSave == 1 && modifiedStamp != synchStamp) {
String title= EditorMessages.getString("Editor.error.save.outofsync.title"); //$NON-NLS-1$
String msg= EditorMessages.getString("Editor.error.save.outofsync.message"); //$NON-NLS-1$
if (MessageDialog.openQuestion(shell, title, msg))
performSaveOperation(createSaveOperation(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.getString("Editor.error.save.title"); //$NON-NLS-1$
String msg= EditorMessages.getString("Editor.error.save.message"); //$NON-NLS-1$
ErrorDialog.openError(shell, title, msg, exception.getStatus());
/*
* 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;
}
}
/**
* The <code>AbstractTextEditor</code> implementation of this
* <code>IEditorPart</code> method returns <code>false</code>.
* Subclasses may override.
*/
public boolean isSaveAsAllowed() {
return false;
}
/*
* @see EditorPart#isSaveOnCloseNeeded()
*/
public boolean isSaveOnCloseNeeded() {
IDocumentProvider p= getDocumentProvider();
return p == null ? false : p.mustSaveDocument(getEditorInput());
}
/*
* @see EditorPart#isDirty()
*/
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.
*/
public void doRevertToSaved() {
IDocumentProvider p= getDocumentProvider();
if (p == null)
return;
performRevertOperation(createRevertOperation(), getProgressMonitor());
}
/**
* Creates a workspace modify operation which reverts the content of the editor
* to the last saved state of the editor's input element. Clients may reimplement this method.
*
* @return the revert operation
* @since 2.1
*/
protected WorkspaceModifyOperation createRevertOperation() {
return new WorkspaceModifyOperation() {
protected void execute(final IProgressMonitor monitor) throws CoreException {
IEditorInput input= getEditorInput();
IDocumentProvider provider= getDocumentProvider();
provider.resetDocument(input);
IAnnotationModel model= provider.getAnnotationModel(input);
if (model instanceof AbstractMarkerAnnotationModel) {
AbstractMarkerAnnotationModel markerModel= (AbstractMarkerAnnotationModel) model;
markerModel.resetMarkers();
}
}
};
}
/**
* Performs the given revert operation and handles errors appropriatly.
*
* @param operation the operation to be performed
* @param progressMonitor the monitor in which to run the operation
* @since 2.1
*/
protected void performRevertOperation(WorkspaceModifyOperation operation, IProgressMonitor progressMonitor) {
IDocumentProvider provider= getDocumentProvider();
if (provider == null)
return;
try {
provider.aboutToChange(getEditorInput());
operation.run(progressMonitor);
editorSaved();
} catch (InterruptedException x) {
} catch (InvocationTargetException x) {
Throwable t= x.getTargetException();
Shell shell= getSite().getShell();
String title= EditorMessages.getString("Editor.error.revert.title"); //$NON-NLS-1$
String msg= EditorMessages.getString("Editor.error.revert.message"); //$NON-NLS-1$
MessageDialog.openError(shell, title, msg + t.getMessage());
} finally {
provider.changed(getEditorInput());
}
}
/*
* @see ITextEditor#setAction(String, IAction)
*/
public void setAction(String actionID, IAction action) {
Assert.isNotNull(actionID);
if (action == null) {
action= (IAction) fActions.remove(actionID);
if (action != null)
fActivationCodeTrigger.unregisterActionFromKeyActivation(action);
} else {
fActions.put(actionID, action);
fActivationCodeTrigger.registerActionForKeyActivation(action);
}
}
/*
* @see ITextEditor#setActionActivationCode(String, char, int, int)
*/
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= (ActionActivationCode) fActivationCodes.get(i);
if (actionID.equals(code.fActionId))
return code;
}
return null;
}
/*
* @see ITextEditor#removeActionActivationCode(String)
*/
public void removeActionActivationCode(String actionID) {
Assert.isNotNull(actionID);
ActionActivationCode code= findActionActivationCode(actionID);
if (code != null)
fActivationCodes.remove(code);
}
/*
* @see ITextEditor#getAction(String)
*/
public IAction getAction(String actionID) {
Assert.isNotNull(actionID);
IAction action= (IAction) 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) {
IExtensionPoint extensionPoint= Platform.getPluginRegistry().getExtensionPoint(PlatformUI.PLUGIN_ID, "editorActions"); //$NON-NLS-1$
if (extensionPoint != null) {
IConfigurationElement[] elements= extensionPoint.getConfigurationElements();
List actions= new ArrayList();
for (int i= 0; i < elements.length; i++) {
IConfigurationElement element= elements[i];
if (TAG_CONTRIBUTION_TYPE.equals(element.getName())) {
if (!getSite().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);
}
}
}
Collections.sort(actions, new ConfigurationElementComparator());
if (actions.size() != 0) {
IConfigurationElement element= (IConfigurationElement) actions.get(0);
String defId = element.getAttribute(ActionDescriptor.ATT_DEFINITION_ID);
return new EditorPluginAction(element, "class", this, defId, IAction.AS_UNSPECIFIED); //$NON-NLS-1$
}
}
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= (IAction) 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 e= fSelectionActions.iterator();
while (e.hasNext())
updateAction((String) e.next());
}
}
/**
* Updates all content dependent actions.
*/
protected void updateContentDependentActions() {
if (fContentActions != null) {
Iterator e= fContentActions.iterator();
while (e.hasNext())
updateAction((String) e.next());
}
}
/**
* Updates all property dependent actions.
* @since 2.0
*/
protected void updatePropertyDependentActions() {
if (fPropertyActions != null) {
Iterator e= fPropertyActions.iterator();
while (e.hasNext())
updateAction((String) e.next());
}
}
/**
* Updates all state dependent actions.
* @since 2.0
*/
protected void updateStateDependentActions() {
if (fStateActions != null) {
Iterator e= fStateActions.iterator();
while (e.hasNext())
updateAction((String) 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= getSourceViewer().getTextWidget();
for (int i= 0; i < ACTION_MAP.length; i++) {
IdMapEntry entry= (IdMapEntry) ACTION_MAP[i];
action= new TextNavigationAction(textWidget, entry.getAction());
action.setActionDefinitionId(entry.getActionId());
setAction(entry.getActionId(), action);
}
action= new ToggleInsertModeAction(textWidget);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.TOGGLE_OVERWRITE);
setAction(ITextEditorActionDefinitionIds.TOGGLE_OVERWRITE, action);
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);
setActionActivationCode(ITextEditorActionDefinitionIds.LINE_END, (char) 0, SWT.END, SWT.NONE);
setActionActivationCode(ITextEditorActionDefinitionIds.LINE_START, (char) 0, SWT.HOME, SWT.NONE);
setActionActivationCode(ITextEditorActionDefinitionIds.SELECT_LINE_END, (char) 0, SWT.END, SWT.SHIFT);
setActionActivationCode(ITextEditorActionDefinitionIds.SELECT_LINE_START, (char) 0, SWT.HOME, SWT.SHIFT);
}
/**
* 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 standard actions and connects them with the global
* workbench actions.
* <p>
* Subclasses may extend.</p>
*/
protected void createActions() {
ResourceAction action;
action= new TextOperationAction(EditorMessages.getResourceBundle(), "Editor.Undo.", this, ITextOperationTarget.UNDO); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.UNDO_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.UNDO);
setAction(ITextEditorActionConstants.UNDO, action);
action= new TextOperationAction(EditorMessages.getResourceBundle(), "Editor.Redo.", this, ITextOperationTarget.REDO); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.REDO_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.REDO);
setAction(ITextEditorActionConstants.REDO, action);
action= new TextOperationAction(EditorMessages.getResourceBundle(), "Editor.Cut.", this, ITextOperationTarget.CUT); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.CUT_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.CUT);
setAction(ITextEditorActionConstants.CUT, action);
action= new TextOperationAction(EditorMessages.getResourceBundle(), "Editor.Copy.", this, ITextOperationTarget.COPY, true); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.COPY_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.COPY);
setAction(ITextEditorActionConstants.COPY, action);
action= new TextOperationAction(EditorMessages.getResourceBundle(), "Editor.Paste.", this, ITextOperationTarget.PASTE); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.PASTE_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.PASTE);
setAction(ITextEditorActionConstants.PASTE, action);
action= new TextOperationAction(EditorMessages.getResourceBundle(), "Editor.Delete.", this, ITextOperationTarget.DELETE); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.DELETE_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.DELETE);
setAction(ITextEditorActionConstants.DELETE, action);
action= new DeleteLineAction(EditorMessages.getResourceBundle(), "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.getResourceBundle(), "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.getResourceBundle(), "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.getResourceBundle(), "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.getResourceBundle(), "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.getResourceBundle(), "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 MarkAction(EditorMessages.getResourceBundle(), "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.getResourceBundle(), "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.getResourceBundle(), "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.getResourceBundle(), "Editor.SelectAll.", this, ITextOperationTarget.SELECT_ALL, true); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.SELECT_ALL_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_ALL);
setAction(ITextEditorActionConstants.SELECT_ALL, action);
action= new ShiftAction(EditorMessages.getResourceBundle(), "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.getResourceBundle(), "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.getResourceBundle(), "Editor.Print.", this, ITextOperationTarget.PRINT, true); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.PRINT_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.PRINT);
setAction(ITextEditorActionConstants.PRINT, action);
action= new FindReplaceAction(EditorMessages.getResourceBundle(), "Editor.FindReplace.", this); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.FIND_REPLACE);
setAction(ITextEditorActionConstants.FIND, action);
action= new FindNextAction(EditorMessages.getResourceBundle(), "Editor.FindNext.", this, true); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_NEXT_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.FIND_NEXT);
setAction(ITextEditorActionConstants.FIND_NEXT, action);
action= new FindNextAction(EditorMessages.getResourceBundle(), "Editor.FindPrevious.", this, false); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_PREVIOUS_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.FIND_PREVIOUS);
setAction(ITextEditorActionConstants.FIND_PREVIOUS, action);
action= new IncrementalFindAction(EditorMessages.getResourceBundle(), "Editor.FindIncremental.", this, true); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_INCREMENTAL_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.FIND_INCREMENTAL);
setAction(ITextEditorActionConstants.FIND_INCREMENTAL, action);
action= new IncrementalFindAction(EditorMessages.getResourceBundle(), "Editor.FindIncrementalReverse.", this, false); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_INCREMENTAL_REVERSE_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.FIND_INCREMENTAL_REVERSE);
setAction(ITextEditorActionConstants.FIND_INCREMENTAL_REVERSE, action);
action= new AddMarkerAction(EditorMessages.getResourceBundle(), "Editor.AddBookmark.", this, IMarker.BOOKMARK, true); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.BOOKMARK_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.ADD_BOOKMARK);
setAction(ITextEditorActionConstants.BOOKMARK, action);
// FIXME: need another way to contribute this action
// action= new AddTaskAction(EditorMessages.getResourceBundle(), "Editor.AddTask.", this); //$NON-NLS-1$
// action.setHelpContextId(IAbstractTextEditorHelpContextIds.ADD_TASK_ACTION);
// action.setActionDefinitionId(ITextEditorActionDefinitionIds.ADD_TASK);
// setAction(ITextEditorActionConstants.ADD_TASK, action);
action= new SaveAction(EditorMessages.getResourceBundle(), "Editor.Save.", this); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.SAVE_ACTION);
// action.setActionDefinitionId(ITextEditorActionDefinitionIds.SAVE);
setAction(ITextEditorActionConstants.SAVE, action);
action= new RevertToSavedAction(EditorMessages.getResourceBundle(), "Editor.Revert.", this); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.REVERT_TO_SAVED_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.REVERT_TO_SAVED);
setAction(ITextEditorActionConstants.REVERT_TO_SAVED, action);
action= new GotoLineAction(EditorMessages.getResourceBundle(), "Editor.GotoLine.", this); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.GOTO_LINE_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.LINE_GOTO);
setAction(ITextEditorActionConstants.GOTO_LINE, action);
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_LEFT, true);
markAsPropertyDependentAction(ITextEditorActionConstants.REVERT_TO_SAVED, 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_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.CUT_LINE, true);
markAsStateDependentAction(ITextEditorActionConstants.CUT_LINE_TO_BEGINNING, true);
markAsStateDependentAction(ITextEditorActionConstants.CUT_LINE_TO_END, true);
setActionActivationCode(ITextEditorActionConstants.SHIFT_RIGHT,'\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) {
for (Iterator i = fRulerContextMenuListeners.iterator(); i.hasNext();)
((IMenuListener) i.next()).menuAboutToShow(menu);
addAction(menu, ITextEditorActionConstants.RULER_MANAGE_BOOKMARKS);
addAction(menu, ITextEditorActionConstants.RULER_MANAGE_TASKS);
menu.add(new Separator(ITextEditorActionConstants.GROUP_REST));
menu.add(new Separator(ITextEditorActionConstants.MB_ADDITIONS));
}
/**
* 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 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(ITextEditorActionConstants.GROUP_ADD));
menu.add(new Separator(ITextEditorActionConstants.GROUP_REST));
menu.add(new Separator(ITextEditorActionConstants.MB_ADDITIONS));
menu.add(new Separator(ITextEditorActionConstants.GROUP_SAVE));
if (isEditable()) {
addAction(menu, ITextEditorActionConstants.GROUP_UNDO, ITextEditorActionConstants.UNDO);
addAction(menu, ITextEditorActionConstants.GROUP_UNDO, ITextEditorActionConstants.REVERT_TO_SAVED);
addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.CUT);
addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.COPY);
addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.PASTE);
addAction(menu, ITextEditorActionConstants.GROUP_SAVE, ITextEditorActionConstants.SAVE);
} 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
*/
private IStatusLineManager getStatusLineManager() {
IEditorActionBarContributor contributor= getEditorSite().getActionBarContributor();
if (!(contributor instanceof EditorActionBarContributor))
return null;
IActionBars actionBars= ((EditorActionBarContributor) contributor).getActionBars();
if (actionBars == null)
return null;
return actionBars.getStatusLineManager();
}
/*
* @see IAdaptable#getAdapter(java.lang.Class)
*/
public Object getAdapter(Class 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 fEditorStatusLine;
}
if (IVerticalRulerInfo.class.equals(required)) {
if (fVerticalRuler instanceof IVerticalRulerInfo)
return fVerticalRuler;
}
if (IMarkRegionTarget.class.equals(required)) {
if (fMarkRegionTarget == null) {
IStatusLineManager manager= getStatusLineManager();
if (manager != null)
fMarkRegionTarget= (fSourceViewer == null ? null : new MarkRegionTarget(fSourceViewer, manager));
}
return fMarkRegionTarget;
}
if (DeleteLineTarget.class.equals(required)){
if (fDeleteLineTarget == null) {
fDeleteLineTarget = new DeleteLineTarget(fSourceViewer);
}
return fDeleteLineTarget;
}
if (IncrementalFindTarget.class.equals(required)) {
if (fIncrementalFindTarget == null) {
IStatusLineManager manager= getStatusLineManager();
if (manager != null)
fIncrementalFindTarget= (fSourceViewer == null ? null : new IncrementalFindTarget(fSourceViewer, manager));
}
return 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 fFindReplaceTarget;
}
if (ITextOperationTarget.class.equals(required))
return (fSourceViewer == null ? null : fSourceViewer.getTextOperationTarget());
if (IRewriteTarget.class.equals(required)) {
if (fSourceViewer instanceof ITextViewerExtension) {
ITextViewerExtension extension= (ITextViewerExtension) fSourceViewer;
return extension.getRewriteTarget();
}
return null;
}
return super.getAdapter(required);
}
/*
* @see IWorkbenchPart#setFocus()
*/
public void setFocus() {
if (fSourceViewer != null && fSourceViewer.getTextWidget() != null)
fSourceViewer.getTextWidget().setFocus();
}
/**
* If the editor can be saved all marker ranges have been changed according to
* the text manipulations. However, those changes are not yet propagated to the
* marker manager. Thus, when opening a marker, the marker's position in the editor
* must be determined as it might differ from the position stated in the marker.
*
* @param marker the marker to go to
* @see EditorPart#gotoMarker(org.eclipse.core.resources.IMarker)
*/
public void gotoMarker(IMarker marker) {
if (fSourceViewer == null)
return;
int start= MarkerUtilities.getCharStart(marker);
int end= MarkerUtilities.getCharEnd(marker);
if (start < 0 || end < 0) {
// there is only a line number
int line= MarkerUtilities.getLineNumber(marker);
if (line > -1) {
// marker line numbers are 1-based
-- line;
try {
IDocument document= getDocumentProvider().getDocument(getEditorInput());
selectAndReveal(document.getLineOffset(line), document.getLineLength(line));
} catch (BadLocationException x) {
// marker refers to invalid text position -> do nothing
}
}
} else {
// look up the current range of the marker when the document has been edited
IAnnotationModel model= getDocumentProvider().getAnnotationModel(getEditorInput());
if (model instanceof AbstractMarkerAnnotationModel) {
AbstractMarkerAnnotationModel markerModel= (AbstractMarkerAnnotationModel) model;
Position pos= markerModel.getMarkerPosition(marker);
if (pos != null && !pos.isDeleted()) {
// use position instead of marker values
start= pos.getOffset();
end= pos.getOffset() + pos.getLength();
}
if (pos != null && pos.isDeleted()) {
// do nothing if position has been deleted
return;
}
}
IDocument document= getDocumentProvider().getDocument(getEditorInput());
int length= document.getLength();
if (end - 1 < length && start < length)
selectAndReveal(start, end - start);
}
}
/*
* @see ITextEditor#showsHighlightRangeOnly()
*/
public boolean showsHighlightRangeOnly() {
return fShowHighlightRangeOnly;
}
/*
* @see ITextEditor#showHighlightRangeOnly(boolean)
*/
public void showHighlightRangeOnly(boolean showHighlightRangeOnly) {
fShowHighlightRangeOnly= showHighlightRangeOnly;
}
/*
* @see ITextEditor#setHighlightRange(int, int, boolean)
*/
public void setHighlightRange(int start, int length, boolean moveCursor) {
if (fSourceViewer == null)
return;
if (fShowHighlightRangeOnly) {
if (moveCursor)
fSourceViewer.setVisibleRegion(start, length);
} else {
IRegion rangeIndication= fSourceViewer.getRangeIndication();
if (rangeIndication == null || start != rangeIndication.getOffset() || length != rangeIndication.getLength())
fSourceViewer.setRangeIndication(start, length, moveCursor);
}
}
/*
* @see ITextEditor#getHighlightRange()
*/
public IRegion getHighlightRange() {
if (fSourceViewer == null)
return null;
if (fShowHighlightRangeOnly)
return getCoverage(fSourceViewer);
return fSourceViewer.getRangeIndication();
}
/*
* @see ITextEditor#resetHighlightRange
*/
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 (!isVisible(fSourceViewer, offset, length))
fSourceViewer.resetVisibleRegion();
}
/*
* @see ITextEditor#selectAndReveal(int, int)
*/
public void selectAndReveal(int start, int length) {
if (fSourceViewer == null)
return;
ISelection selection= getSelectionProvider().getSelection();
if (selection instanceof TextSelection) {
TextSelection textSelection= (TextSelection) selection;
if (textSelection.getOffset() != 0 || textSelection.getLength() != 0)
markInNavigationHistory();
}
StyledText widget= fSourceViewer.getTextWidget();
widget.setRedraw(false);
{
adjustHighlightRange(start, length);
fSourceViewer.revealRange(start, length);
fSourceViewer.setSelectedRange(start, length);
markInNavigationHistory();
}
widget.setRedraw(true);
}
/*
* @see org.eclipse.ui.INavigationLocationProvider#createNavigationLocation()
* @since 2.1
*/
public INavigationLocation createEmptyNavigationLocation() {
return new TextSelectionNavigationLocation(this, false);
}
/*
* @see org.eclipse.ui.INavigationLocationProvider#createNavigationLocation()
*/
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() {
IWorkbenchPage page= getEditorSite().getPage();
page.getNavigationHistory().markLocation(this);
}
/**
* Hook which gets called when the editor has been saved.
* Subclasses may extend.
* @since 2.1
*/
protected void editorSaved() {
IWorkbenchPage page= getEditorSite().getPage();
INavigationLocation[] locations= page.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);
}
}
}
}
/*
* @see WorkbenchPart#firePropertyChange(int)
*/
protected void firePropertyChange(int property) {
super.firePropertyChange(property);
updatePropertyDependentActions();
}
/*
* @see ITextEditorExtension#setStatusField(IStatusField, String)
* @since 2.0
*/
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);
}
/**
* 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 (IStatusField) 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 !fOverwriting;
}
/**
* Handles a potential change of the cursor position.
* Subclasses may extend.
*
* @since 2.0
*/
protected void handleCursorPositionChanged() {
updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_POSITION);
}
/**
* Handles a change of the editor's insert mode.
* Subclasses may extend.
*
* @since 2.0
*/
protected void handleInsertModeChanged() {
updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_MODE);
}
/**
* Updates the status fields for the given category.
*
* @param 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))
text= isInInsertMode() ? fInsertModeLabel : fOverwriteModeLabel;
field.setText(text == null ? fErrorLabel : text);
}
}
/**
* Updates all status fields.
*
* @since 2.0
*/
protected void updateStatusFields() {
if (fStatusFields != null) {
Iterator e= fStatusFields.keySet().iterator();
while (e.hasNext())
updateStatusField((String) 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 - (column % tabWidth);
else
column++;
fLineLabel.fValue= line + 1;
fColumnLabel.fValue= column + 1;
return MessageFormat.format(fPositionLabelPattern, fPositionLabelPatternArguments);
} catch (BadLocationException x) {
return fErrorLabel;
}
}
/*
* @see ITextEditorExtension#isEditorInputReadOnly()
* @since 2.0
*/
public boolean isEditorInputReadOnly() {
IDocumentProvider provider= getDocumentProvider();
if (provider instanceof IDocumentProviderExtension) {
IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
return extension.isReadOnly(getEditorInput());
}
return true;
}
/*
* @see ITextEditorExtension2#isEditorInputModifiable()
* @since 2.1
*/
public boolean isEditorInputModifiable() {
IDocumentProvider provider= getDocumentProvider();
if (provider instanceof IDocumentProviderExtension) {
IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
return extension.isModifiable(getEditorInput());
}
return true;
}
/*
* @see ITextEditorExtension#addRulerContextMenuListener(IMenuListener)
* @since 2.0
*/
public void addRulerContextMenuListener(IMenuListener listener) {
fRulerContextMenuListeners.add(listener);
}
/*
* @see ITextEditorExtension#removeRulerContextMenuListener(IMenuListener)
* @since 2.0
*/
public void removeRulerContextMenuListener(IMenuListener listener) {
fRulerContextMenuListeners.remove(listener);
}
/**
* Returns wether 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
* @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 final static int widgetOffset2ModelOffset(ISourceViewer viewer, int widgetOffset) {
if (viewer instanceof ITextViewerExtension3) {
ITextViewerExtension3 extension= (ITextViewerExtension3) viewer;
return extension.widgetOffset2ModelOffset(widgetOffset);
}
return widgetOffset + 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.
*
* @return the minimal region of the source viewer's document comprising the contents of the viewer's widget
* @since 2.1
*/
protected final static IRegion getCoverage(ISourceViewer viewer) {
if (viewer instanceof ITextViewerExtension3) {
ITextViewerExtension3 extension= (ITextViewerExtension3) 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
* @since 2.1
*/
protected final static boolean isVisible(ISourceViewer viewer, int offset, int length) {
if (viewer instanceof ITextViewerExtension3) {
ITextViewerExtension3 extension= (ITextViewerExtension3) viewer;
IRegion overlap= extension.modelRange2WidgetRange(new Region(offset, length));
return overlap != null;
}
return viewer.overlapsWithVisibleRegion(offset, length);
}
}