Bug 572002: [Runtime] Remove use of deprecated API

Change-Id: I248475dc58884f7b1fc9ee85c5288817e7de1f70
diff --git a/ltk/org.eclipse.statet.ltk.buildpath.ui/META-INF/MANIFEST.MF b/ltk/org.eclipse.statet.ltk.buildpath.ui/META-INF/MANIFEST.MF
index 282f18e..57bbf74 100644
--- a/ltk/org.eclipse.statet.ltk.buildpath.ui/META-INF/MANIFEST.MF
+++ b/ltk/org.eclipse.statet.ltk.buildpath.ui/META-INF/MANIFEST.MF
@@ -16,6 +16,7 @@
  org.eclipse.ui.ide,
  org.eclipse.statet.ltk.buildpath.core;bundle-version="[4.4.0,4.5.0)";visibility:=reexport,
  org.eclipse.statet.ecommons.uimisc;bundle-version="[4.4.0,4.5.0)"
-Import-Package: org.eclipse.statet.jcommons.collections;version="4.4.0"
+Import-Package: org.eclipse.statet.jcommons.collections;version="4.4.0",
+ org.eclipse.statet.jcommons.lang;version="4.4.0"
 Export-Package: org.eclipse.statet.ltk.buildpath.ui,
  org.eclipse.statet.ltk.buildpath.ui.wizards
diff --git a/ltk/org.eclipse.statet.ltk.buildpath.ui/src/org/eclipse/statet/internal/ltk/buildpath/ui/BuildpathElementImageDescriptor.java b/ltk/org.eclipse.statet.ltk.buildpath.ui/src/org/eclipse/statet/internal/ltk/buildpath/ui/BuildpathElementImageDescriptor.java
index 511ee1c..d2f4a18 100644
--- a/ltk/org.eclipse.statet.ltk.buildpath.ui/src/org/eclipse/statet/internal/ltk/buildpath/ui/BuildpathElementImageDescriptor.java
+++ b/ltk/org.eclipse.statet.ltk.buildpath.ui/src/org/eclipse/statet/internal/ltk/buildpath/ui/BuildpathElementImageDescriptor.java
@@ -14,19 +14,21 @@
 
 package org.eclipse.statet.internal.ltk.buildpath.ui;
 
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
+import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
+
 import org.eclipse.jface.resource.CompositeImageDescriptor;
 import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.swt.graphics.ImageData;
 import org.eclipse.swt.graphics.Point;
-import org.eclipse.ui.statushandlers.StatusManager;
+
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
 
 import org.eclipse.statet.ecommons.ui.SharedUIResources;
 
 import org.eclipse.statet.ltk.buildpath.ui.BuildpathsUIResources;
 
 
