From 2177333d7a76a27ae515f01ffe80ea07aa1a3299 Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Wed, 23 May 2018 14:40:53 +0300 Subject: [PATCH] UX-1 new SearchEverywhere popup * search history --- .../SearchEverywhereManagerImpl.java | 125 +++++++++++++++++- 1 file changed, 123 insertions(+), 2 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 81ac934d5ee6..e8c424351604 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,19 +2,23 @@ package com.intellij.ide.actions.searcheverywhere; import com.intellij.ide.ui.UISettings; +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.util.Disposer; import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.impl.IdeFrameImpl; +import com.intellij.ui.SearchTextField; 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.ArrayList; import java.util.List; +import java.util.stream.Collectors; import static com.intellij.ide.actions.SearchEverywhereAction.SEARCH_EVERYWHERE_POPUP; @@ -24,9 +28,12 @@ public class SearchEverywhereManagerImpl implements SearchEverywhereManager { private final List myShownContributors = new ArrayList<>(); private final List myServiceContributors = new ArrayList<>(); - private JBPopup myBalloon; //todo appropriate names #UX-1 + private JBPopup myBalloon; private SearchEverywhereUI mySearchEverywhereUI; + private final List historyList = new ArrayList<>(); + private HistoryIterator myHistoryIterator; + public SearchEverywhereManagerImpl(Project project) { myProject = project; fillContributors(); @@ -49,6 +56,7 @@ public class SearchEverywhereManagerImpl implements SearchEverywhereManager { else { mySearchEverywhereUI = createView(myProject, myServiceContributors, myShownContributors); mySearchEverywhereUI.switchToContributor(selectedContributorID); + myHistoryIterator = new HistoryIterator(selectedContributorID); myBalloon = JBPopupFactory.getInstance().createComponentPopupBuilder(mySearchEverywhereUI, mySearchEverywhereUI.getSearchField()) .setProject(myProject) .setResizable(false) @@ -56,7 +64,10 @@ public class SearchEverywhereManagerImpl implements SearchEverywhereManager { .setCancelOnClickOutside(true) .setRequestFocus(true) .setCancelKeyEnabled(false) - //.setCancelCallback(() -> true) + .setCancelCallback(() -> { + saveSearchText(); + return true; + }) .addUserData("SIMPLE_WINDOW") .setResizable(true) .setMovable(true) @@ -139,6 +150,12 @@ public class SearchEverywhereManagerImpl implements SearchEverywhereManager { } }); + DumbAwareAction.create(__ -> showHistoryItem(true)) + .registerCustomShortcutSet(SearchTextField.SHOW_HISTORY_SHORTCUT, view); + + DumbAwareAction.create(__ -> showHistoryItem(false)) + .registerCustomShortcutSet(SearchTextField.ALT_SHOW_HISTORY_SHORTCUT, view); + return view; } @@ -147,4 +164,108 @@ public class SearchEverywhereManagerImpl implements SearchEverywhereManager { throw new IllegalStateException("Method should be called only when search popup is shown"); } } + + private void saveSearchText() { + updateHistoryIterator(); + String searchText = mySearchEverywhereUI.getSearchField().getText(); + if (!searchText.isEmpty()) { + myHistoryIterator.save(searchText); + } + } + + private void showHistoryItem(boolean next) { + updateHistoryIterator(); + JTextField searchField = mySearchEverywhereUI.getSearchField(); + searchField.setText(next ? myHistoryIterator.next() : myHistoryIterator.prev()); + searchField.selectAll(); + } + + private void updateHistoryIterator() { + String selectedContributorID = mySearchEverywhereUI.getSelectedContributorID(); + if (myHistoryIterator == null || !myHistoryIterator.getContributorID().equals(selectedContributorID)) { + myHistoryIterator = new HistoryIterator(selectedContributorID); + } + } + + private static class HistoryItem { + private final String searchText; + private final String contributorID; + + public HistoryItem(String searchText, String contributorID) { + this.searchText = searchText; + this.contributorID = contributorID; + } + + public String getSearchText() { + return searchText; + } + + public String getContributorID() { + return contributorID; + } + } + + private class HistoryIterator { + + private final String contributorID; + private final List list; + private int index; + + private HistoryIterator(String id) { + contributorID = id; + list = getHistoryForContributor(id); + index = -1; + } + + public String getContributorID() { + return contributorID; + } + + public String next() { + if (list.isEmpty()) { + return ""; + } + + index += 1; + if (index >= list.size()) { + index = 0; + } + return list.get(index); + } + + public String prev() { + if (list.isEmpty()) { + return ""; + } + + index -= 1; + if (index < 0) { + index = list.size() - 1; + } + return list.get(index); + } + + public void save(String text) { + String lastHistoryItem = list.isEmpty() ? null : list.get(list.size() - 1); + if (text.equals(lastHistoryItem)) { + return; + } + + historyList.add(new HistoryItem(text, contributorID)); + list.add(text); + } + + private List getHistoryForContributor(String contributorID) { + if (SearchEverywhereContributor.ALL_CONTRIBUTORS_GROUP_ID.equals(contributorID)) { + return historyList.stream() + .map(item -> item.getSearchText()) + .collect(Collectors.toList()); + } else { + return historyList.stream() + .filter(item -> item.getContributorID().equals(contributorID)) + .map(item -> item.getSearchText()) + .collect(Collectors.toList()); + } + } + } }