001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.corext.util;
011:
012: import org.eclipse.jdt.core.Flags;
013: import org.eclipse.jdt.core.search.IJavaSearchConstants;
014: import org.eclipse.jdt.core.search.IJavaSearchScope;
015: import org.eclipse.jdt.core.search.SearchEngine;
016: import org.eclipse.jdt.core.search.SearchPattern;
017: import org.eclipse.jdt.core.search.TypeNameMatch;
018:
019: import org.eclipse.jdt.ui.dialogs.ITypeInfoFilterExtension;
020:
021: import org.eclipse.jdt.internal.ui.util.StringMatcher;
022:
023: public class TypeInfoFilter {
024:
025: private static class PatternMatcher {
026:
027: private String fPattern;
028: private int fMatchKind;
029: private StringMatcher fStringMatcher;
030:
031: private static final char END_SYMBOL = '<';
032: private static final char ANY_STRING = '*';
033: private static final char BLANK = ' ';
034:
035: public PatternMatcher(String pattern) {
036: this (pattern, SearchPattern.R_EXACT_MATCH
037: | SearchPattern.R_PREFIX_MATCH
038: | SearchPattern.R_PATTERN_MATCH
039: | SearchPattern.R_CAMEL_CASE_MATCH);
040: }
041:
042: public PatternMatcher(String pattern, int allowedModes) {
043: initializePatternAndMatchKind(pattern);
044: fMatchKind = fMatchKind & allowedModes;
045: if (fMatchKind == SearchPattern.R_PATTERN_MATCH) {
046: fStringMatcher = new StringMatcher(fPattern, true,
047: false);
048: }
049: }
050:
051: public String getPattern() {
052: return fPattern;
053: }
054:
055: public int getMatchKind() {
056: return fMatchKind;
057: }
058:
059: public boolean matches(String text) {
060: switch (fMatchKind) {
061: case SearchPattern.R_PATTERN_MATCH:
062: return fStringMatcher.match(text);
063: case SearchPattern.R_EXACT_MATCH:
064: return fPattern.equalsIgnoreCase(text);
065: case SearchPattern.R_CAMEL_CASE_MATCH:
066: return (SearchPattern.camelCaseMatch(fPattern, text,
067: false));
068: case SearchPattern.R_CAMEL_CASE_MATCH
069: | SearchPattern.R_PREFIX_MATCH:
070: if (SearchPattern.camelCaseMatch(fPattern, text)) {
071: return true;
072: }
073: // fall through to prefix match if camel case failed (bug 137244)
074: default:
075: return Strings.startsWithIgnoreCase(text, fPattern);
076: }
077: }
078:
079: private void initializePatternAndMatchKind(String pattern) {
080: int length = pattern.length();
081: if (length == 0) {
082: fMatchKind = SearchPattern.R_EXACT_MATCH;
083: fPattern = pattern;
084: return;
085: }
086: char last = pattern.charAt(length - 1);
087:
088: if (pattern.indexOf('*') != -1
089: || pattern.indexOf('?') != -1) {
090: fMatchKind = SearchPattern.R_PATTERN_MATCH;
091: switch (last) {
092: case END_SYMBOL:
093: fPattern = pattern.substring(0, length - 1);
094: break;
095: case BLANK:
096: fPattern = pattern.trim();
097: break;
098: case ANY_STRING:
099: fPattern = pattern;
100: break;
101: default:
102: fPattern = pattern + ANY_STRING;
103: }
104: return;
105: }
106:
107: if (last == END_SYMBOL || last == BLANK) {
108: fPattern = pattern.substring(0, length - 1);
109: if (SearchUtils.isCamelCasePattern(fPattern)) {
110: fMatchKind = SearchPattern.R_CAMEL_CASE_MATCH;
111: } else {
112: fMatchKind = SearchPattern.R_EXACT_MATCH;
113: }
114: return;
115: }
116:
117: if (SearchUtils.isCamelCasePattern(pattern)) {
118: fMatchKind = SearchPattern.R_CAMEL_CASE_MATCH
119: | SearchPattern.R_PREFIX_MATCH;
120: fPattern = pattern;
121: return;
122: }
123:
124: fMatchKind = SearchPattern.R_PREFIX_MATCH;
125: fPattern = pattern;
126: }
127: }
128:
129: private final String fText;
130: private final IJavaSearchScope fSearchScope;
131: private final boolean fIsWorkspaceScope;
132: private final int fElementKind;
133: private final ITypeInfoFilterExtension fFilterExtension;
134: private final TypeInfoRequestorAdapter fAdapter = new TypeInfoRequestorAdapter();
135:
136: private final PatternMatcher fPackageMatcher;
137: private final PatternMatcher fNameMatcher;
138:
139: private static final int TYPE_MODIFIERS = Flags.AccEnum
140: | Flags.AccAnnotation | Flags.AccInterface;
141:
142: public TypeInfoFilter(String text, IJavaSearchScope scope,
143: int elementKind, ITypeInfoFilterExtension extension) {
144: fText = text;
145: fSearchScope = scope;
146: fIsWorkspaceScope = fSearchScope.equals(SearchEngine
147: .createWorkspaceScope());
148: fElementKind = elementKind;
149: fFilterExtension = extension;
150:
151: int index = text.lastIndexOf("."); //$NON-NLS-1$
152: if (index == -1) {
153: fNameMatcher = new PatternMatcher(text);
154: fPackageMatcher = null;
155: } else {
156: fPackageMatcher = new PatternMatcher(
157: evaluatePackagePattern(text.substring(0, index)));
158: String name = text.substring(index + 1);
159: if (name.length() == 0)
160: name = "*"; //$NON-NLS-1$
161: fNameMatcher = new PatternMatcher(name);
162: }
163: }
164:
165: /*
166: * Transforms o.e.j to o*.e*.j*
167: */
168: private String evaluatePackagePattern(String s) {
169: StringBuffer buf = new StringBuffer();
170: boolean hasWildCard = false;
171: for (int i = 0; i < s.length(); i++) {
172: char ch = s.charAt(i);
173: if (ch == '.') {
174: if (!hasWildCard) {
175: buf.append('*');
176: }
177: hasWildCard = false;
178: } else if (ch == '*' || ch == '?') {
179: hasWildCard = true;
180: }
181: buf.append(ch);
182: }
183: if (!hasWildCard) {
184: buf.append('*');
185: }
186: return buf.toString();
187: }
188:
189: public String getText() {
190: return fText;
191: }
192:
193: /**
194: * Checks whether <code>this</code> filter is a subFilter of the given <code>text</code>.
195: * <p>
196: * <i>WARNING: This is the <b>reverse</b> interpretation compared to
197: * {@link org.eclipse.ui.dialogs.SearchPattern#isSubPattern(org.eclipse.ui.dialogs.SearchPattern)} and
198: * {@link org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.ItemsFilter#isSubFilter}.
199: * </i>
200: * </p>
201: *
202: * @param text another filter text
203: * @return <code>true</code> if <code>this</code> filter is a subFilter of <code>text</code>
204: * e.g. "List" is a subFilter of "L". In this case, the filters matches a proper subset of
205: * the items matched by <code>text</code>.
206: */
207: public boolean isSubFilter(String text) {
208: if (!fText.startsWith(text))
209: return false;
210:
211: return fText.indexOf('.', text.length()) == -1;
212: }
213:
214: public boolean isCamelCasePattern() {
215: return (fNameMatcher.getMatchKind() & SearchPattern.R_CAMEL_CASE_MATCH) != 0;
216: }
217:
218: public String getPackagePattern() {
219: if (fPackageMatcher == null)
220: return null;
221: return fPackageMatcher.getPattern();
222: }
223:
224: public String getNamePattern() {
225: return fNameMatcher.getPattern();
226: }
227:
228: public int getSearchFlags() {
229: return fNameMatcher.getMatchKind();
230: }
231:
232: public int getElementKind() {
233: return fElementKind;
234: }
235:
236: public IJavaSearchScope getSearchScope() {
237: return fSearchScope;
238: }
239:
240: public int getPackageFlags() {
241: if (fPackageMatcher == null)
242: return SearchPattern.R_EXACT_MATCH;
243:
244: return fPackageMatcher.getMatchKind();
245: }
246:
247: public boolean matchesRawNamePattern(TypeNameMatch type) {
248: return Strings.startsWithIgnoreCase(type.getSimpleTypeName(),
249: fNameMatcher.getPattern());
250: }
251:
252: public boolean matchesCachedResult(TypeNameMatch type) {
253: if (!(matchesPackage(type) && matchesFilterExtension(type)))
254: return false;
255: return matchesName(type);
256: }
257:
258: public boolean matchesHistoryElement(TypeNameMatch type) {
259: if (!(matchesPackage(type) && matchesModifiers(type)
260: && matchesScope(type) && matchesFilterExtension(type)))
261: return false;
262: return matchesName(type);
263: }
264:
265: public boolean matchesFilterExtension(TypeNameMatch type) {
266: if (fFilterExtension == null)
267: return true;
268: fAdapter.setMatch(type);
269: return fFilterExtension.select(fAdapter);
270: }
271:
272: private boolean matchesName(TypeNameMatch type) {
273: if (fText.length() == 0) {
274: return true; //empty pattern matches all names
275: }
276: return fNameMatcher.matches(type.getSimpleTypeName());
277: }
278:
279: private boolean matchesPackage(TypeNameMatch type) {
280: if (fPackageMatcher == null)
281: return true;
282: return fPackageMatcher.matches(type.getTypeContainerName());
283: }
284:
285: private boolean matchesScope(TypeNameMatch type) {
286: if (fIsWorkspaceScope)
287: return true;
288: return fSearchScope.encloses(type.getType());
289: }
290:
291: private boolean matchesModifiers(TypeNameMatch type) {
292: if (fElementKind == IJavaSearchConstants.TYPE)
293: return true;
294: int modifiers = type.getModifiers() & TYPE_MODIFIERS;
295: switch (fElementKind) {
296: case IJavaSearchConstants.CLASS:
297: return modifiers == 0;
298: case IJavaSearchConstants.ANNOTATION_TYPE:
299: return Flags.isAnnotation(modifiers);
300: case IJavaSearchConstants.INTERFACE:
301: return Flags.isInterface(modifiers);
302: case IJavaSearchConstants.ENUM:
303: return Flags.isEnum(modifiers);
304: case IJavaSearchConstants.CLASS_AND_INTERFACE:
305: return modifiers == 0 || Flags.isInterface(modifiers);
306: case IJavaSearchConstants.CLASS_AND_ENUM:
307: return modifiers == 0 || Flags.isEnum(modifiers);
308: }
309: return false;
310: }
311: }
|