completely refacrored

This commit is contained in:
Konstantin Bulenkov
2013-08-23 19:52:47 +02:00
parent 6ad345299f
commit 6356a1120d
@@ -33,6 +33,7 @@ import com.intellij.openapi.actionSystem.impl.ActionManagerImpl;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.fileEditor.impl.EditorHistoryManager;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.SearchableConfigurable;
@@ -42,9 +43,9 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.ComponentPopupBuilder;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.PopupChooserBuilder;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
@@ -60,6 +61,7 @@ import com.intellij.psi.codeStyle.NameUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.*;
import com.intellij.ui.border.CustomLineBorder;
import com.intellij.ui.components.JBList;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.OnOffButton;
import com.intellij.util.Alarm;
@@ -80,6 +82,7 @@ import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.lang.reflect.Field;
import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -98,14 +101,30 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
private String[] myActions;
private Component myFocusComponent;
private JBPopup myPopup;
private int myLeftWidth;
private SearchListModel myListModel = new SearchListModel();
private TitleIndexes myTitleIndexes;
private Map<String, String> myConfigurables = new HashMap<String, String>();
private Alarm myAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, ApplicationManager.getApplication());
private JList myList = new JList(); //don't use JBList here!!! todo[kb]
private JBList myList = new JBList(myListModel) {
{
setOpaque(false);
}
@Override
protected void paintComponent(Graphics g) {
g.setColor(getTitlePanelBackground());
g.fillRect(0, 0, myLeftWidth - 1, getHeight());
g.setColor(getSeparatorColor());
g.drawLine(myLeftWidth-1, 0, myLeftWidth-1, getHeight());
super.paintComponent(g);
}
}; //don't use JBList here!!! todo[kb]
private AnActionEvent myActionEvent;
private Component myContextComponent;
private CalcThread myCalcThread;
private static AtomicBoolean ourShiftCanBeUsed = new AtomicBoolean(false);
private ArrayList<VirtualFile> myAlreadyAddedFiles = new ArrayList<VirtualFile>();
static {
IdeEventQueue.getInstance().addPostprocessor(new IdeEventQueue.EventDispatcher() {
@@ -117,7 +136,6 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
return false;
}
}, null);
}
private int myTopHitsCount;
@@ -159,21 +177,11 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
myAlarm.addRequest(new Runnable() {
@Override
public void run() {
if (StringUtil.isEmpty(pattern.trim())) {
//noinspection SSBasedInspection
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (myPopup != null && myPopup.isVisible()) {
myPopup.cancel();
}
}
});
return;
if (field != null && field.getTextEditor().hasFocus()) {
rebuildList(pattern);
}
rebuildList(pattern);
}
}, Registry.intValue("ide.goto.rebuild.delay"));
}, /*Registry.intValue("ide.goto.rebuild.delay")*/30);
}
});
editor.addFocusListener(new FocusAdapter() {
@@ -181,7 +189,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
public void focusGained(FocusEvent e) {
field.setText("");
field.getTextEditor().setForeground(UIUtil.getLabelForeground());
myTitleIndexes = new TitleIndexes();
editor.setColumns(25);
myFocusComponent = e.getOppositeComponent();
//noinspection SSBasedInspection
@@ -193,6 +201,11 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
parent.repaint();
}
});
if (myPopup != null && myPopup.isVisible()) {
myPopup.cancel();
myPopup = null;
}
rebuildList("");
}
@Override
@@ -225,13 +238,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
myCalcThread = null;
}
myAlarm.cancelAllRequests();
myList.setModel(new DefaultListModel());
myClassModel = null;
myFileModel = null;
myActionModel = null;
myClasses = null;
myFiles = null;
myActions = null;
myListModel.clear();
//noinspection SSBasedInspection
SwingUtilities.invokeLater(new Runnable() {
@@ -254,31 +261,35 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
}
AccessToken token = ApplicationManager.getApplication().acquireReadActionLock();
try {
if (value instanceof PsiElement) {
NavigationUtil.activateFileWithPsiElement((PsiElement)value, true);
return;
} else if (isVirtualFile(value)) {
OpenFileDescriptor navigatable = new OpenFileDescriptor(project, (VirtualFile)value);
if (navigatable.canNavigate()) {
navigatable.navigate(true);
if (value instanceof PsiElement) {
NavigationUtil.activateFileWithPsiElement((PsiElement)value, true);
return;
}
} else {
focusManager.requestDefaultFocus(true);
IdeFocusManager.getInstance(project).doWhenFocusSettlesDown(new Runnable() {
@Override
public void run() {
if (value instanceof BooleanOptionDescription) {
final BooleanOptionDescription option = (BooleanOptionDescription)value;
option.setOptionState(!option.isOptionEnabled());
} else {
GotoActionAction.openOptionOrPerformAction(value, pattern, project, myContextComponent ,myActionEvent);
}
else if (isVirtualFile(value)) {
OpenFileDescriptor navigatable = new OpenFileDescriptor(project, (VirtualFile)value);
if (navigatable.canNavigate()) {
navigatable.navigate(true);
return;
}
});
return;
}
else {
focusManager.requestDefaultFocus(true);
IdeFocusManager.getInstance(project).doWhenFocusSettlesDown(new Runnable() {
@Override
public void run() {
if (value instanceof BooleanOptionDescription) {
final BooleanOptionDescription option = (BooleanOptionDescription)value;
option.setOptionState(!option.isOptionEnabled());
}
else {
GotoActionAction.openOptionOrPerformAction(value, pattern, project, myContextComponent, myActionEvent);
}
}
});
return;
}
}
} finally {
finally {
token.finish();
}
focusManager.requestDefaultFocus(true);
@@ -353,11 +364,6 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
return new Dimension(myLeftWidth, super.getPreferredSize().height);
}
};
private int myLeftWidth;
public void setLeftWidth(int width) {
myLeftWidth = width;
}
@Override
public void clear() {
@@ -386,7 +392,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
final OnOffButton button = new OnOffButton();
button.setSelected(((BooleanOptionDescription)value).isOptionEnabled());
rightComponent = button;
} else {
}
else {
rightComponent = myLocation.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
}
panel.add(rightComponent, BorderLayout.EAST);
@@ -394,55 +401,15 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
}
cmp.setBackground(isSelected ? UIUtil.getListSelectionBackground() : getRightBackground());
String title = getTitle(index, value, index == 0 ? null : list.getModel().getElementAt(index -1));
String title = myTitleIndexes.getTitle(index);
myTitle.setText(title == null ? "" : title);
myLeftPanel.removeAll();
myLeftPanel.setBackground(new JBColor(Gray._242, JBColor.background()));
myLeftPanel.setBackground(getTitlePanelBackground());
myMainPanel.removeAll();
myLeftPanel.add(myTitle, BorderLayout.EAST);
myMainPanel.add(myLeftPanel, BorderLayout.WEST);
myMainPanel.add(cmp, BorderLayout.CENTER);
return myMainPanel;
}
private Color getRightBackground() {
return UIUtil.isUnderAquaLookAndFeel() ? Gray._236 : UIUtil.getListBackground();
}
private String getTitle(int index, Object value, Object prevValue) {
if (index == 0 && myTopHitsCount > 0) {
return myTopHitsCount == 1 ? "Top Hit" : "Top Hits";
}
if (index < myTopHitsCount) {
return null;
}
if (index == myTopHitsCount) {
prevValue = null;
}
String gotoClass = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction("GotoClass"));
gotoClass = StringUtil.isEmpty(gotoClass) ? "Classes" : "Classes (" + gotoClass + ")";
String gotoFile = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction("GotoFile"));
gotoFile = StringUtil.isEmpty(gotoFile) ? "Files" : "Files (" + gotoFile + ")";
String gotoAction = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction("GotoAction"));
gotoAction = StringUtil.isEmpty(gotoAction) ? "Actions" : "Actions (" + gotoAction + ")";
String gotoSettings = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction("ShowSettings"));
gotoSettings = StringUtil.isEmpty(gotoAction) ? "Preferences" : "Preferences (" + gotoSettings + ")";
String toolWindows = "Tool Windows";
if (prevValue == null) { // firstElement
if (value instanceof PsiElement)return gotoClass;
if (isVirtualFile(value))return gotoFile;
if (isToolWindowAction(value)) return toolWindows;
if (isSetting(value)) return gotoSettings;
if (isActionValue(value))return gotoAction;
return gotoSettings;
} else {
if (!isVirtualFile(prevValue) && isVirtualFile(value)) return gotoFile;
if (!isSetting(prevValue) && isSetting(value)) return gotoSettings;
if (!isToolWindowAction(prevValue) && isToolWindowAction(value)) return toolWindows;
if ((!isActionValue(prevValue) || isToolWindowAction(prevValue)) && isActionValue(value)) return gotoAction;
}
return null;
}
@Override
@@ -457,7 +424,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
}
else if (isVirtualFile(value)) {
append(((VirtualFile)value).getName());
} else if (isActionValue(value)) {
}
else if (isActionValue(value)) {
final Map.Entry actionWithParentGroup = value instanceof Map.Entry ? (Map.Entry)value : null;
final AnAction anAction = actionWithParentGroup == null ? (AnAction)value : (AnAction)actionWithParentGroup.getKey();
final Presentation templatePresentation = anAction.getTemplatePresentation();
@@ -514,7 +482,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
while (index < model.getSize()) {
Object el = model.getElementAt(index);
Object prev = index == 0 ? null : model.getElementAt(index - 1);
String title = getTitle(index, el, prev);
String title = myTitleIndexes.getTitle(index);
if (title != null) {
myTitle.setText(title);
myLeftWidth = Math.max(myLeftWidth, myTitle.getPreferredSize().width);
@@ -525,7 +493,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
myLeftWidth += 10;
myTitle.setForeground(Gray._122);
myTitle.setAlignmentY(BOTTOM_ALIGNMENT);
myLeftPanel.setBorder(new CompoundBorder(new CustomLineBorder(new JBColor(Gray._206, Gray._75), 0,0,0,1), new EmptyBorder(0,0,0,5)));
myLeftPanel.setBorder(new CompoundBorder(new CustomLineBorder(getSeparatorColor(), 0, 0, 0, 1), new EmptyBorder(0, 0, 0, 5)));
}
private Font getTitleFont() {
@@ -533,6 +501,18 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
}
}
private static JBColor getTitlePanelBackground() {
return new JBColor(Gray._242, JBColor.background());
}
private static Color getRightBackground() {
return UIUtil.isUnderAquaLookAndFeel() ? Gray._236 : UIUtil.getListBackground();
}
private static JBColor getSeparatorColor() {
return new JBColor(Gray._206, Gray._75);
}
private static boolean isActionValue(Object o) {
return o instanceof Map.Entry || o instanceof AnAction;
}
@@ -545,6 +525,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
return o instanceof VirtualFile;
}
@SuppressWarnings("SSBasedInspection")
private class CalcThread implements Runnable {
private final Project project;
private final String pattern;
@@ -557,84 +538,241 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
@Override
public void run() {
//noinspection SSBasedInspection
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
myTitleIndexes.clear();
myListModel.clear();
myAlreadyAddedFiles.clear();
}
});
if (pattern.trim().length() == 0) {
buildModelFromRecentFiles();
updatePopup();
return;
}
checkModelsUpToDate();
buildTopHit(pattern);
buildRecentFiles(pattern);
updatePopup();
AccessToken readLock = ApplicationManager.getApplication().acquireReadActionLock();
try {
buildClasses(pattern);
} finally {readLock.finish();}
updatePopup();
readLock = ApplicationManager.getApplication().acquireReadActionLock();
try {
buildFiles(pattern);
} finally {readLock.finish();}
buildActionsAndSettings(pattern);
updatePopup();
}
private void buildActionsAndSettings(String pattern) {
final Set<AnAction> actions = new HashSet<AnAction>();
final Set<Object> settings = new HashSet<Object>();
final HashSet<AnAction> toolWindows = new HashSet<AnAction>();
List<MatchResult> matches = collectResults(pattern, myActions, myActionModel);
for (MatchResult o : matches) {
//if (actionsCount > 15) break;
myProgressIndicator.checkCanceled();
Object[] objects = myActionModel.getElementsByName(o.elementName, true, pattern);
for (Object object : objects) {
myProgressIndicator.checkCanceled();
if (isSetting(object)) {
settings.add(object);
}
else if (isToolWindowAction(object)) {
toolWindows.add((AnAction)((Map.Entry)object).getKey());
}
else if (isActionValue(object)) {
actions.add((AnAction)((Map.Entry)object).getKey());
}
if (actions.size() + settings.size() + toolWindows.size() > 15) break;
}
}
myProgressIndicator.checkCanceled();
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
if (myProgressIndicator.isCanceled()) return;
if (toolWindows.size() > 0) {
myTitleIndexes.toolWindows = myListModel.size();
for (Object toolWindow : toolWindows) {
myListModel.addElement(toolWindow);
}
}
if (actions.size() > 0) {
myTitleIndexes.actions = myListModel.size();
for (Object action : actions) {
myListModel.addElement(action);
}
}
if (settings.size() > 0) {
myTitleIndexes.settings = myListModel.size();
for (Object setting : settings) {
myListModel.addElement(setting);
}
}
}
});
}
private void buildFiles(String pattern) {
int filesCounter = 0;
List<MatchResult> matches = collectResults(pattern, myFiles, myFileModel);
final List<VirtualFile> files = new ArrayList<VirtualFile>();
for (MatchResult o : matches) {
if (filesCounter > 15) break;
Object[] objects = myFileModel.getElementsByName(o.elementName, false, pattern, myProgressIndicator);
for (Object object : objects) {
if (!myListModel.contains(object)) {
if (object instanceof PsiFile) {
object = ((PsiFile)object).getVirtualFile();
}
if (object instanceof VirtualFile &&
!myAlreadyAddedFiles.contains((VirtualFile)object) &&
!((VirtualFile)object).isDirectory()) {
files.add((VirtualFile)object);
filesCounter++;
}
}
if (filesCounter > 15) break;
}
}
myProgressIndicator.checkCanceled();
if (files.size() > 0) {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
if (!myProgressIndicator.isCanceled()) {
myTitleIndexes.files = myListModel.size();
for (Object file : files) {
myListModel.addElement(file);
}
}
}
});
}
}
private void buildClasses(String pattern) {
int clsCounter = 0;
List<MatchResult> matches = collectResults(pattern, myClasses, myClassModel);
final List<Object> classes = new ArrayList<Object>();
for (MatchResult matchResult : matches) {
if (clsCounter > 15) break;
Object[] objects = myClassModel.getElementsByName(matchResult.elementName, false, pattern, myProgressIndicator);
for (Object object : objects) {
if (!myListModel.contains(object)) {
if (object instanceof PsiElement) {
VirtualFile file = PsiUtilCore.getVirtualFile((PsiElement)object);
if (file != null) {
if (myAlreadyAddedFiles.contains(file)) {
continue;
}
else {
myAlreadyAddedFiles.add(file);
}
}
}
classes.add(object);
clsCounter++;
if (clsCounter > 15) break;
}
}
}
myProgressIndicator.checkCanceled();
if (classes.size() > 0) {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
if (!myProgressIndicator.isCanceled()) {
myTitleIndexes.classes = myListModel.size();
for (Object cls : classes) {
myListModel.addElement(cls);
}
}
}
});
}
}
private void buildRecentFiles(String pattern) {
final MinusculeMatcher matcher = new MinusculeMatcher(pattern, NameUtil.MatchingCaseSensitivity.NONE);
final ArrayList<VirtualFile> files = new ArrayList<VirtualFile>();
for (VirtualFile file : ArrayUtil.reverseArray(EditorHistoryManager.getInstance(project).getFiles())) {
if (StringUtil.isEmptyOrSpaces(pattern) || matcher.matches(file.getName())) {
files.add(file);
}
if (files.size() > 15) break;
}
if (files.size() > 0) {
myAlreadyAddedFiles.addAll(files);
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
if (!myProgressIndicator.isCanceled()) {
myTitleIndexes.recentFiles = myListModel.size();
for (Object file : files) {
myListModel.addElement(file);
}
}
}
});
}
}
private void buildTopHit(String pattern) {
final List<Object> elements = new ArrayList<Object>();
final Consumer<Object> consumer = new Consumer<Object>() {
@Override
public void consume(Object o) {
if (isSetting(o) || isVirtualFile(o) || isActionValue(o) || o instanceof PsiElement) {
elements.add(o);
}
}
};
for (SearchTopHitProvider provider : SearchTopHitProvider.EP_NAME.getExtensions()) {
myProgressIndicator.checkCanceled();
provider.consumeTopHits(pattern, consumer);
}
if (elements.size() > 0) {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
if (!myProgressIndicator.isCanceled()) {
myTitleIndexes.topHit = myListModel.size();
for (Object element : elements) {
myListModel.addElement(element);
}
}
}
});
}
}
private void checkModelsUpToDate() {
if (myClassModel == null) {
myClassModel = new GotoClassModel2(project);
myFileModel = new GotoFileModel(project);
myActionModel = new GotoActionModel(project, myFocusComponent) {
@Override
public boolean matches(@NotNull String name, @NotNull String pattern) {
final AnAction anAction = ActionManager.getInstance().getAction(name);
if (anAction == null) return true;
return NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE).matches(
anAction.getTemplatePresentation().getText());
}
@NotNull
@Override
public Object[] getElementsByName(String id, boolean checkBoxState, String pattern) {
final HashMap<AnAction, String> map = new HashMap<AnAction, String>();
final AnAction act = myActionManager.getAction(id);
if (act != null) {
map.put(act, myActionsMap.get(act));
if (checkBoxState) {
final Set<String> ids = ((ActionManagerImpl)myActionManager).getActionIds();
for (AnAction action : map.keySet()) { //do not add already included actions
ids.remove(getActionId(action));
}
if (ids.contains(id)) {
final AnAction anAction = myActionManager.getAction(id);
map.put(anAction, null);
}
}
}
Object[] objects = map.entrySet().toArray(new Map.Entry[map.size()]);
if (Comparing.strEqual(id, SETTINGS_KEY)) {
final Set<String> words = myIndex.getProcessedWords(pattern);
Set<OptionDescription> optionDescriptions = null;
final String actionManagerName = myActionManager.getComponentName();
for (String word : words) {
final Set<OptionDescription> descriptions = ((SearchableOptionsRegistrarImpl)myIndex).getAcceptableDescriptions(word);
if (descriptions != null) {
for (Iterator<OptionDescription> iterator = descriptions.iterator(); iterator.hasNext(); ) {
OptionDescription description = iterator.next();
if (actionManagerName.equals(description.getPath())) {
iterator.remove();
}
}
if (!descriptions.isEmpty()) {
if (optionDescriptions == null) {
optionDescriptions = descriptions;
}
else {
optionDescriptions.retainAll(descriptions);
}
}
} else {
optionDescriptions = null;
break;
}
}
if (optionDescriptions != null && !optionDescriptions.isEmpty()) {
Set<String> currentHits = new HashSet<String>();
for (Iterator<OptionDescription> iterator = optionDescriptions.iterator(); iterator.hasNext(); ) {
OptionDescription description = iterator.next();
final String hit = description.getHit();
if (hit == null || !currentHits.add(hit.trim())) {
iterator.remove();
}
}
final Object[] descriptions = optionDescriptions.toArray();
Arrays.sort(descriptions);
objects = ArrayUtil.mergeArrays(objects, descriptions);
}
}
return objects;
}
};
myActionModel = createActionModel();
myClasses = myClassModel.getNames(false);
myFiles = myFileModel.getNames(false);
myActions = myActionModel.getNames(true);
@@ -642,152 +780,100 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
fillConfigurablesIds(null, new IdeConfigurablesGroup().getConfigurables());
fillConfigurablesIds(null, new ProjectConfigurablesGroup(project).getConfigurables());
}
int clsCounter = 0;
int filesCounter = 0;
int actionsCount = 0;
final AccessToken token = ApplicationManager.getApplication().acquireReadActionLock();
try {
List<MatchResult> classes = collectResults(pattern, myClasses, myClassModel);
List<MatchResult> files = collectResults(pattern, myFiles, myFileModel);
List<MatchResult> actions = collectResults(pattern, myActions, myActionModel);
DefaultListModel listModel = new DefaultListModel();
Set<VirtualFile> alreadyAddedFiles = new HashSet<VirtualFile>();
}
for (MatchResult o : classes) {
if (clsCounter > 15) break;
private void buildModelFromRecentFiles() {
buildRecentFiles("");
}
Object[] objects = myClassModel.getElementsByName(o.elementName, false, pattern, myProgressIndicator);
for (Object object : objects) {
if (!listModel.contains(object)) {
listModel.addElement(object);
clsCounter++;
if (object instanceof PsiElement) {
VirtualFile file = PsiUtilCore.getVirtualFile((PsiElement)object);
if (file != null) {
alreadyAddedFiles.add(file);
private GotoActionModel createActionModel() {
return new GotoActionModel(project, myFocusComponent) {
@Override
public boolean matches(@NotNull String name, @NotNull String pattern) {
final AnAction anAction = ActionManager.getInstance().getAction(name);
if (anAction == null) return true;
return NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE).matches(
anAction.getTemplatePresentation().getText());
}
@NotNull
@Override
public Object[] getElementsByName(String id, boolean checkBoxState, String pattern) {
final HashMap<AnAction, String> map = new HashMap<AnAction, String>();
final AnAction act = myActionManager.getAction(id);
if (act != null) {
map.put(act, myActionsMap.get(act));
if (checkBoxState) {
final Set<String> ids = ((ActionManagerImpl)myActionManager).getActionIds();
for (AnAction action : map.keySet()) { //do not add already included actions
ids.remove(getActionId(action));
}
if (ids.contains(id)) {
final AnAction anAction = myActionManager.getAction(id);
map.put(anAction, null);
}
}
}
Object[] objects = map.entrySet().toArray(new Map.Entry[map.size()]);
if (Comparing.strEqual(id, SETTINGS_KEY)) {
final Set<String> words = myIndex.getProcessedWords(pattern);
Set<OptionDescription> optionDescriptions = null;
final String actionManagerName = myActionManager.getComponentName();
for (String word : words) {
final Set<OptionDescription> descriptions = ((SearchableOptionsRegistrarImpl)myIndex).getAcceptableDescriptions(word);
if (descriptions != null) {
for (Iterator<OptionDescription> iterator = descriptions.iterator(); iterator.hasNext(); ) {
OptionDescription description = iterator.next();
if (actionManagerName.equals(description.getPath())) {
iterator.remove();
}
}
if (!descriptions.isEmpty()) {
if (optionDescriptions == null) {
optionDescriptions = descriptions;
}
else {
optionDescriptions.retainAll(descriptions);
}
}
}
if (clsCounter > 15) break;
}
}
}
for (MatchResult o : files) {
if (filesCounter > 15) break;
Object[] objects = myFileModel.getElementsByName(o.elementName, false, pattern, myProgressIndicator);
for (Object object : objects) {
if (!listModel.contains(object)) {
if (object instanceof PsiFile) {
object = ((PsiFile)object).getVirtualFile();
}
if (object instanceof VirtualFile && !alreadyAddedFiles.contains((VirtualFile)object) && !((VirtualFile)object).isDirectory()) {
listModel.addElement(object);
filesCounter++;
else {
optionDescriptions = null;
break;
}
}
if (filesCounter > 15) break;
}
}
final Set<AnAction> addedActions = new HashSet<AnAction>();
final List<Object> actionsAndSettings = new ArrayList<Object>();
for (MatchResult o : actions) {
//if (actionsCount > 15) break;
myProgressIndicator.checkCanceled();
Object[] objects = myActionModel.getElementsByName(o.elementName, true, pattern);
for (Object object : objects) {
myProgressIndicator.checkCanceled();
if (isActionValue(object)) {
final AnAction action = (AnAction)((Map.Entry)object).getKey();
if (!addedActions.add(action)) continue;
if (optionDescriptions != null && !optionDescriptions.isEmpty()) {
Set<String> currentHits = new HashSet<String>();
for (Iterator<OptionDescription> iterator = optionDescriptions.iterator(); iterator.hasNext(); ) {
OptionDescription description = iterator.next();
final String hit = description.getHit();
if (hit == null || !currentHits.add(hit.trim())) {
iterator.remove();
}
}
final Object[] descriptions = optionDescriptions.toArray();
Arrays.sort(descriptions);
objects = ArrayUtil.mergeArrays(objects, descriptions);
}
actionsAndSettings.add(object);
actionsCount++;
//if (actionsCount > 15) break;
}
return objects;
}
Collections.sort(actionsAndSettings, new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
final boolean b1 = isSetting(o1);
final boolean b2 = isSetting(o2);
final boolean t1 = isToolWindowAction(o1);
final boolean t2 = isToolWindowAction(o2);
return t1 == t2 ? b1 == b2 ? 0 : b1 ? 1 : -1 : t1 ? -1 : 1;
}
});
for (Object actionOrSetting : actionsAndSettings) {
listModel.addElement(actionOrSetting);
}
updateModel(listModel);
}
finally {
token.finish();
}
};
}
@SuppressWarnings("SSBasedInspection")
private void updateModel(final DefaultListModel listModel) {
private void updatePopup() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
myProgressIndicator.checkCanceled();
final DataContext dataContext = DataManager.getInstance().getDataContext(myContextComponent);
int settings = 0;
int actions = 0;
final DefaultListModel model = new DefaultListModel();
myListModel.update();
myList.revalidate();
myList.repaint();
final String pattern = field.getText();
final Consumer<Object> consumer = new Consumer<Object>() {
@Override
public void consume(Object o) {
if (isSetting(o) || isVirtualFile(o) || isActionValue(o) || o instanceof PsiElement) {
model.addElement(o);
}
}
};
for (SearchTopHitProvider provider : SearchTopHitProvider.EP_NAME.getExtensions()) {
provider.consumeTopHits(pattern, consumer);
}
myTopHitsCount = model.size();
for (Object o : listModel.toArray()) {
if (model.contains(o)) {
continue;
}
if (isSetting(o)) {
if (settings < 15) {
settings++;
model.addElement(o);
}
} else if (isActionValue(o)) {
if (actions < 15) {
final AnAction action = (AnAction)((Map.Entry)o).getKey();
if (model.contains(action)) {
continue;
}
final AnActionEvent event = GotoActionModel.updateActionBeforeShow(action, dataContext);
if (event.getPresentation().isEnabledAndVisible()) {
actions++;
model.addElement(action);
}
}
} else {
model.addElement(o);
}
}
myList.setModel(model);
myRenderer.recalculateWidth();
if (myPopup == null || !myPopup.isVisible()) {
final ActionCallback callback = ListDelegationUtil.installKeyboardDelegation(field.getTextEditor(), myList);
final PopupChooserBuilder builder = JBPopupFactory.getInstance().createListPopupBuilder(myList);
final ComponentPopupBuilder builder = JBPopupFactory.getInstance().createComponentPopupBuilder(new JBScrollPane(myList), null);
myPopup = builder.setRequestFocus(false).createPopup();
Disposer.register(myPopup, new Disposable() {
@Override
@@ -802,26 +888,31 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
myPopup.cancel();
}
}, myPopup);
} else {
}
else {
myList.revalidate();
myList.repaint();
}
ListScrollingUtil.ensureSelectionExists(myList);
if (myList.getModel().getSize() == 0) {
myPopup.cancel();
} else {
//rebuildList("");
}
else {
final Dimension size = myList.getPreferredSize();
Dimension sz = new Dimension(Math.max(field.getWidth(), size.width), size.height);
if (sz.width > 800 || sz.height > 800) {
final int extra = new JBScrollPane().getVerticalScrollBar().getWidth();
sz = new Dimension(Math.min(800, Math.max(field.getWidth(), size.width + extra)), Math.min(800, size.height + extra));
sz.width += 16;
} else {
}
else {
sz.height++;
sz.height++;
sz.width++;
sz.width++;
}
sz.width = 600;
sz.height = 800;
myPopup.setSize(sz);
final Point screen = field.getLocationOnScreen();
final int x = screen.x + field.getWidth() - myPopup.getSize().width;
@@ -909,4 +1000,83 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
}
}
}
static class TitleIndexes {
int topHit;
int recentFiles;
int classes;
int files;
int actions;
int settings;
int toolWindows;
final String gotoClassTitle;
final String gotoFileTitle;
final String gotoActionTitle;
final String gotoSettingsTitle;
final String gotoRecentFilesTitle;
static final String toolWindowsTitle = "Tool Windows";
TitleIndexes() {
String gotoClass = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction("GotoClass"));
gotoClassTitle = StringUtil.isEmpty(gotoClass) ? "Classes" : "Classes (" + gotoClass + ")";
String gotoFile = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction("GotoFile"));
gotoFileTitle = StringUtil.isEmpty(gotoFile) ? "Files" : "Files (" + gotoFile + ")";
String gotoAction = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction("GotoAction"));
gotoActionTitle = StringUtil.isEmpty(gotoAction) ? "Actions" : "Actions (" + gotoAction + ")";
String gotoSettings = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction("ShowSettings"));
gotoSettingsTitle = StringUtil.isEmpty(gotoAction) ? "Preferences" : "Preferences (" + gotoSettings + ")";
String gotoRecentFiles = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction("RecentFiles"));
gotoRecentFilesTitle = StringUtil.isEmpty(gotoRecentFiles) ? "Recent Files" : "Recent Files (" + gotoRecentFiles + ")";
}
String getTitle(int index) {
if (index == topHit) return index == 0 ? "Top Hit" : "Top Hits";
if (index == recentFiles) return gotoRecentFilesTitle;
if (index == classes) return gotoClassTitle;
if (index == files) return gotoFileTitle;
if (index == toolWindows) return toolWindowsTitle;
if (index == actions) return gotoActionTitle;
if (index == settings) return gotoSettingsTitle;
return null;
}
public void clear() {
topHit = -1;
recentFiles = -1;
classes = -1;
files = -1;
actions = -1;
settings = -1;
toolWindows = -1;
}
}
private static class SearchListModel extends DefaultListModel {
Vector myDelegate;
private SearchListModel() {
super();
try {
final Field field = DefaultListModel.class.getDeclaredField("delegate");
field.setAccessible(true);
myDelegate = (Vector)field.get(this);
}
catch (NoSuchFieldException e) {
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
}
@Override
public void addElement(Object obj) {
myDelegate.add(obj);
}
public void update() {
fireContentsChanged(this, 0, getSize() - 1);
}
}
}