/*=============================================================================#
# Copyright (c) 2005-2016 Stephan Wahlbrink (WalWare.de) 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:
# Stephan Wahlbrink - initial API and implementation
#=============================================================================*/
package de.walware.ecommons.ltk.ui.sourceediting;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.commands.IHandler2;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectNature;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ISynchronizable;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITextViewerExtension5;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.link.ILinkedModeListener;
import org.eclipse.jface.text.link.LinkedModeModel;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.text.source.projection.IProjectionListener;
import org.eclipse.jface.text.source.projection.ProjectionSupport;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
import org.eclipse.jface.viewers.IPostSelectionProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.part.IShowInSource;
import org.eclipse.ui.part.IShowInTargetList;
import org.eclipse.ui.part.ShowInContext;
import org.eclipse.ui.services.IServiceLocator;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.texteditor.IUpdate;
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
import org.eclipse.ui.texteditor.templates.ITemplatesPage;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import de.walware.jcommons.collections.ImCollections;
import de.walware.jcommons.collections.ImList;
import de.walware.ecommons.FastList;
import de.walware.ecommons.preferences.PreferencesUtil;
import de.walware.ecommons.preferences.SettingsChangeNotifier;
import de.walware.ecommons.preferences.core.Preference;
import de.walware.ecommons.text.ICharPairMatcher;
import de.walware.ecommons.text.TextUtil;
import de.walware.ecommons.text.core.sections.IDocContentSections;
import de.walware.ecommons.text.ui.TextHandlerUtil;
import de.walware.ecommons.ui.ISettingsChangedHandler;
import de.walware.ecommons.ui.util.UIAccess;
import de.walware.ecommons.ltk.IDocumentModelProvider;
import de.walware.ecommons.ltk.IModelManager;
import de.walware.ecommons.ltk.LTK;
import de.walware.ecommons.ltk.ast.IAstNode;
import de.walware.ecommons.ltk.core.IModelTypeDescriptor;
import de.walware.ecommons.ltk.core.model.IModelElement;
import de.walware.ecommons.ltk.core.model.ISourceStructElement;
import de.walware.ecommons.ltk.core.model.ISourceUnit;
import de.walware.ecommons.ltk.core.model.ISourceUnitModelInfo;
import de.walware.ecommons.ltk.internal.ui.EditingMessages;
import de.walware.ecommons.ltk.ui.ElementInfoController;
import de.walware.ecommons.ltk.ui.IModelElementInputProvider;
import de.walware.ecommons.ltk.ui.ISelectionWithElementInfoListener;
import de.walware.ecommons.ltk.ui.LTKInputData;
import de.walware.ecommons.ltk.ui.LTKUI;
import de.walware.ecommons.ltk.ui.PostSelectionCancelExtension;
import de.walware.ecommons.ltk.ui.PostSelectionWithElementInfoController;
import de.walware.ecommons.ltk.ui.PostSelectionWithElementInfoController.IgnoreActivation;
import de.walware.ecommons.ltk.ui.sourceediting.actions.DeleteNextWordHandler;
import de.walware.ecommons.ltk.ui.sourceediting.actions.DeletePreviousWordHandler;
import de.walware.ecommons.ltk.ui.sourceediting.actions.GotoMatchingBracketHandler;
import de.walware.ecommons.ltk.ui.sourceediting.actions.GotoNextWordHandler;
import de.walware.ecommons.ltk.ui.sourceediting.actions.GotoPreviousWordHandler;
import de.walware.ecommons.ltk.ui.sourceediting.actions.SelectNextWordHandler;
import de.walware.ecommons.ltk.ui.sourceediting.actions.SelectPreviousWordHandler;
import de.walware.ecommons.ltk.ui.sourceediting.actions.SpecificContentAssistHandler;
import de.walware.ecommons.ltk.ui.sourceediting.actions.ToggleCommentHandler;
/**
* Abstract LTK based source editor.
*/
public abstract class SourceEditor1 extends TextEditor implements ISourceEditor,
SettingsChangeNotifier.ChangeListener, IPreferenceChangeListener,
IShowInSource, IShowInTargetList {
public static final String ACTION_ID_TOGGLE_COMMENT = "de.walware.statet.ui.actions.ToggleComment"; //$NON-NLS-1$
protected static final ImList<String> ACTION_SET_CONTEXT_IDS= ImCollections.newIdentityList(
"de.walware.ecommons.ltk.contexts.EditSource1MenuSet", //$NON-NLS-1$
"org.eclipse.ui.edit.text.actionSet.presentation" ); //$NON-NLS-1$
private static final ImList<String> CONTEXT_IDS= ImCollections.addElement(
ACTION_SET_CONTEXT_IDS,
"de.walware.ecommons.text.contexts.TextEditor" ); //$NON-NLS-1$
/*- Static utility methods --------------------------------------------------*/
@Deprecated
protected static IProjectNature getProject(final IEditorInput input, final String projectNatureId) {
if (input != null && input instanceof IFileEditorInput) {
final IProject project = ((IFileEditorInput) input).getFile().getProject();
try {
if (project != null && project.hasNature(projectNatureId)) {
return project.getNature(projectNatureId);
}
}
catch (final CoreException ignore) {}
}
return null;
}
/**
* Returns the lock object for the given annotation model.
*
* @param annotationModel the annotation model
* @return the annotation model's lock object
*/
protected static final Object getLockObject(final IAnnotationModel annotationModel) {
if (annotationModel instanceof ISynchronizable) {
final Object lock = ((ISynchronizable) annotationModel).getLockObject();
if (lock != null) {
return lock;
}
}
return annotationModel;
}
/*- Inner classes -----------------------------------------------------------*/
protected class PostSelectionEditorCancel extends PostSelectionCancelExtension {
public PostSelectionEditorCancel() {
}
@Override
public void init() {
final ISourceViewer viewer = getSourceViewer();
if (viewer != null) {
viewer.addTextInputListener(this);
viewer.getDocument().addDocumentListener(this);
}
}
@Override
public void dispose() {
final ISourceViewer viewer = getSourceViewer();
if (viewer != null) {
viewer.removeTextInputListener(this);
final IDocument document = viewer.getDocument();
if (document != null) {
document.removeDocumentListener(this);
}
}
}
}
private class EffectSynchonizer implements ITextEditToolSynchronizer, ILinkedModeListener {
private EffectSynchonizer() {
}
@Override
public void install(final LinkedModeModel model) {
fEffectSynchonizerCounter++;
if (fMarkOccurrencesProvider != null) {
fMarkOccurrencesProvider.uninstall();
}
model.addLinkingListener(this);
}
@Override
public void left(final LinkedModeModel model, final int flags) {
fEffectSynchonizerCounter--;
updateMarkOccurrencesEnablement();
}
@Override
public void resume(final LinkedModeModel model, final int flags) {
}
@Override
public void suspend(final LinkedModeModel model) {
}
}
/*- Fields -----------------------------------------------------------------*/
private final IContentType contentType;
private final IModelTypeDescriptor modelType;
private SourceEditorViewerConfigurator fConfigurator;
private boolean fLazySetup;
private ISourceUnit fSourceUnit;
private ElementInfoController fModelProvider;
private PostSelectionWithElementInfoController fModelPostSelection;
protected volatile Point fCurrentSelection;
/** The outline page of this editor */
private SourceEditor1OutlinePage fOutlinePage;
/** The templates page of this editor */
private ITemplatesPage fTemplatesPage;
private StructureSelectionHistory fSelectionHistory;
private Preference<Boolean> fFoldingEnablement;
private ProjectionSupport fFoldingSupport;
private ISourceEditorAddon fFoldingProvider;
private FoldingActionGroup fFoldingActionGroup;
private Preference<Boolean> fMarkOccurrencesEnablement;
private ISourceEditorAddon fMarkOccurrencesProvider;
private EffectSynchonizer fEffectSynchronizer;
private int fEffectSynchonizerCounter;
private final FastList<IUpdate> fContentUpdateables = new FastList<>(IUpdate.class);
private final FastList<IHandler2> fStateUpdateables = new FastList<>(IHandler2.class);
private boolean fInputChange;
private int fInputUpdate = Integer.MAX_VALUE;
private ImageDescriptor fImageDescriptor;
/*- Contructors ------------------------------------------------------------*/
public SourceEditor1(final IContentType contentType) {
super();
this.contentType= contentType;
this.modelType= LTK.getExtContentTypeManager().getModelTypeForContentType(contentType.getId());
}
/*- Methods ----------------------------------------------------------------*/
@Override
public IContentType getContentType() {
return this.contentType;
}
/**
* Returns the model type of source units of the editor.
* The value must not change for an editor instance and all source units
* in the editor must be of the same type.
*
* @return id of the model type
*/
public String getModelTypeId() {
return this.modelType.getId();
}
@Override
protected void initializeEditor() {
fConfigurator = createConfiguration();
super.initializeEditor();
setCompatibilityMode(false);
final SourceEditorViewerConfiguration configuration = fConfigurator.getSourceViewerConfiguration();
setPreferenceStore(configuration.getPreferences());
setSourceViewerConfiguration(configuration);
if (configuration.isSmartInsertSupported()) {
configureInsertMode(SMART_INSERT, true);
}
PreferencesUtil.getSettingsChangeNotifier().addChangeListener(this);
}
protected abstract SourceEditorViewerConfigurator createConfiguration();
protected SourceEditorViewerConfigurator createInfoConfigurator() {
return null;
}
protected void enableStructuralFeatures(final IModelManager modelManager,
final Preference<Boolean> codeFoldingEnablement,
final Preference<Boolean> markOccurrencesEnablement) {
fModelProvider = new ElementInfoController(modelManager, LTK.EDITOR_CONTEXT);
fFoldingEnablement = codeFoldingEnablement;
fMarkOccurrencesEnablement = markOccurrencesEnablement;
}
/**
* Overwrites the default title image (editor icon) during the initialization of the editor
* input.
*
* The image is created and disposed automatically.
*
* For example, it can be used to overwrite the default image using the image descriptor of
* the editor input in {@link #setDocumentProvider(IEditorInput)}
*
* @param descriptor the image description of the icon or <code>null</code>
*/
protected void overwriteTitleImage(final ImageDescriptor descriptor) {
if (fImageDescriptor == descriptor || (fImageDescriptor == null && descriptor == null) ) {
return;
}
if (fImageDescriptor != null) {
JFaceResources.getResources().destroyImage(fImageDescriptor);
}
fImageDescriptor = descriptor;
if (fImageDescriptor != null) {
super.setTitleImage(JFaceResources.getResources().createImage(descriptor));
}
}
@Override
protected void setTitleImage(final Image titleImage) {
if (fImageDescriptor == null) {
super.setTitleImage(titleImage);
}
}
protected Collection<String> getContextIds() {
return CONTEXT_IDS;
}
@Override
protected void initializeKeyBindingScopes() {
final Collection<String> ids= getContextIds();
setKeyBindingScopes(ids.toArray(new String[ids.size()]));
}
@Override
protected String[] collectContextMenuPreferencePages() {
final List<String> list = new ArrayList<>();
collectContextMenuPreferencePages(list);
list.addAll(Arrays.asList(super.collectContextMenuPreferencePages()));
return list.toArray(new String[list.size()]);
}
protected void collectContextMenuPreferencePages(final List<String> pageIds) {
}
@Override
protected void doSetInput(final IEditorInput input) throws CoreException {
if (fModelProvider != null && fSourceUnit != null) {
fModelProvider.setInput(null);
}
// project has changed
final ISourceViewer sourceViewer = getSourceViewer();
if (sourceViewer != null) {
fConfigurator.unconfigureTarget();
}
else {
fLazySetup = true;
}
fInputChange = true;
fInputUpdate = 1;
super.doSetInput(input);
// setup in
// 1) setDocumentProvider -> setupConfiguration(..., input)
// 2) handleInsertModeChanged -> setupConfiguration(..., input, SourceViewer)
fInputChange = false;
fInputUpdate = Integer.MAX_VALUE;
initSmartInsert();
if (input != null && fOutlinePage != null) {
updateOutlinePageInput(fOutlinePage);
}
}
private void initSmartInsert() {
final SourceEditorViewerConfiguration config = fConfigurator.getSourceViewerConfiguration();
if (config.isSmartInsertSupported()) {
if (config.isSmartInsertByDefault()) {
setInsertMode(SMART_INSERT);
}
else {
setInsertMode(INSERT);
}
}
}
@Override
protected void setPartName(final String partName) {
super.setPartName(partName);
// see doSetInput
if (fInputChange) {
if (fInputUpdate != 1) {
return;
}
fInputUpdate = 2;
final IEditorInput input = getEditorInput();
setupConfiguration(input);
}
}
@Override
protected void handleInsertModeChanged() {
// see doSetInput
if (fInputChange && !fLazySetup) {
if (fInputUpdate != 2) {
return;
}
fInputUpdate = 3;
final IEditorInput input = getEditorInput();
final ISourceViewer sourceViewer = getSourceViewer();
if (input != null && sourceViewer != null) {
setupConfiguration(input, sourceViewer);
fConfigurator.configureTarget();
}
fInputChange = false;
}
super.handleInsertModeChanged();
}
/**
* Subclasses should setup the SourceViewerConfiguration.
*/
protected void setupConfiguration(final IEditorInput newInput) {
final IDocumentProvider documentProvider = getDocumentProvider();
if (documentProvider instanceof IDocumentModelProvider) {
fSourceUnit = ((IDocumentModelProvider) documentProvider).getWorkingCopy(newInput);
if (fModelProvider != null) {
fModelProvider.setInput(fSourceUnit);
}
}
}
/**
* Subclasses should setup the SourceViewerConfiguration.
*/
protected void setupConfiguration(final IEditorInput newInput, final ISourceViewer sourceViewer) {
updateStateDependentActions();
}
@Override
public ISourceUnit getSourceUnit() {
return fSourceUnit;
}
@Override
public SourceViewer getViewer() {
return (SourceViewer) super.getSourceViewer();
}
@Override
public IDocContentSections getDocumentContentInfo() {
return fConfigurator.getDocumentContentInfo();
}
@Override
public IWorkbenchPart getWorkbenchPart() {
return this;
}
@Override
public IServiceLocator getServiceLocator() {
return getSite();
}
@Override
public boolean isEditable(final boolean validate) {
if (validate) {
return SourceEditor1.this.validateEditorInputState();
}
return SourceEditor1.this.isEditorInputModifiable();
}
public IModelElementInputProvider getModelInputProvider() {
return fModelProvider;
}
public void addPostSelectionWithElementInfoListener(final ISelectionWithElementInfoListener listener) {
if (fModelPostSelection != null) {
fModelPostSelection.addListener(listener);
}
}
public void removePostSelectionWithElementInfoListener(final ISelectionWithElementInfoListener listener) {
if (fModelPostSelection != null) {
fModelPostSelection.removeListener(listener);
}
}
@Override
public void createPartControl(final Composite parent) {
super.createPartControl(parent);
if (fModelProvider != null) {
fModelPostSelection = new PostSelectionWithElementInfoController(fModelProvider,
(IPostSelectionProvider) getSelectionProvider(), new PostSelectionEditorCancel());
fModelPostSelection.addListener(new ISelectionWithElementInfoListener() {
@Override
public void inputChanged() {
}
@Override
public void stateChanged(final LTKInputData state) {
final IRegion toHighlight = getRangeToHighlight(state);
if (toHighlight != null) {
setHighlightRange(toHighlight.getOffset(), toHighlight.getLength(), false);
}
else {
resetHighlightRange();
}
}
});
}
if (fFoldingEnablement != null) {
final ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();
fFoldingSupport = new ProjectionSupport(viewer, getAnnotationAccess(), getSharedColors());
final SourceEditorViewerConfigurator config = createInfoConfigurator();
if (config != null) {
final IInformationControlCreator presentationCreator = new IInformationControlCreator() {
@Override
public IInformationControl createInformationControl(final Shell parent) {
return new SourceViewerInformationControl(parent, createInfoConfigurator(), getOrientation());
}
};
fFoldingSupport.setHoverControlCreator(new IInformationControlCreator() {
@Override
public IInformationControl createInformationControl(final Shell parent) {
return new SourceViewerInformationControl(parent, createInfoConfigurator(), getOrientation(), presentationCreator);
}
});
fFoldingSupport.setInformationPresenterControlCreator(presentationCreator);
}
fFoldingSupport.install();
viewer.addProjectionListener(new IProjectionListener() {
@Override
public void projectionEnabled() {
installFoldingProvider();
}
@Override
public void projectionDisabled() {
uninstallFoldingProvider();
}
});
PreferencesUtil.getInstancePrefs().addPreferenceNodeListener(
fFoldingEnablement.getQualifier(), this);
updateFoldingEnablement();
}
if (fMarkOccurrencesEnablement != null) {
PreferencesUtil.getInstancePrefs().addPreferenceNodeListener(
fMarkOccurrencesEnablement.getQualifier(), this);
updateMarkOccurrencesEnablement();
}
if (fLazySetup) {
fLazySetup = false;
setupConfiguration(getEditorInput(), getSourceViewer());
fConfigurator.setTarget(this);
}
final IContextService contextService= (IContextService) getServiceLocator().getService(IContextService.class);
for (String id : getContextIds()) {
contextService.activateContext(id);
}
}
@Override
protected ISourceViewer createSourceViewer(final Composite parent, final IVerticalRuler ruler, final int styles) {
fAnnotationAccess = getAnnotationAccess();
fOverviewRuler = createOverviewRuler(getSharedColors());
final ISourceViewer viewer = new SourceEditorViewer(parent,
ruler, getOverviewRuler(), isOverviewRulerVisible(), styles,
getSourceViewerFlags() );
// ensure decoration support has been created and configured.
getSourceViewerDecorationSupport(viewer);
return viewer;
}
protected int getSourceViewerFlags() {
return 0;
}
protected IRegion getRangeToReveal(final ISourceUnitModelInfo modelInfo, final ISourceStructElement element) {
return null;
}
protected IRegion getRangeToHighlight(final LTKInputData state) {
final ISourceUnitModelInfo info = state.getInputInfo();
if (info == null) {
return null;
}
final IRegion region= getRangeToHighlight(info, state.getModelSelection());
if (region != null) {
return region;
}
final IAstNode root = info.getAst().root;
TRY_AST: if (root != null) {
final ITextSelection selection = (ITextSelection) state.getSelection();
final int n = root.getChildCount();
for (int i = 0; i < n; i++) {
final IAstNode child = root.getChild(i);
if (selection.getOffset() >= child.getOffset()) {
if (selection.getOffset()+selection.getLength() <= child.getEndOffset()) {
return child;
}
}
else {
break TRY_AST;
}
}
}
return null;
}
protected IRegion getRangeToHighlight(final ISourceUnitModelInfo info, ISourceStructElement element) {
while (element != null) {
switch (element.getElementType() & IModelElement.MASK_C1) {
case IModelElement.C1_CLASS:
case IModelElement.C1_METHOD:
return TextUtil.expand(element.getSourceRange(), element.getDocumentationRange());
case IModelElement.C1_SOURCE:
if ((element.getElementType() & IModelElement.MASK_C2) == IModelElement.C2_SOURCE_CHUNK) {
return TextUtil.expand(element.getSourceRange(), element.getDocumentationRange());
}
return null;
case IModelElement.C1_VARIABLE:
if ((element.getSourceParent().getElementType() & IModelElement.MASK_C2) == IModelElement.C2_SOURCE_FILE) {
return TextUtil.expand(element.getSourceRange(), element.getDocumentationRange());
}
//$FALL-THROUGH$
default:
element = element.getSourceParent();
continue;
}
}
return null;
}
protected ISourceEditorAddon createCodeFoldingProvider() {
return null;
}
private void installFoldingProvider() {
uninstallFoldingProvider();
fFoldingProvider = createCodeFoldingProvider();
if (fFoldingProvider != null) {
fFoldingProvider.install(this);
}
}
private void uninstallFoldingProvider() {
if (fFoldingProvider != null) {
fFoldingProvider.uninstall();
fFoldingProvider = null;
}
}
private void updateFoldingEnablement() {
if (fFoldingEnablement != null) {
UIAccess.getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
final Boolean enable = PreferencesUtil.getInstancePrefs().getPreferenceValue(fFoldingEnablement);
final ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();
if (enable != null && UIAccess.isOkToUse(viewer)) {
if (enable != viewer.isProjectionMode()) {
viewer.doOperation(ProjectionViewer.TOGGLE);
}
}
}
});
}
}
protected ISourceEditorAddon createMarkOccurrencesProvider() {
return null;
}
private void uninstallMarkOccurrencesProvider() {
if (fMarkOccurrencesProvider != null) {
fMarkOccurrencesProvider.uninstall();
fMarkOccurrencesProvider = null;
}
}
private void updateMarkOccurrencesEnablement() {
if (fMarkOccurrencesEnablement != null) {
UIAccess.getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
final Boolean enable = PreferencesUtil.getInstancePrefs().getPreferenceValue(fMarkOccurrencesEnablement);
if (enable) {
if (fMarkOccurrencesProvider == null) {
fMarkOccurrencesProvider = createMarkOccurrencesProvider();
}
if (fMarkOccurrencesProvider != null && fEffectSynchonizerCounter == 0) {
fMarkOccurrencesProvider.install(SourceEditor1.this);
}
}
else {
uninstallMarkOccurrencesProvider();
}
}
});
}
}
@Override
protected void configureSourceViewerDecorationSupport(final SourceViewerDecorationSupport support) {
super.configureSourceViewerDecorationSupport(support);
fConfigurator.configureSourceViewerDecorationSupport(support);
}
@Override
protected void createActions() {
super.createActions();
final IHandlerService handlerService = (IHandlerService) getServiceLocator().getService(IHandlerService.class);
final StyledText textWidget = getViewer().getTextWidget();
{ final IHandler2 handler = new GotoNextWordHandler(this);
setAction(ITextEditorActionDefinitionIds.WORD_NEXT, null);
TextHandlerUtil.disable(textWidget, ITextEditorActionDefinitionIds.WORD_NEXT);
handlerService.activateHandler(ITextEditorActionDefinitionIds.WORD_NEXT, handler);
}
{ final IHandler2 handler = new GotoPreviousWordHandler(this);
setAction(ITextEditorActionDefinitionIds.WORD_PREVIOUS, null);
TextHandlerUtil.disable(textWidget, ITextEditorActionDefinitionIds.WORD_NEXT);
handlerService.activateHandler(ITextEditorActionDefinitionIds.WORD_PREVIOUS, handler);
}
{ final IHandler2 handler = new SelectNextWordHandler(this);
setAction(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT, null);
TextHandlerUtil.disable(textWidget, ITextEditorActionDefinitionIds.SELECT_WORD_NEXT);
handlerService.activateHandler(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT, handler);
}
{ final IHandler2 handler = new SelectPreviousWordHandler(this);
setAction(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS, null);
TextHandlerUtil.disable(textWidget, ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS);
handlerService.activateHandler(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS, handler);
}
{ final IHandler2 handler = new DeleteNextWordHandler(this);
setAction(ITextEditorActionDefinitionIds.DELETE_NEXT_WORD, null);
TextHandlerUtil.disable(textWidget, ITextEditorActionDefinitionIds.DELETE_NEXT_WORD);
handlerService.activateHandler(ITextEditorActionDefinitionIds.DELETE_NEXT_WORD, handler);
markAsStateDependentHandler(handler, true);
}
{ final IHandler2 handler = new DeletePreviousWordHandler(this);
setAction(ITextEditorActionDefinitionIds.DELETE_PREVIOUS_WORD, null);
TextHandlerUtil.disable(textWidget, ITextEditorActionDefinitionIds.DELETE_PREVIOUS_WORD);
handlerService.activateHandler(ITextEditorActionDefinitionIds.DELETE_PREVIOUS_WORD, handler);
markAsStateDependentHandler(handler, true);
}
final ICharPairMatcher matcher = fConfigurator.getSourceViewerConfiguration().getPairMatcher();
if (matcher != null) {
handlerService.activateHandler(ISourceEditorCommandIds.GOTO_MATCHING_BRACKET,
new GotoMatchingBracketHandler(matcher, this));
}
{ final IHandler2 handler= new SpecificContentAssistHandler(this,
this.fConfigurator.getSourceViewerConfiguration().getContentAssist() );
handlerService.activateHandler(ISourceEditorCommandIds.SPECIFIC_CONTENT_ASSIST_COMMAND_ID, handler);
}
{ final IHandler2 handler = createToggleCommentHandler();
if (handler != null) {
handlerService.activateHandler(ISourceEditorCommandIds.TOGGLE_COMMENT, handler);
}
}
{ final IHandler2 handler = createCorrectIndentHandler();
if (handler != null) {
handlerService.activateHandler(LTKUI.CORRECT_INDENT_COMMAND_ID, handler);
}
}
if (fFoldingEnablement != null) {
fFoldingActionGroup = createFoldingActionGroup();
}
if (fModelProvider != null) {
fSelectionHistory = new StructureSelectionHistory(this);
handlerService.activateHandler(ISourceEditorCommandIds.SELECT_ENCLOSING,
new StructureSelectHandler.Enclosing(this, fSelectionHistory));
handlerService.activateHandler(ISourceEditorCommandIds.SELECT_PREVIOUS,
new StructureSelectHandler.Previous(this, fSelectionHistory));
handlerService.activateHandler(ISourceEditorCommandIds.SELECT_NEXT,
new StructureSelectHandler.Next(this, fSelectionHistory));
final StructureSelectionHistoryBackHandler backHandler = new StructureSelectionHistoryBackHandler(this, fSelectionHistory);
handlerService.activateHandler(ISourceEditorCommandIds.SELECT_LAST, backHandler);
fSelectionHistory.addUpdateListener(backHandler);
}
//WorkbenchHelp.setHelp(action, IJavaHelpContextIds.TOGGLE_COMMENT_ACTION);
}
protected FoldingActionGroup createFoldingActionGroup() {
return new FoldingActionGroup(this, (ProjectionViewer) getSourceViewer());
}
protected IHandler2 createToggleCommentHandler() {
final IHandler2 commentHandler = new ToggleCommentHandler(this);
markAsStateDependentHandler(commentHandler, true);
return commentHandler;
}
protected IHandler2 createCorrectIndentHandler() {
return null;
}
protected void markAsContentDependentHandler(final IUpdate handler, final boolean mark) {
if (mark) {
fContentUpdateables.add(handler);
}
else {
fContentUpdateables.remove(handler);
}
}
protected void markAsStateDependentHandler(final IHandler2 handler, final boolean mark) {
if (mark) {
fStateUpdateables.add(handler);
}
else {
fStateUpdateables.remove(handler);
}
}
@Override
protected void updateContentDependentActions() {
super.updateContentDependentActions();
final IUpdate[] listeners = fContentUpdateables.toArray();
for (int i = 0; i < listeners.length; i++) {
listeners[i].update();
}
}
@Override
protected void updateStateDependentActions() {
super.updateStateDependentActions();
final IHandler2[] listeners = fStateUpdateables.toArray();
for (int i = 0; i < listeners.length; i++) {
listeners[i].setEnabled(this);
}
}
@Override
protected void rulerContextMenuAboutToShow(final IMenuManager menu) {
super.rulerContextMenuAboutToShow(menu);
if (fFoldingActionGroup != null) {
final IMenuManager foldingMenu = new MenuManager(EditingMessages.CodeFolding_label, "projection"); //$NON-NLS-1$
menu.appendToGroup(ITextEditorActionConstants.GROUP_RULERS, foldingMenu);
fFoldingActionGroup.fillMenu(foldingMenu);
}
}
@Override
public ITextEditToolSynchronizer getTextEditToolSynchronizer() {
if (fEffectSynchronizer == null) {
fEffectSynchronizer = new EffectSynchonizer();
}
return fEffectSynchronizer;
}
@Override
public Object getAdapter(final Class required) {
if (required == ISourceEditor.class) {
return this;
}
if (required == ISourceViewer.class) {
return getSourceViewer();
}
if (required == IContentType.class) {
return this.contentType;
}
if (required == IContentOutlinePage.class) {
if (fOutlinePage == null) {
fOutlinePage = createOutlinePage();
if (fOutlinePage != null) {
updateOutlinePageInput(fOutlinePage);
}
}
return fOutlinePage;
}
if (required == ITemplatesPage.class) {
if (fTemplatesPage == null) {
fTemplatesPage = createTemplatesPage();
}
return fTemplatesPage;
}
if (fFoldingSupport != null) {
final Object adapter = fFoldingSupport.getAdapter(getSourceViewer(), required);
if (adapter != null) {
return adapter;
}
}
return super.getAdapter(required);
}
@Override
public void settingsChanged(final Set<String> groupIds) {
final Map<String, Object> options = new HashMap<>();
UIAccess.getDisplay().syncExec(new Runnable() {
@Override
public void run() {
handleSettingsChanged(groupIds, options);
}
});
}
/**
* @see ISettingsChangedHandler#handleSettingsChanged(Set, Map)
*/
protected void handleSettingsChanged(final Set<String> groupIds, final Map<String, Object> options) {
if (fConfigurator != null) {
fConfigurator.handleSettingsChanged(groupIds, options);
}
}
@Override
public void preferenceChange(final PreferenceChangeEvent event) {
if (fFoldingEnablement != null && event.getKey().equals(fFoldingEnablement.getKey())) {
updateFoldingEnablement();
}
if (fMarkOccurrencesEnablement != null && event.getKey().equals(fMarkOccurrencesEnablement.getKey())) {
updateMarkOccurrencesEnablement();
}
}
protected void updateIndentSettings() {
updateIndentPrefixes();
}
@Override
protected void handleCursorPositionChanged() {
fCurrentSelection = getSourceViewer().getSelectedRange();
super.handleCursorPositionChanged();
}
protected SourceEditor1OutlinePage createOutlinePage() {
return null;
}
protected void updateOutlinePageInput(final SourceEditor1OutlinePage page) {
}
void handleOutlinePageClosed() {
if (fOutlinePage != null) {
fOutlinePage = null;
resetHighlightRange();
}
}
protected ITemplatesPage createTemplatesPage() {
return null;
}
@Override
// inject annotation painter workaround
protected SourceViewerDecorationSupport getSourceViewerDecorationSupport(final ISourceViewer viewer) {
if (fSourceViewerDecorationSupport == null) {
fSourceViewerDecorationSupport= new de.walware.epatches.ui.SourceViewerDecorationSupport(viewer, getOverviewRuler(), getAnnotationAccess(), getSharedColors());
configureSourceViewerDecorationSupport(fSourceViewerDecorationSupport);
}
return fSourceViewerDecorationSupport;
}
@Override
public void selectAndReveal(final int start, final int length) {
selectAndReveal(start, length, start, length);
}
@Override
protected void selectAndReveal(final int selectionStart, final int selectionLength, final int revealStart, final int revealLength) {
if (fModelPostSelection != null) {
fModelPostSelection.setUpdateOnSelection(true);
try {
super.selectAndReveal(selectionStart, selectionLength, revealStart, revealLength);
}
finally {
fModelPostSelection.setUpdateOnSelection(false);
}
}
else {
super.selectAndReveal(selectionStart, selectionLength, revealStart, revealLength);
}
}
public void setSelection(final ISelection selection, final ISelectionWithElementInfoListener listener) {
if (fModelPostSelection != null && listener != null) {
final IgnoreActivation activation = fModelPostSelection.ignoreNext(listener);
doSetSelection(selection);
activation.deleteNext();
}
else {
doSetSelection(selection);
}
}
@Override
protected void doSetSelection(final ISelection selection) {
if (selection instanceof IStructuredSelection) {
final IStructuredSelection structured= (IStructuredSelection) selection;
if (!structured.isEmpty()) {
final Object first= structured.getFirstElement();
IRegion region= null;
if (first instanceof ISourceStructElement) {
final ISourceStructElement sourceElement= (ISourceStructElement) first;
region= sourceElement.getNameSourceRange();
if (region == null) {
region= sourceElement.getSourceRange();
if (region != null) {
region= new Region(region.getOffset(), 0);
}
}
final ISourceUnit sourceUnit= sourceElement.getSourceUnit();
final ISourceUnitModelInfo modelInfo= sourceUnit.getModelInfo(getModelTypeId(), 0, null);
if (modelInfo != null) {
final IRegion toReveal= getRangeToReveal(modelInfo, sourceElement);
if (toReveal != null) {
final SourceViewer viewer= getViewer();
if (viewer instanceof ITextViewerExtension5) {
((ITextViewerExtension5) viewer).exposeModelRange(toReveal);
}
getViewer().revealRange(toReveal.getOffset(), toReveal.getLength());
}
final IRegion toHighlight= getRangeToHighlight(modelInfo, sourceElement);
if (toHighlight != null) {
setHighlightRange(toHighlight.getOffset(), toHighlight.getLength(), true);
}
}
}
if (region == null && first instanceof IRegion) {
region= (IRegion) first;
}
if (region != null) {
selectAndReveal(region.getOffset(), region.getLength());
return;
}
}
}
super.doSetSelection(selection);
}
@Override
public void dispose() {
if (fModelProvider != null) {
fModelProvider.setInput(null);
fModelProvider.dispose();
}
PreferencesUtil.getSettingsChangeNotifier().removeChangeListener(this);
if (fModelPostSelection != null) {
fModelPostSelection.dispose();
}
if (fFoldingEnablement != null) {
PreferencesUtil.getInstancePrefs().removePreferenceNodeListener(
fFoldingEnablement.getQualifier(), this);
uninstallFoldingProvider();
}
if (fMarkOccurrencesEnablement != null) {
PreferencesUtil.getInstancePrefs().removePreferenceNodeListener(
fMarkOccurrencesEnablement.getQualifier(), this);
uninstallMarkOccurrencesProvider();
}
super.dispose();
if (fImageDescriptor != null) {
JFaceResources.getResources().destroyImage(fImageDescriptor);
fImageDescriptor = null;
}
fSourceUnit = null;
fModelProvider = null;
fModelPostSelection = null;
}
@Override
public ShowInContext getShowInContext() {
final Point selectionPoint = fCurrentSelection;
final ISourceViewer sourceViewer = getSourceViewer();
final ISourceUnit unit = getSourceUnit();
ISelection selection = null;
if (selectionPoint != null && unit != null && sourceViewer != null) {
selection = new LTKInputData(unit, getSelectionProvider());
}
return new ShowInContext(getEditorInput(), selection);
}
@Override
public String[] getShowInTargetIds() {
return new String[] { IPageLayout.ID_PROJECT_EXPLORER };
}
}