IDEA-88280 Cannot scroll down with arrows in "non-prefix matches" search results in "go to" popups

This commit is contained in:
Alexander Kirillin
2012-07-04 20:26:10 +04:00
parent 0c9743b9d1
commit a87003244c
7 changed files with 1920 additions and 1893 deletions
@@ -61,4 +61,6 @@ public interface ChooseByNameModel {
String getHelpId();
boolean willOpenEditor();
boolean useMiddleMatching();
}
@@ -96,4 +96,9 @@ public class GotoInspectionModel extends SimpleChooseByNameModel {
}
return null;
}
@Override
public boolean useMiddleMatching() {
return true;
}
}
@@ -419,6 +419,11 @@ public final class TreeFileChooserDialog extends DialogWrapper implements TreeFi
public String[] getSeparators() {
return new String[] {"/", "\\"};
}
@Override
public boolean useMiddleMatching() {
return false;
}
}
private final class MyCallback extends ChooseByNamePopupComponent.Callback {
File diff suppressed because it is too large Load Diff
@@ -1,183 +1,188 @@
/*
* Copyright 2000-2009 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;
import com.intellij.concurrency.JobLauncher;
import com.intellij.diagnostic.PluginException;
import com.intellij.ide.plugins.PluginManager;
import com.intellij.ide.util.NavigationItemListCellRenderer;
import com.intellij.navigation.ChooseByNameContributor;
import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import com.intellij.util.containers.ConcurrentHashSet;
import com.intellij.util.containers.ContainerUtil;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;
/**
* Contributor-based goto model
*/
public abstract class ContributorsBasedGotoByModel implements ChooseByNameModel {
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.gotoByName.ContributorsBasedGotoByModel");
protected final Project myProject;
private final ChooseByNameContributor[] myContributors;
protected ContributorsBasedGotoByModel(Project project, ChooseByNameContributor[] contributors) {
myProject = project;
myContributors = contributors;
}
public ListCellRenderer getListCellRenderer() {
return new NavigationItemListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
if (value == ChooseByNameBase.NON_PREFIX_SEPARATOR) {
Object previousElement = index > 0 ? list.getModel().getElementAt(index - 1) : null;
return ChooseByNameBase.renderNonPrefixSeparatorComponent(getBackgroundColor(previousElement));
}
else {
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
}
}
};
}
public String[] getNames(final boolean checkBoxState) {
final Set<String> names = new ConcurrentHashSet<String>();
JobLauncher.getInstance().invokeConcurrentlyUnderProgress(filterDumb(myContributors), ProgressManager.getInstance().getProgressIndicator(), false,
new Processor<ChooseByNameContributor>() {
@Override
public boolean process(ChooseByNameContributor contributor) {
try {
if (!myProject.isDisposed()) {
ContainerUtil.addAll(names, contributor.getNames(myProject, checkBoxState));
}
}
catch (ProcessCanceledException ex) {
// index corruption detected, ignore
}
catch (IndexNotReadyException ex) {
// index corruption detected, ignore
}
catch (Exception ex) {
LOG.error(ex);
}
return true;
}
});
return ArrayUtil.toStringArray(names);
}
private List<ChooseByNameContributor> filterDumb(ChooseByNameContributor[] contributors) {
if (!DumbService.getInstance(myProject).isDumb()) return Arrays.asList(contributors);
List<ChooseByNameContributor> answer = new ArrayList<ChooseByNameContributor>(contributors.length);
for (ChooseByNameContributor contributor : contributors) {
if (DumbService.isDumbAware(contributor)) {
answer.add(contributor);
}
}
return answer;
}
/**
* Get elements by name from contributors.
*
* @param name a name
* @param checkBoxState if true, non-project files are considered as well
* @param pattern a pattern to use
* @return a list of navigation items from contributors for
* which {@link #acceptItem(NavigationItem) returns true.
*
*/
public Object[] getElementsByName(final String name, final boolean checkBoxState, final String pattern) {
final List<NavigationItem> items = Collections.synchronizedList(new ArrayList<NavigationItem>());
JobLauncher.getInstance().invokeConcurrentlyUnderProgress(filterDumb(myContributors), ProgressManager.getInstance().getProgressIndicator(), false,
new Processor<ChooseByNameContributor>() {
@Override
public boolean process(ChooseByNameContributor contributor) {
try {
for (NavigationItem item : contributor
.getItemsByName(name, pattern, myProject, checkBoxState)) {
if (item == null) {
final PluginId pluginId =
PluginManager.getPluginByClassName(contributor.getClass().getName());
if (pluginId != null) {
LOG.error(new PluginException(
"null item from contributor " + contributor + " for name " + name, pluginId));
}
else {
LOG.error("null item from contributor " + contributor + " for name " + name);
}
continue;
}
if (acceptItem(item)) {
items.add(item);
}
}
}
catch (ProcessCanceledException ex) {
// index corruption detected, ignore
}
catch (Exception ex) {
LOG.error(ex);
}
return true;
}
});
return ArrayUtil.toObjectArray(items);
}
public String getElementName(Object element) {
return ((NavigationItem)element).getName();
}
public String getHelpId() {
return null;
}
protected ChooseByNameContributor[] getContributors() {
return myContributors;
}
/**
* This method allows extending classes to introduce additional filtering criteria to model
* beyond pattern and project/non-project files. The default implementation just returns true.
*
* @param item an item to filter
* @return true if the item is acceptable according to additional filtering criteria.
*/
protected boolean acceptItem(NavigationItem item) {
return true;
}
}
/*
* Copyright 2000-2009 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;
import com.intellij.concurrency.JobLauncher;
import com.intellij.diagnostic.PluginException;
import com.intellij.ide.plugins.PluginManager;
import com.intellij.ide.util.NavigationItemListCellRenderer;
import com.intellij.navigation.ChooseByNameContributor;
import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import com.intellij.util.containers.ConcurrentHashSet;
import com.intellij.util.containers.ContainerUtil;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;
/**
* Contributor-based goto model
*/
public abstract class ContributorsBasedGotoByModel implements ChooseByNameModel {
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.gotoByName.ContributorsBasedGotoByModel");
protected final Project myProject;
private final ChooseByNameContributor[] myContributors;
protected ContributorsBasedGotoByModel(Project project, ChooseByNameContributor[] contributors) {
myProject = project;
myContributors = contributors;
}
public ListCellRenderer getListCellRenderer() {
return new NavigationItemListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
if (value == ChooseByNameBase.NON_PREFIX_SEPARATOR) {
Object previousElement = index > 0 ? list.getModel().getElementAt(index - 1) : null;
return ChooseByNameBase.renderNonPrefixSeparatorComponent(getBackgroundColor(previousElement));
}
else {
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
}
}
};
}
public String[] getNames(final boolean checkBoxState) {
final Set<String> names = new ConcurrentHashSet<String>();
JobLauncher.getInstance().invokeConcurrentlyUnderProgress(filterDumb(myContributors), ProgressManager.getInstance().getProgressIndicator(), false,
new Processor<ChooseByNameContributor>() {
@Override
public boolean process(ChooseByNameContributor contributor) {
try {
if (!myProject.isDisposed()) {
ContainerUtil.addAll(names, contributor.getNames(myProject, checkBoxState));
}
}
catch (ProcessCanceledException ex) {
// index corruption detected, ignore
}
catch (IndexNotReadyException ex) {
// index corruption detected, ignore
}
catch (Exception ex) {
LOG.error(ex);
}
return true;
}
});
return ArrayUtil.toStringArray(names);
}
private List<ChooseByNameContributor> filterDumb(ChooseByNameContributor[] contributors) {
if (!DumbService.getInstance(myProject).isDumb()) return Arrays.asList(contributors);
List<ChooseByNameContributor> answer = new ArrayList<ChooseByNameContributor>(contributors.length);
for (ChooseByNameContributor contributor : contributors) {
if (DumbService.isDumbAware(contributor)) {
answer.add(contributor);
}
}
return answer;
}
/**
* Get elements by name from contributors.
*
* @param name a name
* @param checkBoxState if true, non-project files are considered as well
* @param pattern a pattern to use
* @return a list of navigation items from contributors for
* which {@link #acceptItem(NavigationItem) returns true.
*
*/
public Object[] getElementsByName(final String name, final boolean checkBoxState, final String pattern) {
final List<NavigationItem> items = Collections.synchronizedList(new ArrayList<NavigationItem>());
JobLauncher.getInstance().invokeConcurrentlyUnderProgress(filterDumb(myContributors), ProgressManager.getInstance().getProgressIndicator(), false,
new Processor<ChooseByNameContributor>() {
@Override
public boolean process(ChooseByNameContributor contributor) {
try {
for (NavigationItem item : contributor
.getItemsByName(name, pattern, myProject, checkBoxState)) {
if (item == null) {
final PluginId pluginId =
PluginManager.getPluginByClassName(contributor.getClass().getName());
if (pluginId != null) {
LOG.error(new PluginException(
"null item from contributor " + contributor + " for name " + name, pluginId));
}
else {
LOG.error("null item from contributor " + contributor + " for name " + name);
}
continue;
}
if (acceptItem(item)) {
items.add(item);
}
}
}
catch (ProcessCanceledException ex) {
// index corruption detected, ignore
}
catch (Exception ex) {
LOG.error(ex);
}
return true;
}
});
return ArrayUtil.toObjectArray(items);
}
public String getElementName(Object element) {
return ((NavigationItem)element).getName();
}
public String getHelpId() {
return null;
}
protected ChooseByNameContributor[] getContributors() {
return myContributors;
}
/**
* This method allows extending classes to introduce additional filtering criteria to model
* beyond pattern and project/non-project files. The default implementation just returns true.
*
* @param item an item to filter
* @return true if the item is acceptable according to additional filtering criteria.
*/
protected boolean acceptItem(NavigationItem item) {
return true;
}
@Override
public boolean useMiddleMatching() {
return true;
}
}
@@ -492,4 +492,9 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
public boolean willOpenEditor() {
return false;
}
@Override
public boolean useMiddleMatching() {
return false;
}
}
@@ -108,4 +108,9 @@ public abstract class SimpleChooseByNameModel implements ChooseByNameModel {
public boolean willOpenEditor() {
return false;
}
@Override
public boolean useMiddleMatching() {
return false;
}
}