Bug 538952: [SourceEditor] Fix inserting templates in editor templates
page/view

  - Fix dispose of TextViewerJFaceUpdater in AbstractEditorTemplatesPage
    when closing page/view
  - Bug 558209: Fix selection variables in templates when using
    Templates view/AbstractEditorTemplatesPage
    Bug 558211: Fix selection variables in templates when using
    Insert Template actions/InsertEditorTemplateHandler

Change-Id: Ibb181bf22f0c0aaee58df5bdf6feca63a9620b8e
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceEditor1.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceEditor1.java
index a335306..6e2e6c9 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceEditor1.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceEditor1.java
@@ -915,7 +915,7 @@
 	
 	@Override
 	@SuppressWarnings("unchecked")
-	public <T> T getAdapter(final Class<T> adapterType) {
+	public <T> @Nullable T getAdapter(final Class<T> adapterType) {
 		if (adapterType == ISourceEditor.class) {
 			return (T) this;
 		}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/InsertEditorTemplateHandler.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/InsertEditorTemplateHandler.java
index 384c4ed..d28355c 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/InsertEditorTemplateHandler.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/InsertEditorTemplateHandler.java
@@ -20,7 +20,6 @@
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.BadPartitioningException;
 import org.eclipse.jface.text.source.SourceViewer;
-import org.eclipse.jface.text.templates.DocumentTemplateContext;
 import org.eclipse.jface.text.templates.Template;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.graphics.Point;
@@ -90,14 +89,14 @@
 		try {
 			final AssistInvocationContext context= createContext(editor);
 			final TextRegion region= context;
-			final DocumentTemplateContext templateContext= computer.createTemplateContext(
-					context, region, SourceEditorTemplateContext.FORMAT_START );
+			final SourceEditorTemplateContext templateContext= computer.createTemplateContext(
+					context, region, SourceEditorTemplateContext.FORMAT_START, true );
 			if (templateContext == null) {
 				return null;
 			}
 			
 			final TemplateProposal proposal= computer.createProposal(
-					new TemplateProposalParameters<>(template, templateContext, region) );
+					new TemplateProposalParameters<>(context, region, templateContext, template) );
 			
 			final SourceViewer viewer= context.getSourceViewer();
 			proposal.apply(viewer, (char) 0, 0, context.getEndOffset());
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/TemplateCompletionComputer.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/TemplateCompletionComputer.java
index d131f6d..1cb6fbf 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/TemplateCompletionComputer.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/TemplateCompletionComputer.java
@@ -23,7 +23,6 @@
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.source.ISourceViewer;
-import org.eclipse.jface.text.templates.DocumentTemplateContext;
 import org.eclipse.jface.text.templates.GlobalTemplateVariables;
 import org.eclipse.jface.text.templates.GlobalTemplateVariables.LineSelection;
 import org.eclipse.jface.text.templates.GlobalTemplateVariables.WordSelection;
@@ -131,7 +130,7 @@
 		else {
 			region= context;
 		}
-		DocumentTemplateContext templateContext= createTemplateContext(context, region, flags);
+		SourceEditorTemplateContext templateContext= createTemplateContext(context, region, flags);
 		if (templateContext == null) {
 			return;
 		}
@@ -140,8 +139,9 @@
 		if (context.getLength() > 0) {
 			if (prefix.length() == context.getLength()) {
 				final TemplateProposalParameters<?> parameters=  new TemplateProposalParameters<>(
-						templateContext, context, region,
-						new SearchPattern(getSearchMatchRules(), prefix) );
+						context, region,
+						new SearchPattern(getSearchMatchRules(), prefix),
+						templateContext );
 				count= computeProposals0(parameters, 0, proposals);
 			}
 			prefix= ""; // wenn erfolglos, dann ohne prefix //$NON-NLS-1$
@@ -153,21 +153,12 @@
 			}
 		}
 		try {
-			final IDocument document= viewer.getDocument();
-			final String text= document.get(context.getOffset(), context.getLength());
-			final int selectionType;
-			if (text.isEmpty()) {
-				selectionType= SELECTION_NONE;
-			}
-			else {
-				selectionType= (text.indexOf('\n') >= 0) ? SELECTION_MULTILINE : SELECTION_INLINE;
-				templateContext.setVariable("text", text); //$NON-NLS-1$
-			}
-			templateContext.setVariable(GlobalTemplateVariables.SELECTION, text);
+			final int selectionType= configureTemplateContext(context, templateContext);
 			
 			final TemplateProposalParameters<?> parameters=  new TemplateProposalParameters<>(
-					templateContext, context, region,
-					new SearchPattern(getSearchMatchRules(), prefix) );
+					context, region,
+					new SearchPattern(getSearchMatchRules(), prefix),
+					templateContext );
 			computeProposals0(parameters, selectionType, proposals);
 		}
 		catch (final BadLocationException e) {
@@ -255,18 +246,43 @@
 	protected abstract @Nullable TemplateContextType getContextType(
 			final AssistInvocationContext context, final TextRegion region);
 	
+	public @Nullable SourceEditorTemplateContext createTemplateContext(
+			final AssistInvocationContext context, final TextRegion region,
+			final int flags, final boolean configure) throws BadLocationException {
+		final SourceEditorTemplateContext templateContext= createTemplateContext(context, region, flags);
+		if (templateContext != null && configure) {
+			configureTemplateContext(context, templateContext);
+		}
+		return templateContext;
+	}
+	
 	protected @Nullable SourceEditorTemplateContext createTemplateContext(
 			final AssistInvocationContext context, final TextRegion region,
 			final int flags) {
 		final TemplateContextType contextType= getContextType(context, region);
 		if (contextType != null) {
-			return new SourceEditorTemplateContext(contextType, context.getDocument(),
-					region.getStartOffset(), region.getLength(),
+			return new SourceEditorTemplateContext(contextType, context.getDocument(), region,
 					context.getEditor(), flags );
 		}
 		return null;
 	}
 	
+	protected int configureTemplateContext(final AssistInvocationContext context,
+			final SourceEditorTemplateContext templateContext) throws BadLocationException {
+		final IDocument document= context.getDocument();
+		final String text= document.get(context.getOffset(), context.getLength());
+		final int selectionType;
+		if (text.isEmpty()) {
+			selectionType= SELECTION_NONE;
+		}
+		else {
+			selectionType= (text.indexOf('\n') >= 0) ? SELECTION_MULTILINE : SELECTION_INLINE;
+			templateContext.setVariable("text", text); //$NON-NLS-1$
+		}
+		templateContext.setVariable(GlobalTemplateVariables.SELECTION, text);
+		return selectionType;
+	}
+	
 	protected TemplateProposal createProposal(final TemplateProposalParameters<?> parameters) {
 		return new TemplateProposal(parameters, getImage(parameters.template));
 	}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/TemplateProposal.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/TemplateProposal.java
index 2ec2294..807abc2 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/TemplateProposal.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/TemplateProposal.java
@@ -48,6 +48,7 @@
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.ui.statushandlers.StatusManager;
 
+import org.eclipse.statet.jcommons.lang.NonNull;
 import org.eclipse.statet.jcommons.lang.NonNullByDefault;
 import org.eclipse.statet.jcommons.lang.Nullable;
 import org.eclipse.statet.jcommons.text.core.SearchPattern;
@@ -58,7 +59,6 @@
 
 import org.eclipse.statet.internal.ltk.ui.LTKUIPlugin;
 import org.eclipse.statet.ltk.ui.LTKUI;
-import org.eclipse.statet.ltk.ui.sourceediting.ISourceEditor;
 import org.eclipse.statet.ltk.ui.sourceediting.ITextEditToolSynchronizer;
 import org.eclipse.statet.ltk.ui.templates.IWorkbenchTemplateContext;
 import org.eclipse.statet.ltk.ui.util.LTKSelectionUtils;
@@ -67,6 +67,7 @@
 /**
  * Like default {@link org.eclipse.jface.text.templates.TemplateProposal}, but
  * <ul>
+ *   <li>supports substring matching
  *   <li>supports {@link ITextEditToolSynchronizer}</li>
  * </ul>
  */
@@ -106,19 +107,20 @@
 		
 		
 		@SuppressWarnings("null")
-		public TemplateProposalParameters(final DocumentTemplateContext templateContext,
+		public TemplateProposalParameters(
 				final TContext context, final TextRegion region,
-				final SearchPattern namePattern) {
+				final SearchPattern namePattern,
+				final DocumentTemplateContext templateContext) {
 			super(context, region.getStartOffset(), namePattern);
 			
 			this.templateContext= templateContext;
 			this.region= region;
 		}
 		
-		public TemplateProposalParameters(final Template template,
-				final DocumentTemplateContext templateContext,
-				/*final TContext context,*/ final TextRegion region) {
-			super(null, region.getStartOffset(), null);
+		public TemplateProposalParameters(
+				final TContext context, final TextRegion region,
+				final DocumentTemplateContext templateContext, final Template template) {
+			super(context, region.getStartOffset(), 0);
 			
 			this.templateContext= templateContext;
 			this.region= region;
@@ -262,9 +264,9 @@
 			this.templateContext.setReadOnly(false);
 			TemplateBuffer templateBuffer;
 			try {
-				templateBuffer= this.templateContext.evaluate(this.template);
+				templateBuffer= nonNullAssert(this.templateContext.evaluate(this.template));
 			}
-			catch (final TemplateException e1) {
+			catch (final TemplateException | NullPointerException e) {
 				applyData.setSelection(this.region);
 				return;
 			}
@@ -294,7 +296,7 @@
 				final int length= variable.getLength();
 				
 				final String[] values= variable.getValues();
-				final ICompletionProposal[] proposals= new ICompletionProposal[values.length];
+				final ICompletionProposal[] proposals= new @NonNull ICompletionProposal[values.length];
 				for (int j= 0; j < values.length; j++) {
 					ensurePositionCategoryInstalled(document, model);
 					final Position pos= new Position(offsets[0] + start, length);
@@ -318,11 +320,10 @@
 			if (hasPositions) {
 				model.forceInstall();
 				
-				if (this.templateContext instanceof IWorkbenchTemplateContext) {
-					final ISourceEditor editor= ((IWorkbenchTemplateContext) this.templateContext).getEditor();
-					if (editor.getTextEditToolSynchronizer() != null) {
-						editor.getTextEditToolSynchronizer().install(model);
-					}
+				final ITextEditToolSynchronizer toolSynchronizer= getInvocationContext().getEditor()
+						.getTextEditToolSynchronizer();
+				if (toolSynchronizer != null) {
+					toolSynchronizer.install(model);
 				}
 				
 				final LinkedModeUI ui= new LinkedModeUI(model, viewer);
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/templates/SourceEditorTemplateContext.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/templates/SourceEditorTemplateContext.java
index 0c2a1b9..50578d8 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/templates/SourceEditorTemplateContext.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/templates/SourceEditorTemplateContext.java
@@ -34,6 +34,7 @@
 
 import org.eclipse.statet.jcommons.lang.NonNullByDefault;
 import org.eclipse.statet.jcommons.lang.Nullable;
+import org.eclipse.statet.jcommons.text.core.TextRegion;
 
 import org.eclipse.statet.ecommons.text.TextUtil;
 
@@ -59,9 +60,9 @@
 	
 	
 	public SourceEditorTemplateContext(final TemplateContextType type, final IDocument document,
-			final int offset, final int length,
+			final TextRegion region,
 			final ISourceEditor editor, final int flags) {
-		super(type, document, offset, length);
+		super(type, document, region.getStartOffset(), region.getLength());
 		this.editor= editor;
 		this.flags= flags;
 	}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/templates/config/AbstractEditorTemplatesPage.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/templates/config/AbstractEditorTemplatesPage.java
index 8e34bc7..643a3f2 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/templates/config/AbstractEditorTemplatesPage.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/templates/config/AbstractEditorTemplatesPage.java
@@ -17,81 +17,101 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
 import org.eclipse.jface.resource.JFaceResources;
 import org.eclipse.jface.text.AbstractDocument;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.BadPartitioningException;
 import org.eclipse.jface.text.Document;
 import org.eclipse.jface.text.IDocument;
-import org.eclipse.jface.text.source.ISourceViewer;
 import org.eclipse.jface.text.source.SourceViewer;
 import org.eclipse.jface.text.templates.ContextTypeRegistry;
-import org.eclipse.jface.text.templates.DocumentTemplateContext;
 import org.eclipse.jface.text.templates.Template;
 import org.eclipse.jface.text.templates.TemplateContextType;
 import org.eclipse.jface.text.templates.persistence.TemplateStore;
 import org.eclipse.jface.window.Window;
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.ui.editors.text.EditorsUI;
+import org.eclipse.ui.texteditor.ITextEditor;
 import org.eclipse.ui.texteditor.templates.AbstractTemplatesPage;
 import org.eclipse.ui.texteditor.templates.ITemplatesPage;
 
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+import org.eclipse.statet.jcommons.text.core.BasicTextRegion;
 import org.eclipse.statet.jcommons.text.core.TextRegion;
 
 import org.eclipse.statet.ecommons.preferences.ui.SettingsUpdater;
 import org.eclipse.statet.ecommons.templates.TemplateVariableProcessor;
+import org.eclipse.statet.ecommons.text.core.util.TextUtils;
 import org.eclipse.statet.ecommons.text.ui.TextViewerEditorColorUpdater;
 import org.eclipse.statet.ecommons.text.ui.TextViewerJFaceUpdater;
 import org.eclipse.statet.ecommons.ui.ISettingsChangedHandler;
 import org.eclipse.statet.ecommons.ui.util.UIAccess;
 
+import org.eclipse.statet.internal.ltk.ui.LTKUIPlugin;
+import org.eclipse.statet.ltk.model.core.IModelManager;
 import org.eclipse.statet.ltk.ui.sourceediting.ISourceEditor;
-import org.eclipse.statet.ltk.ui.sourceediting.SourceEditor1;
 import org.eclipse.statet.ltk.ui.sourceediting.SourceEditorViewerConfigurator;
 import org.eclipse.statet.ltk.ui.sourceediting.ViewerSourceEditorAdapter;
+import org.eclipse.statet.ltk.ui.sourceediting.assist.AssistInvocationContext;
+import org.eclipse.statet.ltk.ui.sourceediting.assist.TemplateCompletionComputer;
 import org.eclipse.statet.ltk.ui.sourceediting.assist.TemplateProposal;
 import org.eclipse.statet.ltk.ui.sourceediting.assist.TemplateProposal.TemplateProposalParameters;
 import org.eclipse.statet.ltk.ui.templates.EnhTemplateStore;
 import org.eclipse.statet.ltk.ui.templates.EnhTemplateStore.WorkingCopy;
-import org.eclipse.statet.ltk.ui.util.LTKSelectionUtils;
+import org.eclipse.statet.ltk.ui.templates.SourceEditorTemplateContext;
 
 
 /**
  * Abstract {@link ITemplatesPage} for SourceEditor1/SourceViewerConfigurator
  */
+@NonNullByDefault
 public abstract class AbstractEditorTemplatesPage extends AbstractTemplatesPage {
 	
 	
 	private final EnhTemplateStore templateStore;
 	private final EnhTemplateStore.WorkingCopy templateStoreWorkingCopy;
-	private Runnable templateStoreListener;
+	private @Nullable Runnable templateStoreListener;
 	
-	private final SourceEditor1 editor;
+	private final ITextEditor editorPart;
+	private final ISourceEditor sourceEditor;
 	
 	private ISourceEditor previewEditor;
 	private final TemplateVariableProcessor previewTemplateProcessor;
 	private final TemplateVariableProcessor editTemplateProcessor;
 	
-	private SourceEditorViewerConfigurator currentPreviewConfigurator;
-	private TextViewerJFaceUpdater currentPreviewUpdater;
+	private @Nullable SourceEditorViewerConfigurator currentPreviewConfigurator;
+	private @Nullable TextViewerJFaceUpdater currentPreviewUpdater;
 	
 	
 	protected AbstractEditorTemplatesPage(final EnhTemplateStore templateStore,
-			final SourceEditor1 editor, final ISourceViewer viewer) {
-		super(editor, viewer);
+			final ITextEditor editorPart, final ISourceEditor sourceEditor) {
+		super(editorPart, sourceEditor.getViewer());
 		
 		this.templateStore= templateStore;
 		this.templateStoreWorkingCopy= this.templateStore.getWorkingCopy();
 		
-		this.editor= editor;
+		this.editorPart= editorPart;
+		this.sourceEditor= sourceEditor;
 		
 		this.previewTemplateProcessor= new TemplateVariableProcessor();
 		this.editTemplateProcessor= new TemplateVariableProcessor();
 	}
 	
 	
-	protected SourceEditor1 getEditor() {
-		return this.editor;
+	protected ISourceEditor getSourceEditor() {
+		return this.sourceEditor;
+	}
+	
+	protected AssistInvocationContext createContext(
+			final ISourceEditor editor, final TextRegion region)
+			throws BadPartitioningException, BadLocationException {
+		final String contentType= TextUtils.getContentType(editor.getViewer().getDocument(),
+				editor.getDocumentContentInfo(), region.getStartOffset(), true );
+		return new AssistInvocationContext(editor, region, contentType, IModelManager.NONE, null );
 	}
 	
 	@Override
@@ -104,44 +124,73 @@
 		return this.templateStore.getContextTypeRegistry();
 	}
 	
+	protected abstract @Nullable TemplateCompletionComputer getComputer(
+			final AssistInvocationContext context, final Template template);
+	
 	
 	@Override
 	protected boolean isValidTemplate(final IDocument document, final Template template,
 			final int offset, final int length) {
-		final String[] contextIds= getContextTypeIds(document, offset);
-		for (int i= 0; i < contextIds.length; i++) {
-			if (contextIds[i].equals(template.getContextTypeId())) {
-				final DocumentTemplateContext context= createContext(document, template, offset, length);
-				return context.canEvaluate(template);
+		final ISourceEditor sourceEditor= getSourceEditor();
+		if (sourceEditor == null) {
+			return false;
+		}
+		try {
+			final String[] contextIds= getContextTypeIds(document, offset);
+			for (int i= 0; i < contextIds.length; i++) {
+				if (contextIds[i].equals(template.getContextTypeId())) {
+					final TextRegion region= new BasicTextRegion(offset, offset + length);
+					final AssistInvocationContext context= createContext(sourceEditor, region);
+					final TemplateCompletionComputer computer= getComputer(context, template);
+					if (computer == null) {
+						return false;
+					}
+					final SourceEditorTemplateContext templateContext= computer.createTemplateContext(
+							context, region, 0, true );
+					return (templateContext != null
+							&& templateContext.canEvaluate(template) );
+				}
 			}
 		}
+		catch (final Exception e) {}
 		return false;
 	}
 	
 	@Override
 	protected void insertTemplate(final Template template, final IDocument document) {
-		final ISourceEditor sourceEditor= this.editor.getAdapter(ISourceEditor.class);
-		if (!sourceEditor.isEditable(true)) {
+		final ISourceEditor sourceEditor= getSourceEditor();
+		if (sourceEditor == null || !sourceEditor.isEditable(true)) {
 			return;
 		}
-		final SourceViewer sourceViewer= sourceEditor.getViewer();
-		final Point selectedRange= sourceViewer.getSelectedRange();
-		final DocumentTemplateContext context= createContext(document, template, selectedRange.x, selectedRange.y);
-		if (context == null) {
-			return;
+		try {
+			final AssistInvocationContext context= createContext(sourceEditor, sourceEditor.getSelectedRegion());
+			final TextRegion region= context;
+			final TemplateCompletionComputer computer= getComputer(context, template);
+			if (computer == null) {
+				return;
+			}
+			final SourceEditorTemplateContext templateContext= computer.createTemplateContext(
+					context, region, 0, true );
+			if (templateContext == null) {
+				return;
+			}
+			final TemplateProposal proposal= new TemplateProposal(
+					new TemplateProposalParameters<>(context, region, templateContext, template) );
+			this.editorPart.getSite().getPage().activate(this.editorPart);
+			proposal.apply(sourceEditor.getViewer(), (char)0, 0, region.getStartOffset());
 		}
-		final TextRegion region= LTKSelectionUtils.toTextRegion(selectedRange);
-		final TemplateProposal proposal= new TemplateProposal(
-				new TemplateProposalParameters<>(template, context, region) );
-		this.editor.getSite().getPage().activate(this.editor);
-		proposal.apply(sourceViewer, (char) 0, 0, region.getStartOffset());
+		catch (final Exception e) {
+			LTKUIPlugin.log(new Status(IStatus.ERROR, LTKUIPlugin.BUNDLE_ID,
+					"An error occurred when applying editor template.", e));
+		}
 	}
 	
 	
 	@Override
 	public void createControl(final Composite ancestor) {
-		if (this.templateStoreListener == null) {
-			this.templateStoreListener= new Runnable() {
+		Runnable listener= this.templateStoreListener;
+		if (listener == null) {
+			listener= new Runnable() {
 				@Override
 				public void run() {
 					final WorkingCopy templateStore= AbstractEditorTemplatesPage.this.templateStoreWorkingCopy;
@@ -150,19 +199,22 @@
 					}
 				}
 			};
-			this.templateStore.addListener(this.templateStoreListener);
+			this.templateStore.addListener(listener);
+			this.templateStoreListener= listener;
 		}
-		this.templateStoreListener.run();
+		listener.run();
 		
 		super.createControl(ancestor);
 	}
 	
 	@Override
 	public void dispose() {
-		if (this.templateStoreListener != null) {
-			this.templateStore.removeListener(this.templateStoreListener);
+		final Runnable templateStoreListener= this.templateStoreListener;
+		if (templateStoreListener != null) {
+			this.templateStore.removeListener(templateStoreListener);
 			this.templateStoreListener= null;
 		}
+		disposePreviewUpdater();
 		
 		super.dispose();
 	}
@@ -181,8 +233,9 @@
 		new SettingsUpdater(new ISettingsChangedHandler() {
 			@Override
 			public void handleSettingsChanged(final Set<String> groupIds, final Map<String, Object> options) {
-				if (AbstractEditorTemplatesPage.this.currentPreviewConfigurator != null) {
-					AbstractEditorTemplatesPage.this.currentPreviewConfigurator.handleSettingsChanged(groupIds, options);
+				final SourceEditorViewerConfigurator configurator= AbstractEditorTemplatesPage.this.currentPreviewConfigurator;
+				if (configurator != null) {
+					configurator.handleSettingsChanged(groupIds, options);
 				}
 			}
 		}, viewer.getControl());
@@ -191,7 +244,7 @@
 	}
 	
 	@Override
-	protected void updatePatternViewer(final Template template) {
+	protected void updatePatternViewer(final @Nullable Template template) {
 		final SourceViewer patternViewer= getPatternViewer();
 		if (patternViewer == null || !(UIAccess.isOkToUse(patternViewer.getControl())) ) {
 			return;
@@ -202,22 +255,21 @@
 			final TemplateContextType type= getContextTypeRegistry().getContextType(template.getContextTypeId());
 			this.previewTemplateProcessor.setContextType(type);
 			
-			if (configurator != this.currentPreviewConfigurator) {
-				if (this.currentPreviewUpdater != null) {
-					this.currentPreviewUpdater.dispose();
-					this.currentPreviewUpdater= null;
-				}
-				if (this.currentPreviewConfigurator != null) {
-					this.currentPreviewConfigurator.unconfigureTarget();
+			final SourceEditorViewerConfigurator currentConfigurator= this.currentPreviewConfigurator;
+			if (configurator != currentConfigurator) {
+				disposePreviewUpdater();
+				if (currentConfigurator != null) {
+					this.currentPreviewConfigurator= null;
+					currentConfigurator.unconfigureTarget();
 				}
 				
+				configurator.setTarget(this.previewEditor);
 				this.currentPreviewConfigurator= configurator;
-				this.currentPreviewConfigurator.setTarget(this.previewEditor);
 				this.currentPreviewUpdater= new TextViewerJFaceUpdater(patternViewer,
-						this.currentPreviewConfigurator.getSourceViewerConfiguration().getPreferences() );
+						configurator.getSourceViewerConfiguration().getPreferences() );
 				
 				final AbstractDocument document= new Document();
-				this.currentPreviewConfigurator.getDocumentSetupParticipant().setup(document);
+				configurator.getDocumentSetupParticipant().setup(document);
 				configureDocument(document, type, configurator);
 				document.set(template.getPattern());
 				patternViewer.setDocument(document);
@@ -236,8 +288,16 @@
 		patternViewer.setSelectedRange(0, 0);
 	}
 	
+	private void disposePreviewUpdater() {
+		final TextViewerJFaceUpdater updater= this.currentPreviewUpdater;
+		if (updater != null) {
+			this.currentPreviewUpdater= null;
+			updater.dispose();
+		}
+	}
+	
 	@Override
-	protected Template editTemplate(final Template template, final boolean edit, final boolean isNameModifiable) {
+	protected @Nullable Template editTemplate(final Template template, final boolean edit, final boolean isNameModifiable) {
 		final SourceEditorViewerConfigurator configurator= getTemplateEditConfig(template, this.editTemplateProcessor);
 		final org.eclipse.statet.ltk.ui.templates.config.EditTemplateDialog dialog= new org.eclipse.statet.ltk.ui.templates.config.EditTemplateDialog(
 				getSite().getShell(), template, edit,
@@ -260,9 +320,6 @@
 	}
 	
 	
-	protected abstract DocumentTemplateContext createContext(IDocument document,
-			Template template, int offset, int length);
-	
 	protected abstract SourceEditorViewerConfigurator getTemplatePreviewConfig(
 			Template template, TemplateVariableProcessor templateProcessor);