+@NonNullByDefault
 public class BuildpathElementImageDescriptor extends CompositeImageDescriptor {
 	
 	
@@ -51,20 +53,10 @@
 	public final static int IGNORE_OPTIONAL_PROBLEMS=       0b0_0001_0000_0000;
 	
 	
-	private static ImageData getImageData(final ImageDescriptor descriptor) {
-		ImageData data= descriptor.getImageData(); // see bug 51965: getImageData can return null
-		if (data == null) {
-			data= DEFAULT_IMAGE_DATA;
-			StatusManager.getManager().handle(new Status(IStatus.WARNING, BuildpathsUIPlugin.BUNDLE_ID,
-					"Image data not available: " + descriptor.toString() )); //$NON-NLS-1$
-		}
-		return data;
-	}
-	
-	
 	private final ImageDescriptor baseImage;
 	private final int flags;
-	private final Point size;
+	
+	private @Nullable Point size;
 	
 	
 	/**
@@ -75,20 +67,9 @@
 	 * 	for valid values.
 	 * @param size the size of the resulting image
 	 */
-	public BuildpathElementImageDescriptor(final ImageDescriptor baseImage, final int flags, final Point size) {
-		if (baseImage == null) {
-			throw new NullPointerException("baseImage"); //$NON-NLS-1$
-		}
-		
-		this.baseImage= baseImage;
+	public BuildpathElementImageDescriptor(final ImageDescriptor baseImage, final int flags) {
+		this.baseImage= nonNullAssert(baseImage);
 		this.flags= flags;
-		if (size != null) {
-			this.size= size;
-		}
-		else {
-			final ImageData data= getImageData(baseImage);
-			this.size= new Point(data.width, data.height);
-		}
 	}
 	
 	
@@ -102,7 +83,13 @@
 	
 	@Override
 	protected final Point getSize() {
-		return this.size;
+		var size= this.size;
+		if (size == null) {
+			final var data= createCachedImageDataProvider(getBaseImage());
+			size= new Point(data.getWidth(), data.getHeight());
+			this.size= size;
+		}
+		return size;
 	}
 	
 	
@@ -110,12 +97,12 @@
 	protected void drawCompositeImage(final int width, final int height) {
 		if ((this.flags & DEPRECATED) != 0) { // draw *behind* the full image
 			final Point size= getSize();
-			final ImageData data= getImageData(SharedUIResources.INSTANCE.getImageDescriptor(
+			final var data= createCachedImageDataProvider(SharedUIResources.INSTANCE.getImageDescriptor(
 					SharedUIResources.OVR_DEPRECATED_IMAGE_ID ));
-			drawImage(data, 0, size.y - data.height);
+			drawImage(data, 0, size.y - data.getHeight());
 		}
 		
-		{	final ImageData data= getImageData(getBaseImage());
+		{	final var data= createCachedImageDataProvider(getBaseImage());
 			drawImage(data, 0, 0);
 		}
 		
@@ -125,8 +112,8 @@
 	}
 	
 	private void addTopRightImage(final ImageDescriptor desc, final Point pos) {
-		final ImageData data= getImageData(desc);
-		final int x= pos.x - data.width;
+		final var data= createCachedImageDataProvider(desc);
+		final int x= pos.x - data.getWidth();
 		if (x >= 0) {
 			drawImage(data, x, pos.y);
 			pos.x= x;
@@ -134,9 +121,9 @@
 	}
 	
 	private void addBottomRightImage(final ImageDescriptor desc, final Point pos) {
-		final ImageData data= getImageData(desc);
-		final int x= pos.x - data.width;
-		final int y= pos.y - data.height;
+		final var data= createCachedImageDataProvider(desc);
+		final int x= pos.x - data.getWidth();
+		final int y= pos.y - data.getHeight();
 		if (x >= 0 && y >= 0) {
 			drawImage(data, x, y);
 			pos.x= x;
@@ -144,12 +131,13 @@
 	}
 	
 	private void addBottomLeftImage(final ImageDescriptor desc, final Point pos) {
-		final ImageData data= getImageData(desc);
+		final var data= createCachedImageDataProvider(desc);
 		final int x= pos.x;
-		final int y= pos.y - data.height;
-		if (x + data.width < getSize().x && y >= 0) {
+		final int y= pos.y - data.getHeight();
+		final int xEnd= x + data.getWidth();
+		if (xEnd < getSize().x && y >= 0) {
 			drawImage(data, x, y);
-			pos.x= x + data.width;
+			pos.x= xEnd;
 		}
 	}
 	
@@ -183,19 +171,18 @@
 	
 	@Override
 	public int hashCode() {
-		return (this.baseImage.hashCode() ^ this.flags) + this.size.hashCode();
+		return (this.baseImage.hashCode() ^ this.flags);
 	}
 	
 	@Override
-	public boolean equals(final Object obj) {
+	public boolean equals(final @Nullable Object obj) {
 		if (this == obj) {
 			return true;
 		}
 		if (obj != null && getClass().equals(obj.getClass())) {
-			final BuildpathElementImageDescriptor other= (BuildpathElementImageDescriptor) obj;
+			final BuildpathElementImageDescriptor other= (BuildpathElementImageDescriptor)obj;
 			return (this.baseImage.equals(other.baseImage)
-					&& this.flags == other.flags
-					&& this.size.equals(other.size) );
+					&& this.flags == other.flags );
 		}
 		return false;
 	}
diff --git a/ltk/org.eclipse.statet.ltk.buildpath.ui/src/org/eclipse/statet/ltk/buildpath/ui/BuildpathListLabelProvider.java b/ltk/org.eclipse.statet.ltk.buildpath.ui/src/org/eclipse/statet/ltk/buildpath/ui/BuildpathListLabelProvider.java
index d5712ae..2d66869 100644
--- a/ltk/org.eclipse.statet.ltk.buildpath.ui/src/org/eclipse/statet/ltk/buildpath/ui/BuildpathListLabelProvider.java
+++ b/ltk/org.eclipse.statet.ltk.buildpath.ui/src/org/eclipse/statet/ltk/buildpath/ui/BuildpathListLabelProvider.java
@@ -26,7 +26,6 @@
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.ide.IDE;
 
-import org.eclipse.statet.ecommons.ui.SharedUIResources;
 import org.eclipse.statet.ecommons.ui.util.ImageDescriptorRegistry;
 import org.eclipse.statet.ecommons.ui.util.MessageUtils;
 
@@ -63,8 +62,7 @@
 			if (imageDescriptor != null) {
 				if (listElement.isMissing() || listElement.hasMissingChildren()) {
 					imageDescriptor= new BuildpathElementImageDescriptor(imageDescriptor,
-							BuildpathElementImageDescriptor.ERROR,
-							SharedUIResources.INSTANCE.getIconDefaultSize() );
+							BuildpathElementImageDescriptor.ERROR );
 				}
 				return this.registry.get(imageDescriptor);
 			}
diff --git a/ltk/org.eclipse.statet.ltk.buildpath.ui/src/org/eclipse/statet/ltk/buildpath/ui/BuildpathsUIResources.java b/ltk/org.eclipse.statet.ltk.buildpath.ui/src/org/eclipse/statet/ltk/buildpath/ui/BuildpathsUIResources.java
index ffeaa64..b39d07f 100644
--- a/ltk/org.eclipse.statet.ltk.buildpath.ui/src/org/eclipse/statet/ltk/buildpath/ui/BuildpathsUIResources.java
+++ b/ltk/org.eclipse.statet.ltk.buildpath.ui/src/org/eclipse/statet/ltk/buildpath/ui/BuildpathsUIResources.java
@@ -14,14 +14,15 @@
 
 package org.eclipse.statet.ltk.buildpath.ui;
 
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.jface.resource.ImageRegistry;
-import org.eclipse.swt.graphics.Image;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+
+import org.eclipse.statet.ecommons.ui.util.UIResources;
 
 import org.eclipse.statet.internal.ltk.buildpath.ui.BuildpathsUIPlugin;
 
 
-public class BuildpathsUIResources {
+@NonNullByDefault
+public class BuildpathsUIResources extends UIResources {
 	
 	
 	private static final String NS= "org.eclipse.statet.ltk.buildpath"; //$NON-NLS-1$
@@ -36,19 +37,9 @@
 	public static final BuildpathsUIResources INSTANCE= new BuildpathsUIResources();
 	
 	
-	private final ImageRegistry registry;
-	
-	
 	private BuildpathsUIResources() {
-		this.registry= BuildpathsUIPlugin.getInstance().getImageRegistry();
+		super(BuildpathsUIPlugin.getInstance().getImageRegistry());
 	}
 	
-	public ImageDescriptor getImageDescriptor(final String id) {
-		return this.registry.getDescriptor(id);
-	}
-	
-	public Image getImage(final String id) {
-		return this.registry.get(id);
-	}
 	
 }
diff --git a/ltk/org.eclipse.statet.ltk.ui/META-INF/MANIFEST.MF b/ltk/org.eclipse.statet.ltk.ui/META-INF/MANIFEST.MF
index 7a6caf1..2a9041e 100644
--- a/ltk/org.eclipse.statet.ltk.ui/META-INF/MANIFEST.MF
+++ b/ltk/org.eclipse.statet.ltk.ui/META-INF/MANIFEST.MF
@@ -40,7 +40,8 @@
  org.eclipse.statet.jcommons.lang;version="4.4.0",
  org.eclipse.statet.jcommons.status;version="4.4.0",
  org.eclipse.statet.jcommons.status.eplatform;version="4.4.0",
- org.eclipse.statet.jcommons.text.core;version="4.4.0"
+ org.eclipse.statet.jcommons.text.core;version="4.4.0",
+ org.eclipse.statet.jcommons.util;version="4.4.0"
 Export-Package: org.eclipse.statet.ecommons.templates,
  org.eclipse.statet.ecommons.text.ui,
  org.eclipse.statet.ecommons.text.ui.presentation,
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ecommons/text/ui/DefaultBrowserInformationInput.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ecommons/text/ui/DefaultBrowserInformationInput.java
index 07f84e4..5bf869c 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ecommons/text/ui/DefaultBrowserInformationInput.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ecommons/text/ui/DefaultBrowserInformationInput.java
@@ -107,13 +107,13 @@
 		}
 		
 		String format(String content, final int formatting) {
-			final StringBuffer s;
+			final StringBuilder s;
 			switch (formatting) {
 			case FORMAT_NONE:
 				return content;
-			case FORMAT_TEXT_INPUT: 
+			case FORMAT_TEXT_INPUT:
 				content= HTMLPrinter.convertToHTMLContent(content);
-				s= new StringBuffer(content.length()+1000);
+				s= new StringBuilder(content.length() + 1000);
 				s.append(content);
 				break;
 			case FORMAT_SOURCE_INPUT:
@@ -122,13 +122,13 @@
 				if (matcher.find()) {
 					content= matcher.replaceAll("    "); //$NON-NLS-1$
 				}
-				s= new StringBuffer(content.length()+1000);
+				s= new StringBuilder(content.length() + 1000);
 				s.append("<pre>"); //$NON-NLS-1$
 				s.append(content);
 				s.append("</pre>"); //$NON-NLS-1$
 				break;
 			case FORMAT_HTMLBODY_INPUT:
-				s= new StringBuffer(content.length()+1000);
+				s= new StringBuilder(content.length() + 1000);
 				s.append(content);
 				break;
 			default:
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 60bb4f8..1d592bd 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
@@ -24,8 +24,6 @@
 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;
@@ -59,7 +57,6 @@
 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;
@@ -146,20 +143,6 @@
 	
 /*- 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.
 	 * 
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceEditorViewer.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceEditorViewer.java
index 952b7f2..50f88cb 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceEditorViewer.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceEditorViewer.java
@@ -34,6 +34,9 @@
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.widgets.Composite;
 
+import org.eclipse.statet.jcommons.lang.NonNull;
+import org.eclipse.statet.jcommons.lang.Nullable;
+
 import org.eclipse.statet.ecommons.text.core.util.NonDeletingPositionUpdater;
 
 
@@ -199,7 +202,7 @@
 		super.unconfigure();
 	}
 	
-	public String[] getDefaultPrefixes(final String contentType) {
+	public @NonNull String @Nullable [] getDefaultPrefixes(final String contentType) {
 		return (this.fDefaultPrefixChars != null) ?
 				(String[]) this.fDefaultPrefixChars.get(contentType) :
 				null;
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceEditorViewerConfigurator.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceEditorViewerConfigurator.java
index 23c41bf..2422d87 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceEditorViewerConfigurator.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceEditorViewerConfigurator.java
@@ -34,7 +34,6 @@
 import org.eclipse.swt.events.DisposeListener;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.ui.texteditor.AbstractDecoratedTextEditor;
-import org.eclipse.ui.texteditor.ITextEditor;
 import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
 import org.eclipse.ui.texteditor.spelling.SpellingProblem;
 
@@ -239,9 +238,7 @@
 		final var sourceEditor= nonNullAssert(this.sourceEditor);
 		
 		if (this.updateCompleteConfig) {
-			if (sourceEditor instanceof ITextEditor) {
-				SpellingProblem.removeAllInActiveEditor((ITextEditor)sourceEditor, null);
-			}
+			SpellingProblem.removeAll(sourceEditor.getViewer(), null);
 			reconfigureSourceViewer(sourceEditor.getViewer());
 		}
 		else {
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/ToggleCommentHandler.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/ToggleCommentHandler.java
index 819e2a3..c05f2aa 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/ToggleCommentHandler.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/ToggleCommentHandler.java
@@ -14,6 +14,8 @@
 
 package org.eclipse.statet.ltk.ui.sourceediting.actions;
 
+import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
+
 import java.util.IdentityHashMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -35,7 +37,6 @@
 import org.eclipse.jface.text.ITextOperationTarget;
 import org.eclipse.jface.text.ITextSelection;
 import org.eclipse.jface.text.ITypedRegion;
-import org.eclipse.jface.text.TextUtilities;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.swt.custom.BusyIndicator;
 import org.eclipse.swt.widgets.Display;
@@ -47,6 +48,13 @@
 import org.eclipse.ui.statushandlers.StatusManager;
 import org.eclipse.ui.texteditor.IEditorStatusLine;
 
+import org.eclipse.statet.jcommons.collections.ImCollections;
+import org.eclipse.statet.jcommons.collections.ImList;
+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.util.StringUtils;
+
 import org.eclipse.statet.ecommons.ui.SharedUIResources;
 
 import org.eclipse.statet.internal.ltk.ui.EditingMessages;
@@ -55,6 +63,7 @@
 import org.eclipse.statet.ltk.ui.sourceediting.SourceEditorViewer;
 
 
+@NonNullByDefault
 public class ToggleCommentHandler extends AbstractHandler {
 	
 	
@@ -76,9 +85,9 @@
 	private final SourceEditor1 editor;
 	
 	/** The text operation target */
-	private ITextOperationTarget operationTarget;
+	private @Nullable ITextOperationTarget operationTarget;
 	
-	private final Map<String, String[]> contentTypePrefixes= new IdentityHashMap<>();
+	private final Map<String, ImList<String>> contentTypePrefixes= new IdentityHashMap<>();
 	
 	
 	public ToggleCommentHandler(final SourceEditor1 editor) {
@@ -93,34 +102,39 @@
 	}
 	
 	@Override
-	public void setEnabled(final Object evaluationContext) {
+	public void setEnabled(final @Nullable Object evaluationContext) {
 		if (this.editor.getViewer() instanceof SourceEditorViewer
 				&& !this.editor.isEditorInputModifiable()) {
 			setBaseEnabled(false);
 			return;
 		}
 		
-		if (this.operationTarget == null) {
-			this.operationTarget= this.editor.getAdapter(ITextOperationTarget.class);
+		var operationTarget= this.operationTarget;
+		if (operationTarget == null) {
+			operationTarget= this.editor.getAdapter(ITextOperationTarget.class);
+			this.operationTarget= operationTarget;
 		}
-		setBaseEnabled(this.operationTarget != null
-				&& this.operationTarget.canDoOperation(ITextOperationTarget.PREFIX)
-				&& this.operationTarget.canDoOperation(ITextOperationTarget.STRIP_PREFIX) );
+		setBaseEnabled(operationTarget != null
+				&& operationTarget.canDoOperation(ITextOperationTarget.PREFIX)
+				&& operationTarget.canDoOperation(ITextOperationTarget.STRIP_PREFIX) );
 	}
 	
-	private ITextSelection getSelection() {
+	private @Nullable ITextSelection getSelection() {
 		final ISelection selection= this.editor.getSelectionProvider().getSelection();
 		return (selection instanceof ITextSelection) ? (ITextSelection) selection : null;
 	}
 	
 	@Override
-	public Object execute(final ExecutionEvent event) throws ExecutionException {
+	public @Nullable Object execute(final ExecutionEvent event) throws ExecutionException {
 		if (!this.editor.validateEditorInputState() || !isEnabled()) {
 			return null;
 		}
 		
+		final AbstractDocument document= (AbstractDocument)this.editor.getViewer().getDocument();
 		final ITextSelection selection= getSelection();
-		final AbstractDocument document= (AbstractDocument) this.editor.getViewer().getDocument();
+		if (document == null || selection == null) {
+			return null;
+		}
 		final int operationCode= (isSelectionCommented(document, selection)) ?
 				ITextOperationTarget.STRIP_PREFIX : ITextOperationTarget.PREFIX;
 		
@@ -154,41 +168,42 @@
 	}
 	
 	
-	protected String[] getPrefixes(final String contentType) {
-		String[] prefixes= this.contentTypePrefixes.get(contentType);
+	protected ImList<String> getPrefixes(final String contentType) {
+		ImList<String> prefixes= this.contentTypePrefixes.get(contentType);
 		if (prefixes == null) {
-			prefixes= ((SourceEditorViewer) this.editor.getViewer()).getDefaultPrefixes(contentType);
-			if (prefixes == null) {
-				prefixes= new String[0];
-			}
-			else {
+			@NonNull String[] array= ((SourceEditorViewer)this.editor.getViewer()).getDefaultPrefixes(contentType);
+			if (array != null) {
 				int numEmpty= 0;
-				for (int i= 0; i < prefixes.length; i++) {
-					if (prefixes[i].isEmpty()) {
+				for (int i= 0; i < array.length; i++) {
+					if (array[i].isEmpty()) {
 						numEmpty++;
 					}
 				}
 				if (numEmpty > 0) {
-					final String[] nonemptyPrefixes= new String[prefixes.length - numEmpty];
-					for (int i= 0, j= 0; i < prefixes.length; i++) {
-						final String prefix= prefixes[i];
+					final var nonemptyPrefixes= new @NonNull String[array.length - numEmpty];
+					for (int i= 0, j= 0; i < array.length; i++) {
+						final String prefix= array[i];
 						if (!prefix.isEmpty()) {
 							nonemptyPrefixes[j++]= prefix;
 						}
 					}
-					prefixes= nonemptyPrefixes;
+					array= nonemptyPrefixes;
 				}
+				prefixes= ImCollections.newList(array);
+			}
+			else {
+				prefixes= ImCollections.emptyList();
 			}
 			this.contentTypePrefixes.put(contentType, prefixes);
 		}
 		return prefixes;
 	}
 	
-	protected Pattern getPrefixPattern(final String contentType, final String prefix) {
+	protected @Nullable Pattern getPrefixPattern(final String contentType, final String prefix) {
 		return getDefaultPrefixPattern(prefix);
 	}
 	
-	protected Pattern getPostfixPattern(final String contentType, final String prefix) {
+	protected @Nullable Pattern getPostfixPattern(final String contentType, final String prefix) {
 		return null;
 	}
 	
@@ -207,7 +222,7 @@
 		try {
 			final IRegion block= EditorUtils.getTextBlockFromSelection(document,
 					selection.getOffset(), selection.getLength() );
-			final ITypedRegion[] regions= document.computePartitioning(
+			final @NonNull ITypedRegion[] regions= document.computePartitioning(
 					this.editor.getDocumentContentInfo().getPartitioning(),
 					block.getOffset(), block.getLength(), false );
 			
@@ -226,8 +241,8 @@
 			
 			// Perform the check
 			for (int i= 0, j= 0; i < regions.length; i++, j+= 2) {
-				final String[] prefixes= getPrefixes(regions[i].getType());
-				if (prefixes != null && prefixes.length > 0 && lines[j] >= 0 && lines[j + 1] >= 0) {
+				final var prefixes= getPrefixes(regions[i].getType());
+				if (prefixes != null && !prefixes.isEmpty() && lines[j] >= 0 && lines[j + 1] >= 0) {
 					if (!isBlockCommented(lines[j], lines[j + 1], prefixes, document)) {
 						return false;
 					}
@@ -253,8 +268,8 @@
 	 *     of the <code>prefixes</code>, ignoring whitespace at the
 	 *     begin of line
 	 */
-	private boolean isBlockCommented(final int startLine, final int endLine, final String[] prefixes,
-			final IDocument document) {
+	private boolean isBlockCommented(final int startLine, final int endLine,
+			final ImList<String> prefixes, final IDocument document) {
 		try {
 			// check for occurrences of prefixes in the given lines
 			for (int i= startLine; i <= endLine; i++) {
@@ -262,16 +277,10 @@
 				final IRegion lineInfo= document.getLineInformation(i);
 				final String text= document.get(lineInfo.getOffset(), lineInfo.getLength());
 				
-				final int[] found= TextUtilities.indexOf(prefixes, text, 0);
+				final int index= StringUtils.firstIndexOfAny(text, prefixes);
 				
-				if (found[0] == -1) {
-					// found a line which is not commented
-					return false;
-				}
-				
-				final String beforePrefix= text.substring(0, found[0]);
-				if (beforePrefix.trim().length() != 0) {
-					// found a line which is not commented
+				if (index == -1 // found a line which is not commented
+						|| !StringUtils.isTrimEmpty(text, 0, index) ) {
 					return false;
 				}
 			}
@@ -307,7 +316,7 @@
 			throws BadLocationException, BadPartitioningException {
 		final int startLine= document.getLineOfOffset(region.getOffset());
 		final int stopLine= (region.getLength() > 0) ?
-				document.getLineOfOffset(region.getOffset()+region.getLength()-1) :
+				document.getLineOfOffset(region.getOffset() + region.getLength() - 1) :
 				startLine;
 		
 		final MultiTextEdit multi= new MultiTextEdit(region.getOffset(), region.getLength());
@@ -331,7 +340,7 @@
 			throws BadLocationException, BadPartitioningException {
 		final int startLine= document.getLineOfOffset(region.getOffset());
 		final int stopLine= (region.getLength() > 0) ?
-				document.getLineOfOffset(region.getOffset()+region.getLength()-1) :
+				document.getLineOfOffset(region.getOffset() + region.getLength() - 1) :
 				startLine;
 		
 		final MultiTextEdit multi= new MultiTextEdit(region.getOffset(), region.getLength());
@@ -356,7 +365,7 @@
 			throws BadLocationException, BadPartitioningException {
 		final int startLine= document.getLineOfOffset(region.getOffset());
 		final int stopLine= (region.getLength() > 0) ?
-				document.getLineOfOffset(region.getOffset()+region.getLength()-1) :
+				document.getLineOfOffset(region.getOffset() + region.getLength() - 1) :
 				startLine;
 		
 		final MultiTextEdit multi= new MultiTextEdit(region.getOffset(), region.getLength());
@@ -366,12 +375,12 @@
 					this.editor.getDocumentContentInfo().getPartitioning(),
 					lineInfo.getOffset(), false );
 			
-			final String[] prefixes= getPrefixes(contentType);
+			final var prefixes= getPrefixes(contentType);
 			final String text= document.get(lineInfo.getOffset(), lineInfo.getLength());
-			final int[] found= TextUtilities.indexOf(prefixes, text, 0);
-			assert (found[0] >= 0);
+			final StringUtils.Match prefix= nonNullAssert(
+					StringUtils.firstMatchOfAny(text, prefixes) );
 			
-			{	final Pattern pattern= getPrefixPattern(contentType, prefixes[found[1]]);
+			{	final Pattern pattern= getPrefixPattern(contentType, prefix.getString());
 				if (pattern != null) {
 					final Matcher matcher= pattern.matcher(text);
 					matcher.reset(text);
@@ -383,11 +392,11 @@
 				}
 				else {
 					multi.addChild(new DeleteEdit(
-							lineInfo.getOffset() + found[0],
-							prefixes[found[1]].length() ));
+							lineInfo.getOffset() + prefix.getStartIndex(),
+							prefix.getLength() ));
 				}
 			}
-			{	final Pattern pattern= getPostfixPattern(contentType, prefixes[found[1]]);
+			{	final Pattern pattern= getPostfixPattern(contentType, prefix.getString());
 				if (pattern != null) {
 					final Matcher matcher= pattern.matcher(text);
 					if (matcher.find()) {
@@ -413,7 +422,9 @@
 	
 	protected void signalError() {
 		final IEditorStatusLine statusLine= this.editor.getAdapter(IEditorStatusLine.class);
-		statusLine.setMessage(true, EditingMessages.ToggleCommentAction_error, null);
+		if (statusLine != null) {
+			statusLine.setMessage(true, EditingMessages.ToggleCommentAction_error, null);
+		}
 		this.editor.getViewer().getTextWidget().getDisplay().beep();
 	}
 	
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/ToggleShowWhitespaceHandler.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/ToggleShowWhitespaceHandler.java
index 750cfc7..ab5de45 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/ToggleShowWhitespaceHandler.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/ToggleShowWhitespaceHandler.java
@@ -24,14 +24,14 @@
 import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
 
 import org.eclipse.statet.ecommons.preferences.core.Preference;
-import org.eclipse.statet.ecommons.ui.actions.TogglePreferenceEnablementHandler;
+import org.eclipse.statet.ecommons.ui.actions.ToggleBooleanPreferenceHandler;
 import org.eclipse.statet.ecommons.ui.util.UIAccess;
 
 
 /**
  * ITextEditorActionDefinitionIds#SHOW_WHITESPACE_CHARACTERS
  */
-public class ToggleShowWhitespaceHandler extends TogglePreferenceEnablementHandler {
+public class ToggleShowWhitespaceHandler extends ToggleBooleanPreferenceHandler {
 	
 	
 	private final SourceViewer viewer;
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/ToggleSoftWordWrapHandler.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/ToggleSoftWordWrapHandler.java
index ee1cccc..c14ad05 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/ToggleSoftWordWrapHandler.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/ToggleSoftWordWrapHandler.java
@@ -18,14 +18,14 @@
 import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
 
 import org.eclipse.statet.ecommons.preferences.core.Preference;
-import org.eclipse.statet.ecommons.ui.actions.TogglePreferenceEnablementHandler;
+import org.eclipse.statet.ecommons.ui.actions.ToggleBooleanPreferenceHandler;
 import org.eclipse.statet.ecommons.ui.util.UIAccess;
 
 
 /**
  * ITextEditorActionDefinitionIds#WORD_WRAP
  */
-public class ToggleSoftWordWrapHandler extends TogglePreferenceEnablementHandler {
+public class ToggleSoftWordWrapHandler extends ToggleBooleanPreferenceHandler {
 	
 	
 	private final SourceViewer viewer;
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/CombinedHover.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/CombinedHover.java
index 17e8930..08bde9c 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/CombinedHover.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/CombinedHover.java
@@ -14,6 +14,8 @@
 
 package org.eclipse.statet.ltk.ui.sourceediting.assist;
 
+import static org.eclipse.statet.jcommons.status.Status.CANCEL_STATUS;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -23,7 +25,6 @@
 import org.eclipse.statet.jcommons.lang.Nullable;
 import org.eclipse.statet.jcommons.status.ProgressMonitor;
 import org.eclipse.statet.jcommons.status.StatusException;
-import org.eclipse.statet.jcommons.status.Statuses;
 
 
 /**
@@ -66,7 +67,7 @@
 		for (int i= 0; i < descriptors.size(); i++) {
 			m.setWorkRemaining(descriptors.size() - i);
 			if (m.isCanceled()) {
-				throw new StatusException(Statuses.CANCEL_STATUS);
+				throw new StatusException(CANCEL_STATUS);
 			}
 			
 			if (i == instantiatedHovers.size()) {
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/templates/SourceEditorContextType.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/templates/SourceEditorContextType.java
index ceb31b3..3638d33 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/templates/SourceEditorContextType.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/templates/SourceEditorContextType.java
@@ -36,8 +36,11 @@
 import org.eclipse.text.edits.ReplaceEdit;
 import org.eclipse.text.edits.TextEdit;
 
+import org.eclipse.statet.jcommons.collections.ImCollections;
+import org.eclipse.statet.jcommons.collections.ImList;
 import org.eclipse.statet.jcommons.lang.NonNullByDefault;
 import org.eclipse.statet.jcommons.lang.Nullable;
+import org.eclipse.statet.jcommons.util.StringUtils;
 
 import org.eclipse.statet.internal.ltk.ui.TemplatesMessages;
 import org.eclipse.statet.ltk.core.ElementName;
@@ -283,8 +286,8 @@
 			resolver.resolve(variable, context);
 			
 			final String value= variable.getDefaultValue();
-			final String[] ln= document.getLegalLineDelimiters();
-			final boolean multiLine= (TextUtilities.indexOf(ln, value, 0)[0] != -1);
+			final ImList<String> lineDelimiters= ImCollections.newList(document.getLegalLineDelimiters());
+			final boolean multiLine= StringUtils.containsAny(value, lineDelimiters);
 			
 			if (!oldValue.equals(value)) {
 				// update buffer to reflect new value
@@ -296,11 +299,12 @@
 							final StringBuilder temp= new StringBuilder(thisValue);
 							int offset= 0;
 							while (true) {
-								final int[] search= TextUtilities.indexOf(ln, temp.toString(), offset);
-								if (search[0] == -1) {
+								final StringUtils.Match delimiter= StringUtils.firstMatchOfAny(temp,
+										lineDelimiters, offset );
+								if (delimiter == null) {
 									break;
 								}
-								offset= search[0] + ln[search[1]].length();
+								offset= delimiter.getEndIndex();
 								temp.insert(offset, indent);
 								offset+= indent.length();
 							}
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 0d75221..391133f 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
@@ -32,9 +32,11 @@
 import org.eclipse.text.edits.MultiTextEdit;
 import org.eclipse.text.edits.TextEdit;
 
+import org.eclipse.statet.jcommons.collections.ImCollections;
 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.jcommons.util.StringUtils;
 
 import org.eclipse.statet.ecommons.text.TextUtil;
 
@@ -98,13 +100,13 @@
 			return null;
 		}
 		
-		final String ln= TextUtilities.getDefaultLineDelimiter(getDocument());
+		final String lineDelimiter= TextUtilities.getDefaultLineDelimiter(getDocument());
 		final TemplateTranslator translator= new TemplateTranslator();
 		String pattern= template.getPattern();
 		// correct line delimiter
 		final Matcher matcher= TextUtil.LINE_DELIMITER_PATTERN.matcher(pattern);
 		if (matcher.find()) {
-			pattern= matcher.replaceAll(ln);
+			pattern= matcher.replaceAll(lineDelimiter);
 		}
 		
 		// default, see super
@@ -113,8 +115,9 @@
 		
 		format(buffer);
 		final String selection= getVariable(SELECTION_VAR_NAME);
-		if (selection != null && TextUtilities.indexOf(getDocument().getLegalLineDelimiters(), selection, 0)[0] != -1) {
-			buffer.setContent(buffer.getString() + ln, buffer.getVariables());
+		if (selection != null && StringUtils.containsAny(selection,
+				ImCollections.newList(getDocument().getLegalLineDelimiters()) )) {
+			buffer.setContent(buffer.getString() + lineDelimiter, buffer.getVariables());
 		}
 		
 		return buffer;
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/util/LTKWorkbenchUIUtil.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/util/LTKWorkbenchUIUtil.java
index acdeab6..af8a28f 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/util/LTKWorkbenchUIUtil.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/util/LTKWorkbenchUIUtil.java
@@ -31,6 +31,7 @@
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IFileEditorInput;
 import org.eclipse.ui.IPathEditorInput;
 import org.eclipse.ui.IURIEditorInput;
 import org.eclipse.ui.IWorkbenchPage;
@@ -104,6 +105,13 @@
 	}
 	
 	
+	public static @Nullable IFile getFile(final @Nullable IEditorInput input) {
+		if (input instanceof IFileEditorInput) {
+			return ((IFileEditorInput)input).getFile();
+		}
+		return null;
+	}
+	
 	public static void openEditor(final IWorkbenchPage page, final IFile file,
 			final @Nullable IRegion initialSelection) {
 		final Display display= page.getWorkbenchWindow().getShell().getDisplay();