519262: copy org.eclipse.ui.internal.misc.StringMatcher
The find(String, int, int) was removed in Photon. In order to retain
compatibility with previous versions and also work on Photon, we'll keep
a copy of the old version.
Change-Id: I1682f7e94e2b730fbec408809b5fc99ae8db1e9d
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=519262
diff --git a/org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/commons/workbench/DecoratingPatternStyledCellLabelProvider.java b/org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/commons/workbench/DecoratingPatternStyledCellLabelProvider.java
index c766793..28b2d05 100644
--- a/org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/commons/workbench/DecoratingPatternStyledCellLabelProvider.java
+++ b/org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/commons/workbench/DecoratingPatternStyledCellLabelProvider.java
@@ -26,6 +26,8 @@
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.jface.viewers.StyledString.Styler;
import org.eclipse.jface.viewers.ViewerColumn;
+import org.eclipse.mylyn.internal.commons.workbench.StringMatcher;
+import org.eclipse.mylyn.internal.commons.workbench.StringMatcher.Position;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.graphics.Color;
@@ -33,19 +35,17 @@
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.internal.misc.StringMatcher;
-import org.eclipse.ui.internal.misc.StringMatcher.Position;
/**
* A decorating styled label provider that supports highlighting of substrings that match a pattern. Based on
* {@link DecoratingFileSearchLabelProvider}.
- *
+ *
* @author Kevin Sawicki
* @see DecoratingFileSearchLabelProvider
* @since 3.7
*/
-public class DecoratingPatternStyledCellLabelProvider extends DecoratingStyledCellLabelProvider implements
- IPropertyChangeListener, ILabelProvider {
+public class DecoratingPatternStyledCellLabelProvider extends DecoratingStyledCellLabelProvider
+ implements IPropertyChangeListener, ILabelProvider {
/**
* Color to use to decorate matches.
@@ -54,8 +54,8 @@
static final Styler HIGHLIGHT_STYLE = StyledString.createColorRegistryStyler(null, HIGHLIGHT_BG_COLOR_NAME);
- private static class PatternStyledLabelProvider extends StyledCellLabelProvider implements IStyledLabelProvider,
- IColorProvider, IFontProvider {
+ private static class PatternStyledLabelProvider extends StyledCellLabelProvider
+ implements IStyledLabelProvider, IColorProvider, IFontProvider {
private final ILabelProvider labelProvider;
@@ -67,7 +67,7 @@
/**
* Set the pattern to highlight
- *
+ *
* @param pattern
*/
public void setPattern(String pattern) {
@@ -134,7 +134,7 @@
/**
* Create a new repository search styled label provider that wraps an {@link ILabelProvider}
- *
+ *
* @param labelProvider
* @param decorator
* @param decorationContext
@@ -154,15 +154,15 @@
PlatformUI.getPreferenceStore().addPropertyChangeListener(this);
JFaceResources.getColorRegistry().addListener(this);
- setOwnerDrawEnabled(PlatformUI.getPreferenceStore()
- .getBoolean(IWorkbenchPreferenceConstants.USE_COLORED_LABELS));
+ setOwnerDrawEnabled(
+ PlatformUI.getPreferenceStore().getBoolean(IWorkbenchPreferenceConstants.USE_COLORED_LABELS));
super.initialize(viewer, column);
}
/**
* Get underyling label provider
- *
+ *
* @return label provider
*/
public ILabelProvider getLabelProvider() {
@@ -182,7 +182,7 @@
/**
* Set the pattern to highlight
- *
+ *
* @param pattern
*/
public void setPattern(String pattern) {
@@ -195,8 +195,8 @@
protected void refresh() {
ColumnViewer viewer = getViewer();
if (viewer != null) {
- boolean coloredLabels = PlatformUI.getPreferenceStore().getBoolean(
- IWorkbenchPreferenceConstants.USE_COLORED_LABELS);
+ boolean coloredLabels = PlatformUI.getPreferenceStore()
+ .getBoolean(IWorkbenchPreferenceConstants.USE_COLORED_LABELS);
if (coloredLabels || coloredLabels != isOwnerDrawEnabled()) {
setOwnerDrawEnabled(coloredLabels);
viewer.refresh();
@@ -228,7 +228,7 @@
/**
* Get text of element from underyling label provider
- *
+ *
* @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
*/
public String getText(Object element) {
@@ -237,7 +237,7 @@
/**
* Override preparation of style range to add border dot about highlight regions that don't have colors applied
- *
+ *
* @see org.eclipse.jface.viewers.StyledCellLabelProvider#prepareStyleRange(org.eclipse.swt.custom.StyleRange,
* boolean)
*/
diff --git a/org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/internal/commons/workbench/StringMatcher.java b/org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/internal/commons/workbench/StringMatcher.java
new file mode 100644
index 0000000..6bcf2e2
--- /dev/null
+++ b/org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/internal/commons/workbench/StringMatcher.java
@@ -0,0 +1,454 @@
+package org.eclipse.mylyn.internal.commons.workbench;
+
+import java.util.Vector;
+
+/**
+ * A string pattern matcher, suppporting "*" and "?" wildcards. Copied from org.eclipse.ui.internal.misc.StringMatcher.
+ */
+public class StringMatcher {
+ protected String fPattern;
+
+ protected int fLength; // pattern length
+
+ protected boolean fIgnoreWildCards;
+
+ protected boolean fIgnoreCase;
+
+ protected boolean fHasLeadingStar;
+
+ protected boolean fHasTrailingStar;
+
+ protected String fSegments[]; //the given pattern is split into * separated segments
+
+ /* boundary value beyond which we don't need to search in the text */
+ protected int fBound = 0;
+
+ protected static final char fSingleWildCard = '\u0000';
+
+ public static class Position {
+ int start; //inclusive
+
+ int end; //exclusive
+
+ public Position(int start, int end) {
+ this.start = start;
+ this.end = end;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+ public int getEnd() {
+ return end;
+ }
+ }
+
+ /**
+ * StringMatcher constructor takes in a String object that is a simple pattern which may contain '*' for 0 and many
+ * characters and '?' for exactly one character. Literal '*' and '?' characters must be escaped in the pattern e.g.,
+ * "\*" means literal "*", etc. Escaping any other character (including the escape character itself), just results
+ * in that character in the pattern. e.g., "\a" means "a" and "\\" means "\" If invoking the StringMatcher with
+ * string literals in Java, don't forget escape characters are represented by "\\".
+ *
+ * @param pattern
+ * the pattern to match text against
+ * @param ignoreCase
+ * if true, case is ignored
+ * @param ignoreWildCards
+ * if true, wild cards and their escape sequences are ignored (everything is taken literally).
+ */
+ public StringMatcher(String pattern, boolean ignoreCase, boolean ignoreWildCards) {
+ if (pattern == null) {
+ throw new IllegalArgumentException();
+ }
+ fIgnoreCase = ignoreCase;
+ fIgnoreWildCards = ignoreWildCards;
+ fPattern = pattern;
+ fLength = pattern.length();
+
+ if (fIgnoreWildCards) {
+ parseNoWildCards();
+ } else {
+ parseWildCards();
+ }
+ }
+
+ /**
+ * Find the first occurrence of the pattern between <code>start</code)(inclusive)
+ * and <code>end</code>(exclusive).
+ *
+ * @param text
+ * the String object to search in
+ * @param start
+ * the starting index of the search range, inclusive
+ * @param end
+ * the ending index of the search range, exclusive
+ * @return an <code>StringMatcher.Position</code> object that keeps the starting (inclusive) and ending positions
+ * (exclusive) of the first occurrence of the pattern in the specified range of the text; return null if not
+ * found or subtext is empty (start==end). A pair of zeros is returned if pattern is empty string Note that
+ * for pattern like "*abc*" with leading and trailing stars, position of "abc" is returned. For a pattern
+ * like"*??*" in text "abcdf", (1,3) is returned
+ */
+ public StringMatcher.Position find(String text, int start, int end) {
+ if (text == null) {
+ throw new IllegalArgumentException();
+ }
+
+ int tlen = text.length();
+ if (start < 0) {
+ start = 0;
+ }
+ if (end > tlen) {
+ end = tlen;
+ }
+ if (end < 0 || start >= end) {
+ return null;
+ }
+ if (fLength == 0) {
+ return new Position(start, start);
+ }
+ if (fIgnoreWildCards) {
+ int x = posIn(text, start, end);
+ if (x < 0) {
+ return null;
+ }
+ return new Position(x, x + fLength);
+ }
+
+ int segCount = fSegments.length;
+ if (segCount == 0) {
+ return new Position(start, end);
+ }
+
+ int curPos = start;
+ int matchStart = -1;
+ int i;
+ for (i = 0; i < segCount && curPos < end; ++i) {
+ String current = fSegments[i];
+ int nextMatch = regExpPosIn(text, curPos, end, current);
+ if (nextMatch < 0) {
+ return null;
+ }
+ if (i == 0) {
+ matchStart = nextMatch;
+ }
+ curPos = nextMatch + current.length();
+ }
+ if (i < segCount) {
+ return null;
+ }
+ return new Position(matchStart, curPos);
+ }
+
+ /**
+ * match the given <code>text</code> with the pattern
+ *
+ * @return true if matched otherwise false
+ * @param text
+ * a String object
+ */
+ public boolean match(String text) {
+ if (text == null) {
+ return false;
+ }
+ return match(text, 0, text.length());
+ }
+
+ /**
+ * Given the starting (inclusive) and the ending (exclusive) positions in the <code>text</code>, determine if the
+ * given substring matches with aPattern
+ *
+ * @return true if the specified portion of the text matches the pattern
+ * @param text
+ * a String object that contains the substring to match
+ * @param start
+ * marks the starting position (inclusive) of the substring
+ * @param end
+ * marks the ending index (exclusive) of the substring
+ */
+ public boolean match(String text, int start, int end) {
+ if (null == text) {
+ throw new IllegalArgumentException();
+ }
+
+ if (start > end) {
+ return false;
+ }
+
+ if (fIgnoreWildCards) {
+ return (end - start == fLength) && fPattern.regionMatches(fIgnoreCase, 0, text, start, fLength);
+ }
+ int segCount = fSegments.length;
+ if (segCount == 0 && (fHasLeadingStar || fHasTrailingStar)) {
+ return true;
+ }
+ if (start == end) {
+ return fLength == 0;
+ }
+ if (fLength == 0) {
+ return start == end;
+ }
+
+ int tlen = text.length();
+ if (start < 0) {
+ start = 0;
+ }
+ if (end > tlen) {
+ end = tlen;
+ }
+
+ int tCurPos = start;
+ int bound = end - fBound;
+ if (bound < 0) {
+ return false;
+ }
+ int i = 0;
+ String current = fSegments[i];
+ int segLength = current.length();
+
+ /* process first segment */
+ if (!fHasLeadingStar) {
+ if (!regExpRegionMatches(text, start, current, 0, segLength)) {
+ return false;
+ } else {
+ ++i;
+ tCurPos = tCurPos + segLength;
+ }
+ }
+ if ((fSegments.length == 1) && (!fHasLeadingStar) && (!fHasTrailingStar)) {
+ // only one segment to match, no wildcards specified
+ return tCurPos == end;
+ }
+ /* process middle segments */
+ while (i < segCount) {
+ current = fSegments[i];
+ int currentMatch;
+ int k = current.indexOf(fSingleWildCard);
+ if (k < 0) {
+ currentMatch = textPosIn(text, tCurPos, end, current);
+ if (currentMatch < 0) {
+ return false;
+ }
+ } else {
+ currentMatch = regExpPosIn(text, tCurPos, end, current);
+ if (currentMatch < 0) {
+ return false;
+ }
+ }
+ tCurPos = currentMatch + current.length();
+ i++;
+ }
+
+ /* process final segment */
+ if (!fHasTrailingStar && tCurPos != end) {
+ int clen = current.length();
+ return regExpRegionMatches(text, end - clen, current, 0, clen);
+ }
+ return i == segCount;
+ }
+
+ /**
+ * This method parses the given pattern into segments seperated by wildcard '*' characters. Since wildcards are not
+ * being used in this case, the pattern consists of a single segment.
+ */
+ private void parseNoWildCards() {
+ fSegments = new String[1];
+ fSegments[0] = fPattern;
+ fBound = fLength;
+ }
+
+ /**
+ * Parses the given pattern into segments seperated by wildcard '*' characters.
+ *
+ * @param p,
+ * a String object that is a simple regular expression with '*' and/or '?'
+ */
+ private void parseWildCards() {
+ if (fPattern.startsWith("*")) { //$NON-NLS-1$
+ fHasLeadingStar = true;
+ }
+ if (fPattern.endsWith("*")) {//$NON-NLS-1$
+ /* make sure it's not an escaped wildcard */
+ if (fLength > 1 && fPattern.charAt(fLength - 2) != '\\') {
+ fHasTrailingStar = true;
+ }
+ }
+
+ Vector temp = new Vector();
+
+ int pos = 0;
+ StringBuffer buf = new StringBuffer();
+ while (pos < fLength) {
+ char c = fPattern.charAt(pos++);
+ switch (c) {
+ case '\\':
+ if (pos >= fLength) {
+ buf.append(c);
+ } else {
+ char next = fPattern.charAt(pos++);
+ /* if it's an escape sequence */
+ if (next == '*' || next == '?' || next == '\\') {
+ buf.append(next);
+ } else {
+ /* not an escape sequence, just insert literally */
+ buf.append(c);
+ buf.append(next);
+ }
+ }
+ break;
+ case '*':
+ if (buf.length() > 0) {
+ /* new segment */
+ temp.addElement(buf.toString());
+ fBound += buf.length();
+ buf.setLength(0);
+ }
+ break;
+ case '?':
+ /* append special character representing single match wildcard */
+ buf.append(fSingleWildCard);
+ break;
+ default:
+ buf.append(c);
+ }
+ }
+
+ /* add last buffer to segment list */
+ if (buf.length() > 0) {
+ temp.addElement(buf.toString());
+ fBound += buf.length();
+ }
+
+ fSegments = new String[temp.size()];
+ temp.copyInto(fSegments);
+ }
+
+ /**
+ * @param text
+ * a string which contains no wildcard
+ * @param start
+ * the starting index in the text for search, inclusive
+ * @param end
+ * the stopping point of search, exclusive
+ * @return the starting index in the text of the pattern , or -1 if not found
+ */
+ protected int posIn(String text, int start, int end) {//no wild card in pattern
+ int max = end - fLength;
+
+ if (!fIgnoreCase) {
+ int i = text.indexOf(fPattern, start);
+ if (i == -1 || i > max) {
+ return -1;
+ }
+ return i;
+ }
+
+ for (int i = start; i <= max; ++i) {
+ if (text.regionMatches(true, i, fPattern, 0, fLength)) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * @param text
+ * a simple regular expression that may only contain '?'(s)
+ * @param start
+ * the starting index in the text for search, inclusive
+ * @param end
+ * the stopping point of search, exclusive
+ * @param p
+ * a simple regular expression that may contains '?'
+ * @return the starting index in the text of the pattern , or -1 if not found
+ */
+ protected int regExpPosIn(String text, int start, int end, String p) {
+ int plen = p.length();
+
+ int max = end - plen;
+ for (int i = start; i <= max; ++i) {
+ if (regExpRegionMatches(text, i, p, 0, plen)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * @return boolean
+ * @param text
+ * a String to match
+ * @param start
+ * int that indicates the starting index of match, inclusive
+ * @param end</code>
+ * int that indicates the ending index of match, exclusive
+ * @param p
+ * String, String, a simple regular expression that may contain '?'
+ * @param ignoreCase
+ * boolean indicating wether code>p</code> is case sensitive
+ */
+ protected boolean regExpRegionMatches(String text, int tStart, String p, int pStart, int plen) {
+ while (plen-- > 0) {
+ char tchar = text.charAt(tStart++);
+ char pchar = p.charAt(pStart++);
+
+ /* process wild cards */
+ if (!fIgnoreWildCards) {
+ /* skip single wild cards */
+ if (pchar == fSingleWildCard) {
+ continue;
+ }
+ }
+ if (pchar == tchar) {
+ continue;
+ }
+ if (fIgnoreCase) {
+ if (Character.toUpperCase(tchar) == Character.toUpperCase(pchar)) {
+ continue;
+ }
+ // comparing after converting to upper case doesn't handle all cases;
+ // also compare after converting to lower case
+ if (Character.toLowerCase(tchar) == Character.toLowerCase(pchar)) {
+ continue;
+ }
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @param text
+ * the string to match
+ * @param start
+ * the starting index in the text for search, inclusive
+ * @param end
+ * the stopping point of search, exclusive
+ * @param p
+ * a pattern string that has no wildcard
+ * @return the starting index in the text of the pattern , or -1 if not found
+ */
+ protected int textPosIn(String text, int start, int end, String p) {
+
+ int plen = p.length();
+ int max = end - plen;
+
+ if (!fIgnoreCase) {
+ int i = text.indexOf(p, start);
+ if (i == -1 || i > max) {
+ return -1;
+ }
+ return i;
+ }
+
+ for (int i = start; i <= max; ++i) {
+ if (text.regionMatches(true, i, p, 0, plen)) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+}