Revert "ChooseByNameBase - extract Matcher (now a custom matcher can be defined)"

This reverts commit b9c9dcce00.
This commit is contained in:
Maxim Shafirov
2010-11-10 20:05:25 +03:00
parent c0c76dfb89
commit 45b7b2d77d
4 changed files with 213 additions and 344 deletions
@@ -20,12 +20,11 @@ import com.intellij.Patches;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.actions.CopyReferenceAction;
import com.intellij.ide.ui.UISettings;
import com.intellij.ide.util.gotoByName.matchers.DefaultMatcher;
import com.intellij.ide.util.gotoByName.matchers.EntityMatcher;
import com.intellij.openapi.MnemonicHelper;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.keymap.KeymapManager;
@@ -33,15 +32,19 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.*;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.NameUtil;
import com.intellij.psi.statistics.StatisticsInfo;
import com.intellij.psi.statistics.StatisticsManager;
import com.intellij.psi.util.proximity.PsiProximityComparator;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.ListScrollingUtil;
import com.intellij.ui.ScrollPaneFactory;
@@ -49,6 +52,9 @@ import com.intellij.ui.components.JBList;
import com.intellij.ui.popup.PopupOwner;
import com.intellij.ui.popup.PopupUpdateProcessor;
import com.intellij.util.Alarm;
import com.intellij.util.Function;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.diff.Diff;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
@@ -62,14 +68,19 @@ import javax.swing.event.ListSelectionListener;
import javax.swing.text.DefaultEditorKit;
import java.awt.*;
import java.awt.event.*;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.List;
public abstract class ChooseByNameBase {
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.gotoByName.ChooseByNameBase");
protected final Project myProject;
protected final ChooseByNameModel myModel;
protected final String myInitialText;
private boolean myPreselectInitialText;
private final Reference<PsiElement> myContext;
protected Component myPreviouslyFocusedComponent;
@@ -104,14 +115,10 @@ public abstract class ChooseByNameBase {
private static int VISIBLE_LIST_SIZE_LIMIT = 10;
private static final int MAXIMUM_LIST_SIZE_LIMIT = 30;
private int myMaximumListSizeLimit = MAXIMUM_LIST_SIZE_LIMIT;
@NonNls
private static final String NOT_FOUND_IN_PROJECT_CARD = "syslib";
@NonNls
private static final String NOT_FOUND_CARD = "nfound";
@NonNls
private static final String CHECK_BOX_CARD = "chkbox";
@NonNls
private static final String SEARCHING_CARD = "searching";
@NonNls private static final String NOT_FOUND_IN_PROJECT_CARD = "syslib";
@NonNls private static final String NOT_FOUND_CARD = "nfound";
@NonNls private static final String CHECK_BOX_CARD = "chkbox";
@NonNls private static final String SEARCHING_CARD = "searching";
private static final int REBUILD_DELAY = 300;
private final Alarm myHideAlarm = new Alarm();
@@ -119,26 +126,32 @@ public abstract class ChooseByNameBase {
protected JBPopup myTextPopup;
protected JBPopup myDropdownPopup;
private EntityMatcher myMatcher;
private static class MatchesComparator implements Comparator<String> {
private final String myOriginalPattern;
private MatchesComparator(final String originalPattern) {
myOriginalPattern = originalPattern.trim();
}
public int compare(final String a, final String b) {
boolean aStarts = a.startsWith(myOriginalPattern);
boolean bStarts = b.startsWith(myOriginalPattern);
if (aStarts && bStarts) return a.compareToIgnoreCase(b);
if (aStarts && !bStarts) return -1;
if (bStarts && !aStarts) return 1;
return a.compareToIgnoreCase(b);
}
}
/**
* @param initialText initial text which will be in the lookup text field
* @param context
*/
protected ChooseByNameBase(Project project, ChooseByNameModel model, String initialText, final PsiElement context) {
this(project, model, initialText);
myMatcher = new DefaultMatcher(model, context);
}
protected ChooseByNameBase(Project project, ChooseByNameModel model, String initialText, EntityMatcher matcher) {
this(project, model, initialText);
myMatcher = matcher;
}
private ChooseByNameBase(Project project, ChooseByNameModel model, String initialText) {
myProject = project;
myModel = model;
myInitialText = initialText;
myContext = new WeakReference<PsiElement>(context);
}
public boolean isPreselectInitialText() {
@@ -259,7 +272,7 @@ public abstract class ChooseByNameBase {
/**
* @param callback
* @param modalityState - if not null rebuilds list in given {@link com.intellij.openapi.application.ModalityState}
* @param modalityState - if not null rebuilds list in given {@link ModalityState}
* @param allowMultipleSelection
*/
protected void initUI(final ChooseByNamePopupComponent.Callback callback,
@@ -284,8 +297,7 @@ public abstract class ChooseByNameBase {
GridBagLayout gb = new GridBagLayout();
JPanel eastWrapper = new JPanel(gb);
gb.setConstraints(hBox, new GridBagConstraints(0, 0, 0, 0, 1, 1, GridBagConstraints.SOUTHEAST, GridBagConstraints.NONE,
new Insets(0, 0, 0, 0), 0, 0));
gb.setConstraints(hBox, new GridBagConstraints(0, 0, 0, 0, 1, 1, GridBagConstraints.SOUTHEAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
eastWrapper.add(hBox);
caption2Tools.add(eastWrapper, BorderLayout.CENTER);
@@ -435,7 +447,8 @@ public abstract class ChooseByNameBase {
myListModel = new DefaultListModel();
myList = new JBList(myListModel);
myList.setFocusable(false);
myList.setSelectionMode(allowMultipleSelection ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION : ListSelectionModel.SINGLE_SELECTION);
myList.setSelectionMode(allowMultipleSelection ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION :
ListSelectionModel.SINGLE_SELECTION);
myList.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (!myTextField.hasFocus()) {
@@ -577,8 +590,8 @@ public abstract class ChooseByNameBase {
final int paneHeight = layeredPane.getHeight();
final int y = paneHeight / 3 - preferredTextFieldPanelSize.height / 2;
VISIBLE_LIST_SIZE_LIMIT =
Math.max(10, (paneHeight - (y + preferredTextFieldPanelSize.height)) / (preferredTextFieldPanelSize.height / 2) - 1);
VISIBLE_LIST_SIZE_LIMIT = Math.max
(10, (paneHeight - (y + preferredTextFieldPanelSize.height)) / (preferredTextFieldPanelSize.height / 2) - 1);
ComponentPopupBuilder builder = JBPopupFactory.getInstance().createComponentPopupBuilder(myTextFieldPanel, myTextField);
builder.setCancelCallback(new Computable<Boolean>() {
@@ -614,11 +627,9 @@ public abstract class ChooseByNameBase {
layeredPane = ((JDialog)parent).getLayeredPane();
}
else {
throw new IllegalStateException("cannot find parent window: project=" +
myProject +
throw new IllegalStateException("cannot find parent window: project=" + myProject +
(myProject != null ? "; open=" + myProject.isOpen() : "") +
"; window=" +
window);
"; window=" + window);
}
return layeredPane;
}
@@ -639,7 +650,8 @@ public abstract class ChooseByNameBase {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
final String text = myTextField.getText();
if (!canShowListForEmptyPattern() && (text == null || text.trim().length() == 0)) {
if (!canShowListForEmptyPattern() &&
(text == null || text.trim().length() == 0)) {
myListModel.clear();
hideList();
myCard.show(myCardContainer, CHECK_BOX_CARD);
@@ -779,12 +791,17 @@ public abstract class ChooseByNameBase {
return "choose_by_name#" + myModel.getPromptText() + "#" + myCheckBox.isSelected() + "#" + myTextField.getText();
}
public String getNamePattern(String pattern) {
return getNamePattern_static(myModel, pattern);
private String getQualifierPattern(String pattern) {
final String[] separators = myModel.getSeparators();
int lastSeparatorOccurence = 0;
for (String separator : separators) {
lastSeparatorOccurence = Math.max(lastSeparatorOccurence, pattern.lastIndexOf(separator));
}
return pattern.substring(0, lastSeparatorOccurence);
}
public static String getNamePattern_static(ChooseByNameModel model, String pattern) {
final String[] separators = model.getSeparators();
public String getNamePattern(String pattern) {
final String[] separators = myModel.getSeparators();
int lastSeparatorOccurence = 0;
for (String separator : separators) {
final int idx = pattern.lastIndexOf(separator);
@@ -970,7 +987,7 @@ public abstract class ChooseByNameBase {
protected void processKeyEvent(KeyEvent e) {
final KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e);
if (myCompletionKeyStroke != null && keyStroke.equals(myCompletionKeyStroke)) {
completionKeyStrokeHappened = true;
e.consume();
@@ -1021,7 +1038,8 @@ public abstract class ChooseByNameBase {
}
private void fillInCommonPrefix(final String pattern) {
final List<String> list = getNamesByPattern(pattern, getNames());
final ArrayList<String> list = new ArrayList<String>();
getNamesByPattern(myCheckBox.isSelected(), null, list, pattern);
if (isComplexPattern(pattern)) return; //TODO: support '*'
final String oldText = myTextField.getText();
@@ -1087,34 +1105,6 @@ public abstract class ChooseByNameBase {
}
}
public List<String> getNamesByPattern(String pattern, String[] names) {
if (pattern.startsWith("@")) {
pattern = pattern.substring(1);
}
boolean empty = pattern.length() == 0;
if (empty) {
if (!canShowListForEmptyPattern()) return Collections.emptyList();
return Arrays.asList(names);
}
ArrayList<String> result = new ArrayList<String>();
try {
for (String name : names) {
if (myCalcElementsThread.myCancelled) {
break;
}
if (myMatcher.nameMatches(pattern, name)) {
result.add(name);
}
}
}
catch (Exception e) {
// Do nothing. No matches appears valid result for "bad" pattern
}
return result;
}
private static final String EXTRA_ELEM = "...";
private class CalcElementsThread implements Runnable {
@@ -1203,31 +1193,55 @@ public abstract class ChooseByNameBase {
}
private void addElementsByPattern(Set<Object> elementsArray, String pattern) {
String[] names = myCheckboxState ? myNames[1] : myNames[0];
String namePattern = getNamePattern(pattern);
String qualifierPattern = getQualifierPattern(pattern);
List<String> namesList = getNamesByPattern(namePattern, names);
boolean empty = namePattern.length() == 0 || namePattern.equals("@"); // TODO[yole]: remove implicit dependency
if (empty && !canShowListForEmptyPattern()) return;
List<String> namesList = new ArrayList<String>();
getNamesByPattern(myCheckboxState, this, namesList, namePattern);
if (myCancelled) {
throw new ProcessCanceledException();
}
// Here we sort using namePattern to have similar logic with empty qualified patten case
Collections.sort(namesList, new MatchesComparator(namePattern));
boolean overflow = false;
List<Object> sameNameElements = new SmartList<Object>();
All:
for (String name : namesList) {
Set<Object> elems = myMatcher.getElementsByPattern(namePattern, name, myCheckboxState,new Computable<Boolean>() {
public Boolean compute() {
return myCancelled;
}
});
if (elementsArray.size() + elems.size() <= myMaximumListSizeLimit) {
elementsArray.addAll(elems);
if (myCancelled) {
throw new ProcessCanceledException();
}
else {
Iterator<Object> iter = elems.iterator();
while (elementsArray.size() < myMaximumListSizeLimit) {
elementsArray.add(iter.next());
final Object[] elements = myModel.getElementsByName(name, myCheckboxState, namePattern);
if (elements.length > 1) {
sameNameElements.clear();
for (final Object element : elements) {
if (matchesQualifier(element, qualifierPattern)) {
sameNameElements.add(element);
}
}
sortByProximity(sameNameElements);
for (Object element : sameNameElements) {
elementsArray.add(element);
if (elementsArray.size() >= myMaximumListSizeLimit) {
overflow = true;
break All;
}
}
elementsArray.add(EXTRA_ELEM);
break;
}
else if (elements.length == 1 && matchesQualifier(elements[0], qualifierPattern)) {
elementsArray.add(elements[0]);
if (elementsArray.size() >= myMaximumListSizeLimit) {
overflow = true;
break;
}
}
}
if (overflow) {
elementsArray.add(EXTRA_ELEM);
}
}
@@ -1238,8 +1252,92 @@ public abstract class ChooseByNameBase {
}
}
private String[] getNames() {
return myCheckBox.isSelected() ? myNames[1] : myNames[0];
private void sortByProximity(final List<Object> sameNameElements) {
Collections.sort(sameNameElements, new PathProximityComparator(myModel, myContext.get()));
}
private List<String> split(String s) {
List<String> answer = new ArrayList<String>();
for (String token : StringUtil.tokenize(s, StringUtil.join(myModel.getSeparators(), ""))) {
if (token.length() > 0) {
answer.add(token);
}
}
return answer.isEmpty() ? Collections.singletonList(s) : answer;
}
private boolean matchesQualifier(final Object element, final String qualifierPattern) {
final String name = myModel.getFullName(element);
if (name == null) return false;
final List<String> suspects = split(name);
final List<Pair<String, NameUtil.Matcher>> patternsAndMatchers =
ContainerUtil.map2List(split(qualifierPattern), new Function<String, Pair<String, NameUtil.Matcher>>() {
public Pair<String, NameUtil.Matcher> fun(String s) {
final String pattern = getNamePattern(s);
final NameUtil.Matcher matcher = buildPatternMatcher(pattern);
return new Pair<String, NameUtil.Matcher>(pattern, matcher);
}
});
int matchPosition = 0;
try {
patterns:
for (Pair<String, NameUtil.Matcher> patternAndMatcher : patternsAndMatchers) {
final String pattern = patternAndMatcher.first;
final NameUtil.Matcher matcher = patternAndMatcher.second;
if (pattern.length() > 0) {
for (int j = matchPosition; j < suspects.size() - 1; j++) {
String suspect = suspects.get(j);
if (matches(pattern, matcher, suspect)) {
matchPosition = j + 1;
continue patterns;
}
}
return false;
}
}
}
catch (Exception e) {
// Do nothing. No matches appears valid result for "bad" pattern
return false;
}
return true;
}
private void getNamesByPattern(final boolean checkboxState,
CalcElementsThread calcElementsThread,
final List<String> list,
String pattern) throws ProcessCanceledException {
if (!canShowListForEmptyPattern()) {
LOG.assertTrue(pattern.length() > 0);
}
if (pattern.startsWith("@")) {
pattern = pattern.substring(1);
}
final String[] names = checkboxState ? myNames[1] : myNames[0];
final NameUtil.Matcher matcher = buildPatternMatcher(pattern);
try {
for (String name : names) {
if (calcElementsThread != null && calcElementsThread.myCancelled) {
break;
}
if (matches(pattern, matcher, name)) {
list.add(name);
}
}
}
catch (Exception e) {
// Do nothing. No matches appears valid result for "bad" pattern
}
}
private boolean canShowListForEmptyPattern() {
@@ -1247,27 +1345,46 @@ public abstract class ChooseByNameBase {
}
protected boolean lastKeyStrokeIsCompletion() {
return myTextField.isCompletionKeyStroke();
return myTextField.isCompletionKeyStroke();
}
private boolean matches(String pattern, NameUtil.Matcher matcher, String name) {
boolean matches = false;
if (name != null) {
if (myModel instanceof CustomMatcherModel) {
if (((CustomMatcherModel)myModel).matches(name, pattern)) {
matches = true;
}
}
else if (pattern.length() == 0 || matcher.matches(name)) {
matches = true;
}
}
return matches;
}
private NameUtil.Matcher buildPatternMatcher(String pattern) {
return NameUtil.buildMatcher(pattern, 0, true, true, pattern.toLowerCase().equals(pattern));
}
private interface CalcElementsCallback {
void run(Set<?> elements);
}
private static class MatchesComparator implements Comparator<String> {
private final String myOriginalPattern;
private static class PathProximityComparator implements Comparator<Object> {
private final ChooseByNameModel myModel;
private final PsiProximityComparator myProximityComparator;
private MatchesComparator(final String originalPattern) {
myOriginalPattern = originalPattern.trim();
private PathProximityComparator(final ChooseByNameModel model, final PsiElement context) {
myModel = model;
myProximityComparator = new PsiProximityComparator(context);
}
public int compare(final String a, final String b) {
boolean aStarts = a.startsWith(myOriginalPattern);
boolean bStarts = b.startsWith(myOriginalPattern);
if (aStarts && bStarts) return a.compareToIgnoreCase(b);
if (aStarts && !bStarts) return -1;
if (bStarts && !aStarts) return 1;
return a.compareToIgnoreCase(b);
public int compare(final Object o1, final Object o2) {
int rc = myProximityComparator.compare(o1, o2);
if (rc != 0) return rc;
return Comparing.compare(myModel.getFullName(o1), myModel.getFullName(o2));
}
}
@@ -17,7 +17,6 @@
package com.intellij.ide.util.gotoByName;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.ide.util.gotoByName.matchers.EntityMatcher;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.ComponentPopupBuilder;
@@ -43,7 +42,7 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNamePopupComponent {
public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNamePopupComponent{
private static final Key<ChooseByNamePopup> CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY = new Key<ChooseByNamePopup>("ChooseByNamePopup");
private Component myOldFocusOwner = null;
private boolean myShowListForEmptyPattern = false;
@@ -59,17 +58,6 @@ public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNameP
}
}
private ChooseByNamePopup(final Project project, final ChooseByNameModel model, final ChooseByNamePopup oldPopup,
EntityMatcher matcher,@Nullable final String predefinedText) {
super(project, model, oldPopup != null ? oldPopup.getEnteredText() : predefinedText, matcher);
if (oldPopup == null && predefinedText != null) {
setPreselectInitialText(true);
}
if (oldPopup != null) { //inherit old focus owner
myOldFocusOwner = oldPopup.myPreviouslyFocusedComponent;
}
}
public String getEnteredText() {
return myTextField.getText();
}
@@ -215,22 +203,6 @@ public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNameP
public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, final PsiElement context) {
return createPopup(project, model, context, null);
}
public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, EntityMatcher matcher) {
return createPopup(project, model, matcher, null);
}
public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, EntityMatcher matcher,
@Nullable final String predefinedText) {
final ChooseByNamePopup oldPopup = project.getUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY);
if (oldPopup != null) {
oldPopup.close(false);
}
ChooseByNamePopup newPopup = new ChooseByNamePopup(project, model, oldPopup, matcher, predefinedText);
project.putUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY, newPopup);
return newPopup;
}
public static ChooseByNamePopup createPopup(final Project project, final ChooseByNameModel model, final PsiElement context,
@Nullable final String predefinedText) {
final ChooseByNamePopup oldPopup = project.getUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY);
@@ -1,194 +0,0 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ide.util.gotoByName.matchers;
import com.intellij.ide.util.gotoByName.ChooseByNameBase;
import com.intellij.ide.util.gotoByName.ChooseByNameModel;
import com.intellij.ide.util.gotoByName.CustomMatcherModel;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.NameUtil;
import com.intellij.psi.util.proximity.PsiProximityComparator;
import com.intellij.util.Function;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import java.lang.ref.WeakReference;
import java.util.*;
public class DefaultMatcher implements EntityMatcher {
private ChooseByNameModel myModel;
private WeakReference<PsiElement> myContext;
private String myPattern = null;
private NameUtil.Matcher myMatcher = null;
public DefaultMatcher(ChooseByNameModel model, PsiElement context) {
myModel = model;
myContext = new WeakReference<PsiElement>(context);
}
public boolean nameMatches(String shortPattern, String shortName) {
if (myPattern == null || !myPattern.equals(shortPattern)) {
myMatcher = buildPatternMatcher(shortPattern);
}
return matches(shortPattern, myMatcher, shortName);
}
public Set<Object> getElementsByPattern(String fullPattern, String shortName, boolean checkboxState, Computable<Boolean> isCancelled) {
String namePattern = getShortNamePattern(fullPattern);
String qualifierPattern = getQualifierPattern(fullPattern);
//todo this is a code duplicate - remove it
String newPattern = namePattern.startsWith("@") ? namePattern.substring(1) : namePattern;
if (!nameMatches(newPattern, shortName)) return Collections.emptySet();
List<Object> sameNameElements = new SmartList<Object>();
final Object[] elements = myModel.getElementsByName(shortName, checkboxState, namePattern);
Set<Object> result = new HashSet<Object>();
if (elements.length == 1) {
if (matchesQualifier(elements[0], qualifierPattern)) {
result.add(elements[0]);
}
return result;
}
sameNameElements.clear();
for (final Object element : elements) {
if (isCancelled.compute()) return result;
if (matchesQualifier(element, qualifierPattern)) {
sameNameElements.add(element);
}
}
sortByProximity(sameNameElements);
result.addAll(sameNameElements);
return result;
}
private void sortByProximity(final List<Object> sameNameElements) {
Collections.sort(sameNameElements, new PathProximityComparator(myModel, myContext.get()));
}
private boolean matchesQualifier(final Object element, final String qualifierPattern) {
final String name = myModel.getFullName(element);
if (name == null) return false;
final List<String> suspects = split(name);
final List<Pair<String, NameUtil.Matcher>> patternsAndMatchers =
ContainerUtil.map2List(split(qualifierPattern), new Function<String, Pair<String, NameUtil.Matcher>>() {
public Pair<String, NameUtil.Matcher> fun(String s) {
final String pattern = getShortNamePattern(s);
final NameUtil.Matcher matcher = buildPatternMatcher(pattern);
return new Pair<String, NameUtil.Matcher>(pattern, matcher);
}
});
int matchPosition = 0;
try {
patterns:
for (Pair<String, NameUtil.Matcher> patternAndMatcher : patternsAndMatchers) {
final String pattern = patternAndMatcher.first;
final NameUtil.Matcher matcher = patternAndMatcher.second;
if (pattern.length() > 0) {
for (int j = matchPosition; j < suspects.size() - 1; j++) {
String suspect = suspects.get(j);
if (matches(pattern, matcher, suspect)) {
matchPosition = j + 1;
continue patterns;
}
}
return false;
}
}
}
catch (Exception e) {
// Do nothing. No matches appears valid result for "bad" pattern
return false;
}
return true;
}
public String getShortNamePattern(String s) {
return ChooseByNameBase.getNamePattern_static(myModel, s);
}
private String getQualifierPattern(String pattern) {
final String[] separators = myModel.getSeparators();
int lastSeparatorOccurence = 0;
for (String separator : separators) {
lastSeparatorOccurence = Math.max(lastSeparatorOccurence, pattern.lastIndexOf(separator));
}
return pattern.substring(0, lastSeparatorOccurence);
}
private boolean matches(String pattern, NameUtil.Matcher matcher, String name) {
boolean matches = false;
if (name != null) {
if (myModel instanceof CustomMatcherModel) {
if (((CustomMatcherModel)myModel).matches(name, pattern)) {
matches = true;
}
}
else if (pattern.length() == 0 || matcher.matches(name)) {
matches = true;
}
}
return matches;
}
private static NameUtil.Matcher buildPatternMatcher(String pattern) {
return NameUtil.buildMatcher(pattern, 0, true, true, pattern.toLowerCase().equals(pattern));
}
private List<String> split(String s) {
List<String> answer = new ArrayList<String>();
for (String token : StringUtil.tokenize(s, StringUtil.join(myModel.getSeparators(), ""))) {
if (token.length() > 0) {
answer.add(token);
}
}
return answer.isEmpty() ? Collections.singletonList(s) : answer;
}
private static class PathProximityComparator implements Comparator<Object> {
private final ChooseByNameModel myModel;
private final PsiProximityComparator myProximityComparator;
private PathProximityComparator(final ChooseByNameModel model, final PsiElement context) {
myModel = model;
myProximityComparator = new PsiProximityComparator(context);
}
public int compare(final Object o1, final Object o2) {
int rc = myProximityComparator.compare(o1, o2);
if (rc != 0) return rc;
return Comparing.compare(myModel.getFullName(o1), myModel.getFullName(o2));
}
}
}
@@ -1,26 +0,0 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ide.util.gotoByName.matchers;
import com.intellij.openapi.util.Computable;
import java.util.Set;
public interface EntityMatcher {
boolean nameMatches(String shortPattern, String shortName);
Set<Object> getElementsByPattern(String fullPattern, String shortName, boolean checkboxState, Computable<Boolean> isCancelled);
}