com.intellij.ide.actions.SearchEverywhereAction.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.ide.actions.SearchEverywhereAction.java

Source

/*
 * Copyright 2000-2014 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.actions;

import com.intellij.codeInsight.navigation.NavigationUtil;
import com.intellij.execution.Executor;
import com.intellij.execution.ExecutorRegistry;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.actions.ChooseRunConfigurationPopup;
import com.intellij.execution.actions.ExecutorProvider;
import com.intellij.execution.executors.DefaultRunExecutor;
import com.intellij.execution.impl.RunDialog;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.icons.AllIcons;
import com.intellij.ide.DataManager;
import com.intellij.ide.IdeEventQueue;
import com.intellij.ide.IdeTooltipManager;
import com.intellij.ide.SearchTopHitProvider;
import com.intellij.ide.structureView.StructureView;
import com.intellij.ide.structureView.StructureViewBuilder;
import com.intellij.ide.structureView.StructureViewModel;
import com.intellij.ide.structureView.StructureViewTreeElement;
import com.intellij.ide.ui.OptionsTopHitProvider;
import com.intellij.ide.ui.UISettings;
import com.intellij.ide.ui.search.BooleanOptionDescription;
import com.intellij.ide.ui.search.OptionDescription;
import com.intellij.ide.util.DefaultPsiElementCellRenderer;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.ide.util.gotoByName.*;
import com.intellij.ide.util.treeView.smartTree.TreeElement;
import com.intellij.lang.Language;
import com.intellij.navigation.ItemPresentation;
import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionUtil;
import com.intellij.openapi.actionSystem.ex.AnActionListener;
import com.intellij.openapi.actionSystem.ex.CustomComponentAction;
import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actions.TextComponentEditorAction;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.fileEditor.impl.EditorHistoryManager;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.keymap.MacKeymapUtil;
import com.intellij.openapi.keymap.impl.ModifierKeyDoubleClickHandler;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.options.ex.IdeConfigurablesGroup;
import com.intellij.openapi.options.ex.ProjectConfigurablesGroup;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.DumbService;
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.util.*;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.VirtualFilePathWrapper;
import com.intellij.openapi.wm.*;
import com.intellij.openapi.wm.impl.IdeFrameImpl;
import com.intellij.pom.Navigatable;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.MinusculeMatcher;
import com.intellij.psi.codeStyle.NameUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.ui.*;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.border.CustomLineBorder;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBList;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.OnOffButton;
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.ui.popup.AbstractPopup;
import com.intellij.ui.popup.PopupPositionManager;
import com.intellij.util.*;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.Matcher;
import com.intellij.util.ui.EmptyIcon;
import com.intellij.util.ui.StatusText;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author Konstantin Bulenkov
 */
@SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized")
public class SearchEverywhereAction extends AnAction
        implements CustomComponentAction, DumbAware, DataProvider, RightAlignedToolbarAction {
    public static final String SE_HISTORY_KEY = "SearchEverywhereHistoryKey";
    public static final int SEARCH_FIELD_COLUMNS = 25;
    private static final int MAX_CLASSES = 6;
    private static final int MAX_FILES = 6;
    private static final int MAX_RUN_CONFIGURATION = 6;
    private static final int MAX_TOOL_WINDOWS = 4;
    private static final int MAX_SYMBOLS = 6;
    private static final int MAX_SETTINGS = 5;
    private static final int MAX_ACTIONS = 5;
    private static final int MAX_STRUCTURE = 10;
    private static final int MAX_RECENT_FILES = 10;
    private static final int DEFAULT_MORE_STEP_COUNT = 15;
    public static final int MAX_SEARCH_EVERYWHERE_HISTORY = 50;
    public static final int MAX_TOP_HIT = 15;
    private static final int POPUP_MAX_WIDTH = 600;
    private static final Logger LOG = Logger.getInstance(SearchEverywhereAction.class.getName());

    private SearchEverywhereAction.MyListRenderer myRenderer;
    MySearchTextField myPopupField;
    private volatile GotoClassModel2 myClassModel;
    private volatile GotoFileModel myFileModel;
    private volatile GotoActionItemProvider myActionProvider;
    private volatile GotoSymbolModel2 mySymbolsModel;
    private Component myFocusComponent;
    private JBPopup myPopup;
    private Map<String, String> myConfigurables = new HashMap<String, String>();

    private Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, ApplicationManager.getApplication());
    private Alarm myUpdateAlarm = new Alarm(ApplicationManager.getApplication());
    private JBList myList;
    private JCheckBox myNonProjectCheckBox;
    private AnActionEvent myActionEvent;
    private Component myContextComponent;
    private CalcThread myCalcThread;
    private static AtomicBoolean ourShiftIsPressed = new AtomicBoolean(false);
    private static AtomicBoolean showAll = new AtomicBoolean(false);
    private volatile ActionCallback myCurrentWorker = ActionCallback.DONE;
    private int myHistoryIndex = 0;
    boolean mySkipFocusGain = false;

    static {
        ModifierKeyDoubleClickHandler.getInstance().registerAction(IdeActions.ACTION_SEARCH_EVERYWHERE,
                KeyEvent.VK_SHIFT, -1);

        IdeEventQueue.getInstance().addPostprocessor(new IdeEventQueue.EventDispatcher() {
            @Override
            public boolean dispatch(AWTEvent event) {
                if (event instanceof KeyEvent) {
                    final int keyCode = ((KeyEvent) event).getKeyCode();
                    if (keyCode == KeyEvent.VK_SHIFT) {
                        ourShiftIsPressed.set(event.getID() == KeyEvent.KEY_PRESSED);
                    }
                }
                return false;
            }
        }, null);
    }

    private volatile JBPopup myBalloon;
    private int myPopupActualWidth;
    private Component myFocusOwner;
    private ChooseByNamePopup myFileChooseByName;
    private ChooseByNamePopup myClassChooseByName;
    private ChooseByNamePopup mySymbolsChooseByName;
    private StructureViewModel myStructureModel;

    private Editor myEditor;
    private FileEditor myFileEditor;
    private PsiFile myFile;
    private HistoryItem myHistoryItem;

    @Override
    public JComponent createCustomComponent(Presentation presentation) {
        JPanel panel = new JPanel(new BorderLayout()) {
            @Override
            protected void paintComponent(Graphics g) {
                if (myBalloon != null && !myBalloon.isDisposed() && myActionEvent != null
                        && myActionEvent.getInputEvent() instanceof MouseEvent) {
                    final Gradient gradient = getGradientColors();
                    ((Graphics2D) g).setPaint(new GradientPaint(0, 0, gradient.getStartColor(), 0, getHeight(),
                            gradient.getEndColor()));
                    g.fillRect(0, 0, getWidth(), getHeight());
                } else {
                    super.paintComponent(g);
                }
            }
        };
        panel.setOpaque(false);

        final JLabel label = new JBLabel(AllIcons.Actions.FindPlain) {
            {
                enableEvents(AWTEvent.MOUSE_EVENT_MASK);
                enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
            }
        };
        panel.add(label, BorderLayout.CENTER);
        initTooltip(label);
        label.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                if (myBalloon != null) {
                    myBalloon.cancel();
                }
                myFocusOwner = IdeFocusManager.findInstance().getFocusOwner();
                label.setToolTipText(null);
                IdeTooltipManager.getInstance().hideCurrentNow(false);
                label.setIcon(AllIcons.Actions.FindWhite);
                actionPerformed(null, e);
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                if (myBalloon == null || myBalloon.isDisposed()) {
                    label.setIcon(AllIcons.Actions.Find);
                }
            }

            @Override
            public void mouseExited(MouseEvent e) {
                if (myBalloon == null || myBalloon.isDisposed()) {
                    label.setIcon(AllIcons.Actions.FindPlain);
                }
            }
        });

        return panel;
    }

    private static Gradient getGradientColors() {
        return new Gradient(new JBColor(new Color(101, 147, 242), new Color(64, 80, 94)),
                new JBColor(new Color(46, 111, 205), new Color(53, 65, 87)));
    }

    public SearchEverywhereAction() {
        updateComponents();
        //noinspection SSBasedInspection
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                onFocusLost();
            }
        });

    }

    private void updateComponents() {
        myRenderer = new MyListRenderer();
        myList = new JBList() {
            @Override
            public Dimension getPreferredSize() {
                final Dimension size = super.getPreferredSize();
                return new Dimension(Math.max(myBalloon.getSize().width, Math.min(size.width - 2, POPUP_MAX_WIDTH)),
                        myList.isEmpty() ? 60 : size.height);
            }

            @Override
            public void clearSelection() {
                //avoid blinking
            }

            @Override
            public Object getSelectedValue() {
                try {
                    return super.getSelectedValue();
                } catch (Exception e) {
                    return null;
                }
            }
        };
        myList.setCellRenderer(myRenderer);
        myList.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                e.consume();
                final int i = myList.locationToIndex(e.getPoint());
                if (i != -1) {
                    mySkipFocusGain = true;
                    getField().requestFocus();
                    //noinspection SSBasedInspection
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            myList.setSelectedIndex(i);
                            doNavigate(i);
                        }
                    });
                }
            }
        });

        myNonProjectCheckBox = new JCheckBox();
        myNonProjectCheckBox.setOpaque(false);
        myNonProjectCheckBox.setAlignmentX(1.0f);
        myNonProjectCheckBox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (showAll.get() != myNonProjectCheckBox.isSelected()) {
                    showAll.set(!showAll.get());
                    final JTextField editor = UIUtil.findComponentOfType(myBalloon.getContent(), JTextField.class);
                    if (editor != null) {
                        final String pattern = editor.getText();
                        myAlarm.cancelAllRequests();
                        myAlarm.addRequest(new Runnable() {
                            @Override
                            public void run() {
                                if (editor.hasFocus()) {
                                    rebuildList(pattern);
                                }
                            }
                        }, 30);
                    }
                }
            }
        });
    }

    private static void initTooltip(JLabel label) {
        final String shortcutText;
        shortcutText = getShortcut();

        label.setToolTipText("<html><body>Search Everywhere<br/>Press <b>" + shortcutText
                + "</b> to access<br/> - Classes<br/> - Files<br/> - Tool Windows<br/> - Actions<br/> - Settings</body></html>");

    }

    @Nullable
    @Override
    public Object getData(@NonNls String dataId) {
        return null;
    }

    private static String getShortcut() {
        String shortcutText;
        final Shortcut[] shortcuts = KeymapManager.getInstance().getActiveKeymap()
                .getShortcuts(IdeActions.ACTION_SEARCH_EVERYWHERE);
        if (shortcuts.length == 0) {
            shortcutText = "Double " + (SystemInfo.isMac ? MacKeymapUtil.SHIFT : "Shift");
        } else {
            shortcutText = KeymapUtil.getShortcutsText(shortcuts);
        }
        return shortcutText;
    }

    private void initSearchField(final MySearchTextField search) {
        final JTextField editor = search.getTextEditor();
        //    onFocusLost();
        editor.getDocument().addDocumentListener(new DocumentAdapter() {
            @Override
            protected void textChanged(DocumentEvent e) {
                final String pattern = editor.getText();
                if (editor.hasFocus()) {
                    rebuildList(pattern);
                }
            }
        });
        editor.addFocusListener(new FocusAdapter() {
            @Override
            public void focusGained(FocusEvent e) {
                if (mySkipFocusGain) {
                    mySkipFocusGain = false;
                    return;
                }
                search.setText("");
                search.getTextEditor().setForeground(UIUtil.getLabelForeground());
                //titleIndex = new TitleIndexes();
                editor.setColumns(SEARCH_FIELD_COLUMNS);
                myFocusComponent = e.getOppositeComponent();
                //noinspection SSBasedInspection
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        final JComponent parent = (JComponent) editor.getParent();
                        parent.revalidate();
                        parent.repaint();
                    }
                });
                //if (myPopup != null && myPopup.isVisible()) {
                //  myPopup.cancel();
                //  myPopup = null;
                //}
                rebuildList("");
            }

            @Override
            public void focusLost(FocusEvent e) {
                if (myPopup instanceof AbstractPopup && myPopup.isVisible() && ((myList == e.getOppositeComponent())
                        || ((AbstractPopup) myPopup).getPopupWindow() == e.getOppositeComponent())) {
                    return;
                }
                if (myNonProjectCheckBox == e.getOppositeComponent()) {
                    mySkipFocusGain = true;
                    editor.requestFocus();
                    return;
                }
                onFocusLost();
            }
        });
    }

    private void jumpNextGroup(boolean forward) {
        final int index = myList.getSelectedIndex();
        final SearchListModel model = getModel();
        if (index >= 0) {
            final int newIndex = forward ? model.next(index) : model.prev(index);
            myList.setSelectedIndex(newIndex);
            int more = model.next(newIndex) - 1;
            if (more < newIndex) {
                more = myList.getItemsCount() - 1;
            }
            ListScrollingUtil.ensureIndexIsVisible(myList, more, forward ? 1 : -1);
            ListScrollingUtil.ensureIndexIsVisible(myList, newIndex, forward ? 1 : -1);
        }
    }

    private SearchListModel getModel() {
        return (SearchListModel) myList.getModel();
    }

    private ActionCallback onFocusLost() {
        final ActionCallback result = new ActionCallback();
        //noinspection SSBasedInspection
        UIUtil.invokeLaterIfNeeded(new Runnable() {
            @Override
            public void run() {
                try {
                    if (myCalcThread != null) {
                        myCalcThread.cancel();
                        //myCalcThread = null;
                    }
                    myAlarm.cancelAllRequests();
                    if (myBalloon != null && !myBalloon.isDisposed() && myPopup != null && !myPopup.isDisposed()) {
                        myBalloon.cancel();
                        myPopup.cancel();
                    }

                    //noinspection SSBasedInspection
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            ActionToolbarImpl.updateAllToolbarsImmediately();
                        }
                    });
                } finally {
                    result.setDone();
                }
            }
        });
        return result;
    }

    private SearchTextField getField() {
        return myPopupField;
    }

    private void doNavigate(final int index) {
        final Project project = CommonDataKeys.PROJECT
                .getData(DataManager.getInstance().getDataContext(getField().getTextEditor()));
        final Executor executor = ourShiftIsPressed.get() ? DefaultRunExecutor.getRunExecutorInstance()
                : ExecutorRegistry.getInstance().getExecutorById(ToolWindowId.DEBUG);
        assert project != null;
        final SearchListModel model = getModel();
        if (isMoreItem(index)) {
            final String pattern = myPopupField.getText();
            WidgetID wid = null;
            if (index == model.moreIndex.classes)
                wid = WidgetID.CLASSES;
            else if (index == model.moreIndex.files)
                wid = WidgetID.FILES;
            else if (index == model.moreIndex.settings)
                wid = WidgetID.SETTINGS;
            else if (index == model.moreIndex.actions)
                wid = WidgetID.ACTIONS;
            else if (index == model.moreIndex.symbols)
                wid = WidgetID.SYMBOLS;
            else if (index == model.moreIndex.runConfigurations)
                wid = WidgetID.RUN_CONFIGURATIONS;
            if (wid != null) {
                final WidgetID widgetID = wid;
                myCurrentWorker.doWhenProcessed(new Runnable() {
                    @Override
                    public void run() {
                        myCalcThread = new CalcThread(project, pattern, true);
                        myPopupActualWidth = 0;
                        myCurrentWorker = myCalcThread.insert(index, widgetID);
                    }
                });

                return;
            }
        }
        final String pattern = getField().getText();
        final Object value = myList.getSelectedValue();
        saveHistory(project, pattern, value);
        IdeFocusManager focusManager = IdeFocusManager.findInstanceByComponent(getField().getTextEditor());
        if (myPopup != null && myPopup.isVisible()) {
            myPopup.cancel();
        }

        if (value instanceof BooleanOptionDescription) {
            final BooleanOptionDescription option = (BooleanOptionDescription) value;
            option.setOptionState(!option.isOptionEnabled());
            myList.revalidate();
            myList.repaint();
            getField().requestFocus();
            return;
        }

        if (value instanceof OptionsTopHitProvider) {
            //noinspection SSBasedInspection
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    getField().setText("#" + ((OptionsTopHitProvider) value).getId() + " ");
                }
            });
            return;
        }
        Runnable onDone = null;

        AccessToken token = ApplicationManager.getApplication().acquireReadActionLock();
        try {
            if (value instanceof PsiElement) {
                onDone = new Runnable() {
                    @Override
                    public void run() {
                        NavigationUtil.activateFileWithPsiElement((PsiElement) value, true);
                    }
                };
                return;
            } else if (isVirtualFile(value)) {
                onDone = new Runnable() {
                    @Override
                    public void run() {
                        OpenSourceUtil.navigate(true, new OpenFileDescriptor(project, (VirtualFile) value));
                    }
                };
                return;
            } else if (isActionValue(value) || isSetting(value) || isRunConfiguration(value)) {
                focusManager.requestDefaultFocus(true);
                final Component comp = myContextComponent;
                final AnActionEvent event = myActionEvent;
                IdeFocusManager.getInstance(project).doWhenFocusSettlesDown(new Runnable() {
                    @Override
                    public void run() {
                        Component c = comp;
                        if (c == null) {
                            c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
                        }

                        if (isRunConfiguration(value)) {
                            ((ChooseRunConfigurationPopup.ItemWrapper) value).perform(project, executor,
                                    DataManager.getInstance().getDataContext(c));
                        } else {
                            GotoActionAction.openOptionOrPerformAction(value, pattern, project, c, event);
                            if (isToolWindowAction(value))
                                return;
                        }
                    }
                });
                return;
            } else if (value instanceof Navigatable) {
                onDone = new Runnable() {
                    @Override
                    public void run() {
                        OpenSourceUtil.navigate(true, (Navigatable) value);
                    }
                };
                return;
            }
        } finally {
            token.finish();
            final ActionCallback callback = onFocusLost();
            if (onDone != null) {
                callback.doWhenDone(onDone);
            }
        }
        focusManager.requestDefaultFocus(true);
    }

    private boolean isMoreItem(int index) {
        final SearchListModel model = getModel();
        return index == model.moreIndex.classes || index == model.moreIndex.files
                || index == model.moreIndex.settings || index == model.moreIndex.actions
                || index == model.moreIndex.symbols || index == model.moreIndex.runConfigurations;
    }

    private void rebuildList(final String pattern) {
        assert EventQueue.isDispatchThread() : "Must be EDT";
        if (myCalcThread != null && !myCurrentWorker.isProcessed()) {
            myCurrentWorker = myCalcThread.cancel();
        }
        if (myCalcThread != null && !myCalcThread.isCanceled()) {
            myCalcThread.cancel();
        }
        final Project project = CommonDataKeys.PROJECT
                .getData(DataManager.getInstance().getDataContext(getField().getTextEditor()));

        assert project != null;
        myRenderer.myProject = project;
        final Runnable run = new Runnable() {
            @Override
            public void run() {
                myCalcThread = new CalcThread(project, pattern, false);
                myPopupActualWidth = 0;
                myCurrentWorker = myCalcThread.start();
            }
        };
        if (myCurrentWorker.isDone()) {
            myCurrentWorker.doWhenDone(run);
        } else {
            myCurrentWorker.doWhenRejected(run);
        }
    }

    @Override
    public void actionPerformed(AnActionEvent e) {
        actionPerformed(e, null);
    }

    public void actionPerformed(AnActionEvent e, MouseEvent me) {
        if (myBalloon != null && myBalloon.isVisible()) {
            showAll.set(!showAll.get());
            myNonProjectCheckBox.setSelected(showAll.get());
            //      myPopupField.getTextEditor().setBackground(showAll.get() ? new JBColor(new Color(0xffffe4), new Color(0x494539)) : UIUtil.getTextFieldBackground());
            rebuildList(myPopupField.getText());
            return;
        }
        myCurrentWorker = ActionCallback.DONE;
        if (e != null) {
            myEditor = e.getData(CommonDataKeys.EDITOR);
            myFileEditor = e.getData(PlatformDataKeys.FILE_EDITOR);
            myFile = e.getData(CommonDataKeys.PSI_FILE);
        }
        if (e == null && myFocusOwner != null) {
            e = new AnActionEvent(me, DataManager.getInstance().getDataContext(myFocusOwner), ActionPlaces.UNKNOWN,
                    getTemplatePresentation(), ActionManager.getInstance(), 0);
        }
        if (e == null)
            return;
        final Project project = e.getProject();
        if (project == null)
            return;

        updateComponents();
        myContextComponent = PlatformDataKeys.CONTEXT_COMPONENT.getData(e.getDataContext());
        Window wnd = myContextComponent != null ? SwingUtilities.windowForComponent(myContextComponent)
                : KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow();
        if (wnd == null && myContextComponent instanceof Window) {
            wnd = (Window) myContextComponent;
        }
        if (wnd == null || wnd.getParent() != null)
            return;
        myActionEvent = e;
        if (myPopupField != null) {
            Disposer.dispose(myPopupField);
        }
        myPopupField = new MySearchTextField();
        myPopupField.getTextEditor().addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent e) {
                myHistoryIndex = 0;
                myHistoryItem = null;
            }

            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
                    myList.repaint();
                }
            }

            @Override
            public void keyReleased(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
                    myList.repaint();
                }
            }
        });
        initSearchField(myPopupField);
        myPopupField.setOpaque(false);
        final JTextField editor = myPopupField.getTextEditor();
        editor.setColumns(SEARCH_FIELD_COLUMNS);
        final JPanel panel = new JPanel(new BorderLayout()) {
            @Override
            protected void paintComponent(Graphics g) {
                final Gradient gradient = getGradientColors();
                ((Graphics2D) g).setPaint(
                        new GradientPaint(0, 0, gradient.getStartColor(), 0, getHeight(), gradient.getEndColor()));
                g.fillRect(0, 0, getWidth(), getHeight());
            }
        };
        final JLabel title = new JLabel(" Search Everywhere:       ");
        final JPanel topPanel = new NonOpaquePanel(new BorderLayout());
        title.setForeground(new JBColor(Gray._240, Gray._200));
        if (SystemInfo.isMac) {
            title.setFont(title.getFont().deriveFont(Font.BOLD, title.getFont().getSize() - 1f));
        } else {
            title.setFont(title.getFont().deriveFont(Font.BOLD));
        }
        topPanel.add(title, BorderLayout.WEST);
        final JPanel controls = new JPanel(new BorderLayout());
        controls.setOpaque(false);
        final JLabel settings = new JLabel(AllIcons.General.SearchEverywhereGear);
        new ClickListener() {
            @Override
            public boolean onClick(@NotNull MouseEvent event, int clickCount) {
                showSettings();
                return true;
            }
        }.installOn(settings);
        controls.add(settings, BorderLayout.EAST);
        myNonProjectCheckBox.setForeground(new JBColor(Gray._240, Gray._200));
        myNonProjectCheckBox.setText("Include non-project items (" + getShortcut() + ")  ");
        controls.add(myNonProjectCheckBox, BorderLayout.WEST);
        topPanel.add(controls, BorderLayout.EAST);
        panel.add(myPopupField, BorderLayout.CENTER);
        panel.add(topPanel, BorderLayout.NORTH);
        panel.setBorder(IdeBorderFactory.createEmptyBorder(3, 5, 4, 5));
        DataManager.registerDataProvider(panel, this);
        final ComponentPopupBuilder builder = JBPopupFactory.getInstance().createComponentPopupBuilder(panel,
                editor);
        myBalloon = builder.setCancelOnClickOutside(true).setModalContext(false).setRequestFocus(true)
                .setCancelCallback(new Computable<Boolean>() {
                    @Override
                    public Boolean compute() {
                        return !mySkipFocusGain;
                    }
                }).createPopup();
        myBalloon.getContent().setBorder(new EmptyBorder(0, 0, 0, 0));
        final Window window = WindowManager.getInstance().suggestParentWindow(project);

        project.getMessageBus().connect(myBalloon).subscribe(DumbService.DUMB_MODE,
                new DumbService.DumbModeListener() {
                    @Override
                    public void enteredDumbMode() {
                    }

                    @Override
                    public void exitDumbMode() {
                        rebuildList(myPopupField.getText());
                    }
                });

        Component parent = UIUtil.findUltimateParent(window);
        registerDataProvider(panel, project);
        final RelativePoint showPoint;
        if (me != null) {
            final Component label = me.getComponent();
            final Component button = label.getParent();
            assert button != null;
            showPoint = new RelativePoint(button,
                    new Point(button.getWidth() - panel.getPreferredSize().width, button.getHeight()));
        } else {
            if (parent != null) {
                int height = UISettings.getInstance().SHOW_MAIN_TOOLBAR ? 135 : 115;
                if (parent instanceof IdeFrameImpl && ((IdeFrameImpl) parent).isInFullScreen()) {
                    height -= 20;
                }
                showPoint = new RelativePoint(parent,
                        new Point((parent.getSize().width - panel.getPreferredSize().width) / 2, height));
            } else {
                showPoint = JBPopupFactory.getInstance().guessBestPopupLocation(e.getDataContext());
            }
        }
        myList.setFont(UIUtil.getListFont());
        myBalloon.show(showPoint);
        initSearchActions(myBalloon, myPopupField);
        IdeFocusManager focusManager = IdeFocusManager.getInstance(project);
        focusManager.requestFocus(editor, true);
        FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE);
    }

    private void showSettings() {
        myPopupField.setText("");
        final SearchListModel model = new SearchListModel();
        //model.addElement(new SEOption("Show current file structure elements", "search.everywhere.structure"));
        model.addElement(new SEOption("Show files", "search.everywhere.files"));
        model.addElement(new SEOption("Show symbols", "search.everywhere.symbols"));
        model.addElement(new SEOption("Show tool windows", "search.everywhere.toolwindows"));
        model.addElement(new SEOption("Show run configurations", "search.everywhere.configurations"));
        model.addElement(new SEOption("Show actions", "search.everywhere.actions"));
        model.addElement(new SEOption("Show IDE settings", "search.everywhere.settings"));

        if (myCalcThread != null && !myCurrentWorker.isProcessed()) {
            myCurrentWorker = myCalcThread.cancel();
        }
        if (myCalcThread != null && !myCalcThread.isCanceled()) {
            myCalcThread.cancel();
        }
        myCurrentWorker.doWhenProcessed(new Runnable() {
            @Override
            public void run() {
                myList.setModel(model);
                updatePopupBounds();
            }
        });
    }

    static class SEOption extends BooleanOptionDescription {
        private final String myKey;

        public SEOption(String option, String registryKey) {
            super(option, null);
            myKey = registryKey;
        }

        @Override
        public boolean isOptionEnabled() {
            return Registry.is(myKey);
        }

        @Override
        public void setOptionState(boolean enabled) {
            Registry.get(myKey).setValue(enabled);
        }
    }

    private static void saveHistory(Project project, String text, Object value) {
        if (project == null || project.isDisposed() || !project.isInitialized()) {
            return;
        }
        HistoryType type = null;
        String fqn = null;
        if (isActionValue(value)) {
            type = HistoryType.ACTION;
            AnAction action = (AnAction) (value instanceof GotoActionModel.ActionWrapper
                    ? ((GotoActionModel.ActionWrapper) value).getAction()
                    : value);
            fqn = ActionManager.getInstance().getId(action);
        } else if (value instanceof VirtualFile) {
            type = HistoryType.FILE;
            fqn = ((VirtualFile) value).getUrl();
        } else if (value instanceof ChooseRunConfigurationPopup.ItemWrapper) {
            type = HistoryType.RUN_CONFIGURATION;
            fqn = ((ChooseRunConfigurationPopup.ItemWrapper) value).getText();
        } else if (value instanceof PsiElement) {
            final PsiElement psiElement = (PsiElement) value;
            final Language language = psiElement.getLanguage();
            final String name = QualifiedNameProviders.getQualifiedNameFromProviders(psiElement);
            if (name != null) {
                type = HistoryType.PSI;
                fqn = language.getID() + "://" + name;
            }
        }

        final PropertiesComponent storage = PropertiesComponent.getInstance(project);
        final String[] values = storage.getValues(SE_HISTORY_KEY);
        List<HistoryItem> history = new ArrayList<HistoryItem>();
        if (values != null) {
            for (String s : values) {
                final String[] split = s.split("\t");
                if (split.length != 3 || text.equals(split[0])) {
                    continue;
                }
                if (!StringUtil.isEmpty(split[0])) {
                    history.add(new HistoryItem(split[0], split[1], split[2]));
                }
            }
        }
        history.add(0, new HistoryItem(text, type == null ? null : type.name(), fqn));

        if (history.size() > MAX_SEARCH_EVERYWHERE_HISTORY) {
            history = history.subList(0, MAX_SEARCH_EVERYWHERE_HISTORY);
        }
        final String[] newValues = new String[history.size()];
        for (int i = 0; i < newValues.length; i++) {
            newValues[i] = history.get(i).toString();
        }
        storage.setValues(SE_HISTORY_KEY, newValues);
    }

    public Executor getExecutor() {
        return ourShiftIsPressed.get() ? DefaultRunExecutor.getRunExecutorInstance()
                : ExecutorRegistry.getInstance().getExecutorById(ToolWindowId.DEBUG);
    }

    private void registerDataProvider(JPanel panel, final Project project) {
        DataManager.registerDataProvider(panel, new DataProvider() {
            @Nullable
            @Override
            public Object getData(@NonNls String dataId) {
                final Object value = myList.getSelectedValue();
                if (CommonDataKeys.PSI_ELEMENT.is(dataId) && value instanceof PsiElement) {
                    return value;
                } else if (CommonDataKeys.VIRTUAL_FILE.is(dataId) && value instanceof VirtualFile) {
                    return value;
                } else if (CommonDataKeys.NAVIGATABLE.is(dataId)) {
                    if (value instanceof Navigatable)
                        return value;
                    if (value instanceof ChooseRunConfigurationPopup.ItemWrapper) {
                        final Object config = ((ChooseRunConfigurationPopup.ItemWrapper) value).getValue();
                        if (config instanceof RunnerAndConfigurationSettings) {
                            return new Navigatable() {
                                @Override
                                public void navigate(boolean requestFocus) {
                                    RunDialog.editConfiguration(project, (RunnerAndConfigurationSettings) config,
                                            "Edit Configuration", getExecutor());
                                }

                                @Override
                                public boolean canNavigate() {
                                    return true;
                                }

                                @Override
                                public boolean canNavigateToSource() {
                                    return true;
                                }
                            };
                        }
                    }
                }
                return null;
            }
        });
    }

    private void initSearchActions(JBPopup balloon, MySearchTextField searchTextField) {
        final JTextField editor = searchTextField.getTextEditor();
        new DumbAwareAction() {
            @Override
            public void actionPerformed(AnActionEvent e) {
                jumpNextGroup(true);
            }
        }.registerCustomShortcutSet(CustomShortcutSet.fromString("TAB"), editor, balloon);
        new DumbAwareAction() {
            @Override
            public void actionPerformed(AnActionEvent e) {
                jumpNextGroup(false);
            }
        }.registerCustomShortcutSet(CustomShortcutSet.fromString("shift TAB"), editor, balloon);
        new DumbAwareAction() {
            @Override
            public void actionPerformed(AnActionEvent e) {
                if (myBalloon != null && myBalloon.isVisible()) {
                    myBalloon.cancel();
                }
                if (myPopup != null && myPopup.isVisible()) {
                    myPopup.cancel();
                }
            }
        }.registerCustomShortcutSet(CustomShortcutSet.fromString("ESCAPE"), editor, balloon);
        new DumbAwareAction() {
            @Override
            public void actionPerformed(AnActionEvent e) {
                final int index = myList.getSelectedIndex();
                if (index != -1) {
                    doNavigate(index);
                }
            }
        }.registerCustomShortcutSet(CustomShortcutSet.fromString("ENTER", "shift ENTER"), editor, balloon);
        new DumbAwareAction() {
            @Override
            public void actionPerformed(AnActionEvent e) {
                final PropertiesComponent storage = PropertiesComponent.getInstance(e.getProject());
                final String[] values = storage.getValues(SE_HISTORY_KEY);
                if (values != null) {
                    if (values.length > myHistoryIndex) {
                        final List<String> data = StringUtil.split(values[myHistoryIndex], "\t");
                        myHistoryItem = new HistoryItem(data.get(0), data.get(1), data.get(2));
                        myHistoryIndex++;
                        editor.setText(myHistoryItem.pattern);
                        editor.setCaretPosition(myHistoryItem.pattern.length());
                        editor.moveCaretPosition(0);
                    }
                }
            }

            @Override
            public void update(AnActionEvent e) {
                e.getPresentation().setEnabled(editor.getCaretPosition() == 0);
            }
        }.registerCustomShortcutSet(CustomShortcutSet.fromString("LEFT"), editor, balloon);
    }

    private static class MySearchTextField extends SearchTextField implements DataProvider, Disposable {
        public MySearchTextField() {
            super(false);
            getTextEditor().setOpaque(false);
            getTextEditor().putClientProperty("JTextField.Search.noBorderRing", Boolean.TRUE);
            if (UIUtil.isUnderDarkBuildInLaf()) {
                getTextEditor().setBackground(Gray._45);
                getTextEditor().setForeground(Gray._240);
            }
        }

        @Override
        protected boolean isSearchControlUISupported() {
            return true;
        }

        @Override
        protected boolean hasIconsOutsideOfTextField() {
            return false;
        }

        @Override
        protected void showPopup() {
        }

        @Nullable
        @Override
        public Object getData(@NonNls String dataId) {
            if (PlatformDataKeys.PREDEFINED_TEXT.is(dataId)) {
                return getTextEditor().getText();
            }
            return null;
        }

        @Override
        public void dispose() {
        }
    }

    private class MyListRenderer extends ColoredListCellRenderer {
        ColoredListCellRenderer myLocation = new ColoredListCellRenderer() {
            @Override
            protected void customizeCellRenderer(JList list, Object value, int index, boolean selected,
                    boolean hasFocus) {
                setPaintFocusBorder(false);
                append(myLocationString, SimpleTextAttributes.GRAYED_ATTRIBUTES);
                setIcon(myLocationIcon);
            }
        };
        SearchEverywherePsiRenderer myFileRenderer = new SearchEverywherePsiRenderer(myList);

        private String myLocationString;
        private DefaultPsiElementCellRenderer myPsiRenderer = new DefaultPsiElementCellRenderer() {
            {
                setFocusBorderEnabled(false);
            }
        };
        private Icon myLocationIcon;
        private Project myProject;
        private JPanel myMainPanel = new JPanel(new BorderLayout());
        private JLabel myTitle = new JLabel();

        @Override
        public void clear() {
            super.clear();
            myLocation.clear();
            myLocationString = null;
            myLocationIcon = null;
        }

        public void setLocationString(String locationString) {
            myLocationString = locationString;
        }

        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
                boolean cellHasFocus) {
            Component cmp;
            PsiElement file;
            myLocationString = null;
            String pattern = "*" + myPopupField.getText();
            Matcher matcher = NameUtil.buildMatcher(pattern, 0, true, true, pattern.toLowerCase().equals(pattern));
            if (isMoreItem(index)) {
                cmp = More.get(isSelected);
            } else if (value instanceof VirtualFile && myProject != null && ((((VirtualFile) value).isDirectory()
                    && (file = PsiManager.getInstance(myProject).findDirectory((VirtualFile) value)) != null)
                    || (file = PsiManager.getInstance(myProject).findFile((VirtualFile) value)) != null)) {
                myFileRenderer.setPatternMatcher(matcher);
                cmp = myFileRenderer.getListCellRendererComponent(list, file, index, isSelected, cellHasFocus);
            } else if (value instanceof PsiElement) {
                myFileRenderer.setPatternMatcher(matcher);
                cmp = myFileRenderer.getListCellRendererComponent(list, value, index, isSelected, isSelected);
            } else {
                cmp = super.getListCellRendererComponent(list, value, index, isSelected, isSelected);
                final JPanel p = new JPanel(new BorderLayout());
                p.setBackground(UIUtil.getListBackground(isSelected));
                p.add(cmp, BorderLayout.CENTER);
                cmp = p;
            }
            if (myLocationString != null || value instanceof BooleanOptionDescription) {
                final JPanel panel = new JPanel(new BorderLayout());
                panel.setBackground(UIUtil.getListBackground(isSelected));
                panel.add(cmp, BorderLayout.CENTER);
                final Component rightComponent;
                if (value instanceof BooleanOptionDescription) {
                    final OnOffButton button = new OnOffButton();
                    button.setSelected(((BooleanOptionDescription) value).isOptionEnabled());
                    rightComponent = button;
                } else {
                    rightComponent = myLocation.getListCellRendererComponent(list, value, index, isSelected,
                            isSelected);
                }
                panel.add(rightComponent, BorderLayout.EAST);
                cmp = panel;
            }

            Color bg = cmp.getBackground();
            if (bg == null) {
                cmp.setBackground(UIUtil.getListBackground(isSelected));
                bg = cmp.getBackground();
            }
            myMainPanel.setBorder(new CustomLineBorder(bg, 0, 0, 2, 0));
            String title = getModel().titleIndex.getTitle(index);
            myMainPanel.removeAll();
            if (title != null) {
                myTitle.setText(title);
                myMainPanel.add(createTitle(" " + title), BorderLayout.NORTH);
            }
            myMainPanel.add(cmp, BorderLayout.CENTER);
            final int width = myMainPanel.getPreferredSize().width;
            if (width > myPopupActualWidth) {
                myPopupActualWidth = width;
                //schedulePopupUpdate();
            }
            return myMainPanel;
        }

        @Override
        protected void customizeCellRenderer(JList list, Object value, int index, boolean selected,
                boolean hasFocus) {
            setPaintFocusBorder(false);
            setIcon(EmptyIcon.ICON_16);
            AccessToken token = ApplicationManager.getApplication().acquireReadActionLock();
            try {
                if (value instanceof PsiElement) {
                    String name = myClassModel.getElementName(value);
                    assert name != null;
                    append(name);
                } else if (value instanceof ChooseRunConfigurationPopup.ItemWrapper) {
                    final ChooseRunConfigurationPopup.ItemWrapper wrapper = (ChooseRunConfigurationPopup.ItemWrapper) value;
                    append(wrapper.getText());
                    setIcon(wrapper.getIcon());
                    setLocationString(ourShiftIsPressed.get() ? "Run" : "Debug");
                    myLocationIcon = ourShiftIsPressed.get() ? AllIcons.Toolwindows.ToolWindowRun
                            : AllIcons.Toolwindows.ToolWindowDebugger;
                } else if (isVirtualFile(value)) {
                    final VirtualFile file = (VirtualFile) value;
                    if (file instanceof VirtualFilePathWrapper) {
                        append(((VirtualFilePathWrapper) file).getPresentablePath());
                    } else {
                        append(file.getName());
                    }
                    setIcon(IconUtil.getIcon(file, Iconable.ICON_FLAG_READ_STATUS, myProject));
                } else if (isActionValue(value)) {
                    final GotoActionModel.ActionWrapper actionWithParentGroup = value instanceof GotoActionModel.ActionWrapper
                            ? (GotoActionModel.ActionWrapper) value
                            : null;
                    final AnAction anAction = actionWithParentGroup == null ? (AnAction) value
                            : actionWithParentGroup.getAction();
                    final Presentation templatePresentation = anAction.getTemplatePresentation();
                    Icon icon = templatePresentation.getIcon();
                    if (anAction instanceof ActivateToolWindowAction) {
                        final String id = ((ActivateToolWindowAction) anAction).getToolWindowId();
                        ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(id);
                        if (toolWindow != null) {
                            icon = toolWindow.getIcon();
                        }
                    }

                    append(templatePresentation.getText());
                    if (actionWithParentGroup != null) {
                        final String groupName = actionWithParentGroup.getGroupName();
                        if (!StringUtil.isEmpty(groupName)) {
                            setLocationString(groupName);
                        }
                    }

                    final String groupName = actionWithParentGroup == null ? null
                            : actionWithParentGroup.getGroupName();
                    if (!StringUtil.isEmpty(groupName)) {
                        setLocationString(groupName);
                    }
                    if (icon != null && icon.getIconWidth() <= 16 && icon.getIconHeight() <= 16) {
                        setIcon(IconUtil.toSize(icon, 16, 16));
                    }
                } else if (isSetting(value)) {
                    String text = getSettingText((OptionDescription) value);
                    append(text);
                    final String id = ((OptionDescription) value).getConfigurableId();
                    final String name = myConfigurables.get(id);
                    if (name != null) {
                        setLocationString(name);
                    }
                } else if (value instanceof OptionsTopHitProvider) {
                    append("#" + ((OptionsTopHitProvider) value).getId());
                } else {
                    ItemPresentation presentation = null;
                    if (value instanceof ItemPresentation) {
                        presentation = (ItemPresentation) value;
                    } else if (value instanceof NavigationItem) {
                        presentation = ((NavigationItem) value).getPresentation();
                    }
                    if (presentation != null) {
                        final String text = presentation.getPresentableText();
                        append(text == null ? value.toString() : text);
                        final String location = presentation.getLocationString();
                        if (!StringUtil.isEmpty(location)) {
                            setLocationString(location);
                        }
                        Icon icon = presentation.getIcon(false);
                        if (icon != null)
                            setIcon(icon);
                    }
                }
            } finally {
                token.finish();
            }
        }

        public void recalculateWidth() {
            ListModel model = myList.getModel();
            myTitle.setIcon(EmptyIcon.ICON_16);
            myTitle.setFont(getTitleFont());
            int index = 0;
            while (index < model.getSize()) {
                String title = getModel().titleIndex.getTitle(index);
                if (title != null) {
                    myTitle.setText(title);
                }
                index++;
            }

            myTitle.setForeground(Gray._122);
            myTitle.setAlignmentY(BOTTOM_ALIGNMENT);
        }
    }

    private static String getSettingText(OptionDescription value) {
        String hit = value.getHit();
        if (hit == null) {
            hit = value.getOption();
        }
        hit = StringUtil.unescapeXml(hit);
        if (hit.length() > 60) {
            hit = hit.substring(0, 60) + "...";
        }
        hit = hit.replace("  ", " "); //avoid extra spaces from mnemonics and xml conversion
        String text = hit.trim();
        if (text.endsWith(":")) {
            text = text.substring(0, text.length() - 1);
        }
        return text;
    }

    private static boolean isActionValue(Object o) {
        return o instanceof GotoActionModel.ActionWrapper || o instanceof AnAction;
    }

    private static boolean isSetting(Object o) {
        return o instanceof OptionDescription;
    }

    private static boolean isRunConfiguration(Object o) {
        return o instanceof ChooseRunConfigurationPopup.ItemWrapper;
    }

    private static boolean isVirtualFile(Object o) {
        return o instanceof VirtualFile;
    }

    private static Font getTitleFont() {
        return UIUtil.getLabelFont().deriveFont(UIUtil.getFontSize(UIUtil.FontSize.SMALL));
    }

    enum WidgetID {
        CLASSES, FILES, ACTIONS, SETTINGS, SYMBOLS, RUN_CONFIGURATIONS
    }

    @SuppressWarnings("SSBasedInspection")
    private class CalcThread implements Runnable {
        private final Project project;
        private final String pattern;
        private final ProgressIndicator myProgressIndicator = new ProgressIndicatorBase();
        private final ActionCallback myDone = new ActionCallback();
        private final SearchListModel myListModel;
        private final ArrayList<VirtualFile> myAlreadyAddedFiles = new ArrayList<VirtualFile>();
        private final ArrayList<AnAction> myAlreadyAddedActions = new ArrayList<AnAction>();

        public CalcThread(Project project, String pattern, boolean reuseModel) {
            this.project = project;
            this.pattern = pattern;
            myListModel = reuseModel ? (SearchListModel) myList.getModel() : new SearchListModel();
        }

        @Override
        public void run() {
            try {
                check();

                //noinspection SSBasedInspection
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        // this line must be called on EDT to avoid context switch at clear().append("text") Don't touch. Ask [kb]
                        myList.getEmptyText().setText("Searching...");

                        if (myList.getModel() instanceof SearchListModel) {
                            //noinspection unchecked
                            myAlarm.cancelAllRequests();
                            myAlarm.addRequest(new Runnable() {
                                @Override
                                public void run() {
                                    if (!myDone.isRejected()) {
                                        myList.setModel(myListModel);
                                        updatePopup();
                                    }
                                }
                            }, 50);
                        } else {
                            myList.setModel(myListModel);
                        }
                    }
                });

                if (pattern.trim().length() == 0) {
                    buildModelFromRecentFiles();
                    updatePopup();
                    return;
                }

                checkModelsUpToDate();
                check();
                buildTopHit(pattern);
                check();

                if (!pattern.startsWith("#")) {
                    buildRecentFiles(pattern);
                    check();
                    runReadAction(new Runnable() {
                        @Override
                        public void run() {
                            buildStructure(pattern);
                        }
                    }, true);
                    updatePopup();
                    check();
                    buildToolWindows(pattern);
                    check();
                    updatePopup();
                    check();

                    runReadAction(new Runnable() {
                        @Override
                        public void run() {
                            buildRunConfigurations(pattern);
                        }
                    }, true);
                    runReadAction(new Runnable() {
                        @Override
                        public void run() {
                            buildClasses(pattern);
                        }
                    }, true);
                    runReadAction(new Runnable() {
                        @Override
                        public void run() {
                            buildFiles(pattern);
                        }
                    }, false);
                    runReadAction(new Runnable() {
                        @Override
                        public void run() {
                            buildSymbols(pattern);
                        }
                    }, true);

                    buildActionsAndSettings(pattern);

                    updatePopup();

                }
                updatePopup();
            } catch (ProcessCanceledException ignore) {
                myDone.setRejected();
            } catch (Exception e) {
                LOG.error(e);
                myDone.setRejected();
            } finally {
                if (!isCanceled()) {
                    //noinspection SSBasedInspection
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            myList.getEmptyText().setText(StatusText.DEFAULT_EMPTY_TEXT);
                        }
                    });
                    updatePopup();
                }
                if (!myDone.isProcessed()) {
                    myDone.setDone();
                }
            }
        }

        private void runReadAction(Runnable action, boolean checkDumb) {
            if (!checkDumb || !DumbService.getInstance(project).isDumb()) {
                ApplicationManager.getApplication().runReadAction(action);
                updatePopup();
            }
        }

        protected void check() {
            myProgressIndicator.checkCanceled();
            if (myDone.isRejected())
                throw new ProcessCanceledException();
            if (myBalloon == null || myBalloon.isDisposed())
                throw new ProcessCanceledException();
        }

        private synchronized void buildToolWindows(String pattern) {
            if (!Registry.is("search.everywhere.toolwindows")) {
                return;
            }
            final List<ActivateToolWindowAction> actions = new ArrayList<ActivateToolWindowAction>();
            for (ActivateToolWindowAction action : ToolWindowsGroup.getToolWindowActions(project)) {
                String text = action.getTemplatePresentation().getText();
                if (text != null && StringUtil.startsWithIgnoreCase(text, pattern)) {
                    actions.add(action);

                    if (actions.size() == MAX_TOOL_WINDOWS) {
                        break;
                    }
                }
            }

            check();

            if (actions.isEmpty()) {
                return;
            }

            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    myListModel.titleIndex.toolWindows = myListModel.size();
                    for (Object toolWindow : actions) {
                        myListModel.addElement(toolWindow);
                    }
                }
            });
        }

        private SearchResult getActionsOrSettings(final String pattern, final int max, final boolean actions) {
            final SearchResult result = new SearchResult();
            if ((actions && !Registry.is("search.everywhere.actions"))
                    || (!actions && !Registry.is("search.everywhere.settings"))) {
                return result;
            }
            final MinusculeMatcher matcher = new MinusculeMatcher("*" + pattern,
                    NameUtil.MatchingCaseSensitivity.NONE);
            if (myActionProvider == null) {
                myActionProvider = createActionProvider();
            }

            myActionProvider.filterElements(pattern, true, new Processor<GotoActionModel.MatchedValue>() {
                @Override
                public boolean process(GotoActionModel.MatchedValue matched) {
                    check();
                    Object object = matched.value;
                    if (myListModel.contains(object))
                        return true;

                    if (!actions && isSetting(object)) {
                        if (matcher.matches(getSettingText((OptionDescription) object))) {
                            result.add(object);
                        }
                    } else if (actions && !isToolWindowAction(object) && isActionValue(object)) {
                        result.add(object);
                    }
                    return result.size() <= max;
                }
            });

            return result;
        }

        private synchronized void buildActionsAndSettings(String pattern) {
            final SearchResult actions = getActionsOrSettings(pattern, MAX_ACTIONS, true);
            final SearchResult settings = getActionsOrSettings(pattern, MAX_SETTINGS, false);

            check();

            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    if (isCanceled())
                        return;
                    if (actions.size() > 0) {
                        myListModel.titleIndex.actions = myListModel.size();
                        for (Object action : actions) {
                            myListModel.addElement(action);
                        }
                    }
                    myListModel.moreIndex.actions = actions.size() >= MAX_ACTIONS ? myListModel.size() - 1 : -1;
                    if (settings.size() > 0) {
                        myListModel.titleIndex.settings = myListModel.size();
                        for (Object setting : settings) {
                            myListModel.addElement(setting);
                        }
                    }
                    myListModel.moreIndex.settings = settings.size() >= MAX_SETTINGS ? myListModel.size() - 1 : -1;
                }
            });
        }

        private synchronized void buildFiles(final String pattern) {
            final SearchResult files = getFiles(pattern, MAX_FILES, myFileChooseByName);

            check();

            if (files.size() > 0) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        if (isCanceled())
                            return;
                        myListModel.titleIndex.files = myListModel.size();
                        for (Object file : files) {
                            myListModel.addElement(file);
                        }
                        myListModel.moreIndex.files = files.needMore ? myListModel.size() - 1 : -1;
                    }
                });
            }
        }

        private synchronized void buildStructure(final String pattern) {
            if (!Registry.is("search.everywhere.structure") || myStructureModel == null)
                return;
            final List<StructureViewTreeElement> elements = new ArrayList<StructureViewTreeElement>();
            final MinusculeMatcher matcher = new MinusculeMatcher("*" + pattern,
                    NameUtil.MatchingCaseSensitivity.NONE);
            fillStructure(myStructureModel.getRoot(), elements, matcher);
            if (elements.size() > 0) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        if (isCanceled())
                            return;
                        myListModel.titleIndex.structure = myListModel.size();
                        for (Object element : elements) {
                            myListModel.addElement(element);
                        }
                        myListModel.moreIndex.files = -1;
                    }
                });
            }
        }

        private void fillStructure(StructureViewTreeElement element, List<StructureViewTreeElement> elements,
                Matcher matcher) {
            final TreeElement[] children = element.getChildren();
            check();
            for (TreeElement child : children) {
                check();
                if (child instanceof StructureViewTreeElement) {
                    final String text = child.getPresentation().getPresentableText();
                    if (text != null && matcher.matches(text)) {
                        elements.add((StructureViewTreeElement) child);
                    }
                    fillStructure((StructureViewTreeElement) child, elements, matcher);
                }
            }
        }

        private synchronized void buildSymbols(final String pattern) {
            final SearchResult symbols = getSymbols(pattern, MAX_SYMBOLS, mySymbolsChooseByName);
            check();

            if (symbols.size() > 0) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        if (isCanceled())
                            return;
                        myListModel.titleIndex.symbols = myListModel.size();
                        for (Object file : symbols) {
                            myListModel.addElement(file);
                        }
                        myListModel.moreIndex.symbols = symbols.needMore ? myListModel.size() - 1 : -1;
                    }
                });
            }
        }

        @Nullable
        private ChooseRunConfigurationPopup.ItemWrapper getRunConfigurationByName(String name) {
            final ChooseRunConfigurationPopup.ItemWrapper[] wrappers = ChooseRunConfigurationPopup
                    .createSettingsList(project, new ExecutorProvider() {
                        @Override
                        public Executor getExecutor() {
                            return ExecutorRegistry.getInstance().getExecutorById(ToolWindowId.DEBUG);
                        }
                    }, false);

            for (ChooseRunConfigurationPopup.ItemWrapper wrapper : wrappers) {
                if (wrapper.getText().equals(name)) {
                    return wrapper;
                }
            }
            return null;
        }

        private synchronized void buildRunConfigurations(String pattern) {
            final SearchResult runConfigurations = getConfigurations(pattern, MAX_RUN_CONFIGURATION);

            if (runConfigurations.size() > 0) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        if (isCanceled())
                            return;
                        myListModel.titleIndex.runConfigurations = myListModel.size();
                        for (Object runConfiguration : runConfigurations) {
                            myListModel.addElement(runConfiguration);
                        }
                        myListModel.moreIndex.runConfigurations = runConfigurations.needMore
                                ? myListModel.getSize() - 1
                                : -1;
                    }
                });
            }
        }

        private SearchResult getConfigurations(String pattern, int max) {
            SearchResult configurations = new SearchResult();
            if (!Registry.is("search.everywhere.configurations")) {
                return configurations;
            }
            MinusculeMatcher matcher = new MinusculeMatcher(pattern, NameUtil.MatchingCaseSensitivity.NONE);
            final ChooseRunConfigurationPopup.ItemWrapper[] wrappers = ChooseRunConfigurationPopup
                    .createSettingsList(project, new ExecutorProvider() {
                        @Override
                        public Executor getExecutor() {
                            return ExecutorRegistry.getInstance().getExecutorById(ToolWindowId.DEBUG);
                        }
                    }, false);
            check();
            for (ChooseRunConfigurationPopup.ItemWrapper wrapper : wrappers) {
                if (matcher.matches(wrapper.getText()) && !myListModel.contains(wrapper)) {
                    if (configurations.size() == max) {
                        configurations.needMore = true;
                        break;
                    }
                    configurations.add(wrapper);
                }
                check();
            }

            return configurations;
        }

        private synchronized void buildClasses(final String pattern) {
            final SearchResult classes = getClasses(pattern, showAll.get(), MAX_CLASSES, myClassChooseByName);
            check();

            if (classes.size() > 0) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        if (isCanceled())
                            return;
                        myListModel.titleIndex.classes = myListModel.size();
                        for (Object file : classes) {
                            myListModel.addElement(file);
                        }
                        myListModel.moreIndex.classes = -1;
                        if (classes.needMore) {
                            myListModel.moreIndex.classes = myListModel.size() - 1;
                        }
                    }
                });
            }
        }

        private SearchResult getSymbols(String pattern, final int max, ChooseByNamePopup chooseByNamePopup) {
            final SearchResult symbols = new SearchResult();
            if (!Registry.is("search.everywhere.symbols")) {
                return symbols;
            }
            final GlobalSearchScope scope = GlobalSearchScope.projectScope(project);
            if (chooseByNamePopup == null)
                return symbols;
            final ChooseByNameItemProvider provider = chooseByNamePopup.getProvider();
            provider.filterElements(chooseByNamePopup, pattern, false, myProgressIndicator,
                    new Processor<Object>() {
                        @Override
                        public boolean process(Object o) {
                            if (o instanceof PsiElement && !(((PsiElement) o).getParent() instanceof PsiFile)) {
                                final PsiElement element = (PsiElement) o;
                                final PsiFile file = element.getContainingFile();
                                if (!myListModel.contains(o) &&
                                //some elements are non-physical like DB columns
                                (file == null || (file.getVirtualFile() != null
                                        && scope.accept(file.getVirtualFile())))) {
                                    symbols.add(o);
                                }
                            }
                            symbols.needMore = symbols.size() == max;
                            return !symbols.needMore;
                        }
                    });
            return symbols;
        }

        private SearchResult getClasses(String pattern, boolean includeLibs, final int max,
                ChooseByNamePopup chooseByNamePopup) {
            final SearchResult classes = new SearchResult();
            if (chooseByNamePopup == null) {
                return classes;
            }
            chooseByNamePopup.getProvider().filterElements(chooseByNamePopup, pattern, includeLibs,
                    myProgressIndicator, new Processor<Object>() {
                        @Override
                        public boolean process(Object o) {
                            if (o instanceof PsiElement && !myListModel.contains(o) && !classes.contains(o)) {
                                if (classes.size() == max) {
                                    classes.needMore = true;
                                    return false;
                                }
                                classes.add(o);
                                if (o instanceof PsiNamedElement) {
                                    final String name = ((PsiNamedElement) o).getName();
                                    final PsiFile file = ((PsiNamedElement) o).getContainingFile();
                                    if (file != null) {
                                        final VirtualFile virtualFile = file.getVirtualFile();
                                        if (StringUtil.equals(name, virtualFile.getNameWithoutExtension())) {
                                            myAlreadyAddedFiles.add(virtualFile);
                                        }
                                    }
                                }
                            }
                            return true;
                        }
                    });
            if (!includeLibs && classes.isEmpty()) {
                return getClasses(pattern, true, max, chooseByNamePopup);
            }
            return classes;
        }

        private SearchResult getFiles(final String pattern, final int max, ChooseByNamePopup chooseByNamePopup) {
            final SearchResult files = new SearchResult();
            if (chooseByNamePopup == null || !Registry.is("search.everywhere.files")) {
                return files;
            }
            final GlobalSearchScope scope = GlobalSearchScope.projectScope(project);
            chooseByNamePopup.getProvider().filterElements(chooseByNamePopup, pattern, true, myProgressIndicator,
                    new Processor<Object>() {
                        @Override
                        public boolean process(Object o) {
                            VirtualFile file = null;
                            if (o instanceof VirtualFile) {
                                file = (VirtualFile) o;
                            } else if (o instanceof PsiFile) {
                                file = ((PsiFile) o).getVirtualFile();
                            } else if (o instanceof PsiDirectory) {
                                file = ((PsiDirectory) o).getVirtualFile();
                            }
                            if (file != null && !(pattern.indexOf(' ') != -1 && file.getName().indexOf(' ') == -1)
                                    && (showAll.get() || scope.accept(file) && !myListModel.contains(file)
                                            && !myAlreadyAddedFiles.contains(file))
                                    && !files.contains(file)) {
                                if (files.size() == max) {
                                    files.needMore = true;
                                    return false;
                                }
                                files.add(file);
                            }
                            return true;
                        }
                    });
            return files;
        }

        private synchronized void buildRecentFiles(String pattern) {
            final MinusculeMatcher matcher = new MinusculeMatcher("*" + pattern,
                    NameUtil.MatchingCaseSensitivity.NONE);
            final ArrayList<VirtualFile> files = new ArrayList<VirtualFile>();
            final List<VirtualFile> selected = Arrays
                    .asList(FileEditorManager.getInstance(project).getSelectedFiles());
            for (VirtualFile file : ArrayUtil.reverseArray(EditorHistoryManager.getInstance(project).getFiles())) {
                if (StringUtil.isEmptyOrSpaces(pattern) || matcher.matches(file.getName())) {
                    if (!files.contains(file) && !selected.contains(file)) {
                        files.add(file);
                    }
                }
                if (files.size() > MAX_RECENT_FILES)
                    break;
            }

            if (files.size() > 0) {
                myAlreadyAddedFiles.addAll(files);

                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        if (isCanceled())
                            return;
                        myListModel.titleIndex.recentFiles = myListModel.size();
                        for (Object file : files) {
                            myListModel.addElement(file);
                        }
                    }
                });
            }
        }

        private boolean isCanceled() {
            return myProgressIndicator.isCanceled() || myDone.isRejected();
        }

        private synchronized void buildTopHit(String pattern) {
            final List<Object> elements = new ArrayList<Object>();
            final HistoryItem history = myHistoryItem;
            if (history != null) {
                final HistoryType type = parseHistoryType(history.type);
                if (type != null) {
                    switch (type) {
                    case PSI:
                        if (!DumbService.isDumb(project)) {
                            ApplicationManager.getApplication().runReadAction(new Runnable() {
                                @Override
                                public void run() {

                                    final int i = history.fqn.indexOf("://");
                                    if (i != -1) {
                                        final String langId = history.fqn.substring(0, i);
                                        final Language language = Language.findLanguageByID(langId);
                                        final String psiFqn = history.fqn.substring(i + 3);
                                        if (language != null) {
                                            Pair<PsiElement, QualifiedNameProvider> pair = QualifiedNameProviders
                                                    .findElementByQualifiedName(psiFqn, project);
                                            final PsiElement psi = pair == null ? null : pair.getFirst();
                                            if (psi != null) {
                                                elements.add(psi);
                                                final PsiFile psiFile = psi.getContainingFile();
                                                if (psiFile != null) {
                                                    final VirtualFile file = psiFile.getVirtualFile();
                                                    if (file != null) {
                                                        myAlreadyAddedFiles.add(file);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            });
                        }
                        break;
                    case FILE:
                        final VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(history.fqn);
                        if (file != null) {
                            elements.add(file);
                        }
                        break;
                    case SETTING:
                        break;
                    case ACTION:
                        final AnAction action = ActionManager.getInstance().getAction(history.fqn);
                        if (action != null) {
                            elements.add(action);
                            myAlreadyAddedActions.add(action);
                        }
                        break;
                    case RUN_CONFIGURATION:
                        if (!DumbService.isDumb(project)) {
                            ApplicationManager.getApplication().runReadAction(new Runnable() {
                                @Override
                                public void run() {
                                    final ChooseRunConfigurationPopup.ItemWrapper runConfiguration = getRunConfigurationByName(
                                            history.fqn);
                                    if (runConfiguration != null) {
                                        elements.add(runConfiguration);
                                    }
                                }
                            });
                        }
                        break;
                    }
                }
            }
            final Consumer<Object> consumer = new Consumer<Object>() {
                @Override
                public void consume(Object o) {
                    if (isSetting(o) || isVirtualFile(o) || isActionValue(o) || o instanceof PsiElement
                            || o instanceof OptionsTopHitProvider) {
                        if (o instanceof AnAction && myAlreadyAddedActions.contains(o)) {
                            return;
                        }
                        elements.add(o);
                    }
                }
            };

            if (pattern.equals("#")) {
                final HashSet<String> ids = new HashSet<String>();
                for (SearchTopHitProvider provider : SearchTopHitProvider.EP_NAME.getExtensions()) {
                    check();
                    if (provider instanceof OptionsTopHitProvider) {
                        if (!ids.contains(((OptionsTopHitProvider) provider).getId())) {
                            consumer.consume(provider);
                            ids.add(((OptionsTopHitProvider) provider).getId());
                        }
                    }
                }
            } else {
                final ActionManager actionManager = ActionManager.getInstance();
                final List<String> actions = AbbreviationManager.getInstance().findActions(pattern);
                for (String actionId : actions) {
                    consumer.consume(actionManager.getAction(actionId));
                }

                for (SearchTopHitProvider provider : SearchTopHitProvider.EP_NAME.getExtensions()) {
                    check();
                    if (provider instanceof OptionsTopHitProvider
                            && !((OptionsTopHitProvider) provider).isEnabled(project)) {
                        continue;
                    }
                    provider.consumeTopHits(pattern, consumer, project);
                }
            }
            if (elements.size() > 0) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        if (isCanceled())
                            return;

                        for (Object element : new ArrayList(elements)) {
                            if (element instanceof AnAction) {
                                final AnAction action = (AnAction) element;
                                final AnActionEvent e = new AnActionEvent(myActionEvent.getInputEvent(),
                                        myActionEvent.getDataContext(), myActionEvent.getPlace(),
                                        action.getTemplatePresentation(), myActionEvent.getActionManager(),
                                        myActionEvent.getModifiers());
                                ActionUtil.performDumbAwareUpdate(action, e, false);
                                final Presentation presentation = e.getPresentation();
                                if (!presentation.isEnabled() || !presentation.isVisible()
                                        || StringUtil.isEmpty(presentation.getText())) {
                                    elements.remove(element);
                                }
                                if (isCanceled())
                                    return;
                            }
                        }
                        if (isCanceled() || elements.isEmpty())
                            return;
                        myListModel.titleIndex.topHit = myListModel.size();
                        for (Object element : ContainerUtil.getFirstItems(elements, MAX_TOP_HIT)) {
                            myListModel.addElement(element);
                        }
                    }
                });
            }
        }

        private synchronized void checkModelsUpToDate() {
            if (myClassModel == null) {
                myClassModel = new GotoClassModel2(project);
                myFileModel = new GotoFileModel(project);
                mySymbolsModel = new GotoSymbolModel2(project);
                myFileChooseByName = ChooseByNamePopup.createPopup(project, myFileModel, (PsiElement) null);
                myClassChooseByName = ChooseByNamePopup.createPopup(project, myClassModel, (PsiElement) null);
                mySymbolsChooseByName = ChooseByNamePopup.createPopup(project, mySymbolsModel, (PsiElement) null);
                project.putUserData(ChooseByNamePopup.CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY, null);
                myActionProvider = createActionProvider();
                myConfigurables.clear();
                fillConfigurablesIds(null, new IdeConfigurablesGroup().getConfigurables());
                fillConfigurablesIds(null, new ProjectConfigurablesGroup(project).getConfigurables());
            }
            if (myStructureModel == null && myFileEditor != null && Registry.is("search.everywhere.structure")) {
                runReadAction(new Runnable() {
                    @Override
                    public void run() {
                        StructureViewBuilder structureViewBuilder = myFileEditor.getStructureViewBuilder();
                        if (structureViewBuilder == null)
                            return;
                        StructureView structureView = structureViewBuilder.createStructureView(myFileEditor,
                                project);
                        myStructureModel = structureView.getTreeModel();
                    }
                }, true);
            }
        }

        private void buildModelFromRecentFiles() {
            buildRecentFiles("");
        }

        private GotoActionItemProvider createActionProvider() {
            GotoActionModel model = new GotoActionModel(project, myFocusComponent, myEditor, myFile) {
                @Override
                protected MatchMode actionMatches(String pattern, @NotNull AnAction anAction) {
                    String text = anAction.getTemplatePresentation().getText();
                    return text != null && NameUtil
                            .buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE).matches(text)
                                    ? MatchMode.NAME
                                    : MatchMode.NONE;
                }
            };
            return new GotoActionItemProvider(model);
        }

        @SuppressWarnings("SSBasedInspection")
        private void updatePopup() {
            check();
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    myListModel.update();
                    myList.revalidate();
                    myList.repaint();

                    myRenderer.recalculateWidth();
                    if (myBalloon == null || myBalloon.isDisposed()) {
                        return;
                    }
                    if (myPopup == null || !myPopup.isVisible()) {
                        final ActionCallback callback = ListDelegationUtil
                                .installKeyboardDelegation(getField().getTextEditor(), myList);
                        JBScrollPane content = new JBScrollPane(myList);
                        content.setMinimumSize(new Dimension(myBalloon.getSize().width, 30));
                        final ComponentPopupBuilder builder = JBPopupFactory.getInstance()
                                .createComponentPopupBuilder(content, null);
                        myPopup = builder.setRequestFocus(false).setCancelKeyEnabled(false)
                                .setCancelCallback(new Computable<Boolean>() {
                                    @Override
                                    public Boolean compute() {
                                        return myBalloon == null || myBalloon.isDisposed()
                                                || (!getField().getTextEditor().hasFocus() && !mySkipFocusGain);
                                    }
                                }).createPopup();
                        myPopup.setMinimumSize(new Dimension(myBalloon.getSize().width, 30));
                        myPopup.getContent().setBorder(new EmptyBorder(0, 0, 0, 0));
                        Disposer.register(myPopup, new Disposable() {
                            @Override
                            public void dispose() {
                                callback.setDone();
                                resetFields();
                                myNonProjectCheckBox.setSelected(false);
                                ActionToolbarImpl.updateAllToolbarsImmediately();
                                if (myActionEvent != null && myActionEvent.getInputEvent() instanceof MouseEvent) {
                                    final Component component = myActionEvent.getInputEvent().getComponent();
                                    if (component != null) {
                                        final JLabel label = UIUtil.getParentOfType(JLabel.class, component);
                                        if (label != null) {
                                            label.setIcon(AllIcons.Actions.FindPlain);
                                        }
                                    }
                                }
                                myActionEvent = null;
                            }
                        });
                        myPopup.show(new RelativePoint(getField().getParent(),
                                new Point(0, getField().getParent().getHeight())));
                        //updatePopupBounds();

                        ActionManager.getInstance().addAnActionListener(new AnActionListener.Adapter() {
                            @Override
                            public void beforeActionPerformed(AnAction action, DataContext dataContext,
                                    AnActionEvent event) {
                                if (action instanceof TextComponentEditorAction) {
                                    return;
                                }
                                myPopup.cancel();
                            }
                        }, myPopup);
                    } else {
                        myList.revalidate();
                        myList.repaint();
                    }
                    ListScrollingUtil.ensureSelectionExists(myList);
                    if (myList.getModel().getSize() > 0) {
                        updatePopupBounds();
                    }
                }
            });
        }

        public ActionCallback cancel() {
            myProgressIndicator.cancel();
            myDone.setRejected();
            return myDone;
        }

        public ActionCallback insert(final int index, final WidgetID id) {
            ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
                @Override
                public void run() {
                    runReadAction(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                final SearchResult result = id == WidgetID.CLASSES
                                        ? getClasses(pattern, showAll.get(), DEFAULT_MORE_STEP_COUNT,
                                                myClassChooseByName)
                                        : id == WidgetID.FILES
                                                ? getFiles(pattern, DEFAULT_MORE_STEP_COUNT, myFileChooseByName)
                                                : id == WidgetID.RUN_CONFIGURATIONS
                                                        ? getConfigurations(pattern, DEFAULT_MORE_STEP_COUNT)
                                                        : id == WidgetID.SYMBOLS
                                                                ? getSymbols(pattern, DEFAULT_MORE_STEP_COUNT,
                                                                        mySymbolsChooseByName)
                                                                : id == WidgetID.ACTIONS
                                                                        ? getActionsOrSettings(pattern,
                                                                                DEFAULT_MORE_STEP_COUNT, true)
                                                                        : id == WidgetID.SETTINGS
                                                                                ? getActionsOrSettings(pattern,
                                                                                        DEFAULT_MORE_STEP_COUNT,
                                                                                        false)
                                                                                : new SearchResult();

                                check();
                                SwingUtilities.invokeLater(new Runnable() {
                                    @Override
                                    public void run() {
                                        try {
                                            int shift = 0;
                                            int i = index + 1;
                                            for (Object o : result) {
                                                //noinspection unchecked
                                                myListModel.insertElementAt(o, i);
                                                shift++;
                                                i++;
                                            }
                                            MoreIndex moreIndex = myListModel.moreIndex;
                                            myListModel.titleIndex.shift(index, shift);
                                            moreIndex.shift(index, shift);

                                            if (!result.needMore) {
                                                switch (id) {
                                                case CLASSES:
                                                    moreIndex.classes = -1;
                                                    break;
                                                case FILES:
                                                    moreIndex.files = -1;
                                                    break;
                                                case ACTIONS:
                                                    moreIndex.actions = -1;
                                                    break;
                                                case SETTINGS:
                                                    moreIndex.settings = -1;
                                                    break;
                                                case SYMBOLS:
                                                    moreIndex.symbols = -1;
                                                    break;
                                                case RUN_CONFIGURATIONS:
                                                    moreIndex.runConfigurations = -1;
                                                    break;
                                                }
                                            }
                                            ListScrollingUtil.selectItem(myList, index);
                                            myDone.setDone();
                                        } catch (Exception e) {
                                            myDone.setRejected();
                                        }
                                    }
                                });
                            } catch (Exception e) {
                                myDone.setRejected();
                            }
                        }
                    }, true);
                }
            });
            return myDone;
        }

        public ActionCallback start() {
            ApplicationManager.getApplication().executeOnPooledThread(this);
            return myDone;
        }
    }

    protected void resetFields() {
        if (myBalloon != null) {
            myBalloon.cancel();
            myBalloon = null;
        }
        myCurrentWorker.doWhenProcessed(new Runnable() {
            @Override
            public void run() {
                myFileModel = null;
                if (myFileChooseByName != null) {
                    myFileChooseByName.close(false);
                    myFileChooseByName = null;
                }
                if (myClassChooseByName != null) {
                    myClassChooseByName.close(false);
                    myClassChooseByName = null;
                }
                if (mySymbolsChooseByName != null) {
                    mySymbolsChooseByName.close(false);
                    mySymbolsChooseByName = null;
                }
                final Object lock = myCalcThread;
                if (lock != null) {
                    synchronized (lock) {
                        myClassModel = null;
                        myActionProvider = null;
                        mySymbolsModel = null;
                        myConfigurables.clear();
                        myFocusComponent = null;
                        myContextComponent = null;
                        myFocusOwner = null;
                        myRenderer.myProject = null;
                        myPopup = null;
                        myHistoryIndex = 0;
                        myPopupActualWidth = 0;
                        myCurrentWorker = ActionCallback.DONE;
                        showAll.set(false);
                        myCalcThread = null;
                        myEditor = null;
                        myFileEditor = null;
                        myStructureModel = null;
                    }
                }
            }
        });
        mySkipFocusGain = false;
    }

    private void updatePopupBounds() {
        if (myPopup == null || !myPopup.isVisible()) {
            return;
        }
        final Container parent = getField().getParent();
        final Dimension size = myList.getParent().getParent().getPreferredSize();
        size.width = myPopupActualWidth - 2;
        if (size.width + 2 < parent.getWidth()) {
            size.width = parent.getWidth();
        }
        if (myList.getItemsCount() == 0) {
            size.height = 30;
        }
        Dimension sz = new Dimension(size.width, myList.getPreferredSize().height);
        if (sz.width > POPUP_MAX_WIDTH || sz.height > POPUP_MAX_WIDTH) {
            final JBScrollPane pane = new JBScrollPane();
            final int extraWidth = pane.getVerticalScrollBar().getWidth() + 1;
            final int extraHeight = pane.getHorizontalScrollBar().getHeight() + 1;
            sz = new Dimension(Math.min(POPUP_MAX_WIDTH, Math.max(getField().getWidth(), sz.width + extraWidth)),
                    Math.min(POPUP_MAX_WIDTH, sz.height + extraHeight));
            sz.width += 20;
            sz.height += 2;
        } else {
            sz.width += 2;
            sz.height += 2;
        }
        sz.width = Math.max(sz.width, myPopup.getSize().width);
        myPopup.setSize(sz);
        if (myActionEvent != null && myActionEvent.getInputEvent() == null) {
            final Point p = parent.getLocationOnScreen();
            p.y += parent.getHeight();
            if (parent.getWidth() < sz.width) {
                p.x -= sz.width - parent.getWidth();
            }
            myPopup.setLocation(p);
        } else {
            try {
                adjustPopup();
            } catch (Exception ignore) {
            }
        }
    }

    private void adjustPopup() {
        //    new PopupPositionManager.PositionAdjuster(getField().getParent(), 0).adjust(myPopup, PopupPositionManager.Position.BOTTOM);
        final Dimension d = PopupPositionManager.PositionAdjuster.getPopupSize(myPopup);
        final JComponent myRelativeTo = myBalloon.getContent();
        Point myRelativeOnScreen = myRelativeTo.getLocationOnScreen();
        Rectangle screen = ScreenUtil.getScreenRectangle(myRelativeOnScreen);
        Rectangle popupRect = null;
        Rectangle r = new Rectangle(myRelativeOnScreen.x, myRelativeOnScreen.y + myRelativeTo.getHeight(), d.width,
                d.height);

        if (screen.contains(r)) {
            popupRect = r;
        }

        if (popupRect != null) {
            myPopup.setLocation(new Point(r.x - 1, r.y));
        } else {
            if (r.y + d.height > screen.y + screen.height) {
                r.height = screen.y + screen.height - r.y - 2;
            }
            if (r.width > screen.width) {
                r.width = screen.width - 50;
            }
            if (r.x + r.width > screen.x + screen.width) {
                r.x = screen.x + screen.width - r.width - 2;
            }

            myPopup.setSize(r.getSize());
            myPopup.setLocation(r.getLocation());
        }

    }

    private static boolean isToolWindowAction(Object o) {
        return isActionValue(o) && o instanceof GotoActionModel.ActionWrapper
                && ((GotoActionModel.ActionWrapper) o).getAction() instanceof ActivateToolWindowAction;
    }

    private void fillConfigurablesIds(String pathToParent, Configurable[] configurables) {
        for (Configurable configurable : configurables) {
            if (configurable instanceof SearchableConfigurable) {
                final String id = ((SearchableConfigurable) configurable).getId();
                String name = configurable.getDisplayName();
                if (pathToParent != null) {
                    name = pathToParent + " -> " + name;
                }
                myConfigurables.put(id, name);
                if (configurable instanceof SearchableConfigurable.Parent) {
                    fillConfigurablesIds(name, ((SearchableConfigurable.Parent) configurable).getConfigurables());
                }
            }
        }
    }

    static class MoreIndex {
        volatile int classes = -1;
        volatile int files = -1;
        volatile int actions = -1;
        volatile int settings = -1;
        volatile int symbols = -1;
        volatile int runConfigurations = -1;
        volatile int structure = -1;

        public void shift(int index, int shift) {
            if (runConfigurations >= index)
                runConfigurations += shift;
            if (classes >= index)
                classes += shift;
            if (files >= index)
                files += shift;
            if (symbols >= index)
                symbols += shift;
            if (actions >= index)
                actions += shift;
            if (settings >= index)
                settings += shift;
            if (structure >= index)
                structure += shift;
        }
    }

    static class TitleIndex {
        volatile int topHit = -1;
        volatile int recentFiles = -1;
        volatile int runConfigurations = -1;
        volatile int classes = -1;
        volatile int structure = -1;
        volatile int files = -1;
        volatile int actions = -1;
        volatile int settings = -1;
        volatile int toolWindows = -1;
        volatile int symbols = -1;

        final String gotoClassTitle;
        final String gotoFileTitle;
        final String gotoActionTitle;
        final String gotoSettingsTitle;
        final String gotoRecentFilesTitle;
        final String gotoRunConfigurationsTitle;
        final String gotoSymbolTitle;
        final String gotoStructureTitle;
        static final String toolWindowsTitle = "Tool Windows";

        TitleIndex() {
            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) ? ShowSettingsUtil.getSettingsMenuName()
                    : ShowSettingsUtil.getSettingsMenuName() + " (" + gotoSettings + ")";
            String gotoRecentFiles = KeymapUtil
                    .getFirstKeyboardShortcutText(ActionManager.getInstance().getAction("RecentFiles"));
            gotoRecentFilesTitle = StringUtil.isEmpty(gotoRecentFiles) ? "Recent Files"
                    : "Recent Files (" + gotoRecentFiles + ")";
            String gotoSymbol = KeymapUtil
                    .getFirstKeyboardShortcutText(ActionManager.getInstance().getAction("GotoSymbol"));
            gotoSymbolTitle = StringUtil.isEmpty(gotoSymbol) ? "Symbols" : "Symbols (" + gotoSymbol + ")";
            String gotoRunConfiguration = KeymapUtil.getFirstKeyboardShortcutText(
                    ActionManager.getInstance().getAction("ChooseDebugConfiguration"));
            if (StringUtil.isEmpty(gotoRunConfiguration)) {
                gotoRunConfiguration = KeymapUtil.getFirstKeyboardShortcutText(
                        ActionManager.getInstance().getAction("ChooseRunConfiguration"));
            }
            gotoRunConfigurationsTitle = StringUtil.isEmpty(gotoRunConfiguration) ? "Run Configurations"
                    : "Run Configurations (" + gotoRunConfiguration + ")";
            String gotoStructure = KeymapUtil
                    .getFirstKeyboardShortcutText(ActionManager.getInstance().getAction("FileStructurePopup"));
            gotoStructureTitle = StringUtil.isEmpty(gotoStructure) ? "File Structure"
                    : "File Structure (" + gotoStructure + ")";
        }

        String getTitle(int index) {
            if (index == topHit)
                return index == 0 ? "Top Hit" : "Top Hits";
            if (index == recentFiles)
                return gotoRecentFilesTitle;
            if (index == structure)
                return gotoStructureTitle;
            if (index == runConfigurations)
                return gotoRunConfigurationsTitle;
            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;
            if (index == symbols)
                return gotoSymbolTitle;
            return null;
        }

        public void clear() {
            topHit = -1;
            runConfigurations = -1;
            recentFiles = -1;
            classes = -1;
            files = -1;
            structure = -1;
            actions = -1;
            settings = -1;
            toolWindows = -1;
        }

        public void shift(int index, int shift) {
            if (toolWindows != -1 && toolWindows > index)
                toolWindows += shift;
            if (settings != -1 && settings > index)
                settings += shift;
            if (actions != -1 && actions > index)
                actions += shift;
            if (files != -1 && files > index)
                files += shift;
            if (structure != -1 && structure > index)
                structure += shift;
            if (classes != -1 && classes > index)
                classes += shift;
            if (runConfigurations != -1 && runConfigurations > index)
                runConfigurations += shift;
            if (symbols != -1 && symbols > index)
                symbols += shift;
        }
    }

    static class SearchResult extends ArrayList<Object> {
        boolean needMore;
    }

    @SuppressWarnings("unchecked")
    private static class SearchListModel extends DefaultListModel {
        @SuppressWarnings("UseOfObsoleteCollectionType")
        Vector myDelegate;

        volatile TitleIndex titleIndex = new TitleIndex();
        volatile MoreIndex moreIndex = new MoreIndex();

        private SearchListModel() {
            super();
            myDelegate = ReflectionUtil.getField(DefaultListModel.class, this, Vector.class, "delegate");
        }

        int next(int index) {
            int[] all = getAll();
            Arrays.sort(all);
            for (int next : all) {
                if (next > index)
                    return next;
            }
            return 0;
        }

        int[] getAll() {
            return new int[] { titleIndex.topHit, titleIndex.recentFiles, titleIndex.structure,
                    titleIndex.runConfigurations, titleIndex.classes, titleIndex.files, titleIndex.actions,
                    titleIndex.settings, titleIndex.toolWindows, titleIndex.symbols, moreIndex.classes,
                    moreIndex.actions, moreIndex.files, moreIndex.settings, moreIndex.symbols,
                    moreIndex.runConfigurations, moreIndex.structure };
        }

        int prev(int index) {
            int[] all = getAll();
            Arrays.sort(all);
            for (int i = all.length - 1; i >= 0; i--) {
                if (all[i] != -1 && all[i] < index)
                    return all[i];
            }
            return all[all.length - 1];
        }

        @Override
        public void addElement(Object obj) {
            myDelegate.add(obj);
        }

        public void update() {
            fireContentsChanged(this, 0, getSize() - 1);
        }
    }

    static class More extends JPanel {
        static final More instance = new More();
        final JLabel label = new JLabel("    ... more   ");

        private More() {
            super(new BorderLayout());
            add(label, BorderLayout.CENTER);
        }

        static More get(boolean isSelected) {
            instance.setBackground(UIUtil.getListBackground(isSelected));
            instance.label.setForeground(UIUtil.getLabelDisabledForeground());
            instance.label.setFont(getTitleFont());
            instance.label.setBackground(UIUtil.getListBackground(isSelected));
            return instance;
        }
    }

    private static JComponent createTitle(String titleText) {
        JLabel titleLabel = new JLabel(titleText);
        titleLabel.setFont(getTitleFont());
        titleLabel.setForeground(UIUtil.getLabelDisabledForeground());
        final Color bg = UIUtil.getListBackground();
        SeparatorComponent separatorComponent = new SeparatorComponent(titleLabel.getPreferredSize().height / 2,
                new JBColor(Gray._220, Gray._80), null);

        JPanel result = new JPanel(new BorderLayout(5, 10));
        result.add(titleLabel, BorderLayout.WEST);
        result.add(separatorComponent, BorderLayout.CENTER);
        result.setBackground(bg);

        return result;
    }

    private enum HistoryType {
        PSI, FILE, SETTING, ACTION, RUN_CONFIGURATION
    }

    @Nullable
    private static HistoryType parseHistoryType(@Nullable String name) {
        try {
            return HistoryType.valueOf(name);
        } catch (Exception e) {
            return null;
        }
    }

    private static class HistoryItem {
        final String pattern, type, fqn;

        private HistoryItem(String pattern, String type, String fqn) {
            this.pattern = pattern;
            this.type = type;
            this.fqn = fqn;
        }

        @Override
        public String toString() {
            return pattern + "\t" + type + "\t" + fqn;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (o == null || getClass() != o.getClass())
                return false;

            HistoryItem item = (HistoryItem) o;

            if (!pattern.equals(item.pattern))
                return false;

            return true;
        }

        @Override
        public int hashCode() {
            return pattern.hashCode();
        }
    }
}