| /******************************************************************************* |
| * Copyright (c) 2000, 2015 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 |
| *******************************************************************************/ |
| package org.eclipse.ui.editors.text; |
| |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.StringTokenizer; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.RGB; |
| import org.eclipse.swt.widgets.Shell; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.IAdaptable; |
| |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| |
| import org.eclipse.jface.text.DefaultInformationControl; |
| import org.eclipse.jface.text.DefaultTextHover; |
| import org.eclipse.jface.text.IInformationControl; |
| import org.eclipse.jface.text.IInformationControlCreator; |
| import org.eclipse.jface.text.ITextHover; |
| import org.eclipse.jface.text.ITextHoverExtension; |
| import org.eclipse.jface.text.ITextViewerExtension2; |
| import org.eclipse.jface.text.IUndoManager; |
| import org.eclipse.jface.text.TextViewerUndoManager; |
| import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; |
| import org.eclipse.jface.text.hyperlink.IHyperlinkPresenter; |
| import org.eclipse.jface.text.hyperlink.MultipleHyperlinkPresenter; |
| import org.eclipse.jface.text.quickassist.IQuickAssistAssistant; |
| import org.eclipse.jface.text.quickassist.QuickAssistAssistant; |
| import org.eclipse.jface.text.reconciler.IReconciler; |
| import org.eclipse.jface.text.reconciler.IReconcilingStrategy; |
| import org.eclipse.jface.text.reconciler.MonoReconciler; |
| import org.eclipse.jface.text.source.Annotation; |
| import org.eclipse.jface.text.source.DefaultAnnotationHover; |
| import org.eclipse.jface.text.source.IAnnotationHover; |
| import org.eclipse.jface.text.source.ISourceViewer; |
| import org.eclipse.jface.text.source.SourceViewerConfiguration; |
| |
| import org.eclipse.ui.internal.editors.text.EditorsPlugin; |
| |
| import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants; |
| import org.eclipse.ui.texteditor.AnnotationPreference; |
| import org.eclipse.ui.texteditor.HyperlinkDetectorRegistry; |
| import org.eclipse.ui.texteditor.spelling.SpellingCorrectionProcessor; |
| import org.eclipse.ui.texteditor.spelling.SpellingReconcileStrategy; |
| import org.eclipse.ui.texteditor.spelling.SpellingService; |
| |
| |
| /** |
| * Source viewer configuration for the text editor. |
| * |
| * @since 3.0 |
| */ |
| public class TextSourceViewerConfiguration extends SourceViewerConfiguration { |
| |
| /** |
| * The preference store used to initialize this configuration. |
| * <p> |
| * Note: protected since 3.1 |
| * </p> |
| */ |
| protected IPreferenceStore fPreferenceStore; |
| |
| /** |
| * Creates a text source viewer configuration. |
| */ |
| public TextSourceViewerConfiguration() { |
| } |
| |
| /** |
| * Creates a text source viewer configuration and |
| * initializes it with the given preference store. |
| * |
| * @param preferenceStore the preference store used to initialize this configuration |
| */ |
| public TextSourceViewerConfiguration(IPreferenceStore preferenceStore) { |
| fPreferenceStore= preferenceStore; |
| } |
| |
| @Override |
| public IAnnotationHover getAnnotationHover(ISourceViewer sourceViewer) { |
| return new DefaultAnnotationHover() { |
| @Override |
| protected boolean isIncluded(Annotation annotation) { |
| return isShowInVerticalRuler(annotation); |
| } |
| }; |
| } |
| |
| /* |
| * @see DefaultAnnotationHover#isIncluded(Annotation) |
| * @since 3.2 |
| */ |
| protected boolean isShowInVerticalRuler(Annotation annotation) { |
| AnnotationPreference preference= getAnnotationPreference(annotation); |
| if (preference == null) |
| return true; |
| String key= preference.getVerticalRulerPreferenceKey(); |
| // backward compatibility |
| if (key != null && !fPreferenceStore.getBoolean(key)) |
| return false; |
| |
| return true; |
| } |
| |
| @Override |
| public IAnnotationHover getOverviewRulerAnnotationHover(ISourceViewer sourceViewer) { |
| return new DefaultAnnotationHover(true) { |
| @Override |
| protected boolean isIncluded(Annotation annotation) { |
| return isShowInOverviewRuler(annotation); |
| } |
| }; |
| } |
| |
| /* |
| * @see DefaultAnnotationHover#isIncluded(Annotation) |
| * @since 3.2 |
| */ |
| protected boolean isShowInOverviewRuler(Annotation annotation) { |
| AnnotationPreference preference= getAnnotationPreference(annotation); |
| if (preference == null) |
| return true; |
| String key= preference.getOverviewRulerPreferenceKey(); |
| if (key == null || !fPreferenceStore.getBoolean(key)) |
| return false; |
| |
| return true; |
| } |
| |
| @Override |
| public int[] getConfiguredTextHoverStateMasks(ISourceViewer sourceViewer, String contentType) { |
| return new int[] { ITextViewerExtension2.DEFAULT_HOVER_STATE_MASK }; |
| } |
| |
| @Override |
| public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) { |
| return new TextHover(sourceViewer); |
| } |
| |
| /* |
| * @see DefaultTextHover#isIncluded(Annotation) |
| * @since 3.2 |
| */ |
| protected boolean isShownInText(Annotation annotation) { |
| AnnotationPreference preference= getAnnotationPreference(annotation); |
| if (preference == null) |
| return false; |
| String key= preference.getTextPreferenceKey(); |
| if (key != null) { |
| if (!fPreferenceStore.getBoolean(key)) |
| return false; |
| } else { |
| key= preference.getHighlightPreferenceKey(); |
| if (key == null || !fPreferenceStore.getBoolean(key)) |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Returns the annotation preference for the given annotation. |
| * |
| * @param annotation the annotation |
| * @return the annotation preference or <code>null</code> if none |
| * @since 3.2 |
| */ |
| private AnnotationPreference getAnnotationPreference(Annotation annotation) { |
| if (annotation == null || fPreferenceStore == null) |
| return null; |
| return EditorsUI.getAnnotationPreferenceLookup().getAnnotationPreference(annotation); |
| } |
| |
| @Override |
| public int getTabWidth(ISourceViewer sourceViewer) { |
| if (fPreferenceStore == null) |
| return super.getTabWidth(sourceViewer); |
| return fPreferenceStore.getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH); |
| } |
| |
| @Override |
| public String[] getIndentPrefixes(ISourceViewer sourceViewer, String contentType) { |
| String[] indentPrefixes= getIndentPrefixesForTab(getTabWidth(sourceViewer)); |
| if (indentPrefixes == null) |
| return null; |
| |
| int length= indentPrefixes.length; |
| if (length > 2 && fPreferenceStore != null && fPreferenceStore.getBoolean(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SPACES_FOR_TABS)) { |
| // Swap first with second last |
| String first= indentPrefixes[0]; |
| indentPrefixes[0]= indentPrefixes[length - 2]; |
| indentPrefixes[length - 2]= first; |
| } |
| |
| return indentPrefixes; |
| } |
| |
| @Override |
| public IHyperlinkDetector[] getHyperlinkDetectors(ISourceViewer sourceViewer) { |
| if (sourceViewer == null || fPreferenceStore == null) |
| return super.getHyperlinkDetectors(sourceViewer); |
| |
| if (!fPreferenceStore.getBoolean(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_HYPERLINKS_ENABLED)) |
| return null; |
| |
| return getRegisteredHyperlinkDetectors(sourceViewer); |
| } |
| |
| /** |
| * Returns the registered hyperlink detectors which are used to detect |
| * hyperlinks in the given source viewer. |
| * |
| * @param sourceViewer the source viewer to be configured by this configuration |
| * @return an array with hyperlink detectors or <code>null</code> if no hyperlink detectors are registered |
| * @since 3.3 |
| */ |
| protected final IHyperlinkDetector[] getRegisteredHyperlinkDetectors(ISourceViewer sourceViewer) { |
| HyperlinkDetectorRegistry registry= EditorsUI.getHyperlinkDetectorRegistry(); |
| |
| Map<String, IAdaptable> targets= getHyperlinkDetectorTargets(sourceViewer); |
| Assert.isNotNull(targets); |
| |
| IHyperlinkDetector[] result= null; |
| Iterator<Entry<String, IAdaptable>> iter= targets.entrySet().iterator(); |
| while (iter.hasNext()) { |
| Entry<String, IAdaptable> target= iter.next(); |
| String targetId= target.getKey(); |
| IAdaptable context= target.getValue(); |
| result= merge(result, registry.createHyperlinkDetectors(targetId, context)); |
| } |
| return result; |
| } |
| |
| /** |
| * Returns the hyperlink detector targets supported by the |
| * given source viewer. |
| * <p> |
| * Subclasses are allowed to modify the returned map. |
| * </p> |
| * |
| * @param sourceViewer the source viewer to be configured by this configuration |
| * @return the hyperlink detector targets with target id (<code>String</code>) as key |
| * and the target context (<code>IAdaptable</code>) as value |
| * @since 3.3 |
| */ |
| protected Map<String, IAdaptable> getHyperlinkDetectorTargets(ISourceViewer sourceViewer) { |
| Map<String, IAdaptable> targets= new HashMap<>(); |
| targets.put(EditorsUI.DEFAULT_TEXT_EDITOR_ID, null); |
| return targets; |
| } |
| |
| @Override |
| public int getHyperlinkStateMask(ISourceViewer sourceViewer) { |
| if (fPreferenceStore == null) |
| return super.getHyperlinkStateMask(sourceViewer); |
| |
| String modifiers= fPreferenceStore.getString(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_HYPERLINK_KEY_MODIFIER); |
| int modifierMask= computeStateMask(modifiers); |
| if (modifierMask == -1) { |
| // Fall back to stored state mask |
| modifierMask= fPreferenceStore.getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_HYPERLINK_KEY_MODIFIER_MASK); |
| } |
| return modifierMask; |
| } |
| |
| @Override |
| public IHyperlinkPresenter getHyperlinkPresenter(ISourceViewer sourceViewer) { |
| if (fPreferenceStore == null) |
| return new MultipleHyperlinkPresenter(new RGB(0, 0, 255)); |
| |
| return new MultipleHyperlinkPresenter(fPreferenceStore); |
| } |
| |
| /** |
| * Maps the localized modifier name to a code in the same |
| * manner as #findModifier. |
| * |
| * @param modifierName the modifier name |
| * @return the SWT modifier bit, or <code>0</code> if no match was found |
| * @since 3.1 |
| */ |
| protected static final int findLocalizedModifier(String modifierName) { |
| if (modifierName == null) |
| return 0; |
| |
| if (modifierName.equalsIgnoreCase(Action.findModifierString(SWT.CTRL))) |
| return SWT.CTRL; |
| if (modifierName.equalsIgnoreCase(Action.findModifierString(SWT.SHIFT))) |
| return SWT.SHIFT; |
| if (modifierName.equalsIgnoreCase(Action.findModifierString(SWT.ALT))) |
| return SWT.ALT; |
| if (modifierName.equalsIgnoreCase(Action.findModifierString(SWT.COMMAND))) |
| return SWT.COMMAND; |
| |
| return 0; |
| } |
| |
| /** |
| * Computes the state mask out of the given modifiers string. |
| * |
| * @param modifiers a string containing modifiers |
| * @return the state mask |
| * @since 3.1 |
| */ |
| protected static final int computeStateMask(String modifiers) { |
| if (modifiers == null) |
| return -1; |
| |
| if (modifiers.length() == 0) |
| return SWT.NONE; |
| |
| int stateMask= 0; |
| StringTokenizer modifierTokenizer= new StringTokenizer(modifiers, ",;.:+-* "); //$NON-NLS-1$ |
| while (modifierTokenizer.hasMoreTokens()) { |
| int modifier= findLocalizedModifier(modifierTokenizer.nextToken()); |
| if (modifier == 0 || (stateMask & modifier) == modifier) |
| return -1; |
| stateMask= stateMask | modifier; |
| } |
| return stateMask; |
| } |
| |
| @Override |
| public IUndoManager getUndoManager(ISourceViewer sourceViewer) { |
| if (fPreferenceStore == null || !fPreferenceStore.contains(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_UNDO_HISTORY_SIZE)) |
| return super.getUndoManager(sourceViewer); |
| |
| int undoHistorySize= fPreferenceStore.getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_UNDO_HISTORY_SIZE); |
| return new TextViewerUndoManager(undoHistorySize); |
| } |
| |
| /** |
| * Returns the reconciler ready to be used with the given source viewer. |
| * <p> |
| * This implementation currently returns a {@link MonoReconciler} which |
| * is responsible for spell checking. In the future a different reconciler |
| * taking over more responsibilities might be returned.</p> |
| * |
| * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getReconciler(org.eclipse.jface.text.source.ISourceViewer) |
| * @since 3.3 |
| */ |
| @Override |
| public IReconciler getReconciler(ISourceViewer sourceViewer) { |
| if (fPreferenceStore == null || !fPreferenceStore.getBoolean(SpellingService.PREFERENCE_SPELLING_ENABLED)) |
| return null; |
| |
| SpellingService spellingService= EditorsUI.getSpellingService(); |
| if (spellingService.getActiveSpellingEngineDescriptor(fPreferenceStore) == null) |
| return null; |
| |
| IReconcilingStrategy strategy= new SpellingReconcileStrategy(sourceViewer, spellingService); |
| MonoReconciler reconciler= new MonoReconciler(strategy, false); |
| reconciler.setDelay(500); |
| return reconciler; |
| } |
| |
| @Override |
| public IQuickAssistAssistant getQuickAssistAssistant(ISourceViewer sourceViewer) { |
| if (fPreferenceStore == null || !fPreferenceStore.getBoolean(SpellingService.PREFERENCE_SPELLING_ENABLED)) |
| return null; |
| |
| QuickAssistAssistant assistant= new QuickAssistAssistant(); |
| assistant.setQuickAssistProcessor(new SpellingCorrectionProcessor()); |
| assistant.setRestoreCompletionProposalSize(EditorsPlugin.getDefault().getDialogSettingsSection("quick_assist_proposal_size")); //$NON-NLS-1$ |
| assistant.setInformationControlCreator(getQuickAssistAssistantInformationControlCreator()); |
| |
| return assistant; |
| } |
| |
| /** |
| * Returns the information control creator for the quick assist assistant. |
| * |
| * @return the information control creator |
| * @since 3.3 |
| */ |
| private IInformationControlCreator getQuickAssistAssistantInformationControlCreator() { |
| return new IInformationControlCreator() { |
| @Override |
| public IInformationControl createInformationControl(Shell parent) { |
| return new DefaultInformationControl(parent, EditorsPlugin.getAdditionalInfoAffordanceString()); |
| } |
| }; |
| } |
| |
| /** |
| * Helper method to merge two {@link IHyperlinkDetector} arrays. |
| * |
| * @param array1 an array of hyperlink detectors or <code>null</code> |
| * @param array2 an array of hyperlink detectors or <code>null</code> |
| * @return an array with the merged hyperlink detectors or <code>null</code> if both given arrays are <code>null</code> |
| * @since 3.3 |
| */ |
| private IHyperlinkDetector[] merge(IHyperlinkDetector[] array1, IHyperlinkDetector[] array2) { |
| if (array1 == null && array2 == null) |
| return null; |
| else if (array1 == null) |
| return array2; |
| else if (array2 == null) |
| return array1; |
| else { |
| IHyperlinkDetector[] allHyperlinkDetectors; |
| int size= array1.length + array2.length; |
| allHyperlinkDetectors= new IHyperlinkDetector[size]; |
| System.arraycopy(array1, 0, allHyperlinkDetectors, 0, array1.length); |
| System.arraycopy(array2, 0, allHyperlinkDetectors, array1.length, array2.length); |
| return allHyperlinkDetectors; |
| } |
| } |
| |
| /** |
| * Text hover with custom control creator that |
| * can show the tool tip affordance. |
| * |
| * @since 3.3 |
| */ |
| private final class TextHover extends DefaultTextHover implements ITextHoverExtension { |
| public TextHover(ISourceViewer sourceViewer) { |
| super(sourceViewer); |
| } |
| |
| @Override |
| protected boolean isIncluded(Annotation annotation) { |
| return isShownInText(annotation); |
| } |
| |
| @Override |
| public IInformationControlCreator getHoverControlCreator() { |
| return new IInformationControlCreator() { |
| @Override |
| public IInformationControl createInformationControl(Shell parent) { |
| return new DefaultInformationControl(parent, EditorsUI.getTooltipAffordanceString()); |
| } |
| }; |
| } |
| } |
| |
| } |