blob: fa804e73d8e73b98a544485775b83302cad766b2 [file] [log] [blame]
package org.eclipse.ui.texteditor;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
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.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.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.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
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.IRegion;
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.Position;
import org.eclipse.jface.text.TextEvent;
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.util.Assert;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
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.IPartListener;
import org.eclipse.ui.IReusableEditor;
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.EditorPluginAction;
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 arguments 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 {
private static final String TAG_CONTRIBUTION_TYPE= "editorContribution"; //$NON-NLS-1$
/**
* Internal element state listener.
*/
class ElementStateListener implements IElementStateListener, IElementStateListenerExtension {
class Validator implements VerifyListener {
private boolean fInputChanged;
private ITextInputListener fInputListener= new ITextInputListener() {
public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {}
public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { fInputChanged= true; }
};
public void verifyText(VerifyEvent e) {
ISourceViewer viewer= getSourceViewer();
fInputChanged= false;
viewer.addTextInputListener(fInputListener);
try {
validateState(getEditorInput());
sanityCheckState(getEditorInput());
if (isEditorInputReadOnly() || fInputChanged)
e.doit= false;
} finally {
viewer.removeTextInputListener(fInputListener);
}
}
};
private Validator fValidator;
/*
* @see IElementStateListenerExtension#elementStateValidationChanged(Object, boolean)
*/
public void elementStateValidationChanged(Object element, boolean isStateValidated) {
if (element != null && element.equals(getEditorInput())) {
if (isStateValidated && fValidator != null) {
ISourceViewer viewer= getSourceViewer();
if (viewer != null) {
StyledText textWidget= viewer.getTextWidget();
if (textWidget != null && !textWidget.isDisposed())
textWidget.removeVerifyListener(fValidator);
fValidator= null;
}
} else if (!isStateValidated && fValidator == null) {
ISourceViewer viewer= getSourceViewer();
if (viewer != null) {
StyledText textWidget= viewer.getTextWidget();
if (textWidget != null && !textWidget.isDisposed()) {
fValidator= new Validator();
textWidget.addVerifyListener(fValidator);
}
}
}
}
}
/*
* @see IElementStateListener#elementDirtyStateChanged
*/
public void elementDirtyStateChanged(Object element, boolean isDirty) {
if (element != null && element.equals(getEditorInput()))
firePropertyChange(PROP_DIRTY);
}
/*
* @see IElementStateListener#elementContentAboutToBeReplaced
*/
public void elementContentAboutToBeReplaced(Object element) {
if (element != null && element.equals(getEditorInput())) {
rememberSelection();
resetHighlightRange();
}
}
/*
* @see IElementStateListener#elementContentReplaced
*/
public void elementContentReplaced(Object element) {
if (element != null && element.equals(getEditorInput())) {
firePropertyChange(PROP_DIRTY);
restoreSelection();
}
}
/*
* @see IElementStateListener#elementDeleted
*/
public void elementDeleted(Object deletedElement) {
if (deletedElement != null && deletedElement.equals(getEditorInput()))
close(false);
}
/*
* @see IElementStateListener#elementMoved
*/
public void elementMoved(Object originalElement, Object movedElement) {
if (originalElement != null &&
originalElement.equals(getEditorInput()) &&
(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();
}
}
};
/**
* Internal text listener.
*/
class TextListener implements ITextListener {
private Runnable fRunnable= new Runnable() {
public void run() {
if (fSourceViewer != null) {
// check whether editor has not been disposed yet
updateContentDependentActions();
}
}
};
private Display fDisplay;
/*
* @see ITextListener#textChanged(TextEvent)
*/
public void textChanged(TextEvent event) {
if (fDisplay == null)
fDisplay= getSite().getShell().getDisplay();
fDisplay.asyncExec(fRunnable);
}
};
static class ConfigurationElementComparator implements Comparator {
/*
* @see Comparator#compare(Object, Object)
*/
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;
}
private static boolean dependsOn(IConfigurationElement element0, IConfigurationElement element1) {
IPluginDescriptor descriptor0= element0.getDeclaringExtension().getDeclaringPluginDescriptor();
IPluginDescriptor descriptor1= element1.getDeclaringExtension().getDeclaringPluginDescriptor();
return dependsOn(descriptor0, descriptor1);
}
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.
*/
class PropertyChangeListener implements IPropertyChangeListener {
/*
* @see IPropertyChangeListener#propertyChange(PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent event) {
handlePreferenceStoreChanged(event);
}
};
/**
* Internal key verify listener for triggering action activation codes.
*/
class ActivationCodeTrigger implements VerifyKeyListener {
private boolean fIsInstalled= false;
private IKeyBindingService fKeyBindingService;
/*
* @see VerifyKeyListener#verifyKey(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;
}
}
}
}
if (fKeyBindingService.processKey(event))
event.doit= false;
}
/**
* Installs this trigger on the editor's text widget.
*/
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();
fKeyBindingService.enable(true);
fIsInstalled= true;
}
}
/**
* Uninstalls this trigger from the editor's text widget.
*/
public void uninstall() {
if (fIsInstalled) {
if (fSourceViewer instanceof ITextViewerExtension) {
ITextViewerExtension e= (ITextViewerExtension) fSourceViewer;
e.removeVerifyKeyListener(this);
} else {
StyledText text= fSourceViewer.getTextWidget();
text.removeVerifyKeyListener(fActivationCodeTrigger);
}
fIsInstalled= false;
fKeyBindingService= null;
}
}
/**
* Registers the given action for key activation.
*/
public void registerActionForKeyActivation(IAction action) {
if (action.getActionDefinitionId() != null)
fKeyBindingService.registerAction(action);
}
/**
* The given action is no longer available for key activation
*/
public void unregisterActionFromKeyActivation(IAction action) {
// No such action available on the service
}
};
/**
* Representation of action activation codes.
*/
class ActionActivationCode {
public String fActionId;
public char fCharacter;
public int fKeyCode;
public int fStateMask;
public ActionActivationCode(String actionId) {
fActionId= actionId;
}
public boolean matches(VerifyEvent event) {
return (event.character == fCharacter &&
event.keyCode == fKeyCode &&
event.stateMask == fStateMask);
}
};
/**
* Internal part and shell activation listener
*/
class ActivationListener extends ShellAdapter implements IPartListener {
private IWorkbenchPart fActivePart;
private boolean fIsHandlingActivation= false;
/*
* @see IPartListener#partActivated(IWorkbenchPart)
*/
public void partActivated(IWorkbenchPart part) {
fActivePart= part;
handleActivation();
}
/*
* @see IPartListener#partBroughtToTop(IWorkbenchPart)
*/
public void partBroughtToTop(IWorkbenchPart part) {
}
/*
* @see IPartListener#partClosed(IWorkbenchPart)
*/
public void partClosed(IWorkbenchPart part) {
}
/*
* @see IPartListener#partDeactivated(IWorkbenchPart)
*/
public void partDeactivated(IWorkbenchPart part) {
fActivePart= null;
}
/*
* @see IPartListener#partOpened(IWorkbenchPart)
*/
public void partOpened(IWorkbenchPart part) {
}
/*
* @see ShellListener#shellActivated(ShellEvent)
*/
public void shellActivated(ShellEvent e) {
handleActivation();
}
private void handleActivation() {
if (fIsHandlingActivation)
return;
if (fActivePart == AbstractTextEditor.this) {
fIsHandlingActivation= true;
try {
sanityCheckState(getEditorInput());
} finally {
fIsHandlingActivation= false;
}
}
}
};
/**
* Internal interface for a cursor listener. I.e. aggregation
* of mouse and key listener.
*/
interface ICursorListener extends MouseListener, KeyListener {
};
/**
* Maps an action definition id to an StyledText action.
*/
static class IdMapEntry {
private String fActionId;
private int fAction;
public IdMapEntry(String actionId, int action) {
fActionId= actionId;
fAction= action;
}
public String getActionId() {
return fActionId;
}
public int getAction() {
return fAction;
}
};
/**
* Internal action to scroll the editor's viewer by a specified number of lines.
*/
class ScrollLinesAction extends Action {
private int fScrollIncrement;
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);
}
};
/**
* Internal action to show the editor's ruler context menu (accessibility).
*/
private class ShowRulerContextMenuAction extends Action {
/*
* @see IAction#run()
*/
public void run() {
fRulerContextMenu.setVisible(true);
}
}
/** Key used to look up font preference */
public final static String PREFERENCE_FONT= JFaceResources.TEXT_FONT;
/** Key used to look up foreground color preference */
public final static String PREFERENCE_COLOR_FOREGROUND= "AbstractTextEditor.Color.Foreground"; //$NON-NLS-1$
/** Key used to look up background color preference */
public final static String PREFERENCE_COLOR_BACKGROUND= "AbstractTextEditor.Color.Background"; //$NON-NLS-1$
/** Key used to look up foreground color system default preference */
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 */
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 */
public final static String PREFERENCE_COLOR_FIND_SCOPE= "AbstractTextEditor.Color.FindScope"; //$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. */
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),
// miscellaneous
new IdMapEntry(ITextEditorActionDefinitionIds.TOGGLE_OVERWRITE, ST.TOGGLE_OVERWRITE)
};
/* Status line labels */
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$
private static class PositionLabelValue {
public int fValue;
public String toString() {
return String.valueOf(fValue);
}
};
private final String fPositionLabelError= EditorMessages.getString("Editor.statusline.position.error.label"); //$NON-NLS-1$
private final String fPositionLabelPattern= EditorMessages.getString("Editor.statusline.position.pattern"); //$NON-NLS-1$
private final PositionLabelValue fLineLabel= new PositionLabelValue();
private final PositionLabelValue fColumnLabel= new PositionLabelValue();
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 font */
private Font fFont;
/** The editor's foreground color */
private Color fForegroundColor;
/** The editor's background color */
private Color fBackgroundColor;
/** The find scope's highlight color */
private Color fFindScopeHighlightColor;
/** 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 */
private List fPropertyActions= new ArrayList(5);
/** The actions marked as state dependent */
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 listener */
private ITextListener fTextListener= new TextListener();
/** The editor's property change listener */
private IPropertyChangeListener fPropertyChangeListener= new PropertyChangeListener();
/** The editor's activation listener */
private ActivationListener fActivationListener= new ActivationListener();
/** The map of the editor's status fields */
private Map fStatusFields;
/** The editor's cursor listener */
private ICursorListener fCursorListener;
/** The editor's insert mode */
private boolean fOverwriting= false;
/** The editor's remembered text selection */
private ITextSelection fRememberedSelection;
/** Indicates whether the editor runs in 1.0 context menu registration compatibility mode */
private boolean fCompatibilityMode= true;
/** The number of reentrances into error correction code while saving */
private int fErrorCorrectionOnSave;
/** The incremental find target */
private IncrementalFindTarget fIncrementalFindTarget;
/** Cached modification stamp of the editor's input */
private long fModificationStamp= -1;
/**
* 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
*/
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 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 (fSourceViewer != null ? fSourceViewer.getSelectionProvider() : null);
}
/**
* 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.
*
* @see #restoreSelection
*/
protected void rememberSelection() {
ISelectionProvider sp= getSelectionProvider();
fRememberedSelection= (sp == null ? null : (ITextSelection) 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
*/
protected void restoreSelection() {
if (getSourceViewer() != null && fRememberedSelection != null)
selectAndReveal(fRememberedSelection.getOffset(), fRememberedSelection.getLength());
fRememberedSelection= null;
}
/**
* 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) {
}
};
}
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();
handleCursorPositionChanged();
}
}
};
private Display fDisplay;
public void selectionChanged(SelectionChangedEvent event) {
if (fDisplay == null)
fDisplay= getSite().getShell().getDisplay();
fDisplay.asyncExec(fRunnable);
}
};
}
return fSelectionChangedListener;
}
/**
* Returns this editor's "cursor" listener to be installed on the editor's
* source viewer. This listener is listening to key and mouse button events.
*
* @return the listener
*/
protected final ICursorListener getCursorListener() {
if (fCursorListener == null) {
fCursorListener= new ICursorListener() {
public void keyPressed(KeyEvent e) {
if (e.keyCode != 0) {
StyledText styledText= (StyledText) e.widget;
int action = styledText.getKeyBinding(e.keyCode | e.stateMask);
if (ST.TOGGLE_OVERWRITE == action) {
fOverwriting= !fOverwriting;
handleInsertModeChanged();
}
}
}
public void keyReleased(KeyEvent e) {
handleCursorPositionChanged();
}
public void mouseDoubleClick(MouseEvent e) {
}
public void mouseDown(MouseEvent e) {
}
public void mouseUp(MouseEvent e) {
handleCursorPositionChanged();
}
};
}
return fCursorListener;
}
/*
* @see IEditorPart#init
*/
public void init(IEditorSite site, IEditorInput input) throws PartInitException {
setSite(site);
try {
doSetInput(input);
} catch (CoreException x) {
throw new PartInitException(x.getStatus());
}
IWorkbenchWindow window= getSite().getWorkbenchWindow();
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.
*/
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();
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);
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);
if (fVerticalRuler instanceof IVerticalRulerInfo) {
IVerticalRulerInfo info= (IVerticalRulerInfo) fVerticalRuler;
info.addMouseListener(getRulerMouseListener());
} else {
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());
fActivationCodeTrigger.install();
createNavigationActions();
createAccessibilityActions();
createActions();
initializeSourceViewer(getEditorInput());
}
/**
* Initializes the given widget's font.
*
* @param styledText the widget to be initialized
*/
private void initializeViewerFont(ISourceViewer viewer) {
IPreferenceStore store= getPreferenceStore();
if (store != null) {
FontData data= null;
if (store.contains(PREFERENCE_FONT) && !store.isDefault(PREFERENCE_FONT))
data= PreferenceConverter.getFontData(store, PREFERENCE_FONT);
else
data= PreferenceConverter.getDefaultFontData(store, PREFERENCE_FONT);
if (data != null) {
Font font= new Font(viewer.getTextWidget().getDisplay(), data);
setFont(viewer, font);
if (fFont != null)
fFont.dispose();
fFont= font;
return;
}
}
// if all the preferences failed
setFont(viewer, JFaceResources.getTextFont());
}
/**
* Sets the font for the given viewer sustaining selection and scroll position.
*
* @param sourceViewer the source viewer
* @param font the font
*/
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.
*/
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
*/
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;
}
}
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) {
if (getDocumentProvider() != null)
getDocumentProvider().removeElementStateListener(fElementStateListener);
if (fInternalDocumentProvider == null)
fExternalDocumentProvider= DocumentProviderRegistry.getDefault().getDocumentProvider(input);
if (getDocumentProvider() != null)
getDocumentProvider().addElementStateListener(fElementStateListener);
}
/**
* 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
*/
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) {
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 (fPropertyChangeListener != null) {
if (fPreferenceStore != null) {
fPreferenceStore.removePropertyChangeListener(fPropertyChangeListener);
fPreferenceStore= null;
}
fPropertyChangeListener= 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;
}
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) {
fActivationCodeTrigger= null;
fActivationCodes.clear();
fActivationCodes= 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 whether the event describes a preference change affecting the editor's
* presentation
*/
protected boolean affectsTextPresentation(PropertyChangeEvent event) {
return false;
}
/**
* 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 (PREFERENCE_FONT.equals(property)) {
initializeViewerFont(fSourceViewer);
} 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();
}
/**
* Handles an external change of the editor's input element.
*/
protected void handleEditorInputChanged() {
String title;
String msg;
Shell shell= getSite().getShell();
IDocumentProvider provider= getDocumentProvider();
if (provider == null) {
// fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=15066
close(false);
return;
}
if (provider.isDeleted(getEditorInput())) {
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) {
NullProgressMonitor pm= new NullProgressMonitor();
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$
MessageDialog.openConfirm(shell, title, msg);
}
} 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)) {
try {
doSetInput(getEditorInput());
} catch (CoreException x) {
title= EditorMessages.getString("Editor.error.refresh.outofsync.title"); //$NON-NLS-1$
msg= EditorMessages.getString("Editor.error.refresh.outofsync.message"); //$NON-NLS-1$
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.
*/
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 does nothing. 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(new NullProgressMonitor());
}
/**
* 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.
*/
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);
}
}
/**
* Checks the state of the editor input.
*/
protected void sanityCheckState(IEditorInput input) {
IDocumentProvider p= getDocumentProvider();
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);
}
/**
* 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
*/
protected void validateState(IEditorInput input) {
IDocumentProvider provider= getDocumentProvider();
if (provider instanceof IDocumentProviderExtension) {
IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
try {
extension.validateState(input, getSite().getShell());
if (fSourceViewer != null)
fSourceViewer.setEditable(isEditable());
} catch (CoreException x) {
ILog log= Platform.getPlugin(PlatformUI.PLUGIN_ID).getLog();
log.log(x.getStatus());
}
}
}
/**
* Updates the state of the given editor input such as Read-only flag etc.
*
* @param input the input to be validated
*/
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();
try {
provider.aboutToChange(getEditorInput());
operation.run(progressMonitor);
} 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 a 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 IEditorPart#isSaveOnCloseNeeded()
*/
public boolean isSaveOnCloseNeeded() {
IDocumentProvider p= getDocumentProvider();
return p == null ? false : p.mustSaveDocument(getEditorInput());
}
/*
* @see IEditorPart#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;
try {
p.resetDocument(getEditorInput());
IAnnotationModel model= p.getAnnotationModel(getEditorInput());
if (model instanceof AbstractMarkerAnnotationModel) {
AbstractMarkerAnnotationModel markerModel= (AbstractMarkerAnnotationModel) model;
markerModel.resetMarkers();
}
firePropertyChange(PROP_DIRTY);
} catch (CoreException x) {
String title= EditorMessages.getString("Editor.error.revert.title"); //$NON-NLS-1$
String msg= EditorMessages.getString("Editor.error.revert.message"); //$NON-NLS-1$
Shell shell= getSite().getShell();
ErrorDialog.openError(shell, title, msg, x.getStatus());
}
}
/*
* @see ITextEditor#setAction
*/
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
*/
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;
}
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);
return new EditorPluginAction(element, "class", this); //$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
*/
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
*/
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.
*/
protected void updatePropertyDependentActions() {
if (fPropertyActions != null) {
Iterator e= fPropertyActions.iterator();
while (e.hasNext())
updateAction((String) e.next());
}
}
/**
* Updates all state dependent actions.
*/
protected void updateStateDependentActions() {
if (fStateActions != null) {
Iterator e= fStateActions.iterator();
while (e.hasNext())
updateAction((String) e.next());
}
}
/**
* Creates this editor's standard navigation actions.
* <p>
* Subclasses may extend.
* </p>
*/
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 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);
}
/**
* Creates this editor's accessibility actions.
*/
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 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_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_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.FIND_PREVIOUS);
setAction(ITextEditorActionConstants.FIND_PREVIOUS, action);
action= new IncrementalFindAction(EditorMessages.getResourceBundle(), "Editor.FindIncremental.", this); //$NON-NLS-1$
action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_ACTION);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.FIND_INCREMENTAL);
setAction(ITextEditorActionConstants.FIND_INCREMENTAL, 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);
action= new AddMarkerAction(EditorMessages.getResourceBundle(), "Editor.AddTask.", this, IMarker.TASK, true); //$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);
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);
setActionActivationCode(ITextEditorActionConstants.SHIFT_RIGHT,'\t', 0, 0);
setActionActivationCode(ITextEditorActionConstants.SHIFT_LEFT, '\t', 0, SWT.SHIFT);
}
/**
* Convenience method to add the action installed under the given action id
* to the given menu.
*/
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.
*/
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.
*/
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) {
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) {
if (isEditable()) {
menu.add(new Separator(ITextEditorActionConstants.GROUP_UNDO));
addAction(menu, ITextEditorActionConstants.UNDO);
addAction(menu, ITextEditorActionConstants.REDO);
addAction(menu, ITextEditorActionConstants.REVERT_TO_SAVED);
}
menu.add(new Separator(ITextEditorActionConstants.GROUP_COPY));
if (isEditable()) {
addAction(menu, ITextEditorActionConstants.CUT);
addAction(menu, ITextEditorActionConstants.COPY);
addAction(menu, ITextEditorActionConstants.PASTE);
addAction(menu, ITextEditorActionConstants.SELECT_ALL);
} else {
addAction(menu, ITextEditorActionConstants.COPY);
addAction(menu, ITextEditorActionConstants.SELECT_ALL);
}
menu.add(new Separator(ITextEditorActionConstants.GROUP_PRINT));
menu.add(new Separator(ITextEditorActionConstants.GROUP_EDIT));
addAction(menu, ITextEditorActionConstants.SHIFT_RIGHT);
addAction(menu, ITextEditorActionConstants.SHIFT_LEFT);
menu.add(new Separator(ITextEditorActionConstants.GROUP_FIND));
addAction(menu, ITextEditorActionConstants.FIND);
addAction(menu, ITextEditorActionConstants.GOTO_LINE);
String label= EditorMessages.getString("Editor.AddMenu.label"); //$NON-NLS-1$
MenuManager submenu= new MenuManager(label, ITextEditorActionConstants.GROUP_ADD);
addAction(submenu, ITextEditorActionConstants.BOOKMARK);
addAction(submenu, ITextEditorActionConstants.ADD_TASK);
menu.add(submenu);
menu.add(new Separator(ITextEditorActionConstants.GROUP_SAVE));
if (isEditable())
addAction(menu, ITextEditorActionConstants.SAVE);
menu.add(new Separator(ITextEditorActionConstants.GROUP_REST));
menu.add(new Separator(ITextEditorActionConstants.MB_ADDITIONS));
}
/*
* @see IAdaptable#getAdapter(Class)
*/
public Object getAdapter(Class required) {
if (IVerticalRulerInfo.class.equals(required)) {
if (fVerticalRuler instanceof IVerticalRulerInfo)
return fVerticalRuler;
}
if (IncrementalFindTarget.class.equals(required)) {
if (fIncrementalFindTarget == null) {
IEditorActionBarContributor contributor= getEditorSite().getActionBarContributor();
if (contributor instanceof EditorActionBarContributor) {
IStatusLineManager manager= ((EditorActionBarContributor) contributor).getActionBars().getStatusLineManager();
fIncrementalFindTarget= (fSourceViewer == null ? null : new IncrementalFindTarget(fSourceViewer, manager));
}
}
return fIncrementalFindTarget;
}
if (IFindReplaceTarget.class.equals(required)) {
IFindReplaceTarget target= (fSourceViewer == null ? null : fSourceViewer.getFindReplaceTarget());
if (target != null && target instanceof IFindReplaceTargetExtension)
((IFindReplaceTargetExtension) target).setScopeHighlightColor(fFindScopeHighlightColor);
return target;
}
if (ITextOperationTarget.class.equals(required))
return (fSourceViewer == null ? null : fSourceViewer.getTextOperationTarget());
return super.getAdapter(required);
}
/*
* @see IDesktopPart#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.
* @see EditorPart#gotoMarker
*/
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()) {
// do nothing if position has been deleted
return;
}
start= pos.getOffset();
end= pos.getOffset() + pos.getLength();
}
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
*/
public void showHighlightRangeOnly(boolean showHighlightRangeOnly) {
fShowHighlightRangeOnly= showHighlightRangeOnly;
}
/*
* @see ITextEditor#setHighlightRange
*/
public void setHighlightRange(int start, int length, boolean moveCursor) {
if (fSourceViewer == null)
return;
if (fShowHighlightRangeOnly) {
if (moveCursor) {
IRegion visibleRegion= fSourceViewer.getVisibleRegion();
if (start != visibleRegion.getOffset() || length != visibleRegion.getLength())
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 fSourceViewer.getVisibleRegion();
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.
*
* @param offset the offset of the range which at least should be highlighted
* @param length the length of the range which at least should be highlighted
*/
protected void adjustHighlightRange(int offset, int length) {
if (fSourceViewer == null)
return;
if (!fSourceViewer.overlapsWithVisibleRegion(offset, length))
fSourceViewer.resetVisibleRegion();
}
/*
* @see ITextEditor#selectAndReveal
*/
public void selectAndReveal(int start, int length) {
if (fSourceViewer == null)
return;
StyledText widget= fSourceViewer.getTextWidget();
widget.setRedraw(false);
{
adjustHighlightRange(start, length);
fSourceViewer.revealRange(start, length);
fSourceViewer.setSelectedRange(start, length);
}
widget.setRedraw(true);
}
/*
* @see EditorPart#firePropertyChange
*/
protected void firePropertyChange(int property) {
super.firePropertyChange(property);
updatePropertyDependentActions();
}
/*
* @see ITextEditorExtension#setStatusField(IStatusField, String)
*/
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.
*/
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
*/
protected boolean isInInsertMode() {
return !fOverwriting;
}
/**
* Handles a potential change of the cursor position.
*/
protected void handleCursorPositionChanged() {
updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_POSITION);
}
/**
* Handles a change of the editor's insert mode.
*/
protected void handleInsertModeChanged() {
updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_MODE);
}
/**
* Updates the status fields for the given category.
*
* @param category
*/
protected void updateStatusField(String category) {
if (ITextEditorActionConstants.STATUS_CATEGORY_INPUT_POSITION.equals(category)) {
IStatusField field= getStatusField(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_POSITION);
if (field != null)
field.setText(getCursorPosition());
} else if (ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE.equals(category)) {
IStatusField field= getStatusField(ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE);
if (field != null)
field.setText(isEditorInputReadOnly() ? fReadOnlyLabel : fWritableLabel);
} else if (ITextEditorActionConstants.STATUS_CATEGORY_INPUT_MODE.equals(category)) {
IStatusField field= getStatusField(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_MODE);
if (field != null)
field.setText(isInInsertMode() ? fInsertModeLabel : fOverwriteModeLabel);
}
}
/**
* Returns a description of the cursor position.
*
* @return a description of the cursor position
*/
protected String getCursorPosition() {
StyledText styledText= fSourceViewer.getTextWidget();
int offset= fSourceViewer.getVisibleRegion().getOffset();
int caret= offset + styledText.getCaretOffset();
IDocument document= fSourceViewer.getDocument();
try {
int line=document.getLineOfOffset(caret);
int lineOffset= document.getLineOffset(line);
int occurrences= 0;
for (int i= lineOffset; i < caret; i++)
if ('\t' == document.getChar(i))
++ occurrences;
int tabWidth= styledText.getTabs();
int column= caret - lineOffset + (tabWidth -1) * occurrences;
fLineLabel.fValue= line + 1;
fColumnLabel.fValue= column + 1;
return MessageFormat.format(fPositionLabelPattern, fPositionLabelPatternArguments);
} catch (BadLocationException x) {
return fPositionLabelError;
}
}
/*
* @see ITextEditorExtension#isEditorInputReadOnly()
*/
public boolean isEditorInputReadOnly() {
IDocumentProvider provider= getDocumentProvider();
if (provider instanceof IDocumentProviderExtension) {
IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
return extension.isReadOnly(getEditorInput());
}
return true;
}
}