| /******************************************************************************* |
| * Copyright (c) 2000, 2006 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.jdt.internal.corext.util; |
| |
| import org.eclipse.jdt.core.Flags; |
| import org.eclipse.jdt.core.search.IJavaSearchConstants; |
| import org.eclipse.jdt.core.search.IJavaSearchScope; |
| import org.eclipse.jdt.core.search.SearchEngine; |
| import org.eclipse.jdt.core.search.SearchPattern; |
| |
| import org.eclipse.jdt.internal.corext.util.TypeInfo.TypeInfoAdapter; |
| |
| import org.eclipse.jdt.ui.dialogs.ITypeInfoFilterExtension; |
| |
| import org.eclipse.jdt.internal.ui.util.StringMatcher; |
| |
| public class TypeInfoFilter { |
| |
| private static class PatternMatcher { |
| |
| private String fPattern; |
| private int fMatchKind; |
| private StringMatcher fStringMatcher; |
| |
| private static final char END_SYMBOL= '<'; |
| private static final char ANY_STRING= '*'; |
| private static final char BLANK= ' '; |
| |
| public PatternMatcher(String pattern, boolean ignoreCase) { |
| this(pattern, SearchPattern.R_EXACT_MATCH | SearchPattern.R_PREFIX_MATCH | |
| SearchPattern.R_PATTERN_MATCH | SearchPattern.R_CAMELCASE_MATCH); |
| } |
| |
| public PatternMatcher(String pattern, int allowedModes) { |
| initializePatternAndMatchKind(pattern); |
| fMatchKind= fMatchKind & allowedModes; |
| if (fMatchKind == SearchPattern.R_PATTERN_MATCH) { |
| fStringMatcher= new StringMatcher(fPattern, true, false); |
| } |
| } |
| |
| public String getPattern() { |
| return fPattern; |
| } |
| |
| public int getMatchKind() { |
| return fMatchKind; |
| } |
| |
| public boolean matches(String text) { |
| switch (fMatchKind) { |
| case SearchPattern.R_PATTERN_MATCH: |
| return fStringMatcher.match(text); |
| case SearchPattern.R_EXACT_MATCH: |
| return fPattern.equalsIgnoreCase(text); |
| case SearchPattern.R_CAMELCASE_MATCH: |
| if (SearchPattern.camelCaseMatch(fPattern, text)) { |
| return true; |
| } |
| // fall through to prefix match if camel case failed (bug 137244) |
| default: |
| return Strings.startsWithIgnoreCase(text, fPattern); |
| } |
| } |
| |
| private void initializePatternAndMatchKind(String pattern) { |
| int length= pattern.length(); |
| if (length == 0) { |
| fMatchKind= SearchPattern.R_EXACT_MATCH; |
| fPattern= pattern; |
| return; |
| } |
| char last= pattern.charAt(length - 1); |
| |
| if (pattern.indexOf('*') != -1 || pattern.indexOf('?') != -1) { |
| fMatchKind= SearchPattern.R_PATTERN_MATCH; |
| switch (last) { |
| case END_SYMBOL: |
| fPattern= pattern.substring(0, length - 1); |
| break; |
| case BLANK: |
| fPattern= pattern.trim(); |
| break; |
| case ANY_STRING: |
| fPattern= pattern; |
| break; |
| default: |
| fPattern= pattern + ANY_STRING; |
| } |
| return; |
| } |
| |
| if (last == END_SYMBOL) { |
| fMatchKind= SearchPattern.R_EXACT_MATCH; |
| fPattern= pattern.substring(0, length - 1); |
| return; |
| } |
| |
| if (last == BLANK) { |
| fMatchKind= SearchPattern.R_EXACT_MATCH; |
| fPattern= pattern.trim(); |
| return; |
| } |
| |
| if (SearchUtils.isCamelCasePattern(pattern)) { |
| fMatchKind= SearchPattern.R_CAMELCASE_MATCH; |
| fPattern= pattern; |
| return; |
| } |
| |
| fMatchKind= SearchPattern.R_PREFIX_MATCH; |
| fPattern= pattern; |
| } |
| } |
| |
| private String fText; |
| private IJavaSearchScope fSearchScope; |
| private boolean fIsWorkspaceScope; |
| private int fElementKind; |
| private ITypeInfoFilterExtension fFilterExtension; |
| private TypeInfoAdapter fAdapter= new TypeInfoAdapter(); |
| |
| private PatternMatcher fPackageMatcher; |
| private PatternMatcher fNameMatcher; |
| |
| private static final int TYPE_MODIFIERS= Flags.AccEnum | Flags.AccAnnotation | Flags.AccInterface; |
| |
| public TypeInfoFilter(String text, IJavaSearchScope scope, int elementKind, ITypeInfoFilterExtension extension) { |
| fText= text; |
| fSearchScope= scope; |
| fIsWorkspaceScope= fSearchScope.equals(SearchEngine.createWorkspaceScope()); |
| fElementKind= elementKind; |
| fFilterExtension= extension; |
| |
| int index= text.lastIndexOf("."); //$NON-NLS-1$ |
| if (index == -1) { |
| fNameMatcher= new PatternMatcher(text, true); |
| } else { |
| fPackageMatcher= new PatternMatcher(text.substring(0, index), |
| SearchPattern.R_EXACT_MATCH | SearchPattern.R_PATTERN_MATCH); |
| String name= text.substring(index + 1); |
| if (name.length() == 0) |
| name= "*"; //$NON-NLS-1$ |
| fNameMatcher= new PatternMatcher(name, true); |
| } |
| } |
| |
| public String getText() { |
| return fText; |
| } |
| |
| public boolean isSubFilter(String text) { |
| if (! fText.startsWith(text)) |
| return false; |
| |
| return fText.indexOf('.', text.length()) == -1; |
| } |
| |
| public boolean isCamcelCasePattern() { |
| return fNameMatcher.getMatchKind() == SearchPattern.R_CAMELCASE_MATCH; |
| } |
| |
| public String getPackagePattern() { |
| if (fPackageMatcher == null) |
| return null; |
| return fPackageMatcher.getPattern(); |
| } |
| |
| public String getNamePattern() { |
| return fNameMatcher.getPattern(); |
| } |
| |
| public int getSearchFlags() { |
| return fNameMatcher.getMatchKind(); |
| } |
| |
| public boolean matchesRawNamePattern(TypeInfo type) { |
| return Strings.startsWithIgnoreCase(type.getTypeName(), fNameMatcher.getPattern()); |
| } |
| |
| public boolean matchesCachedResult(TypeInfo type) { |
| if (!(matchesPackage(type) && matchesFilterExtension(type))) |
| return false; |
| return matchesName(type); |
| } |
| |
| public boolean matchesHistoryElement(TypeInfo type) { |
| if (!(matchesPackage(type) && matchesModifiers(type) && matchesScope(type) && matchesFilterExtension(type))) |
| return false; |
| return matchesName(type); |
| } |
| |
| public boolean matchesFilterExtension(TypeInfo type) { |
| if (fFilterExtension == null) |
| return true; |
| fAdapter.setInfo(type); |
| return fFilterExtension.select(fAdapter); |
| } |
| |
| private boolean matchesName(TypeInfo type) { |
| return fNameMatcher.matches(type.getTypeName()); |
| } |
| |
| private boolean matchesPackage(TypeInfo type) { |
| if (fPackageMatcher == null) |
| return true; |
| // We should use the type container name here. However this |
| // require support from JDT/Core. See |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=120534 |
| return fPackageMatcher.matches(type.getPackageName()); |
| } |
| |
| private boolean matchesScope(TypeInfo type) { |
| if (fIsWorkspaceScope) |
| return true; |
| return type.isEnclosed(fSearchScope); |
| } |
| |
| private boolean matchesModifiers(TypeInfo type) { |
| if (fElementKind == IJavaSearchConstants.TYPE) |
| return true; |
| int modifiers= type.getModifiers() & TYPE_MODIFIERS; |
| switch (fElementKind) { |
| case IJavaSearchConstants.CLASS: |
| return modifiers == 0; |
| case IJavaSearchConstants.ANNOTATION_TYPE: |
| return Flags.isAnnotation(modifiers); |
| case IJavaSearchConstants.INTERFACE: |
| return Flags.isInterface(modifiers); |
| case IJavaSearchConstants.ENUM: |
| return Flags.isEnum(modifiers); |
| case IJavaSearchConstants.CLASS_AND_INTERFACE: |
| return modifiers == 0 || Flags.isInterface(modifiers); |
| case IJavaSearchConstants.CLASS_AND_ENUM: |
| return modifiers == 0 || Flags.isEnum(modifiers); |
| } |
| return false; |
| } |
| } |