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 java.util.MissingResourceException; | |
import java.util.ResourceBundle; | |
import org.eclipse.core.internal.plugins.ConfigurationElement; | |
import org.eclipse.core.resources.IMarker; | |
import org.eclipse.core.resources.IStorage; | |
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.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.ShellListener; | |
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.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.IDialogConstants; | |
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.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.IFileEditorInput; | |
import org.eclipse.ui.IKeyBindingService; | |
import org.eclipse.ui.IPartListener; | |
import org.eclipse.ui.IReusableEditor; | |
import org.eclipse.ui.IStorageEditorInput; | |
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.internal.EditorPluginAction; | |
import org.eclipse.ui.help.WorkbenchHelp; | |
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(); | |
// fix for http://bugs.eclipse.org/bugs/show_bug.cgi?id=15058 | |
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); | |
} | |
}; | |
/** 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; | |
Control ruler= fVerticalRuler.getControl(); | |
id= fRulerContextMenuId != null ? fRulerContextMenuId : DEFAULT_RULER_CONTEXT_MENU_ID; | |
manager= new MenuManager(id, id); | |
manager.setRemoveAllWhenShown(true); | |
manager.addMenuListener(getContextMenuListener()); | |
fRulerContextMenu= manager.createContextMenu(ruler); | |
ruler.setMenu(fRulerContextMenu); | |
ruler.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(); | |
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(); | |
styledText.setRedraw(false); | |
styledText.setFont(font); | |
sourceViewer.setSelectedRange(selection.x , selection.y); | |
sourceViewer.setTopIndex(topIndex); | |
styledText.setRedraw(true); | |
} else { | |
StyledText styledText= sourceViewer.getTextWidget(); | |
styledText.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 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)) | |
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; | |
} | |
} |