From 8dc80ebbb359d449c91a0b7cf1a0483a681e3ee2 Mon Sep 17 00:00:00 2001 From: azerr Date: Thu, 27 Oct 2022 19:39:43 +0200 Subject: [PATCH] API to Track TextViewer install/uninstall in generic editor contribution Signed-off-by: azerr --- .../jface/text/ITextViewerLifecycle.java | 64 +++++++++++++++++ .../text/contentassist/IContentAssistant.java | 5 +- .../text/hyperlink/IHyperlinkPresenter.java | 5 +- .../information/IInformationPresenter.java | 5 +- .../presentation/IPresentationReconciler.java | 5 +- .../jface/text/reconciler/IReconciler.java | 5 +- .../jface/text/reconciler/MonoReconciler.java | 18 +++++ .../jface/text/reconciler/Reconciler.java | 31 ++++++++ .../jface/text/source/SourceViewer.java | 70 +++++++++++++------ .../CompositeReconcilerStrategy.java | 48 +++++++++---- 10 files changed, 216 insertions(+), 40 deletions(-) create mode 100644 org.eclipse.jface.text/src/org/eclipse/jface/text/ITextViewerLifecycle.java diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/ITextViewerLifecycle.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/ITextViewerLifecycle.java new file mode 100644 index 000000000..32c93c7e1 --- /dev/null +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/ITextViewerLifecycle.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2022 Red Hat Inc. and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * - Angelo ZERR (Red Hat Inc.) - initial implementation + *******************************************************************************/ +package org.eclipse.jface.text; + +import org.eclipse.jface.text.DefaultInformationControl.IInformationPresenter; +import org.eclipse.jface.text.contentassist.IContentAssistant; +import org.eclipse.jface.text.hyperlink.IHyperlinkPresenter; +import org.eclipse.jface.text.presentation.IPresentationReconciler; +import org.eclipse.jface.text.reconciler.IReconciler; +import org.eclipse.jface.text.reconciler.IReconcilingStrategy; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.jface.text.source.ISourceViewerExtension2; + +/** + * {@link ITextViewer} lifecycle API to track install / uninstall of a given {@link ITextViewer} for + * the given contribution which extends {@link ITextViewerLifecycle}: + * + * + * + * It is possible too to implement {@link ITextViewerLifecycle} to track install / uninstall of a + * given {@link ITextViewer} for implementation of: + * + * + * + * @since 3.23 + * + */ +public interface ITextViewerLifecycle { + + /** + * Installs a text viewer. This method is called when + * {@link ISourceViewer#configure(org.eclipse.jface.text.source.SourceViewerConfiguration)} is + * called. + * + * @param textViewer the text viewer + */ + void install(ITextViewer textViewer); + + /** + * Uninstalls the registered text viewer. This method is called when + * {@link ISourceViewerExtension2#unconfigure()} is called. + */ + void uninstall(); +} diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/IContentAssistant.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/IContentAssistant.java index f6954cda6..a6f76494a 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/IContentAssistant.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/IContentAssistant.java @@ -14,6 +14,7 @@ package org.eclipse.jface.text.contentassist; import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITextViewerLifecycle; /** @@ -76,7 +77,7 @@ * @see org.eclipse.jface.text.ITextViewer * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor */ - public interface IContentAssistant { +public interface IContentAssistant extends ITextViewerLifecycle { //------ proposal popup orientation styles ------------ /** The context info list will overlay the list of completion proposals. */ @@ -98,12 +99,14 @@ public interface IContentAssistant { * * @param textViewer the text viewer on which content assist will work */ + @Override void install(ITextViewer textViewer); /** * Uninstalls content assist support from the text viewer it has * previously be installed on. */ + @Override void uninstall(); /** diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/hyperlink/IHyperlinkPresenter.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/hyperlink/IHyperlinkPresenter.java index f926faccd..5ea7d1bfb 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/hyperlink/IHyperlinkPresenter.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/hyperlink/IHyperlinkPresenter.java @@ -14,6 +14,7 @@ package org.eclipse.jface.text.hyperlink; import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITextViewerLifecycle; /** @@ -39,7 +40,7 @@ * @see IHyperlinkPresenterExtension2 * @since 3.1 */ -public interface IHyperlinkPresenter { +public interface IHyperlinkPresenter extends ITextViewerLifecycle { /** * Tells whether this presenter is able to handle @@ -73,10 +74,12 @@ public interface IHyperlinkPresenter { * * @param textViewer the text viewer */ + @Override void install(ITextViewer textViewer); /** * Uninstalls this hyperlink presenter. */ + @Override void uninstall(); } diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/information/IInformationPresenter.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/information/IInformationPresenter.java index 2874e9ae1..263aae15e 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/information/IInformationPresenter.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/information/IInformationPresenter.java @@ -14,6 +14,7 @@ package org.eclipse.jface.text.information; import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITextViewerLifecycle; /** @@ -46,7 +47,7 @@ * @see org.eclipse.jface.text.information.IInformationProvider * @since 2.0 */ -public interface IInformationPresenter { +public interface IInformationPresenter extends ITextViewerLifecycle { /** * Installs the information presenter on the given text viewer. After this method has been @@ -55,12 +56,14 @@ public interface IInformationPresenter { * * @param textViewer the viewer on which the presenter is installed */ + @Override void install(ITextViewer textViewer); /** * Removes the information presenter from the text viewer it has previously been * installed on. */ + @Override void uninstall(); /** diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/presentation/IPresentationReconciler.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/presentation/IPresentationReconciler.java index 222233ed5..03338a60d 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/presentation/IPresentationReconciler.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/presentation/IPresentationReconciler.java @@ -15,6 +15,7 @@ import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITextViewerLifecycle; /** @@ -55,7 +56,7 @@ * @see org.eclipse.jface.text.presentation.IPresentationRepairer * @see org.eclipse.jface.text.TextPresentation */ -public interface IPresentationReconciler { +public interface IPresentationReconciler extends ITextViewerLifecycle { /** * Installs this presentation reconciler on the given text viewer. After @@ -71,12 +72,14 @@ public interface IPresentationReconciler { * @param viewer the viewer on which this presentation reconciler is * installed */ + @Override void install(ITextViewer viewer); /** * Removes the reconciler from the text viewer it has previously been * installed on. */ + @Override void uninstall(); /** diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/IReconciler.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/IReconciler.java index fc3fa2c32..06419f15c 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/IReconciler.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/IReconciler.java @@ -14,6 +14,7 @@ package org.eclipse.jface.text.reconciler; import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITextViewerLifecycle; /** @@ -47,7 +48,7 @@ * @see ITextViewer * @see IReconcilingStrategy */ -public interface IReconciler { +public interface IReconciler extends ITextViewerLifecycle { /** * Installs the reconciler on the given text viewer. After this method has been @@ -56,12 +57,14 @@ public interface IReconciler { * * @param textViewer the viewer on which the reconciler is installed */ + @Override void install(ITextViewer textViewer); /** * Removes the reconciler from the text viewer it has * previously been installed on. */ + @Override void uninstall(); /** diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/MonoReconciler.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/MonoReconciler.java index 176c6e1da..eba0502c4 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/MonoReconciler.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/MonoReconciler.java @@ -17,6 +17,8 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITextViewerLifecycle; import org.eclipse.jface.text.Region; @@ -98,4 +100,20 @@ protected void initialProcess() { extension.initialReconcile(); } } + + @Override + public void install(ITextViewer textViewer) { + super.install(textViewer); + if (fStrategy instanceof ITextViewerLifecycle) { + ((ITextViewerLifecycle) fStrategy).install(textViewer); + } + } + + @Override + public void uninstall() { + if (fStrategy instanceof ITextViewerLifecycle) { + ((ITextViewerLifecycle) fStrategy).uninstall(); + } + super.uninstall(); + } } diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/Reconciler.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/Reconciler.java index 4a7eea840..3cfbefc48 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/Reconciler.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/reconciler/Reconciler.java @@ -26,6 +26,8 @@ import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentExtension3; import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITextViewerLifecycle; import org.eclipse.jface.text.ITypedRegion; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.TextUtilities; @@ -161,6 +163,35 @@ protected void reconcilerDocumentChanged(IDocument document) { } } + + @Override + public void install(ITextViewer textViewer) { + super.install(textViewer); + if (fStrategies != null) { + Iterator e= fStrategies.values().iterator(); + while (e.hasNext()) { + IReconcilingStrategy strategy= e.next(); + if (strategy instanceof ITextViewerLifecycle) { + ((ITextViewerLifecycle) strategy).install(textViewer); + } + } + } + } + + @Override + public void uninstall() { + if (fStrategies != null) { + Iterator e= fStrategies.values().iterator(); + while (e.hasNext()) { + IReconcilingStrategy strategy= e.next(); + if (strategy instanceof ITextViewerLifecycle) { + ((ITextViewerLifecycle) strategy).uninstall(); + } + } + } + super.uninstall(); + } + @Override public void setProgressMonitor(IProgressMonitor monitor) { super.setProgressMonitor(monitor); diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/SourceViewer.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/SourceViewer.java index eb4b9e5bf..21a2989a0 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/SourceViewer.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/SourceViewer.java @@ -17,7 +17,9 @@ *******************************************************************************/ package org.eclipse.jface.text.source; +import java.util.HashSet; import java.util.Iterator; +import java.util.Set; import java.util.Stack; import org.eclipse.swt.SWT; @@ -40,6 +42,7 @@ import org.eclipse.jface.text.BlockTextSelection; import org.eclipse.jface.text.DocumentRewriteSession; import org.eclipse.jface.text.DocumentRewriteSessionType; +import org.eclipse.jface.text.IAutoEditStrategy; import org.eclipse.jface.text.IBlockTextSelection; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentExtension4; @@ -51,6 +54,7 @@ import org.eclipse.jface.text.ISynchronizable; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewerExtension2; +import org.eclipse.jface.text.ITextViewerLifecycle; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.TextViewer; @@ -89,8 +93,8 @@ *

* Clients may subclass this class but should expect some breakage by future releases.

*/ -public class SourceViewer extends TextViewer implements ISourceViewer, ISourceViewerExtension, ISourceViewerExtension2, ISourceViewerExtension3, ISourceViewerExtension4, ISourceViewerExtension5 { - +public class SourceViewer extends TextViewer + implements ISourceViewer, ISourceViewerExtension, ISourceViewerExtension2, ISourceViewerExtension3, ISourceViewerExtension4, ISourceViewerExtension5 { /** * Layout of a source viewer. Vertical ruler, text widget, and overview ruler are shown side by side. @@ -389,6 +393,8 @@ private int[] computeScrollArrowHeights(StyledText textWidget, int bottomOffset) */ private CodeMiningManager fCodeMiningManager; + private final Set lifecycles; + /** * Constructs a new source viewer. The vertical ruler is initially visible. * The viewer has not yet been initialized with a source viewer configuration. @@ -422,7 +428,7 @@ public SourceViewer(Composite parent, IVerticalRuler verticalRuler, IOverviewRul fIsVerticalRulerVisible= (verticalRuler != null); fOverviewRuler= overviewRuler; fIsOverviewRulerVisible= (showAnnotationsOverview && overviewRuler != null); - + this.lifecycles= new HashSet<>(); createControl(parent, styles); } @@ -490,16 +496,14 @@ public void configure(SourceViewerConfiguration configuration) { // install content type independent plug-ins fPresentationReconciler= configuration.getPresentationReconciler(this); - if (fPresentationReconciler != null) - fPresentationReconciler.install(this); + addTextViewerLifecycle(fPresentationReconciler); fReconciler= configuration.getReconciler(this); - if (fReconciler != null) - fReconciler.install(this); + addTextViewerLifecycle(fReconciler); fContentAssistant= configuration.getContentAssistant(this); + addTextViewerLifecycle(fContentAssistant); if (fContentAssistant != null) { - fContentAssistant.install(this); if (fContentAssistant instanceof IContentAssistantExtension2 && fContentAssistant instanceof IContentAssistantExtension4) fContentAssistantFacade= new ContentAssistantFacade(fContentAssistant); fContentAssistantInstalled= true; @@ -514,8 +518,7 @@ public void configure(SourceViewerConfiguration configuration) { fContentFormatter= configuration.getContentFormatter(this); fInformationPresenter= configuration.getInformationPresenter(this); - if (fInformationPresenter != null) - fInformationPresenter.install(this); + addTextViewerLifecycle(fInformationPresenter); setUndoManager(configuration.getUndoManager(this)); @@ -537,7 +540,7 @@ public void configure(SourceViewerConfiguration configuration) { String[] types= configuration.getConfiguredContentTypes(this); for (String t : types) { - setAutoEditStrategies(configuration.getAutoEditStrategies(this, t), t); + doSetAutoEditStrategies(configuration.getAutoEditStrategies(this, t), t); setTextDoubleClickStrategy(configuration.getDoubleClickStrategy(this, t), t); int[] stateMasks= configuration.getConfiguredTextHoverStateMasks(this, t); @@ -558,10 +561,21 @@ public void configure(SourceViewerConfiguration configuration) { setDefaultPrefixes(prefixes, t); } setCodeMiningProviders(configuration.getCodeMiningProviders(this)); - + installTextViewer(); activatePlugins(); } + private void doSetAutoEditStrategies(IAutoEditStrategy[] strategies, String contentType) { + super.setAutoEditStrategies(strategies, contentType); + if (strategies != null) { + for (IAutoEditStrategy strategy : strategies) { + if (strategy instanceof ITextViewerLifecycle) { + addTextViewerLifecycle((ITextViewerLifecycle) strategy); + } + } + } + } + /** * After this method has been executed the caller knows that any installed annotation hover has been installed. */ @@ -712,18 +726,11 @@ public IAnnotationModel getVisualAnnotationModel() { public void unconfigure() { clearRememberedSelection(); - if (fPresentationReconciler != null) { - fPresentationReconciler.uninstall(); - fPresentationReconciler= null; - } - - if (fReconciler != null) { - fReconciler.uninstall(); - fReconciler= null; - } + uninstallTextViewer(); + fPresentationReconciler= null; + fReconciler= null; if (fContentAssistant != null) { - fContentAssistant.uninstall(); fContentAssistantInstalled= false; fContentAssistant= null; if (fContentAssistantFacade != null) @@ -1322,4 +1329,23 @@ public void setCodeMiningAnnotationPainter(AnnotationPainter painter) { ensureCodeMiningManagerInstalled(); } + private void addTextViewerLifecycle(ITextViewerLifecycle lifecycle) { + if (lifecycle != null) { + lifecycles.add(lifecycle); + } + } + + private void installTextViewer() { + for (ITextViewerLifecycle lifecycle : lifecycles) { + lifecycle.install(this); + } + } + + private void uninstallTextViewer() { + for (ITextViewerLifecycle lifecycle : lifecycles) { + lifecycle.uninstall(); + } + lifecycles.clear(); + } + } diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/CompositeReconcilerStrategy.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/CompositeReconcilerStrategy.java index bdd731c35..2c50ac3ad 100644 --- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/CompositeReconcilerStrategy.java +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/CompositeReconcilerStrategy.java @@ -18,52 +18,74 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITextViewerLifecycle; import org.eclipse.jface.text.reconciler.DirtyRegion; import org.eclipse.jface.text.reconciler.IReconcilingStrategy; import org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension; -public class CompositeReconcilerStrategy implements IReconcilingStrategy, IReconcilingStrategyExtension{ +public class CompositeReconcilerStrategy + implements IReconcilingStrategy, IReconcilingStrategyExtension, ITextViewerLifecycle { private List fReconcilingStrategies; public CompositeReconcilerStrategy(List strategies) { this.fReconcilingStrategies = strategies; } + @Override public void setProgressMonitor(IProgressMonitor monitor) { - for (IReconcilingStrategy iReconcilingStrategy : fReconcilingStrategies) { - if (iReconcilingStrategy instanceof IReconcilingStrategyExtension) { - ((IReconcilingStrategyExtension) iReconcilingStrategy).setProgressMonitor(monitor); + for (IReconcilingStrategy strategy : fReconcilingStrategies) { + if (strategy instanceof IReconcilingStrategyExtension) { + ((IReconcilingStrategyExtension) strategy).setProgressMonitor(monitor); } } } @Override public void initialReconcile() { - for (IReconcilingStrategy iReconcilingStrategy : fReconcilingStrategies) { - if (iReconcilingStrategy instanceof IReconcilingStrategyExtension) { - ((IReconcilingStrategyExtension) iReconcilingStrategy).initialReconcile(); + for (IReconcilingStrategy strategy : fReconcilingStrategies) { + if (strategy instanceof IReconcilingStrategyExtension) { + ((IReconcilingStrategyExtension) strategy).initialReconcile(); } } } @Override public void setDocument(IDocument document) { - for (IReconcilingStrategy iReconcilingStrategy : fReconcilingStrategies) { - iReconcilingStrategy.setDocument(document); + for (IReconcilingStrategy strategy : fReconcilingStrategies) { + strategy.setDocument(document); } } @Override public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) { - for (IReconcilingStrategy iReconcilingStrategy : fReconcilingStrategies) { - iReconcilingStrategy.reconcile(dirtyRegion, subRegion); + for (IReconcilingStrategy strategy : fReconcilingStrategies) { + strategy.reconcile(dirtyRegion, subRegion); } } @Override public void reconcile(IRegion partition) { - for (IReconcilingStrategy iReconcilingStrategy : fReconcilingStrategies) { - iReconcilingStrategy.reconcile(partition); + for (IReconcilingStrategy strategy : fReconcilingStrategies) { + strategy.reconcile(partition); + } + } + + @Override + public void install(ITextViewer textViewer) { + for (IReconcilingStrategy strategy : fReconcilingStrategies) { + if (strategy instanceof ITextViewerLifecycle) { + ((ITextViewerLifecycle) strategy).install(textViewer); + } + } + } + + @Override + public void uninstall() { + for (IReconcilingStrategy strategy : fReconcilingStrategies) { + if (strategy instanceof ITextViewerLifecycle) { + ((ITextViewerLifecycle) strategy).uninstall(); + } } }