Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/CompareResourceFilter.java')
-rw-r--r--bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/CompareResourceFilter.java399
1 files changed, 399 insertions, 0 deletions
diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/CompareResourceFilter.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/CompareResourceFilter.java
new file mode 100644
index 000000000..0e7090296
--- /dev/null
+++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/CompareResourceFilter.java
@@ -0,0 +1,399 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.compare.internal;
+
+import java.util.StringTokenizer;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IStatus;
+
+import com.ibm.icu.text.MessageFormat;
+
+
+public class CompareResourceFilter {
+ private static final char[][] NO_CHAR_CHAR= new char[0][];
+
+ private char[][] fExtraResourceFileFilters;
+ private String[] fExtraResourceFolderFilters;
+
+
+ public CompareResourceFilter() {
+ // nothing to do
+ }
+
+ /*
+ * Returns true if path matches filter, that is if path should be filtered.
+ */
+ public boolean filter(String path0, boolean folder, boolean isArchive) {
+ if (!folder && fExtraResourceFileFilters != null) {
+ char[] name= path0.toCharArray();
+ for (int i= 0, l= fExtraResourceFileFilters.length; i < l; i++)
+ if (match(fExtraResourceFileFilters[i], name, true))
+ return true;
+ }
+ if (folder && fExtraResourceFolderFilters != null) {
+ for (int i= 0, l= fExtraResourceFolderFilters.length; i < l; i++)
+ if (fExtraResourceFolderFilters[i].equals(path0))
+ return true;
+ }
+ return false;
+ }
+
+ public static String validateResourceFilters(String text) {
+ IWorkspace workspace= ResourcesPlugin.getWorkspace();
+ String[] filters= getTokens(text, ","); //$NON-NLS-1$
+ for (int i= 0; i < filters.length; i++) {
+ String fileName= filters[i].replace('*', 'x');
+ int resourceType= IResource.FILE;
+ int lastCharacter= fileName.length() - 1;
+ if (lastCharacter >= 0 && fileName.charAt(lastCharacter) == '/') {
+ fileName= fileName.substring(0, lastCharacter);
+ resourceType= IResource.FOLDER;
+ }
+ IStatus status= workspace.validateName(fileName, resourceType);
+ if (status.matches(IStatus.ERROR)) {
+ String format= Utilities.getString("ComparePreferencePage.filter.invalidsegment.error"); //$NON-NLS-1$
+ return MessageFormat.format(format, new String[] { status.getMessage() } );
+ }
+ }
+ return null;
+ }
+
+ public void setFilters(String filterSequence) {
+ char[][] filters= filterSequence != null && filterSequence.length() > 0
+ ? splitAndTrimOn(',', filterSequence.toCharArray())
+ : null;
+ if (filters == null) {
+ fExtraResourceFileFilters= null;
+ fExtraResourceFolderFilters= null;
+ } else {
+ int fileCount= 0, folderCount= 0;
+ for (int i= 0, l= filters.length; i < l; i++) {
+ char[] f= filters[i];
+ if (f.length == 0)
+ continue;
+ if (f[f.length - 1] == '/')
+ folderCount++;
+ else
+ fileCount++;
+ }
+ fExtraResourceFileFilters= new char[fileCount][];
+ fExtraResourceFolderFilters= new String[folderCount];
+ for (int i= 0, l= filters.length; i < l; i++) {
+ char[] f= filters[i];
+ if (f.length == 0)
+ continue;
+ if (f[f.length - 1] == '/')
+ fExtraResourceFolderFilters[--folderCount]= new String(subarray(f, 0, f.length - 1));
+ else
+ fExtraResourceFileFilters[--fileCount]= f;
+ }
+ }
+ }
+
+ /////////
+
+ private static String[] getTokens(String text, String separator) {
+ StringTokenizer tok= new StringTokenizer(text, separator);
+ int nTokens= tok.countTokens();
+ String[] res= new String[nTokens];
+ for (int i= 0; i < res.length; i++)
+ res[i]= tok.nextToken().trim();
+ return res;
+ }
+
+ /**
+ * Answers true if the pattern matches the given name, false otherwise.
+ * This char[] pattern matching accepts wild-cards '*' and '?'.
+ *
+ * When not case sensitive, the pattern is assumed to already be
+ * lowercased, the name will be lowercased character per character as
+ * comparing. If name is null, the answer is false. If pattern is null, the
+ * answer is true if name is not null. <br><br>For example:
+ * <ol>
+ * <li>
+ *
+ * <pre>
+ * pattern = { '?', 'b', '*' } name = { 'a', 'b', 'c' , 'd' } isCaseSensitive = true result => true
+ * </pre>
+ *
+ *
+ * </li>
+ * <li>
+ *
+ * <pre>
+ * pattern = { '?', 'b', '?' } name = { 'a', 'b', 'c' , 'd' } isCaseSensitive = true result => false
+ * </pre>
+ *
+ *
+ * </li>
+ * <li>
+ *
+ * <pre>
+ * pattern = { 'b', '*' } name = { 'a', 'b', 'c' , 'd' } isCaseSensitive = true result => false
+ * </pre>
+ *
+ *
+ * </li>
+ * </ol>
+ *
+ * @param pattern
+ * the given pattern
+ * @param name
+ * the given name
+ * @param isCaseSensitive
+ * flag to know whether or not the matching should be case
+ * sensitive
+ * @return true if the pattern matches the given name, false otherwise
+ */
+ private boolean match(char[] pattern, char[] name, boolean isCaseSensitive) {
+ if (name == null)
+ return false; // null name cannot match
+ if (pattern == null)
+ return true; // null pattern is equivalent to '*'
+ return match(pattern, 0, pattern.length, name, 0, name.length, isCaseSensitive);
+ }
+
+ /**
+ * Answers true if the a sub-pattern matches the subpart of the given name,
+ * false otherwise. char[] pattern matching, accepting wild-cards '*' and
+ * '?'. Can match only subset of name/pattern. end positions are
+ * non-inclusive. The subpattern is defined by the patternStart and
+ * pattternEnd positions. When not case sensitive, the pattern is assumed
+ * to already be lowercased, the name will be lowercased character per
+ * character as comparing. <br><br>For example:
+ * <ol>
+ * <li>
+ *
+ * <pre>
+ * pattern = { '?', 'b', '*' } patternStart = 1 patternEnd = 3 name = { 'a', 'b', 'c' , 'd' } nameStart = 1 nameEnd = 4 isCaseSensitive = true result => true
+ * </pre>
+ *
+ *
+ * </li>
+ * <li>
+ *
+ * <pre>
+ * pattern = { '?', 'b', '*' } patternStart = 1 patternEnd = 2 name = { 'a', 'b', 'c' , 'd' } nameStart = 1 nameEnd = 2 isCaseSensitive = true result => false
+ * </pre>
+ *
+ *
+ * </li>
+ * </ol>
+ *
+ * @param pattern
+ * the given pattern
+ * @param patternStart
+ * the given pattern start
+ * @param patternEnd
+ * the given pattern end
+ * @param name
+ * the given name
+ * @param nameStart
+ * the given name start
+ * @param nameEnd
+ * the given name end
+ * @param isCaseSensitive
+ * flag to know if the matching should be case sensitive
+ * @return true if the a sub-pattern matches the subpart of the given name,
+ * false otherwise
+ */
+ private boolean match(char[] pattern, int patternStart, int patternEnd, char[] name, int nameStart, int nameEnd,
+ boolean isCaseSensitive) {
+ if (name == null)
+ return false; // null name cannot match
+ if (pattern == null)
+ return true; // null pattern is equivalent to '*'
+ int iPattern= patternStart;
+ int iName= nameStart;
+ if (patternEnd < 0)
+ patternEnd= pattern.length;
+ if (nameEnd < 0)
+ nameEnd= name.length;
+ /* check first segment */
+ char patternChar= 0;
+ while ((iPattern < patternEnd) && (patternChar= pattern[iPattern]) != '*') {
+ if (iName == nameEnd)
+ return false;
+ if (patternChar != (isCaseSensitive ? name[iName] : Character.toLowerCase(name[iName])) && patternChar != '?') {
+ return false;
+ }
+ iName++;
+ iPattern++;
+ }
+ /* check sequence of star+segment */
+ int segmentStart;
+ if (patternChar == '*') {
+ segmentStart= ++iPattern; // skip star
+ } else {
+ segmentStart= 0; // force iName check
+ }
+ int prefixStart= iName;
+ checkSegment : while (iName < nameEnd) {
+ if (iPattern == patternEnd) {
+ iPattern= segmentStart; // mismatch - restart current segment
+ iName= ++prefixStart;
+ continue checkSegment;
+ }
+ /* segment is ending */
+ if ((patternChar= pattern[iPattern]) == '*') {
+ segmentStart= ++iPattern; // skip start
+ if (segmentStart == patternEnd) {
+ return true;
+ }
+ prefixStart= iName;
+ continue checkSegment;
+ }
+ /* check current name character */
+ if ((isCaseSensitive ? name[iName] : Character.toLowerCase(name[iName])) != patternChar && patternChar != '?') {
+ iPattern= segmentStart; // mismatch - restart current segment
+ iName= ++prefixStart;
+ continue checkSegment;
+ }
+ iName++;
+ iPattern++;
+ }
+ return (segmentStart == patternEnd) || (iName == nameEnd && iPattern == patternEnd)
+ || (iPattern == patternEnd - 1 && pattern[iPattern] == '*');
+ }
+
+ /**
+ * Return a new array which is the split of the given array using the given
+ * divider and triming each subarray to remove whitespaces equals to ' '.
+ * <br><br>For example:
+ * <ol>
+ * <li>
+ *
+ * <pre>
+ * divider = 'b' array = { 'a' , 'b', 'b', 'a', 'b', 'a' } result => { { 'a' }, { }, { 'a' }, { 'a' } }
+ * </pre>
+ *
+ *
+ * </li>
+ * <li>
+ *
+ * <pre>
+ * divider = 'c' array = { 'a' , 'b', 'b', 'a', 'b', 'a' } result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
+ * </pre>
+ *
+ *
+ * </li>
+ * <li>
+ *
+ * <pre>
+ * divider = 'b' array = { 'a' , ' ', 'b', 'b', 'a', 'b', 'a' } result => { { 'a' }, { }, { 'a' }, { 'a' } }
+ * </pre>
+ *
+ *
+ * </li>
+ * <li>
+ *
+ * <pre>
+ * divider = 'c' array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' } result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
+ * </pre>
+ *
+ *
+ * </li>
+ * </ol>
+ *
+ * @param divider
+ * the given divider
+ * @param array
+ * the given array
+ * @return a new array which is the split of the given array using the
+ * given divider and triming each subarray to remove whitespaces
+ * equals to ' '
+ */
+ private char[][] splitAndTrimOn(char divider, char[] array) {
+ int length= array == null ? 0 : array.length;
+ if (length == 0)
+ return NO_CHAR_CHAR;
+ int wordCount= 1;
+ for (int i= 0; i < length; i++)
+ if (array[i] == divider)
+ wordCount++;
+ char[][] split= new char[wordCount][];
+ int last= 0, currentWord= 0;
+ for (int i= 0; i < length; i++) {
+ if (array[i] == divider) {
+ int start= last, end= i - 1;
+ while (start < i && array[start] == ' ')
+ start++;
+ while (end > start && array[end] == ' ')
+ end--;
+ split[currentWord]= new char[end - start + 1];
+ System.arraycopy(array, start, split[currentWord++], 0, end - start + 1);
+ last= i + 1;
+ }
+ }
+ int start= last, end= length - 1;
+ while (start < length && array[start] == ' ')
+ start++;
+ while (end > start && array[end] == ' ')
+ end--;
+ split[currentWord]= new char[end - start + 1];
+ System.arraycopy(array, start, split[currentWord++], 0, end - start + 1);
+ return split;
+ }
+
+ /**
+ * Answers a new array which is a copy of the given array starting at the
+ * given start and ending at the given end. The given start is inclusive
+ * and the given end is exclusive. Answers null if start is greater than
+ * end, if start is lower than 0 or if end is greater than the length of
+ * the given array. If end equals -1, it is converted to the array length.
+ * <br><br>For example:
+ * <ol>
+ * <li>
+ *
+ * <pre>
+ * array = { 'a' , 'b' } start = 0 end = 1 result => { 'a' }
+ * </pre>
+ *
+ *
+ * </li>
+ * <li>
+ *
+ * <pre>
+ * array = { 'a', 'b' } start = 0 end = -1 result => { 'a' , 'b' }
+ * </pre>
+ *
+ *
+ * </li>
+ * </ol>
+ *
+ * @param array
+ * the given array
+ * @param start
+ * the given starting index
+ * @param end
+ * the given ending index
+ * @return a new array which is a copy of the given array starting at the
+ * given start and ending at the given end
+ * @exception NullPointerException
+ * if the given array is null
+ */
+ private char[] subarray(char[] array, int start, int end) {
+ if (end == -1)
+ end= array.length;
+ if (start > end)
+ return null;
+ if (start < 0)
+ return null;
+ if (end > array.length)
+ return null;
+ char[] result= new char[end - start];
+ System.arraycopy(array, start, result, 0, end - start);
+ return result;
+ }
+}

Back to the top