diff options
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.java | 399 |
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; + } +} |