From ced46ff5cad6b90dbf537851b9f04074c27e0b33 Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Thu, 19 Apr 2018 19:08:37 +0300 Subject: [PATCH 01/28] UX-1 Consolidated GOTO popup * UI for consolidated GOTO popup created --- .../actions/SearchEverywhereContributor.java | 6 + .../ide/actions/SearchEverywhereAction.java | 15 ++ .../ide/actions/SearchEverywhereUI.java | 167 +++++++++++++++++- .../ClassSearchEverywhereContributor.java | 7 + .../FileSearchEverywhereContributor.java | 7 + .../SymbolSearchEverywhereContributor.java | 7 + .../ide/ui/laf/darcula/darcula.properties | 7 +- .../ide/ui/laf/intellijlaf.properties | 7 +- .../ide/ui/laf/intellijlaf_native.properties | 7 +- .../src/messages/IdeBundle.properties | 3 + .../util/src/com/intellij/util/ui/JBUI.java | 27 +++ 11 files changed, 252 insertions(+), 8 deletions(-) diff --git a/platform/lang-api/src/com/intellij/ide/actions/SearchEverywhereContributor.java b/platform/lang-api/src/com/intellij/ide/actions/SearchEverywhereContributor.java index 2e0a462bcacc..3b6e388b3962 100644 --- a/platform/lang-api/src/com/intellij/ide/actions/SearchEverywhereContributor.java +++ b/platform/lang-api/src/com/intellij/ide/actions/SearchEverywhereContributor.java @@ -3,7 +3,9 @@ */ package com.intellij.ide.actions; +import com.intellij.ide.IdeBundle; import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; import java.util.Arrays; @@ -22,6 +24,10 @@ public interface SearchEverywhereContributor { @NotNull String getGroupName(); + default String includeNonProjectItemsText() { + return IdeBundle.message("checkbox.include.non.project.items", IdeUICustomization.getInstance().getProjectConceptName()); + } + int getSortWeight(); static List getProvidersSorted() { diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index 3771a9e2dfb1..e2ced62fe463 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -562,8 +562,23 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA public void actionPerformed(AnActionEvent e, MouseEvent me) { if (Registry.is("new.search.everywhere")) { //todo[mikhail.sokolov] show new UI + SearchEverywhereUI searchEverywhereUI = new SearchEverywhereUI(null); + JBPopup popup = JBPopupFactory.getInstance().createComponentPopupBuilder(searchEverywhereUI, searchEverywhereUI.getSearchField()) + .setProject(e.getProject()) + .setMovable(true) + .setResizable(false) + .setMayBeParent(true) + .setCancelOnClickOutside(true) + .setRequestFocus(true) + .setCancelKeyEnabled(false) + .setCancelCallback(() -> true) + .addUserData("SIMPLE_WINDOW") + .createPopup(); + + popup.showInBestPositionFor(e.getDataContext()); return; } + if (myBalloon != null && myBalloon.isVisible()) { showAll.set(!showAll.get()); myNonProjectCheckBox.setSelected(showAll.get()); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java index 632320f1c7e9..2537b2e9ff74 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java @@ -1,38 +1,195 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.actions; -import com.intellij.ui.JBColor; +import com.intellij.icons.AllIcons; +import com.intellij.ide.IdeBundle; +import com.intellij.ide.ui.UISettings; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.impl.ActionButton; +import com.intellij.ui.*; +import com.intellij.ui.components.JBCheckBox; +import com.intellij.ui.components.fields.ExtendableTextField; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.components.BorderLayoutPanel; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.Border; import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; /** * @author Konstantin Bulenkov + * @author Mikhail.Sokolov */ public class SearchEverywhereUI extends BorderLayoutPanel { private SETab mySelectedTab; + private final JTextField mySearchField; + private final JCheckBox myNonProjectCB = new JBCheckBox(); public SearchEverywhereUI(@Nullable SearchEverywhereContributor selected) { + withMinimumWidth(670); + withPreferredWidth(670); + setBackground(JBUI.CurrentTheme.SearchEverywhere.dialogBackground()); + JPanel contributorsPanel = createTabPanel(selected); + JPanel settingsPanel = createSettingsPanel(); + mySearchField = createSearchField(); + + addToLeft(contributorsPanel); + addToRight(settingsPanel); + addToBottom(mySearchField); + } + + public JTextField getSearchField() { + return mySearchField; + } + + private JTextField createSearchField() { + ExtendableTextField searchField = new ExtendableTextField() { + @Override + public Dimension getPreferredSize() { + Dimension size = super.getPreferredSize(); + size.height = JBUI.scale(29); + return size; + } + }; + + ExtendableTextField.Extension searchExtension = new ExtendableTextField.Extension() { + @Override + public Icon getIcon(boolean hovered) { + return AllIcons.Actions.Search; + } + + @Override + public boolean isIconBeforeText() { + return true; + } + }; + ExtendableTextField.Extension hintExtension = new ExtendableTextField.Extension() { + private final TextIcon icon; + { + icon = new TextIcon(IdeBundle.message("searcheverywhere.switch.scope.hint"), JBColor.GRAY, null, 0); + icon.setFont(RelativeFont.SMALL.derive(getFont())); + } + + @Override + public Icon getIcon(boolean hovered) { + return icon; + } + }; + searchField.setExtensions(searchExtension, hintExtension); + + //todo gap between icon and text #UX-1 + Insets insets = JBUI.CurrentTheme.SearchEverywhere.searchFieldInsets(); + Border border = JBUI.Borders.merge( + JBUI.Borders.empty(insets.top, searchExtension.getPreferredSpace() + insets.left, insets.bottom, hintExtension.getPreferredSpace() + insets.right), + IdeBorderFactory.createBorder(JBUI.CurrentTheme.SearchEverywhere.searchFieldBorderColor(), SideBorder.BOTTOM | SideBorder.TOP), + true); + searchField.setBorder(border); + searchField.setBackground(JBUI.CurrentTheme.SearchEverywhere.searchFieldBackground()); + + return searchField; + } + + private JPanel createSettingsPanel() { + JPanel res = new JPanel(); + BoxLayout bl = new BoxLayout(res, BoxLayout.X_AXIS); + res.setLayout(bl); + res.setOpaque(false); + + res.add(myNonProjectCB); + res.add(Box.createHorizontalStrut(JBUI.scale(19))); + + ToggleAction pinAction = new ToggleAction(null, null, AllIcons.General.AutohideOff) { + @Override + public boolean isSelected(AnActionEvent e) { + return UISettings.getInstance().getPinFindInPath(); + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + UISettings.getInstance().setPinFindInPath(state); + } + }; + ActionButton pinButton = new ActionButton(pinAction, pinAction.getTemplatePresentation(), ActionPlaces.UNKNOWN, ActionToolbar.DEFAULT_MINIMUM_BUTTON_SIZE); + res.add(pinButton); + res.add(Box.createHorizontalStrut(JBUI.scale(10))); + + AnAction emptyAction = new AnAction(AllIcons.General.Filter) { + @Override + public void actionPerformed(AnActionEvent e) {} + }; + ActionButton filterButton = new ActionButton(emptyAction, emptyAction.getTemplatePresentation(), ActionPlaces.UNKNOWN, ActionToolbar.DEFAULT_MINIMUM_BUTTON_SIZE); + res.add(filterButton); + res.add(Box.createHorizontalStrut(JBUI.scale(10))); + + return res; + } + + @NotNull + private JPanel createTabPanel(@Nullable SearchEverywhereContributor selected) { + JPanel contributorsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); + contributorsPanel.setOpaque(false); + + String allNonProjectItemsText = IdeBundle.message("checkbox.include.non.project.items", IdeUICustomization.getInstance().getProjectConceptName()); + SETab allTab = new SETab(IdeBundle.message("searcheverywhere.allelements.tab.name"), allNonProjectItemsText); + contributorsPanel.add(allTab); + + SearchEverywhereContributor.getProvidersSorted().forEach(contributor -> { + SETab tab = new SETab(contributor); + if (contributor == selected) { + mySelectedTab = tab; + } + contributorsPanel.add(tab); + }); + + if (mySelectedTab == null) { + mySelectedTab = allTab; + myNonProjectCB.setText(allNonProjectItemsText); + } + + return contributorsPanel; } private class SETab extends JLabel { - public SETab(String tabName) { + public SETab(SearchEverywhereContributor contributor) { + this(contributor.getGroupName(), contributor.includeNonProjectItemsText()); + } + + public SETab(String tabName, String nonProjectItemCBText) { super(tabName); + Insets insets = JBUI.CurrentTheme.SearchEverywhere.tabInsets(); + setBorder(JBUI.Borders.empty(insets.top, insets.left, insets.bottom, insets.right)); + addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + mySelectedTab = SETab.this; + SearchEverywhereUI.this.repaint(); + myNonProjectCB.setText(nonProjectItemCBText); + } + }); } @Override - public Border getBorder() { - return JBUI.Borders.empty(0, 12); + public Dimension getPreferredSize() { + Dimension size = super.getPreferredSize(); + size.height = JBUI.scale(29); + return size; + } + + @Override + public boolean isOpaque() { + return mySelectedTab == this; } @Override public Color getBackground() { - return mySelectedTab == this ? new JBColor(0xdedede, 0x565a5e) : super.getBackground(); + return mySelectedTab == this + ? JBUI.CurrentTheme.SearchEverywhere.selectedTabColor() + : super.getBackground(); } } } diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ClassSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ClassSearchEverywhereContributor.java index b903e28dfa0e..2dfd561c7fd5 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ClassSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ClassSearchEverywhereContributor.java @@ -1,7 +1,9 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.util.gotoByName; +import com.intellij.ide.IdeBundle; import com.intellij.ide.actions.SearchEverywhereContributor; +import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; /** @@ -20,6 +22,11 @@ public class ClassSearchEverywhereContributor implements SearchEverywhereContrib return "Classes"; } + @Override + public String includeNonProjectItemsText() { + return IdeBundle.message("checkbox.include.non.project.classes", IdeUICustomization.getInstance().getProjectConceptName()); + } + @Override public int getSortWeight() { return 100; diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/FileSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/FileSearchEverywhereContributor.java index 99f75d3d7af5..32b3ef794171 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/FileSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/FileSearchEverywhereContributor.java @@ -1,7 +1,9 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.util.gotoByName; +import com.intellij.ide.IdeBundle; import com.intellij.ide.actions.SearchEverywhereContributor; +import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; /** @@ -20,6 +22,11 @@ public class FileSearchEverywhereContributor implements SearchEverywhereContribu return "Files"; } + @Override + public String includeNonProjectItemsText() { + return IdeBundle.message("checkbox.include.non.project.files", IdeUICustomization.getInstance().getProjectConceptName()); + } + @Override public int getSortWeight() { return 200; diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/SymbolSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/SymbolSearchEverywhereContributor.java index b3399f114b15..eaa06dabb7ea 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/SymbolSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/SymbolSearchEverywhereContributor.java @@ -1,7 +1,9 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.util.gotoByName; +import com.intellij.ide.IdeBundle; import com.intellij.ide.actions.SearchEverywhereContributor; +import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; /** @@ -20,6 +22,11 @@ public class SymbolSearchEverywhereContributor implements SearchEverywhereContri return "Symbols"; } + @Override + public String includeNonProjectItemsText() { + return IdeBundle.message("checkbox.include.non.project.symbols", IdeUICustomization.getInstance().getProjectConceptName()); + } + @Override public int getSortWeight() { return 300; diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties index d7a6cf38064b..9795fa64a7b8 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties @@ -201,4 +201,9 @@ Popup.Header.inactiveBackground=434649 Popup.Border.color=616161 Popup.Border.inactiveColor=565656 Popup.Toolbar.background=3c3f41 -Popup.Toolbar.Border.color=4a4e52 \ No newline at end of file +Popup.Toolbar.Border.color=4a4e52 + +SearchEverywhere.Dialog.background=45494a +SearchEverywhere.Tab.selected.background=555a5e +SearchEverywhere.SearchField.background=3c3f41 +SearchEverywhere.SearchField.Border.color=646464 \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties index 1227f090bd18..3ef07671187c 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties @@ -191,4 +191,9 @@ Popup.Header.inactiveBackground=ededed Popup.Border.color=808080 Popup.Border.inactiveColor=aaaaaa Popup.Toolbar.background=f7f7f7 -Popup.Toolbar.Border.color=f7f7f7 \ No newline at end of file +Popup.Toolbar.Border.color=f7f7f7 + +SearchEverywhere.Dialog.background=f2f2f2 +SearchEverywhere.Tab.selected.background=dedede +SearchEverywhere.SearchField.background=ffffff +SearchEverywhere.SearchField.Border.color=bdbdbd \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties index acf05b9bea87..c0bd22658d90 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties @@ -214,4 +214,9 @@ Popup.Header.inactiveBackground=ededed Popup.Border.color=808080 Popup.Border.inactiveColor=aaaaaa Popup.Toolbar.background=f7f7f7 -Popup.Toolbar.Border.color=f7f7f7 \ No newline at end of file +Popup.Toolbar.Border.color=f7f7f7 + +SearchEverywhere.Dialog.background=f2f2f2 +SearchEverywhere.Tab.selected.background=dedede +SearchEverywhere.SearchField.background=ffffff +SearchEverywhere.SearchField.Border.color=bdbdbd \ No newline at end of file diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index 97528893eb04..5b960b37bec2 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -1269,6 +1269,9 @@ change.color.command.text=Change color warning.use.rest.api=''{0}'' API is requested. Do you trust ''{1}''? title.use.rest.api=Using REST API +searcheverywhere.allelements.tab.name=All +searcheverywhere.switch.scope.hint=Tab to switch scope + run.anything.command.empty.list.title=Press ENTER to execute input command run.anything.console.process.finished=\nProcess finished with exit code {0}. run.anything.console.title=Run anything command diff --git a/platform/util/src/com/intellij/util/ui/JBUI.java b/platform/util/src/com/intellij/util/ui/JBUI.java index a67fd5db51f7..da5d92d73e4d 100644 --- a/platform/util/src/com/intellij/util/ui/JBUI.java +++ b/platform/util/src/com/intellij/util/ui/JBUI.java @@ -1550,6 +1550,33 @@ public class JBUI { return scale(28); } } + + //todo #UX-1 maybe move to popup + public static class SearchEverywhere { + public static Color dialogBackground() { + return JBColor.namedColor("SearchEverywhere.Dialog.background", 0xf2f2f2); + } + + public static Insets tabInsets() { + return insets(0, 12); + } + + public static Color selectedTabColor() { + return JBColor.namedColor("SearchEverywhere.Tab.selected.background", 0xdedede); + } + + public static Color searchFieldBackground() { + return JBColor.namedColor("SearchEverywhere.SearchField.background", 0xffffff); + } + + public static Color searchFieldBorderColor() { + return JBColor.namedColor("SearchEverywhere.SearchField.Border.color", 0xbdbdbd); + } + + public static Insets searchFieldInsets() { + return insets(0, 12, 0, 10); + } + } } From 298dcb9d358adcf790bcaaaab066ee31db703bb7 Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Fri, 20 Apr 2018 12:31:01 +0300 Subject: [PATCH 02/28] UX-1 Consolidated GOTO popup * switch on TAB --- .../ide/actions/SearchEverywhereUI.java | 73 ++++++++++++++++--- 1 file changed, 61 insertions(+), 12 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java index 2537b2e9ff74..ffa2f0272e06 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java @@ -17,8 +17,12 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.Border; import java.awt.*; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; /** * @author Konstantin Bulenkov @@ -28,6 +32,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { private SETab mySelectedTab; private final JTextField mySearchField; private final JCheckBox myNonProjectCB = new JBCheckBox(); + private final List myTabs = new ArrayList<>(); public SearchEverywhereUI(@Nullable SearchEverywhereContributor selected) { withMinimumWidth(670); @@ -47,6 +52,18 @@ public class SearchEverywhereUI extends BorderLayoutPanel { return mySearchField; } + private void switchToNextTab() { + int currentIndex = myTabs.indexOf(mySelectedTab); + SETab nextTab = currentIndex == myTabs.size() - 1 ? myTabs.get(0) : myTabs.get(currentIndex + 1); + switchToTab(nextTab); + } + + private void switchToTab(SETab tab) { + mySelectedTab = tab; + myNonProjectCB.setText(tab.getContributor().includeNonProjectItemsText()); + repaint(); + } + private JTextField createSearchField() { ExtendableTextField searchField = new ExtendableTextField() { @Override @@ -91,6 +108,17 @@ public class SearchEverywhereUI extends BorderLayoutPanel { searchField.setBorder(border); searchField.setBackground(JBUI.CurrentTheme.SearchEverywhere.searchFieldBackground()); + searchField.setFocusTraversalKeysEnabled(false); + searchField.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_TAB) { + switchToNextTab(); + e.consume(); + } + } + }); + return searchField; } @@ -135,44 +163,65 @@ public class SearchEverywhereUI extends BorderLayoutPanel { contributorsPanel.setOpaque(false); String allNonProjectItemsText = IdeBundle.message("checkbox.include.non.project.items", IdeUICustomization.getInstance().getProjectConceptName()); - SETab allTab = new SETab(IdeBundle.message("searcheverywhere.allelements.tab.name"), allNonProjectItemsText); + SETab allTab = new SETab(allElementsContributor); contributorsPanel.add(allTab); + myTabs.add(allTab); SearchEverywhereContributor.getProvidersSorted().forEach(contributor -> { SETab tab = new SETab(contributor); if (contributor == selected) { - mySelectedTab = tab; + switchToTab(tab); } contributorsPanel.add(tab); + myTabs.add(tab); }); if (mySelectedTab == null) { - mySelectedTab = allTab; - myNonProjectCB.setText(allNonProjectItemsText); + switchToTab(allTab); } return contributorsPanel; } - private class SETab extends JLabel { - public SETab(SearchEverywhereContributor contributor) { - this(contributor.getGroupName(), contributor.includeNonProjectItemsText()); + private SearchEverywhereContributor allElementsContributor = new SearchEverywhereContributor() { + @NotNull + @Override + public String getSearchProviderId() { + return "All"; } - public SETab(String tabName, String nonProjectItemCBText) { - super(tabName); + @NotNull + @Override + public String getGroupName() { + return IdeBundle.message("searcheverywhere.allelements.tab.name"); + } + + @Override + public int getSortWeight() { + return 0; + } + }; + + private class SETab extends JLabel { + private final SearchEverywhereContributor myContributor; + + public SETab(SearchEverywhereContributor contributor) { + super(contributor.getGroupName()); + myContributor = contributor; Insets insets = JBUI.CurrentTheme.SearchEverywhere.tabInsets(); setBorder(JBUI.Borders.empty(insets.top, insets.left, insets.bottom, insets.right)); addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { - mySelectedTab = SETab.this; - SearchEverywhereUI.this.repaint(); - myNonProjectCB.setText(nonProjectItemCBText); + switchToTab(SETab.this); } }); } + public SearchEverywhereContributor getContributor() { + return myContributor; + } + @Override public Dimension getPreferredSize() { Dimension size = super.getPreferredSize(); From b265b2bc0ed8097e7b812cc5cbae1804cfe7e874 Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Mon, 23 Apr 2018 13:17:34 +0300 Subject: [PATCH 03/28] UX-1 Consolidated GOTO popup * Open GoTo File/Class/Symbol in new popup * Enable/disable "Use non-project items" CheckBox when repeat shortcut --- .../ide/actions/SearchEverywhereAction.java | 50 ++++---- .../ide/actions/SearchEverywhereAction2.java | 121 ++++++++++++++++++ .../ide/actions/SearchEverywhereHelper.java | 70 ++++++++++ .../ide/actions/SearchEverywhereUI.java | 29 +++-- .../ClassSearchEverywhereContributor.java | 2 +- .../src/idea/LangActions.xml | 10 +- .../src/idea/PlatformActions.xml | 2 +- 7 files changed, 247 insertions(+), 37 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction2.java create mode 100644 platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereHelper.java diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index e2ced62fe463..dfe9be2790a9 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -562,20 +562,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA public void actionPerformed(AnActionEvent e, MouseEvent me) { if (Registry.is("new.search.everywhere")) { //todo[mikhail.sokolov] show new UI - SearchEverywhereUI searchEverywhereUI = new SearchEverywhereUI(null); - JBPopup popup = JBPopupFactory.getInstance().createComponentPopupBuilder(searchEverywhereUI, searchEverywhereUI.getSearchField()) - .setProject(e.getProject()) - .setMovable(true) - .setResizable(false) - .setMayBeParent(true) - .setCancelOnClickOutside(true) - .setRequestFocus(true) - .setCancelKeyEnabled(false) - .setCancelCallback(() -> true) - .addUserData("SIMPLE_WINDOW") - .createPopup(); - - popup.showInBestPositionFor(e.getDataContext()); + SearchEverywhereHelper.showSearchEverywherePopup(e, null); return; } @@ -716,7 +703,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA .setRequestFocus(true) .createPopup(); myBalloon.getContent().setBorder(JBUI.Borders.empty()); - final Window window = WindowManager.getInstance().suggestParentWindow(project); + project.getMessageBus().connect(myBalloon).subscribe(DumbService.DUMB_MODE, new DumbService.DumbModeListener() { @@ -726,18 +713,9 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } }); - Component parent = UIUtil.findUltimateParent(window); + registerDataProvider(panel, project); - final RelativePoint showPoint; - if (parent != null) { - int height = UISettings.getInstance().getShowMainToolbar() ? 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()); - } + final RelativePoint showPoint = calculateShowingPoint(e, panel); myList.setFont(UIUtil.getListFont()); myBalloon.show(showPoint); initSearchActions(myBalloon, myPopupField); @@ -746,6 +724,26 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE); } + @NotNull + private static RelativePoint calculateShowingPoint(AnActionEvent e, JComponent showingContent) { + Project project = e.getProject(); + final Window window = project != null + ? WindowManager.getInstance().suggestParentWindow(project) + : KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow(); + Component parent = UIUtil.findUltimateParent(window); + final RelativePoint showPoint; + if (parent != null) { + int height = UISettings.getInstance().getShowMainToolbar() ? 135 : 115; + if (parent instanceof IdeFrameImpl && ((IdeFrameImpl)parent).isInFullScreen()) { + height -= 20; + } + showPoint = new RelativePoint(parent, new Point((parent.getSize().width - showingContent.getPreferredSize().width) / 2, height)); + } else { + showPoint = JBPopupFactory.getInstance().guessBestPopupLocation(e.getDataContext()); + } + return showPoint; + } + private void showSettings() { myPopupField.setText(""); final SearchListModel model = new SearchListModel(); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction2.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction2.java new file mode 100644 index 000000000000..a3c9c8ac1dd1 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction2.java @@ -0,0 +1,121 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.ide.actions; + +import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.ide.IdeEventQueue; +import com.intellij.ide.ui.UISettings; +import com.intellij.ide.util.gotoByName.ClassSearchEverywhereContributor; +import com.intellij.ide.util.gotoByName.FileSearchEverywhereContributor; +import com.intellij.ide.util.gotoByName.SymbolSearchEverywhereContributor; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.keymap.impl.ModifierKeyDoubleClickHandler; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.openapi.wm.impl.IdeFrameImpl; +import com.intellij.ui.awt.RelativePoint; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; +import java.util.List; + +public class SearchEverywhereAction2 extends AnAction { + + static { + ModifierKeyDoubleClickHandler.getInstance().registerAction(IdeActions.ACTION_SEARCH_EVERYWHERE, KeyEvent.VK_SHIFT, -1, false); + } + + @Nullable + protected final String mySelectedProviderID; + private JBPopup myBalloon; + private SearchEverywhereUI searchEverywhereUI; + + public SearchEverywhereAction2(@Nullable String selectedProviderID) { + mySelectedProviderID = selectedProviderID; + } + + public SearchEverywhereAction2() { + this(null); + } + + @Override + public void actionPerformed(AnActionEvent evnt) { + if (myBalloon != null && !myBalloon.isDisposed()) { + searchEverywhereUI.setUseNonProjectItems(!searchEverywhereUI.isUseNonProjectItems()); + return; + } + + IdeEventQueue.getInstance().getPopupManager().closeAllPopups(false); + List contributors = SearchEverywhereContributor.getProvidersSorted(); + SearchEverywhereContributor selected = contributors.stream() + .filter(contributor -> contributor.getSearchProviderId().equals(mySelectedProviderID)) + .findAny() + .orElse(null); + + searchEverywhereUI = new SearchEverywhereUI(contributors, selected); + myBalloon = JBPopupFactory.getInstance().createComponentPopupBuilder(searchEverywhereUI, searchEverywhereUI.getSearchField()) + .setProject(evnt.getProject()) + //.setMovable(false) + .setResizable(false) + //.setMayBeParent(true) + .setModalContext(false) + .setCancelOnClickOutside(true) + .setRequestFocus(true) + .setCancelKeyEnabled(false) + .setCancelCallback(() -> true) + .addUserData("SIMPLE_WINDOW") + .createPopup(); + + RelativePoint showingPoint = calculateShowingPoint(evnt, searchEverywhereUI); + myBalloon.show(showingPoint); + AnAction escape = ActionManager.getInstance().getAction("EditorEscape"); + DumbAwareAction.create(__ -> myBalloon.cancel()) + .registerCustomShortcutSet(escape == null ? CommonShortcuts.ESCAPE : escape.getShortcutSet(), myBalloon.getContent(), + myBalloon); + FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE); + } + + @NotNull + private static RelativePoint calculateShowingPoint(AnActionEvent e, JComponent showingContent) { + Project project = e.getProject(); + final Window window = project != null + ? WindowManager.getInstance().suggestParentWindow(project) + : KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow(); + Component parent = UIUtil.findUltimateParent(window); + final RelativePoint showPoint; + if (parent != null) { + int height = UISettings.getInstance().getShowMainToolbar() ? 135 : 115; + if (parent instanceof IdeFrameImpl && ((IdeFrameImpl)parent).isInFullScreen()) { + height -= 20; + } + showPoint = new RelativePoint(parent, new Point((parent.getSize().width - showingContent.getPreferredSize().width) / 2, height)); + } else { + showPoint = JBPopupFactory.getInstance().guessBestPopupLocation(e.getDataContext()); + } + return showPoint; + } + + public static class Class extends SearchEverywhereAction2 { + public Class() { + super(ClassSearchEverywhereContributor.class.getSimpleName()); + } + } + + public static class File extends SearchEverywhereAction2 { + public File() { + super(FileSearchEverywhereContributor.class.getSimpleName()); + } + } + + public static class Symbol extends SearchEverywhereAction2 { + public Symbol() { + super(SymbolSearchEverywhereContributor.class.getSimpleName()); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereHelper.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereHelper.java new file mode 100644 index 000000000000..55c4e2b16930 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereHelper.java @@ -0,0 +1,70 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.ide.actions; + +import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.ide.ui.UISettings; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.openapi.wm.impl.IdeFrameImpl; +import com.intellij.ui.awt.RelativePoint; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.util.List; + +public class SearchEverywhereHelper { + + public static void showSearchEverywherePopup(AnActionEvent evnt, String selectedProviderID) { + List contributors = SearchEverywhereContributor.getProvidersSorted(); + SearchEverywhereContributor selected = contributors.stream() + .filter(contributor -> contributor.getSearchProviderId().equals(selectedProviderID)) + .findAny() + .orElse(null); + + SearchEverywhereUI searchEverywhereUI = new SearchEverywhereUI(contributors, selected); + JBPopup popup = JBPopupFactory.getInstance().createComponentPopupBuilder(searchEverywhereUI, searchEverywhereUI.getSearchField()) + .setProject(evnt.getProject()) + .setMovable(false) + .setResizable(false) + .setMayBeParent(true) + .setCancelOnClickOutside(true) + .setRequestFocus(true) + .setCancelKeyEnabled(false) + .setCancelCallback(() -> true) + .addUserData("SIMPLE_WINDOW") + .createPopup(); + + RelativePoint showingPoint = calculateShowingPoint(evnt, searchEverywhereUI); + popup.show(showingPoint); + AnAction escape = ActionManager.getInstance().getAction("EditorEscape"); + DumbAwareAction.create(__ -> popup.cancel()) + .registerCustomShortcutSet(escape == null ? CommonShortcuts.ESCAPE : escape.getShortcutSet(), popup.getContent(), popup); + FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE); + } + + @NotNull + private static RelativePoint calculateShowingPoint(AnActionEvent e, JComponent showingContent) { + Project project = e.getProject(); + final Window window = project != null + ? WindowManager.getInstance().suggestParentWindow(project) + : KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow(); + Component parent = UIUtil.findUltimateParent(window); + final RelativePoint showPoint; + if (parent != null) { + int height = UISettings.getInstance().getShowMainToolbar() ? 135 : 115; + if (parent instanceof IdeFrameImpl && ((IdeFrameImpl)parent).isInFullScreen()) { + height -= 20; + } + showPoint = new RelativePoint(parent, new Point((parent.getSize().width - showingContent.getPreferredSize().width) / 2, height)); + } else { + showPoint = JBPopupFactory.getInstance().guessBestPopupLocation(e.getDataContext()); + } + return showPoint; + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java index ffa2f0272e06..0ab677aab788 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java @@ -31,15 +31,19 @@ import java.util.List; public class SearchEverywhereUI extends BorderLayoutPanel { private SETab mySelectedTab; private final JTextField mySearchField; - private final JCheckBox myNonProjectCB = new JBCheckBox(); + private final JCheckBox myNonProjectCB; private final List myTabs = new ArrayList<>(); - public SearchEverywhereUI(@Nullable SearchEverywhereContributor selected) { + public SearchEverywhereUI(List contributors, @Nullable SearchEverywhereContributor selected) { withMinimumWidth(670); withPreferredWidth(670); setBackground(JBUI.CurrentTheme.SearchEverywhere.dialogBackground()); - JPanel contributorsPanel = createTabPanel(selected); + myNonProjectCB = new JBCheckBox(); + myNonProjectCB.setOpaque(false); + myNonProjectCB.setFocusable(false); + + JPanel contributorsPanel = createTabPanel(contributors, selected); JPanel settingsPanel = createSettingsPanel(); mySearchField = createSearchField(); @@ -52,6 +56,14 @@ public class SearchEverywhereUI extends BorderLayoutPanel { return mySearchField; } + public void setUseNonProjectItems(boolean use) { + myNonProjectCB.setSelected(use); + } + + public boolean isUseNonProjectItems() { + return myNonProjectCB.isSelected(); + } + private void switchToNextTab() { int currentIndex = myTabs.indexOf(mySelectedTab); SETab nextTab = currentIndex == myTabs.size() - 1 ? myTabs.get(0) : myTabs.get(currentIndex + 1); @@ -61,6 +73,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { private void switchToTab(SETab tab) { mySelectedTab = tab; myNonProjectCB.setText(tab.getContributor().includeNonProjectItemsText()); + myNonProjectCB.setSelected(false); repaint(); } @@ -112,7 +125,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { searchField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_TAB) { + if (e.getKeyCode() == KeyEvent.VK_TAB && e.getModifiers() == 0) { switchToNextTab(); e.consume(); } @@ -158,16 +171,16 @@ public class SearchEverywhereUI extends BorderLayoutPanel { } @NotNull - private JPanel createTabPanel(@Nullable SearchEverywhereContributor selected) { + private JPanel createTabPanel(List contributors, @Nullable SearchEverywhereContributor selected) { JPanel contributorsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); contributorsPanel.setOpaque(false); - String allNonProjectItemsText = IdeBundle.message("checkbox.include.non.project.items", IdeUICustomization.getInstance().getProjectConceptName()); SETab allTab = new SETab(allElementsContributor); contributorsPanel.add(allTab); myTabs.add(allTab); - SearchEverywhereContributor.getProvidersSorted().forEach(contributor -> { + + contributors.forEach(contributor -> { SETab tab = new SETab(contributor); if (contributor == selected) { switchToTab(tab); @@ -183,7 +196,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { return contributorsPanel; } - private SearchEverywhereContributor allElementsContributor = new SearchEverywhereContributor() { + private final SearchEverywhereContributor allElementsContributor = new SearchEverywhereContributor() { @NotNull @Override public String getSearchProviderId() { diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ClassSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ClassSearchEverywhereContributor.java index 2dfd561c7fd5..ebf876f4348c 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ClassSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ClassSearchEverywhereContributor.java @@ -13,7 +13,7 @@ public class ClassSearchEverywhereContributor implements SearchEverywhereContrib @NotNull @Override public String getSearchProviderId() { - return "Class"; + return getClass().getSimpleName(); } @NotNull diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index 720294db1e3a..ab91d3a897fa 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -209,11 +209,19 @@ + + + + + + + + diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index 2b4659e4d09f..b127e3dbac3f 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -76,7 +76,7 @@ > - + From 3913f67dcc97e819293f194f92711a01dd0dd075 Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Mon, 23 Apr 2018 20:00:41 +0300 Subject: [PATCH 04/28] UX-1 Consolidated GOTO popup * SearchEverywhereManager is added --- .../SearchEverywhereContributor.java | 2 +- .../ide/actions/SearchEverywhereAction.java | 1 - .../ide/actions/SearchEverywhereAction2.java | 96 ++++----------- .../ide/actions/SearchEverywhereHelper.java | 70 ----------- .../AllSearchEverywhereContributor.java | 26 ++++ .../ClassSearchEverywhereContributor.java | 3 +- .../FileSearchEverywhereContributor.java | 3 +- .../SearchEverywhereManager.java | 29 +++++ .../SearchEverywhereManagerImpl.java | 115 ++++++++++++++++++ .../SearchEverywhereUI.java | 41 +++---- .../SymbolSearchEverywhereContributor.java | 3 +- .../src/META-INF/LangExtensionPoints.xml | 3 +- .../src/META-INF/LangExtensions.xml | 10 +- .../src/idea/PlatformActions.xml | 2 +- 14 files changed, 227 insertions(+), 177 deletions(-) rename platform/lang-api/src/com/intellij/ide/actions/{ => searcheverywhere}/SearchEverywhereContributor.java (95%) delete mode 100644 platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereHelper.java create mode 100644 platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AllSearchEverywhereContributor.java rename platform/lang-impl/src/com/intellij/ide/{util/gotoByName => actions/searcheverywhere}/ClassSearchEverywhereContributor.java (89%) rename platform/lang-impl/src/com/intellij/ide/{util/gotoByName => actions/searcheverywhere}/FileSearchEverywhereContributor.java (88%) create mode 100644 platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManager.java create mode 100644 platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java rename platform/lang-impl/src/com/intellij/ide/actions/{ => searcheverywhere}/SearchEverywhereUI.java (90%) rename platform/lang-impl/src/com/intellij/ide/{util/gotoByName => actions/searcheverywhere}/SymbolSearchEverywhereContributor.java (89%) diff --git a/platform/lang-api/src/com/intellij/ide/actions/SearchEverywhereContributor.java b/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java similarity index 95% rename from platform/lang-api/src/com/intellij/ide/actions/SearchEverywhereContributor.java rename to platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java index 3b6e388b3962..b72b623cef9c 100644 --- a/platform/lang-api/src/com/intellij/ide/actions/SearchEverywhereContributor.java +++ b/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java @@ -1,7 +1,7 @@ /* * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ -package com.intellij.ide.actions; +package com.intellij.ide.actions.searcheverywhere; import com.intellij.ide.IdeBundle; import com.intellij.openapi.extensions.ExtensionPointName; diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index dfe9be2790a9..18c222757fbb 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -562,7 +562,6 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA public void actionPerformed(AnActionEvent e, MouseEvent me) { if (Registry.is("new.search.everywhere")) { //todo[mikhail.sokolov] show new UI - SearchEverywhereHelper.showSearchEverywherePopup(e, null); return; } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction2.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction2.java index a3c9c8ac1dd1..e89be33c58f5 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction2.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction2.java @@ -3,102 +3,52 @@ package com.intellij.ide.actions; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.IdeEventQueue; -import com.intellij.ide.ui.UISettings; -import com.intellij.ide.util.gotoByName.ClassSearchEverywhereContributor; -import com.intellij.ide.util.gotoByName.FileSearchEverywhereContributor; -import com.intellij.ide.util.gotoByName.SymbolSearchEverywhereContributor; -import com.intellij.openapi.actionSystem.*; +import com.intellij.ide.actions.searcheverywhere.*; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.keymap.impl.ModifierKeyDoubleClickHandler; -import com.intellij.openapi.project.DumbAwareAction; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.popup.JBPopup; -import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.openapi.wm.WindowManager; -import com.intellij.openapi.wm.impl.IdeFrameImpl; -import com.intellij.ui.awt.RelativePoint; -import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import javax.swing.*; -import java.awt.*; import java.awt.event.KeyEvent; -import java.util.List; -public class SearchEverywhereAction2 extends AnAction { +public abstract class SearchEverywhereAction2 extends AnAction { static { ModifierKeyDoubleClickHandler.getInstance().registerAction(IdeActions.ACTION_SEARCH_EVERYWHERE, KeyEvent.VK_SHIFT, -1, false); } - @Nullable - protected final String mySelectedProviderID; - private JBPopup myBalloon; - private SearchEverywhereUI searchEverywhereUI; + @NotNull + protected final String mySelectedProviderID; //todo change to contributor??? UX-1 - public SearchEverywhereAction2(@Nullable String selectedProviderID) { + protected SearchEverywhereAction2(@NotNull String selectedProviderID) { mySelectedProviderID = selectedProviderID; } - public SearchEverywhereAction2() { - this(null); - } - @Override public void actionPerformed(AnActionEvent evnt) { - if (myBalloon != null && !myBalloon.isDisposed()) { - searchEverywhereUI.setUseNonProjectItems(!searchEverywhereUI.isUseNonProjectItems()); + //todo same or different action triggered? #UX-1 + FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE); + + SearchEverywhereManager seManager = SearchEverywhereManager.getInstance(evnt.getProject()); + if (seManager.isShown()) { + if (mySelectedProviderID.equals(seManager.getShownContributor().getSearchProviderId())) { + seManager.setShowNonProjectItems(!seManager.isShowNonProjectItems()); + } + else { + seManager.setShownContributor(mySelectedProviderID); + } return; } IdeEventQueue.getInstance().getPopupManager().closeAllPopups(false); - List contributors = SearchEverywhereContributor.getProvidersSorted(); - SearchEverywhereContributor selected = contributors.stream() - .filter(contributor -> contributor.getSearchProviderId().equals(mySelectedProviderID)) - .findAny() - .orElse(null); - - searchEverywhereUI = new SearchEverywhereUI(contributors, selected); - myBalloon = JBPopupFactory.getInstance().createComponentPopupBuilder(searchEverywhereUI, searchEverywhereUI.getSearchField()) - .setProject(evnt.getProject()) - //.setMovable(false) - .setResizable(false) - //.setMayBeParent(true) - .setModalContext(false) - .setCancelOnClickOutside(true) - .setRequestFocus(true) - .setCancelKeyEnabled(false) - .setCancelCallback(() -> true) - .addUserData("SIMPLE_WINDOW") - .createPopup(); - - RelativePoint showingPoint = calculateShowingPoint(evnt, searchEverywhereUI); - myBalloon.show(showingPoint); - AnAction escape = ActionManager.getInstance().getAction("EditorEscape"); - DumbAwareAction.create(__ -> myBalloon.cancel()) - .registerCustomShortcutSet(escape == null ? CommonShortcuts.ESCAPE : escape.getShortcutSet(), myBalloon.getContent(), - myBalloon); - FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE); + seManager.show(mySelectedProviderID); } - @NotNull - private static RelativePoint calculateShowingPoint(AnActionEvent e, JComponent showingContent) { - Project project = e.getProject(); - final Window window = project != null - ? WindowManager.getInstance().suggestParentWindow(project) - : KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow(); - Component parent = UIUtil.findUltimateParent(window); - final RelativePoint showPoint; - if (parent != null) { - int height = UISettings.getInstance().getShowMainToolbar() ? 135 : 115; - if (parent instanceof IdeFrameImpl && ((IdeFrameImpl)parent).isInFullScreen()) { - height -= 20; - } - showPoint = new RelativePoint(parent, new Point((parent.getSize().width - showingContent.getPreferredSize().width) / 2, height)); - } else { - showPoint = JBPopupFactory.getInstance().guessBestPopupLocation(e.getDataContext()); + public static class All extends SearchEverywhereAction2 { + protected All() { + super(AllSearchEverywhereContributor.class.getSimpleName()); } - return showPoint; } public static class Class extends SearchEverywhereAction2 { diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereHelper.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereHelper.java deleted file mode 100644 index 55c4e2b16930..000000000000 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereHelper.java +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.intellij.ide.actions; - -import com.intellij.featureStatistics.FeatureUsageTracker; -import com.intellij.ide.ui.UISettings; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.project.DumbAwareAction; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.popup.JBPopup; -import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.openapi.wm.WindowManager; -import com.intellij.openapi.wm.impl.IdeFrameImpl; -import com.intellij.ui.awt.RelativePoint; -import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import java.awt.*; -import java.util.List; - -public class SearchEverywhereHelper { - - public static void showSearchEverywherePopup(AnActionEvent evnt, String selectedProviderID) { - List contributors = SearchEverywhereContributor.getProvidersSorted(); - SearchEverywhereContributor selected = contributors.stream() - .filter(contributor -> contributor.getSearchProviderId().equals(selectedProviderID)) - .findAny() - .orElse(null); - - SearchEverywhereUI searchEverywhereUI = new SearchEverywhereUI(contributors, selected); - JBPopup popup = JBPopupFactory.getInstance().createComponentPopupBuilder(searchEverywhereUI, searchEverywhereUI.getSearchField()) - .setProject(evnt.getProject()) - .setMovable(false) - .setResizable(false) - .setMayBeParent(true) - .setCancelOnClickOutside(true) - .setRequestFocus(true) - .setCancelKeyEnabled(false) - .setCancelCallback(() -> true) - .addUserData("SIMPLE_WINDOW") - .createPopup(); - - RelativePoint showingPoint = calculateShowingPoint(evnt, searchEverywhereUI); - popup.show(showingPoint); - AnAction escape = ActionManager.getInstance().getAction("EditorEscape"); - DumbAwareAction.create(__ -> popup.cancel()) - .registerCustomShortcutSet(escape == null ? CommonShortcuts.ESCAPE : escape.getShortcutSet(), popup.getContent(), popup); - FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE); - } - - @NotNull - private static RelativePoint calculateShowingPoint(AnActionEvent e, JComponent showingContent) { - Project project = e.getProject(); - final Window window = project != null - ? WindowManager.getInstance().suggestParentWindow(project) - : KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow(); - Component parent = UIUtil.findUltimateParent(window); - final RelativePoint showPoint; - if (parent != null) { - int height = UISettings.getInstance().getShowMainToolbar() ? 135 : 115; - if (parent instanceof IdeFrameImpl && ((IdeFrameImpl)parent).isInFullScreen()) { - height -= 20; - } - showPoint = new RelativePoint(parent, new Point((parent.getSize().width - showingContent.getPreferredSize().width) / 2, height)); - } else { - showPoint = JBPopupFactory.getInstance().guessBestPopupLocation(e.getDataContext()); - } - return showPoint; - } -} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AllSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AllSearchEverywhereContributor.java new file mode 100644 index 000000000000..7c9d432e78fd --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AllSearchEverywhereContributor.java @@ -0,0 +1,26 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.ide.actions.searcheverywhere; + +import com.intellij.ide.IdeBundle; +import org.jetbrains.annotations.NotNull; + +public class AllSearchEverywhereContributor implements SearchEverywhereContributor { + + @NotNull + @Override + public String getSearchProviderId() { + return getClass().getSimpleName(); + } + + @NotNull + @Override + public String getGroupName() { + return IdeBundle.message("searcheverywhere.allelements.tab.name"); + } + + @Override + public int getSortWeight() { + return 0; + } + +} diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ClassSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java similarity index 89% rename from platform/lang-impl/src/com/intellij/ide/util/gotoByName/ClassSearchEverywhereContributor.java rename to platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java index ebf876f4348c..72c87329bcd4 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ClassSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java @@ -1,8 +1,7 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.intellij.ide.util.gotoByName; +package com.intellij.ide.actions.searcheverywhere; import com.intellij.ide.IdeBundle; -import com.intellij.ide.actions.SearchEverywhereContributor; import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/FileSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java similarity index 88% rename from platform/lang-impl/src/com/intellij/ide/util/gotoByName/FileSearchEverywhereContributor.java rename to platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java index 32b3ef794171..41d3304fc32b 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/FileSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java @@ -1,8 +1,7 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.intellij.ide.util.gotoByName; +package com.intellij.ide.actions.searcheverywhere; import com.intellij.ide.IdeBundle; -import com.intellij.ide.actions.SearchEverywhereContributor; import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManager.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManager.java new file mode 100644 index 000000000000..e3fcf2df4e9e --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManager.java @@ -0,0 +1,29 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.ide.actions.searcheverywhere; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +/** + * @author Mikhail.Sokolov + */ +public interface SearchEverywhereManager { + + static SearchEverywhereManager getInstance(Project project) { + return ServiceManager.getService(project, SearchEverywhereManager.class); + } + + boolean isShown(); + + void show(@NotNull String selectedContributorID); //todo change to contributor??? UX-1 + + SearchEverywhereContributor getShownContributor(); + + void setShownContributor(@NotNull String newSelectedContributorID); //todo change to contributor??? UX-1 + + boolean isShowNonProjectItems(); + + void setShowNonProjectItems(boolean show); + +} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java new file mode 100644 index 000000000000..b42073fd0e50 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java @@ -0,0 +1,115 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.ide.actions.searcheverywhere; + +import com.intellij.ide.ui.UISettings; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.CommonShortcuts; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.openapi.wm.impl.IdeFrameImpl; +import com.intellij.ui.awt.RelativePoint; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; + +import java.awt.*; +import java.util.List; + +public class SearchEverywhereManagerImpl implements SearchEverywhereManager { + private final Project myProject; + + private JBPopup myBalloon; + private final SearchEverywhereUI mySearchEverywhereUI; + + public SearchEverywhereManagerImpl(Project project) { + myProject = project; + + List contributors = SearchEverywhereContributor.getProvidersSorted(); + //SearchEverywhereContributor selected = contributors.stream() + // .filter(contributor -> contributor.getSearchProviderId().equals(mySelectedProviderID)) + // .findAny() + // .orElse(null); + mySearchEverywhereUI = new SearchEverywhereUI(contributors, null); + } + + @Override + public void show(@NotNull String selectedContributorID) { + if (isShown()) { + setShownContributor(selectedContributorID); + } + else { + mySearchEverywhereUI.clear(); + mySearchEverywhereUI.switchToContributor(selectedContributorID); + myBalloon = JBPopupFactory.getInstance().createComponentPopupBuilder(mySearchEverywhereUI, mySearchEverywhereUI.getSearchField()) + .setProject(myProject) + .setResizable(false) + .setModalContext(false) + .setCancelOnClickOutside(true) + .setRequestFocus(true) + .setCancelKeyEnabled(false) + .setCancelCallback(() -> true) + .addUserData("SIMPLE_WINDOW") + .createPopup(); + + AnAction escape = ActionManager.getInstance().getAction("EditorEscape"); + DumbAwareAction.create(__ -> myBalloon.cancel()) + .registerCustomShortcutSet(escape == null ? CommonShortcuts.ESCAPE : escape.getShortcutSet(), + myBalloon.getContent(), myBalloon); + + RelativePoint showingPoint = calculateShowingPoint(); + if (showingPoint != null) { + myBalloon.show(showingPoint); + } + else { + myBalloon.showInFocusCenter(); + } + } + + } + + @Override + public boolean isShown() { + return myBalloon != null && !myBalloon.isDisposed(); + } + + @Override + public SearchEverywhereContributor getShownContributor() { + return mySearchEverywhereUI.getSelectedContributor(); + } + + @Override + public void setShownContributor(@NotNull String contributorID) { + if (!contributorID.equals(getShownContributor().getSearchProviderId())) { + mySearchEverywhereUI.switchToContributor(contributorID); + } + } + + @Override + public boolean isShowNonProjectItems() { + return mySearchEverywhereUI.isUseNonProjectItems(); + } + + @Override + public void setShowNonProjectItems(boolean show) { + mySearchEverywhereUI.setUseNonProjectItems(show); + } + + private RelativePoint calculateShowingPoint() { + final Window window = myProject != null + ? WindowManager.getInstance().suggestParentWindow(myProject) + : KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow(); + Component parent = UIUtil.findUltimateParent(window); + if (parent == null) { + return null; + } + + int height = UISettings.getInstance().getShowMainToolbar() ? 135 : 115; + if (parent instanceof IdeFrameImpl && ((IdeFrameImpl)parent).isInFullScreen()) { + height -= 20; + } + return new RelativePoint(parent, new Point((parent.getSize().width - mySearchEverywhereUI.getPreferredSize().width) / 2, height)); + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java similarity index 90% rename from platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java rename to platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java index 0ab677aab788..fa874c6adcd1 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java @@ -1,5 +1,5 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.intellij.ide.actions; +package com.intellij.ide.actions.searcheverywhere; import com.intellij.icons.AllIcons; import com.intellij.ide.IdeBundle; @@ -34,6 +34,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { private final JCheckBox myNonProjectCB; private final List myTabs = new ArrayList<>(); + // todo remove second param #UX-1 public SearchEverywhereUI(List contributors, @Nullable SearchEverywhereContributor selected) { withMinimumWidth(670); withPreferredWidth(670); @@ -64,6 +65,23 @@ public class SearchEverywhereUI extends BorderLayoutPanel { return myNonProjectCB.isSelected(); } + public void switchToContributor(String contributorID) { + SETab selectedTab = myTabs.stream() + .filter(tab -> contributorID.equals(tab.getContributor().getSearchProviderId())) + .findAny() + .orElseThrow(() -> new IllegalArgumentException(String.format("Contributor %s is not supported", contributorID))); + switchToTab(selectedTab); + } + + public SearchEverywhereContributor getSelectedContributor() { + return mySelectedTab.getContributor(); + } + + public void clear() { + mySearchField.setText(""); + myNonProjectCB.setSelected(false); + } + private void switchToNextTab() { int currentIndex = myTabs.indexOf(mySelectedTab); SETab nextTab = currentIndex == myTabs.size() - 1 ? myTabs.get(0) : myTabs.get(currentIndex + 1); @@ -175,7 +193,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { JPanel contributorsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); contributorsPanel.setOpaque(false); - SETab allTab = new SETab(allElementsContributor); + SETab allTab = new SETab(new AllSearchEverywhereContributor()); contributorsPanel.add(allTab); myTabs.add(allTab); @@ -196,25 +214,6 @@ public class SearchEverywhereUI extends BorderLayoutPanel { return contributorsPanel; } - private final SearchEverywhereContributor allElementsContributor = new SearchEverywhereContributor() { - @NotNull - @Override - public String getSearchProviderId() { - return "All"; - } - - @NotNull - @Override - public String getGroupName() { - return IdeBundle.message("searcheverywhere.allelements.tab.name"); - } - - @Override - public int getSortWeight() { - return 0; - } - }; - private class SETab extends JLabel { private final SearchEverywhereContributor myContributor; diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/SymbolSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java similarity index 89% rename from platform/lang-impl/src/com/intellij/ide/util/gotoByName/SymbolSearchEverywhereContributor.java rename to platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java index eaa06dabb7ea..bd0c46e6732a 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/SymbolSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java @@ -1,8 +1,7 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.intellij.ide.util.gotoByName; +package com.intellij.ide.actions.searcheverywhere; import com.intellij.ide.IdeBundle; -import com.intellij.ide.actions.SearchEverywhereContributor; import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index a47a2f113dcf..5a4fd1097b85 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -287,7 +287,8 @@ interface="com.intellij.navigation.ChooseByNameContributor"/> - + diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 4a9937e9f7ee..ff076f3e801f 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -1094,9 +1094,13 @@ - - - + + + + + + > - + From 930c32a5d7f4774f96b63507c5a1b08373a0660d Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Tue, 24 Apr 2018 15:03:04 +0300 Subject: [PATCH 05/28] UX-1 Consolidated GOTO popup * support keyboard mnemonics for checkbox --- .../ide/actions/searcheverywhere/SearchEverywhereUI.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java index fa874c6adcd1..8c9c56d4168a 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java @@ -9,6 +9,7 @@ import com.intellij.openapi.actionSystem.impl.ActionButton; import com.intellij.ui.*; import com.intellij.ui.components.JBCheckBox; import com.intellij.ui.components.fields.ExtendableTextField; +import com.intellij.util.ui.DialogUtil; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.components.BorderLayoutPanel; import org.jetbrains.annotations.NotNull; @@ -90,7 +91,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { private void switchToTab(SETab tab) { mySelectedTab = tab; - myNonProjectCB.setText(tab.getContributor().includeNonProjectItemsText()); + DialogUtil.setTextWithMnemonic(myNonProjectCB, tab.getContributor().includeNonProjectItemsText()); myNonProjectCB.setSelected(false); repaint(); } From a2c1cc4c67daef0ebb1edbabb51310e0f14f1773 Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Tue, 24 Apr 2018 18:26:25 +0300 Subject: [PATCH 06/28] UX-1 Consolidated GOTO popup --- .../intellij/ide/actions/GotoActionBase.java | 21 ++++++ .../intellij/ide/actions/GotoClassAction.java | 7 ++ .../intellij/ide/actions/GotoFileAction.java | 16 ++++- .../ide/actions/GotoSymbolAction.java | 12 ++++ .../ide/actions/SearchEverywhereAction.java | 20 ++++++ .../ide/actions/SearchEverywhereAction2.java | 71 ------------------- .../AllSearchEverywhereContributor.java | 5 ++ .../searcheverywhere/SearchEverywhereUI.java | 10 ++- .../src/idea/LangActions.xml | 8 --- .../src/idea/PlatformActions.xml | 2 +- 10 files changed, 90 insertions(+), 82 deletions(-) delete mode 100644 platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction2.java diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java index a0f9b251427d..da97de9cc0dc 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java @@ -16,6 +16,9 @@ package com.intellij.ide.actions; +import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.ide.IdeEventQueue; +import com.intellij.ide.actions.searcheverywhere.SearchEverywhereManager; import com.intellij.ide.util.gotoByName.*; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ModalityState; @@ -332,6 +335,24 @@ public abstract class GotoActionBase extends AnAction { }.registerCustomShortcutSet(SearchTextField.SHOW_HISTORY_SHORTCUT, editor); } + protected void showInSearchEverywherePopup(String searchProviderID, AnActionEvent evnt) { + FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE); + FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE + "." + searchProviderID); + + SearchEverywhereManager seManager = SearchEverywhereManager.getInstance(evnt.getProject()); + if (seManager.isShown()) { + if (searchProviderID.equals(seManager.getShownContributor().getSearchProviderId())) { + seManager.setShowNonProjectItems(!seManager.isShowNonProjectItems()); + } + else { + seManager.setShownContributor(searchProviderID); + } + return; + } + + IdeEventQueue.getInstance().getPopupManager().closeAllPopups(false); + seManager.show(searchProviderID); + } private static boolean historyEnabled() { return !ContainerUtil.isEmpty(ourHistory.get(myInAction)); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java index 01306cfcdb51..a9f1b6603d19 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java @@ -18,6 +18,7 @@ package com.intellij.ide.actions; import com.intellij.codeInsight.navigation.NavigationUtil; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.IdeBundle; +import com.intellij.ide.actions.searcheverywhere.ClassSearchEverywhereContributor; import com.intellij.ide.structureView.StructureView; import com.intellij.ide.structureView.StructureViewBuilder; import com.intellij.ide.structureView.StructureViewTreeElement; @@ -40,6 +41,7 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.playback.commands.ActionCommand; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.Navigatable; @@ -59,6 +61,11 @@ import java.util.List; public class GotoClassAction extends GotoActionBase implements DumbAware { @Override public void actionPerformed(@NotNull AnActionEvent e) { + if (Registry.is("new.search.everywhere")) { + showInSearchEverywherePopup(ClassSearchEverywhereContributor.class.getSimpleName(), e); + return; + } + Project project = e.getProject(); if (project == null) return; diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java index 55da4991a82e..7c448703e1a6 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java @@ -17,7 +17,11 @@ package com.intellij.ide.actions; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.IdeBundle; -import com.intellij.ide.util.gotoByName.*; +import com.intellij.ide.actions.searcheverywhere.FileSearchEverywhereContributor; +import com.intellij.ide.util.gotoByName.ChooseByNameFilter; +import com.intellij.ide.util.gotoByName.ChooseByNamePopup; +import com.intellij.ide.util.gotoByName.GotoFileConfiguration; +import com.intellij.ide.util.gotoByName.GotoFileModel; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.application.ApplicationManager; @@ -27,6 +31,7 @@ import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.Navigatable; import com.intellij.psi.PsiFile; @@ -48,6 +53,15 @@ import java.util.List; public class GotoFileAction extends GotoActionBase implements DumbAware { public static final String ID = "GotoFile"; + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + if (Registry.is("new.search.everywhere")) { + showInSearchEverywherePopup(FileSearchEverywhereContributor.class.getSimpleName(), e); + } else { + super.actionPerformed(e); + } + } + @Override public void gotoActionPerformed(AnActionEvent e) { final Project project = e.getData(CommonDataKeys.PROJECT); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java index 81f183f64fbf..c5dd26007a39 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java @@ -16,16 +16,28 @@ package com.intellij.ide.actions; import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.ide.actions.searcheverywhere.SymbolSearchEverywhereContributor; import com.intellij.ide.util.gotoByName.*; import com.intellij.lang.Language; import com.intellij.navigation.ChooseByNameRegistry; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.PsiDocumentManager; import org.jetbrains.annotations.NotNull; public class GotoSymbolAction extends GotoActionBase { + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + if (Registry.is("new.search.everywhere")) { + showInSearchEverywherePopup(SymbolSearchEverywhereContributor.class.getSimpleName(), e); + } else { + super.actionPerformed(e); + } + } + @Override public void gotoActionPerformed(AnActionEvent e) { FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.symbol"); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index 18c222757fbb..889b3a2a08c0 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -16,6 +16,8 @@ import com.intellij.execution.runners.ProgramRunner; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.icons.AllIcons; import com.intellij.ide.*; +import com.intellij.ide.actions.searcheverywhere.AllSearchEverywhereContributor; +import com.intellij.ide.actions.searcheverywhere.SearchEverywhereManager; import com.intellij.ide.structureView.StructureView; import com.intellij.ide.structureView.StructureViewBuilder; import com.intellij.ide.structureView.StructureViewModel; @@ -562,6 +564,24 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA public void actionPerformed(AnActionEvent e, MouseEvent me) { if (Registry.is("new.search.everywhere")) { //todo[mikhail.sokolov] show new UI + String searchProviderID = AllSearchEverywhereContributor.class.getSimpleName(); + + FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE); + FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE + "." + searchProviderID); + + SearchEverywhereManager seManager = SearchEverywhereManager.getInstance(e.getProject()); + if (seManager.isShown()) { + if (searchProviderID.equals(seManager.getShownContributor().getSearchProviderId())) { + seManager.setShowNonProjectItems(!seManager.isShowNonProjectItems()); + } + else { + seManager.setShownContributor(searchProviderID); + } + return; + } + + IdeEventQueue.getInstance().getPopupManager().closeAllPopups(false); + seManager.show(searchProviderID); return; } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction2.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction2.java deleted file mode 100644 index e89be33c58f5..000000000000 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction2.java +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.intellij.ide.actions; - -import com.intellij.featureStatistics.FeatureUsageTracker; -import com.intellij.ide.IdeEventQueue; -import com.intellij.ide.actions.searcheverywhere.*; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.IdeActions; -import com.intellij.openapi.keymap.impl.ModifierKeyDoubleClickHandler; -import org.jetbrains.annotations.NotNull; - -import java.awt.event.KeyEvent; - -public abstract class SearchEverywhereAction2 extends AnAction { - - static { - ModifierKeyDoubleClickHandler.getInstance().registerAction(IdeActions.ACTION_SEARCH_EVERYWHERE, KeyEvent.VK_SHIFT, -1, false); - } - - @NotNull - protected final String mySelectedProviderID; //todo change to contributor??? UX-1 - - protected SearchEverywhereAction2(@NotNull String selectedProviderID) { - mySelectedProviderID = selectedProviderID; - } - - @Override - public void actionPerformed(AnActionEvent evnt) { - //todo same or different action triggered? #UX-1 - FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE); - - SearchEverywhereManager seManager = SearchEverywhereManager.getInstance(evnt.getProject()); - if (seManager.isShown()) { - if (mySelectedProviderID.equals(seManager.getShownContributor().getSearchProviderId())) { - seManager.setShowNonProjectItems(!seManager.isShowNonProjectItems()); - } - else { - seManager.setShownContributor(mySelectedProviderID); - } - return; - } - - IdeEventQueue.getInstance().getPopupManager().closeAllPopups(false); - seManager.show(mySelectedProviderID); - } - - public static class All extends SearchEverywhereAction2 { - protected All() { - super(AllSearchEverywhereContributor.class.getSimpleName()); - } - } - - public static class Class extends SearchEverywhereAction2 { - public Class() { - super(ClassSearchEverywhereContributor.class.getSimpleName()); - } - } - - public static class File extends SearchEverywhereAction2 { - public File() { - super(FileSearchEverywhereContributor.class.getSimpleName()); - } - } - - public static class Symbol extends SearchEverywhereAction2 { - public Symbol() { - super(SymbolSearchEverywhereContributor.class.getSimpleName()); - } - } -} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AllSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AllSearchEverywhereContributor.java index 7c9d432e78fd..c12f7a545108 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AllSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AllSearchEverywhereContributor.java @@ -2,6 +2,7 @@ package com.intellij.ide.actions.searcheverywhere; import com.intellij.ide.IdeBundle; +import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; public class AllSearchEverywhereContributor implements SearchEverywhereContributor { @@ -23,4 +24,8 @@ public class AllSearchEverywhereContributor implements SearchEverywhereContribut return 0; } + @Override + public String includeNonProjectItemsText() { + return IdeBundle.message("checkbox.include.non.project.items", IdeUICustomization.getInstance().getProjectConceptName()); + } } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java index 8c9c56d4168a..d597d4e35b7b 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java @@ -11,6 +11,7 @@ import com.intellij.ui.components.JBCheckBox; import com.intellij.ui.components.fields.ExtendableTextField; import com.intellij.util.ui.DialogUtil; import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.components.BorderLayoutPanel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -91,7 +92,14 @@ public class SearchEverywhereUI extends BorderLayoutPanel { private void switchToTab(SETab tab) { mySelectedTab = tab; - DialogUtil.setTextWithMnemonic(myNonProjectCB, tab.getContributor().includeNonProjectItemsText()); + String text = tab.getContributor().includeNonProjectItemsText(); + if (text.indexOf(UIUtil.MNEMONIC) != -1) { + DialogUtil.setTextWithMnemonic(myNonProjectCB, text); + } else { + myNonProjectCB.setText(text); + myNonProjectCB.setDisplayedMnemonicIndex(-1); + myNonProjectCB.setMnemonic(0); + } myNonProjectCB.setSelected(false); repaint(); } diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index ab91d3a897fa..ba02ac0ebbdd 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -209,17 +209,9 @@ - - - - - - - diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index 694c1a5214ed..2b4659e4d09f 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -76,7 +76,7 @@ > - + From 1e35bf4023f2e05f5204f78ebd949ff85fc6d8a4 Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Fri, 27 Apr 2018 21:05:48 +0300 Subject: [PATCH 07/28] UX-1 extract GotoListController --- .../SearchEverywhereContributor.java | 33 ++ .../ide/actions/SearchEverywhereAction.java | 59 +-- .../ClassSearchEverywhereContributor.java | 30 ++ .../FileSearchEverywhereContributor.java | 61 +++ .../SearchEverywhereManagerImpl.java | 451 +++++++++++++++++- 5 files changed, 598 insertions(+), 36 deletions(-) diff --git a/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java b/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java index b72b623cef9c..4a908326a5f7 100644 --- a/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java +++ b/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java @@ -5,10 +5,13 @@ package com.intellij.ide.actions.searcheverywhere; import com.intellij.ide.IdeBundle; import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.project.Project; import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; import java.util.Arrays; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -30,9 +33,39 @@ public interface SearchEverywhereContributor { int getSortWeight(); + default ContributorSearchResult search(Project project, String pattern, boolean everywhere, ProgressIndicator progressIndicator, int elementsLimit) { + return new ContributorSearchResult(Collections.emptyList(), false); + } + + default List search(Project project, String pattern, boolean everywhere, ProgressIndicator progressIndicator) { + return search(project, pattern, everywhere, progressIndicator, -1).getItems(); + } + static List getProvidersSorted() { return Arrays.stream(EP_NAME.getExtensions()) .sorted(Comparator.comparingInt(SearchEverywhereContributor::getSortWeight)) .collect(Collectors.toList()); } + + class ContributorSearchResult { + private final List items; + private final boolean hasMoreItems; + + public ContributorSearchResult(List items, boolean hasMoreItems) { + this.items = items; + this.hasMoreItems = hasMoreItems; + } + + public List getItems() { + return items; + } + + public boolean hasMoreItems() { + return hasMoreItems; + } + + public boolean isEmpty() { + return items.isEmpty(); + } + } } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index 857787d454a5..58c509839cd1 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -1317,7 +1317,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA enum WidgetID {CLASSES, FILES, ACTIONS, SETTINGS, SYMBOLS, RUN_CONFIGURATIONS} - @SuppressWarnings({"SSBasedInspection", "unchecked"}) + @SuppressWarnings({"SSBasedInspection", "unchecked", "Duplicates"}) private class CalcThread implements Runnable { private final Project project; private final String pattern; @@ -2334,14 +2334,14 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } - 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 static class MoreIndex { + public volatile int classes = -1; + public volatile int files = -1; + public volatile int actions = -1; + public volatile int settings = -1; + public volatile int symbols = -1; + public volatile int runConfigurations = -1; + public volatile int structure = -1; public void shift(int index, int shift) { if (runConfigurations >= index) runConfigurations += shift; @@ -2354,17 +2354,17 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } - 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; + public static class TitleIndex { + public volatile int topHit = -1; + public volatile int recentFiles = -1; + public volatile int runConfigurations = -1; + public volatile int classes = -1; + public volatile int structure = -1; + public volatile int files = -1; + public volatile int actions = -1; + public volatile int settings = -1; + public volatile int toolWindows = -1; + public volatile int symbols = -1; final String gotoClassTitle; final String gotoFileTitle; @@ -2437,19 +2437,19 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } - static class SearchResult extends ArrayList { + public static class SearchResult extends ArrayList { boolean needMore; } @SuppressWarnings("unchecked") - private static class SearchListModel extends DefaultListModel { + public static class SearchListModel extends DefaultListModel { @SuppressWarnings("UseOfObsoleteCollectionType") Vector myDelegate; - volatile TitleIndex titleIndex = new TitleIndex(); - volatile MoreIndex moreIndex = new MoreIndex(); + public volatile TitleIndex titleIndex = new TitleIndex(); + public volatile MoreIndex moreIndex = new MoreIndex(); - private SearchListModel() { + public SearchListModel() { super(); myDelegate = ReflectionUtil.getField(DefaultListModel.class, this, Vector.class, "delegate"); } @@ -2504,7 +2504,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } - static class More extends JPanel { + public static class More extends JPanel { static final More instance = new More(); final JLabel label = new JLabel(" ... more "); @@ -2536,10 +2536,10 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA .withBackground(UIUtil.getListBackground()); } - private enum HistoryType {PSI, FILE, SETTING, ACTION, RUN_CONFIGURATION} + public enum HistoryType {PSI, FILE, SETTING, ACTION, RUN_CONFIGURATION} @Nullable - private static HistoryType parseHistoryType(@Nullable String name) { + public static HistoryType parseHistoryType(@Nullable String name) { try { return HistoryType.valueOf(name); } catch (Exception e) { @@ -2547,7 +2547,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } - private static class HistoryItem { + //todo history maybe unnecessary #UX-1 + public static class HistoryItem { final String pattern, type, fqn; private HistoryItem(String pattern, String type, String fqn) { diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java index 72c87329bcd4..f3af44805f70 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java @@ -2,9 +2,19 @@ package com.intellij.ide.actions.searcheverywhere; import com.intellij.ide.IdeBundle; +import com.intellij.ide.actions.SearchEverywhereClassifier; +import com.intellij.ide.util.gotoByName.ChooseByNameModel; +import com.intellij.ide.util.gotoByName.ChooseByNamePopup; +import com.intellij.ide.util.gotoByName.GotoClassModel2; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.List; + /** * @author Konstantin Bulenkov */ @@ -30,4 +40,24 @@ public class ClassSearchEverywhereContributor implements SearchEverywhereContrib public int getSortWeight() { return 100; } + + public SearchEverywhereContributor.ContributorSearchResult search(Project project, String pattern, boolean everywhere, ProgressIndicator progressIndicator, int elementsLimit) { + ChooseByNameModel mdl = new GotoClassModel2(project); + ChooseByNamePopup popup = ChooseByNamePopup.createPopup(project, mdl, (PsiElement)null); + List items = new ArrayList<>(); + boolean[] hasMore = {false}; //todo builder for ContributorSearchResult #UX-1 + popup.getProvider().filterElements(popup, pattern, everywhere, progressIndicator, o -> { + if (SearchEverywhereClassifier.EP_Manager.isClass(o) && !items.contains(o)) { + if (elementsLimit >=0 && items.size() >= elementsLimit) { + hasMore[0] = true; + return false; + } + items.add(o); + + } + return true; + }); + + return new SearchEverywhereContributor.ContributorSearchResult(items, hasMore[0]); + } } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java index 41d3304fc32b..39246e0582ef 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java @@ -2,9 +2,23 @@ package com.intellij.ide.actions.searcheverywhere; import com.intellij.ide.IdeBundle; +import com.intellij.ide.actions.SearchEverywhereClassifier; +import com.intellij.ide.util.gotoByName.ChooseByNameModel; +import com.intellij.ide.util.gotoByName.ChooseByNamePopup; +import com.intellij.ide.util.gotoByName.GotoFileModel; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.List; + /** * @author Konstantin Bulenkov */ @@ -30,4 +44,51 @@ public class FileSearchEverywhereContributor implements SearchEverywhereContribu public int getSortWeight() { return 200; } + + @Override + public ContributorSearchResult search(Project project, String pattern, boolean everywhere, ProgressIndicator progressIndicator, int elementsLimit) { + final GlobalSearchScope scope = getProjectScope(project); + + ChooseByNameModel mdl = new GotoFileModel(project){ + @Override + public boolean isSlashlessMatchingEnabled() { + return false; + } + }; + + ChooseByNamePopup popup = ChooseByNamePopup.createPopup(project, mdl, (PsiElement)null); + List items = new ArrayList<>(); + boolean[] hasMore = {false}; //todo builder for ContributorSearchResult #UX-1 + popup.getProvider().filterElements(popup, pattern, true, + progressIndicator, 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) + && (everywhere || scope.accept(file)) + && !items.contains(file)) { + if (elementsLimit >= 0 && items.size() >= elementsLimit) { + hasMore[0] = true; + return false; + } + items.add(file); + } + return true; + }); + + return new ContributorSearchResult(items, hasMore[0]); + } + + @NotNull + private static GlobalSearchScope getProjectScope(@NotNull Project project) { + final GlobalSearchScope scope = SearchEverywhereClassifier.EP_Manager.getProjectScope(project); + if (scope != null) return scope; + return GlobalSearchScope.projectScope(project); + } } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java index b42073fd0e50..17ac5be769b2 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java @@ -1,38 +1,130 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.actions.searcheverywhere; +import com.intellij.execution.Executor; +import com.intellij.execution.ExecutorRegistry; +import com.intellij.execution.actions.ChooseRunConfigurationPopup; +import com.intellij.execution.actions.ExecutorProvider; +import com.intellij.icons.AllIcons; +import com.intellij.ide.DataManager; +import com.intellij.ide.IdeEventQueue; +import com.intellij.ide.SearchTopHitProvider; +import com.intellij.ide.actions.*; +import com.intellij.ide.actions.searcheverywhere.SearchEverywhereContributor.ContributorSearchResult; +import com.intellij.ide.structureView.StructureView; +import com.intellij.ide.structureView.StructureViewBuilder; +import com.intellij.ide.structureView.StructureViewTreeElement; +import com.intellij.ide.ui.OptionsTopHitProvider; import com.intellij.ide.ui.UISettings; -import com.intellij.openapi.actionSystem.ActionManager; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.CommonShortcuts; +import com.intellij.ide.ui.search.OptionDescription; +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.lang.LanguagePsiElementExternalizer; +import com.intellij.navigation.PsiElementNavigationItem; +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.impl.ActionToolbarImpl; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.actions.TextComponentEditorAction; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.fileEditor.impl.EditorHistoryManager; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.util.ProgressIndicatorBase; 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.ActionCallback; +import com.intellij.openapi.util.Disposer; +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.wm.ToolWindowId; import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.impl.IdeFrameImpl; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiNamedElement; +import com.intellij.psi.codeStyle.MinusculeMatcher; +import com.intellij.psi.codeStyle.NameUtil; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.ui.DocumentAdapter; +import com.intellij.ui.ScrollingUtil; import com.intellij.ui.awt.RelativePoint; +import com.intellij.ui.components.JBLabel; +import com.intellij.ui.components.JBList; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.util.Alarm; +import com.intellij.util.Consumer; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.text.Matcher; +import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.StatusText; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; import java.awt.*; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import static com.intellij.ide.actions.SearchEverywhereAction.SEARCH_EVERYWHERE_POPUP; + public class SearchEverywhereManagerImpl implements SearchEverywhereManager { + + private static final Logger LOG = Logger.getInstance(SearchEverywhereManagerImpl.class); + public static final int ELEMENTS_LIMIT = 15; + private final Project myProject; - private JBPopup myBalloon; + private JBPopup myBalloon; //todo appropriate names #UX-1 + private JBPopup myPopup; private final SearchEverywhereUI mySearchEverywhereUI; + private final JBList myList = new JBList<>(); + + private CalcThread myCalcThread; + private volatile ActionCallback myCurrentWorker = ActionCallback.DONE; + private int myCalcThreadRestartRequestId = 0; + private final Object myWorkerRestartRequestLock = new Object(); + private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, ApplicationManager.getApplication()); + private final ProgressIndicator myProgressIndicator = new ProgressIndicatorBase(); + + private final List allContributors = SearchEverywhereContributor.getProvidersSorted(); public SearchEverywhereManagerImpl(Project project) { myProject = project; - List contributors = SearchEverywhereContributor.getProvidersSorted(); //SearchEverywhereContributor selected = contributors.stream() // .filter(contributor -> contributor.getSearchProviderId().equals(mySelectedProviderID)) // .findAny() // .orElse(null); - mySearchEverywhereUI = new SearchEverywhereUI(contributors, null); + mySearchEverywhereUI = new SearchEverywhereUI(allContributors, null); + JTextField editor = mySearchEverywhereUI.getSearchField(); + editor.getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + if (isShown()) { + rebuildList(editor.getText()); + } + } + }); } @Override @@ -43,7 +135,7 @@ public class SearchEverywhereManagerImpl implements SearchEverywhereManager { else { mySearchEverywhereUI.clear(); mySearchEverywhereUI.switchToContributor(selectedContributorID); - myBalloon = JBPopupFactory.getInstance().createComponentPopupBuilder(mySearchEverywhereUI, mySearchEverywhereUI.getSearchField()) + myBalloon = JBPopupFactory.getInstance().createComponentPopupBuilder(mySearchEverywhereUI, getSearchField()) .setProject(myProject) .setResizable(false) .setModalContext(false) @@ -112,4 +204,349 @@ public class SearchEverywhereManagerImpl implements SearchEverywhereManager { } return new RelativePoint(parent, new Point((parent.getSize().width - mySearchEverywhereUI.getPreferredSize().width) / 2, height)); } + + 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(); + } + + //assert project != null; + //myRenderer.myProject = project; + synchronized (myWorkerRestartRequestLock) { // this lock together with RestartRequestId should be enough to prevent two CalcThreads running at the same time + final int currentRestartRequest = ++myCalcThreadRestartRequestId; + myCurrentWorker.doWhenProcessed(() -> { + synchronized (myWorkerRestartRequestLock) { + if (currentRestartRequest != myCalcThreadRestartRequestId) { + return; + } + myCalcThread = new CalcThread(myProject, pattern, false); + + myCurrentWorker = myCalcThread.start(); + } + }); + } + } + + @SuppressWarnings("Duplicates") //todo remove suppress #UX-1 + 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 SearchEverywhereAction.SearchListModel myListModel; + private final ArrayList myAlreadyAddedFiles = new ArrayList<>(); + private final ArrayList myAlreadyAddedActions = new ArrayList<>(); + + + public CalcThread(Project project, String pattern, boolean reuseModel) { + this.project = project; + this.pattern = pattern; + myListModel = reuseModel ? (SearchEverywhereAction.SearchListModel)myList.getModel() : new SearchEverywhereAction.SearchListModel(); + } + + @Override + public void run() { + try { + check(); + + //noinspection SSBasedInspection + SwingUtilities.invokeLater(() -> { + // 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 SearchEverywhereAction.SearchListModel) { + //noinspection unchecked + myAlarm.cancelAllRequests(); + myAlarm.addRequest(() -> { + 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(); + + SearchEverywhereContributor selectedContributor = mySearchEverywhereUI.getSelectedContributor(); + if (selectedContributor != null) { + runReadAction(() -> addContributorItems(selectedContributor, true), true); + } else { + for (SearchEverywhereContributor contributor : allContributors) { + runReadAction(() -> addContributorItems(contributor, false), true); + } + } + + //runReadAction(() -> buildStructure(pattern), true); + //updatePopup(); + //check(); + //buildToolWindows(pattern); + //check(); + //updatePopup(); + //check(); + // + //checkModelsUpToDate(); + //runReadAction(() -> buildRunConfigurations(pattern), true); + //runReadAction(() -> buildClasses(pattern), true); + //runReadAction(() -> buildFiles(pattern), false); + //runReadAction(() -> 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(() -> myList.getEmptyText().setText(StatusText.DEFAULT_EMPTY_TEXT)); + updatePopup(); + } + if (!myDone.isProcessed()) { + myDone.setDone(); + } + } + } + + private void addContributorItems(SearchEverywhereContributor contributor, boolean exclusiveContributor) { + ContributorSearchResult results = contributor.search(myProject, pattern, mySearchEverywhereUI.isUseNonProjectItems(), myProgressIndicator, ELEMENTS_LIMIT); + if (!results.isEmpty()) { + SwingUtilities.invokeLater(() -> { + if (isCanceled()) return; + + if (!exclusiveContributor) { + myListModel.titleIndex.classes = myListModel.size(); + } + for (Object item : results.getItems()) { + myListModel.addElement(item); + } + if (!exclusiveContributor) { + myListModel.moreIndex.classes = results.hasMoreItems() ? myListModel.size() - 1 : -1; + } + }); + } + } + + 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(); + assert myCalcThread == this : "There are two CalcThreads running before one of them was cancelled"; + } + + + + @NotNull + private GlobalSearchScope getProjectScope(@NotNull Project project) { + final GlobalSearchScope scope = SearchEverywhereClassifier.EP_Manager.getProjectScope(project); + if (scope != null) return scope; + return GlobalSearchScope.projectScope(project); + } + + private boolean isCanceled() { + return myProgressIndicator.isCanceled() || myDone.isRejected(); + } + + @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()) { + ScrollingUtil.installActions(myList, getSearchField()); + JBScrollPane content = new JBScrollPane(myList) { + { + if (UIUtil.isUnderDarcula()) { + setBorder(null); + } + } + @Override + public Dimension getPreferredSize() { + Dimension size = super.getPreferredSize(); + Dimension listSize = myList.getPreferredSize(); + if (size.height > listSize.height || myList.getModel().getSize() == 0) { + size.height = Math.max(JBUI.scale(30), listSize.height); + } + + if (myBalloon != null && size.width < myBalloon.getSize().width) { + size.width = myBalloon.getSize().width; + } + + return size; + } + }; + content.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + content.setMinimumSize(new Dimension(myBalloon.getSize().width, 30)); + final ComponentPopupBuilder builder = JBPopupFactory.getInstance() + .createComponentPopupBuilder(content, null); + myPopup = builder + .setRequestFocus(false) + .setCancelKeyEnabled(false) + .setResizable(true) + .setCancelCallback(() -> { + final JBPopup balloon = myBalloon; + final AWTEvent event = IdeEventQueue.getInstance().getTrueCurrentEvent(); + if (event instanceof MouseEvent) { + final Component comp = ((MouseEvent)event).getComponent(); + if (balloon != null && UIUtil.getWindow(comp) == UIUtil.getWindow(balloon.getContent())) { + return false; + } + } + final boolean canClose = balloon == null || balloon.isDisposed();// || (!getSearchField().hasFocus() && !mySkipFocusGain); + //if (canClose) { + // PropertiesComponent.getInstance().setValue("search.everywhere.max.popup.width", Math.max(content.getWidth(), JBUI.scale(600)), JBUI.scale(600)); + //} + return canClose; + }) + .setShowShadow(false) + .setShowBorder(false) + .createPopup(); + project.putUserData(SEARCH_EVERYWHERE_POPUP, myPopup); + //myPopup.setMinimumSize(new Dimension(myBalloon.getSize().width, 30)); + myPopup.getContent().setBorder(null); + Disposer.register(myPopup, new Disposable() { + @Override + public void dispose() { + project.putUserData(SEARCH_EVERYWHERE_POPUP, null); + ApplicationManager.getApplication().executeOnPooledThread(() -> { + //noinspection SSBasedInspection + SwingUtilities.invokeLater(() -> ActionToolbarImpl.updateAllToolbarsImmediately()); + }); + } + }); + updateResultsPopupBounds(); + myPopup.show(new RelativePoint(mySearchEverywhereUI, new Point(0, mySearchEverywhereUI.getHeight()))); + + ActionManager.getInstance().addAnActionListener(new AnActionListener.Adapter() { + @Override + public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) { + if (action instanceof TextComponentEditorAction) { + return; + } + if (myPopup!=null) { + myPopup.cancel(); + } + } + }, myPopup); + } + else { + myList.revalidate(); + myList.repaint(); + } + ScrollingUtil.ensureSelectionExists(myList); + if (myList.getModel().getSize() > 0) { + updateResultsPopupBounds(); + } + } + }); + } + + public ActionCallback cancel() { + myProgressIndicator.cancel(); + //myDone.setRejected(); + return myDone; + } + + //public ActionCallback insert(final int index, final SearchEverywhereAction.WidgetID id) { + // ApplicationManager.getApplication().executeOnPooledThread(() -> runReadAction(() -> { + // try { + // + // check(); + // SwingUtilities.invokeLater(() -> { + // try { + // int shift = 0; + // int i = index+1; + // for (Object o : result) { + // //noinspection unchecked + // myListModel.insertElementAt(o, i); + // shift++; + // i++; + // } + // SearchEverywhereAction.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; + // } + // } + // ScrollingUtil.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; + } + } + + private void updateResultsPopupBounds() { + int height = myList.getPreferredSize().height + 2; + int width = mySearchEverywhereUI.getWidth(); + myPopup.setSize(JBUI.size(width, height)); + + } + + private JTextField getSearchField() { + return mySearchEverywhereUI.getSearchField(); + } } From 6244473a74c9bae14303bee4024c772e1eeb3842 Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Sat, 28 Apr 2018 13:00:30 +0300 Subject: [PATCH 08/28] UX-1 extract GotoListController --- .../SymbolSearchEverywhereContributor.java | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java index bd0c46e6732a..2f544529eb45 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java @@ -2,9 +2,23 @@ package com.intellij.ide.actions.searcheverywhere; import com.intellij.ide.IdeBundle; +import com.intellij.ide.actions.SearchEverywhereClassifier; +import com.intellij.ide.util.gotoByName.ChooseByNameItemProvider; +import com.intellij.ide.util.gotoByName.ChooseByNameModel; +import com.intellij.ide.util.gotoByName.ChooseByNamePopup; +import com.intellij.ide.util.gotoByName.GotoSymbolModel2; +import com.intellij.navigation.PsiElementNavigationItem; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.List; + /** * @author Konstantin Bulenkov */ @@ -30,4 +44,49 @@ public class SymbolSearchEverywhereContributor implements SearchEverywhereContri public int getSortWeight() { return 300; } + + @Override + public ContributorSearchResult search(Project project, + String pattern, + boolean everywhere, + ProgressIndicator progressIndicator, + int elementsLimit) { + final GlobalSearchScope scope = getProjectScope(project); + ChooseByNameModel model = new GotoSymbolModel2(project); + ChooseByNamePopup popup = ChooseByNamePopup.createPopup(project, model, (PsiElement)null); + final ChooseByNameItemProvider provider = popup.getProvider(); + + List symbols = new ArrayList<>(); + boolean[] hasMore = {false}; + provider.filterElements(popup, pattern, everywhere,progressIndicator, o -> { + if (SearchEverywhereClassifier.EP_Manager.isSymbol(o) && !symbols.contains(o)) { + PsiElement element = null; + if (o instanceof PsiElement) { + element = (PsiElement)o; + } + else if (o instanceof PsiElementNavigationItem) { + element = ((PsiElementNavigationItem)o).getTargetElement(); + } + VirtualFile virtualFile = SearchEverywhereClassifier.EP_Manager.getVirtualFile(o); + //some elements are non-physical like DB columns + boolean isElementWithoutFile = element != null && element.getContainingFile() == null; + boolean isFileInScope = virtualFile != null && (everywhere || scope.accept(virtualFile)); + boolean isSpecialElement = element == null && virtualFile == null; //all Rider elements don't have any psi elements within + if (isElementWithoutFile || isFileInScope || isSpecialElement) { + symbols.add(o); + } + } + hasMore[0] = symbols.size() >= elementsLimit; + return !hasMore[0]; + }); + + return new ContributorSearchResult(symbols, hasMore[0]); + } + + @NotNull + private static GlobalSearchScope getProjectScope(@NotNull Project project) { + final GlobalSearchScope scope = SearchEverywhereClassifier.EP_Manager.getProjectScope(project); + if (scope != null) return scope; + return GlobalSearchScope.projectScope(project); + } } From 76347f136001122c86977ddfed77ae1e509e5661 Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Sat, 28 Apr 2018 14:38:16 +0300 Subject: [PATCH 09/28] UX-1 extract GotoListController * Result list updating code moved to SearchEverywhereUI --- .../SearchEverywhereManagerImpl.java | 445 +----------------- .../searcheverywhere/SearchEverywhereUI.java | 395 +++++++++++++++- 2 files changed, 402 insertions(+), 438 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java index 17ac5be769b2..2e6dfaa99c17 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java @@ -1,112 +1,28 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.actions.searcheverywhere; -import com.intellij.execution.Executor; -import com.intellij.execution.ExecutorRegistry; -import com.intellij.execution.actions.ChooseRunConfigurationPopup; -import com.intellij.execution.actions.ExecutorProvider; -import com.intellij.icons.AllIcons; -import com.intellij.ide.DataManager; -import com.intellij.ide.IdeEventQueue; -import com.intellij.ide.SearchTopHitProvider; -import com.intellij.ide.actions.*; -import com.intellij.ide.actions.searcheverywhere.SearchEverywhereContributor.ContributorSearchResult; -import com.intellij.ide.structureView.StructureView; -import com.intellij.ide.structureView.StructureViewBuilder; -import com.intellij.ide.structureView.StructureViewTreeElement; -import com.intellij.ide.ui.OptionsTopHitProvider; import com.intellij.ide.ui.UISettings; -import com.intellij.ide.ui.search.OptionDescription; -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.lang.LanguagePsiElementExternalizer; -import com.intellij.navigation.PsiElementNavigationItem; -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.impl.ActionToolbarImpl; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.actions.TextComponentEditorAction; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.fileEditor.impl.EditorHistoryManager; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.util.ProgressIndicatorBase; 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.ActionCallback; -import com.intellij.openapi.util.Disposer; -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.wm.ToolWindowId; import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.impl.IdeFrameImpl; -import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiNamedElement; -import com.intellij.psi.codeStyle.MinusculeMatcher; -import com.intellij.psi.codeStyle.NameUtil; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.ui.DocumentAdapter; -import com.intellij.ui.ScrollingUtil; import com.intellij.ui.awt.RelativePoint; -import com.intellij.ui.components.JBLabel; -import com.intellij.ui.components.JBList; -import com.intellij.ui.components.JBScrollPane; -import com.intellij.util.Alarm; -import com.intellij.util.Consumer; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.text.Matcher; -import com.intellij.util.ui.JBUI; -import com.intellij.util.ui.StatusText; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; import java.awt.*; -import java.awt.event.MouseEvent; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; import java.util.List; -import static com.intellij.ide.actions.SearchEverywhereAction.SEARCH_EVERYWHERE_POPUP; - public class SearchEverywhereManagerImpl implements SearchEverywhereManager { - private static final Logger LOG = Logger.getInstance(SearchEverywhereManagerImpl.class); - public static final int ELEMENTS_LIMIT = 15; - private final Project myProject; private JBPopup myBalloon; //todo appropriate names #UX-1 - private JBPopup myPopup; private final SearchEverywhereUI mySearchEverywhereUI; - private final JBList myList = new JBList<>(); - - private CalcThread myCalcThread; - private volatile ActionCallback myCurrentWorker = ActionCallback.DONE; - private int myCalcThreadRestartRequestId = 0; - private final Object myWorkerRestartRequestLock = new Object(); - private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, ApplicationManager.getApplication()); - private final ProgressIndicator myProgressIndicator = new ProgressIndicatorBase(); - - private final List allContributors = SearchEverywhereContributor.getProvidersSorted(); public SearchEverywhereManagerImpl(Project project) { myProject = project; @@ -115,16 +31,8 @@ public class SearchEverywhereManagerImpl implements SearchEverywhereManager { // .filter(contributor -> contributor.getSearchProviderId().equals(mySelectedProviderID)) // .findAny() // .orElse(null); - mySearchEverywhereUI = new SearchEverywhereUI(allContributors, null); - JTextField editor = mySearchEverywhereUI.getSearchField(); - editor.getDocument().addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(DocumentEvent e) { - if (isShown()) { - rebuildList(editor.getText()); - } - } - }); + List allContributors = SearchEverywhereContributor.getProvidersSorted(); + mySearchEverywhereUI = new SearchEverywhereUI(project, allContributors, null); } @Override @@ -133,7 +41,7 @@ public class SearchEverywhereManagerImpl implements SearchEverywhereManager { setShownContributor(selectedContributorID); } else { - mySearchEverywhereUI.clear(); + mySearchEverywhereUI.setShown(true); mySearchEverywhereUI.switchToContributor(selectedContributorID); myBalloon = JBPopupFactory.getInstance().createComponentPopupBuilder(mySearchEverywhereUI, getSearchField()) .setProject(myProject) @@ -142,7 +50,11 @@ public class SearchEverywhereManagerImpl implements SearchEverywhereManager { .setCancelOnClickOutside(true) .setRequestFocus(true) .setCancelKeyEnabled(false) - .setCancelCallback(() -> true) + .setCancelCallback(() -> { + mySearchEverywhereUI.clear(); + mySearchEverywhereUI.setShown(false); + return true; + }) .addUserData("SIMPLE_WINDOW") .createPopup(); @@ -205,347 +117,6 @@ public class SearchEverywhereManagerImpl implements SearchEverywhereManager { return new RelativePoint(parent, new Point((parent.getSize().width - mySearchEverywhereUI.getPreferredSize().width) / 2, height)); } - 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(); - } - - //assert project != null; - //myRenderer.myProject = project; - synchronized (myWorkerRestartRequestLock) { // this lock together with RestartRequestId should be enough to prevent two CalcThreads running at the same time - final int currentRestartRequest = ++myCalcThreadRestartRequestId; - myCurrentWorker.doWhenProcessed(() -> { - synchronized (myWorkerRestartRequestLock) { - if (currentRestartRequest != myCalcThreadRestartRequestId) { - return; - } - myCalcThread = new CalcThread(myProject, pattern, false); - - myCurrentWorker = myCalcThread.start(); - } - }); - } - } - - @SuppressWarnings("Duplicates") //todo remove suppress #UX-1 - 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 SearchEverywhereAction.SearchListModel myListModel; - private final ArrayList myAlreadyAddedFiles = new ArrayList<>(); - private final ArrayList myAlreadyAddedActions = new ArrayList<>(); - - - public CalcThread(Project project, String pattern, boolean reuseModel) { - this.project = project; - this.pattern = pattern; - myListModel = reuseModel ? (SearchEverywhereAction.SearchListModel)myList.getModel() : new SearchEverywhereAction.SearchListModel(); - } - - @Override - public void run() { - try { - check(); - - //noinspection SSBasedInspection - SwingUtilities.invokeLater(() -> { - // 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 SearchEverywhereAction.SearchListModel) { - //noinspection unchecked - myAlarm.cancelAllRequests(); - myAlarm.addRequest(() -> { - 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(); - - SearchEverywhereContributor selectedContributor = mySearchEverywhereUI.getSelectedContributor(); - if (selectedContributor != null) { - runReadAction(() -> addContributorItems(selectedContributor, true), true); - } else { - for (SearchEverywhereContributor contributor : allContributors) { - runReadAction(() -> addContributorItems(contributor, false), true); - } - } - - //runReadAction(() -> buildStructure(pattern), true); - //updatePopup(); - //check(); - //buildToolWindows(pattern); - //check(); - //updatePopup(); - //check(); - // - //checkModelsUpToDate(); - //runReadAction(() -> buildRunConfigurations(pattern), true); - //runReadAction(() -> buildClasses(pattern), true); - //runReadAction(() -> buildFiles(pattern), false); - //runReadAction(() -> 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(() -> myList.getEmptyText().setText(StatusText.DEFAULT_EMPTY_TEXT)); - updatePopup(); - } - if (!myDone.isProcessed()) { - myDone.setDone(); - } - } - } - - private void addContributorItems(SearchEverywhereContributor contributor, boolean exclusiveContributor) { - ContributorSearchResult results = contributor.search(myProject, pattern, mySearchEverywhereUI.isUseNonProjectItems(), myProgressIndicator, ELEMENTS_LIMIT); - if (!results.isEmpty()) { - SwingUtilities.invokeLater(() -> { - if (isCanceled()) return; - - if (!exclusiveContributor) { - myListModel.titleIndex.classes = myListModel.size(); - } - for (Object item : results.getItems()) { - myListModel.addElement(item); - } - if (!exclusiveContributor) { - myListModel.moreIndex.classes = results.hasMoreItems() ? myListModel.size() - 1 : -1; - } - }); - } - } - - 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(); - assert myCalcThread == this : "There are two CalcThreads running before one of them was cancelled"; - } - - - - @NotNull - private GlobalSearchScope getProjectScope(@NotNull Project project) { - final GlobalSearchScope scope = SearchEverywhereClassifier.EP_Manager.getProjectScope(project); - if (scope != null) return scope; - return GlobalSearchScope.projectScope(project); - } - - private boolean isCanceled() { - return myProgressIndicator.isCanceled() || myDone.isRejected(); - } - - @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()) { - ScrollingUtil.installActions(myList, getSearchField()); - JBScrollPane content = new JBScrollPane(myList) { - { - if (UIUtil.isUnderDarcula()) { - setBorder(null); - } - } - @Override - public Dimension getPreferredSize() { - Dimension size = super.getPreferredSize(); - Dimension listSize = myList.getPreferredSize(); - if (size.height > listSize.height || myList.getModel().getSize() == 0) { - size.height = Math.max(JBUI.scale(30), listSize.height); - } - - if (myBalloon != null && size.width < myBalloon.getSize().width) { - size.width = myBalloon.getSize().width; - } - - return size; - } - }; - content.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - content.setMinimumSize(new Dimension(myBalloon.getSize().width, 30)); - final ComponentPopupBuilder builder = JBPopupFactory.getInstance() - .createComponentPopupBuilder(content, null); - myPopup = builder - .setRequestFocus(false) - .setCancelKeyEnabled(false) - .setResizable(true) - .setCancelCallback(() -> { - final JBPopup balloon = myBalloon; - final AWTEvent event = IdeEventQueue.getInstance().getTrueCurrentEvent(); - if (event instanceof MouseEvent) { - final Component comp = ((MouseEvent)event).getComponent(); - if (balloon != null && UIUtil.getWindow(comp) == UIUtil.getWindow(balloon.getContent())) { - return false; - } - } - final boolean canClose = balloon == null || balloon.isDisposed();// || (!getSearchField().hasFocus() && !mySkipFocusGain); - //if (canClose) { - // PropertiesComponent.getInstance().setValue("search.everywhere.max.popup.width", Math.max(content.getWidth(), JBUI.scale(600)), JBUI.scale(600)); - //} - return canClose; - }) - .setShowShadow(false) - .setShowBorder(false) - .createPopup(); - project.putUserData(SEARCH_EVERYWHERE_POPUP, myPopup); - //myPopup.setMinimumSize(new Dimension(myBalloon.getSize().width, 30)); - myPopup.getContent().setBorder(null); - Disposer.register(myPopup, new Disposable() { - @Override - public void dispose() { - project.putUserData(SEARCH_EVERYWHERE_POPUP, null); - ApplicationManager.getApplication().executeOnPooledThread(() -> { - //noinspection SSBasedInspection - SwingUtilities.invokeLater(() -> ActionToolbarImpl.updateAllToolbarsImmediately()); - }); - } - }); - updateResultsPopupBounds(); - myPopup.show(new RelativePoint(mySearchEverywhereUI, new Point(0, mySearchEverywhereUI.getHeight()))); - - ActionManager.getInstance().addAnActionListener(new AnActionListener.Adapter() { - @Override - public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) { - if (action instanceof TextComponentEditorAction) { - return; - } - if (myPopup!=null) { - myPopup.cancel(); - } - } - }, myPopup); - } - else { - myList.revalidate(); - myList.repaint(); - } - ScrollingUtil.ensureSelectionExists(myList); - if (myList.getModel().getSize() > 0) { - updateResultsPopupBounds(); - } - } - }); - } - - public ActionCallback cancel() { - myProgressIndicator.cancel(); - //myDone.setRejected(); - return myDone; - } - - //public ActionCallback insert(final int index, final SearchEverywhereAction.WidgetID id) { - // ApplicationManager.getApplication().executeOnPooledThread(() -> runReadAction(() -> { - // try { - // - // check(); - // SwingUtilities.invokeLater(() -> { - // try { - // int shift = 0; - // int i = index+1; - // for (Object o : result) { - // //noinspection unchecked - // myListModel.insertElementAt(o, i); - // shift++; - // i++; - // } - // SearchEverywhereAction.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; - // } - // } - // ScrollingUtil.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; - } - } - - private void updateResultsPopupBounds() { - int height = myList.getPreferredSize().height + 2; - int width = mySearchEverywhereUI.getWidth(); - myPopup.setSize(JBUI.size(width, height)); - - } - private JTextField getSearchField() { return mySearchEverywhereUI.getSearchField(); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java index d597d4e35b7b..a9e06452ff87 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java @@ -3,14 +3,38 @@ package com.intellij.ide.actions.searcheverywhere; import com.intellij.icons.AllIcons; import com.intellij.ide.IdeBundle; +import com.intellij.ide.IdeEventQueue; +import com.intellij.ide.actions.SearchEverywhereAction; import com.intellij.ide.ui.UISettings; +import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ex.AnActionListener; import com.intellij.openapi.actionSystem.impl.ActionButton; +import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.actions.TextComponentEditorAction; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.util.ProgressIndicatorBase; +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.ActionCallback; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.*; +import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.JBCheckBox; +import com.intellij.ui.components.JBList; +import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.fields.ExtendableTextField; +import com.intellij.util.Alarm; import com.intellij.util.ui.DialogUtil; import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.StatusText; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.components.BorderLayoutPanel; import org.jetbrains.annotations.NotNull; @@ -18,6 +42,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.Border; +import javax.swing.event.DocumentEvent; import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; @@ -26,22 +51,46 @@ import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; +import static com.intellij.ide.actions.SearchEverywhereAction.SEARCH_EVERYWHERE_POPUP; + /** * @author Konstantin Bulenkov * @author Mikhail.Sokolov */ public class SearchEverywhereUI extends BorderLayoutPanel { + private static final Logger LOG = Logger.getInstance(SearchEverywhereUI.class); + public static final int ELEMENTS_LIMIT = 15; + + private final List allContributors; + private final Project myProject; + + private boolean myShown; + private SETab mySelectedTab; private final JTextField mySearchField; private final JCheckBox myNonProjectCB; private final List myTabs = new ArrayList<>(); + private JBPopup myPopup; + private final JBList myList = new JBList<>(); + + private CalcThread myCalcThread; + private volatile ActionCallback myCurrentWorker = ActionCallback.DONE; + private int myCalcThreadRestartRequestId = 0; + private final Object myWorkerRestartRequestLock = new Object(); + private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, ApplicationManager.getApplication()); + // todo remove second param #UX-1 - public SearchEverywhereUI(List contributors, @Nullable SearchEverywhereContributor selected) { + public SearchEverywhereUI(Project project, + List contributors, + @Nullable SearchEverywhereContributor selected) { + myProject = project; withMinimumWidth(670); withPreferredWidth(670); setBackground(JBUI.CurrentTheme.SearchEverywhere.dialogBackground()); + allContributors = contributors; + myNonProjectCB = new JBCheckBox(); myNonProjectCB.setOpaque(false); myNonProjectCB.setFocusable(false); @@ -84,6 +133,11 @@ public class SearchEverywhereUI extends BorderLayoutPanel { myNonProjectCB.setSelected(false); } + public void setShown(boolean shown) { + myShown = shown; + //todo cancel all threads #UX-1 + } + private void switchToNextTab() { int currentIndex = myTabs.indexOf(mySelectedTab); SETab nextTab = currentIndex == myTabs.size() - 1 ? myTabs.get(0) : myTabs.get(currentIndex + 1); @@ -159,6 +213,13 @@ public class SearchEverywhereUI extends BorderLayoutPanel { } }); + searchField.getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + rebuildList(searchField.getText()); + } + }); + return searchField; } @@ -262,4 +323,336 @@ public class SearchEverywhereUI extends BorderLayoutPanel { : super.getBackground(); } } + + 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(); + } + + //assert project != null; + //myRenderer.myProject = project; + synchronized (myWorkerRestartRequestLock) { // this lock together with RestartRequestId should be enough to prevent two CalcThreads running at the same time + final int currentRestartRequest = ++myCalcThreadRestartRequestId; + myCurrentWorker.doWhenProcessed(() -> { + synchronized (myWorkerRestartRequestLock) { + if (currentRestartRequest != myCalcThreadRestartRequestId) { + return; + } + myCalcThread = new CalcThread(myProject, pattern, false); + + myCurrentWorker = myCalcThread.start(); + } + }); + } + } + + @SuppressWarnings("Duplicates") //todo remove suppress #UX-1 + 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 SearchEverywhereAction.SearchListModel myListModel; + private final ArrayList myAlreadyAddedFiles = new ArrayList<>(); + private final ArrayList myAlreadyAddedActions = new ArrayList<>(); + + + public CalcThread(Project project, String pattern, boolean reuseModel) { + this.project = project; + this.pattern = pattern; + myListModel = reuseModel ? (SearchEverywhereAction.SearchListModel) myList.getModel() : new SearchEverywhereAction.SearchListModel(); + } + + @Override + public void run() { + try { + check(); + + //noinspection SSBasedInspection + SwingUtilities.invokeLater(() -> { + // 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 SearchEverywhereAction.SearchListModel) { + //noinspection unchecked + myAlarm.cancelAllRequests(); + myAlarm.addRequest(() -> { + 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(); + + SearchEverywhereContributor selectedContributor = getSelectedContributor(); + if (selectedContributor != null) { + runReadAction(() -> addContributorItems(selectedContributor, true), true); + } else { + for (SearchEverywhereContributor contributor : allContributors) { + runReadAction(() -> addContributorItems(contributor, false), true); + } + } + + //runReadAction(() -> buildStructure(pattern), true); + //updatePopup(); + //check(); + //buildToolWindows(pattern); + //check(); + //updatePopup(); + //check(); + // + //checkModelsUpToDate(); + //runReadAction(() -> buildRunConfigurations(pattern), true); + //runReadAction(() -> buildClasses(pattern), true); + //runReadAction(() -> buildFiles(pattern), false); + //runReadAction(() -> 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(() -> myList.getEmptyText().setText(StatusText.DEFAULT_EMPTY_TEXT)); + updatePopup(); + } + if (!myDone.isProcessed()) { + myDone.setDone(); + } + } + } + + private void addContributorItems(SearchEverywhereContributor contributor, boolean exclusiveContributor) { + SearchEverywhereContributor.ContributorSearchResult + results = contributor.search(project, pattern, isUseNonProjectItems(), myProgressIndicator, ELEMENTS_LIMIT); + if (!results.isEmpty()) { + SwingUtilities.invokeLater(() -> { + if (isCanceled()) return; + + if (!exclusiveContributor) { + myListModel.titleIndex.classes = myListModel.size(); + } + for (Object item : results.getItems()) { + myListModel.addElement(item); + } + if (!exclusiveContributor) { + myListModel.moreIndex.classes = results.hasMoreItems() ? myListModel.size() - 1 : -1; + } + }); + } + } + + 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 (!myShown) throw new ProcessCanceledException(); + assert myCalcThread == this : "There are two CalcThreads running before one of them was cancelled"; + } + + private boolean isCanceled() { + return myProgressIndicator.isCanceled() || myDone.isRejected(); + } + + @SuppressWarnings("SSBasedInspection") + private void updatePopup() { + check(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + myListModel.update(); + myList.revalidate(); + myList.repaint(); + + //myRenderer.recalculateWidth(); + if (!myShown) { + return; + } + if (myPopup == null || !myPopup.isVisible()) { + ScrollingUtil.installActions(myList, getSearchField()); + JBScrollPane content = new JBScrollPane(myList) { + { + if (UIUtil.isUnderDarcula()) { + setBorder(null); + } + } + @Override + public Dimension getPreferredSize() { + Dimension size = super.getPreferredSize(); + Dimension listSize = myList.getPreferredSize(); + if (size.height > listSize.height || myList.getModel().getSize() == 0) { + size.height = Math.max(JBUI.scale(30), listSize.height); + } + + if (size.width < getWidth()) { + size.width = getWidth(); + } + + return size; + } + }; + content.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + content.setMinimumSize(new Dimension(getWidth(), 30)); + final ComponentPopupBuilder builder = JBPopupFactory.getInstance() + .createComponentPopupBuilder(content, null); + myPopup = builder + .setRequestFocus(false) + .setCancelKeyEnabled(false) + .setResizable(true) + .setCancelCallback(() -> { + final AWTEvent event = IdeEventQueue.getInstance().getTrueCurrentEvent(); + if (event instanceof MouseEvent) { + final Component comp = ((MouseEvent)event).getComponent(); + if (UIUtil.getWindow(comp) == UIUtil.getWindow(SearchEverywhereUI.this)) { + return false; + } + } + //final boolean canClose = balloon == null || balloon.isDisposed() || (!getSearchField().hasFocus() && !mySkipFocusGain); + //if (canClose) { + // PropertiesComponent.getInstance().setValue("search.everywhere.max.popup.width", Math.max(content.getWidth(), JBUI.scale(600)), JBUI.scale(600)); + //} + return true; + }) + .setShowShadow(false) + .setShowBorder(false) + .createPopup(); + project.putUserData(SEARCH_EVERYWHERE_POPUP, myPopup); + //myPopup.setMinimumSize(new Dimension(myBalloon.getSize().width, 30)); + myPopup.getContent().setBorder(null); + Disposer.register(myPopup, new Disposable() { + @Override + public void dispose() { + project.putUserData(SEARCH_EVERYWHERE_POPUP, null); + ApplicationManager.getApplication().executeOnPooledThread(() -> { + //noinspection SSBasedInspection + SwingUtilities.invokeLater(() -> ActionToolbarImpl.updateAllToolbarsImmediately()); + }); + } + }); + updateResultsPopupBounds(); + myPopup.show(new RelativePoint(SearchEverywhereUI.this, new Point(0, getHeight()))); + + ActionManager.getInstance().addAnActionListener(new AnActionListener.Adapter() { + @Override + public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) { + if (action instanceof TextComponentEditorAction) { + return; + } + if (myPopup!=null) { + myPopup.cancel(); + } + } + }, myPopup); + } + else { + myList.revalidate(); + myList.repaint(); + } + ScrollingUtil.ensureSelectionExists(myList); + if (myList.getModel().getSize() > 0) { + updateResultsPopupBounds(); + } + } + }); + } + + public ActionCallback cancel() { + myProgressIndicator.cancel(); + //myDone.setRejected(); + return myDone; + } + + //public ActionCallback insert(final int index, final SearchEverywhereAction.WidgetID id) { + // ApplicationManager.getApplication().executeOnPooledThread(() -> runReadAction(() -> { + // try { + // + // check(); + // SwingUtilities.invokeLater(() -> { + // try { + // int shift = 0; + // int i = index+1; + // for (Object o : result) { + // //noinspection unchecked + // myListModel.insertElementAt(o, i); + // shift++; + // i++; + // } + // SearchEverywhereAction.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; + // } + // } + // ScrollingUtil.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; + } + } + + private void updateResultsPopupBounds() { + int height = myList.getPreferredSize().height + 2; + int width = getWidth(); + myPopup.setSize(JBUI.size(width, height)); + + } } From 3fed92cbeb7bd9802c06f5b1c33686261ab2a99e Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Sat, 28 Apr 2018 14:53:28 +0300 Subject: [PATCH 10/28] UX-1 extract GotoListController * Result list updating code moved to SearchEverywhereUI --- .../searcheverywhere/SearchEverywhereUI.java | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java index a9e06452ff87..df0373130f2a 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java @@ -71,8 +71,8 @@ public class SearchEverywhereUI extends BorderLayoutPanel { private final JCheckBox myNonProjectCB; private final List myTabs = new ArrayList<>(); - private JBPopup myPopup; - private final JBList myList = new JBList<>(); + private JBPopup myResultsPopup; + private final JBList myResultsList = new JBList<>(); private CalcThread myCalcThread; private volatile ActionCallback myCurrentWorker = ActionCallback.DONE; @@ -364,7 +364,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { public CalcThread(Project project, String pattern, boolean reuseModel) { this.project = project; this.pattern = pattern; - myListModel = reuseModel ? (SearchEverywhereAction.SearchListModel) myList.getModel() : new SearchEverywhereAction.SearchListModel(); + myListModel = reuseModel ? (SearchEverywhereAction.SearchListModel) myResultsList.getModel() : new SearchEverywhereAction.SearchListModel(); } @Override @@ -375,19 +375,19 @@ public class SearchEverywhereUI extends BorderLayoutPanel { //noinspection SSBasedInspection SwingUtilities.invokeLater(() -> { // this line must be called on EDT to avoid context switch at clear().append("text") Don't touch. Ask [kb] - myList.getEmptyText().setText("Searching..."); + myResultsList.getEmptyText().setText("Searching..."); - if (myList.getModel() instanceof SearchEverywhereAction.SearchListModel) { + if (myResultsList.getModel() instanceof SearchEverywhereAction.SearchListModel) { //noinspection unchecked myAlarm.cancelAllRequests(); myAlarm.addRequest(() -> { if (!myDone.isRejected()) { - myList.setModel(myListModel); + myResultsList.setModel(myListModel); updatePopup(); } }, 50); } else { - myList.setModel(myListModel); + myResultsList.setModel(myListModel); } }); @@ -444,7 +444,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { finally { if (!isCanceled()) { //noinspection SSBasedInspection - SwingUtilities.invokeLater(() -> myList.getEmptyText().setText(StatusText.DEFAULT_EMPTY_TEXT)); + SwingUtilities.invokeLater(() -> myResultsList.getEmptyText().setText(StatusText.DEFAULT_EMPTY_TEXT)); updatePopup(); } if (!myDone.isProcessed()) { @@ -498,16 +498,16 @@ public class SearchEverywhereUI extends BorderLayoutPanel { @Override public void run() { myListModel.update(); - myList.revalidate(); - myList.repaint(); + myResultsList.revalidate(); + myResultsList.repaint(); //myRenderer.recalculateWidth(); if (!myShown) { return; } - if (myPopup == null || !myPopup.isVisible()) { - ScrollingUtil.installActions(myList, getSearchField()); - JBScrollPane content = new JBScrollPane(myList) { + if (myResultsPopup == null || !myResultsPopup.isVisible()) { + ScrollingUtil.installActions(myResultsList, getSearchField()); + JBScrollPane content = new JBScrollPane(myResultsList) { { if (UIUtil.isUnderDarcula()) { setBorder(null); @@ -516,8 +516,8 @@ public class SearchEverywhereUI extends BorderLayoutPanel { @Override public Dimension getPreferredSize() { Dimension size = super.getPreferredSize(); - Dimension listSize = myList.getPreferredSize(); - if (size.height > listSize.height || myList.getModel().getSize() == 0) { + Dimension listSize = myResultsList.getPreferredSize(); + if (size.height > listSize.height || myResultsList.getModel().getSize() == 0) { size.height = Math.max(JBUI.scale(30), listSize.height); } @@ -532,7 +532,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { content.setMinimumSize(new Dimension(getWidth(), 30)); final ComponentPopupBuilder builder = JBPopupFactory.getInstance() .createComponentPopupBuilder(content, null); - myPopup = builder + myResultsPopup = builder .setRequestFocus(false) .setCancelKeyEnabled(false) .setResizable(true) @@ -553,10 +553,10 @@ public class SearchEverywhereUI extends BorderLayoutPanel { .setShowShadow(false) .setShowBorder(false) .createPopup(); - project.putUserData(SEARCH_EVERYWHERE_POPUP, myPopup); - //myPopup.setMinimumSize(new Dimension(myBalloon.getSize().width, 30)); - myPopup.getContent().setBorder(null); - Disposer.register(myPopup, new Disposable() { + project.putUserData(SEARCH_EVERYWHERE_POPUP, myResultsPopup); + //myResultsPopup.setMinimumSize(new Dimension(myBalloon.getSize().width, 30)); + myResultsPopup.getContent().setBorder(null); + Disposer.register(myResultsPopup, new Disposable() { @Override public void dispose() { project.putUserData(SEARCH_EVERYWHERE_POPUP, null); @@ -567,7 +567,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { } }); updateResultsPopupBounds(); - myPopup.show(new RelativePoint(SearchEverywhereUI.this, new Point(0, getHeight()))); + myResultsPopup.show(new RelativePoint(SearchEverywhereUI.this, new Point(0, getHeight()))); ActionManager.getInstance().addAnActionListener(new AnActionListener.Adapter() { @Override @@ -575,18 +575,18 @@ public class SearchEverywhereUI extends BorderLayoutPanel { if (action instanceof TextComponentEditorAction) { return; } - if (myPopup!=null) { - myPopup.cancel(); + if (myResultsPopup != null) { + myResultsPopup.cancel(); } } - }, myPopup); + }, myResultsPopup); } else { - myList.revalidate(); - myList.repaint(); + myResultsList.revalidate(); + myResultsList.repaint(); } - ScrollingUtil.ensureSelectionExists(myList); - if (myList.getModel().getSize() > 0) { + ScrollingUtil.ensureSelectionExists(myResultsList); + if (myResultsList.getModel().getSize() > 0) { updateResultsPopupBounds(); } } @@ -628,7 +628,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { // case RUN_CONFIGURATIONS: moreIndex.runConfigurations = -1; break; // } // } - // ScrollingUtil.selectItem(myList, index); + // ScrollingUtil.selectItem(myResultsList, index); // myDone.setDone(); // } // catch (Exception e) { @@ -650,9 +650,9 @@ public class SearchEverywhereUI extends BorderLayoutPanel { } private void updateResultsPopupBounds() { - int height = myList.getPreferredSize().height + 2; + int height = myResultsList.getPreferredSize().height + 2; int width = getWidth(); - myPopup.setSize(JBUI.size(width, height)); + myResultsPopup.setSize(JBUI.size(width, height)); } } From 2f2c9334102e205007d6dfb20e2a0cd9b953ef5a Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Thu, 3 May 2018 19:48:52 +0300 Subject: [PATCH 11/28] UX-1 extract GotoListController * get list elements renderer from contributors --- .../SearchEverywhereContributor.java | 4 + .../AllSearchEverywhereContributor.java | 9 + .../ClassSearchEverywhereContributor.java | 7 + .../FileSearchEverywhereContributor.java | 62 ++++--- .../searcheverywhere/SearchEverywhereUI.java | 159 ++++++++++++------ .../SymbolSearchEverywhereContributor.java | 7 + 6 files changed, 165 insertions(+), 83 deletions(-) diff --git a/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java b/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java index 4a908326a5f7..d178153ebd85 100644 --- a/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java +++ b/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java @@ -10,6 +10,7 @@ import com.intellij.openapi.project.Project; import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; +import javax.swing.*; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; @@ -41,6 +42,9 @@ public interface SearchEverywhereContributor { return search(project, pattern, everywhere, progressIndicator, -1).getItems(); } + //todo any way to listen project in contributor + ListCellRenderer getElementsRenderer(Project project); + static List getProvidersSorted() { return Arrays.stream(EP_NAME.getExtensions()) .sorted(Comparator.comparingInt(SearchEverywhereContributor::getSortWeight)) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AllSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AllSearchEverywhereContributor.java index c12f7a545108..59bef8f07453 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AllSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AllSearchEverywhereContributor.java @@ -2,9 +2,13 @@ package com.intellij.ide.actions.searcheverywhere; import com.intellij.ide.IdeBundle; +import com.intellij.ide.util.NavigationItemListCellRenderer; +import com.intellij.openapi.project.Project; import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; +import javax.swing.*; + public class AllSearchEverywhereContributor implements SearchEverywhereContributor { @NotNull @@ -28,4 +32,9 @@ public class AllSearchEverywhereContributor implements SearchEverywhereContribut public String includeNonProjectItemsText() { return IdeBundle.message("checkbox.include.non.project.items", IdeUICustomization.getInstance().getProjectConceptName()); } + + @Override + public ListCellRenderer getElementsRenderer(Project project) { + return new NavigationItemListCellRenderer(); + } } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java index f3af44805f70..cd058c750f79 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java @@ -3,6 +3,7 @@ package com.intellij.ide.actions.searcheverywhere; import com.intellij.ide.IdeBundle; import com.intellij.ide.actions.SearchEverywhereClassifier; +import com.intellij.ide.util.NavigationItemListCellRenderer; import com.intellij.ide.util.gotoByName.ChooseByNameModel; import com.intellij.ide.util.gotoByName.ChooseByNamePopup; import com.intellij.ide.util.gotoByName.GotoClassModel2; @@ -12,6 +13,7 @@ import com.intellij.psi.PsiElement; import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; +import javax.swing.*; import java.util.ArrayList; import java.util.List; @@ -60,4 +62,9 @@ public class ClassSearchEverywhereContributor implements SearchEverywhereContrib return new SearchEverywhereContributor.ContributorSearchResult(items, hasMore[0]); } + + @Override + public ListCellRenderer getElementsRenderer(Project project) { + return new NavigationItemListCellRenderer(); + } } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java index 39246e0582ef..4e9bbd0e0c96 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java @@ -8,14 +8,12 @@ import com.intellij.ide.util.gotoByName.ChooseByNamePopup; import com.intellij.ide.util.gotoByName.GotoFileModel; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; +import javax.swing.*; import java.util.ArrayList; import java.util.List; @@ -47,42 +45,35 @@ public class FileSearchEverywhereContributor implements SearchEverywhereContribu @Override public ContributorSearchResult search(Project project, String pattern, boolean everywhere, ProgressIndicator progressIndicator, int elementsLimit) { - final GlobalSearchScope scope = getProjectScope(project); + ChooseByNameModel mdl = createModel(project); - ChooseByNameModel mdl = new GotoFileModel(project){ + ChooseByNamePopup popup = ChooseByNamePopup.createPopup(project, mdl, (PsiElement)null); + List items = new ArrayList<>(); + boolean[] hasMore = {false}; //todo builder for ContributorSearchResult #UX-1 + popup.getProvider().filterElements(popup, pattern, everywhere, + progressIndicator, o -> { + + if (o != null && !items.contains(o)) { + if (elementsLimit >= 0 && items.size() >= elementsLimit) { + hasMore[0] = true; + return false; + } + items.add(o); + } + return true; + }); + + return new ContributorSearchResult(items, hasMore[0]); + } + + @NotNull + private GotoFileModel createModel(Project project) { + return new GotoFileModel(project){ @Override public boolean isSlashlessMatchingEnabled() { return false; } }; - - ChooseByNamePopup popup = ChooseByNamePopup.createPopup(project, mdl, (PsiElement)null); - List items = new ArrayList<>(); - boolean[] hasMore = {false}; //todo builder for ContributorSearchResult #UX-1 - popup.getProvider().filterElements(popup, pattern, true, - progressIndicator, 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) - && (everywhere || scope.accept(file)) - && !items.contains(file)) { - if (elementsLimit >= 0 && items.size() >= elementsLimit) { - hasMore[0] = true; - return false; - } - items.add(file); - } - return true; - }); - - return new ContributorSearchResult(items, hasMore[0]); } @NotNull @@ -91,4 +82,9 @@ public class FileSearchEverywhereContributor implements SearchEverywhereContribu if (scope != null) return scope; return GlobalSearchScope.projectScope(project); } + + @Override + public ListCellRenderer getElementsRenderer(Project project) { + return createModel(project).getListCellRenderer(); + } } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java index df0373130f2a..092859e9c612 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java @@ -24,7 +24,8 @@ import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.codeStyle.MinusculeMatcher; +import com.intellij.psi.codeStyle.NameUtil; import com.intellij.ui.*; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.JBCheckBox; @@ -32,6 +33,8 @@ import com.intellij.ui.components.JBList; import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.fields.ExtendableTextField; import com.intellij.util.Alarm; +import com.intellij.util.Range; +import com.intellij.util.text.MatcherHolder; import com.intellij.util.ui.DialogUtil; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.StatusText; @@ -48,7 +51,7 @@ import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.util.ArrayList; +import java.util.*; import java.util.List; import static com.intellij.ide.actions.SearchEverywhereAction.SEARCH_EVERYWHERE_POPUP; @@ -74,6 +77,8 @@ public class SearchEverywhereUI extends BorderLayoutPanel { private JBPopup myResultsPopup; private final JBList myResultsList = new JBList<>(); + private final Map myResultsRanges = new HashMap<>(); + private CalcThread myCalcThread; private volatile ActionCallback myCurrentWorker = ActionCallback.DONE; private int myCalcThreadRestartRequestId = 0; @@ -102,6 +107,8 @@ public class SearchEverywhereUI extends BorderLayoutPanel { addToLeft(contributorsPanel); addToRight(settingsPanel); addToBottom(mySearchField); + + myResultsList.setCellRenderer(new CompositeCellRenderer(myResultsRanges)); } public JTextField getSearchField() { @@ -333,6 +340,9 @@ public class SearchEverywhereUI extends BorderLayoutPanel { myCalcThread.cancel(); } + MinusculeMatcher matcher = NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE); + MatcherHolder.associateMatcher(myResultsList, matcher); + //assert project != null; //myRenderer.myProject = project; synchronized (myWorkerRestartRequestLock) { // this lock together with RestartRequestId should be enough to prevent two CalcThreads running at the same time @@ -356,10 +366,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { private final String pattern; private final ProgressIndicator myProgressIndicator = new ProgressIndicatorBase(); private final ActionCallback myDone = new ActionCallback(); - private final SearchEverywhereAction.SearchListModel myListModel; - private final ArrayList myAlreadyAddedFiles = new ArrayList<>(); - private final ArrayList myAlreadyAddedActions = new ArrayList<>(); - + private final SearchEverywhereAction.SearchListModel myListModel; //todo use usual model #UX-1 public CalcThread(Project project, String pattern, boolean reuseModel) { this.project = project; @@ -391,46 +398,14 @@ public class SearchEverywhereUI extends BorderLayoutPanel { } }); - //if (pattern.trim().length() == 0) { - // buildModelFromRecentFiles(); - // //updatePopup(); - // return; - //} - - //checkModelsUpToDate(); check(); - //buildTopHit(pattern); check(); - - if (!pattern.startsWith("#")) { - //buildRecentFiles(pattern); - //check(); - - SearchEverywhereContributor selectedContributor = getSelectedContributor(); - if (selectedContributor != null) { - runReadAction(() -> addContributorItems(selectedContributor, true), true); - } else { - for (SearchEverywhereContributor contributor : allContributors) { - runReadAction(() -> addContributorItems(contributor, false), true); - } + myResultsRanges.clear(); + SearchEverywhereContributor selectedContributor = getSelectedContributor(); + if (selectedContributor != null) { + runReadAction(() -> addContributorItems(selectedContributor, true), true); + } else { + for (SearchEverywhereContributor contributor : allContributors) { + runReadAction(() -> addContributorItems(contributor, false), true); } - - //runReadAction(() -> buildStructure(pattern), true); - //updatePopup(); - //check(); - //buildToolWindows(pattern); - //check(); - //updatePopup(); - //check(); - // - //checkModelsUpToDate(); - //runReadAction(() -> buildRunConfigurations(pattern), true); - //runReadAction(() -> buildClasses(pattern), true); - //runReadAction(() -> buildFiles(pattern), false); - //runReadAction(() -> buildSymbols(pattern), true); - // - //buildActionsAndSettings(pattern); - // - //updatePopup(); - } updatePopup(); } @@ -460,15 +435,17 @@ public class SearchEverywhereUI extends BorderLayoutPanel { SwingUtilities.invokeLater(() -> { if (isCanceled()) return; - if (!exclusiveContributor) { - myListModel.titleIndex.classes = myListModel.size(); - } + int start = myListModel.getSize(); for (Object item : results.getItems()) { myListModel.addElement(item); } - if (!exclusiveContributor) { - myListModel.moreIndex.classes = results.hasMoreItems() ? myListModel.size() - 1 : -1; + int end = myListModel.getSize() - 1; + + if (results.hasMoreItems()) { + myListModel.addElement("more"); } + ResultsRange range = results.hasMoreItems() ? new ResultsRange(start, end, end + 1) : new ResultsRange(start, end); + myResultsRanges.put(range, contributor); }); } } @@ -649,6 +626,88 @@ public class SearchEverywhereUI extends BorderLayoutPanel { } } + private class CompositeCellRenderer implements ListCellRenderer { + + public CompositeCellRenderer(Map delegates) { + this.delegates = delegates; + } + + private final Map delegates; + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + return getDelegate(index).getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + } + + @NotNull + private ListCellRenderer getDelegate(int index) { + //is it "more item" ? + boolean isMoreElement = delegates.entrySet().stream() + .map(entry -> entry.getKey().getMoreElementIndex().orElse(null)) + .filter(Objects::nonNull) + .anyMatch(i -> i.equals(index)); + + if (isMoreElement) { + return moreRenderer; + } + + //look for delegate in ranges + ListCellRenderer delegate = delegates.entrySet().stream() + .filter(entry -> entry.getKey().getElementsRange().isWithin(index, true)) + .findAny() + .map(entry -> entry.getValue().getElementsRenderer(myProject)) + .orElse(null); + + + if (delegate == null) throw new IllegalStateException("Contributor for element is not specified"); + + return delegate; + } + } + + private static class ResultsRange { + private final Range elementsRange; + private final Integer moreElementIndex; + + private ResultsRange(int from, int to, Integer moreIndex) { + elementsRange = new Range<>(from, to); + moreElementIndex = moreIndex; + } + + public ResultsRange(int from, int to) { + this(from, to, null); + } + + public Range getElementsRange() { + return elementsRange; + } + + public Optional getMoreElementIndex() { + return Optional.ofNullable(moreElementIndex); + } + } + + private static final MoreRenderer moreRenderer = new MoreRenderer(); + + public static class MoreRenderer extends JPanel implements ListCellRenderer { + final JLabel label = new JLabel(" ... more "); + + private MoreRenderer() { + super(new BorderLayout()); + add(label, BorderLayout.CENTER); + } + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + setBackground(UIUtil.getListBackground(isSelected)); + label.setForeground(UIUtil.getLabelDisabledForeground()); + label.setFont(UIUtil.getLabelFont().deriveFont(UIUtil.getFontSize(UIUtil.FontSize.SMALL))); + label.setBackground(UIUtil.getListBackground(isSelected)); + + return this; + } + } + private void updateResultsPopupBounds() { int height = myResultsList.getPreferredSize().height + 2; int width = getWidth(); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java index 2f544529eb45..e9f96161a632 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java @@ -3,6 +3,7 @@ package com.intellij.ide.actions.searcheverywhere; import com.intellij.ide.IdeBundle; import com.intellij.ide.actions.SearchEverywhereClassifier; +import com.intellij.ide.util.NavigationItemListCellRenderer; import com.intellij.ide.util.gotoByName.ChooseByNameItemProvider; import com.intellij.ide.util.gotoByName.ChooseByNameModel; import com.intellij.ide.util.gotoByName.ChooseByNamePopup; @@ -16,6 +17,7 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; +import javax.swing.*; import java.util.ArrayList; import java.util.List; @@ -89,4 +91,9 @@ public class SymbolSearchEverywhereContributor implements SearchEverywhereContri if (scope != null) return scope; return GlobalSearchScope.projectScope(project); } + + @Override + public ListCellRenderer getElementsRenderer(Project project) { + return new NavigationItemListCellRenderer(); + } } From c55bc3ff145ad10ce02510748299671384161e4e Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Thu, 3 May 2018 21:15:18 +0300 Subject: [PATCH 12/28] UX-1 extract GotoListController * get rid of AllSearchEverywhereContributor --- .../SearchEverywhereContributor.java | 4 ++ .../intellij/ide/actions/GotoActionBase.java | 2 +- .../ide/actions/SearchEverywhereAction.java | 6 +-- .../AllSearchEverywhereContributor.java | 40 ------------------- .../SearchEverywhereManager.java | 2 +- .../SearchEverywhereManagerImpl.java | 6 +-- .../searcheverywhere/SearchEverywhereUI.java | 26 +++++++----- 7 files changed, 29 insertions(+), 57 deletions(-) delete mode 100644 platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AllSearchEverywhereContributor.java diff --git a/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java b/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java index d178153ebd85..c475e06ea29f 100644 --- a/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java +++ b/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java @@ -21,7 +21,11 @@ import java.util.stream.Collectors; * @author Konstantin Bulenkov */ public interface SearchEverywhereContributor { + + String ALL_CONTRIBUTORS_GROUP_ID = SearchEverywhereContributor.class.getSimpleName() + ".All"; + ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.searchEverywhereContributor"); + @NotNull String getSearchProviderId(); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java index da97de9cc0dc..6342f2229f7b 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java @@ -341,7 +341,7 @@ public abstract class GotoActionBase extends AnAction { SearchEverywhereManager seManager = SearchEverywhereManager.getInstance(evnt.getProject()); if (seManager.isShown()) { - if (searchProviderID.equals(seManager.getShownContributor().getSearchProviderId())) { + if (searchProviderID.equals(seManager.getShownContributorID())) { seManager.setShowNonProjectItems(!seManager.isShowNonProjectItems()); } else { diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index 58c509839cd1..e9232337a43b 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -16,7 +16,7 @@ import com.intellij.execution.runners.ProgramRunner; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.icons.AllIcons; import com.intellij.ide.*; -import com.intellij.ide.actions.searcheverywhere.AllSearchEverywhereContributor; +import com.intellij.ide.actions.searcheverywhere.SearchEverywhereContributor; import com.intellij.ide.actions.searcheverywhere.SearchEverywhereManager; import com.intellij.ide.structureView.StructureView; import com.intellij.ide.structureView.StructureViewBuilder; @@ -564,14 +564,14 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA public void actionPerformed(AnActionEvent e, MouseEvent me) { if (Registry.is("new.search.everywhere")) { //todo[mikhail.sokolov] show new UI - String searchProviderID = AllSearchEverywhereContributor.class.getSimpleName(); + String searchProviderID = SearchEverywhereContributor.ALL_CONTRIBUTORS_GROUP_ID; FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE); FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE + "." + searchProviderID); SearchEverywhereManager seManager = SearchEverywhereManager.getInstance(e.getProject()); if (seManager.isShown()) { - if (searchProviderID.equals(seManager.getShownContributor().getSearchProviderId())) { + if (searchProviderID.equals(seManager.getShownContributorID())) { seManager.setShowNonProjectItems(!seManager.isShowNonProjectItems()); } else { diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AllSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AllSearchEverywhereContributor.java deleted file mode 100644 index 59bef8f07453..000000000000 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AllSearchEverywhereContributor.java +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.intellij.ide.actions.searcheverywhere; - -import com.intellij.ide.IdeBundle; -import com.intellij.ide.util.NavigationItemListCellRenderer; -import com.intellij.openapi.project.Project; -import com.intellij.ui.IdeUICustomization; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; - -public class AllSearchEverywhereContributor implements SearchEverywhereContributor { - - @NotNull - @Override - public String getSearchProviderId() { - return getClass().getSimpleName(); - } - - @NotNull - @Override - public String getGroupName() { - return IdeBundle.message("searcheverywhere.allelements.tab.name"); - } - - @Override - public int getSortWeight() { - return 0; - } - - @Override - public String includeNonProjectItemsText() { - return IdeBundle.message("checkbox.include.non.project.items", IdeUICustomization.getInstance().getProjectConceptName()); - } - - @Override - public ListCellRenderer getElementsRenderer(Project project) { - return new NavigationItemListCellRenderer(); - } -} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManager.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManager.java index e3fcf2df4e9e..ce3b42275059 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManager.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManager.java @@ -18,7 +18,7 @@ public interface SearchEverywhereManager { void show(@NotNull String selectedContributorID); //todo change to contributor??? UX-1 - SearchEverywhereContributor getShownContributor(); + String getShownContributorID(); void setShownContributor(@NotNull String newSelectedContributorID); //todo change to contributor??? UX-1 diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java index 2e6dfaa99c17..59402dea3dcf 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java @@ -80,13 +80,13 @@ public class SearchEverywhereManagerImpl implements SearchEverywhereManager { } @Override - public SearchEverywhereContributor getShownContributor() { - return mySearchEverywhereUI.getSelectedContributor(); + public String getShownContributorID() { + return mySearchEverywhereUI.getSelectedContributorID(); } @Override public void setShownContributor(@NotNull String contributorID) { - if (!contributorID.equals(getShownContributor().getSearchProviderId())) { + if (!contributorID.equals(getShownContributorID())) { mySearchEverywhereUI.switchToContributor(contributorID); } } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java index 092859e9c612..3443e50d54b0 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java @@ -125,14 +125,14 @@ public class SearchEverywhereUI extends BorderLayoutPanel { public void switchToContributor(String contributorID) { SETab selectedTab = myTabs.stream() - .filter(tab -> contributorID.equals(tab.getContributor().getSearchProviderId())) + .filter(tab -> tab.getID().equals(contributorID)) .findAny() .orElseThrow(() -> new IllegalArgumentException(String.format("Contributor %s is not supported", contributorID))); switchToTab(selectedTab); } - public SearchEverywhereContributor getSelectedContributor() { - return mySelectedTab.getContributor(); + public String getSelectedContributorID() { + return mySelectedTab.getID(); } public void clear() { @@ -153,7 +153,9 @@ public class SearchEverywhereUI extends BorderLayoutPanel { private void switchToTab(SETab tab) { mySelectedTab = tab; - String text = tab.getContributor().includeNonProjectItemsText(); + String text = tab.getContributor() + .map(SearchEverywhereContributor::includeNonProjectItemsText) + .orElse(IdeBundle.message("checkbox.include.non.project.items", IdeUICustomization.getInstance().getProjectConceptName())); if (text.indexOf(UIUtil.MNEMONIC) != -1) { DialogUtil.setTextWithMnemonic(myNonProjectCB, text); } else { @@ -270,7 +272,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { JPanel contributorsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); contributorsPanel.setOpaque(false); - SETab allTab = new SETab(new AllSearchEverywhereContributor()); + SETab allTab = new SETab(null); contributorsPanel.add(allTab); myTabs.add(allTab); @@ -295,7 +297,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { private final SearchEverywhereContributor myContributor; public SETab(SearchEverywhereContributor contributor) { - super(contributor.getGroupName()); + super(contributor == null ? IdeBundle.message("searcheverywhere.allelements.tab.name") : contributor.getGroupName()); myContributor = contributor; Insets insets = JBUI.CurrentTheme.SearchEverywhere.tabInsets(); setBorder(JBUI.Borders.empty(insets.top, insets.left, insets.bottom, insets.right)); @@ -307,8 +309,14 @@ public class SearchEverywhereUI extends BorderLayoutPanel { }); } - public SearchEverywhereContributor getContributor() { - return myContributor; + public String getID() { + return getContributor() + .map(SearchEverywhereContributor::getSearchProviderId) + .orElse(SearchEverywhereContributor.ALL_CONTRIBUTORS_GROUP_ID); + } + + public Optional getContributor() { + return Optional.ofNullable(myContributor); } @Override @@ -399,7 +407,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { }); myResultsRanges.clear(); - SearchEverywhereContributor selectedContributor = getSelectedContributor(); + SearchEverywhereContributor selectedContributor = mySelectedTab.getContributor().orElse(null); if (selectedContributor != null) { runReadAction(() -> addContributorItems(selectedContributor, true), true); } else { From a68dde869591cd652c9e60fb1124128be8b3ee0a Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Fri, 4 May 2018 15:58:13 +0300 Subject: [PATCH 13/28] UX-1 new SearchEverywhere popup * group headers in results list --- .../searcheverywhere/SearchEverywhereUI.java | 94 +++++++++++++------ 1 file changed, 66 insertions(+), 28 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java index 3443e50d54b0..a4b6675d91f0 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java @@ -634,7 +634,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { } } - private class CompositeCellRenderer implements ListCellRenderer { + private class CompositeCellRenderer implements ListCellRenderer { public CompositeCellRenderer(Map delegates) { this.delegates = delegates; @@ -644,32 +644,33 @@ public class SearchEverywhereUI extends BorderLayoutPanel { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - return getDelegate(index).getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (isMoreElement(index)) { + return moreRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + } + + Map.Entry delegateEntry = delegates.entrySet().stream() + .filter(entry -> entry.getKey().getElementsRange() + .isWithin(index, true)) + .findAny() + .orElseThrow(() -> new IllegalStateException("Contributor for element is not specified")); + + SearchEverywhereContributor contributor = delegateEntry.getValue(); + Component component = contributor.getElementsRenderer(myProject) + .getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + int rangeStart = delegateEntry.getKey().getElementsRange().getFrom(); + boolean allGroupSelected = SearchEverywhereContributor.ALL_CONTRIBUTORS_GROUP_ID.equals(getSelectedContributorID()); + if (allGroupSelected && rangeStart == index) { + return groupTitleRenderer.withDisplayedData(contributor.getGroupName(), component); + } + + return component; } - @NotNull - private ListCellRenderer getDelegate(int index) { - //is it "more item" ? - boolean isMoreElement = delegates.entrySet().stream() + private boolean isMoreElement(int index) { + return delegates.entrySet().stream() .map(entry -> entry.getKey().getMoreElementIndex().orElse(null)) .filter(Objects::nonNull) .anyMatch(i -> i.equals(index)); - - if (isMoreElement) { - return moreRenderer; - } - - //look for delegate in ranges - ListCellRenderer delegate = delegates.entrySet().stream() - .filter(entry -> entry.getKey().getElementsRange().isWithin(index, true)) - .findAny() - .map(entry -> entry.getValue().getElementsRenderer(myProject)) - .orElse(null); - - - if (delegate == null) throw new IllegalStateException("Contributor for element is not specified"); - - return delegate; } } @@ -698,28 +699,65 @@ public class SearchEverywhereUI extends BorderLayoutPanel { private static final MoreRenderer moreRenderer = new MoreRenderer(); public static class MoreRenderer extends JPanel implements ListCellRenderer { - final JLabel label = new JLabel(" ... more "); + final JLabel label; private MoreRenderer() { super(new BorderLayout()); + label = groupInfoLabel(" ... more "); add(label, BorderLayout.CENTER); } @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { setBackground(UIUtil.getListBackground(isSelected)); - label.setForeground(UIUtil.getLabelDisabledForeground()); - label.setFont(UIUtil.getLabelFont().deriveFont(UIUtil.getFontSize(UIUtil.FontSize.SMALL))); - label.setBackground(UIUtil.getListBackground(isSelected)); - return this; } } + private static final GroupTitleRenderer groupTitleRenderer = new GroupTitleRenderer(); + + public static class GroupTitleRenderer extends JPanel { + + private final JLabel titleLabel; + private final BorderLayout myLayout = new BorderLayout(); + + public GroupTitleRenderer() { + setLayout(myLayout); + setBackground(UIUtil.getListBackground(false)); + titleLabel = groupInfoLabel("Group"); + SeparatorComponent separatorComponent = new SeparatorComponent(titleLabel.getPreferredSize().height / 2, UIUtil.getLabelDisabledForeground(), null); + + + JPanel topPanel = JBUI.Panels.simplePanel(5, 0) + .addToCenter(separatorComponent) + .addToLeft(titleLabel) + .withBorder(JBUI.Borders.empty()) + .withBackground(UIUtil.getListBackground()); + add(topPanel, BorderLayout.NORTH); + } + + public GroupTitleRenderer withDisplayedData(String title, Component itemContent) { + titleLabel.setText(title); + Component prevContent = myLayout.getLayoutComponent(BorderLayout.CENTER); + if (prevContent != null) { + remove(prevContent); + } + add(itemContent, BorderLayout.CENTER); + return this; + } + } + + private static JLabel groupInfoLabel(String text) { + JLabel label = new JLabel(text); + label.setForeground(UIUtil.getLabelDisabledForeground()); + label.setFont(UIUtil.getLabelFont().deriveFont(UIUtil.getFontSize(UIUtil.FontSize.SMALL))); + label.setOpaque(false); + return label; + } + private void updateResultsPopupBounds() { int height = myResultsList.getPreferredSize().height + 2; int width = getWidth(); myResultsPopup.setSize(JBUI.size(width, height)); - } } From a1bce4960a6d5742301345e7f59c3bc610609c9e Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Fri, 4 May 2018 19:36:15 +0300 Subject: [PATCH 14/28] UX-1 new SearchEverywhere popup * mouse selection for list items --- .../SearchEverywhereContributor.java | 3 + .../ide/actions/SearchEverywhereAction.java | 1 + .../ClassSearchEverywhereContributor.java | 8 ++ .../FileSearchEverywhereContributor.java | 18 ++--- .../SearchEverywhereManagerImpl.java | 1 + .../searcheverywhere/SearchEverywhereUI.java | 80 ++++++++++++++++--- .../SymbolSearchEverywhereContributor.java | 9 +++ 7 files changed, 98 insertions(+), 22 deletions(-) diff --git a/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java b/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java index c475e06ea29f..a11ebfe83a64 100644 --- a/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java +++ b/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java @@ -20,6 +20,7 @@ import java.util.stream.Collectors; /** * @author Konstantin Bulenkov */ +//todo generic? #UX-1 public interface SearchEverywhereContributor { String ALL_CONTRIBUTORS_GROUP_ID = SearchEverywhereContributor.class.getSimpleName() + ".All"; @@ -46,6 +47,8 @@ public interface SearchEverywhereContributor { return search(project, pattern, everywhere, progressIndicator, -1).getItems(); } + void processSelectedItem(Object selected); + //todo any way to listen project in contributor ListCellRenderer getElementsRenderer(Project project); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index e9232337a43b..1817d9545937 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -2334,6 +2334,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } + //todo return private (same for other) #UX-1 public static class MoreIndex { public volatile int classes = -1; public volatile int files = -1; diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java index cd058c750f79..868935589114 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java @@ -1,6 +1,7 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.actions.searcheverywhere; +import com.intellij.codeInsight.navigation.NavigationUtil; import com.intellij.ide.IdeBundle; import com.intellij.ide.actions.SearchEverywhereClassifier; import com.intellij.ide.util.NavigationItemListCellRenderer; @@ -67,4 +68,11 @@ public class ClassSearchEverywhereContributor implements SearchEverywhereContrib public ListCellRenderer getElementsRenderer(Project project) { return new NavigationItemListCellRenderer(); } + + @Override + public void processSelectedItem(Object selected) { + if (selected instanceof PsiElement) { + NavigationUtil.activateFileWithPsiElement((PsiElement) selected, true); + } + } } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java index 4e9bbd0e0c96..0291347d2253 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java @@ -1,15 +1,14 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.actions.searcheverywhere; +import com.intellij.codeInsight.navigation.NavigationUtil; import com.intellij.ide.IdeBundle; -import com.intellij.ide.actions.SearchEverywhereClassifier; import com.intellij.ide.util.gotoByName.ChooseByNameModel; import com.intellij.ide.util.gotoByName.ChooseByNamePopup; import com.intellij.ide.util.gotoByName.GotoFileModel; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.ui.IdeUICustomization; import org.jetbrains.annotations.NotNull; @@ -76,15 +75,16 @@ public class FileSearchEverywhereContributor implements SearchEverywhereContribu }; } - @NotNull - private static GlobalSearchScope getProjectScope(@NotNull Project project) { - final GlobalSearchScope scope = SearchEverywhereClassifier.EP_Manager.getProjectScope(project); - if (scope != null) return scope; - return GlobalSearchScope.projectScope(project); - } - @Override public ListCellRenderer getElementsRenderer(Project project) { return createModel(project).getListCellRenderer(); } + + @Override + public void processSelectedItem(Object selected) { + //todo maybe another elements types + if (selected instanceof PsiElement) { + NavigationUtil.activateFileWithPsiElement((PsiElement) selected, true); + } + } } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java index 59402dea3dcf..3c78fcefe408 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java @@ -57,6 +57,7 @@ public class SearchEverywhereManagerImpl implements SearchEverywhereManager { }) .addUserData("SIMPLE_WINDOW") .createPopup(); + mySearchEverywhereUI.setSearchFinishedHandler(() -> myBalloon.cancel()); AnAction escape = ActionManager.getInstance().getAction("EditorEscape"); DumbAwareAction.create(__ -> myBalloon.cancel()) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java index a4b6675d91f0..c2ef1f73ed08 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java @@ -85,6 +85,8 @@ public class SearchEverywhereUI extends BorderLayoutPanel { private final Object myWorkerRestartRequestLock = new Object(); private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, ApplicationManager.getApplication()); + private Runnable searchFinishedHandler = () -> {}; + // todo remove second param #UX-1 public SearchEverywhereUI(Project project, List contributors, @@ -108,7 +110,8 @@ public class SearchEverywhereUI extends BorderLayoutPanel { addToRight(settingsPanel); addToBottom(mySearchField); - myResultsList.setCellRenderer(new CompositeCellRenderer(myResultsRanges)); + myResultsList.setCellRenderer(new CompositeCellRenderer()); + initListActions(); } public JTextField getSearchField() { @@ -131,6 +134,10 @@ public class SearchEverywhereUI extends BorderLayoutPanel { switchToTab(selectedTab); } + public void setSearchFinishedHandler(@NotNull Runnable searchFinishedHandler) { + this.searchFinishedHandler = searchFinishedHandler; + } + public String getSelectedContributorID() { return mySelectedTab.getID(); } @@ -368,6 +375,55 @@ public class SearchEverywhereUI extends BorderLayoutPanel { } } + private void initListActions() { + myResultsList.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + e.consume(); + final int i = myResultsList.locationToIndex(e.getPoint()); + if (i != -1) { + ApplicationManager.getApplication().invokeLater(() -> { + myResultsList.setSelectedIndex(i); + elementSelected(i); + }); + } + } + }); + + } + + private void elementSelected(int i) { + Map.Entry entry = myResultsRanges.entrySet().stream() + .filter(e -> e.getKey().containsIndex(i)) + .findAny() + .orElseThrow(() -> new IllegalStateException("Contributor for element is not specified")); + + Boolean isMoreElement = entry.getKey().getMoreElementIndex().map(moreIndex -> moreIndex.equals(i)).orElse(false); + if (isMoreElement) { + showMoreElements(entry.getValue()); + } else { + gotoSelectedItem(entry.getValue()); + } + } + + private void showMoreElements(SearchEverywhereContributor contributor) { + + } + + private void gotoSelectedItem(SearchEverywhereContributor contributor) { + Object value = myResultsList.getSelectedValue(); + stopSearching(); + searchFinishedHandler.run(); + contributor.processSelectedItem(value); + } + + private void stopSearching() { + myAlarm.cancelAllRequests(); + if (myCalcThread != null && !myCalcThread.isCanceled()) { + myCalcThread.cancel(); + } + } + @SuppressWarnings("Duplicates") //todo remove suppress #UX-1 private class CalcThread implements Runnable { private final Project project; @@ -634,13 +690,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { } } - private class CompositeCellRenderer implements ListCellRenderer { - - public CompositeCellRenderer(Map delegates) { - this.delegates = delegates; - } - - private final Map delegates; + private class CompositeCellRenderer implements ListCellRenderer { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { @@ -648,7 +698,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { return moreRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); } - Map.Entry delegateEntry = delegates.entrySet().stream() + Map.Entry delegateEntry = myResultsRanges.entrySet().stream() .filter(entry -> entry.getKey().getElementsRange() .isWithin(index, true)) .findAny() @@ -667,10 +717,10 @@ public class SearchEverywhereUI extends BorderLayoutPanel { } private boolean isMoreElement(int index) { - return delegates.entrySet().stream() - .map(entry -> entry.getKey().getMoreElementIndex().orElse(null)) - .filter(Objects::nonNull) - .anyMatch(i -> i.equals(index)); + return myResultsRanges.entrySet().stream() + .map(entry -> entry.getKey().getMoreElementIndex().orElse(null)) + .filter(Objects::nonNull) + .anyMatch(i -> i.equals(index)); } } @@ -694,6 +744,10 @@ public class SearchEverywhereUI extends BorderLayoutPanel { public Optional getMoreElementIndex() { return Optional.ofNullable(moreElementIndex); } + + public boolean containsIndex(int i) { + return elementsRange.isWithin(i, true) || (moreElementIndex != null && moreElementIndex.equals(i)); + } } private static final MoreRenderer moreRenderer = new MoreRenderer(); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java index e9f96161a632..b9969bab307a 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java @@ -1,6 +1,7 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.actions.searcheverywhere; +import com.intellij.codeInsight.navigation.NavigationUtil; import com.intellij.ide.IdeBundle; import com.intellij.ide.actions.SearchEverywhereClassifier; import com.intellij.ide.util.NavigationItemListCellRenderer; @@ -96,4 +97,12 @@ public class SymbolSearchEverywhereContributor implements SearchEverywhereContri public ListCellRenderer getElementsRenderer(Project project) { return new NavigationItemListCellRenderer(); } + + @Override + public void processSelectedItem(Object selected) { + //todo maybe another elements types + if (selected instanceof PsiElement) { + NavigationUtil.activateFileWithPsiElement((PsiElement) selected, true); + } + } } From e76e51b97fbca06cb6f83a6ebbf613623d664622 Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Mon, 7 May 2018 14:45:51 +0300 Subject: [PATCH 15/28] UX-1 new SearchEverywhere popup * mouse selection for list items --- .../SearchEverywhereManagerImpl.java | 7 -- .../searcheverywhere/SearchEverywhereUI.java | 69 ++++++++++--------- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java index 3c78fcefe408..66735e0cdb25 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java @@ -2,8 +2,6 @@ package com.intellij.ide.actions.searcheverywhere; import com.intellij.ide.ui.UISettings; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; @@ -59,11 +57,6 @@ public class SearchEverywhereManagerImpl implements SearchEverywhereManager { .createPopup(); mySearchEverywhereUI.setSearchFinishedHandler(() -> myBalloon.cancel()); - AnAction escape = ActionManager.getInstance().getAction("EditorEscape"); - DumbAwareAction.create(__ -> myBalloon.cancel()) - .registerCustomShortcutSet(escape == null ? CommonShortcuts.ESCAPE : escape.getShortcutSet(), - myBalloon.getContent(), myBalloon); - RelativePoint showingPoint = calculateShowingPoint(); if (showingPoint != null) { myBalloon.show(showingPoint); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java index c2ef1f73ed08..0ec2b6eac192 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java @@ -8,15 +8,14 @@ import com.intellij.ide.actions.SearchEverywhereAction; import com.intellij.ide.ui.UISettings; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.actionSystem.ex.AnActionListener; import com.intellij.openapi.actionSystem.impl.ActionButton; import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.actions.TextComponentEditorAction; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.util.ProgressIndicatorBase; +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; @@ -111,7 +110,8 @@ public class SearchEverywhereUI extends BorderLayoutPanel { addToBottom(mySearchField); myResultsList.setCellRenderer(new CompositeCellRenderer()); - initListActions(); + + initSearchActions(); } public JTextField getSearchField() { @@ -172,6 +172,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { } myNonProjectCB.setSelected(false); repaint(); + rebuildList(mySearchField != null ? mySearchField.getText() : ""); } private JTextField createSearchField() { @@ -217,24 +218,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { true); searchField.setBorder(border); searchField.setBackground(JBUI.CurrentTheme.SearchEverywhere.searchFieldBackground()); - searchField.setFocusTraversalKeysEnabled(false); - searchField.addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_TAB && e.getModifiers() == 0) { - switchToNextTab(); - e.consume(); - } - } - }); - - searchField.getDocument().addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(DocumentEvent e) { - rebuildList(searchField.getText()); - } - }); return searchField; } @@ -375,7 +359,28 @@ public class SearchEverywhereUI extends BorderLayoutPanel { } } - private void initListActions() { + private void initSearchActions() { + mySearchField.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_TAB && e.getModifiers() == 0) { + switchToNextTab(); + e.consume(); + } + } + }); + + AnAction escape = ActionManager.getInstance().getAction("EditorEscape"); + DumbAwareAction.create(__ -> searchFinishedHandler.run()) + .registerCustomShortcutSet(escape == null ? CommonShortcuts.ESCAPE : escape.getShortcutSet(), this); + + mySearchField.getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + rebuildList(mySearchField.getText()); + } + }); + myResultsList.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { @@ -610,17 +615,17 @@ public class SearchEverywhereUI extends BorderLayoutPanel { updateResultsPopupBounds(); myResultsPopup.show(new RelativePoint(SearchEverywhereUI.this, new Point(0, getHeight()))); - ActionManager.getInstance().addAnActionListener(new AnActionListener.Adapter() { - @Override - public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) { - if (action instanceof TextComponentEditorAction) { - return; - } - if (myResultsPopup != null) { - myResultsPopup.cancel(); - } - } - }, myResultsPopup); + //ActionManager.getInstance().addAnActionListener(new AnActionListener.Adapter() { + // @Override + // public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) { + // if (action instanceof TextComponentEditorAction) { + // return; + // } + // if (myResultsPopup != null) { + // myResultsPopup.cancel(); + // } + // } + //}, myResultsPopup); } else { myResultsList.revalidate(); From 514b96aae48ecf72986498bad449fd7e7c0a0d0f Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Fri, 4 May 2018 18:16:23 +0200 Subject: [PATCH 16/28] SSR: fix text constraints not available --- .../StructuralSearchProfile.java | 2 +- .../StructuralSearchTestCase.java | 30 ++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java b/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java index 1f1e86dd02d2..50c7cd5201e2 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java @@ -294,10 +294,10 @@ public abstract class StructuralSearchProfile { */ public boolean isApplicableConstraint(String constraintName, @Nullable PsiElement variableNode, boolean completePattern, boolean target) { switch (constraintName) { - case UIUtil.TEXT: case UIUtil.MINIMUM_ZERO: if (target) return false; case UIUtil.MAXIMUM_UNLIMITED: + case UIUtil.TEXT: case UIUtil.REFERENCE: return !completePattern; } return false; diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java index 8864da307c29..977fbc596fe9 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java @@ -7,8 +7,13 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.openapi.util.io.FileUtilRt; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.PsiElement; +import com.intellij.structuralsearch.impl.matcher.CompiledPattern; +import com.intellij.structuralsearch.impl.matcher.compiler.PatternCompiler; +import com.intellij.structuralsearch.plugin.ui.UIUtil; import java.io.File; import java.io.IOException; @@ -51,10 +56,33 @@ public abstract class StructuralSearchTestCase extends LightQuickFixTestCase { options.setFileType(patternFileType); options.setDialect(patternLanguage); - Matcher.validate(getProject(), options); + final String message = checkApplicableConstraints(); + assertNull(message, message); return testMatcher.testFindMatches(in, options, true, sourceFileType, sourceExtension, physicalSourceFile); } + public String checkApplicableConstraints() { + final CompiledPattern compiledPattern = PatternCompiler.compilePattern(getProject(), options); + final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByFileType(options.getFileType()); + assert profile != null; + for (String varName : options.getVariableConstraintNames()) { + final List nodes = compiledPattern.getVariableNodes(varName); + final PsiElement node = nodes.size() == 1 ? nodes.get(0) : null; + final MatchVariableConstraint constraint = options.getVariableConstraint(varName); + final String constraintName; + if (!StringUtil.isEmpty(constraint.getRegExp())) { + constraintName = UIUtil.TEXT; + } + else { // todo check other constraints + constraintName = null; + } + if (constraintName != null && !profile.isApplicableConstraint(constraintName, node, false, constraint.isPartOfSearchResults())) { + return constraintName + " not applicable for " + varName; + } + } + return null; + } + protected List findMatches(String in, String pattern, FileType patternFileType) { return findMatches(in, pattern, patternFileType, null, patternFileType, null, false); } From 0478f745987134f76056c31df5b2969604c525fc Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Sat, 5 May 2018 10:10:05 +0200 Subject: [PATCH 17/28] SSR: fix min count not available bugs --- .../JavaStructuralSearchProfile.java | 136 +++++++++++------- .../StructuralSearchProfile.java | 11 ++ .../matcher/compiler/PatternCompiler.java | 22 ++- .../plugin/ui/EditVarConstraintsDialog.java | 17 ++- .../OptimizedSearchScanTest.java | 4 +- .../StructuralSearchTest.java | 59 ++++---- .../StructuralSearchTestCase.java | 17 ++- .../XmlStructuralSearchTest.java | 4 +- 8 files changed, 159 insertions(+), 111 deletions(-) diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java index 228259d6fd27..0e3f832d54b3 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java @@ -21,6 +21,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.source.JavaDummyHolder; import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.javadoc.PsiDocToken; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilCore; @@ -856,10 +857,11 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { } return variableNode != null && variableNode.getParent() instanceof PsiExpression; case UIUtil.MINIMUM_ZERO: - if (target) return false; - return isApplicableCount(variableNode, false); + if (target || variableNode == null) return false; + return isApplicableMinCount(variableNode) || isApplicableMinMaxCount(variableNode); case UIUtil.MAXIMUM_UNLIMITED: - return isApplicableCount(variableNode, true); + if (variableNode == null) return false; + return isApplicableMaxCount(variableNode) || isApplicableMinMaxCount(variableNode); case UIUtil.REFERENCE: if (completePattern || variableNode == null) return false; if (variableNode instanceof PsiLiteralExpression && ((PsiLiteralExpression)variableNode).getValue() instanceof String) return true; @@ -869,59 +871,83 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { } } - private static boolean isApplicableCount(@Nullable PsiElement variableNode, boolean max) { - if (variableNode != null) { - final PsiElement parent = variableNode.getParent(); - if (max && parent instanceof PsiLocalVariable) { - final PsiLocalVariable localVariable = (PsiLocalVariable)parent; - if (localVariable instanceof PsiResourceVariable) return false; - if (localVariable.getTypeElement().isInferredType()) return false; - return true; + private static boolean isApplicableMinCount(@NotNull PsiElement variableNode) { + final PsiElement parent = variableNode.getParent(); + if (parent instanceof PsiBreakStatement) return true; + if (parent instanceof PsiContinueStatement) return true; + + final PsiElement grandParent = parent.getParent(); + if (grandParent instanceof PsiReferenceList) return true; + if (parent instanceof PsiReferenceExpression) { + if (grandParent instanceof PsiReferenceExpression) return true; + if (grandParent instanceof PsiReturnStatement) return true; + if (grandParent instanceof PsiAssertStatement) return ((PsiAssertStatement)grandParent).getAssertDescription() == parent; + if (grandParent instanceof PsiNameValuePair) return ((PsiNameValuePair)grandParent).getValue() == parent; + } + if (grandParent instanceof PsiVariable) { + return ((PsiVariable)grandParent).getInitializer() == parent; + } + if (grandParent instanceof PsiNewExpression) { + return ((PsiNewExpression)grandParent).getArrayInitializer() != null; + } + if (grandParent instanceof PsiExpressionStatement && hasSemicolon(grandParent)) { + final PsiElement greatGrandParent = grandParent.getParent(); + return !(greatGrandParent instanceof PsiCodeBlock) || + !(greatGrandParent.getParent() instanceof JavaDummyHolder) || + PsiTreeUtil.getChildrenOfAnyType(greatGrandParent, PsiStatement.class, PsiComment.class).size() > 1; + } + return false; + } + + private static boolean isApplicableMaxCount(@NotNull PsiElement variableNode) { + final PsiElement parent = variableNode.getParent(); + if (parent instanceof PsiLocalVariable) { + final PsiLocalVariable localVariable = (PsiLocalVariable)parent; + if (localVariable instanceof PsiResourceVariable) return false; + if (localVariable.getTypeElement().isInferredType()) return false; + return true; + } + if (parent instanceof PsiField) return true; + + final PsiElement grandParent = parent.getParent(); + if (grandParent instanceof PsiPolyadicExpression) return true; + if (grandParent instanceof PsiExpressionStatement && hasSemicolon(grandParent)) return true; + if (grandParent instanceof PsiReferenceList) { + final PsiReferenceList referenceList = (PsiReferenceList)grandParent; + final PsiElement greatGrandParent = referenceList.getParent(); + return !(greatGrandParent instanceof PsiClass) || ((PsiClass)greatGrandParent).getExtendsList() != referenceList; + } + return false; + } + + private static boolean isApplicableMinMaxCount(@NotNull PsiElement variableNode) { + if (variableNode instanceof PsiDocToken) return true; + final PsiElement parent = variableNode.getParent(); + if (parent instanceof PsiMember && !(parent instanceof PsiTypeParameter)) { + final PsiMember member = (PsiMember)parent; + final PsiClass aClass = member.getContainingClass(); + if (aClass == null) { + return false; } - else if (max && parent instanceof PsiField) { - return true; - } - if (parent instanceof PsiMember && !(parent instanceof PsiTypeParameter)) { - final PsiMember member = (PsiMember)parent; - final PsiClass aClass = member.getContainingClass(); - if (aClass == null) { - return false; - } - final String name = aClass.getName(); - return name != null && !"_Dummy_".equals(name); - } - final PsiElement grandParent = parent.getParent(); - if (!max && parent instanceof PsiReferenceExpression && grandParent instanceof PsiReferenceExpression) { - return true; - } - if (grandParent instanceof PsiAnnotation && !(grandParent.getParent().getNextSibling() instanceof PsiErrorElement)) { - return true; - } - if (grandParent instanceof PsiExpressionStatement && hasSemicolon(grandParent)) { - if (max) { - return true; - } - else { - final PsiElement greatGrandParent = grandParent.getParent(); - return !(greatGrandParent instanceof PsiCodeBlock) || !(greatGrandParent.getParent() instanceof JavaDummyHolder); - } - } - if (!max && grandParent instanceof PsiVariable && - PsiTreeUtil.isAncestor(((PsiVariable)grandParent).getInitializer(), variableNode, true)) { - return true; - } - if (grandParent instanceof PsiReferenceList) { - if (!max) return true; - final PsiReferenceList referenceList = (PsiReferenceList)grandParent; - final PsiElement greatGrandParent = referenceList.getParent(); - return !(greatGrandParent instanceof PsiClass) || ((PsiClass)greatGrandParent).getExtendsList() != referenceList; - } - if (grandParent instanceof PsiParameterList || grandParent instanceof PsiExpressionList || - grandParent instanceof PsiTypeParameterList || grandParent instanceof PsiResourceList) { - return true; - } - if (grandParent instanceof PsiTypeElement && grandParent.getParent() instanceof PsiReferenceParameterList) return true; - if (grandParent instanceof PsiPolyadicExpression && max) return true; + final String name = aClass.getName(); + return name != null && !"_Dummy_".equals(name); + } + final PsiElement grandParent = parent.getParent(); + if (grandParent instanceof PsiAnnotation && !(grandParent.getParent().getNextSibling() instanceof PsiErrorElement)) { + return true; + } + if (grandParent instanceof PsiParameterList || grandParent instanceof PsiExpressionList || + grandParent instanceof PsiTypeParameterList || grandParent instanceof PsiResourceList || + grandParent instanceof PsiArrayInitializerExpression) { + return true; + } + if (grandParent instanceof PsiTypeElement) { + final PsiElement greatGrandParent = grandParent.getParent(); + if (greatGrandParent instanceof PsiReferenceParameterList || greatGrandParent instanceof PsiClass) return true; + } + if (grandParent instanceof PsiAnnotationParameterList && parent instanceof PsiNameValuePair) { + final PsiNameValuePair nameValuePair = (PsiNameValuePair)parent; + return nameValuePair.getNameIdentifier() == variableNode; } return false; } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java b/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java index 50c7cd5201e2..2c49c33bfcc1 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java @@ -302,4 +302,15 @@ public abstract class StructuralSearchProfile { } return false; } + + public final boolean isApplicableConstraint(String constraintName, List nodes, boolean completePattern, boolean target) { + if (nodes.isEmpty()) { + return isApplicableConstraint(constraintName, (PsiElement)null, completePattern, target); + } + boolean result = true; + for (PsiElement node : nodes) { + result &= isApplicableConstraint(constraintName, node, completePattern, target); + } + return result; + } } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java index 314b543ee438..03e59e361ec1 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java @@ -116,11 +116,7 @@ public class PatternCompiler { element.accept(new PsiRecursiveElementWalkingVisitor() { @Override public void visitElement(PsiElement element) { - final Object userData = element.getUserData(CompiledPattern.HANDLER_KEY); - if (userData != null) { - if (userData instanceof SubstitutionHandler) { - pattern.putVariableNode(((SubstitutionHandler)userData).getName(), element); - } + if (element.getUserData(CompiledPattern.HANDLER_KEY) != null) { return; } super.visitElement(element); @@ -137,10 +133,24 @@ public class PatternCompiler { } return; } - MatchingHandler handler = pattern.getHandler(pattern.getTypedVarString(element)); + final MatchingHandler handler = pattern.getHandler(pattern.getTypedVarString(element)); if (handler == null) { throw new MalformedPatternException(); } + } + }); + element.accept(new PsiRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + collectNode(element, element.getUserData(CompiledPattern.HANDLER_KEY)); + super.visitElement(element); + + if (element instanceof LeafElement) { + collectNode(element, pattern.getHandler(pattern.getTypedVarString(element))); + } + } + + private void collectNode(PsiElement element, Object handler) { if (handler instanceof DelegatingHandler) { handler = ((DelegatingHandler)handler).getDelegate(); } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/EditVarConstraintsDialog.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/EditVarConstraintsDialog.java index 5c241425e3e0..6e4c1a07ef49 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/EditVarConstraintsDialog.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/EditVarConstraintsDialog.java @@ -336,14 +336,13 @@ class EditVarConstraintsDialog extends DialogWrapper { return; } else { final List nodes = myCompiledPattern.getVariableNodes(varName); - final PsiElement node = nodes.size() == 1 ? nodes.get(0) : null; final boolean completePattern = Configuration.CONTEXT_VAR_NAME.equals(varName); - final boolean text = myProfile.isApplicableConstraint(UIUtil.TEXT, node, completePattern, false); + final boolean text = myProfile.isApplicableConstraint(UIUtil.TEXT, nodes, completePattern, false); textConstraintsPanel.setVisible(text); - applyWithinTypeHierarchy.setVisible(text && myProfile.isApplicableConstraint(UIUtil.TEXT_HIERARCHY, node, completePattern, false)); - final boolean minZero = myProfile.isApplicableConstraint(UIUtil.MINIMUM_ZERO, node, completePattern, false); - final boolean maxUnlimited = myProfile.isApplicableConstraint(UIUtil.MAXIMUM_UNLIMITED, node, completePattern, false); + applyWithinTypeHierarchy.setVisible(text && myProfile.isApplicableConstraint(UIUtil.TEXT_HIERARCHY, nodes, completePattern, false)); + final boolean minZero = myProfile.isApplicableConstraint(UIUtil.MINIMUM_ZERO, nodes, completePattern, false); + final boolean maxUnlimited = myProfile.isApplicableConstraint(UIUtil.MAXIMUM_UNLIMITED, nodes, completePattern, false); if (minZero || maxUnlimited) { occurencePanel.setVisible(true); minoccurs.setMinValue(minZero ? 0 : 1); @@ -356,11 +355,11 @@ class EditVarConstraintsDialog extends DialogWrapper { else { occurencePanel.setVisible(false); } - final boolean typeComponent = myProfile.isApplicableConstraint(UIUtil.TYPE, node, completePattern, false); + final boolean typeComponent = myProfile.isApplicableConstraint(UIUtil.TYPE, nodes, completePattern, false); expressionConstraints.setVisible(typeComponent); - expectedTypeConstraints.setVisible(typeComponent && myProfile.isApplicableConstraint(UIUtil.EXPECTED_TYPE, node, completePattern, - false)); - referenceTargetConstraints.setVisible(myProfile.isApplicableConstraint(UIUtil.REFERENCE, node, completePattern, false)); + expectedTypeConstraints.setVisible(typeComponent && + myProfile.isApplicableConstraint(UIUtil.EXPECTED_TYPE, nodes, completePattern, false)); + referenceTargetConstraints.setVisible(myProfile.isApplicableConstraint(UIUtil.REFERENCE, nodes, completePattern, false)); containedInConstraints.setVisible(completePattern); scriptConstraints.setVisible(Registry.is("ssr.enable.script.constraint.on.all.variables") || completePattern); diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/OptimizedSearchScanTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/OptimizedSearchScanTest.java index b184e84f1404..aa5e7643569f 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/OptimizedSearchScanTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/OptimizedSearchScanTest.java @@ -30,13 +30,13 @@ public class OptimizedSearchScanTest extends StructuralSearchTestCase { public void testOptionalMethodWithThrowsClause() { final String plan = findWordsToBeUsedWhenSearchingFor( "class C {" + - " void 'm{0,1} () throws OMGWTFBBQException {}" + + " void '_m{0,1} () throws OMGWTFBBQException {}" + "}"); assertEquals("exception should not be in plan", "[in code:class|in code:enum|in code:interface][in code:C]", plan); final String plan2 = findWordsToBeUsedWhenSearchingFor( "class C {" + - " String m() throws 'E{0,1} {" + + " String m() throws '_E{0,1} {" + " System.out.println();" + " return null;" + " }" + diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index 3cc37f8ea6a9..b3a65b472460 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -304,7 +304,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "processInheritors(1,2,3,4,5,6);" + "}}"; assertEquals("no smart detection of search target", 3, - findMatchesCount(in, "'instance?.processInheritors('_param1{1,6});")); + findMatchesCount(in, "'_instance?.processInheritors('_param1{1,6});")); String someCode = "class X {{ a *= 2; a+=2; }}"; assertEquals("Improper *= 2 search", 1, findMatchesCount(someCode, "a *= 2;")); @@ -316,7 +316,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " }\n" + "}" + "}}"; - assertEquals("Find inner class parameters", 2, findMatchesCount(s1, "new Thread('args*) { '_Other* }")); + assertEquals("Find inner class parameters", 2, findMatchesCount(s1, "new Thread('args+) { '_Other* }")); String s3 = "class X {{" + "Thread t = new Thread(\"my thread\") {\n" + @@ -420,7 +420,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { findMatchesCount(s9, "new int []{ '_* }")); assertEquals("Find new int array expressions, including array initializer expressions using variable ", 2, - findMatchesCount(s9, "new 'a?:int [] { '_* }")); + findMatchesCount(s9, "new '_a?:int [] { '_* }")); assertEquals("Find all new array expressions, including array initializers", 8, findMatchesCount(s9, "new '_? []{ '_* }")); @@ -782,7 +782,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "}"; final String s136 = "class 'm {\n" + " void f();\n" + - " '_type '_method{0,0} ('_paramtype* '_paramname* );\n" + + " '_type '_method{0,0} ('_paramtype '_paramname* );\n" + "}"; assertEquals("reject method with 0 max occurence", 1, findMatchesCount(s135,s136)); @@ -999,7 +999,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " void a(String in, String pattern) {}\n" + " }"; String s1001 = "class '_Class { \n" + - " '_ReturnType+ 'MethodName+ ('_ParameterType* '_Parameter* );\n" + + " '_ReturnType+ 'MethodName+ ('_ParameterType '_Parameter* );\n" + "}"; assertEquals("handling of no match", 2, findMatchesCount(s1000,s1001)); } @@ -1034,7 +1034,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals("parameterized cast match", 1, findMatchesCount(s81, "( '_Type<'_Parameter+> ) '_Expr")); assertEquals("parameterized symbol without variables matching", 2, findMatchesCount(s81, "S")); assertEquals("parameterized definition match", 3, findMatchesCount(s81, "'_Type<'_Parameter+> 'a = '_Init?;")); - assertEquals("parameterized method match", 1, findMatchesCount(s81, "class '_ { <'_+> '_Type 'Method('_* '_*); }")); + assertEquals("parameterized method match", 1, findMatchesCount(s81, "class '_ { <'_+> '_Type 'Method('_ '_*); }")); assertEquals("parameterized constraint match", 2, findMatchesCount(s81_2, "class '_<'_+ extends 'res+> {}")); String s82_7 = "'Type"; @@ -1049,7 +1049,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " public T[] toArray(T[] a) {return c.toArray(a);}\n" + " }\n" + "}"; - assertEquals("typed symbol symbol", 2, findMatchesCount(s81_3, "class '_ { <'_+> '_Type 'Method('_* '_*); }")); + assertEquals("typed symbol symbol", 2, findMatchesCount(s81_3, "class '_ { <'_+> '_Type 'Method('_ '_*); }")); String s81_4="class A { \n" + " static void c(D f) throws R {\n" + @@ -1191,9 +1191,8 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals("find nested class by special pattern", 1, findMatchesCount(s63_2, "class '_ { class 'T { public void '_T2:run () {} } }")); - assertEquals("* regexp for typed var", 5, findMatchesCount(s61, "{ 'T*; }")); assertEquals("+ regexp for typed var", 4, findMatchesCount(s61, "{ 'T+; }")); - assertEquals("? regexp for typed var", 2, findMatchesCount(s61, "{ 'T?; }")); + assertEquals("? regexp for typed var", 2, findMatchesCount(s61, "{ '_T?; }")); assertEquals("cast in method arguments", 1, findMatchesCount(s67, " (VirtualFile)'T")); assertEquals("searching for static field in static call", 2, findMatchesCount(s69, " System.out ")); assertEquals("searching for static field in static call, 2", 2, findMatchesCount(s69, " java.lang.System.out ")); @@ -1267,14 +1266,14 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " static final long serialVersionUID = 4383685877147921099L;" + "}"; String s134 = "class '_ implements '_:*Serializable {\n" + - " static final long 'VersionField?:serialVersionUID = '_?;\n" + + " static final long 'VersionField:serialVersionUID = '_?;\n" + " private static final ObjectStreamField[] '_?:serialPersistentFields = '_?; \n" + " private void '_SerializationWriteHandler?:writeObject (ObjectOutputStream s) throws IOException;\n" + " private void '_SerializationReadHandler?:readObject (ObjectInputStream s) throws IOException, ClassNotFoundException;\n" + " Object '_SpecialSerializationReadHandler?:readResolve () throws ObjectStreamException;" + " Object '_SpecialSerializationWriteHandler?:writeReplace () throws ObjectStreamException;" + "}"; - assertEquals("serialization match", 2, findMatchesCount(s133,s134)); + assertEquals("serialization match", 2, findMatchesCount(s133, s134)); String s135 = "class SimpleStudentEventActionImpl extends Action { " + " public ActionForward execute(ActionMapping mapping,\n" + @@ -1303,7 +1302,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " private static NodeFilter instance;\n" + "}"; final String s124 = "class 'Class {\n" + - " private 'Class('_* '_*) {\n" + + " private 'Class('_ '_*) {\n" + " '_*;\n" + " }\n" + " private static '_Class2:* '_Instance;\n" + @@ -1524,8 +1523,8 @@ public class StructuralSearchTest extends StructuralSearchTestCase { String s111 = "class A { void getManager() { getManager(); } };\n" + "class B { void getManager() { getManager(); getManager(); } };"; - assertEquals("caring about missing qualifier type", 2, findMatchesCount(s111, "'Instance?:[exprtype( B )].getManager()")); - assertEquals("static query should not match instance method", 0, findMatchesCount(s111, "'Instance?:[regex( B )].getManager()")); + assertEquals("caring about missing qualifier type", 2, findMatchesCount(s111, "'_Instance?:[exprtype( B )].getManager()")); + assertEquals("static query should not match instance method", 0, findMatchesCount(s111, "'_Instance?:[regex( B )].getManager()")); assertEquals("static query should not match instance method 2", 0, findMatchesCount(s111, "B.getManager()")); String s113 = "class A { static void a() { a(); }}\n" + @@ -1663,14 +1662,14 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " public String otherField;\n" + "}"; String s4 = "class '_a {\n" + - " @'_Annotation+ ( 'AnnotationMember*:name = '_AnnotationValue* )\n" + + " @'_Annotation+ ( 'AnnotationMember+:name = '_AnnotationValue )\n" + " String '_field* ;\n" + "}"; assertEquals("Find annotation members of annotated field class", 4, findMatchesCount(s3, s4)); String s4_2 = "class '_a {\n" + " @'_Annotation+ ()\n" + - " String 'field* ;\n" + + " String 'field+ ;\n" + "}"; assertEquals("Find annotation fields", 3, findMatchesCount(s3, s4_2)); @@ -1680,9 +1679,9 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "}"; assertEquals("Find annotated methods", 2, - findMatchesCount(s5, "class '_c {@NotNull '_rt 'method* ('_pt* '_p*){ '_inst*; } }")); + findMatchesCount(s5, "class '_c {@NotNull '_rt 'method+ ('_pt '_p*){ '_inst*; } }")); assertEquals("Find annotated methods, 2", 2, - findMatchesCount(s5, "class '_c {@'_:NotNull '_rt 'method* ('_pt* '_p*){ '_inst*; } }")); + findMatchesCount(s5, "class '_c {@'_:NotNull '_rt 'method+ ('_pt '_p*){ '_inst*; } }")); String s7 = "class A { void message(@NonNls String msg); }\n" + "class B { void message2(String msg); }\n" + @@ -1698,11 +1697,11 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " @NonNls Object[] method3() {}\n" + "}"; assertEquals("Find not annotated methods, 2", 2, - findMatchesCount(s9, "class '_A { @'_Ann{0,0}:NonNls '_Type:Object\\[\\] 'b+( '_pt* '_p* ); }")); + findMatchesCount(s9, "class '_A { @'_Ann{0,0}:NonNls '_Type:Object\\[\\] 'b+( '_pt '_p* ); }")); assertEquals("Find not annotated methods, 2", 2, - findMatchesCount(s9, "class '_A { @'_Ann{0,0}:NonNls '_Type [] 'b+( '_pt* '_p* ); }")); + findMatchesCount(s9, "class '_A { @'_Ann{0,0}:NonNls '_Type [] 'b+( '_pt '_p* ); }")); assertEquals("Find not annotated methods, 2", 2, - findMatchesCount(s9, "class '_A { @'_Ann{0,0}:NonNls '_Type:Object [] 'b+( '_pt* '_p* ); }")); + findMatchesCount(s9, "class '_A { @'_Ann{0,0}:NonNls '_Type:Object [] 'b+( '_pt '_p* ); }")); String s11 = "class A {\n" + " @Foo(value=baz) int a;\n" + @@ -1732,7 +1731,8 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals("Match anno parameter name 2", 3, findMatchesCount(s11, "@Foo(value='_value)")); assertEquals("Match value anno parameter only", 2, findMatchesCount(s11, "@Foo(baz2)")); assertEquals("Match value anno parameters", 3, findMatchesCount(s11, "@Foo('_value)")); - assertEquals("Match all annotations", 10, findMatchesCount(s11, "@Foo('_value*)")); + assertEquals("Match all annotations", 10, findMatchesCount(s11, "@Foo('_value?)")); + assertEquals("Match all annotations 2", 10, findMatchesCount(s11, "@Foo")); assertEquals("Match annotations without parameters", 1, findMatchesCount(s11, "@Foo('_name{0,0}='_v)")); String s12 = "@X(value=1, x=2) @Y(1) @Z(x=0, y=0, z=0) @W(2) @V(x=0, y=0, z=0) class One {}"; @@ -1973,9 +1973,9 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " static { int b = 1; }" + " { int c = 2; }" + "}"; - assertEquals("Static / instance initializers", 2, findMatchesCount(s1, "static { 't*; }")); - assertEquals("Static / instance initializers", 1, findMatchesCount(s1, "@Modifier(\"Instance\") { 't*; }")); - assertEquals("Static / instance initializers", 3, findMatchesCount(s1, "{ 't*; }")); + assertEquals("Static / instance initializers", 2, findMatchesCount(s1, "static { '_t*; }")); + assertEquals("Static / instance initializers", 1, findMatchesCount(s1, "@Modifier(\"Instance\") { '_t*; }")); + assertEquals("Static / instance initializers", 3, findMatchesCount(s1, "{ '_t*; }")); } @NotNull @@ -1988,7 +1988,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { String s1 = loadFile(getTestName(false) + ".java"); String s2 = "ApplicationManager.getApplication().runReadAction(new Runnable() {\n" + " public void run() {\n" + - " 't*:[ !regex( .*return.* ) ];\n" + + " '_t*:[ !regex( .*return.* ) ];\n" + " }});"; assertEquals(0, findMatchesCount(s1,s2)); } @@ -2336,10 +2336,10 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " void m();" + "}"; - String pattern1 = "interface '_Class { default '_ReturnType+ 'MethodName+('_ParameterType* '_Parameter*);}"; + String pattern1 = "interface '_Class { default '_ReturnType+ 'MethodName+('_ParameterType '_Parameter*);}"; assertEquals("should find default method", 1, findMatchesCount(source, pattern1)); - String pattern2 = "interface 'Class { default '_ReturnType+ '_MethodName{0,0}('_ParameterType* '_Parameter*);}"; + String pattern2 = "interface 'Class { default '_ReturnType+ '_MethodName{0,0}('_ParameterType '_Parameter*);}"; assertEquals("should find interface without default methods", 1, findMatchesCount(source, pattern2)); } @@ -2389,7 +2389,6 @@ public class StructuralSearchTest extends StructuralSearchTestCase { fail("malformed pattern warning expected"); } catch (MalformedPatternException ignored) {} - findMatchesCount(source, "'_ReturnType '_Method*('_ParameterType '_Parameter);"); } public void testInvalidPatternWarnings() { @@ -2583,7 +2582,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " }" + "}"; assertEquals("find assert statements", 3, findMatchesCount(source, "assert '_a;")); - assertEquals("find assert statements 2", 3, findMatchesCount(source, "assert '_a : 'b*;")); + assertEquals("find assert statements 2", 3, findMatchesCount(source, "assert '_a : '_b?;")); assertEquals("find assert statement with messages", 1, findMatchesCount(source, "assert '_a : '_b;")); assertEquals("find assert statement without messages", 2, findMatchesCount(source, "assert 'a : '_b{0,0};")); } diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java index 977fbc596fe9..49f817b6e1d6 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java @@ -14,6 +14,7 @@ import com.intellij.psi.PsiElement; import com.intellij.structuralsearch.impl.matcher.CompiledPattern; import com.intellij.structuralsearch.impl.matcher.compiler.PatternCompiler; import com.intellij.structuralsearch.plugin.ui.UIUtil; +import com.intellij.util.SmartList; import java.io.File; import java.io.IOException; @@ -67,17 +68,19 @@ public abstract class StructuralSearchTestCase extends LightQuickFixTestCase { assert profile != null; for (String varName : options.getVariableConstraintNames()) { final List nodes = compiledPattern.getVariableNodes(varName); - final PsiElement node = nodes.size() == 1 ? nodes.get(0) : null; final MatchVariableConstraint constraint = options.getVariableConstraint(varName); - final String constraintName; + final List usedConstraints = new SmartList<>(); if (!StringUtil.isEmpty(constraint.getRegExp())) { - constraintName = UIUtil.TEXT; + usedConstraints.add(UIUtil.TEXT); } - else { // todo check other constraints - constraintName = null; + if (constraint.getMinCount() == 0) { + usedConstraints.add(UIUtil.MINIMUM_ZERO); } - if (constraintName != null && !profile.isApplicableConstraint(constraintName, node, false, constraint.isPartOfSearchResults())) { - return constraintName + " not applicable for " + varName; + // todo check other constraints + for (String usedConstraint : usedConstraints) { + if (!profile.isApplicableConstraint(usedConstraint, nodes, false, constraint.isPartOfSearchResults())) { + return usedConstraint + " not applicable for " + varName; + } } } return null; diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/XmlStructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/XmlStructuralSearchTest.java index 412a537aca82..051963ea7430 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/XmlStructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/XmlStructuralSearchTest.java @@ -90,7 +90,7 @@ public class XmlStructuralSearchTest extends StructuralSearchTestCase { String s3 = " content \n" + " another content \n" + "another zzzcontent "; - String s4 = "<'_tag>'Content*"; + String s4 = "<'_tag>'Content+"; assertEquals("Content match", 6, findMatchesCount(s3, s4, StdFileTypes.HTML)); assertEquals("Content match", 6, findMatchesCount(s3, s4, StdFileTypes.XML)); } @@ -171,7 +171,7 @@ public class XmlStructuralSearchTest extends StructuralSearchTestCase { public void testXmlSearch2() { String s1 = "

AAA

ZZZ

"; - String s2 = "

'content?

"; + String s2 = "

'_content?

"; assertEquals(5, findMatchesCount(s1, s2, StdFileTypes.XML)); } From 451bc769e77cd0a922488f1a2efccb288676860b Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 7 May 2018 12:16:16 +0200 Subject: [PATCH 18/28] SSR: fix & test max count not available bugs --- .../JavaStructuralSearchProfile.java | 16 +++++----- .../StructuralSearchTest.java | 30 ++++++++++++------- .../StructuralSearchTestCase.java | 3 ++ 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java index 0e3f832d54b3..9babfd56bca2 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java @@ -913,9 +913,9 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { if (grandParent instanceof PsiPolyadicExpression) return true; if (grandParent instanceof PsiExpressionStatement && hasSemicolon(grandParent)) return true; if (grandParent instanceof PsiReferenceList) { - final PsiReferenceList referenceList = (PsiReferenceList)grandParent; - final PsiElement greatGrandParent = referenceList.getParent(); - return !(greatGrandParent instanceof PsiClass) || ((PsiClass)greatGrandParent).getExtendsList() != referenceList; + final PsiElement greatGrandParent = grandParent.getParent(); + return !(greatGrandParent instanceof PsiClass) || ((PsiClass)greatGrandParent).getExtendsList() != grandParent || + greatGrandParent instanceof PsiTypeParameter; } return false; } @@ -933,12 +933,11 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { return name != null && !"_Dummy_".equals(name); } final PsiElement grandParent = parent.getParent(); - if (grandParent instanceof PsiAnnotation && !(grandParent.getParent().getNextSibling() instanceof PsiErrorElement)) { - return true; - } + if (grandParent instanceof PsiCatchSection && parent instanceof PsiParameter) return true; + if (grandParent instanceof PsiAnnotation && !(grandParent.getParent().getNextSibling() instanceof PsiErrorElement)) return true; if (grandParent instanceof PsiParameterList || grandParent instanceof PsiExpressionList || grandParent instanceof PsiTypeParameterList || grandParent instanceof PsiResourceList || - grandParent instanceof PsiArrayInitializerExpression) { + grandParent instanceof PsiArrayInitializerExpression || grandParent instanceof PsiArrayInitializerMemberValue) { return true; } if (grandParent instanceof PsiTypeElement) { @@ -946,8 +945,7 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { if (greatGrandParent instanceof PsiReferenceParameterList || greatGrandParent instanceof PsiClass) return true; } if (grandParent instanceof PsiAnnotationParameterList && parent instanceof PsiNameValuePair) { - final PsiNameValuePair nameValuePair = (PsiNameValuePair)parent; - return nameValuePair.getNameIdentifier() == variableNode; + return ((PsiNameValuePair)parent).getNameIdentifier() == variableNode; } return false; } diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index b3a65b472460..1136159997b4 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -636,7 +636,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "try { a(); } catch(Exception ex) {}" + "}}"; assertEquals("catch parameter matching", 3, - findMatchesCount(s10031, "try { a(); } catch('_Type+ 'Arg+) { '_Statements*; }\n")); + findMatchesCount(s10031, "try { a(); } catch('_Type 'Arg+) { '_Statements*; }\n")); String s10033 = "class X {{ " + "return x;\n" + @@ -826,7 +826,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "class D { void method() {} }\n" + "class E {}"; assertEquals("parameterless constructor search", 3, - findMatchesCount(s143, "class '_a { '_d{0,0}:[ script( \"__context__.constructor\" ) ]('_b+ '_c+); }")); + findMatchesCount(s143, "class '_a { '_d{0,0}:[ script( \"__context__.constructor\" ) ]('_b '_c+); }")); assertEquals("parameterless constructor search 2", 2, findMatchesCount(s143, "'_Constructor() { '_st*; }")); } @@ -999,7 +999,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " void a(String in, String pattern) {}\n" + " }"; String s1001 = "class '_Class { \n" + - " '_ReturnType+ 'MethodName+ ('_ParameterType '_Parameter* );\n" + + " '_ReturnType 'MethodName+ ('_ParameterType '_Parameter* );\n" + "}"; assertEquals("handling of no match", 2, findMatchesCount(s1000,s1001)); } @@ -1284,7 +1284,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "} " + "public class DoEnrollStudent extends SimpleStudentEventActionImpl { }" + "public class DoCancelStudent extends SimpleStudentEventActionImpl { }"; - String s136 = "public class 'StrutsActionClass extends '_*:Action {" + + String s136 = "public class 'StrutsActionClass extends '_:*Action {" + " public ActionForward '_AnActionMethod:*execute (ActionMapping '_,\n" + " ActionForm '_,\n" + " HttpServletRequest '_,\n" + @@ -1787,7 +1787,6 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals("Find SuppressWarnings annotations", 2, findMatchesCount(source6, "@SuppressWarnings")); assertEquals("Find SuppressWarnings annotations", 2, findMatchesCount(source6, "@SuppressWarnings(value='_any)")); assertEquals("Find annotation with 3 value array initializer", 1, findMatchesCount(source6, "@SuppressWarnings({'_value{3,3} })")); - } public void testBoxingAndUnboxing() { @@ -2183,22 +2182,22 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "}"; String pattern1 = "class '_A {" + - " '_type+ 'method+ () throws '_E{0,0};" + + " '_type 'method+ () throws '_E{0,0};" + "}"; assertEquals(1, findMatchesCount(source, pattern1)); String pattern2 = "class '_A {" + - " '_type+ 'method+ () throws '_E{1,2};" + + " '_type 'method+ () throws '_E{1,2};" + "}"; assertEquals(2, findMatchesCount(source, pattern2)); String pattern3 = "class '_A {" + - " '_type+ 'method+ () throws '_E{2,2};" + + " '_type 'method+ () throws '_E{2,2};" + "}"; assertEquals(1, findMatchesCount(source, pattern3)); String pattern4 = "class '_A {" + - " '_type+ 'method+ () throws '_E{0,0}:[ regex( E2 )];" + + " '_type 'method+ () throws '_E{0,0}:[ regex( E2 )];" + "}"; assertEquals(2, findMatchesCount(source, pattern4)); } @@ -2336,10 +2335,10 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " void m();" + "}"; - String pattern1 = "interface '_Class { default '_ReturnType+ 'MethodName+('_ParameterType '_Parameter*);}"; + String pattern1 = "interface '_Class { default '_ReturnType 'MethodName+('_ParameterType '_Parameter*);}"; assertEquals("should find default method", 1, findMatchesCount(source, pattern1)); - String pattern2 = "interface 'Class { default '_ReturnType+ '_MethodName{0,0}('_ParameterType '_Parameter*);}"; + String pattern2 = "interface 'Class { default '_ReturnType '_MethodName{0,0}('_ParameterType '_Parameter*);}"; assertEquals("should find interface without default methods", 1, findMatchesCount(source, pattern2)); } @@ -2430,6 +2429,15 @@ public class StructuralSearchTest extends StructuralSearchTestCase { } catch (MalformedPatternException ignored) {} } + public void testNotApplicableConstraints() { + options.fillSearchCriteria("class A extends '_B* {}"); + assertEquals("MAXIMUM UNLIMITED not applicable for B", checkApplicableConstraints()); + + options.clearVariableConstraints(); + options.fillSearchCriteria("'_a?.'_b?"); + assertEquals("MINIMUM ZERO not applicable for b", checkApplicableConstraints()); + } + public void testFindInnerClass() { String source = "class Foo {\n" + " static class Bar {}\n" + diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java index 49f817b6e1d6..649ca34e8605 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java @@ -76,6 +76,9 @@ public abstract class StructuralSearchTestCase extends LightQuickFixTestCase { if (constraint.getMinCount() == 0) { usedConstraints.add(UIUtil.MINIMUM_ZERO); } + if (constraint.getMaxCount() > 1) { + usedConstraints.add(UIUtil.MAXIMUM_UNLIMITED); + } // todo check other constraints for (String usedConstraint : usedConstraints) { if (!profile.isApplicableConstraint(usedConstraint, nodes, false, constraint.isPartOfSearchResults())) { From d1fb12a1e27e804a2f070b7ee559c440aed30081 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 7 May 2018 12:51:33 +0200 Subject: [PATCH 19/28] SSR: fix & test other constraints availability --- .../JavaStructuralSearchProfile.java | 32 ++++++++++++------- .../StructuralSearchTest.java | 2 +- .../StructuralSearchTestCase.java | 13 +++++++- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java index 9babfd56bca2..0917188945c8 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java @@ -833,10 +833,13 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { case UIUtil.TEXT_HIERARCHY: if (variableNode != null) { final PsiElement parent = variableNode.getParent(); - if (parent instanceof PsiJavaCodeReferenceElement && parent.getParent() instanceof PsiTypeElement || - parent instanceof PsiClass) { - return true; + if (parent instanceof PsiJavaCodeReferenceElement) { + final PsiElement grandParent = parent.getParent(); + if (grandParent instanceof PsiTypeElement || grandParent instanceof PsiReferenceList || + grandParent instanceof PsiReferenceExpression) return true; } + else if (parent instanceof PsiClass) return true; + else if (isMemberSurroundedByClass(parent)) return true; } return false; case UIUtil.EXPECTED_TYPE: @@ -923,15 +926,7 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { private static boolean isApplicableMinMaxCount(@NotNull PsiElement variableNode) { if (variableNode instanceof PsiDocToken) return true; final PsiElement parent = variableNode.getParent(); - if (parent instanceof PsiMember && !(parent instanceof PsiTypeParameter)) { - final PsiMember member = (PsiMember)parent; - final PsiClass aClass = member.getContainingClass(); - if (aClass == null) { - return false; - } - final String name = aClass.getName(); - return name != null && !"_Dummy_".equals(name); - } + if (isMemberSurroundedByClass(parent)) return true; final PsiElement grandParent = parent.getParent(); if (grandParent instanceof PsiCatchSection && parent instanceof PsiParameter) return true; if (grandParent instanceof PsiAnnotation && !(grandParent.getParent().getNextSibling() instanceof PsiErrorElement)) return true; @@ -950,6 +945,19 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { return false; } + private static boolean isMemberSurroundedByClass(PsiElement parent) { + if (!(parent instanceof PsiMember) || parent instanceof PsiTypeParameter) { + return false; + } + final PsiMember member = (PsiMember)parent; + final PsiClass aClass = member.getContainingClass(); + if (aClass == null) { + return false; + } + final String name = aClass.getName(); + return name != null && !"_Dummy_".equals(name); + } + private static boolean hasSemicolon(PsiElement element) { PsiElement lastChild = element.getLastChild(); while (lastChild instanceof PsiComment || lastChild instanceof PsiWhiteSpace) { diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index 1136159997b4..db2f5ae4d12b 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -474,7 +474,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "}"; assertEquals("match literal contents", 1, findMatchesCount(s2, "\"'String:[regex( alpha )]\"")); assertEquals("negate match literal contents", 2, findMatchesCount(s2, "\"'String:[!regex( alpha )]\"")); - assertEquals("match literal contents and all types", 1, findMatchesCount(s2, "\"'String:[regex( alpha ) && exprtype( .* )]\"")); + assertEquals("match literal contents combined with other constraint", 1, findMatchesCount(s2, "\"'String:[regex( alpha ) && script( true )]\"")); String s3 = "class A {" + " int i = 0x20;" + diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java index 649ca34e8605..1a7ed5b7b083 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java @@ -73,13 +73,24 @@ public abstract class StructuralSearchTestCase extends LightQuickFixTestCase { if (!StringUtil.isEmpty(constraint.getRegExp())) { usedConstraints.add(UIUtil.TEXT); } + if (constraint.isWithinHierarchy()) { + usedConstraints.add(UIUtil.TEXT_HIERARCHY); + } if (constraint.getMinCount() == 0) { usedConstraints.add(UIUtil.MINIMUM_ZERO); } if (constraint.getMaxCount() > 1) { usedConstraints.add(UIUtil.MAXIMUM_UNLIMITED); } - // todo check other constraints + if (!StringUtil.isEmpty(constraint.getNameOfExprType())) { + usedConstraints.add(UIUtil.TYPE); + } + if (!StringUtil.isEmpty(constraint.getNameOfFormalArgType())) { + usedConstraints.add(UIUtil.EXPECTED_TYPE); + } + if (!StringUtil.isEmpty(constraint.getReferenceConstraint())) { + usedConstraints.add(UIUtil.REFERENCE); + } for (String usedConstraint : usedConstraints) { if (!profile.isApplicableConstraint(usedConstraint, nodes, false, constraint.isPartOfSearchResults())) { return usedConstraint + " not applicable for " + varName; From d33d5b1533c8fb36feeca946c8c9fa38c2f7a0d3 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 7 May 2018 14:21:09 +0200 Subject: [PATCH 20/28] SSR: remove need to call clearVariableConstraints() before initializing --- .../com/intellij/structuralsearch/MatchOptions.java | 9 +-------- .../structuralsearch/plugin/replace/impl/Replacer.java | 1 - .../intellij/structuralsearch/StructuralSearchTest.java | 2 -- .../structuralsearch/StructuralSearchTestCase.java | 1 - 4 files changed, 1 insertion(+), 12 deletions(-) diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/MatchOptions.java b/platform/structuralsearch/source/com/intellij/structuralsearch/MatchOptions.java index b82e9489046a..47cfbfe2535e 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/MatchOptions.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/MatchOptions.java @@ -68,14 +68,6 @@ public class MatchOptions implements JDOMExternalizable { variableConstraints.put(constraint.getName(), constraint); } - public boolean hasVariableConstraints() { - return !variableConstraints.isEmpty(); - } - - public void clearVariableConstraints() { - variableConstraints.clear(); - } - public void retainVariableConstraints(Collection names) { if (variableConstraints.isEmpty()) { return; @@ -140,6 +132,7 @@ public class MatchOptions implements JDOMExternalizable { } public void fillSearchCriteria(String criteria) { + if (!variableConstraints.isEmpty()) variableConstraints.clear(); StringToConstraintsTransformer.transformCriteria(criteria, this); } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/Replacer.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/Replacer.java index 26e7ae8c410d..d9efe409d3c1 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/Replacer.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/Replacer.java @@ -75,7 +75,6 @@ public class Replacer { replaceOptions.setReplacement(by); final MatchOptions matchOptions = replaceOptions.getMatchOptions(); - matchOptions.clearVariableConstraints(); matchOptions.fillSearchCriteria(what); Matcher.validate(project, matchOptions); diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index db2f5ae4d12b..0d26272d8768 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -2035,7 +2035,6 @@ public class StructuralSearchTest extends StructuralSearchTestCase { results.clear(); - options.clearVariableConstraints(); options.fillSearchCriteria("try { '_st*; } catch('Type:Type2 '_t) { '_st2*; }"); for(PsiVariable var:vars) { @@ -2433,7 +2432,6 @@ public class StructuralSearchTest extends StructuralSearchTestCase { options.fillSearchCriteria("class A extends '_B* {}"); assertEquals("MAXIMUM UNLIMITED not applicable for B", checkApplicableConstraints()); - options.clearVariableConstraints(); options.fillSearchCriteria("'_a?.'_b?"); assertEquals("MINIMUM ZERO not applicable for b", checkApplicableConstraints()); } diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java index 1a7ed5b7b083..c7097f98bc7e 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java @@ -52,7 +52,6 @@ public abstract class StructuralSearchTestCase extends LightQuickFixTestCase { FileType sourceFileType, String sourceExtension, boolean physicalSourceFile) { - options.clearVariableConstraints(); options.fillSearchCriteria(pattern); options.setFileType(patternFileType); options.setDialect(patternLanguage); From c7b6235551d99d5dcea3487dfa93104396ee5bce Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 7 May 2018 12:02:15 +0200 Subject: [PATCH 21/28] API to exclude files from indexing globally --- .../util/indexing/FileBasedIndexImpl.java | 3 +- .../util/indexing/GlobalIndexFilter.java | 35 +++++++++++++++++++ .../src/META-INF/LangExtensionPoints.xml | 1 + 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 platform/lang-impl/src/com/intellij/util/indexing/GlobalIndexFilter.java diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index c460b55e3560..84631f37a7d0 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -398,7 +398,8 @@ public class FileBasedIndexImpl extends FileBasedIndex implements BaseComponent, state.registerIndex(name, createIndex(extension, new MemoryIndexStorage<>(storage, name)), - file -> file instanceof VirtualFileWithId && inputFilter.acceptInput(file), + file -> file instanceof VirtualFileWithId && inputFilter.acceptInput(file) && + !GlobalIndexFilter.isExcludedFromIndexViaFilters(file, name), version, addedTypes); break; diff --git a/platform/lang-impl/src/com/intellij/util/indexing/GlobalIndexFilter.java b/platform/lang-impl/src/com/intellij/util/indexing/GlobalIndexFilter.java new file mode 100644 index 000000000000..9affec43941d --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/GlobalIndexFilter.java @@ -0,0 +1,35 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.util.indexing; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +/** + * Allows to exclude files from indexing, on a per-index basis. + * + * @author yole + */ +@ApiStatus.Experimental +public interface GlobalIndexFilter { + /** + * Returns true if the given file should be excluded from indexing by the given index. + */ + boolean isExcludedFromIndex(@NotNull VirtualFile virtualFile, @NotNull IndexId indexId); + + ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.globalIndexFilter"); + + /** + * Returns true if the given file should be excluded from indexing by any of the registered filters. + */ + static boolean isExcludedFromIndexViaFilters(@NotNull VirtualFile file, @NotNull IndexId indexId) { + for (GlobalIndexFilter filter : Extensions.getExtensions(EP_NAME)) { + if (filter.isExcludedFromIndex(file, indexId)) { + return true; + } + } + return false; + } +} diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index 2c7a39144fce..c93d53114665 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -400,6 +400,7 @@ + From 74237fe6b0613dc1f05db1855b27da7fc376a6b7 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 7 May 2018 15:51:34 +0200 Subject: [PATCH 22/28] IDEA-CR-32392 LafIconLookup.getIcon should be not always strict --- .../src/com/intellij/util/ui/LafIconLookup.kt | 18 ++++++++++++++--- .../ide/ui/laf/darcula/DarculaLaf.java | 2 +- .../laf/intellij/WinIntelliJTextFieldUI.java | 20 +++---------------- .../testSrc/com/intellij/ui/SvgRenderer.kt | 5 +++-- .../com/intellij/openapi/util/IconLoader.java | 14 +++++++++++-- 5 files changed, 34 insertions(+), 25 deletions(-) diff --git a/platform/platform-api/src/com/intellij/util/ui/LafIconLookup.kt b/platform/platform-api/src/com/intellij/util/ui/LafIconLookup.kt index bffe906f76b2..f2520fe50a0b 100644 --- a/platform/platform-api/src/com/intellij/util/ui/LafIconLookup.kt +++ b/platform/platform-api/src/com/intellij/util/ui/LafIconLookup.kt @@ -2,7 +2,9 @@ package com.intellij.util.ui import com.intellij.icons.AllIcons +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.util.IconLoader +import com.intellij.util.ThreeState import javax.swing.Icon /** @@ -12,11 +14,11 @@ object LafIconLookup { @JvmStatic @JvmOverloads fun getIcon(name: String, selected: Boolean = false, focused: Boolean = false, enabled: Boolean = true, editable: Boolean = false, pressed: Boolean = false): Icon { - return findIcon(name, selected = selected, focused = focused, enabled = enabled, editable = editable, pressed = pressed, isThrowErrorIfNotFound = true) + return findIcon(name, selected = selected, focused = focused, enabled = enabled, editable = editable, pressed = pressed) ?: AllIcons.Actions.Stub } - fun findIcon(name: String, selected: Boolean = false, focused: Boolean = false, enabled: Boolean = true, editable: Boolean = false, pressed: Boolean = false, isThrowErrorIfNotFound: Boolean = false): Icon? { + fun findIcon(name: String, selected: Boolean = false, focused: Boolean = false, enabled: Boolean = true, editable: Boolean = false, pressed: Boolean = false, isThrowErrorIfNotFound: ThreeState = ThreeState.UNSURE): Icon? { var key = name if (editable) key += "Editable" if (selected) key += "Selected" @@ -37,7 +39,17 @@ object LafIconLookup { } key = dir + key - return IconLoader.findIcon("/com/intellij/ide/ui/laf/icons/$key.png", LafIconLookup::class.java, true, isThrowErrorIfNotFound) + @Suppress("DEPRECATION") + return IconLoader.findIcon("/com/intellij/ide/ui/laf/icons/$key.png", LafIconLookup::class.java, resolveIsThrowErrorIfNotFound(isThrowErrorIfNotFound)) + } + + private fun resolveIsThrowErrorIfNotFound(value: ThreeState): Boolean { + if (value != ThreeState.UNSURE) { + return value == ThreeState.YES + } + + val app = ApplicationManager.getApplication() + return app.isUnitTestMode || app.isInternal } @JvmStatic diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java index d447bc367553..e013bac997d2 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java @@ -362,7 +362,7 @@ public class DarculaLaf extends BasicLookAndFeel { } if (value.endsWith(".png") || value.endsWith(".svg")) { - Icon icon = IconLoader.findIcon(value, DarculaLaf.class, true); + Icon icon = IconLoader.findIcon(value, DarculaLaf.class); if (icon != null) { return icon; } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextFieldUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextFieldUI.java index 1296c7dc2d10..ba19f2c64b74 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextFieldUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextFieldUI.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 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. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.ui.laf.intellij; import com.intellij.ide.ui.laf.darcula.DarculaUIUtil; @@ -140,7 +126,7 @@ public class WinIntelliJTextFieldUI extends TextFieldWithPopupHandlerUI { } }; } - return icon != null ? icon : IconLoader.findIcon("/com/intellij/ide/ui/laf/icons/search.png", DarculaTextFieldUI.class, true); + return icon != null ? icon : IconLoader.findIcon("/com/intellij/ide/ui/laf/icons/search.png", DarculaTextFieldUI.class); } @Override @@ -152,7 +138,7 @@ public class WinIntelliJTextFieldUI extends TextFieldWithPopupHandlerUI { protected Icon getClearIcon(boolean hovered, boolean clickable) { if (!clickable) return null; Icon icon = UIManager.getIcon("TextField.darcula.clear.icon"); - return icon != null ? icon : IconLoader.findIcon("/com/intellij/ide/ui/laf/icons/clear.png", DarculaTextFieldUI.class, true); + return icon != null ? icon : IconLoader.findIcon("/com/intellij/ide/ui/laf/icons/clear.png", DarculaTextFieldUI.class); } @Override diff --git a/platform/platform-tests/testSrc/com/intellij/ui/SvgRenderer.kt b/platform/platform-tests/testSrc/com/intellij/ui/SvgRenderer.kt index 9bcc75b659e9..6216cb3524e5 100644 --- a/platform/platform-tests/testSrc/com/intellij/ui/SvgRenderer.kt +++ b/platform/platform-tests/testSrc/com/intellij/ui/SvgRenderer.kt @@ -8,6 +8,7 @@ import com.intellij.openapi.util.SystemInfoRt import com.intellij.openapi.util.io.FileUtilRt import com.intellij.openapi.util.text.StringUtilRt import com.intellij.testFramework.assertions.Assertions.assertThat +import com.intellij.util.ThreeState import com.intellij.util.ui.LafIconLookup import gnu.trove.THashMap import org.apache.batik.anim.dom.SVGDOMImplementation @@ -58,7 +59,7 @@ internal class SvgRenderer(val svgFileDir: Path, private val deviceConfiguration for (name in arrayOf("checkBox", "radio", "gear", "spinnerRight")) { val iconWrapper = when (name) { "gear" -> IconLoader.getIcon("/general/gear.png") - else -> LafIconLookup.findIcon(name) + else -> LafIconLookup.findIcon(name, isThrowErrorIfNotFound = ThreeState.NO) } ?: continue if (isImage(iconWrapper)) { @@ -66,7 +67,7 @@ internal class SvgRenderer(val svgFileDir: Path, private val deviceConfiguration } } for (name in arrayOf("checkBox", "radio")) { - val iconWrapper = LafIconLookup.findIcon(name, selected = true) ?: continue + val iconWrapper = LafIconLookup.findIcon(name, selected = true, isThrowErrorIfNotFound = ThreeState.NO) ?: continue if (isImage(iconWrapper)) { return getIconRelativePath(iconWrapper.toString()) } diff --git a/platform/util/src/com/intellij/openapi/util/IconLoader.java b/platform/util/src/com/intellij/openapi/util/IconLoader.java index 3aba9bc3056a..94518000157e 100644 --- a/platform/util/src/com/intellij/openapi/util/IconLoader.java +++ b/platform/util/src/com/intellij/openapi/util/IconLoader.java @@ -168,16 +168,26 @@ public final class IconLoader { */ @Nullable public static Icon findIcon(@NotNull final String path, @NotNull final Class aClass) { - return findIcon(path, aClass, false); + //noinspection deprecation + return findIcon(path, aClass, false, STRICT); } + /** + * @deprecated Use {@link #findIcon(String, Class)} + */ @Nullable + @Deprecated public static Icon findIcon(@NotNull String path, @NotNull final Class aClass, boolean computeNow) { return findIcon(path, aClass, computeNow, STRICT); } + /** + * @deprecated Use {@link #findIcon(String, Class)} + */ + @SuppressWarnings("DeprecatedIsStillUsed") @Nullable - public static Icon findIcon(@NotNull String path, @NotNull Class aClass, boolean computeNow, boolean strict) { + @Deprecated + public static Icon findIcon(@NotNull String path, @NotNull Class aClass, @SuppressWarnings("unused") boolean unused, boolean strict) { String originalPath = path; Pair patchedPath = patchPath(path); path = patchedPath.first; From 74f52871982586c9f20bba7cf532852dd1017e69 Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Mon, 7 May 2018 16:52:48 +0300 Subject: [PATCH 23/28] UX-1 new SearchEverywhere popup * recalc results on "non project" checkbox state changes * removed unused params --- .../searcheverywhere/SearchEverywhereUI.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java index 0ec2b6eac192..5dca6758ecd6 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java @@ -172,7 +172,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { } myNonProjectCB.setSelected(false); repaint(); - rebuildList(mySearchField != null ? mySearchField.getText() : ""); + rebuildList(); } private JTextField createSearchField() { @@ -330,7 +330,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { } } - private void rebuildList(final String pattern) { + private void rebuildList() { assert EventQueue.isDispatchThread() : "Must be EDT"; if (myCalcThread != null && !myCurrentWorker.isProcessed()) { myCurrentWorker = myCalcThread.cancel(); @@ -339,6 +339,8 @@ public class SearchEverywhereUI extends BorderLayoutPanel { myCalcThread.cancel(); } + String pattern = mySearchField != null ? mySearchField.getText() : ""; + MinusculeMatcher matcher = NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE); MatcherHolder.associateMatcher(myResultsList, matcher); @@ -377,10 +379,12 @@ public class SearchEverywhereUI extends BorderLayoutPanel { mySearchField.getDocument().addDocumentListener(new DocumentAdapter() { @Override protected void textChanged(DocumentEvent e) { - rebuildList(mySearchField.getText()); + rebuildList(); } }); + myNonProjectCB.addItemListener(e -> rebuildList()); + myResultsList.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { @@ -470,10 +474,10 @@ public class SearchEverywhereUI extends BorderLayoutPanel { myResultsRanges.clear(); SearchEverywhereContributor selectedContributor = mySelectedTab.getContributor().orElse(null); if (selectedContributor != null) { - runReadAction(() -> addContributorItems(selectedContributor, true), true); + runReadAction(() -> addContributorItems(selectedContributor), true); } else { for (SearchEverywhereContributor contributor : allContributors) { - runReadAction(() -> addContributorItems(contributor, false), true); + runReadAction(() -> addContributorItems(contributor), true); } } updatePopup(); @@ -497,7 +501,7 @@ public class SearchEverywhereUI extends BorderLayoutPanel { } } - private void addContributorItems(SearchEverywhereContributor contributor, boolean exclusiveContributor) { + private void addContributorItems(SearchEverywhereContributor contributor) { SearchEverywhereContributor.ContributorSearchResult results = contributor.search(project, pattern, isUseNonProjectItems(), myProgressIndicator, ELEMENTS_LIMIT); if (!results.isEmpty()) { From 1d406f73ec6e5b907b56cffd2da9dfa4d8ca6f2c Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Mon, 7 May 2018 17:01:33 +0300 Subject: [PATCH 24/28] EA-107109 - PCE: AbstractProgressIndicatorBase.throwIfCanceled --- .../intellij/openapi/module/impl/ModuleManagerImpl.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java index 4c09cd1e7311..102c15439138 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java @@ -14,10 +14,7 @@ import com.intellij.openapi.components.ServiceKt; import com.intellij.openapi.components.impl.stores.ModuleStore; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.*; -import com.intellij.openapi.progress.EmptyProgressIndicator; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressIndicatorProvider; -import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.*; import com.intellij.openapi.progress.util.ProgressWrapper; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; @@ -300,6 +297,8 @@ public abstract class ModuleManagerImpl extends ModuleManager implements Disposa catch (IOException e) { reportError(errors, modulePath, e); } + catch (ProcessCanceledException ignore) { + } catch (Exception e) { LOG.error(e); } From 6ef53ca382fe2c4446afc69b62162f61fecd68f1 Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Fri, 4 May 2018 17:14:06 +0300 Subject: [PATCH 25/28] Migration to PsiFile-based CodStyle API --- .../intentions/ConvertFieldToAtomicIntention.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToAtomicIntention.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToAtomicIntention.java index b6ba5ee14f21..13713b301c8a 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToAtomicIntention.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToAtomicIntention.java @@ -11,7 +11,6 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleSettings; import com.intellij.psi.impl.AllowedApiFilterExtension; @@ -138,7 +137,7 @@ public class ConvertFieldToAtomicIntention extends PsiElementBaseIntentionAction static void postProcessVariable(@NotNull PsiVariable var, @NotNull String toType) { Project project = var.getProject(); - if (var instanceof PsiField || CodeStyleSettingsManager.getSettings(project).getCustomSettings(JavaCodeStyleSettings.class).GENERATE_FINAL_LOCALS) { + if (var instanceof PsiField || JavaCodeStyleSettings.getInstance(var.getContainingFile()).GENERATE_FINAL_LOCALS) { PsiModifierList modifierList = assertNotNull(var.getModifierList()); WriteAction.run(() -> { if (var.getInitializer() == null) { From ceb92ee48f40e8c8a61f8a0456a6dc2a17afb61b Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Mon, 7 May 2018 15:39:40 +0300 Subject: [PATCH 26/28] Migration to PsiFile-based CodeStyle API --- .../codeStyle/CodeStyleManagerImpl.java | 82 ++++++++++--------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java index 7450a4b8b02d..17400fcde29e 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java @@ -51,14 +51,11 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting private final ThreadLocal myCurrentFormattingMode = ThreadLocal.withInitial(() -> FormattingMode.REFORMAT); - private final FormatterTagHandler myTagHandler; - private final Project myProject; @NonNls private static final String DUMMY_IDENTIFIER = "xxx"; public CodeStyleManagerImpl(Project project) { myProject = project; - myTagHandler = new FormatterTagHandler(getSettings()); } @Override @@ -83,35 +80,38 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting } ASTNode treeElement = element.getNode(); - final PsiElement formatted = new CodeFormatterFacade(getSettings(), element.getLanguage(), canChangeWhiteSpacesOnly).processElement(treeElement).getPsi(); + final PsiFile file = element.getContainingFile(); + final PsiElement formatted = + new CodeFormatterFacade(getSettings(file), element.getLanguage(), canChangeWhiteSpacesOnly) + .processElement(treeElement).getPsi(); if (!canChangeWhiteSpacesOnly) { - return postProcessElement(formatted); + return postProcessElement(file, formatted); } return formatted; } - private PsiElement postProcessElement(@NotNull final PsiElement formatted) { + private static PsiElement postProcessElement(@NotNull PsiFile file, @NotNull final PsiElement formatted) { PsiElement result = formatted; - if (getSettings().FORMATTER_TAGS_ENABLED && formatted instanceof PsiFile) { - postProcessEnabledRanges((PsiFile) formatted, formatted.getTextRange(), getSettings()); + if (getSettings(file).FORMATTER_TAGS_ENABLED && formatted instanceof PsiFile) { + postProcessEnabledRanges((PsiFile) formatted, formatted.getTextRange(), getSettings(file)); } else { for (PostFormatProcessor postFormatProcessor : Extensions.getExtensions(PostFormatProcessor.EP_NAME)) { - result = postFormatProcessor.processElement(result, getSettings()); + result = postFormatProcessor.processElement(result, getSettings(file)); } } return result; } - private void postProcessText(@NotNull final PsiFile file, @NotNull final TextRange textRange) { - if (!getSettings().FORMATTER_TAGS_ENABLED) { + private static void postProcessText(@NotNull final PsiFile file, @NotNull final TextRange textRange) { + if (!getSettings(file).FORMATTER_TAGS_ENABLED) { TextRange currentRange = textRange; for (final PostFormatProcessor myPostFormatProcessor : Extensions.getExtensions(PostFormatProcessor.EP_NAME)) { - currentRange = myPostFormatProcessor.processText(file, currentRange, getSettings()); + currentRange = myPostFormatProcessor.processText(file, currentRange, getSettings(file)); } } else { - postProcessEnabledRanges(file, textRange, getSettings()); + postProcessEnabledRanges(file, textRange, getSettings(file)); } } @@ -180,7 +180,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting ASTNode treeElement = SourceTreeToPsiMap.psiElementToTree(file); transformAllChildren(treeElement); - final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(getSettings(), file.getLanguage()); + final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(getSettings(file), file.getLanguage()); codeFormatter.setReformatContext(reformatContext); LOG.assertTrue(file.isValid(), "File name: " + file.getName() + " , class: " + file.getClass().getSimpleName()); @@ -191,7 +191,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting CaretPositionKeeper caretKeeper = null; if (editor != null) { - caretKeeper = new CaretPositionKeeper(editor, getSettings(), file.getLanguage()); + caretKeeper = new CaretPositionKeeper(editor, getSettings(file), file.getLanguage()); } if (FormatterUtil.isFormatterCalledExplicitly()) { @@ -259,10 +259,10 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting } } - private PsiElement reformatRangeImpl(final @NotNull PsiElement element, - final int startOffset, - final int endOffset, - boolean canChangeWhiteSpacesOnly) throws IncorrectOperationException { + private static PsiElement reformatRangeImpl(final @NotNull PsiElement element, + final int startOffset, + final int endOffset, + boolean canChangeWhiteSpacesOnly) throws IncorrectOperationException { LOG.assertTrue(element.isValid()); CheckUtil.checkWritable(element); if( !SourceTreeToPsiMap.hasTreeElement( element ) ) @@ -271,10 +271,11 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting } ASTNode treeElement = element.getNode(); - final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(getSettings(), element.getLanguage()); + final PsiFile file = element.getContainingFile(); + final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(getSettings(file), element.getLanguage()); final PsiElement formatted = codeFormatter.processRange(treeElement, startOffset, endOffset).getPsi(); - return canChangeWhiteSpacesOnly ? formatted : postProcessElement(formatted); + return canChangeWhiteSpacesOnly ? formatted : postProcessElement(file, formatted); } @@ -290,6 +291,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting if (fileViewProvider instanceof MultiplePsiFilesPerDocumentFileViewProvider) { containingFile = fileViewProvider.getPsi(fileViewProvider.getBaseLanguage()); } + assert containingFile != null; TextRange textRange = addedElement.getTextRange(); final Document document = fileViewProvider.getDocument(); @@ -300,8 +302,8 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting final FormattingModelBuilder builder = LanguageFormatting.INSTANCE.forContext(containingFile); if (builder != null) { - final FormattingModel model = CoreFormatterUtil.buildModel(builder, containingFile, getSettings(), FormattingMode.REFORMAT); - FormatterEx.getInstanceEx().formatAroundRange(model, getSettings(), containingFile, textRange); + final FormattingModel model = CoreFormatterUtil.buildModel(builder, containingFile, getSettings(containingFile), FormattingMode.REFORMAT); + FormatterEx.getInstanceEx().formatAroundRange(model, getSettings(containingFile), containingFile, textRange); } adjustLineIndent(containingFile, textRange); @@ -411,6 +413,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting } @Override + @Deprecated public boolean isLineToBeIndented(@NotNull PsiFile file, int offset) { if (!SourceTreeToPsiMap.hasTreeElement(file)) { return false; @@ -440,7 +443,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting return false; } */ - if (getSettings().getCommonSettings(file.getLanguage()).KEEP_FIRST_COLUMN_COMMENT && isCommentToken(element)) { + if (getSettings(file).getCommonSettings(file.getLanguage()).KEEP_FIRST_COLUMN_COMMENT && isCommentToken(element)) { if (IndentHelper.getInstance().getIndent(myProject, file.getFileType(), element, true) == 0) { return false; } @@ -568,20 +571,23 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting } @Override + @Deprecated public Indent getIndent(String text, FileType fileType) { int indent = IndentHelperImpl.getIndent(CodeStyle.getSettings(myProject).getIndentOptions(fileType), text, true); int indentLevel = indent / IndentHelperImpl.INDENT_FACTOR; int spaceCount = indent - indentLevel * IndentHelperImpl.INDENT_FACTOR; - return new IndentImpl(getSettings(), indentLevel, spaceCount, fileType); + return new IndentImpl(CodeStyle.getSettings(myProject), indentLevel, spaceCount, fileType); } @Override + @Deprecated public String fillIndent(Indent indent, FileType fileType) { IndentImpl indent1 = (IndentImpl)indent; int indentLevel = indent1.getIndentLevel(); int spaceCount = indent1.getSpaceCount(); + final CodeStyleSettings settings = CodeStyle.getSettings(myProject); if (indentLevel < 0) { - spaceCount += indentLevel * getSettings().getIndentSize(fileType); + spaceCount += indentLevel * settings.getIndentSize(fileType); indentLevel = 0; if (spaceCount < 0) { spaceCount = 0; @@ -589,9 +595,9 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting } else { if (spaceCount < 0) { - int v = (-spaceCount + getSettings().getIndentSize(fileType) - 1) / getSettings().getIndentSize(fileType); + int v = (-spaceCount + settings.getIndentSize(fileType) - 1) / settings.getIndentSize(fileType); indentLevel -= v; - spaceCount += v * getSettings().getIndentSize(fileType); + spaceCount += v * settings.getIndentSize(fileType); if (indentLevel < 0) { indentLevel = 0; } @@ -601,14 +607,15 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting } @Override + @Deprecated public Indent zeroIndent() { - return new IndentImpl(getSettings(), 0, 0, null); + return new IndentImpl(CodeStyle.getSettings(myProject), 0, 0, null); } @NotNull - private CodeStyleSettings getSettings() { - return CodeStyleSettingsManager.getSettings(myProject); + private static CodeStyleSettings getSettings(@NotNull PsiFile file) { + return CodeStyle.getSettings(file); } @Override @@ -729,7 +736,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting RangeMarker myBeforeCaretRangeMarker; String myCaretIndentToRestore; int myVisualColumnToRestore = -1; - boolean myBlankLineIndentPreserved = true; + boolean myBlankLineIndentPreserved; CaretPositionKeeper(@NotNull Editor editor, @NotNull CodeStyleSettings settings, @NotNull Language language) { myEditor = editor; @@ -749,11 +756,8 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting private static boolean isBlankLineIndentPreserved(@NotNull CodeStyleSettings settings, @NotNull Language language) { CommonCodeStyleSettings langSettings = settings.getCommonSettings(language); - if (langSettings != null) { - CommonCodeStyleSettings.IndentOptions indentOptions = langSettings.getIndentOptions(); - return indentOptions != null && indentOptions.KEEP_INDENTS_ON_EMPTY_LINES; - } - return false; + CommonCodeStyleSettings.IndentOptions indentOptions = langSettings.getIndentOptions(); + return indentOptions != null && indentOptions.KEEP_INDENTS_ON_EMPTY_LINES; } private void initRestoreInfo(int caretOffset) { @@ -857,8 +861,8 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting } } - private void postProcessEnabledRanges(@NotNull final PsiFile file, @NotNull TextRange range, CodeStyleSettings settings) { - List enabledRanges = myTagHandler.getEnabledRanges(file.getNode(), range); + private static void postProcessEnabledRanges(@NotNull final PsiFile file, @NotNull TextRange range, CodeStyleSettings settings) { + List enabledRanges = new FormatterTagHandler(getSettings(file)).getEnabledRanges(file.getNode(), range); int delta = 0; for (TextRange enabledRange : enabledRanges) { enabledRange = enabledRange.shiftRight(delta); From 0207bd99d18819b47caecc329a5ed7d8227ac11e Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Mon, 7 May 2018 16:14:37 +0300 Subject: [PATCH 27/28] Migration to PsiFile-based CodeStyle API --- .../com/intellij/application/options/CodeStyle.java | 10 ++++++++++ .../psi/impl/source/codeStyle/CodeStyleFacadeImpl.java | 6 ------ .../src/com/intellij/codeStyle/CodeStyleFacade.java | 2 -- .../ide/ui/search/SearchableOptionsRegistrarImpl.java | 3 ++- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/platform/lang-api/src/com/intellij/application/options/CodeStyle.java b/platform/lang-api/src/com/intellij/application/options/CodeStyle.java index 244696d48796..bf933a00a004 100644 --- a/platform/lang-api/src/com/intellij/application/options/CodeStyle.java +++ b/platform/lang-api/src/com/intellij/application/options/CodeStyle.java @@ -254,4 +254,14 @@ public class CodeStyle { } } + /** + * @param project The project to check. + * @return {@code true} if the project uses its own project code style, {@code false} if global (application-level) code style settings + * are used. + */ + public static boolean usesOwnSettings(@NotNull Project project) { + //noinspection deprecation + return CodeStyleSettingsManager.getInstance(project).USE_PER_PROJECT_SETTINGS; + } + } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleFacadeImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleFacadeImpl.java index 805f6889a816..dc22436cfcb8 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleFacadeImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleFacadeImpl.java @@ -29,7 +29,6 @@ import com.intellij.openapi.options.Configurable; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.lineIndent.LineIndentProvider; import com.intellij.psi.codeStyle.lineIndent.LineIndentProviderEP; import org.jetbrains.annotations.NotNull; @@ -78,11 +77,6 @@ public class CodeStyleFacadeImpl extends CodeStyleFacade { return CodeStyle.getProjectOrDefaultSettings(myProject).getLineSeparator(); } - @Override - public boolean projectUsesOwnSettings() { - return myProject != null && CodeStyleSettingsManager.getInstance(myProject).USE_PER_PROJECT_SETTINGS; - } - @Override public boolean isUnsuitableCodeStyleConfigurable(final Configurable c) { return false; diff --git a/platform/platform-api/src/com/intellij/codeStyle/CodeStyleFacade.java b/platform/platform-api/src/com/intellij/codeStyle/CodeStyleFacade.java index 826f8800f09b..1103bc808397 100644 --- a/platform/platform-api/src/com/intellij/codeStyle/CodeStyleFacade.java +++ b/platform/platform-api/src/com/intellij/codeStyle/CodeStyleFacade.java @@ -106,7 +106,5 @@ public abstract class CodeStyleFacade { */ public abstract String getLineSeparator(); - public abstract boolean projectUsesOwnSettings(); - public abstract boolean isUnsuitableCodeStyleConfigurable(Configurable c); } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java index c9d3a9907d97..81795744337f 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java @@ -16,6 +16,7 @@ package com.intellij.ide.ui.search; +import com.intellij.application.options.CodeStyle; import com.intellij.codeStyle.CodeStyleFacade; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.PluginManagerConfigurable; @@ -415,7 +416,7 @@ public class SearchableOptionsRegistrarImpl extends SearchableOptionsRegistrar { @Override public Map> findPossibleExtension(@NotNull String prefix, final Project project) { loadHugeFilesIfNecessary(); - final boolean perProject = CodeStyleFacade.getInstance(project).projectUsesOwnSettings(); + final boolean perProject = CodeStyle.usesOwnSettings(project); final Map> result = new THashMap<>(); int count = 0; final Set prefixes = getProcessedWordsWithoutStemming(prefix); From 5396154505e1d46b44dbb4de4567f16a4687883e Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Mon, 7 May 2018 17:09:07 +0300 Subject: [PATCH 28/28] EA-115264 - IAE: PathReferenceProviderBase.$$$reportNull$$$ --- .../com/intellij/openapi/paths/PathReferenceProviderBase.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/openapi/paths/PathReferenceProviderBase.java b/platform/lang-impl/src/com/intellij/openapi/paths/PathReferenceProviderBase.java index 43b759999056..0503376e05d7 100644 --- a/platform/lang-impl/src/com/intellij/openapi/paths/PathReferenceProviderBase.java +++ b/platform/lang-impl/src/com/intellij/openapi/paths/PathReferenceProviderBase.java @@ -25,6 +25,8 @@ public abstract class PathReferenceProviderBase implements PathReferenceProvider int offset = range.getStartOffset(); int endOffset = range.getEndOffset(); final String elementText = psiElement.getText(); + if (elementText == null) + return false; for (DynamicContextProvider provider: Extensions.getExtensions(DynamicContextProvider.EP_NAME)) { final int dynamicOffset = provider.getOffset(psiElement, offset, elementText); if (dynamicOffset == -1) {