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